mirror of
https://github.com/pion/mediadevices.git
synced 2026-04-22 15:57:27 +08:00
Merge branch 'add-svt-av1-codec' into temporary-svt-av1-example
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#include <EbSvtAv1.h>
|
||||
#include <EbSvtAv1Enc.h>
|
||||
#include <EbSvtAv1ErrorCodes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
+10
-109
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <EbSvtAv1.h>
|
||||
#include <EbSvtAv1Enc.h>
|
||||
#include <EbSvtAv1ErrorCodes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user