mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
svtav1: Merge SVT-AV1 encoder into gst-plugins-bad
This is based on d5e1e2a586020854733f6b0806064d0c900c88d2 from https://gitlab.com/AOMediaCodec/SVT-AV1.
This commit is contained in:
commit
b15efacf84
3 changed files with 1095 additions and 0 deletions
981
subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c
Normal file
981
subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c
Normal file
|
@ -0,0 +1,981 @@
|
|||
/*
|
||||
* Copyright(c) 2019 Intel Corporation
|
||||
* Authors: Jun Tian <jun.tian@intel.com> Xavier Hallade <xavier.hallade@intel.com>
|
||||
* SPDX - License - Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-gstsvtav1enc
|
||||
*
|
||||
* The svtav1enc element does AV1 encoding using Scalable
|
||||
* Video Technology for AV1 Encoder (SVT-AV1 Encoder).
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example launch line</title>
|
||||
* |[
|
||||
* gst-launch-1.0 -e videotestsrc ! video/x-raw ! svtav1enc ! matroskamux ! filesink location=out.mkv
|
||||
* ]|
|
||||
* Encodes test input into AV1 compressed data which is then packaged in out.mkv
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/video/gstvideoencoder.h>
|
||||
#include "gstsvtav1enc.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC(gst_svtav1enc_debug_category);
|
||||
#define GST_CAT_DEFAULT gst_svtav1enc_debug_category
|
||||
|
||||
#define GST_SVTAV1ENC_TYPE_INTRA_REFRESH_TYPE (gst_svtav1enc_intra_refresh_type_get_type())
|
||||
static GType gst_svtav1enc_intra_refresh_type_get_type(void) {
|
||||
static GType intra_refresh_type = 0;
|
||||
static const GEnumValue intra_refresh[] = {
|
||||
{SVT_AV1_FWDKF_REFRESH, "Open GOP", "CRA"},
|
||||
{SVT_AV1_KF_REFRESH, "Closed GOP", "IDR"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!intra_refresh_type) {
|
||||
intra_refresh_type = g_enum_register_static("GstSvtAv1EncIntraRefreshType", intra_refresh);
|
||||
}
|
||||
return intra_refresh_type;
|
||||
}
|
||||
|
||||
/* prototypes */
|
||||
static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gst_svtav1enc_finalize(GObject *object);
|
||||
|
||||
static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc);
|
||||
static void gst_svtav1enc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc);
|
||||
static gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc);
|
||||
static GstFlowReturn gst_svtav1enc_encode(GstSvtAv1Enc *svtav1enc, GstVideoCodecFrame *frame);
|
||||
static gboolean gst_svtav1enc_send_eos(GstSvtAv1Enc *svtav1enc);
|
||||
static GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1enc,
|
||||
gboolean closing_encoder,
|
||||
gboolean output_frames);
|
||||
|
||||
static gboolean gst_svtav1enc_open(GstVideoEncoder *encoder);
|
||||
static gboolean gst_svtav1enc_close(GstVideoEncoder *encoder);
|
||||
static gboolean gst_svtav1enc_start(GstVideoEncoder *encoder);
|
||||
static gboolean gst_svtav1enc_stop(GstVideoEncoder *encoder);
|
||||
static gboolean gst_svtav1enc_set_format(GstVideoEncoder *encoder, GstVideoCodecState *state);
|
||||
static GstFlowReturn gst_svtav1enc_handle_frame(GstVideoEncoder *encoder,
|
||||
GstVideoCodecFrame *frame);
|
||||
static GstFlowReturn gst_svtav1enc_finish(GstVideoEncoder *encoder);
|
||||
static gboolean gst_svtav1enc_propose_allocation(GstVideoEncoder *encoder, GstQuery *query);
|
||||
static gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder);
|
||||
|
||||
static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PRESET,
|
||||
PROP_TARGET_BITRATE,
|
||||
PROP_MAX_BITRATE,
|
||||
PROP_MAX_QP_ALLOWED,
|
||||
PROP_MIN_QP_ALLOWED,
|
||||
PROP_CQP,
|
||||
PROP_CRF,
|
||||
PROP_MAXIMUM_BUFFER_SIZE,
|
||||
PROP_INTRA_PERIOD_LENGTH,
|
||||
PROP_INTRA_REFRESH_TYPE,
|
||||
PROP_LOGICAL_PROCESSORS,
|
||||
PROP_TARGET_SOCKET,
|
||||
PROP_PARAMETERS_STRING,
|
||||
};
|
||||
|
||||
#define PROP_PRESET_DEFAULT 10
|
||||
#define PROP_TARGET_BITRATE_DEFAULT 0
|
||||
#define PROP_MAX_BITRATE_DEFAULT 0
|
||||
#define PROP_QP_MAX_QP_ALLOWED_DEFAULT 63
|
||||
#define PROP_QP_MIN_QP_ALLOWED_DEFAULT 1
|
||||
#define PROP_CQP_DEFAULT -1
|
||||
#define PROP_CRF_DEFAULT 35
|
||||
#define PROP_MAXIMUM_BUFFER_SIZE_DEFAULT 1000
|
||||
#define PROP_INTRA_PERIOD_LENGTH_DEFAULT -2
|
||||
#define PROP_INTRA_REFRESH_TYPE_DEFAULT SVT_AV1_KF_REFRESH
|
||||
#define PROP_LOGICAL_PROCESSORS_DEFAULT 0
|
||||
#define PROP_TARGET_SOCKET_DEFAULT -1
|
||||
#define PROP_PARAMETERS_STRING_DEFAULT NULL
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
#define FORMAT_I420_10 "I420_10LE"
|
||||
#else
|
||||
#define FORMAT_I420_10 "I420_10BE"
|
||||
#endif
|
||||
|
||||
/* pad templates */
|
||||
static GstStaticPadTemplate gst_svtav1enc_sink_pad_template = GST_STATIC_PAD_TEMPLATE(
|
||||
"sink", GST_PAD_SINK, GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS("video/x-raw, "
|
||||
"format = (string) {I420, " FORMAT_I420_10 "}, "
|
||||
"width = (int) [64, 16384], "
|
||||
"height = (int) [64, 8704], "
|
||||
"framerate = (fraction) [0, MAX]"));
|
||||
|
||||
static GstStaticPadTemplate gst_svtav1enc_src_pad_template = GST_STATIC_PAD_TEMPLATE(
|
||||
"src", GST_PAD_SRC, GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS("video/x-av1, "
|
||||
"stream-format = (string) obu-stream, "
|
||||
"alignment = (string) tu, "
|
||||
"width = (int) [64, 16384], "
|
||||
"height = (int) [64, 8704], "
|
||||
"framerate = (fraction) [0, MAX]"));
|
||||
|
||||
/* class initialization */
|
||||
G_DEFINE_TYPE_WITH_CODE(GstSvtAv1Enc, gst_svtav1enc, GST_TYPE_VIDEO_ENCODER,
|
||||
GST_DEBUG_CATEGORY_INIT(gst_svtav1enc_debug_category, "svtav1enc", 0,
|
||||
"SVT-AV1 encoder element"));
|
||||
|
||||
/* this mutex is required to avoid race conditions in SVT-AV1 memory allocations, which aren't thread-safe */
|
||||
G_LOCK_DEFINE_STATIC(init_mutex);
|
||||
|
||||
static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) {
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
|
||||
GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS(klass);
|
||||
|
||||
gst_element_class_add_static_pad_template(GST_ELEMENT_CLASS(klass),
|
||||
&gst_svtav1enc_src_pad_template);
|
||||
|
||||
gst_element_class_add_static_pad_template(GST_ELEMENT_CLASS(klass),
|
||||
&gst_svtav1enc_sink_pad_template);
|
||||
|
||||
gst_element_class_set_static_metadata(
|
||||
GST_ELEMENT_CLASS(klass),
|
||||
"SvtAv1Enc",
|
||||
"Codec/Encoder/Video",
|
||||
"Scalable Video Technology for AV1 Encoder (SVT-AV1 Encoder)",
|
||||
"Jun Tian <jun.tian@intel.com> Xavier Hallade <xavier.hallade@intel.com>");
|
||||
|
||||
gobject_class->set_property = gst_svtav1enc_set_property;
|
||||
gobject_class->get_property = gst_svtav1enc_get_property;
|
||||
gobject_class->finalize = gst_svtav1enc_finalize;
|
||||
video_encoder_class->open = GST_DEBUG_FUNCPTR(gst_svtav1enc_open);
|
||||
video_encoder_class->close = GST_DEBUG_FUNCPTR(gst_svtav1enc_close);
|
||||
video_encoder_class->start = GST_DEBUG_FUNCPTR(gst_svtav1enc_start);
|
||||
video_encoder_class->stop = GST_DEBUG_FUNCPTR(gst_svtav1enc_stop);
|
||||
video_encoder_class->set_format = GST_DEBUG_FUNCPTR(gst_svtav1enc_set_format);
|
||||
video_encoder_class->handle_frame = GST_DEBUG_FUNCPTR(gst_svtav1enc_handle_frame);
|
||||
video_encoder_class->finish = GST_DEBUG_FUNCPTR(gst_svtav1enc_finish);
|
||||
video_encoder_class->propose_allocation = GST_DEBUG_FUNCPTR(gst_svtav1enc_propose_allocation);
|
||||
video_encoder_class->flush = GST_DEBUG_FUNCPTR(gst_svtav1enc_flush);
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_PRESET,
|
||||
g_param_spec_uint("preset",
|
||||
"Preset",
|
||||
"Quality vs density tradeoff point"
|
||||
" that the encoding is to be performed at"
|
||||
" (0 is the highest quality, 13 is the highest speed) ",
|
||||
0,
|
||||
13,
|
||||
PROP_PRESET_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_TARGET_BITRATE,
|
||||
g_param_spec_uint("target-bitrate",
|
||||
"Target bitrate",
|
||||
"Target bitrate in kbits/sec. Enables CBR or VBR mode",
|
||||
0,
|
||||
100000,
|
||||
PROP_TARGET_BITRATE_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_MAX_BITRATE,
|
||||
g_param_spec_uint("max-bitrate",
|
||||
"Maximum bitrate",
|
||||
"Maximum bitrate in kbits/sec. Enables VBR mode if a different "
|
||||
"target-bitrate is provided",
|
||||
0,
|
||||
100000,
|
||||
PROP_MAX_BITRATE_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_MAX_QP_ALLOWED,
|
||||
g_param_spec_uint("max-qp-allowed",
|
||||
"Max Quantization parameter",
|
||||
"Maximum QP value allowed for rate control use"
|
||||
" Only used in CBR and VBR mode.",
|
||||
0,
|
||||
63,
|
||||
PROP_MAX_QP_ALLOWED,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_MIN_QP_ALLOWED,
|
||||
g_param_spec_uint("min-qp-allowed",
|
||||
"Min Quantization parameter",
|
||||
"Minimum QP value allowed for rate control use"
|
||||
" Only used in CBR and VBR mode.",
|
||||
0,
|
||||
63,
|
||||
PROP_MIN_QP_ALLOWED,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_CQP,
|
||||
g_param_spec_int("cqp",
|
||||
"Quantization parameter",
|
||||
"Quantization parameter used in CQP mode (-1 is disabled)",
|
||||
-1,
|
||||
63,
|
||||
PROP_CQP_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_CRF,
|
||||
g_param_spec_int("crf",
|
||||
"Constant Rate Factor",
|
||||
"Quantization parameter used in CRF mode (-1 is disabled)",
|
||||
-1,
|
||||
63,
|
||||
PROP_CRF_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(gobject_class,
|
||||
PROP_MAXIMUM_BUFFER_SIZE,
|
||||
g_param_spec_uint("maximum-buffer-size",
|
||||
"Maximum Buffer Size",
|
||||
"Maximum buffer size in milliseconds."
|
||||
" Only used in CBR mode.",
|
||||
20,
|
||||
10000,
|
||||
PROP_MAXIMUM_BUFFER_SIZE_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_INTRA_PERIOD_LENGTH,
|
||||
g_param_spec_int("intra-period-length",
|
||||
"Intra Period Length",
|
||||
"Period of Intra Frames insertion (-2 is auto, -1 no updates)",
|
||||
-2,
|
||||
G_MAXINT,
|
||||
PROP_INTRA_PERIOD_LENGTH_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(gobject_class,
|
||||
PROP_INTRA_REFRESH_TYPE,
|
||||
g_param_spec_enum("intra-refresh-type",
|
||||
"Intra refresh type",
|
||||
"CRA (open GOP)"
|
||||
"or IDR frames (closed GOP)",
|
||||
GST_SVTAV1ENC_TYPE_INTRA_REFRESH_TYPE,
|
||||
PROP_INTRA_REFRESH_TYPE_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_LOGICAL_PROCESSORS,
|
||||
g_param_spec_uint("logical-processors",
|
||||
"Logical Processors",
|
||||
"Number of logical CPU cores to be used. 0: auto",
|
||||
0,
|
||||
G_MAXUINT,
|
||||
PROP_LOGICAL_PROCESSORS_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_TARGET_SOCKET,
|
||||
g_param_spec_int("target-socket",
|
||||
"Target socket",
|
||||
"Target CPU socket to run on. -1: all available",
|
||||
-1,
|
||||
15,
|
||||
PROP_TARGET_SOCKET_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property(
|
||||
gobject_class,
|
||||
PROP_PARAMETERS_STRING,
|
||||
g_param_spec_string(
|
||||
"parameters-string",
|
||||
"Parameters String",
|
||||
"Colon-delimited list of key=value pairs of additional parameters to set",
|
||||
PROP_PARAMETERS_STRING_DEFAULT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) {
|
||||
svtav1enc->svt_config = g_new0(EbSvtAv1EncConfiguration, 1);
|
||||
svtav1enc->preset = PROP_PRESET_DEFAULT;
|
||||
svtav1enc->target_bitrate = PROP_TARGET_BITRATE_DEFAULT;
|
||||
svtav1enc->max_bitrate = PROP_MAX_BITRATE_DEFAULT;
|
||||
svtav1enc->max_qp_allowed = PROP_QP_MAX_QP_ALLOWED_DEFAULT;
|
||||
svtav1enc->min_qp_allowed = PROP_QP_MIN_QP_ALLOWED_DEFAULT;
|
||||
svtav1enc->cqp = PROP_CQP_DEFAULT;
|
||||
svtav1enc->crf = PROP_CRF_DEFAULT;
|
||||
svtav1enc->maximum_buffer_size = PROP_MAXIMUM_BUFFER_SIZE_DEFAULT;
|
||||
svtav1enc->intra_period_length = PROP_INTRA_PERIOD_LENGTH_DEFAULT;
|
||||
svtav1enc->intra_refresh_type = PROP_INTRA_REFRESH_TYPE_DEFAULT;
|
||||
svtav1enc->logical_processors = PROP_LOGICAL_PROCESSORS_DEFAULT;
|
||||
svtav1enc->target_socket = PROP_TARGET_SOCKET_DEFAULT;
|
||||
svtav1enc->parameters_string = PROP_PARAMETERS_STRING_DEFAULT;
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value,
|
||||
GParamSpec *pspec) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object);
|
||||
|
||||
/* TODO: support reconfiguring on the fly when possible */
|
||||
if (svtav1enc->state) {
|
||||
GST_ERROR_OBJECT(svtav1enc,
|
||||
"encoder state has been set before properties, this isn't supported yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT(svtav1enc, "setting property %u", property_id);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PRESET: svtav1enc->preset = g_value_get_uint(value); break;
|
||||
case PROP_TARGET_BITRATE: svtav1enc->target_bitrate = g_value_get_uint(value) * 1000; break;
|
||||
case PROP_MAX_BITRATE: svtav1enc->max_bitrate = g_value_get_uint(value) * 1000; break;
|
||||
case PROP_MAX_QP_ALLOWED: svtav1enc->max_qp_allowed = g_value_get_uint(value); break;
|
||||
case PROP_MIN_QP_ALLOWED: svtav1enc->min_qp_allowed = g_value_get_uint(value); break;
|
||||
case PROP_CQP: svtav1enc->cqp = g_value_get_int(value); break;
|
||||
case PROP_CRF: svtav1enc->crf = g_value_get_int(value); break;
|
||||
case PROP_MAXIMUM_BUFFER_SIZE: svtav1enc->maximum_buffer_size = g_value_get_uint(value); break;
|
||||
case PROP_INTRA_PERIOD_LENGTH: svtav1enc->intra_period_length = g_value_get_int(value); break;
|
||||
case PROP_INTRA_REFRESH_TYPE: svtav1enc->intra_refresh_type = g_value_get_enum(value); break;
|
||||
case PROP_LOGICAL_PROCESSORS: svtav1enc->logical_processors = g_value_get_uint(value); break;
|
||||
case PROP_TARGET_SOCKET: svtav1enc->target_socket = g_value_get_int(value); break;
|
||||
case PROP_PARAMETERS_STRING: {
|
||||
g_free(svtav1enc->parameters_string);
|
||||
svtav1enc->parameters_string = g_value_dup_string(value);
|
||||
break;
|
||||
}
|
||||
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValue *value,
|
||||
GParamSpec *pspec) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object);
|
||||
|
||||
GST_LOG_OBJECT(svtav1enc, "getting property %u", property_id);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_PRESET: g_value_set_uint(value, svtav1enc->preset); break;
|
||||
case PROP_TARGET_BITRATE: g_value_set_uint(value, svtav1enc->target_bitrate / 1000); break;
|
||||
case PROP_MAX_BITRATE: g_value_set_uint(value, svtav1enc->max_bitrate / 1000); break;
|
||||
case PROP_MAX_QP_ALLOWED: g_value_set_uint(value, svtav1enc->max_qp_allowed); break;
|
||||
case PROP_MIN_QP_ALLOWED: g_value_set_uint(value, svtav1enc->min_qp_allowed); break;
|
||||
case PROP_CQP: g_value_set_int(value, svtav1enc->cqp); break;
|
||||
case PROP_CRF: g_value_set_int(value, svtav1enc->crf); break;
|
||||
case PROP_MAXIMUM_BUFFER_SIZE: g_value_set_uint(value, svtav1enc->maximum_buffer_size); break;
|
||||
case PROP_INTRA_PERIOD_LENGTH: g_value_set_int(value, svtav1enc->intra_period_length); break;
|
||||
case PROP_INTRA_REFRESH_TYPE: g_value_set_enum(value, svtav1enc->intra_refresh_type); break;
|
||||
case PROP_LOGICAL_PROCESSORS: g_value_set_uint(value, svtav1enc->logical_processors); break;
|
||||
case PROP_TARGET_SOCKET: g_value_set_int(value, svtav1enc->target_socket); break;
|
||||
case PROP_PARAMETERS_STRING: g_value_set_string(value, svtav1enc->parameters_string); break;
|
||||
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_finalize(GObject *object) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "finalizing svtav1enc");
|
||||
|
||||
g_free(svtav1enc->svt_config);
|
||||
g_free(svtav1enc->parameters_string);
|
||||
|
||||
G_OBJECT_CLASS(gst_svtav1enc_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) {
|
||||
svtav1enc->input_buf = g_new0(EbBufferHeaderType, 1);
|
||||
svtav1enc->input_buf->p_buffer = (guint8 *)g_new0(EbSvtIOFormat, 1);
|
||||
svtav1enc->input_buf->size = sizeof(EbBufferHeaderType);
|
||||
svtav1enc->input_buf->p_app_private = NULL;
|
||||
svtav1enc->input_buf->pic_type = EB_AV1_INVALID_PICTURE;
|
||||
svtav1enc->input_buf->metadata = NULL;
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc) {
|
||||
if (svtav1enc->input_buf) {
|
||||
g_free(svtav1enc->input_buf->p_buffer);
|
||||
svtav1enc->input_buf->p_buffer = NULL;
|
||||
g_free(svtav1enc->input_buf);
|
||||
svtav1enc->input_buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) {
|
||||
if (!svtav1enc->state) {
|
||||
GST_WARNING_OBJECT(svtav1enc, "no state, can't configure encoder yet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* set object properties */
|
||||
svtav1enc->svt_config->enc_mode = svtav1enc->preset;
|
||||
if (svtav1enc->target_bitrate != 0) {
|
||||
svtav1enc->svt_config->target_bit_rate = svtav1enc->target_bitrate;
|
||||
if (svtav1enc->target_bitrate != svtav1enc->max_bitrate) {
|
||||
GST_DEBUG_OBJECT(svtav1enc,
|
||||
"Enabling VBR mode (br %u max-br %u max-qp %u min-qp %u)",
|
||||
svtav1enc->target_bitrate,
|
||||
svtav1enc->max_bitrate,
|
||||
svtav1enc->max_qp_allowed,
|
||||
svtav1enc->min_qp_allowed);
|
||||
svtav1enc->svt_config->max_bit_rate = svtav1enc->max_bitrate;
|
||||
svtav1enc->svt_config->rate_control_mode = SVT_AV1_RC_MODE_VBR;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT(svtav1enc,
|
||||
"Enabling CBR mode (br %u max-bs %u)",
|
||||
svtav1enc->target_bitrate,
|
||||
svtav1enc->maximum_buffer_size);
|
||||
svtav1enc->svt_config->rate_control_mode = SVT_AV1_RC_MODE_CBR;
|
||||
svtav1enc->svt_config->maximum_buffer_size_ms = svtav1enc->maximum_buffer_size;
|
||||
}
|
||||
svtav1enc->svt_config->max_qp_allowed = svtav1enc->max_qp_allowed;
|
||||
svtav1enc->svt_config->min_qp_allowed = svtav1enc->min_qp_allowed;
|
||||
svtav1enc->svt_config->force_key_frames = FALSE;
|
||||
} else if (svtav1enc->crf > 0) {
|
||||
GST_DEBUG_OBJECT(svtav1enc, "Enabling CRF mode (qp %u)", svtav1enc->crf);
|
||||
svtav1enc->svt_config->qp = svtav1enc->crf;
|
||||
svtav1enc->svt_config->rate_control_mode = SVT_AV1_RC_MODE_CQP_OR_CRF;
|
||||
svtav1enc->svt_config->force_key_frames = TRUE;
|
||||
} else if (svtav1enc->cqp > 0) {
|
||||
GST_DEBUG_OBJECT(svtav1enc, "Enabling CQP mode (qp %u)", svtav1enc->cqp);
|
||||
svtav1enc->svt_config->qp = svtav1enc->cqp;
|
||||
svtav1enc->svt_config->rate_control_mode = SVT_AV1_RC_MODE_CQP_OR_CRF;
|
||||
svtav1enc->svt_config->enable_adaptive_quantization = FALSE;
|
||||
svtav1enc->svt_config->force_key_frames = TRUE;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT(svtav1enc, "Using default rate control settings");
|
||||
}
|
||||
svtav1enc->svt_config->intra_period_length = svtav1enc->intra_period_length;
|
||||
svtav1enc->svt_config->intra_refresh_type = svtav1enc->intra_refresh_type;
|
||||
svtav1enc->svt_config->logical_processors = svtav1enc->logical_processors;
|
||||
svtav1enc->svt_config->target_socket = svtav1enc->target_socket;
|
||||
gst_svtav1enc_parse_parameters_string(svtav1enc);
|
||||
|
||||
/* set properties out of GstVideoInfo */
|
||||
const GstVideoInfo *info = &svtav1enc->state->info;
|
||||
svtav1enc->svt_config->encoder_bit_depth = GST_VIDEO_INFO_COMP_DEPTH(info, 0);
|
||||
svtav1enc->svt_config->source_width = GST_VIDEO_INFO_WIDTH(info);
|
||||
svtav1enc->svt_config->source_height = GST_VIDEO_INFO_HEIGHT(info);
|
||||
svtav1enc->svt_config->frame_rate_numerator = GST_VIDEO_INFO_FPS_N(info) > 0
|
||||
? GST_VIDEO_INFO_FPS_N(info)
|
||||
: 1;
|
||||
svtav1enc->svt_config->frame_rate_denominator = GST_VIDEO_INFO_FPS_D(info) > 0
|
||||
? GST_VIDEO_INFO_FPS_D(info)
|
||||
: 1;
|
||||
GST_LOG_OBJECT(svtav1enc,
|
||||
"width %d, height %d, framerate %d/%d",
|
||||
svtav1enc->svt_config->source_width,
|
||||
svtav1enc->svt_config->source_height,
|
||||
svtav1enc->svt_config->frame_rate_numerator,
|
||||
svtav1enc->svt_config->frame_rate_denominator);
|
||||
|
||||
switch (GST_VIDEO_INFO_COLORIMETRY(info).primaries) {
|
||||
case GST_VIDEO_COLOR_PRIMARIES_BT709:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_BT_709;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_BT470M:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_BT_470_M;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_BT_470_B_G;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_BT_601;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_SMPTE_240;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_FILM:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_GENERIC_FILM;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_BT2020:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_BT_2020;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_SMPTERP431:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_SMPTE_431;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_SMPTEEG432:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_SMPTE_432;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_PRIMARIES_EBU3213:
|
||||
svtav1enc->svt_config->color_primaries = EB_CICP_CP_EBU_3213;
|
||||
break;
|
||||
default: svtav1enc->svt_config->color_primaries = EB_CICP_CP_UNSPECIFIED; break;
|
||||
}
|
||||
|
||||
switch (GST_VIDEO_INFO_COLORIMETRY(info).transfer) {
|
||||
case GST_VIDEO_TRANSFER_BT709:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_BT_709;
|
||||
break;
|
||||
case GST_VIDEO_TRANSFER_GAMMA28:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_BT_470_B_G;
|
||||
break;
|
||||
#if GST_CHECK_VERSION(1, 18, 0)
|
||||
case GST_VIDEO_TRANSFER_BT601:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_BT_601;
|
||||
break;
|
||||
#endif
|
||||
case GST_VIDEO_TRANSFER_SMPTE240M:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_SMPTE_240;
|
||||
break;
|
||||
case GST_VIDEO_TRANSFER_GAMMA10:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_LINEAR;
|
||||
break;
|
||||
case GST_VIDEO_TRANSFER_LOG100:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_LOG_100;
|
||||
break;
|
||||
case GST_VIDEO_TRANSFER_LOG316:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_LOG_100_SQRT10;
|
||||
break;
|
||||
case GST_VIDEO_TRANSFER_SRGB:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_SRGB;
|
||||
break;
|
||||
#if GST_CHECK_VERSION(1, 18, 0)
|
||||
case GST_VIDEO_TRANSFER_BT2020_10:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_BT_2020_10_BIT;
|
||||
break;
|
||||
#endif
|
||||
case GST_VIDEO_TRANSFER_BT2020_12:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_BT_2020_12_BIT;
|
||||
break;
|
||||
#if GST_CHECK_VERSION(1, 18, 0)
|
||||
case GST_VIDEO_TRANSFER_SMPTE2084:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_SMPTE_2084;
|
||||
break;
|
||||
case GST_VIDEO_TRANSFER_ARIB_STD_B67:
|
||||
svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_HLG;
|
||||
break;
|
||||
#endif
|
||||
default: svtav1enc->svt_config->transfer_characteristics = EB_CICP_TC_UNSPECIFIED; break;
|
||||
}
|
||||
|
||||
switch (GST_VIDEO_INFO_COLORIMETRY(info).matrix) {
|
||||
case GST_VIDEO_COLOR_MATRIX_RGB:
|
||||
svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_IDENTITY;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT709:
|
||||
svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_BT_709;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_FCC:
|
||||
svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_FCC;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT601:
|
||||
svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_BT_601;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
|
||||
svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_SMPTE_240;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT2020:
|
||||
svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_BT_2020_NCL;
|
||||
break;
|
||||
|
||||
default: svtav1enc->svt_config->matrix_coefficients = EB_CICP_MC_UNSPECIFIED; break;
|
||||
}
|
||||
|
||||
if (GST_VIDEO_INFO_COLORIMETRY(info).range == GST_VIDEO_COLOR_RANGE_0_255) {
|
||||
svtav1enc->svt_config->color_range = EB_CR_FULL_RANGE;
|
||||
} else {
|
||||
svtav1enc->svt_config->color_range = EB_CR_STUDIO_RANGE;
|
||||
}
|
||||
|
||||
switch (GST_VIDEO_INFO_CHROMA_SITE(info)) {
|
||||
case GST_VIDEO_CHROMA_SITE_V_COSITED:
|
||||
svtav1enc->svt_config->chroma_sample_position = EB_CSP_VERTICAL;
|
||||
break;
|
||||
case GST_VIDEO_CHROMA_SITE_COSITED:
|
||||
svtav1enc->svt_config->chroma_sample_position = EB_CSP_COLOCATED;
|
||||
break;
|
||||
default: svtav1enc->svt_config->chroma_sample_position = EB_CSP_UNKNOWN;
|
||||
}
|
||||
|
||||
#if GST_CHECK_VERSION(1, 18, 0)
|
||||
GstVideoMasteringDisplayInfo master_display_info;
|
||||
if (gst_video_mastering_display_info_from_caps(&master_display_info, svtav1enc->state->caps)) {
|
||||
svtav1enc->svt_config->mastering_display.r.x = master_display_info.display_primaries[0].x;
|
||||
svtav1enc->svt_config->mastering_display.r.y = master_display_info.display_primaries[0].y;
|
||||
svtav1enc->svt_config->mastering_display.g.x = master_display_info.display_primaries[1].x;
|
||||
svtav1enc->svt_config->mastering_display.g.y = master_display_info.display_primaries[1].y;
|
||||
svtav1enc->svt_config->mastering_display.b.x = master_display_info.display_primaries[2].x;
|
||||
svtav1enc->svt_config->mastering_display.b.y = master_display_info.display_primaries[2].y;
|
||||
svtav1enc->svt_config->mastering_display.white_point.x = master_display_info.white_point.x;
|
||||
svtav1enc->svt_config->mastering_display.white_point.y = master_display_info.white_point.y;
|
||||
svtav1enc->svt_config->mastering_display.max_luma =
|
||||
master_display_info.max_display_mastering_luminance;
|
||||
svtav1enc->svt_config->mastering_display.min_luma =
|
||||
master_display_info.min_display_mastering_luminance;
|
||||
svtav1enc->svt_config->high_dynamic_range_input = TRUE;
|
||||
} else {
|
||||
memset(&svtav1enc->svt_config->mastering_display,
|
||||
0,
|
||||
sizeof(svtav1enc->svt_config->mastering_display));
|
||||
svtav1enc->svt_config->high_dynamic_range_input = FALSE;
|
||||
}
|
||||
|
||||
GstVideoContentLightLevel content_light_level;
|
||||
if (gst_video_content_light_level_from_caps(&content_light_level, svtav1enc->state->caps)) {
|
||||
svtav1enc->svt_config->content_light_level.max_cll =
|
||||
content_light_level.max_content_light_level;
|
||||
svtav1enc->svt_config->content_light_level.max_fall =
|
||||
content_light_level.max_frame_average_light_level;
|
||||
} else {
|
||||
memset(&svtav1enc->svt_config->content_light_level,
|
||||
0,
|
||||
sizeof(svtav1enc->svt_config->content_light_level));
|
||||
}
|
||||
#endif
|
||||
|
||||
EbErrorType res = svt_av1_enc_set_parameter(svtav1enc->svt_encoder, svtav1enc->svt_config);
|
||||
if (res != EB_ErrorNone) {
|
||||
GST_ELEMENT_ERROR(svtav1enc,
|
||||
LIBRARY,
|
||||
INIT,
|
||||
(NULL),
|
||||
("svt_av1_enc_set_parameter failed with error %d", res));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_start_svt(GstSvtAv1Enc *svtav1enc) {
|
||||
G_LOCK(init_mutex);
|
||||
EbErrorType res = svt_av1_enc_init(svtav1enc->svt_encoder);
|
||||
G_UNLOCK(init_mutex);
|
||||
|
||||
if (res != EB_ErrorNone) {
|
||||
GST_ELEMENT_ERROR(
|
||||
svtav1enc, LIBRARY, INIT, (NULL), ("svt_av1_enc_init failed with error %d", res));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn gst_svtav1enc_encode(GstSvtAv1Enc *svtav1enc, GstVideoCodecFrame *frame) {
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
EbErrorType res = EB_ErrorNone;
|
||||
EbBufferHeaderType *input_buffer = svtav1enc->input_buf;
|
||||
EbSvtIOFormat *input_picture_buffer = (EbSvtIOFormat *)svtav1enc->input_buf->p_buffer;
|
||||
GstVideoFrame video_frame;
|
||||
|
||||
if (!gst_video_frame_map(
|
||||
&video_frame, &svtav1enc->state->info, frame->input_buffer, GST_MAP_READ)) {
|
||||
GST_ELEMENT_ERROR(svtav1enc, LIBRARY, ENCODE, (NULL), ("couldn't map input frame"));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
input_picture_buffer->y_stride = GST_VIDEO_FRAME_COMP_STRIDE(&video_frame, 0) /
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE(&video_frame, 0);
|
||||
input_picture_buffer->cb_stride = GST_VIDEO_FRAME_COMP_STRIDE(&video_frame, 1) /
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE(&video_frame, 1);
|
||||
input_picture_buffer->cr_stride = GST_VIDEO_FRAME_COMP_STRIDE(&video_frame, 2) /
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE(&video_frame, 2);
|
||||
|
||||
input_picture_buffer->luma = GST_VIDEO_FRAME_PLANE_DATA(&video_frame, 0);
|
||||
input_picture_buffer->cb = GST_VIDEO_FRAME_PLANE_DATA(&video_frame, 1);
|
||||
input_picture_buffer->cr = GST_VIDEO_FRAME_PLANE_DATA(&video_frame, 2);
|
||||
|
||||
input_buffer->n_filled_len = GST_VIDEO_FRAME_SIZE(&video_frame);
|
||||
|
||||
/* Fill in Buffers Header control data */
|
||||
input_buffer->flags = 0;
|
||||
input_buffer->p_app_private = NULL;
|
||||
input_buffer->pts = frame->pts;
|
||||
input_buffer->pic_type = EB_AV1_INVALID_PICTURE;
|
||||
|
||||
if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME(frame)) {
|
||||
input_buffer->pic_type = EB_AV1_KEY_PICTURE;
|
||||
}
|
||||
|
||||
input_buffer->metadata = NULL;
|
||||
|
||||
res = svt_av1_enc_send_picture(svtav1enc->svt_encoder, input_buffer);
|
||||
if (res != EB_ErrorNone) {
|
||||
GST_ELEMENT_ERROR(
|
||||
svtav1enc, LIBRARY, ENCODE, (NULL), ("error in sending picture to encoder"));
|
||||
ret = GST_FLOW_ERROR;
|
||||
}
|
||||
gst_video_frame_unmap(&video_frame);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_send_eos(GstSvtAv1Enc *svtav1enc) {
|
||||
EbErrorType ret = EB_ErrorNone;
|
||||
|
||||
EbBufferHeaderType input_buffer;
|
||||
input_buffer.n_alloc_len = 0;
|
||||
input_buffer.n_filled_len = 0;
|
||||
input_buffer.n_tick_count = 0;
|
||||
input_buffer.p_app_private = NULL;
|
||||
input_buffer.flags = EB_BUFFERFLAG_EOS;
|
||||
input_buffer.p_buffer = NULL;
|
||||
input_buffer.metadata = NULL;
|
||||
|
||||
ret = svt_av1_enc_send_picture(svtav1enc->svt_encoder, &input_buffer);
|
||||
|
||||
if (ret != EB_ErrorNone) {
|
||||
GST_ELEMENT_ERROR(svtav1enc, LIBRARY, ENCODE, (NULL), ("couldn't send EOS frame."));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (ret == EB_ErrorNone);
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder) {
|
||||
GstFlowReturn ret = gst_svtav1enc_dequeue_encoded_frames(GST_SVTAV1ENC(encoder), TRUE, FALSE);
|
||||
|
||||
return (ret != GST_FLOW_ERROR);
|
||||
}
|
||||
|
||||
static GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1enc,
|
||||
gboolean done_sending_pics,
|
||||
gboolean output_frames) {
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
EbErrorType res = EB_ErrorNone;
|
||||
gboolean encode_at_eos = FALSE;
|
||||
|
||||
do {
|
||||
GstVideoCodecFrame *frame = NULL;
|
||||
EbBufferHeaderType *output_buf = NULL;
|
||||
|
||||
res = svt_av1_enc_get_packet(svtav1enc->svt_encoder, &output_buf, done_sending_pics);
|
||||
|
||||
if (output_buf != NULL)
|
||||
encode_at_eos = ((output_buf->flags & EB_BUFFERFLAG_EOS) == EB_BUFFERFLAG_EOS);
|
||||
|
||||
if (res == EB_ErrorMax) {
|
||||
GST_ELEMENT_ERROR(svtav1enc, LIBRARY, ENCODE, (NULL), ("encode failed"));
|
||||
return GST_FLOW_ERROR;
|
||||
} else if (res != EB_NoErrorEmptyQueue && output_frames && output_buf) {
|
||||
// AV1 has no frame re-ordering so always get the oldest frame
|
||||
frame = gst_video_encoder_get_oldest_frame(GST_VIDEO_ENCODER(svtav1enc));
|
||||
if (output_buf->pic_type == EB_AV1_KEY_PICTURE ||
|
||||
output_buf->pic_type == EB_AV1_INTRA_ONLY_PICTURE) {
|
||||
GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT(frame);
|
||||
}
|
||||
|
||||
if ((ret = gst_video_encoder_allocate_output_frame(
|
||||
GST_VIDEO_ENCODER(svtav1enc), frame, output_buf->n_filled_len)) !=
|
||||
GST_FLOW_OK) {
|
||||
svt_av1_enc_release_out_buffer(&output_buf);
|
||||
gst_video_codec_frame_unref(frame);
|
||||
return ret;
|
||||
}
|
||||
gst_buffer_fill(
|
||||
frame->output_buffer, 0, output_buf->p_buffer, output_buf->n_filled_len);
|
||||
|
||||
frame->pts = frame->output_buffer->pts = output_buf->pts;
|
||||
|
||||
GST_LOG_OBJECT(svtav1enc,
|
||||
"#frame:%u pts:%" G_GINT64_FORMAT " SliceType:%d\n",
|
||||
frame->system_frame_number,
|
||||
(frame->pts),
|
||||
output_buf->pic_type);
|
||||
|
||||
svt_av1_enc_release_out_buffer(&output_buf);
|
||||
output_buf = NULL;
|
||||
|
||||
ret = gst_video_encoder_finish_frame(GST_VIDEO_ENCODER(svtav1enc), frame);
|
||||
}
|
||||
|
||||
} while (res == EB_ErrorNone && !encode_at_eos && ret == GST_FLOW_OK);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_open(GstVideoEncoder *encoder) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "open");
|
||||
|
||||
EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config);
|
||||
if (res != EB_ErrorNone) {
|
||||
GST_ELEMENT_ERROR(svtav1enc,
|
||||
LIBRARY,
|
||||
INIT,
|
||||
(NULL),
|
||||
("svt_av1_enc_init_handle failed with error %d", res));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
static gboolean gst_svtav1enc_close(GstVideoEncoder *encoder) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "close");
|
||||
|
||||
svt_av1_enc_deinit_handle(svtav1enc->svt_encoder);
|
||||
svtav1enc->svt_encoder = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_start(GstVideoEncoder *encoder) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "start");
|
||||
|
||||
gst_svtav1enc_allocate_svt_buffers(svtav1enc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_stop(GstVideoEncoder *encoder) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "stop");
|
||||
|
||||
if (svtav1enc->state)
|
||||
gst_video_codec_state_unref(svtav1enc->state);
|
||||
svtav1enc->state = NULL;
|
||||
|
||||
svt_av1_enc_deinit(svtav1enc->svt_encoder);
|
||||
gst_svtav1enc_deallocate_svt_buffers(svtav1enc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_set_format(GstVideoEncoder *encoder, GstVideoCodecState *state) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
GstClockTime min_latency_frames = 0;
|
||||
GstCaps *src_caps = NULL;
|
||||
GstVideoCodecState *output_state;
|
||||
GST_DEBUG_OBJECT(svtav1enc, "set_format");
|
||||
|
||||
if (svtav1enc->state) {
|
||||
gst_video_codec_state_unref(svtav1enc->state);
|
||||
svt_av1_enc_deinit(svtav1enc->svt_encoder);
|
||||
}
|
||||
svtav1enc->state = gst_video_codec_state_ref(state);
|
||||
|
||||
if (!gst_svtav1enc_configure_svt(svtav1enc))
|
||||
return FALSE;
|
||||
if (!gst_svtav1enc_start_svt(svtav1enc))
|
||||
return FALSE;
|
||||
|
||||
guint32 fps = svtav1enc->svt_config->frame_rate_numerator /
|
||||
svtav1enc->svt_config->frame_rate_denominator;
|
||||
fps = fps > 120 ? 120 : fps;
|
||||
fps = fps < 24 ? 24 : fps;
|
||||
|
||||
min_latency_frames = ((fps * 5) >> 2);
|
||||
|
||||
gst_video_encoder_set_latency(encoder,
|
||||
min_latency_frames * GST_SECOND /
|
||||
(svtav1enc->svt_config->frame_rate_numerator /
|
||||
svtav1enc->svt_config->frame_rate_denominator),
|
||||
-1);
|
||||
|
||||
src_caps = gst_static_pad_template_get_caps(&gst_svtav1enc_src_pad_template);
|
||||
output_state = gst_video_encoder_set_output_state(
|
||||
GST_VIDEO_ENCODER(encoder), src_caps, svtav1enc->state);
|
||||
gst_video_codec_state_unref(output_state);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "output caps: %" GST_PTR_FORMAT, svtav1enc->state->caps);
|
||||
|
||||
return gst_video_encoder_negotiate(encoder);
|
||||
}
|
||||
|
||||
static GstFlowReturn gst_svtav1enc_handle_frame(GstVideoEncoder *encoder,
|
||||
GstVideoCodecFrame *frame) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "handle_frame");
|
||||
|
||||
ret = gst_svtav1enc_encode(svtav1enc, frame);
|
||||
gst_video_codec_frame_unref(frame);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
GST_DEBUG_OBJECT(svtav1enc, "gst_svtav1enc_encode returned %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return gst_svtav1enc_dequeue_encoded_frames(svtav1enc, FALSE, TRUE);
|
||||
}
|
||||
|
||||
static GstFlowReturn gst_svtav1enc_finish(GstVideoEncoder *encoder) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "finish");
|
||||
|
||||
gst_svtav1enc_send_eos(svtav1enc);
|
||||
|
||||
return gst_svtav1enc_dequeue_encoded_frames(svtav1enc, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static gboolean gst_svtav1enc_propose_allocation(GstVideoEncoder *encoder, GstQuery *query) {
|
||||
GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder);
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "propose_allocation");
|
||||
|
||||
gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
|
||||
|
||||
return GST_VIDEO_ENCODER_CLASS(gst_svtav1enc_parent_class)->propose_allocation(encoder, query);
|
||||
}
|
||||
|
||||
static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc) {
|
||||
gchar **key_values, **p;
|
||||
|
||||
if (!svtav1enc->parameters_string)
|
||||
return;
|
||||
|
||||
p = key_values = g_strsplit(svtav1enc->parameters_string, ":", -1);
|
||||
while (p && *p) {
|
||||
gchar *equals;
|
||||
EbErrorType res;
|
||||
|
||||
equals = strchr(*p, '=');
|
||||
if (!equals) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
*equals = '\0';
|
||||
equals++;
|
||||
|
||||
GST_DEBUG_OBJECT(svtav1enc, "Setting parameter %s=%s", *p, equals);
|
||||
|
||||
res = svt_av1_enc_parse_parameter(svtav1enc->svt_config, *p, equals);
|
||||
if (res != EB_ErrorNone) {
|
||||
GST_WARNING_OBJECT(svtav1enc, "Failed to set parameter %s=%s: %d", *p, equals, res);
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
g_strfreev(key_values);
|
||||
}
|
||||
|
||||
static gboolean plugin_init(GstPlugin *plugin) {
|
||||
return gst_element_register(plugin, "svtav1enc", GST_RANK_SECONDARY, GST_TYPE_SVTAV1ENC);
|
||||
}
|
||||
|
||||
#ifndef VERSION
|
||||
#define VERSION "1.0"
|
||||
#endif
|
||||
#ifndef PACKAGE
|
||||
#define PACKAGE "gstreamer-svt-av1"
|
||||
#endif
|
||||
#ifndef PACKAGE_NAME
|
||||
#define PACKAGE_NAME "SVT-AV1 Encoder plugin for GStreamer"
|
||||
#endif
|
||||
#ifndef GST_PACKAGE_ORIGIN
|
||||
#define GST_PACKAGE_ORIGIN "https://gitlab.com/AOMediaCodec"
|
||||
#endif
|
||||
|
||||
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, svtav1enc,
|
||||
"Scalable Video Technology for AV1 Encoder (SVT-AV1 Encoder)", plugin_init,
|
||||
VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
60
subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h
Normal file
60
subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright(c) 2019 Intel Corporation
|
||||
* Authors: Jun Tian <jun.tian@intel.com> Xavier Hallade <xavier.hallade@intel.com>
|
||||
* SPDX - License - Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef _GST_SVTAV1ENC_H_
|
||||
#define _GST_SVTAV1ENC_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/video/gstvideoencoder.h>
|
||||
|
||||
#include <EbSvtAv1.h>
|
||||
#include <EbSvtAv1Enc.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#define GST_TYPE_SVTAV1ENC (gst_svtav1enc_get_type())
|
||||
#define GST_SVTAV1ENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_SVTAV1ENC, GstSvtAv1Enc))
|
||||
#define GST_SVTAV1ENC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_SVTAV1ENC, GstSvtHevcEncClass))
|
||||
#define GST_IS_SVTAV1ENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_SVTAV1ENC))
|
||||
#define GST_IS_SVTAV1ENC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_SVTAV1ENC))
|
||||
|
||||
typedef struct _GstSvtAv1Enc {
|
||||
GstVideoEncoder video_encoder;
|
||||
|
||||
/* SVT-AV1 Encoder Handle */
|
||||
EbComponentType *svt_encoder;
|
||||
|
||||
/* GStreamer Codec state */
|
||||
GstVideoCodecState *state;
|
||||
|
||||
/* SVT-AV1 configuration */
|
||||
EbSvtAv1EncConfiguration *svt_config;
|
||||
/* Property values */
|
||||
guint preset;
|
||||
guint target_bitrate;
|
||||
guint max_bitrate;
|
||||
guint max_qp_allowed;
|
||||
guint min_qp_allowed;
|
||||
gint cqp, crf;
|
||||
guint maximum_buffer_size;
|
||||
gint intra_period_length;
|
||||
gint intra_refresh_type;
|
||||
gint logical_processors;
|
||||
gint target_socket;
|
||||
gchar *parameters_string;
|
||||
|
||||
EbBufferHeaderType *input_buf;
|
||||
} GstSvtAv1Enc;
|
||||
|
||||
typedef struct _GstSvtAv1EncClass {
|
||||
GstVideoEncoderClass video_encoder_class;
|
||||
} GstSvtAv1EncClass;
|
||||
|
||||
GType gst_svtav1enc_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif
|
54
subprojects/gst-plugins-bad/ext/svtav1/meson.build
Normal file
54
subprojects/gst-plugins-bad/ext/svtav1/meson.build
Normal file
|
@ -0,0 +1,54 @@
|
|||
# standalone plugin meson configuration
|
||||
project('gst-svt-av1', 'c',
|
||||
version : '0.1',
|
||||
meson_version : '>= 0.29',
|
||||
default_options : [ 'buildtype=debugoptimized' ])
|
||||
|
||||
# GStreamer dependencies
|
||||
gst_req = '>= 1.16'
|
||||
gst_dep = dependency('gstreamer-1.0', version : gst_req,
|
||||
fallback : ['gstreamer', 'gst_dep'])
|
||||
gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req,
|
||||
fallback : ['gstreamer', 'gstbase_dep'])
|
||||
gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req,
|
||||
fallback : ['gstreamer', 'gstvideo_dep'])
|
||||
plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir'))
|
||||
|
||||
# common meson configuration
|
||||
svtav1enc_dep = dependency('SvtAv1Enc')
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
cc_flags = [
|
||||
'-O2',
|
||||
'-D_FORTIFY_SOURCE=2',
|
||||
'-Wformat',
|
||||
'-Wformat-security',
|
||||
'-fPIE',
|
||||
'-fPIC',
|
||||
'-fstack-protector-strong',
|
||||
]
|
||||
foreach flag: cc_flags
|
||||
if cc.has_argument(flag)
|
||||
add_global_arguments(flag, language: 'c')
|
||||
endif
|
||||
endforeach
|
||||
|
||||
|
||||
ldflags = [
|
||||
'-Wl,-z,now',
|
||||
'-Wl,-z,relro',
|
||||
'-Wl,-z,noexecstack',
|
||||
]
|
||||
foreach lflag : ldflags
|
||||
add_global_link_arguments(lflag, language : 'c')
|
||||
endforeach
|
||||
|
||||
|
||||
if svtav1enc_dep.found()
|
||||
gstsvtav1enc = library('gstsvtav1enc',
|
||||
'gstsvtav1enc.c',
|
||||
dependencies: [gstbase_dep, gstvideo_dep, svtav1enc_dep],
|
||||
install: true,
|
||||
install_dir: plugins_install_dir,
|
||||
)
|
||||
endif
|
Loading…
Reference in a new issue