diff --git a/pkg/codec/svtav1/bridge.c b/pkg/codec/svtav1/bridge.c new file mode 100644 index 0000000..f76ae82 --- /dev/null +++ b/pkg/codec/svtav1/bridge.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +#include "bridge.h" + +int enc_new(Encoder **e) { + *e = malloc(sizeof(Encoder)); + (*e)->param = malloc(sizeof(EbSvtAv1EncConfiguration)); + (*e)->in_buf = malloc(sizeof(EbBufferHeaderType)); + + memset((*e)->in_buf, 0, sizeof(EbBufferHeaderType)); + (*e)->in_buf->p_buffer = malloc(sizeof(EbSvtIOFormat)); + (*e)->in_buf->size = sizeof(EbBufferHeaderType); + + (*e)->handle = NULL; + +#if SVT_AV1_CHECK_VERSION(3, 0, 0) + const EbErrorType sret = svt_av1_enc_init_handle(&(*e)->handle, (*e)->param); +#else + const EbErrorType sret = svt_av1_enc_init_handle(&(*e)->handle, NULL, (*e)->param); +#endif + if (sret != EB_ErrorNone) { + enc_free(*e); + return ERR_INIT_ENC_HANDLER; + } + + return 0; +} + +int enc_free(Encoder *e) { + if (e->handle != NULL) { + svt_av1_enc_deinit(e->handle); + svt_av1_enc_deinit_handle(e->handle); + } + free(e->in_buf->p_buffer); + free(e->in_buf); + free(e->param); + free(e); + + return 0; +} + +int enc_init(Encoder *e) { + EbErrorType sret; + + e->param->encoder_bit_depth = 8; + e->param->encoder_color_format = EB_YUV420; + + sret = svt_av1_enc_set_parameter(e->handle, e->param); + if (sret != EB_ErrorNone) { + return ERR_SET_ENC_PARAM; + } + + sret = svt_av1_enc_init(e->handle); + if (sret != EB_ErrorNone) { + return ERR_ENC_INIT; + } + + return 0; +} + +int enc_apply_param(Encoder *e) { + const EbErrorType sret = svt_av1_enc_set_parameter(e->handle, e->param); + if (sret != EB_ErrorNone) { + return ERR_SET_ENC_PARAM; + } + + return 0; +} + +int enc_force_keyframe(Encoder *e) { + e->force_keyframe = true; + return 0; +} + +int enc_send_frame(Encoder *e, uint8_t *y, uint8_t *cb, uint8_t *cr, int ystride, int cstride) { + EbSvtIOFormat *in_data = (EbSvtIOFormat *)e->in_buf->p_buffer; + in_data->luma = y; + in_data->cb = cb; + in_data->cr = cr; + in_data->y_stride = ystride; + in_data->cb_stride = cstride; + in_data->cr_stride = cstride; + + e->in_buf->pic_type = EB_AV1_INVALID_PICTURE; // auto + if (e->force_keyframe) { + e->in_buf->pic_type = EB_AV1_KEY_PICTURE; + e->force_keyframe = false; + } + e->in_buf->flags = 0; + e->in_buf->pts++; + e->in_buf->n_filled_len = ystride * e->param->source_height; + e->in_buf->n_filled_len += 2 * cstride * e->param->source_height / 2; + + const EbErrorType sret = svt_av1_enc_send_picture(e->handle, e->in_buf); + if (sret != EB_ErrorNone) { + return ERR_SEND_PICTURE; + } + return 0; +} + +int enc_get_packet(Encoder *e, EbBufferHeaderType **out) { + const EbErrorType sret = svt_av1_enc_get_packet(e->handle, out, 0); + if (sret == EB_NoErrorEmptyQueue) { + return 0; + } + if (sret != EB_ErrorNone) { + return ERR_GET_PACKET; + } + + return 0; +} + +void memcpy_uint8(uint8_t *dst, const uint8_t *src, size_t n) { + // Just make CGO types compatible + memcpy(dst, src, n); +} diff --git a/pkg/codec/svtav1/bridge.h b/pkg/codec/svtav1/bridge.h index 7dbed45..3be2441 100644 --- a/pkg/codec/svtav1/bridge.h +++ b/pkg/codec/svtav1/bridge.h @@ -1,9 +1,8 @@ +#pragma once + #include #include -#include #include -#include -#include #define ERR_INIT_ENC_HANDLER 1 #define ERR_SET_ENC_PARAM 2 @@ -19,109 +18,11 @@ typedef struct Encoder { bool force_keyframe; } Encoder; -int enc_free(Encoder *e) { - free(e->in_buf->p_buffer); - free(e->in_buf); - free(e->param); - free(e); - - return 0; -} - -int enc_new(Encoder **e) { - *e = malloc(sizeof(Encoder)); - (*e)->param = malloc(sizeof(EbSvtAv1EncConfiguration)); - (*e)->in_buf = malloc(sizeof(EbBufferHeaderType)); - - memset((*e)->in_buf, 0, sizeof(EbBufferHeaderType)); - (*e)->in_buf->p_buffer = malloc(sizeof(EbSvtIOFormat)); - (*e)->in_buf->size = sizeof(EbBufferHeaderType); - -#if SVT_AV1_CHECK_VERSION(3, 0, 0) - const EbErrorType sret = svt_av1_enc_init_handle(&(*e)->handle, (*e)->param); -#else - const EbErrorType sret = svt_av1_enc_init_handle(&(*e)->handle, NULL, (*e)->param); -#endif - if (sret != EB_ErrorNone) { - enc_free(*e); - return ERR_INIT_ENC_HANDLER; - } - - return 0; -} - -int enc_init(Encoder *e) { - EbErrorType sret; - - e->param->encoder_bit_depth = 8; - e->param->encoder_color_format = EB_YUV420; - - sret = svt_av1_enc_set_parameter(e->handle, e->param); - if (sret != EB_ErrorNone) { - return ERR_SET_ENC_PARAM; - } - - sret = svt_av1_enc_init(e->handle); - if (sret != EB_ErrorNone) { - return ERR_ENC_INIT; - } - - return 0; -} - -int enc_apply_param(Encoder *e) { - const EbErrorType sret = svt_av1_enc_set_parameter(e->handle, e->param); - if (sret != EB_ErrorNone) { - return ERR_SET_ENC_PARAM; - } - - return 0; -} - -int enc_force_keyframe(Encoder *e) { - e->force_keyframe = true; - return 0; -} - -int enc_send_frame(Encoder *e, uint8_t *y, uint8_t *cb, uint8_t *cr, int ystride, int cstride) { - EbSvtIOFormat *in_data = (EbSvtIOFormat *)e->in_buf->p_buffer; - in_data->luma = y; - in_data->cb = cb; - in_data->cr = cr; - in_data->y_stride = ystride; - in_data->cb_stride = cstride; - in_data->cr_stride = cstride; - - e->in_buf->pic_type = EB_AV1_INVALID_PICTURE; // auto - if (e->force_keyframe) { - e->in_buf->pic_type = EB_AV1_KEY_PICTURE; - e->force_keyframe = false; - } - e->in_buf->flags = 0; - e->in_buf->pts++; - e->in_buf->n_filled_len = ystride * e->param->source_height; - e->in_buf->n_filled_len += 2 * cstride * e->param->source_height / 2; - - const EbErrorType sret = svt_av1_enc_send_picture(e->handle, e->in_buf); - if (sret != EB_ErrorNone) { - return ERR_SEND_PICTURE; - } - return 0; -} - -int enc_get_packet(Encoder *e, EbBufferHeaderType **out) { - const EbErrorType sret = svt_av1_enc_get_packet(e->handle, out, 0); - if (sret == EB_NoErrorEmptyQueue) { - return 0; - } - if (sret != EB_ErrorNone) { - return ERR_GET_PACKET; - } - - return 0; -} - -void memcpy_uint8(uint8_t *dst, const uint8_t *src, size_t n) { - // Just make CGO types compatible - memcpy(dst, src, n); -} +int enc_free(Encoder *e); +int enc_new(Encoder **e); +int enc_init(Encoder *e); +int enc_apply_param(Encoder *e); +int enc_force_keyframe(Encoder *e); +int enc_send_frame(Encoder *e, uint8_t *y, uint8_t *cb, uint8_t *cr, int ystride, int cstride); +int enc_get_packet(Encoder *e, EbBufferHeaderType **out); +void memcpy_uint8(uint8_t *dst, const uint8_t *src, size_t n); diff --git a/pkg/codec/svtav1/errors.go b/pkg/codec/svtav1/errors.go index 7e2f816..75a33a3 100644 --- a/pkg/codec/svtav1/errors.go +++ b/pkg/codec/svtav1/errors.go @@ -1,8 +1,10 @@ package svtav1 -import ( - "errors" -) +import "errors" + +// #cgo pkg-config: SvtAv1Enc +// #include "bridge.h" +import "C" var ( ErrUnknownErrorCode = errors.New("unknown error code") @@ -12,3 +14,22 @@ var ( ErrSendPicture = errors.New("failed to send picture") ErrGetPacket = errors.New("failed to get packet") ) + +func errFromC(ret C.int) error { + switch ret { + case 0: + return nil + case C.ERR_INIT_ENC_HANDLER: + return ErrInitEncHandler + case C.ERR_SET_ENC_PARAM: + return ErrSetEncParam + case C.ERR_ENC_INIT: + return ErrEncInit + case C.ERR_SEND_PICTURE: + return ErrSendPicture + case C.ERR_GET_PACKET: + return ErrGetPacket + default: + return ErrUnknownErrorCode + } +} diff --git a/pkg/codec/svtav1/params.go b/pkg/codec/svtav1/params.go index dc0af3c..9835e07 100644 --- a/pkg/codec/svtav1/params.go +++ b/pkg/codec/svtav1/params.go @@ -8,7 +8,7 @@ import ( "github.com/pion/mediadevices/pkg/prop" ) -// Params stores libx264 specific encoding parameters. +// Params stores SVT-AV1 specific encoding parameters. type Params struct { codec.BaseParams @@ -23,7 +23,7 @@ type Params struct { MaximumBufferSize time.Duration } -// NewParams returns default x264 codec specific parameters. +// NewParams returns default SVT-AV1 codec specific parameters. func NewParams() (Params, error) { return Params{ BaseParams: codec.BaseParams{ @@ -41,7 +41,7 @@ func (p *Params) RTPCodec() *codec.RTPCodec { return codec.NewRTPAV1Codec(90000) } -// BuildVideoEncoder builds x264 encoder with given params +// BuildVideoEncoder builds SVT-AV1 encoder with given params func (p *Params) BuildVideoEncoder(r video.Reader, property prop.Media) (codec.ReadCloser, error) { return newEncoder(r, property, *p) } diff --git a/pkg/codec/svtav1/svtav1.go b/pkg/codec/svtav1/svtav1.go index 5ef0358..5e08ce6 100644 --- a/pkg/codec/svtav1/svtav1.go +++ b/pkg/codec/svtav1/svtav1.go @@ -67,25 +67,6 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser, return &e, nil } -func errFromC(ret C.int) error { - switch ret { - case 0: - return nil - case C.ERR_INIT_ENC_HANDLER: - return ErrInitEncHandler - case C.ERR_SET_ENC_PARAM: - return ErrSetEncParam - case C.ERR_ENC_INIT: - return ErrEncInit - case C.ERR_SEND_PICTURE: - return ErrSendPicture - case C.ERR_GET_PACKET: - return ErrGetPacket - default: - return ErrUnknownErrorCode - } -} - func (e *encoder) Read() ([]byte, func(), error) { e.mu.Lock() defer e.mu.Unlock()