From 36d5e870f7b616aec3bad149e33b6b3b65b97c38 Mon Sep 17 00:00:00 2001 From: Jun Date: Fri, 29 Mar 2019 15:58:56 -0700 Subject: [PATCH 01/81] GStreamer plugin (#195) * SVT-AV1 GStreamer plugin --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1113 +++++++++++++++++ .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.h | 57 + .../gst-plugins-bad/ext/svtav1/meson.build | 54 + 3 files changed, 1224 insertions(+) create mode 100644 subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c create mode 100644 subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h create mode 100644 subprojects/gst-plugins-bad/ext/svtav1/meson.build diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c new file mode 100644 index 0000000000..6eeb739977 --- /dev/null +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -0,0 +1,1113 @@ +/* +* Copyright(c) 2019 Intel Corporation +* Authors: Jun Tian Xavier Hallade +* 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). + * + * + * Example launch line + * |[ + * 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 + * + */ + +#include +#include +#include +#include "gstsvtav1enc.h" + +GST_DEBUG_CATEGORY_STATIC (gst_svtav1enc_debug_category); +#define GST_CAT_DEFAULT gst_svtav1enc_debug_category + +/* 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_dispose (GObject * object); +static void gst_svtav1enc_finalize (GObject * object); + +gboolean gst_svtav1enc_allocate_svt_buffers (GstSvtAv1Enc * svtav1enc); +void gst_svthevenc_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 GstFlowReturn gst_svtav1enc_pre_push (GstVideoEncoder * encoder, + GstVideoCodecFrame * frame); +static GstCaps *gst_svtav1enc_getcaps (GstVideoEncoder * encoder, + GstCaps * filter); +static gboolean gst_svtav1enc_sink_event (GstVideoEncoder * encoder, + GstEvent * event); +static gboolean gst_svtav1enc_src_event (GstVideoEncoder * encoder, + GstEvent * event); +static gboolean gst_svtav1enc_negotiate (GstVideoEncoder * encoder); +static gboolean gst_svtav1enc_decide_allocation (GstVideoEncoder * encoder, + GstQuery * query); +static gboolean gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, + GstQuery * query); +static gboolean gst_svtav1enc_flush (GstVideoEncoder * encoder); + +/* helpers */ +void set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config); +gint compare_video_code_frame_and_pts (const void *video_codec_frame_ptr, + const void *pts_ptr); + +enum +{ + PROP_0, + PROP_ENCMODE, + PROP_SPEEDCONTROL, + PROP_B_PYRAMID, + PROP_P_FRAMES, + PROP_PRED_STRUCTURE, + PROP_GOP_SIZE, + PROP_INTRA_REFRESH, + PROP_QP, + PROP_QP_MAX, + PROP_QP_MIN, + PROP_DEBLOCKING, + PROP_RC_MODE, + PROP_BITRATE, + PROP_LOOKAHEAD, + PROP_SCD, + PROP_CORES, + PROP_SOCKET +}; + +#define PROP_RC_MODE_CQP 0 +#define PROP_RC_MODE_VBR 1 + +#define PROP_ENCMODE_DEFAULT 7 +#define PROP_SPEEDCONTROL_DEFAULT 60 +#define PROP_HIERARCHICAL_LEVEL_DEFAULT 4 +#define PROP_P_FRAMES_DEFAULT 0 +#define PROP_PRED_STRUCTURE_DEFAULT 2 +#define PROP_GOP_SIZE_DEFAULT -1 +#define PROP_INTRA_REFRESH_DEFAULT 1 +#define PROP_QP_DEFAULT 50 +#define PROP_DEBLOCKING_DEFAULT TRUE +#define PROP_RC_MODE_DEFAULT PROP_RC_MODE_CQP +#define PROP_BITRATE_DEFAULT 7000000 +#define PROP_QP_MAX_DEFAULT 63 +#define PROP_QP_MIN_DEFAULT 0 +#define PROP_LOOKAHEAD_DEFAULT (unsigned int)-1 +#define PROP_SCD_DEFAULT FALSE +#define PROP_AUD_DEFAULT FALSE +#define PROP_CORES_DEFAULT 0 +#define PROP_SOCKET_DEFAULT -1 + +/* 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, I420_10LE}, " + "width = (int) [64, 3840], " + "height = (int) [64, 2160], " "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) byte-stream, " + "alignment = (string) au, " + "width = (int) [64, 3840], " + "height = (int) [64, 2160], " "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, + "debug category for 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 Xavier Hallade "); + + gobject_class->set_property = gst_svtav1enc_set_property; + gobject_class->get_property = gst_svtav1enc_get_property; + gobject_class->dispose = gst_svtav1enc_dispose; + 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->pre_push = GST_DEBUG_FUNCPTR (gst_svtav1enc_pre_push); + video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_svtav1enc_getcaps); + video_encoder_class->sink_event = + GST_DEBUG_FUNCPTR (gst_svtav1enc_sink_event); + video_encoder_class->src_event = GST_DEBUG_FUNCPTR (gst_svtav1enc_src_event); + video_encoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_svtav1enc_negotiate); + video_encoder_class->decide_allocation = + GST_DEBUG_FUNCPTR (gst_svtav1enc_decide_allocation); + 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_ENCMODE, + g_param_spec_uint ("speed", "speed (Encoder Mode)", + "Quality vs density tradeoff point" + " that the encoding is to be performed at" + " (0 is the highest quality, 7 is the highest speed) ", + 0, 7, PROP_ENCMODE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + + g_object_class_install_property (gobject_class, PROP_SPEEDCONTROL, + g_param_spec_uint ("speed-control", "Speed Control (in fps)", + "Dynamically change the encoding speed preset" + " to meet this defined average encoding speed (in fps)", + 1, 240, PROP_SPEEDCONTROL_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_B_PYRAMID, + g_param_spec_uint ("hierarchical-level", "Hierarchical levels", + "3 : 4 - Level Hierarchy," + "4 : 5 - Level Hierarchy", + 3, 4, PROP_HIERARCHICAL_LEVEL_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + //g_object_class_install_property (gobject_class, PROP_P_FRAMES, + // g_param_spec_boolean ("p-frames", "P Frames", + // "Use P-frames in the base layer", + // PROP_P_FRAMES_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + //g_object_class_install_property (gobject_class, PROP_PRED_STRUCTURE, + // g_param_spec_uint ("pred-struct", "Prediction Structure", + // "0 : Low Delay P, 1 : Low Delay B" + // ", 2 : Random Access", + // 0, 2, PROP_PRED_STRUCTURE_DEFAULT, + // G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_GOP_SIZE, + g_param_spec_int ("gop-size", "GOP size", + "Period of Intra Frames insertion (-1 is auto)", + -1, 251, PROP_GOP_SIZE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH, + g_param_spec_int ("intra-refresh", "Intra refresh type", + "CRA (open GOP)" + "or IDR frames (closed GOP)", + 1, 2, PROP_INTRA_REFRESH_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_QP, + g_param_spec_uint ("qp", "Quantization parameter", + "Quantization parameter used in CQP mode", + 0, 63, PROP_QP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DEBLOCKING, + g_param_spec_boolean ("deblocking", "Deblock Filter", + "Enable Deblocking Loop Filtering", + PROP_DEBLOCKING_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_RC_MODE, + g_param_spec_uint ("rc", "Rate-control mode", + "0 : CQP, 1 : VBR", + 0, 1, PROP_RC_MODE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /* TODO: add GST_PARAM_MUTABLE_PLAYING property and handle it? */ + g_object_class_install_property (gobject_class, PROP_BITRATE, + g_param_spec_uint ("bitrate", "Target bitrate", + "Target bitrate in bits/sec. Only used when in VBR mode", + 1, G_MAXUINT, PROP_BITRATE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_QP_MAX, + g_param_spec_uint ("max-qp", "Max Quantization parameter", + "Maximum QP value allowed for rate control use" + " Only used in VBR mode.", + 0, 63, PROP_QP_MAX_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_QP_MIN, + g_param_spec_uint ("min-qp", "Min Quantization parameter", + "Minimum QP value allowed for rate control use" + " Only used in VBR mode.", + 0, 63, PROP_QP_MIN_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_LOOKAHEAD, + g_param_spec_int ("lookahead", "Look Ahead Distance", + "Number of frames to look ahead. -1 lets the encoder pick a value", + -1, 250, PROP_LOOKAHEAD_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SCD, + g_param_spec_boolean ("scd", "Scene Change Detection", + "Enable Scene Change Detection algorithm", + PROP_SCD_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CORES, + g_param_spec_uint ("cores", "Number of logical cores", + "Number of logical cores to be used. 0: auto", + 0, UINT_MAX, PROP_CORES_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SOCKET, + g_param_spec_int ("socket", "Target socket", + "Target socket to run on. -1: all available", + -1, 15, PROP_SOCKET_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_svtav1enc_init (GstSvtAv1Enc * svtav1enc) +{ + GST_OBJECT_LOCK (svtav1enc); + svtav1enc->svt_config = g_malloc (sizeof (EbSvtAv1EncConfiguration)); + if (!svtav1enc->svt_config) { + GST_ERROR_OBJECT (svtav1enc, "insufficient resources"); + GST_OBJECT_UNLOCK (svtav1enc); + return; + } + memset (&svtav1enc->svt_encoder, 0, sizeof (svtav1enc->svt_encoder)); + svtav1enc->frame_count = 0; + svtav1enc->dts_offset = 0; + + EbErrorType res = + eb_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); + if (res != EB_ErrorNone) { + GST_ERROR_OBJECT (svtav1enc, "eb_init_handle failed with error %d", res); + GST_OBJECT_UNLOCK (svtav1enc); + return; + } + /* setting configuration here since eb_init_handle overrides it */ + set_default_svt_configuration (svtav1enc->svt_config); + GST_OBJECT_UNLOCK (svtav1enc); +} + +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_ENCMODE: + svtav1enc->svt_config->enc_mode = g_value_get_uint (value); + break; + case PROP_GOP_SIZE: + svtav1enc->svt_config->intra_period_length = g_value_get_int(value) - 1; + break; + case PROP_INTRA_REFRESH: + svtav1enc->svt_config->intra_refresh_type = g_value_get_int(value); + break; + case PROP_SPEEDCONTROL: + if (g_value_get_uint (value) > 0) { + svtav1enc->svt_config->injector_frame_rate = g_value_get_uint (value); + svtav1enc->svt_config->speed_control_flag = 1; + } else { + svtav1enc->svt_config->injector_frame_rate = 60 << 16; + svtav1enc->svt_config->speed_control_flag = 0; + } + break; + case PROP_B_PYRAMID: + svtav1enc->svt_config->hierarchical_levels = g_value_get_uint (value); + break; + case PROP_PRED_STRUCTURE: + svtav1enc->svt_config->pred_structure = g_value_get_uint(value); + break; + case PROP_P_FRAMES: + svtav1enc->svt_config->base_layer_switch_mode = g_value_get_boolean (value); + break; + case PROP_QP: + svtav1enc->svt_config->qp = g_value_get_uint (value); + break; + case PROP_DEBLOCKING: + svtav1enc->svt_config->disable_dlf_flag = !g_value_get_boolean (value); + break; + case PROP_RC_MODE: + svtav1enc->svt_config->rate_control_mode = g_value_get_uint (value); + break; + case PROP_BITRATE: + svtav1enc->svt_config->target_bit_rate = g_value_get_uint (value) * 1000; + break; + case PROP_QP_MAX: + svtav1enc->svt_config->max_qp_allowed = g_value_get_uint (value); + break; + case PROP_QP_MIN: + svtav1enc->svt_config->min_qp_allowed = g_value_get_uint (value); + break; + case PROP_LOOKAHEAD: + svtav1enc->svt_config->look_ahead_distance = + (unsigned int)g_value_get_int(value); + break; + case PROP_SCD: + svtav1enc->svt_config->scene_change_detection = + g_value_get_boolean (value); + break; + case PROP_CORES: + svtav1enc->svt_config->logical_processors = g_value_get_uint (value); + break; + case PROP_SOCKET: + svtav1enc->svt_config->target_socket = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +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_ENCMODE: + g_value_set_uint (value, svtav1enc->svt_config->enc_mode); + break; + case PROP_SPEEDCONTROL: + if (svtav1enc->svt_config->speed_control_flag) { + g_value_set_uint (value, svtav1enc->svt_config->injector_frame_rate); + } else { + g_value_set_uint (value, 0); + } + break; + case PROP_B_PYRAMID: + g_value_set_uint (value, svtav1enc->svt_config->hierarchical_levels); + break; + case PROP_P_FRAMES: + g_value_set_boolean (value, + svtav1enc->svt_config->base_layer_switch_mode == 1); + break; + case PROP_PRED_STRUCTURE: + g_value_set_uint (value, svtav1enc->svt_config->pred_structure); + break; + case PROP_GOP_SIZE: + g_value_set_int (value, svtav1enc->svt_config->intra_period_length + 1); + break; + case PROP_INTRA_REFRESH: + g_value_set_int(value, svtav1enc->svt_config->intra_refresh_type); + break; + case PROP_QP: + g_value_set_uint (value, svtav1enc->svt_config->qp); + break; + case PROP_DEBLOCKING: + g_value_set_boolean (value, svtav1enc->svt_config->disable_dlf_flag == 0); + break; + case PROP_RC_MODE: + g_value_set_uint (value, svtav1enc->svt_config->rate_control_mode); + break; + case PROP_BITRATE: + g_value_set_uint (value, svtav1enc->svt_config->target_bit_rate / 1000); + break; + case PROP_QP_MAX: + g_value_set_uint (value, svtav1enc->svt_config->max_qp_allowed); + break; + case PROP_QP_MIN: + g_value_set_uint (value, svtav1enc->svt_config->min_qp_allowed); + break; + case PROP_LOOKAHEAD: + g_value_set_int(value, (int)svtav1enc->svt_config->look_ahead_distance); + break; + case PROP_SCD: + g_value_set_boolean (value, + svtav1enc->svt_config->scene_change_detection == 1); + break; + case PROP_CORES: + g_value_set_uint (value, svtav1enc->svt_config->logical_processors); + break; + case PROP_SOCKET: + g_value_set_int (value, svtav1enc->svt_config->target_socket); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_svtav1enc_dispose (GObject * object) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (object); + + GST_DEBUG_OBJECT (svtav1enc, "dispose"); + + /* clean up as possible. may be called multiple times */ + if (svtav1enc->state) + gst_video_codec_state_unref (svtav1enc->state); + svtav1enc->state = NULL; + + G_OBJECT_CLASS (gst_svtav1enc_parent_class)->dispose (object); +} + +void +gst_svtav1enc_finalize (GObject * object) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (object); + + GST_DEBUG_OBJECT (svtav1enc, "finalizing svtav1enc"); + + GST_OBJECT_LOCK (svtav1enc); + eb_deinit_handle(svtav1enc->svt_encoder); + svtav1enc->svt_encoder = NULL; + g_free (svtav1enc->svt_config); + GST_OBJECT_UNLOCK (svtav1enc); + + G_OBJECT_CLASS (gst_svtav1enc_parent_class)->finalize (object); +} + +gboolean +gst_svtav1enc_allocate_svt_buffers (GstSvtAv1Enc * svtav1enc) +{ + svtav1enc->input_buf = g_malloc (sizeof (EbBufferHeaderType)); + if (!svtav1enc->input_buf) { + GST_ERROR_OBJECT (svtav1enc, "insufficient resources"); + return FALSE; + } + svtav1enc->input_buf->p_buffer = g_malloc (sizeof (EbSvtIOFormat)); + if (!svtav1enc->input_buf->p_buffer) { + GST_ERROR_OBJECT (svtav1enc, "insufficient resources"); + return FALSE; + } + memset(svtav1enc->input_buf->p_buffer, 0, sizeof(EbSvtIOFormat)); + svtav1enc->input_buf->size = sizeof (EbBufferHeaderType); + svtav1enc->input_buf->p_app_private = NULL; + svtav1enc->input_buf->pic_type = EB_AV1_INVALID_PICTURE; + + return TRUE; +} + +void +gst_svthevenc_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; + } +} + +gboolean +gst_svtav1enc_configure_svt (GstSvtAv1Enc * svtav1enc) +{ + if (!svtav1enc->state) { + GST_WARNING_OBJECT (svtav1enc, "no state, can't configure encoder yet"); + return FALSE; + } + + /* set properties out of GstVideoInfo */ + 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; + svtav1enc->svt_config->frame_rate = + svtav1enc->svt_config->frame_rate_numerator / + svtav1enc->svt_config->frame_rate_denominator; + + if (svtav1enc->svt_config->frame_rate < 1000) { + svtav1enc->svt_config->frame_rate = svtav1enc->svt_config->frame_rate << 16; + } + + GST_LOG_OBJECT(svtav1enc, "width %d, height %d, framerate %d", svtav1enc->svt_config->source_width, svtav1enc->svt_config->source_height, svtav1enc->svt_config->frame_rate); + + /* pick a default value for the look ahead distance + * in CQP mode:2*minigop+1. in VBR: intra Period */ + if (svtav1enc->svt_config->look_ahead_distance == (unsigned int) -1) { + svtav1enc->svt_config->look_ahead_distance = + (svtav1enc->svt_config->rate_control_mode == PROP_RC_MODE_VBR) ? + svtav1enc->svt_config->intra_period_length : + 2 * (1 << svtav1enc->svt_config->hierarchical_levels) + 1; + } + + /* TODO: better handle HDR metadata when GStreamer will have such support + * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/400 */ + if (GST_VIDEO_INFO_COLORIMETRY (info).matrix == GST_VIDEO_COLOR_MATRIX_BT2020 + && GST_VIDEO_INFO_COMP_DEPTH (info, 0) > 8) { + svtav1enc->svt_config->high_dynamic_range_input = TRUE; + } + + EbErrorType res = + eb_svt_enc_set_parameter(svtav1enc->svt_encoder, svtav1enc->svt_config); + if (res != EB_ErrorNone) { + GST_ERROR_OBJECT (svtav1enc, "eb_svt_enc_set_parameter failed with error %d", res); + return FALSE; + } + return TRUE; +} + +gboolean +gst_svtav1enc_start_svt (GstSvtAv1Enc * svtav1enc) +{ + G_LOCK (init_mutex); + EbErrorType res = eb_init_encoder(svtav1enc->svt_encoder); + G_UNLOCK (init_mutex); + + if (res != EB_ErrorNone) { + GST_ERROR_OBJECT (svtav1enc, "eb_init_encoder failed with error %d", res); + return FALSE; + } + return TRUE; +} + +void +set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) +{ + memset(svt_config, 0, sizeof(EbSvtAv1EncConfiguration)); + svt_config->source_width = 0; + svt_config->source_height = 0; + svt_config->intra_period_length = PROP_GOP_SIZE_DEFAULT - 1; + svt_config->intra_refresh_type = PROP_INTRA_REFRESH_DEFAULT; + svt_config->enc_mode = PROP_ENCMODE_DEFAULT; + svt_config->frame_rate = 25; + svt_config->frame_rate_denominator = 1; + svt_config->frame_rate_numerator = 25; + svt_config->hierarchical_levels = PROP_HIERARCHICAL_LEVEL_DEFAULT; + svt_config->base_layer_switch_mode = PROP_P_FRAMES_DEFAULT; + svt_config->pred_structure = PROP_PRED_STRUCTURE_DEFAULT; + svt_config->scene_change_detection = PROP_SCD_DEFAULT; + svt_config->look_ahead_distance = (uint32_t)~0; + svt_config->frames_to_be_encoded = 0; + svt_config->rate_control_mode = PROP_RC_MODE_DEFAULT; + svt_config->target_bit_rate = PROP_BITRATE_DEFAULT; + svt_config->max_qp_allowed = PROP_QP_MAX_DEFAULT; + svt_config->min_qp_allowed = PROP_QP_MIN_DEFAULT; + svt_config->qp = PROP_QP_DEFAULT; + svt_config->use_qp_file = FALSE; + svt_config->disable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == FALSE); + svt_config->enable_denoise_flag = FALSE; + svt_config->film_grain_denoise_strength = FALSE; + svt_config->enable_warped_motion = FALSE; + svt_config->use_default_me_hme = TRUE; + svt_config->enable_hme_flag = TRUE; + svt_config->enable_hme_level0_flag = TRUE; + svt_config->enable_hme_level1_flag = FALSE; + svt_config->enable_hme_level2_flag = FALSE; + svt_config->ext_block_flag = FALSE; + svt_config->in_loop_me_flag = TRUE; + svt_config->search_area_width = 16; + svt_config->search_area_height = 7; + svt_config->number_hme_search_region_in_width = 2; + svt_config->number_hme_search_region_in_height = 2; + svt_config->hme_level0_total_search_area_width = 64; + svt_config->hme_level0_total_search_area_height = 25; + svt_config->hme_level0_search_area_in_width_array[0] = 32; + svt_config->hme_level0_search_area_in_width_array[1] = 32; + svt_config->hme_level0_search_area_in_height_array[0] = 12; + svt_config->hme_level0_search_area_in_height_array[1] = 13; + svt_config->hme_level1_search_area_in_width_array[0] = 1; + svt_config->hme_level1_search_area_in_width_array[1] = 1; + svt_config->hme_level1_search_area_in_height_array[0] = 1; + svt_config->hme_level1_search_area_in_height_array[1] = 1; + svt_config->hme_level2_search_area_in_width_array[0] = 1; + svt_config->hme_level2_search_area_in_width_array[1] = 1; + svt_config->hme_level2_search_area_in_height_array[0] = 1; + svt_config->hme_level2_search_area_in_height_array[1] = 1; + svt_config->channel_id = 0; + svt_config->active_channel_count = 1; + svt_config->logical_processors = PROP_CORES_DEFAULT; + svt_config->target_socket = PROP_SOCKET_DEFAULT; + svt_config->recon_enabled = FALSE; + //svt_config->tile_columns = 0; + //svt_config->tile_rows = 0; + svt_config->stat_report = FALSE; + svt_config->improve_sharpness = FALSE; + svt_config->high_dynamic_range_input = FALSE; + svt_config->encoder_bit_depth = 8; + svt_config->compressed_ten_bit_format = FALSE; + svt_config->profile = 0; + svt_config->tier = 0; + svt_config->level = 0; + svt_config->injector_frame_rate = PROP_SPEEDCONTROL_DEFAULT; + svt_config->speed_control_flag = FALSE; + svt_config->sb_sz = 64; + svt_config->super_block_size = 128; + svt_config->partition_depth = 4; + svt_config->enable_qp_scaling_flag = 0; + svt_config->asm_type = 1; +} + +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_ERROR_OBJECT (svtav1enc, "couldn't map input frame"); + return GST_FLOW_ERROR; + } + + input_picture_buffer->yStride = + GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, + 0) / GST_VIDEO_FRAME_COMP_PSTRIDE (&video_frame, 0); + input_picture_buffer->cbStride = + GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, + 1) / GST_VIDEO_FRAME_COMP_PSTRIDE (&video_frame, 1); + input_picture_buffer->crStride = + 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 = (void *) frame; + 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; + } + + res = eb_svt_enc_send_picture(svtav1enc->svt_encoder, input_buffer); + if (res != EB_ErrorNone) { + GST_ERROR_OBJECT (svtav1enc, "Issue %d sending picture to SVT-AV1.", res); + ret = GST_FLOW_ERROR; + } + gst_video_frame_unmap (&video_frame); + + return ret; +} + +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; + + ret = eb_svt_enc_send_picture(svtav1enc->svt_encoder, &input_buffer); + + if (ret != EB_ErrorNone) { + GST_ERROR_OBJECT (svtav1enc, "couldn't send EOS frame."); + return FALSE; + } + + return (ret == EB_ErrorNone); +} + +gboolean +gst_svtav1enc_flush (GstVideoEncoder * encoder) +{ + GstFlowReturn ret = + gst_svtav1enc_dequeue_encoded_frames (GST_SVTAV1ENC (encoder), TRUE, + FALSE); + + return (ret != GST_FLOW_ERROR); +} + +gint +compare_video_code_frame_and_pts (const void *video_codec_frame_ptr, + const void *pts_ptr) +{ + return ((GstVideoCodecFrame *) video_codec_frame_ptr)->pts - + *((GstClockTime *) pts_ptr); +} + +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 { + GList *pending_frames = NULL; + GList *frame_list_element = NULL; + GstVideoCodecFrame *frame = NULL; + EbBufferHeaderType *output_buf = NULL; + + res = + eb_svt_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_ERROR_OBJECT (svtav1enc, "Error while encoding, return\n"); + return GST_FLOW_ERROR; + } else if (res != EB_NoErrorEmptyQueue && output_frames && output_buf) { + /* if p_app_private is indeed propagated, get the frame through it + * it's not currently the case with SVT-AV1 + * so we fallback on using its PTS to find it back */ + if (output_buf->p_app_private) { + frame = (GstVideoCodecFrame *) output_buf->p_app_private; + } else { + pending_frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER + (svtav1enc)); + frame_list_element = g_list_find_custom (pending_frames, + &output_buf->pts, compare_video_code_frame_and_pts); + + if (frame_list_element == NULL) + return GST_FLOW_ERROR; + + frame = (GstVideoCodecFrame *) frame_list_element->data; + } + + 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); + } + + frame->output_buffer = + gst_buffer_new_allocate (NULL, output_buf->n_filled_len, NULL); + GST_BUFFER_FLAG_SET(frame->output_buffer, GST_BUFFER_FLAG_LIVE); + gst_buffer_fill (frame->output_buffer, 0, + output_buf->p_buffer, output_buf->n_filled_len); + + + /* SVT-AV1 may return first frames with a negative DTS, + * offsetting it to start at 0 since GStreamer 1.x doesn't support it */ + if (output_buf->dts + svtav1enc->dts_offset < 0) { + svtav1enc->dts_offset = -output_buf->dts; + } + /* Gstreamer doesn't support negative DTS so we return + * very small increasing ones for the first frames. */ + if (output_buf->dts < 1) { + frame->dts = frame->output_buffer->dts = + output_buf->dts + svtav1enc->dts_offset; + } else { + frame->dts = frame->output_buffer->dts = + (output_buf->dts * + svtav1enc->svt_config->frame_rate_denominator * GST_SECOND) / + svtav1enc->svt_config->frame_rate_numerator; + } + + frame->pts = frame->output_buffer->pts = output_buf->pts; + + GST_LOG_OBJECT (svtav1enc, "#frame:%lld dts:%" G_GINT64_FORMAT " pts:%" + G_GINT64_FORMAT " SliceType:%d\n", svtav1enc->frame_count, + (frame->dts), (frame->pts), output_buf->pic_type); + + eb_svt_release_out_buffer(&output_buf); + output_buf = NULL; + + ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (svtav1enc), frame); + + if (pending_frames != NULL) { + g_list_free_full (pending_frames, + (GDestroyNotify) gst_video_codec_frame_unref); + } + + svtav1enc->frame_count++; + } + + } while (res == EB_ErrorNone && !encode_at_eos); + + return ret; +} + +static gboolean +gst_svtav1enc_open (GstVideoEncoder * encoder) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "open"); + + return TRUE; +} + +static gboolean +gst_svtav1enc_close (GstVideoEncoder * encoder) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "close"); + + return TRUE; +} + +static gboolean +gst_svtav1enc_start (GstVideoEncoder * encoder) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "start"); + /* starting the encoder is done in set_format, + * once caps are fully negotiated */ + + return TRUE; +} + +static gboolean +gst_svtav1enc_stop (GstVideoEncoder * encoder) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "stop"); + + GstVideoCodecFrame *remaining_frame = NULL; + while ((remaining_frame = + gst_video_encoder_get_oldest_frame (encoder)) != NULL) { + GST_WARNING_OBJECT (svtav1enc, + "encoder is being stopped, dropping frame %d", + remaining_frame->system_frame_number); + remaining_frame->output_buffer = NULL; + gst_video_encoder_finish_frame (encoder, remaining_frame); + } + + GST_OBJECT_LOCK (svtav1enc); + if (svtav1enc->state) + gst_video_codec_state_unref (svtav1enc->state); + svtav1enc->state = NULL; + GST_OBJECT_UNLOCK (svtav1enc); + + GST_OBJECT_LOCK (svtav1enc); + eb_deinit_encoder(svtav1enc->svt_encoder); + /* Destruct the buffer memory pool */ + gst_svthevenc_deallocate_svt_buffers (svtav1enc); + GST_OBJECT_UNLOCK (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; + GST_DEBUG_OBJECT (svtav1enc, "set_format"); + + /* TODO: handle configuration changes while encoder is running + * and if there was already a state. */ + svtav1enc->state = gst_video_codec_state_ref (state); + + gst_svtav1enc_configure_svt (svtav1enc); + gst_svtav1enc_allocate_svt_buffers (svtav1enc); + gst_svtav1enc_start_svt (svtav1enc); + + uint32_t fps = (uint32_t)((svtav1enc->svt_config->frame_rate > 1000) ? + svtav1enc->svt_config->frame_rate >> 16 : svtav1enc->svt_config->frame_rate); + fps = fps > 120 ? 120 : fps; + fps = fps < 24 ? 24 : fps; + + min_latency_frames = svtav1enc->svt_config->look_ahead_distance + ((fps * 5) >> 2); + + /* TODO: find a better value for max_latency */ + gst_video_encoder_set_latency (encoder, + min_latency_frames * GST_SECOND / svtav1enc->svt_config->frame_rate, + 3 * GST_SECOND); + + src_caps = + gst_static_pad_template_get_caps (&gst_svtav1enc_src_pad_template); + gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder), src_caps, + svtav1enc->state); + gst_caps_unref (src_caps); + + GST_DEBUG_OBJECT (svtav1enc, "output caps: %" GST_PTR_FORMAT, + svtav1enc->state->caps); + + return TRUE; +} + +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); + 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 GstFlowReturn +gst_svtav1enc_pre_push (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "pre_push"); + + return GST_FLOW_OK; +} + +static GstCaps * +gst_svtav1enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "getcaps"); + + GstCaps *sink_caps = + gst_static_pad_template_get_caps (&gst_svtav1enc_sink_pad_template); + GstCaps *ret = + gst_video_encoder_proxy_getcaps (GST_VIDEO_ENCODER (svtav1enc), + sink_caps, filter); + gst_caps_unref (sink_caps); + + return ret; +} + +static gboolean +gst_svtav1enc_sink_event (GstVideoEncoder * encoder, GstEvent * event) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "sink_event"); + + return + GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->sink_event + (encoder, event); +} + +static gboolean +gst_svtav1enc_src_event (GstVideoEncoder * encoder, GstEvent * event) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "src_event"); + + return + GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->src_event (encoder, + event); +} + +static gboolean +gst_svtav1enc_negotiate (GstVideoEncoder * encoder) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "negotiate"); + + return + GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->negotiate(encoder); +} + +static gboolean +gst_svtav1enc_decide_allocation (GstVideoEncoder * encoder, GstQuery * query) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "decide_allocation"); + + return TRUE; +} + +static gboolean +gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) +{ + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); + + GST_DEBUG_OBJECT (svtav1enc, "propose_allocation"); + + return TRUE; +} + +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://github.com/OpenVisualCloud" +#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) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h new file mode 100644 index 0000000000..8ad8a9bcf3 --- /dev/null +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h @@ -0,0 +1,57 @@ +/* +* Copyright(c) 2019 Intel Corporation +* Authors: Jun Tian Xavier Hallade +* SPDX - License - Identifier: LGPL-2.1-or-later +*/ + +#ifndef _GST_SVTAV1ENC_H_ +#define _GST_SVTAV1ENC_H_ + +#include +#include +#include + +#include +#include + + +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; + + EbBufferHeaderType *input_buf; + + long long int frame_count; + int dts_offset; +} GstSvtAv1Enc; + +typedef struct _GstSvtAv1EncClass +{ + GstVideoEncoderClass video_encoder_class; +} GstSvtAv1EncClass; + +GType gst_svtav1enc_get_type (void); + +G_END_DECLS +#endif diff --git a/subprojects/gst-plugins-bad/ext/svtav1/meson.build b/subprojects/gst-plugins-bad/ext/svtav1/meson.build new file mode 100644 index 0000000000..a792a10d88 --- /dev/null +++ b/subprojects/gst-plugins-bad/ext/svtav1/meson.build @@ -0,0 +1,54 @@ +# standalone plugin meson configuration +project('gst-svt-av1', 'c', + version : '0.1', + meson_version : '>= 0.29', + default_options : [ 'buildtype=debugoptimized' ]) + +# standard gst-plugins-bad dependencies and configuration +gst_req = '>= 1.15.1' +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 From 64fcdea75099d09c8e5ae1521d8c887611f7804a Mon Sep 17 00:00:00 2001 From: adixonn <44004742+adixonn@users.noreply.github.com> Date: Mon, 1 Apr 2019 13:33:35 -0700 Subject: [PATCH 02/81] Coding style updates to ASM folders and ~25% of Codec folder header files (#206) Coding style cleanups --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 6eeb739977..243296b50c 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -696,13 +696,13 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) return GST_FLOW_ERROR; } - input_picture_buffer->yStride = + input_picture_buffer->y_stride = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 0) / GST_VIDEO_FRAME_COMP_PSTRIDE (&video_frame, 0); - input_picture_buffer->cbStride = + input_picture_buffer->cb_stride = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 1) / GST_VIDEO_FRAME_COMP_PSTRIDE (&video_frame, 1); - input_picture_buffer->crStride = + input_picture_buffer->cr_stride = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 2) / GST_VIDEO_FRAME_COMP_PSTRIDE (&video_frame, 2); From a1bb4238312930855bd47260e85c08ea55a34f43 Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Tue, 11 Jun 2019 22:02:30 -0500 Subject: [PATCH 03/81] cleanup: tabs2fourSpaces, remove trailing spaces --- subprojects/gst-plugins-bad/ext/svtav1/meson.build | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/meson.build b/subprojects/gst-plugins-bad/ext/svtav1/meson.build index a792a10d88..bbf0e73534 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/meson.build +++ b/subprojects/gst-plugins-bad/ext/svtav1/meson.build @@ -40,15 +40,15 @@ ldflags = [ '-Wl,-z,noexecstack', ] foreach lflag : ldflags - add_global_link_arguments(lflag, language : 'c') + 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, - ) + gstsvtav1enc = library('gstsvtav1enc', + 'gstsvtav1enc.c', + dependencies: [gstbase_dep, gstvideo_dep, svtav1enc_dep], + install: true, + install_dir: plugins_install_dir, + ) endif From 555582bd5a14de70654eccad196421c3ff81838e Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Wed, 12 Jun 2019 00:23:14 -0500 Subject: [PATCH 04/81] gstreamer: add spaces between title and blocks From 343d8749e7f5973a085d2e9142133a9b1564878e Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Wed, 12 Jun 2019 00:24:20 -0500 Subject: [PATCH 05/81] gstreamer: add ` around libs and PATH, right format list From 0e75921cbe4550fa7e93d88a7335cd09d2638da2 Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Wed, 12 Jun 2019 00:27:08 -0500 Subject: [PATCH 06/81] gstreamer: codeblocks for usage From 622ac14e7a20bf829e82f0b7cf6576e59cd2581c Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Wed, 12 Jun 2019 00:28:40 -0500 Subject: [PATCH 07/81] gstreamer: shift right build deps and use sudo apt for debian/ubuntu From bae3f1d398cae6636158354c46dfdca96925e6c6 Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Wed, 12 Jun 2019 00:30:17 -0500 Subject: [PATCH 08/81] gstreamer: code blocks for linux instructions From b1b874f147f4410e915864d4697cb5ae58f17100 Mon Sep 17 00:00:00 2001 From: Chris Degawa Date: Wed, 12 Jun 2019 00:32:28 -0500 Subject: [PATCH 09/81] gstreamer: code blocks for windows instruction From c3411de7c9ceb1d7afdb788a5202f8ae4679368e Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:19:05 -0500 Subject: [PATCH 10/81] gstreamer CMake: set build_type before project From c452a98d506a21acad159bed3cf531b6095749a6 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:19:44 -0500 Subject: [PATCH 11/81] gstreamer CMake: include checkcompilerflag From 1080c4d6a180654c7ea3995249a9d1fb40b07c82 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:21:49 -0500 Subject: [PATCH 12/81] gstreamer CMake: move pkg_check_modules together From e5c6a5d1cd78389a2acaffcda77372f6e4450019 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:25:25 -0500 Subject: [PATCH 13/81] gstreamer CMake: condense include dirs From 8360dfefd5cff363fec2e6f267cd19b445591fa5 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:27:20 -0500 Subject: [PATCH 14/81] gstreamer CMake: add POSITION_INDEPENDENT_CODE From 1b15a9b3654643b133d12a9b617b9d3212f6acc0 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:27:37 -0500 Subject: [PATCH 15/81] gstreamer CMake: set cflags From 0cee47c7b88c86bea8cb4c1ffce5238c51172a62 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 30 May 2019 11:27:56 -0500 Subject: [PATCH 16/81] gstreamer CMake: cosmetic changes From f43cc84340730efed85585a54aa792af55b05100 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Tue, 24 Sep 2019 21:53:51 +0000 Subject: [PATCH 17/81] Port to FreeBSD and maybe more (#162) * Make Unix conditionals the fallback Provides a clear path what needs to be ported if the system is neither Windows nor POSIX-like. If the difference from Linux is minor like on macOS or BSDs then new conditionals can be added on case-by-case basis. * gstreamer-plugin: sync Meson version check with CMake * gstreamer-plugin: don't assume CMake can find libs by default --- subprojects/gst-plugins-bad/ext/svtav1/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/meson.build b/subprojects/gst-plugins-bad/ext/svtav1/meson.build index bbf0e73534..8a2d2a6e35 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/meson.build +++ b/subprojects/gst-plugins-bad/ext/svtav1/meson.build @@ -5,7 +5,7 @@ project('gst-svt-av1', 'c', default_options : [ 'buildtype=debugoptimized' ]) # standard gst-plugins-bad dependencies and configuration -gst_req = '>= 1.15.1' +gst_req = '>= 1.8' gst_dep = dependency('gstreamer-1.0', version : gst_req, fallback : ['gstreamer', 'gst_dep']) gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req, From 7ebe9db06e471c5cab1366755a78a930e87972d1 Mon Sep 17 00:00:00 2001 From: JackZhouVCD <50381776+JackZhouVCD@users.noreply.github.com> Date: Tue, 24 Sep 2019 16:15:06 -0700 Subject: [PATCH 18/81] Remove ImproveSharpness Feature (#634) * remove ImproveSharpness feature * remove use_delta_qp and useDeltaQpSegments (both unused) --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 243296b50c..e7b1a2d5b8 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -664,7 +664,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) //svt_config->tile_columns = 0; //svt_config->tile_rows = 0; svt_config->stat_report = FALSE; - svt_config->improve_sharpness = FALSE; svt_config->high_dynamic_range_input = FALSE; svt_config->encoder_bit_depth = 8; svt_config->compressed_ten_bit_format = FALSE; From 0032aea50b1fbe000bbaba8641c60071b5ea79f9 Mon Sep 17 00:00:00 2001 From: Slawomir Pawlowski Date: Mon, 4 Nov 2019 22:59:57 +0100 Subject: [PATCH 19/81] Add optimization level "-asm" to limit cpu features at runtime --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index e7b1a2d5b8..0252d92373 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -676,7 +676,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->super_block_size = 128; svt_config->partition_depth = 4; svt_config->enable_qp_scaling_flag = 0; - svt_config->asm_type = 1; + svt_config->use_cpu_flags = CPU_FLAGS_ALL; } GstFlowReturn From d384bf5a86ca309817f1be25e7015b2834cdded3 Mon Sep 17 00:00:00 2001 From: "Zhou, Jack" Date: Sun, 22 Dec 2019 23:01:47 -0800 Subject: [PATCH 20/81] Remove dead-code and address snake_case violations and apply Clang format when possible Remove dead code Address some snake_case PascalCase violations for variables, functions, enums and types Rename lcu fields to sb Rename tu fields to txb Rename cu fields to blk Shorten variable names in prep to apply clang format: e.g. - picture_control_set_ptr -- > pcs_ptr - sequence_control_set_ptr -- > scs_ptr Remove RawStringFormats property from clang-format until it's fixed Apply clang-format on files in source/lib/encoder/codec/ except: - aom_dsp_rtcd.c - aom_dsp_rtcd.h - EbMdRateEstimation.h - EbIntraPrediction.c - EbModeDecisionConfiguration.c - EbMotionEstimation.h - EbPictureDecisionProcess.c - EbRateControlTables.c - EbQMatrices.h - EbEncHandle.c --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 0252d92373..58a0f82f37 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -620,7 +620,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->pred_structure = PROP_PRED_STRUCTURE_DEFAULT; svt_config->scene_change_detection = PROP_SCD_DEFAULT; svt_config->look_ahead_distance = (uint32_t)~0; - svt_config->frames_to_be_encoded = 0; svt_config->rate_control_mode = PROP_RC_MODE_DEFAULT; svt_config->target_bit_rate = PROP_BITRATE_DEFAULT; svt_config->max_qp_allowed = PROP_QP_MAX_DEFAULT; From 075d42ef9893dd558687f4d334c6388331266f11 Mon Sep 17 00:00:00 2001 From: Omran Date: Wed, 5 Feb 2020 10:43:26 -0800 Subject: [PATCH 21/81] Improve help menu: Format and improve help menu update cfg file and user guide to be conformant to the help menu --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 58a0f82f37..57b7fe8b68 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -363,9 +363,9 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, case PROP_PRED_STRUCTURE: svtav1enc->svt_config->pred_structure = g_value_get_uint(value); break; - case PROP_P_FRAMES: - svtav1enc->svt_config->base_layer_switch_mode = g_value_get_boolean (value); - break; + + + case PROP_QP: svtav1enc->svt_config->qp = g_value_get_uint (value); break; @@ -426,10 +426,10 @@ gst_svtav1enc_get_property (GObject * object, guint property_id, case PROP_B_PYRAMID: g_value_set_uint (value, svtav1enc->svt_config->hierarchical_levels); break; - case PROP_P_FRAMES: - g_value_set_boolean (value, - svtav1enc->svt_config->base_layer_switch_mode == 1); - break; + + + + case PROP_PRED_STRUCTURE: g_value_set_uint (value, svtav1enc->svt_config->pred_structure); break; @@ -616,7 +616,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->frame_rate_denominator = 1; svt_config->frame_rate_numerator = 25; svt_config->hierarchical_levels = PROP_HIERARCHICAL_LEVEL_DEFAULT; - svt_config->base_layer_switch_mode = PROP_P_FRAMES_DEFAULT; + svt_config->pred_structure = PROP_PRED_STRUCTURE_DEFAULT; svt_config->scene_change_detection = PROP_SCD_DEFAULT; svt_config->look_ahead_distance = (uint32_t)~0; From 9f90c74d3c8ae84cbcd7bbf5c9fadd78745f41f2 Mon Sep 17 00:00:00 2001 From: elenril Date: Wed, 15 Apr 2020 21:22:54 +0200 Subject: [PATCH 22/81] [RFC] consistent namespacing for public API functions (#951) * EbSvtAv1Dec.h: remove prototype for non-existent functions Those functions have apparently never existed in the tree: - eb_peek_sequence_header() - eb_svt_decode_obu() - eb_svt_decode_tu() - eb_dec_flush() - eb_get_stream_info() * EbSvtAv1Dec.h: consistently use the svt_av1_dec_ namespace for public functions * EbSvtAv1Enc.h: consistently use the svt_av1_enc_ namespace for public functions --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 57b7fe8b68..d66167a2e3 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -312,13 +312,13 @@ gst_svtav1enc_init (GstSvtAv1Enc * svtav1enc) svtav1enc->dts_offset = 0; EbErrorType res = - eb_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); + svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "eb_init_handle failed with error %d", res); + GST_ERROR_OBJECT (svtav1enc, "svt_av1_enc_init_handle failed with error %d", res); GST_OBJECT_UNLOCK (svtav1enc); return; } - /* setting configuration here since eb_init_handle overrides it */ + /* setting configuration here since svt_av1_enc_init_handle overrides it */ set_default_svt_configuration (svtav1enc->svt_config); GST_OBJECT_UNLOCK (svtav1enc); } @@ -499,7 +499,7 @@ gst_svtav1enc_finalize (GObject * object) GST_DEBUG_OBJECT (svtav1enc, "finalizing svtav1enc"); GST_OBJECT_LOCK (svtav1enc); - eb_deinit_handle(svtav1enc->svt_encoder); + svt_av1_enc_deinit_handle(svtav1enc->svt_encoder); svtav1enc->svt_encoder = NULL; g_free (svtav1enc->svt_config); GST_OBJECT_UNLOCK (svtav1enc); @@ -581,9 +581,9 @@ gst_svtav1enc_configure_svt (GstSvtAv1Enc * svtav1enc) } EbErrorType res = - eb_svt_enc_set_parameter(svtav1enc->svt_encoder, svtav1enc->svt_config); + svt_av1_enc_set_parameter(svtav1enc->svt_encoder, svtav1enc->svt_config); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "eb_svt_enc_set_parameter failed with error %d", res); + GST_ERROR_OBJECT (svtav1enc, "svt_av1_enc_set_parameter failed with error %d", res); return FALSE; } return TRUE; @@ -593,11 +593,11 @@ gboolean gst_svtav1enc_start_svt (GstSvtAv1Enc * svtav1enc) { G_LOCK (init_mutex); - EbErrorType res = eb_init_encoder(svtav1enc->svt_encoder); + EbErrorType res = svt_av1_enc_init(svtav1enc->svt_encoder); G_UNLOCK (init_mutex); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "eb_init_encoder failed with error %d", res); + GST_ERROR_OBJECT (svtav1enc, "svt_av1_enc_init failed with error %d", res); return FALSE; } return TRUE; @@ -720,7 +720,7 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) input_buffer->pic_type = EB_AV1_KEY_PICTURE; } - res = eb_svt_enc_send_picture(svtav1enc->svt_encoder, input_buffer); + res = svt_av1_enc_send_picture(svtav1enc->svt_encoder, input_buffer); if (res != EB_ErrorNone) { GST_ERROR_OBJECT (svtav1enc, "Issue %d sending picture to SVT-AV1.", res); ret = GST_FLOW_ERROR; @@ -743,7 +743,7 @@ gst_svtav1enc_send_eos (GstSvtAv1Enc * svtav1enc) input_buffer.flags = EB_BUFFERFLAG_EOS; input_buffer.p_buffer = NULL; - ret = eb_svt_enc_send_picture(svtav1enc->svt_encoder, &input_buffer); + ret = svt_av1_enc_send_picture(svtav1enc->svt_encoder, &input_buffer); if (ret != EB_ErrorNone) { GST_ERROR_OBJECT (svtav1enc, "couldn't send EOS frame."); @@ -786,7 +786,7 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, EbBufferHeaderType *output_buf = NULL; res = - eb_svt_get_packet(svtav1enc->svt_encoder, &output_buf, + svt_av1_enc_get_packet(svtav1enc->svt_encoder, &output_buf, done_sending_pics); if (output_buf != NULL) @@ -849,7 +849,7 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, G_GINT64_FORMAT " SliceType:%d\n", svtav1enc->frame_count, (frame->dts), (frame->pts), output_buf->pic_type); - eb_svt_release_out_buffer(&output_buf); + svt_av1_enc_release_out_buffer(&output_buf); output_buf = NULL; ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (svtav1enc), frame); @@ -923,7 +923,7 @@ gst_svtav1enc_stop (GstVideoEncoder * encoder) GST_OBJECT_UNLOCK (svtav1enc); GST_OBJECT_LOCK (svtav1enc); - eb_deinit_encoder(svtav1enc->svt_encoder); + svt_av1_enc_deinit(svtav1enc->svt_encoder); /* Destruct the buffer memory pool */ gst_svthevenc_deallocate_svt_buffers (svtav1enc); GST_OBJECT_UNLOCK (svtav1enc); From 0176e535c605b3229d383a8e34aeec67ec0146b6 Mon Sep 17 00:00:00 2001 From: Jun Date: Wed, 22 Apr 2020 10:05:11 -0700 Subject: [PATCH 23/81] [GStreamer]Update encoder interface and add CI test (#1240) Signed-off-by: Jun Tian Co-authored-by: Christopher Degawa --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 100 +++++++++++++++--- .../gst-plugins-bad/ext/svtav1/meson.build | 2 +- 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index d66167a2e3..7f594da93b 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -98,7 +98,7 @@ enum #define PROP_RC_MODE_CQP 0 #define PROP_RC_MODE_VBR 1 -#define PROP_ENCMODE_DEFAULT 7 +#define PROP_ENCMODE_DEFAULT 8 #define PROP_SPEEDCONTROL_DEFAULT 60 #define PROP_HIERARCHICAL_LEVEL_DEFAULT 4 #define PROP_P_FRAMES_DEFAULT 0 @@ -193,8 +193,8 @@ gst_svtav1enc_class_init (GstSvtAv1EncClass * klass) g_param_spec_uint ("speed", "speed (Encoder Mode)", "Quality vs density tradeoff point" " that the encoding is to be performed at" - " (0 is the highest quality, 7 is the highest speed) ", - 0, 7, PROP_ENCMODE_DEFAULT, + " (0 is the highest quality, 8 is the highest speed) ", + 0, 8, PROP_ENCMODE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -612,24 +612,58 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->intra_period_length = PROP_GOP_SIZE_DEFAULT - 1; svt_config->intra_refresh_type = PROP_INTRA_REFRESH_DEFAULT; svt_config->enc_mode = PROP_ENCMODE_DEFAULT; + svt_config->snd_pass_enc_mode = PROP_ENCMODE_DEFAULT + 1; svt_config->frame_rate = 25; svt_config->frame_rate_denominator = 1; svt_config->frame_rate_numerator = 25; svt_config->hierarchical_levels = PROP_HIERARCHICAL_LEVEL_DEFAULT; - svt_config->pred_structure = PROP_PRED_STRUCTURE_DEFAULT; svt_config->scene_change_detection = PROP_SCD_DEFAULT; svt_config->look_ahead_distance = (uint32_t)~0; - svt_config->rate_control_mode = PROP_RC_MODE_DEFAULT; + svt_config->rate_control_mode = PROP_RC_MODE_DEFAULT; // todo: add CVBR svt_config->target_bit_rate = PROP_BITRATE_DEFAULT; svt_config->max_qp_allowed = PROP_QP_MAX_DEFAULT; svt_config->min_qp_allowed = PROP_QP_MIN_DEFAULT; + svt_config->screen_content_mode = FALSE; + svt_config->intrabc_mode = -1; + svt_config->enable_adaptive_quantization = FALSE; svt_config->qp = PROP_QP_DEFAULT; svt_config->use_qp_file = FALSE; svt_config->disable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == FALSE); svt_config->enable_denoise_flag = FALSE; svt_config->film_grain_denoise_strength = FALSE; svt_config->enable_warped_motion = FALSE; + svt_config->enable_global_motion = TRUE; + svt_config->cdef_mode = -1; + svt_config->enable_restoration_filtering = -1; + svt_config->sg_filter_mode = -1; + svt_config->wn_filter_mode = -1; + svt_config->edge_skp_angle_intra = -1; + svt_config->intra_angle_delta = -1; + svt_config->inter_intra_compound = -1; + svt_config->enable_paeth = -1; + svt_config->enable_smooth = -1; + svt_config->combine_class_12 = -1; + svt_config->enable_mfmv = -1; + svt_config->enable_redundant_blk = -1; + svt_config->spatial_sse_fl = -1; + svt_config->enable_subpel = -1; + svt_config->over_bndry_blk = -1; + svt_config->new_nearest_comb_inject = -1; + svt_config->prune_unipred_me = -1; + svt_config->prune_ref_rec_part = -1; + svt_config->nsq_table = -1; + svt_config->frame_end_cdf_update = -1; + svt_config->pred_me = -1; + svt_config->bipred_3x3_inject = -1; + svt_config->compound_level = -1; + svt_config->set_chroma_mode = -1; + svt_config->disable_cfl_flag = -1; + svt_config->enable_obmc = 1; + svt_config->enable_rdoq = -1; + svt_config->enable_filter_intra = 1; + svt_config->enable_intra_edge_filter = -1; + svt_config->pic_based_rate_est = -1; svt_config->use_default_me_hme = TRUE; svt_config->enable_hme_flag = TRUE; svt_config->enable_hme_level0_flag = TRUE; @@ -639,6 +673,9 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->in_loop_me_flag = TRUE; svt_config->search_area_width = 16; svt_config->search_area_height = 7; + svt_config->enable_hbd_mode_decision = 1; + svt_config->enable_palette = -1; + // HME parameters svt_config->number_hme_search_region_in_width = 2; svt_config->number_hme_search_region_in_height = 2; svt_config->hme_level0_total_search_area_width = 64; @@ -657,25 +694,58 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->hme_level2_search_area_in_height_array[1] = 1; svt_config->channel_id = 0; svt_config->active_channel_count = 1; + svt_config->recon_enabled = FALSE; + + // thread affinity svt_config->logical_processors = PROP_CORES_DEFAULT; svt_config->target_socket = PROP_SOCKET_DEFAULT; - svt_config->recon_enabled = FALSE; - //svt_config->tile_columns = 0; - //svt_config->tile_rows = 0; - svt_config->stat_report = FALSE; - svt_config->high_dynamic_range_input = FALSE; - svt_config->encoder_bit_depth = 8; - svt_config->compressed_ten_bit_format = FALSE; + svt_config->unpin_lp1 = 1; + + // tile based encoding + svt_config->tile_columns = 0; + svt_config->tile_rows = 0; + svt_config->unrestricted_motion_vector = 1; + + // alt-ref + svt_config->enable_altrefs = TRUE; + svt_config->altref_strength = 5; + svt_config->altref_nframes = 7; + svt_config->enable_overlays = FALSE; + + // super resolution + svt_config->superres_mode = FALSE; // SUPERRES_NONE + svt_config->superres_denom = 8; + svt_config->superres_kf_denom = 8; + svt_config->superres_qthres = 43; + + svt_config->sq_weight = 100; + + svt_config->md_stage_1_cand_prune_th = 75; + svt_config->md_stage_1_class_prune_th = 100; + svt_config->md_stage_2_3_cand_prune_th = 15; + svt_config->md_stage_2_3_class_prune_th = 25; + + // latency + svt_config->injector_frame_rate = PROP_SPEEDCONTROL_DEFAULT; + svt_config->speed_control_flag = FALSE; + svt_config->super_block_size = 128; + + // Annex A svt_config->profile = 0; svt_config->tier = 0; svt_config->level = 0; - svt_config->injector_frame_rate = PROP_SPEEDCONTROL_DEFAULT; - svt_config->speed_control_flag = FALSE; + + svt_config->stat_report = FALSE; + svt_config->high_dynamic_range_input = FALSE; + svt_config->encoder_bit_depth = 8; + svt_config->is_16bit_pipeline = 0; // todo + svt_config->encoder_color_format = 1; // todo. Only 420 for now. + svt_config->compressed_ten_bit_format = FALSE; svt_config->sb_sz = 64; - svt_config->super_block_size = 128; svt_config->partition_depth = 4; svt_config->enable_qp_scaling_flag = 0; svt_config->use_cpu_flags = CPU_FLAGS_ALL; + svt_config->ten_bit_format = FALSE; } GstFlowReturn diff --git a/subprojects/gst-plugins-bad/ext/svtav1/meson.build b/subprojects/gst-plugins-bad/ext/svtav1/meson.build index 8a2d2a6e35..408ed78255 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/meson.build +++ b/subprojects/gst-plugins-bad/ext/svtav1/meson.build @@ -5,7 +5,7 @@ project('gst-svt-av1', 'c', default_options : [ 'buildtype=debugoptimized' ]) # standard gst-plugins-bad dependencies and configuration -gst_req = '>= 1.8' +gst_req = '>= 1.13.1' gst_dep = dependency('gstreamer-1.0', version : gst_req, fallback : ['gstreamer', 'gst_dep']) gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req, From add8269e1774290e30305f615e9f6f53252a5136 Mon Sep 17 00:00:00 2001 From: ttrigui <44172344+ttrigui@users.noreply.github.com> Date: Thu, 4 Jun 2020 11:33:25 -0700 Subject: [PATCH 24/81] Unpin thread execution and multi thread buffer tuning (#1275) Add the option of unpinning threads from being executed on cores 0-x when -lp x is defined. Tuning the multi-threaded buffer tuning for better efficiency with low core count when running in a VOD environment. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 7f594da93b..1e67845276 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -699,7 +699,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) // thread affinity svt_config->logical_processors = PROP_CORES_DEFAULT; svt_config->target_socket = PROP_SOCKET_DEFAULT; - svt_config->unpin_lp1 = 1; + svt_config->unpin = 1; // tile based encoding svt_config->tile_columns = 0; From 25d19309773a5df9334a30bb4b26ffe8c3d4dd58 Mon Sep 17 00:00:00 2001 From: Jun Date: Mon, 13 Jul 2020 11:15:58 -0700 Subject: [PATCH 25/81] Use GST_ELEMENT_ERROR macro for GST_FLOW_ERROR (#1357) * Use GST_ELEMENT_ERROR macro for GST_FLOW_ERROR * swap TEXT and DEBUG field Signed-off-by: Jun Tian --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 1e67845276..d96b7cfa6e 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -314,7 +314,7 @@ gst_svtav1enc_init (GstSvtAv1Enc * svtav1enc) EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "svt_av1_enc_init_handle failed with error %d", res); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, INIT, (NULL), ("svt_av1_enc_init_handle failed with error %d", res)); GST_OBJECT_UNLOCK (svtav1enc); return; } @@ -583,7 +583,7 @@ gst_svtav1enc_configure_svt (GstSvtAv1Enc * svtav1enc) EbErrorType res = svt_av1_enc_set_parameter(svtav1enc->svt_encoder, svtav1enc->svt_config); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "svt_av1_enc_set_parameter failed with error %d", res); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, INIT, (NULL), ("svt_av1_enc_set_parameter failed with error %d", res)); return FALSE; } return TRUE; @@ -597,7 +597,7 @@ gst_svtav1enc_start_svt (GstSvtAv1Enc * svtav1enc) G_UNLOCK (init_mutex); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "svt_av1_enc_init failed with error %d", res); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, INIT, (NULL), ("svt_av1_enc_init failed with error %d", res)); return FALSE; } return TRUE; @@ -760,7 +760,7 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) if (!gst_video_frame_map (&video_frame, &svtav1enc->state->info, frame->input_buffer, GST_MAP_READ)) { - GST_ERROR_OBJECT (svtav1enc, "couldn't map input frame"); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("couldn't map input frame")); return GST_FLOW_ERROR; } @@ -792,7 +792,7 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) res = svt_av1_enc_send_picture(svtav1enc->svt_encoder, input_buffer); if (res != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "Issue %d sending picture to SVT-AV1.", res); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("error in sending picture to encoder")); ret = GST_FLOW_ERROR; } gst_video_frame_unmap (&video_frame); @@ -816,7 +816,7 @@ gst_svtav1enc_send_eos (GstSvtAv1Enc * svtav1enc) ret = svt_av1_enc_send_picture(svtav1enc->svt_encoder, &input_buffer); if (ret != EB_ErrorNone) { - GST_ERROR_OBJECT (svtav1enc, "couldn't send EOS frame."); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("couldn't send EOS frame.")); return FALSE; } @@ -864,7 +864,7 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, ((output_buf->flags & EB_BUFFERFLAG_EOS) == EB_BUFFERFLAG_EOS); if (res == EB_ErrorMax) { - GST_ERROR_OBJECT (svtav1enc, "Error while encoding, return\n"); + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("encode failed")); return GST_FLOW_ERROR; } else if (res != EB_NoErrorEmptyQueue && output_frames && output_buf) { /* if p_app_private is indeed propagated, get the frame through it @@ -878,8 +878,10 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, frame_list_element = g_list_find_custom (pending_frames, &output_buf->pts, compare_video_code_frame_and_pts); - if (frame_list_element == NULL) + if (frame_list_element == NULL) { + GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("failed to get unfinished frame")); return GST_FLOW_ERROR; + } frame = (GstVideoCodecFrame *) frame_list_element->data; } From 0e98f8947026d81c5d2eb409ec05ba4adee0372d Mon Sep 17 00:00:00 2001 From: Omar Khlif Date: Mon, 20 Jul 2020 14:06:05 -0700 Subject: [PATCH 26/81] code cleanup Co-authored-by: hguermaz Co-authored-by: kelvinhu325 Co-authored-by: Amir Naghdinezhad Co-authored-by: PhoenixWorthVCD Co-authored-by: lijing0010 Co-authored-by: NaderMahdi Co-authored-by: chkngit --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index d96b7cfa6e..dc4334bacd 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -643,14 +643,11 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->inter_intra_compound = -1; svt_config->enable_paeth = -1; svt_config->enable_smooth = -1; - svt_config->combine_class_12 = -1; svt_config->enable_mfmv = -1; svt_config->enable_redundant_blk = -1; svt_config->spatial_sse_fl = -1; - svt_config->enable_subpel = -1; svt_config->over_bndry_blk = -1; svt_config->new_nearest_comb_inject = -1; - svt_config->prune_unipred_me = -1; svt_config->prune_ref_rec_part = -1; svt_config->nsq_table = -1; svt_config->frame_end_cdf_update = -1; From a7c9c6aba8b7dfae5cca48bb85d24dbb07360005 Mon Sep 17 00:00:00 2001 From: Omar Khlif Date: Tue, 21 Jul 2020 12:11:15 -0700 Subject: [PATCH 27/81] add CLI , define MR and MRS as enc-mode Co-authored-by: hguermaz Co-authored-by: kelvinhu325 Co-authored-by: Amir Naghdinezhad Co-authored-by: PhoenixWorthVCD Co-authored-by: lijing0010 Co-authored-by: NaderMahdi Co-authored-by: chkngit --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index dc4334bacd..dec16eef30 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -656,9 +656,9 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->compound_level = -1; svt_config->set_chroma_mode = -1; svt_config->disable_cfl_flag = -1; - svt_config->enable_obmc = 1; + svt_config->obmc_level = 1; svt_config->enable_rdoq = -1; - svt_config->enable_filter_intra = 1; + svt_config->filter_intra_level = 1; svt_config->enable_intra_edge_filter = -1; svt_config->pic_based_rate_est = -1; svt_config->use_default_me_hme = TRUE; From d0f0e8581b2368c5b187901d85f17ecc3421c347 Mon Sep 17 00:00:00 2001 From: Aaron Huang <34738252+Arhuan@users.noreply.github.com> Date: Tue, 18 Aug 2020 10:35:32 -0700 Subject: [PATCH 28/81] Svt-02 CLI features (#1408) * updating CLI support for RDOQ * updating CLI support for Spatial SSE * updating CLI support for Palette * updating CLI support for ALTREF * updating CLI for CDEF * updated user guide, sample cfg, --help, and macro use * Removed all added macros RDOQ_CLI, SSSE_CLI, PALETTE_CLI, ALTREF_CLI, and CDEF_CLI. Renaming and new changes are now made under existing active macros * removed unnecessary #else and #endif causing build failure * removed boolean conversion for static_config.cdef_level in non default case * update CDEF documentation to reflect naming changes * update altref and palette documentation to reflect naming changes --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index dec16eef30..59410db835 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -634,7 +634,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->film_grain_denoise_strength = FALSE; svt_config->enable_warped_motion = FALSE; svt_config->enable_global_motion = TRUE; - svt_config->cdef_mode = -1; + svt_config->cdef_level = -1; svt_config->enable_restoration_filtering = -1; svt_config->sg_filter_mode = -1; svt_config->wn_filter_mode = -1; @@ -645,7 +645,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->enable_smooth = -1; svt_config->enable_mfmv = -1; svt_config->enable_redundant_blk = -1; - svt_config->spatial_sse_fl = -1; + svt_config->spatial_sse_full_loop_level = -1; svt_config->over_bndry_blk = -1; svt_config->new_nearest_comb_inject = -1; svt_config->prune_ref_rec_part = -1; @@ -657,7 +657,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->set_chroma_mode = -1; svt_config->disable_cfl_flag = -1; svt_config->obmc_level = 1; - svt_config->enable_rdoq = -1; + svt_config->rdoq_level = -1; svt_config->filter_intra_level = 1; svt_config->enable_intra_edge_filter = -1; svt_config->pic_based_rate_est = -1; @@ -671,7 +671,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->search_area_width = 16; svt_config->search_area_height = 7; svt_config->enable_hbd_mode_decision = 1; - svt_config->enable_palette = -1; + svt_config->palette_level = -1; // HME parameters svt_config->number_hme_search_region_in_width = 2; svt_config->number_hme_search_region_in_height = 2; @@ -704,7 +704,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->unrestricted_motion_vector = 1; // alt-ref - svt_config->enable_altrefs = TRUE; + svt_config->tf_level = 1; svt_config->altref_strength = 5; svt_config->altref_nframes = 7; svt_config->enable_overlays = FALSE; From c3467b8c134c301723a96924fd7ba0ee28cc7cc2 Mon Sep 17 00:00:00 2001 From: PhoenixWorthVCD <55719945+PhoenixWorthVCD@users.noreply.github.com> Date: Mon, 31 Aug 2020 11:21:48 -0700 Subject: [PATCH 29/81] Improve Lambda Generation and optimize preset trade-offs (#1448) * use frame info to generate lambda * Add new settings for optimized trade-offs --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 59410db835..3a66b2fdde 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -638,7 +638,9 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->enable_restoration_filtering = -1; svt_config->sg_filter_mode = -1; svt_config->wn_filter_mode = -1; + #if 0 //!REMOVE_EDGE_SKIP_ANGLE_INTRA svt_config->edge_skp_angle_intra = -1; + #endif svt_config->intra_angle_delta = -1; svt_config->inter_intra_compound = -1; svt_config->enable_paeth = -1; @@ -648,7 +650,9 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->spatial_sse_full_loop_level = -1; svt_config->over_bndry_blk = -1; svt_config->new_nearest_comb_inject = -1; + #if 0 //!REMOVE_REF_FOR_RECT_PART svt_config->prune_ref_rec_part = -1; + #endif svt_config->nsq_table = -1; svt_config->frame_end_cdf_update = -1; svt_config->pred_me = -1; From 99ad43e50738c9b41d54811ceb3207a55b0e9d27 Mon Sep 17 00:00:00 2001 From: Hassene Tmar <42185990+hassount@users.noreply.github.com> Date: Fri, 4 Sep 2020 17:06:35 -0700 Subject: [PATCH 30/81] Run-time flags cleanup (#1476) * Cleanup users guide, configuration file and remove extra run-time signals that are not anymore applicable. * Restrict intra bc for the case where scm is set to 1 only Co-authored-by: Omran --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 3a66b2fdde..d41c47a1f1 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -612,7 +612,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->intra_period_length = PROP_GOP_SIZE_DEFAULT - 1; svt_config->intra_refresh_type = PROP_INTRA_REFRESH_DEFAULT; svt_config->enc_mode = PROP_ENCMODE_DEFAULT; - svt_config->snd_pass_enc_mode = PROP_ENCMODE_DEFAULT + 1; svt_config->frame_rate = 25; svt_config->frame_rate_denominator = 1; svt_config->frame_rate_numerator = 25; @@ -719,13 +718,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->superres_kf_denom = 8; svt_config->superres_qthres = 43; - svt_config->sq_weight = 100; - - svt_config->md_stage_1_cand_prune_th = 75; - svt_config->md_stage_1_class_prune_th = 100; - svt_config->md_stage_2_3_cand_prune_th = 15; - svt_config->md_stage_2_3_class_prune_th = 25; - // latency svt_config->injector_frame_rate = PROP_SPEEDCONTROL_DEFAULT; svt_config->speed_control_flag = FALSE; From df40f636ba9dfb3125f3df93bb31460fdf92f07a Mon Sep 17 00:00:00 2001 From: Jun Zhao Date: Mon, 21 Sep 2020 22:13:39 +0800 Subject: [PATCH 31/81] replace OpenVisualCloud with AOMediaCodec replace OpenVisualCloud with AOMediaCodec, video.tar.gz file is still under OpenVisualCloud, so keep the other links. Signed-off-by: Jun Zhao --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index d41c47a1f1..960cff75b3 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -1166,7 +1166,7 @@ plugin_init (GstPlugin * plugin) #define PACKAGE_NAME "SVT-AV1 Encoder plugin for GStreamer" #endif #ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "https://github.com/OpenVisualCloud" +#define GST_PACKAGE_ORIGIN "https://github.com/AOMediaCodec" #endif GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, From f6a75cd53e534d3eb48e01cf5e5901095916684e Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Wed, 17 Feb 2021 13:46:18 -0600 Subject: [PATCH 32/81] docs: Update url to gitlab.com Signed-off-by: Christopher Degawa --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 960cff75b3..498961756a 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -1166,7 +1166,7 @@ plugin_init (GstPlugin * plugin) #define PACKAGE_NAME "SVT-AV1 Encoder plugin for GStreamer" #endif #ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "https://github.com/AOMediaCodec" +#define GST_PACKAGE_ORIGIN "https://gitlab.com/AOMediaCodec" #endif GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, From f94f337ec76ee2f111711fe0993bf392daff0c7a Mon Sep 17 00:00:00 2001 From: Omar Khlif Date: Fri, 12 Mar 2021 02:46:38 +0000 Subject: [PATCH 33/81] Tune and redesign TF controls --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 498961756a..65368b5e0e 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -708,8 +708,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) // alt-ref svt_config->tf_level = 1; - svt_config->altref_strength = 5; - svt_config->altref_nframes = 7; svt_config->enable_overlays = FALSE; // super resolution From bf46cfe44c453e0a259e257dd2628a091c8d9c1a Mon Sep 17 00:00:00 2001 From: Omar Date: Thu, 6 May 2021 07:25:25 -0700 Subject: [PATCH 34/81] Unused code cleanup (IME, TRL, LAD) --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 65368b5e0e..c39ced93f1 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -384,10 +384,6 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, case PROP_QP_MIN: svtav1enc->svt_config->min_qp_allowed = g_value_get_uint (value); break; - case PROP_LOOKAHEAD: - svtav1enc->svt_config->look_ahead_distance = - (unsigned int)g_value_get_int(value); - break; case PROP_SCD: svtav1enc->svt_config->scene_change_detection = g_value_get_boolean (value); @@ -457,9 +453,6 @@ gst_svtav1enc_get_property (GObject * object, guint property_id, case PROP_QP_MIN: g_value_set_uint (value, svtav1enc->svt_config->min_qp_allowed); break; - case PROP_LOOKAHEAD: - g_value_set_int(value, (int)svtav1enc->svt_config->look_ahead_distance); - break; case PROP_SCD: g_value_set_boolean (value, svtav1enc->svt_config->scene_change_detection == 1); @@ -564,15 +557,6 @@ gst_svtav1enc_configure_svt (GstSvtAv1Enc * svtav1enc) GST_LOG_OBJECT(svtav1enc, "width %d, height %d, framerate %d", svtav1enc->svt_config->source_width, svtav1enc->svt_config->source_height, svtav1enc->svt_config->frame_rate); - /* pick a default value for the look ahead distance - * in CQP mode:2*minigop+1. in VBR: intra Period */ - if (svtav1enc->svt_config->look_ahead_distance == (unsigned int) -1) { - svtav1enc->svt_config->look_ahead_distance = - (svtav1enc->svt_config->rate_control_mode == PROP_RC_MODE_VBR) ? - svtav1enc->svt_config->intra_period_length : - 2 * (1 << svtav1enc->svt_config->hierarchical_levels) + 1; - } - /* TODO: better handle HDR metadata when GStreamer will have such support * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/400 */ if (GST_VIDEO_INFO_COLORIMETRY (info).matrix == GST_VIDEO_COLOR_MATRIX_BT2020 @@ -618,7 +602,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->hierarchical_levels = PROP_HIERARCHICAL_LEVEL_DEFAULT; svt_config->pred_structure = PROP_PRED_STRUCTURE_DEFAULT; svt_config->scene_change_detection = PROP_SCD_DEFAULT; - svt_config->look_ahead_distance = (uint32_t)~0; svt_config->rate_control_mode = PROP_RC_MODE_DEFAULT; // todo: add CVBR svt_config->target_bit_rate = PROP_BITRATE_DEFAULT; svt_config->max_qp_allowed = PROP_QP_MAX_DEFAULT; @@ -670,7 +653,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->enable_hme_level1_flag = FALSE; svt_config->enable_hme_level2_flag = FALSE; svt_config->ext_block_flag = FALSE; - svt_config->in_loop_me_flag = TRUE; svt_config->search_area_width = 16; svt_config->search_area_height = 7; svt_config->enable_hbd_mode_decision = 1; @@ -1016,7 +998,7 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, fps = fps > 120 ? 120 : fps; fps = fps < 24 ? 24 : fps; - min_latency_frames = svtav1enc->svt_config->look_ahead_distance + ((fps * 5) >> 2); + min_latency_frames = ((fps * 5) >> 2); /* TODO: find a better value for max_latency */ gst_video_encoder_set_latency (encoder, From 820842c2282d8d7564f19e09c8acae8e074b88ed Mon Sep 17 00:00:00 2001 From: palexander-14 Date: Mon, 22 Mar 2021 15:15:07 +0700 Subject: [PATCH 35/81] Added support for color description information The following parameters are supported: - `color_range` - `color_primaries` - `transfer_characteristics` - `matrix_coefficients` Added writing of color description into a bit stream Updated the encoder config structure (API) to support color description parameters Updated the encoding app to support color description in config files Added unit tests for color description settings Added default color description values into the gst plugin Updated documentation --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index c39ced93f1..ca25a4b8dd 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -719,6 +719,12 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->enable_qp_scaling_flag = 0; svt_config->use_cpu_flags = CPU_FLAGS_ALL; svt_config->ten_bit_format = FALSE; + + // color description + svt_config->color_range = 0; + svt_config->color_primaries = 2; + svt_config->transfer_characteristics = 2; + svt_config->matrix_coefficients = 2; } GstFlowReturn From 775f8fca11092e8d4ae9c8fa54e52e5f544b912b Mon Sep 17 00:00:00 2001 From: hassount Date: Fri, 10 Dec 2021 13:30:50 -0800 Subject: [PATCH 36/81] Cleanup unused tokens and apis - Fix Lookahead distance documentation to be capped at 120 --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index ca25a4b8dd..3d698a4bd4 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -350,10 +350,8 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, break; case PROP_SPEEDCONTROL: if (g_value_get_uint (value) > 0) { - svtav1enc->svt_config->injector_frame_rate = g_value_get_uint (value); svtav1enc->svt_config->speed_control_flag = 1; } else { - svtav1enc->svt_config->injector_frame_rate = 60 << 16; svtav1enc->svt_config->speed_control_flag = 0; } break; @@ -414,7 +412,7 @@ gst_svtav1enc_get_property (GObject * object, guint property_id, break; case PROP_SPEEDCONTROL: if (svtav1enc->svt_config->speed_control_flag) { - g_value_set_uint (value, svtav1enc->svt_config->injector_frame_rate); + g_value_set_uint (value, 60); } else { g_value_set_uint (value, 0); } @@ -612,7 +610,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->qp = PROP_QP_DEFAULT; svt_config->use_qp_file = FALSE; svt_config->disable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == FALSE); - svt_config->enable_denoise_flag = FALSE; svt_config->film_grain_denoise_strength = FALSE; svt_config->enable_warped_motion = FALSE; svt_config->enable_global_motion = TRUE; @@ -699,7 +696,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->superres_qthres = 43; // latency - svt_config->injector_frame_rate = PROP_SPEEDCONTROL_DEFAULT; svt_config->speed_control_flag = FALSE; svt_config->super_block_size = 128; From 4d99d86f99729d94b82f2325cd8923612b84284c Mon Sep 17 00:00:00 2001 From: hassount Date: Thu, 23 Dec 2021 15:09:50 -0600 Subject: [PATCH 37/81] Cleanup some API signals API signaled (re)moved: - intra_angle_delta - palette_level - 16-bit-pipeline - sb_sz - super_block_size - partition_depth - warp motion - global motion - self guided filter level - weiner filter level - inter intra compound - paeth - smooth - mrp level - spatial sse - over_bndry_blk - new_nearest_comb_inject - nsq_table - frame_end_cdf_update - pred_me - bipred_3x3_inject - compound_level - set_chroma_mode - disable_cfl_flag - obmc_level - rdoq_level - filter_intra_level - enable_intra_edge_filter - pic_based_rate_est - unused me parameters - unused me variables - intrabc_mode - enable_hbd_mode_decision - enable_qp_scaling_flag - ten_bit_format - enable_adaptive_mini_gop - max_heirachical_level - speed_control_flag Move unnecessary definitions to EbDefinitions.h --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 85 ------------------- 1 file changed, 85 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 3d698a4bd4..1787f6b578 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -77,7 +77,6 @@ enum { PROP_0, PROP_ENCMODE, - PROP_SPEEDCONTROL, PROP_B_PYRAMID, PROP_P_FRAMES, PROP_PRED_STRUCTURE, @@ -99,7 +98,6 @@ enum #define PROP_RC_MODE_VBR 1 #define PROP_ENCMODE_DEFAULT 8 -#define PROP_SPEEDCONTROL_DEFAULT 60 #define PROP_HIERARCHICAL_LEVEL_DEFAULT 4 #define PROP_P_FRAMES_DEFAULT 0 #define PROP_PRED_STRUCTURE_DEFAULT 2 @@ -197,14 +195,6 @@ gst_svtav1enc_class_init (GstSvtAv1EncClass * klass) 0, 8, PROP_ENCMODE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_SPEEDCONTROL, - g_param_spec_uint ("speed-control", "Speed Control (in fps)", - "Dynamically change the encoding speed preset" - " to meet this defined average encoding speed (in fps)", - 1, 240, PROP_SPEEDCONTROL_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_B_PYRAMID, g_param_spec_uint ("hierarchical-level", "Hierarchical levels", "3 : 4 - Level Hierarchy," @@ -348,13 +338,6 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, case PROP_INTRA_REFRESH: svtav1enc->svt_config->intra_refresh_type = g_value_get_int(value); break; - case PROP_SPEEDCONTROL: - if (g_value_get_uint (value) > 0) { - svtav1enc->svt_config->speed_control_flag = 1; - } else { - svtav1enc->svt_config->speed_control_flag = 0; - } - break; case PROP_B_PYRAMID: svtav1enc->svt_config->hierarchical_levels = g_value_get_uint (value); break; @@ -410,13 +393,6 @@ gst_svtav1enc_get_property (GObject * object, guint property_id, case PROP_ENCMODE: g_value_set_uint (value, svtav1enc->svt_config->enc_mode); break; - case PROP_SPEEDCONTROL: - if (svtav1enc->svt_config->speed_control_flag) { - g_value_set_uint (value, 60); - } else { - g_value_set_uint (value, 0); - } - break; case PROP_B_PYRAMID: g_value_set_uint (value, svtav1enc->svt_config->hierarchical_levels); break; @@ -605,72 +581,18 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->max_qp_allowed = PROP_QP_MAX_DEFAULT; svt_config->min_qp_allowed = PROP_QP_MIN_DEFAULT; svt_config->screen_content_mode = FALSE; - svt_config->intrabc_mode = -1; svt_config->enable_adaptive_quantization = FALSE; svt_config->qp = PROP_QP_DEFAULT; svt_config->use_qp_file = FALSE; svt_config->disable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == FALSE); svt_config->film_grain_denoise_strength = FALSE; - svt_config->enable_warped_motion = FALSE; - svt_config->enable_global_motion = TRUE; svt_config->cdef_level = -1; svt_config->enable_restoration_filtering = -1; - svt_config->sg_filter_mode = -1; - svt_config->wn_filter_mode = -1; #if 0 //!REMOVE_EDGE_SKIP_ANGLE_INTRA svt_config->edge_skp_angle_intra = -1; #endif - svt_config->intra_angle_delta = -1; - svt_config->inter_intra_compound = -1; - svt_config->enable_paeth = -1; - svt_config->enable_smooth = -1; svt_config->enable_mfmv = -1; - svt_config->enable_redundant_blk = -1; - svt_config->spatial_sse_full_loop_level = -1; - svt_config->over_bndry_blk = -1; - svt_config->new_nearest_comb_inject = -1; - #if 0 //!REMOVE_REF_FOR_RECT_PART - svt_config->prune_ref_rec_part = -1; - #endif - svt_config->nsq_table = -1; - svt_config->frame_end_cdf_update = -1; - svt_config->pred_me = -1; - svt_config->bipred_3x3_inject = -1; - svt_config->compound_level = -1; - svt_config->set_chroma_mode = -1; - svt_config->disable_cfl_flag = -1; - svt_config->obmc_level = 1; - svt_config->rdoq_level = -1; - svt_config->filter_intra_level = 1; - svt_config->enable_intra_edge_filter = -1; - svt_config->pic_based_rate_est = -1; - svt_config->use_default_me_hme = TRUE; - svt_config->enable_hme_flag = TRUE; - svt_config->enable_hme_level0_flag = TRUE; - svt_config->enable_hme_level1_flag = FALSE; - svt_config->enable_hme_level2_flag = FALSE; - svt_config->ext_block_flag = FALSE; - svt_config->search_area_width = 16; - svt_config->search_area_height = 7; - svt_config->enable_hbd_mode_decision = 1; - svt_config->palette_level = -1; // HME parameters - svt_config->number_hme_search_region_in_width = 2; - svt_config->number_hme_search_region_in_height = 2; - svt_config->hme_level0_total_search_area_width = 64; - svt_config->hme_level0_total_search_area_height = 25; - svt_config->hme_level0_search_area_in_width_array[0] = 32; - svt_config->hme_level0_search_area_in_width_array[1] = 32; - svt_config->hme_level0_search_area_in_height_array[0] = 12; - svt_config->hme_level0_search_area_in_height_array[1] = 13; - svt_config->hme_level1_search_area_in_width_array[0] = 1; - svt_config->hme_level1_search_area_in_width_array[1] = 1; - svt_config->hme_level1_search_area_in_height_array[0] = 1; - svt_config->hme_level1_search_area_in_height_array[1] = 1; - svt_config->hme_level2_search_area_in_width_array[0] = 1; - svt_config->hme_level2_search_area_in_width_array[1] = 1; - svt_config->hme_level2_search_area_in_height_array[0] = 1; - svt_config->hme_level2_search_area_in_height_array[1] = 1; svt_config->channel_id = 0; svt_config->active_channel_count = 1; svt_config->recon_enabled = FALSE; @@ -696,8 +618,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->superres_qthres = 43; // latency - svt_config->speed_control_flag = FALSE; - svt_config->super_block_size = 128; // Annex A svt_config->profile = 0; @@ -707,14 +627,9 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->stat_report = FALSE; svt_config->high_dynamic_range_input = FALSE; svt_config->encoder_bit_depth = 8; - svt_config->is_16bit_pipeline = 0; // todo svt_config->encoder_color_format = 1; // todo. Only 420 for now. svt_config->compressed_ten_bit_format = FALSE; - svt_config->sb_sz = 64; - svt_config->partition_depth = 4; - svt_config->enable_qp_scaling_flag = 0; svt_config->use_cpu_flags = CPU_FLAGS_ALL; - svt_config->ten_bit_format = FALSE; // color description svt_config->color_range = 0; From 4bd83fb3c0a3dc2978f0cee4c1d0b9f5c449ed41 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Mon, 27 Dec 2021 13:46:01 -0600 Subject: [PATCH 38/81] gstreamer: remove useless if 0 Signed-off-by: Christopher Degawa --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 1787f6b578..d1b4ca4d07 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -588,9 +588,6 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->film_grain_denoise_strength = FALSE; svt_config->cdef_level = -1; svt_config->enable_restoration_filtering = -1; - #if 0 //!REMOVE_EDGE_SKIP_ANGLE_INTRA - svt_config->edge_skp_angle_intra = -1; - #endif svt_config->enable_mfmv = -1; // HME parameters svt_config->channel_id = 0; From 571897ef0c10382ac8dd5ce193dc797a7768d617 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Wed, 5 Jan 2022 12:02:52 -0600 Subject: [PATCH 39/81] rename --tf-level to --enable-tf Also does the renaming for the API and the config file option along with changing the option to a EbBool Signed-off-by: Christopher Degawa --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index d1b4ca4d07..e2f9146c8b 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -605,7 +605,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->unrestricted_motion_vector = 1; // alt-ref - svt_config->tf_level = 1; + svt_config->enable_tf = TRUE; svt_config->enable_overlays = FALSE; // super resolution From a2ec26a8ca08675f0b0b506e554962b19826dfae Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 6 Jan 2022 14:55:56 -0600 Subject: [PATCH 40/81] rename disable-dlf to enable-dlf Signed-off-by: Christopher Degawa --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index e2f9146c8b..db077e470a 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -351,7 +351,7 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, svtav1enc->svt_config->qp = g_value_get_uint (value); break; case PROP_DEBLOCKING: - svtav1enc->svt_config->disable_dlf_flag = !g_value_get_boolean (value); + svtav1enc->svt_config->enable_dlf_flag = g_value_get_boolean (value); break; case PROP_RC_MODE: svtav1enc->svt_config->rate_control_mode = g_value_get_uint (value); @@ -413,7 +413,7 @@ gst_svtav1enc_get_property (GObject * object, guint property_id, g_value_set_uint (value, svtav1enc->svt_config->qp); break; case PROP_DEBLOCKING: - g_value_set_boolean (value, svtav1enc->svt_config->disable_dlf_flag == 0); + g_value_set_boolean (value, svtav1enc->svt_config->enable_dlf_flag == 1); break; case PROP_RC_MODE: g_value_set_uint (value, svtav1enc->svt_config->rate_control_mode); @@ -584,7 +584,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) svt_config->enable_adaptive_quantization = FALSE; svt_config->qp = PROP_QP_DEFAULT; svt_config->use_qp_file = FALSE; - svt_config->disable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == FALSE); + svt_config->enable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == TRUE); svt_config->film_grain_denoise_strength = FALSE; svt_config->cdef_level = -1; svt_config->enable_restoration_filtering = -1; From b1d167ec2249d4f22e5844bb737b8e3af4bc8d27 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 6 Jan 2022 15:54:54 -0600 Subject: [PATCH 41/81] rename unrestricted motion vector to restricted motion vector Signed-off-by: Christopher Degawa --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index db077e470a..d0cf29cde7 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -602,7 +602,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) // tile based encoding svt_config->tile_columns = 0; svt_config->tile_rows = 0; - svt_config->unrestricted_motion_vector = 1; + svt_config->restricted_motion_vector = FALSE; // alt-ref svt_config->enable_tf = TRUE; From a85ab85bf865d21a86850ee5b765f4fbd26c8943 Mon Sep 17 00:00:00 2001 From: hassount Date: Fri, 14 Jan 2022 22:27:25 -0800 Subject: [PATCH 42/81] Fix warning typos and Gstreamer ci test --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index d0cf29cde7..f6069e767c 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -597,7 +597,7 @@ set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) // thread affinity svt_config->logical_processors = PROP_CORES_DEFAULT; svt_config->target_socket = PROP_SOCKET_DEFAULT; - svt_config->unpin = 1; + svt_config->pin_threads = 0; // tile based encoding svt_config->tile_columns = 0; From f8c0485af4f24523fdc4d9117c6a3a8e1f5518d0 Mon Sep 17 00:00:00 2001 From: Wojciech Kapsa Date: Thu, 17 Feb 2022 09:00:41 +0000 Subject: [PATCH 43/81] SVT-AV1 0.9 speed updated. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index f6069e767c..4ee0dbbbe9 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -191,8 +191,8 @@ gst_svtav1enc_class_init (GstSvtAv1EncClass * klass) g_param_spec_uint ("speed", "speed (Encoder Mode)", "Quality vs density tradeoff point" " that the encoding is to be performed at" - " (0 is the highest quality, 8 is the highest speed) ", - 0, 8, PROP_ENCMODE_DEFAULT, + " (0 is the highest quality, 12 is the highest speed) ", + 0, 12, PROP_ENCMODE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_B_PYRAMID, From 86c308549f9928d93047cbe11578b53681075796 Mon Sep 17 00:00:00 2001 From: Acky Xu Date: Fri, 25 Mar 2022 16:49:29 -0700 Subject: [PATCH 44/81] Prevent gstreamer from reinitializing svt default values --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 76 ------------------- 1 file changed, 76 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 4ee0dbbbe9..8457233602 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -69,7 +69,6 @@ static gboolean gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, static gboolean gst_svtav1enc_flush (GstVideoEncoder * encoder); /* helpers */ -void set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config); gint compare_video_code_frame_and_pts (const void *video_codec_frame_ptr, const void *pts_ptr); @@ -309,7 +308,6 @@ gst_svtav1enc_init (GstSvtAv1Enc * svtav1enc) return; } /* setting configuration here since svt_av1_enc_init_handle overrides it */ - set_default_svt_configuration (svtav1enc->svt_config); GST_OBJECT_UNLOCK (svtav1enc); } @@ -561,80 +559,6 @@ gst_svtav1enc_start_svt (GstSvtAv1Enc * svtav1enc) return TRUE; } -void -set_default_svt_configuration (EbSvtAv1EncConfiguration * svt_config) -{ - memset(svt_config, 0, sizeof(EbSvtAv1EncConfiguration)); - svt_config->source_width = 0; - svt_config->source_height = 0; - svt_config->intra_period_length = PROP_GOP_SIZE_DEFAULT - 1; - svt_config->intra_refresh_type = PROP_INTRA_REFRESH_DEFAULT; - svt_config->enc_mode = PROP_ENCMODE_DEFAULT; - svt_config->frame_rate = 25; - svt_config->frame_rate_denominator = 1; - svt_config->frame_rate_numerator = 25; - svt_config->hierarchical_levels = PROP_HIERARCHICAL_LEVEL_DEFAULT; - svt_config->pred_structure = PROP_PRED_STRUCTURE_DEFAULT; - svt_config->scene_change_detection = PROP_SCD_DEFAULT; - svt_config->rate_control_mode = PROP_RC_MODE_DEFAULT; // todo: add CVBR - svt_config->target_bit_rate = PROP_BITRATE_DEFAULT; - svt_config->max_qp_allowed = PROP_QP_MAX_DEFAULT; - svt_config->min_qp_allowed = PROP_QP_MIN_DEFAULT; - svt_config->screen_content_mode = FALSE; - svt_config->enable_adaptive_quantization = FALSE; - svt_config->qp = PROP_QP_DEFAULT; - svt_config->use_qp_file = FALSE; - svt_config->enable_dlf_flag = (PROP_DEBLOCKING_DEFAULT == TRUE); - svt_config->film_grain_denoise_strength = FALSE; - svt_config->cdef_level = -1; - svt_config->enable_restoration_filtering = -1; - svt_config->enable_mfmv = -1; - // HME parameters - svt_config->channel_id = 0; - svt_config->active_channel_count = 1; - svt_config->recon_enabled = FALSE; - - // thread affinity - svt_config->logical_processors = PROP_CORES_DEFAULT; - svt_config->target_socket = PROP_SOCKET_DEFAULT; - svt_config->pin_threads = 0; - - // tile based encoding - svt_config->tile_columns = 0; - svt_config->tile_rows = 0; - svt_config->restricted_motion_vector = FALSE; - - // alt-ref - svt_config->enable_tf = TRUE; - svt_config->enable_overlays = FALSE; - - // super resolution - svt_config->superres_mode = FALSE; // SUPERRES_NONE - svt_config->superres_denom = 8; - svt_config->superres_kf_denom = 8; - svt_config->superres_qthres = 43; - - // latency - - // Annex A - svt_config->profile = 0; - svt_config->tier = 0; - svt_config->level = 0; - - svt_config->stat_report = FALSE; - svt_config->high_dynamic_range_input = FALSE; - svt_config->encoder_bit_depth = 8; - svt_config->encoder_color_format = 1; // todo. Only 420 for now. - svt_config->compressed_ten_bit_format = FALSE; - svt_config->use_cpu_flags = CPU_FLAGS_ALL; - - // color description - svt_config->color_range = 0; - svt_config->color_primaries = 2; - svt_config->transfer_characteristics = 2; - svt_config->matrix_coefficients = 2; -} - GstFlowReturn gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) { From 02258ba529628eb6c4479f3cf3aa65ed497d0c49 Mon Sep 17 00:00:00 2001 From: anaghdin Date: Fri, 1 Apr 2022 15:16:20 -0700 Subject: [PATCH 45/81] - In lowdelay VBR is not supported: forces CBR, In RA, CBR is not supported, forces VBR - Limit the max bit rate and target bitrate to 100,000 kbps - Remove frame_rate from API. Inside library frame_rate is always in Q16 format - Fix the seg fault with 2 PASS and max bit rate - Remove frame_rate from CI and gstreamer --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 8457233602..a124510b9e 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -519,15 +519,11 @@ gst_svtav1enc_configure_svt (GstSvtAv1Enc * svtav1enc) 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; - svtav1enc->svt_config->frame_rate = - svtav1enc->svt_config->frame_rate_numerator / - svtav1enc->svt_config->frame_rate_denominator; - - if (svtav1enc->svt_config->frame_rate < 1000) { - svtav1enc->svt_config->frame_rate = svtav1enc->svt_config->frame_rate << 16; - } - - GST_LOG_OBJECT(svtav1enc, "width %d, height %d, framerate %d", svtav1enc->svt_config->source_width, svtav1enc->svt_config->source_height, svtav1enc->svt_config->frame_rate); + GST_LOG_OBJECT(svtav1enc, + "width %d, height %d, framerate %d", + svtav1enc->svt_config->source_width, + svtav1enc->svt_config->source_height, + svtav1enc->svt_config->frame_rate_numerator / svtav1enc->svt_config->frame_rate_denominator); /* TODO: better handle HDR metadata when GStreamer will have such support * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/400 */ @@ -831,17 +827,19 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, gst_svtav1enc_allocate_svt_buffers (svtav1enc); gst_svtav1enc_start_svt (svtav1enc); - uint32_t fps = (uint32_t)((svtav1enc->svt_config->frame_rate > 1000) ? - svtav1enc->svt_config->frame_rate >> 16 : svtav1enc->svt_config->frame_rate); - fps = fps > 120 ? 120 : fps; - fps = fps < 24 ? 24 : fps; + uint32_t 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); + min_latency_frames = ((fps * 5) >> 2); /* TODO: find a better value for max_latency */ - gst_video_encoder_set_latency (encoder, - min_latency_frames * GST_SECOND / svtav1enc->svt_config->frame_rate, - 3 * GST_SECOND); + gst_video_encoder_set_latency(encoder, + min_latency_frames * GST_SECOND / + (svtav1enc->svt_config->frame_rate_numerator / + svtav1enc->svt_config->frame_rate_denominator), + 3 * GST_SECOND); src_caps = gst_static_pad_template_get_caps (&gst_svtav1enc_src_pad_template); From b22376483269363e0d4ed423c0fd99e5d42eb1c6 Mon Sep 17 00:00:00 2001 From: Cidana-Developers Date: Tue, 10 May 2022 10:23:07 +0800 Subject: [PATCH 46/81] add random access for reference scaling 1. add random access configuration for reference scaling fixed and random mode 2. add e2e tests for random access configuration of reference scaling --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index a124510b9e..9d56faf961 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -564,6 +564,9 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) EbSvtIOFormat *input_picture_buffer = (EbSvtIOFormat *) svtav1enc->input_buf->p_buffer; GstVideoFrame video_frame; +#if FTR_RSZ_RANDOM_ACCESS + EbPrivDataNode private_data; +#endif // FTR_RSZ_RANDOM_ACCESS if (!gst_video_frame_map (&video_frame, &svtav1enc->state->info, frame->input_buffer, GST_MAP_READ)) { @@ -589,7 +592,16 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) /* Fill in Buffers Header control data */ input_buffer->flags = 0; +#if FTR_RSZ_RANDOM_ACCESS + // private data is copied in svt_av1_enc_send_picture + private_data.node_type = PRIVATE_DATA; + private_data.size = sizeof (GstVideoCodecFrame); + private_data.data = (void *) frame; + private_data.next = NULL; + input_buffer->p_app_private = (void *) &private_data; +#else input_buffer->p_app_private = (void *) frame; +#endif // FTR_RSZ_RANDOM_ACCESS input_buffer->pts = frame->pts; input_buffer->pic_type = EB_AV1_INVALID_PICTURE; @@ -678,7 +690,12 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, * it's not currently the case with SVT-AV1 * so we fallback on using its PTS to find it back */ if (output_buf->p_app_private) { +#if FTR_RSZ_RANDOM_ACCESS + EbPrivDataNode *private_data = (EbPrivDataNode *) output_buf->p_app_private; + frame = (GstVideoCodecFrame *) private_data->data; +#else frame = (GstVideoCodecFrame *) output_buf->p_app_private; +#endif // FTR_RSZ_RANDOM_ACCESS } else { pending_frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (svtav1enc)); From e2a6d5f76d0bb217f823e3e2a2797b2126fa9e9c Mon Sep 17 00:00:00 2001 From: Cidana-Developers Date: Mon, 16 May 2022 12:21:49 +0800 Subject: [PATCH 47/81] refine reference scaling 1. modify codes by review suggestion 2. clean-up macros --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 9d56faf961..6dee3d6519 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -564,9 +564,7 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) EbSvtIOFormat *input_picture_buffer = (EbSvtIOFormat *) svtav1enc->input_buf->p_buffer; GstVideoFrame video_frame; -#if FTR_RSZ_RANDOM_ACCESS EbPrivDataNode private_data; -#endif // FTR_RSZ_RANDOM_ACCESS if (!gst_video_frame_map (&video_frame, &svtav1enc->state->info, frame->input_buffer, GST_MAP_READ)) { @@ -592,16 +590,12 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) /* Fill in Buffers Header control data */ input_buffer->flags = 0; -#if FTR_RSZ_RANDOM_ACCESS // private data is copied in svt_av1_enc_send_picture private_data.node_type = PRIVATE_DATA; private_data.size = sizeof (GstVideoCodecFrame); private_data.data = (void *) frame; private_data.next = NULL; input_buffer->p_app_private = (void *) &private_data; -#else - input_buffer->p_app_private = (void *) frame; -#endif // FTR_RSZ_RANDOM_ACCESS input_buffer->pts = frame->pts; input_buffer->pic_type = EB_AV1_INVALID_PICTURE; @@ -690,12 +684,8 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, * it's not currently the case with SVT-AV1 * so we fallback on using its PTS to find it back */ if (output_buf->p_app_private) { -#if FTR_RSZ_RANDOM_ACCESS EbPrivDataNode *private_data = (EbPrivDataNode *) output_buf->p_app_private; frame = (GstVideoCodecFrame *) private_data->data; -#else - frame = (GstVideoCodecFrame *) output_buf->p_app_private; -#endif // FTR_RSZ_RANDOM_ACCESS } else { pending_frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (svtav1enc)); From 84786005966f2da321f4e97f3f45422070962242 Mon Sep 17 00:00:00 2001 From: Christopher Degawa Date: Thu, 7 Jul 2022 12:34:21 -0500 Subject: [PATCH 48/81] gst: init metadata to null Signed-off-by: Christopher Degawa --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 6dee3d6519..108824c1c6 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -489,6 +489,7 @@ gst_svtav1enc_allocate_svt_buffers (GstSvtAv1Enc * svtav1enc) 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; return TRUE; } @@ -603,6 +604,8 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * 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")); @@ -625,6 +628,7 @@ gst_svtav1enc_send_eos (GstSvtAv1Enc * svtav1enc) 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); From a8c6eb0606c3a617949e01fc98648b4fb32a8743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:00:49 +0200 Subject: [PATCH 49/81] gstreamer: Don't use private data but simply always get the oldest frame The private data is not copied over for SVT AV1 encoder so this code path would've never worked. Instead of relying on the PTS, which is not required to be unique or existing at all, we always take the oldest frame as AV1 has no frame reordering / B frames. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 39 ++----------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 108824c1c6..595fbf1708 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -565,7 +565,6 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) EbSvtIOFormat *input_picture_buffer = (EbSvtIOFormat *) svtav1enc->input_buf->p_buffer; GstVideoFrame video_frame; - EbPrivDataNode private_data; if (!gst_video_frame_map (&video_frame, &svtav1enc->state->info, frame->input_buffer, GST_MAP_READ)) { @@ -591,12 +590,7 @@ gst_svtav1enc_encode (GstSvtAv1Enc * svtav1enc, GstVideoCodecFrame * frame) /* Fill in Buffers Header control data */ input_buffer->flags = 0; - // private data is copied in svt_av1_enc_send_picture - private_data.node_type = PRIVATE_DATA; - private_data.size = sizeof (GstVideoCodecFrame); - private_data.data = (void *) frame; - private_data.next = NULL; - input_buffer->p_app_private = (void *) &private_data; + input_buffer->p_app_private = NULL; input_buffer->pts = frame->pts; input_buffer->pic_type = EB_AV1_INVALID_PICTURE; @@ -650,14 +644,6 @@ gst_svtav1enc_flush (GstVideoEncoder * encoder) return (ret != GST_FLOW_ERROR); } -gint -compare_video_code_frame_and_pts (const void *video_codec_frame_ptr, - const void *pts_ptr) -{ - return ((GstVideoCodecFrame *) video_codec_frame_ptr)->pts - - *((GstClockTime *) pts_ptr); -} - GstFlowReturn gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, gboolean done_sending_pics, gboolean output_frames) @@ -668,7 +654,6 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, do { GList *pending_frames = NULL; - GList *frame_list_element = NULL; GstVideoCodecFrame *frame = NULL; EbBufferHeaderType *output_buf = NULL; @@ -684,26 +669,8 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("encode failed")); return GST_FLOW_ERROR; } else if (res != EB_NoErrorEmptyQueue && output_frames && output_buf) { - /* if p_app_private is indeed propagated, get the frame through it - * it's not currently the case with SVT-AV1 - * so we fallback on using its PTS to find it back */ - if (output_buf->p_app_private) { - EbPrivDataNode *private_data = (EbPrivDataNode *) output_buf->p_app_private; - frame = (GstVideoCodecFrame *) private_data->data; - } else { - pending_frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER - (svtav1enc)); - frame_list_element = g_list_find_custom (pending_frames, - &output_buf->pts, compare_video_code_frame_and_pts); - - if (frame_list_element == NULL) { - GST_ELEMENT_ERROR (svtav1enc, LIBRARY, ENCODE, (NULL), ("failed to get unfinished frame")); - return GST_FLOW_ERROR; - } - - frame = (GstVideoCodecFrame *) frame_list_element->data; - } - + // 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); From 3b3e862580f4668f23edff0bd441fbec7f138cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:04:07 +0200 Subject: [PATCH 50/81] gstreamer: Don't set a DTS and remove non-working DTS hack The previous hack would create bogus DTS that confused other elements. Fixes https://gitlab.com/AOMediaCodec/SVT-AV1/-/issues/1915 --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 595fbf1708..233b96e0be 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -298,7 +298,6 @@ gst_svtav1enc_init (GstSvtAv1Enc * svtav1enc) } memset (&svtav1enc->svt_encoder, 0, sizeof (svtav1enc->svt_encoder)); svtav1enc->frame_count = 0; - svtav1enc->dts_offset = 0; EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); @@ -682,29 +681,11 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, gst_buffer_fill (frame->output_buffer, 0, output_buf->p_buffer, output_buf->n_filled_len); - - /* SVT-AV1 may return first frames with a negative DTS, - * offsetting it to start at 0 since GStreamer 1.x doesn't support it */ - if (output_buf->dts + svtav1enc->dts_offset < 0) { - svtav1enc->dts_offset = -output_buf->dts; - } - /* Gstreamer doesn't support negative DTS so we return - * very small increasing ones for the first frames. */ - if (output_buf->dts < 1) { - frame->dts = frame->output_buffer->dts = - output_buf->dts + svtav1enc->dts_offset; - } else { - frame->dts = frame->output_buffer->dts = - (output_buf->dts * - svtav1enc->svt_config->frame_rate_denominator * GST_SECOND) / - svtav1enc->svt_config->frame_rate_numerator; - } - frame->pts = frame->output_buffer->pts = output_buf->pts; - GST_LOG_OBJECT (svtav1enc, "#frame:%lld dts:%" G_GINT64_FORMAT " pts:%" + GST_LOG_OBJECT (svtav1enc, "#frame:%lld pts:%" G_GINT64_FORMAT " SliceType:%d\n", svtav1enc->frame_count, - (frame->dts), (frame->pts), output_buf->pic_type); + (frame->pts), output_buf->pic_type); svt_av1_enc_release_out_buffer(&output_buf); output_buf = NULL; From 158c1f66026f173cb97cefc4cbc83347177f83ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:06:58 +0200 Subject: [PATCH 51/81] gstreamer: Don't unnecessarily override `decide_allocation()` This avoids more optimal output buffer allocation. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 233b96e0be..854792e4d9 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -62,8 +62,6 @@ static gboolean gst_svtav1enc_sink_event (GstVideoEncoder * encoder, static gboolean gst_svtav1enc_src_event (GstVideoEncoder * encoder, GstEvent * event); static gboolean gst_svtav1enc_negotiate (GstVideoEncoder * encoder); -static gboolean gst_svtav1enc_decide_allocation (GstVideoEncoder * encoder, - GstQuery * query); static gboolean gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query); static gboolean gst_svtav1enc_flush (GstVideoEncoder * encoder); @@ -180,8 +178,6 @@ gst_svtav1enc_class_init (GstSvtAv1EncClass * klass) GST_DEBUG_FUNCPTR (gst_svtav1enc_sink_event); video_encoder_class->src_event = GST_DEBUG_FUNCPTR (gst_svtav1enc_src_event); video_encoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_svtav1enc_negotiate); - video_encoder_class->decide_allocation = - GST_DEBUG_FUNCPTR (gst_svtav1enc_decide_allocation); video_encoder_class->propose_allocation = GST_DEBUG_FUNCPTR (gst_svtav1enc_propose_allocation); video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_svtav1enc_flush); @@ -904,16 +900,6 @@ gst_svtav1enc_negotiate (GstVideoEncoder * encoder) GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->negotiate(encoder); } -static gboolean -gst_svtav1enc_decide_allocation (GstVideoEncoder * encoder, GstQuery * query) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "decide_allocation"); - - return TRUE; -} - static gboolean gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) { From c5b166491cc03f642d1e7f89f59195429bf25a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:10:13 +0200 Subject: [PATCH 52/81] gstreamer: Don't override various virtual methods unnecessarily There was no custom behaviour in there. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 115 ------------------ 1 file changed, 115 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 854792e4d9..eadee133b5 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -44,24 +44,12 @@ 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 GstFlowReturn gst_svtav1enc_pre_push (GstVideoEncoder * encoder, - GstVideoCodecFrame * frame); -static GstCaps *gst_svtav1enc_getcaps (GstVideoEncoder * encoder, - GstCaps * filter); -static gboolean gst_svtav1enc_sink_event (GstVideoEncoder * encoder, - GstEvent * event); -static gboolean gst_svtav1enc_src_event (GstVideoEncoder * encoder, - GstEvent * event); -static gboolean gst_svtav1enc_negotiate (GstVideoEncoder * encoder); static gboolean gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query); static gboolean gst_svtav1enc_flush (GstVideoEncoder * encoder); @@ -163,21 +151,12 @@ gst_svtav1enc_class_init (GstSvtAv1EncClass * klass) gobject_class->get_property = gst_svtav1enc_get_property; gobject_class->dispose = gst_svtav1enc_dispose; 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->pre_push = GST_DEBUG_FUNCPTR (gst_svtav1enc_pre_push); - video_encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_svtav1enc_getcaps); - video_encoder_class->sink_event = - GST_DEBUG_FUNCPTR (gst_svtav1enc_sink_event); - video_encoder_class->src_event = GST_DEBUG_FUNCPTR (gst_svtav1enc_src_event); - video_encoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_svtav1enc_negotiate); video_encoder_class->propose_allocation = GST_DEBUG_FUNCPTR (gst_svtav1enc_propose_allocation); video_encoder_class->flush = GST_DEBUG_FUNCPTR (gst_svtav1enc_flush); @@ -701,38 +680,6 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, return ret; } -static gboolean -gst_svtav1enc_open (GstVideoEncoder * encoder) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "open"); - - return TRUE; -} - -static gboolean -gst_svtav1enc_close (GstVideoEncoder * encoder) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "close"); - - return TRUE; -} - -static gboolean -gst_svtav1enc_start (GstVideoEncoder * encoder) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "start"); - /* starting the encoder is done in set_format, - * once caps are fully negotiated */ - - return TRUE; -} - static gboolean gst_svtav1enc_stop (GstVideoEncoder * encoder) { @@ -838,68 +785,6 @@ gst_svtav1enc_finish (GstVideoEncoder * encoder) return gst_svtav1enc_dequeue_encoded_frames (svtav1enc, TRUE, TRUE); } -static GstFlowReturn -gst_svtav1enc_pre_push (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "pre_push"); - - return GST_FLOW_OK; -} - -static GstCaps * -gst_svtav1enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "getcaps"); - - GstCaps *sink_caps = - gst_static_pad_template_get_caps (&gst_svtav1enc_sink_pad_template); - GstCaps *ret = - gst_video_encoder_proxy_getcaps (GST_VIDEO_ENCODER (svtav1enc), - sink_caps, filter); - gst_caps_unref (sink_caps); - - return ret; -} - -static gboolean -gst_svtav1enc_sink_event (GstVideoEncoder * encoder, GstEvent * event) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "sink_event"); - - return - GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->sink_event - (encoder, event); -} - -static gboolean -gst_svtav1enc_src_event (GstVideoEncoder * encoder, GstEvent * event) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "src_event"); - - return - GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->src_event (encoder, - event); -} - -static gboolean -gst_svtav1enc_negotiate (GstVideoEncoder * encoder) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); - - GST_DEBUG_OBJECT (svtav1enc, "negotiate"); - - return - GST_VIDEO_ENCODER_CLASS (gst_svtav1enc_parent_class)->negotiate(encoder); -} - static gboolean gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) { From 785ba05bcab8af0ea6a9628ecf8f7f79b0a1b211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:11:48 +0200 Subject: [PATCH 53/81] gstreamer: Announce support for video meta on the input side This allows handling input buffers with non-default strides, which was already handled fine by the element code. Without this, potentially expensive conversion was needed. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index eadee133b5..e12a27458d 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -792,7 +792,9 @@ gst_svtav1enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) GST_DEBUG_OBJECT (svtav1enc, "propose_allocation"); - return TRUE; + 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 gboolean From 9128978042d5c9c21cccbf3232a2f6e39bd5616a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:13:21 +0200 Subject: [PATCH 54/81] gstreamer: The encoder has no maximum latency It will buffer as much as it needs to. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index e12a27458d..4d5a2d4ca6 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -736,12 +736,11 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, min_latency_frames = ((fps * 5) >> 2); - /* TODO: find a better value for max_latency */ gst_video_encoder_set_latency(encoder, min_latency_frames * GST_SECOND / (svtav1enc->svt_config->frame_rate_numerator / svtav1enc->svt_config->frame_rate_denominator), - 3 * GST_SECOND); + -1); src_caps = gst_static_pad_template_get_caps (&gst_svtav1enc_src_pad_template); From 13fa6d387db295151a565deeafa7933b0293dd04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:14:41 +0200 Subject: [PATCH 55/81] gstreamer: Fix reference leak of the input state if the caps are changing Also remove misleading comment: reconfiguration was already handled by the following code. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 4d5a2d4ca6..b559ee5be8 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -721,8 +721,8 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, GstCaps *src_caps = NULL; GST_DEBUG_OBJECT (svtav1enc, "set_format"); - /* TODO: handle configuration changes while encoder is running - * and if there was already a state. */ + if (svtav1enc->state) + gst_video_codec_state_unref (svtav1enc->state); svtav1enc->state = gst_video_codec_state_ref (state); gst_svtav1enc_configure_svt (svtav1enc); From b498bdb7655b085556f6c5c35d08fef69a117c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:17:07 +0200 Subject: [PATCH 56/81] gstreamer: Add missing property setter/getter for lookahead property --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index b559ee5be8..351e0801cf 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -347,6 +347,9 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, case PROP_SOCKET: svtav1enc->svt_config->target_socket = g_value_get_int (value); break; + case PROP_LOOKAHEAD: + svtav1enc->svt_config->look_ahead_distance = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -409,6 +412,9 @@ gst_svtav1enc_get_property (GObject * object, guint property_id, case PROP_SOCKET: g_value_set_int (value, svtav1enc->svt_config->target_socket); break; + case PROP_LOOKAHEAD: + g_value_set_int (value, svtav1enc->svt_config->look_ahead_distance); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; From d9efa5478330e34e00ecb30f3b7dc926c5dacc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:19:04 +0200 Subject: [PATCH 57/81] gstreamer: Fix output state reference leak --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 351e0801cf..e0d78defef 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -725,6 +725,7 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, 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) @@ -750,9 +751,10 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, src_caps = gst_static_pad_template_get_caps (&gst_svtav1enc_src_pad_template); - gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder), src_caps, + output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder), src_caps, svtav1enc->state); gst_caps_unref (src_caps); + gst_video_codec_state_unref (output_state); GST_DEBUG_OBJECT (svtav1enc, "output caps: %" GST_PTR_FORMAT, svtav1enc->state->caps); From 30e0c1e4fd1cdc90d13ee0babc93799908b0ad05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:19:12 +0200 Subject: [PATCH 58/81] gstreamer: Negotiate the encoder immediately after setting the format --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index e0d78defef..0d7b6f7f6e 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -759,7 +759,7 @@ gst_svtav1enc_set_format (GstVideoEncoder * encoder, GST_DEBUG_OBJECT (svtav1enc, "output caps: %" GST_PTR_FORMAT, svtav1enc->state->caps); - return TRUE; + return gst_video_encoder_negotiate (encoder); } static GstFlowReturn From 85b9c8e103b15f1bf74c5ab2d2e77004d682b297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:21:26 +0200 Subject: [PATCH 59/81] gstreamer: Allocate output buffers via the encoder This makes sure the correct allocator and configuration is used. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 0d7b6f7f6e..6f5cb90141 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -656,8 +656,11 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); } - frame->output_buffer = - gst_buffer_new_allocate (NULL, output_buf->n_filled_len, NULL); + 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_FLAG_SET(frame->output_buffer, GST_BUFFER_FLAG_LIVE); gst_buffer_fill (frame->output_buffer, 0, output_buf->p_buffer, output_buf->n_filled_len); From 5f03d9c4d1a3f2969e66dec5a160e0f3d166e298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:22:01 +0200 Subject: [PATCH 60/81] gstreamer: Don't set bogus LIVE flag on output buffers --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 6f5cb90141..a10e65e07a 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -661,7 +661,6 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, gst_video_codec_frame_unref (frame); return ret; } - GST_BUFFER_FLAG_SET(frame->output_buffer, GST_BUFFER_FLAG_LIVE); gst_buffer_fill (frame->output_buffer, 0, output_buf->p_buffer, output_buf->n_filled_len); From 040c92d8b04f991da81d1f794bb9351a5959056a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:22:24 +0200 Subject: [PATCH 61/81] gstreamer: Stop outputting frames if pushing one has caused an error --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index a10e65e07a..b0f85af9b9 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -683,7 +683,7 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, svtav1enc->frame_count++; } - } while (res == EB_ErrorNone && !encode_at_eos); + } while (res == EB_ErrorNone && !encode_at_eos && ret == GST_FLOW_OK); return ret; } From f56e8b2fade39eda1053a2a761708657a7753bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:23:03 +0200 Subject: [PATCH 62/81] gstreamer: Remove unused variable --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index b0f85af9b9..14359eefa3 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -633,7 +633,6 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, gboolean encode_at_eos = FALSE; do { - GList *pending_frames = NULL; GstVideoCodecFrame *frame = NULL; EbBufferHeaderType *output_buf = NULL; @@ -675,11 +674,6 @@ gst_svtav1enc_dequeue_encoded_frames (GstSvtAv1Enc * svtav1enc, ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (svtav1enc), frame); - if (pending_frames != NULL) { - g_list_free_full (pending_frames, - (GDestroyNotify) gst_video_codec_frame_unref); - } - svtav1enc->frame_count++; } From ff911c76c0436ec9838120640ffddc2f5dd7784a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:23:35 +0200 Subject: [PATCH 63/81] gstreamer: Don't explicitly drop frames on `stop()` This is already handled by the base class. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 14359eefa3..bcaec83247 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -689,16 +689,6 @@ gst_svtav1enc_stop (GstVideoEncoder * encoder) GST_DEBUG_OBJECT (svtav1enc, "stop"); - GstVideoCodecFrame *remaining_frame = NULL; - while ((remaining_frame = - gst_video_encoder_get_oldest_frame (encoder)) != NULL) { - GST_WARNING_OBJECT (svtav1enc, - "encoder is being stopped, dropping frame %d", - remaining_frame->system_frame_number); - remaining_frame->output_buffer = NULL; - gst_video_encoder_finish_frame (encoder, remaining_frame); - } - GST_OBJECT_LOCK (svtav1enc); if (svtav1enc->state) gst_video_codec_state_unref (svtav1enc->state); From 7652026f0dd591913634a55ba19d7889dd825584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 11 Jan 2023 15:40:25 +0200 Subject: [PATCH 64/81] gstreamer: Don't leak all video frames --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index bcaec83247..f2dde2539c 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -758,6 +758,7 @@ gst_svtav1enc_handle_frame (GstVideoEncoder * encoder, 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; From 80e364876b51feffc7b77865d073e1f115be21dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Jan 2023 21:38:00 +0200 Subject: [PATCH 65/81] gstreamer: Fix code style by running `clang-format` --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1288 ++++++++--------- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.h | 45 +- 2 files changed, 648 insertions(+), 685 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index f2dde2539c..6caa695d6d 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -24,286 +24,335 @@ #include #include "gstsvtav1enc.h" -GST_DEBUG_CATEGORY_STATIC (gst_svtav1enc_debug_category); +GST_DEBUG_CATEGORY_STATIC(gst_svtav1enc_debug_category); #define GST_CAT_DEFAULT gst_svtav1enc_debug_category /* 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_dispose (GObject * object); -static void gst_svtav1enc_finalize (GObject * object); +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_dispose(GObject *object); +static void gst_svtav1enc_finalize(GObject *object); -gboolean gst_svtav1enc_allocate_svt_buffers (GstSvtAv1Enc * svtav1enc); -void gst_svthevenc_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); +gboolean gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc); +void gst_svthevenc_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_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 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); /* helpers */ -gint compare_video_code_frame_and_pts (const void *video_codec_frame_ptr, - const void *pts_ptr); +gint compare_video_code_frame_and_pts(const void *video_codec_frame_ptr, const void *pts_ptr); -enum -{ - PROP_0, - PROP_ENCMODE, - PROP_B_PYRAMID, - PROP_P_FRAMES, - PROP_PRED_STRUCTURE, - PROP_GOP_SIZE, - PROP_INTRA_REFRESH, - PROP_QP, - PROP_QP_MAX, - PROP_QP_MIN, - PROP_DEBLOCKING, - PROP_RC_MODE, - PROP_BITRATE, - PROP_LOOKAHEAD, - PROP_SCD, - PROP_CORES, - PROP_SOCKET +enum { + PROP_0, + PROP_ENCMODE, + PROP_B_PYRAMID, + PROP_P_FRAMES, + PROP_PRED_STRUCTURE, + PROP_GOP_SIZE, + PROP_INTRA_REFRESH, + PROP_QP, + PROP_QP_MAX, + PROP_QP_MIN, + PROP_DEBLOCKING, + PROP_RC_MODE, + PROP_BITRATE, + PROP_LOOKAHEAD, + PROP_SCD, + PROP_CORES, + PROP_SOCKET }; #define PROP_RC_MODE_CQP 0 #define PROP_RC_MODE_VBR 1 -#define PROP_ENCMODE_DEFAULT 8 -#define PROP_HIERARCHICAL_LEVEL_DEFAULT 4 -#define PROP_P_FRAMES_DEFAULT 0 -#define PROP_PRED_STRUCTURE_DEFAULT 2 -#define PROP_GOP_SIZE_DEFAULT -1 -#define PROP_INTRA_REFRESH_DEFAULT 1 -#define PROP_QP_DEFAULT 50 -#define PROP_DEBLOCKING_DEFAULT TRUE -#define PROP_RC_MODE_DEFAULT PROP_RC_MODE_CQP -#define PROP_BITRATE_DEFAULT 7000000 -#define PROP_QP_MAX_DEFAULT 63 -#define PROP_QP_MIN_DEFAULT 0 -#define PROP_LOOKAHEAD_DEFAULT (unsigned int)-1 -#define PROP_SCD_DEFAULT FALSE -#define PROP_AUD_DEFAULT FALSE -#define PROP_CORES_DEFAULT 0 -#define PROP_SOCKET_DEFAULT -1 +#define PROP_ENCMODE_DEFAULT 8 +#define PROP_HIERARCHICAL_LEVEL_DEFAULT 4 +#define PROP_P_FRAMES_DEFAULT 0 +#define PROP_PRED_STRUCTURE_DEFAULT 2 +#define PROP_GOP_SIZE_DEFAULT -1 +#define PROP_INTRA_REFRESH_DEFAULT 1 +#define PROP_QP_DEFAULT 50 +#define PROP_DEBLOCKING_DEFAULT TRUE +#define PROP_RC_MODE_DEFAULT PROP_RC_MODE_CQP +#define PROP_BITRATE_DEFAULT 7000000 +#define PROP_QP_MAX_DEFAULT 63 +#define PROP_QP_MIN_DEFAULT 0 +#define PROP_LOOKAHEAD_DEFAULT (unsigned int)-1 +#define PROP_SCD_DEFAULT FALSE +#define PROP_AUD_DEFAULT FALSE +#define PROP_CORES_DEFAULT 0 +#define PROP_SOCKET_DEFAULT -1 /* 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, I420_10LE}, " - "width = (int) [64, 3840], " - "height = (int) [64, 2160], " "framerate = (fraction) [0, MAX]") - ); +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, I420_10LE}, " + "width = (int) [64, 3840], " + "height = (int) [64, 2160], " + "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) byte-stream, " - "alignment = (string) au, " - "width = (int) [64, 3840], " - "height = (int) [64, 2160], " "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) byte-stream, " + "alignment = (string) au, " + "width = (int) [64, 3840], " + "height = (int) [64, 2160], " + "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, - "debug category for SVT-AV1 encoder element")); +G_DEFINE_TYPE_WITH_CODE(GstSvtAv1Enc, gst_svtav1enc, GST_TYPE_VIDEO_ENCODER, + GST_DEBUG_CATEGORY_INIT(gst_svtav1enc_debug_category, "svtav1enc", 0, + "debug category for 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); +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); +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_src_pad_template); - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass), - &gst_svtav1enc_sink_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 Xavier Hallade "); + 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 Xavier Hallade "); - gobject_class->set_property = gst_svtav1enc_set_property; - gobject_class->get_property = gst_svtav1enc_get_property; - gobject_class->dispose = gst_svtav1enc_dispose; - gobject_class->finalize = gst_svtav1enc_finalize; - 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); + gobject_class->set_property = gst_svtav1enc_set_property; + gobject_class->get_property = gst_svtav1enc_get_property; + gobject_class->dispose = gst_svtav1enc_dispose; + gobject_class->finalize = gst_svtav1enc_finalize; + 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_ENCMODE, - g_param_spec_uint ("speed", "speed (Encoder Mode)", - "Quality vs density tradeoff point" - " that the encoding is to be performed at" - " (0 is the highest quality, 12 is the highest speed) ", - 0, 12, PROP_ENCMODE_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_ENCMODE, + g_param_spec_uint("speed", + "speed (Encoder Mode)", + "Quality vs density tradeoff point" + " that the encoding is to be performed at" + " (0 is the highest quality, 12 is the highest speed) ", + 0, + 12, + PROP_ENCMODE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_B_PYRAMID, - g_param_spec_uint ("hierarchical-level", "Hierarchical levels", - "3 : 4 - Level Hierarchy," - "4 : 5 - Level Hierarchy", - 3, 4, PROP_HIERARCHICAL_LEVEL_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, + PROP_B_PYRAMID, + g_param_spec_uint("hierarchical-level", + "Hierarchical levels", + "3 : 4 - Level Hierarchy," + "4 : 5 - Level Hierarchy", + 3, + 4, + PROP_HIERARCHICAL_LEVEL_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - //g_object_class_install_property (gobject_class, PROP_P_FRAMES, - // g_param_spec_boolean ("p-frames", "P Frames", - // "Use P-frames in the base layer", - // PROP_P_FRAMES_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + //g_object_class_install_property (gobject_class, PROP_P_FRAMES, + // g_param_spec_boolean ("p-frames", "P Frames", + // "Use P-frames in the base layer", + // PROP_P_FRAMES_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - //g_object_class_install_property (gobject_class, PROP_PRED_STRUCTURE, - // g_param_spec_uint ("pred-struct", "Prediction Structure", - // "0 : Low Delay P, 1 : Low Delay B" - // ", 2 : Random Access", - // 0, 2, PROP_PRED_STRUCTURE_DEFAULT, - // G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + //g_object_class_install_property (gobject_class, PROP_PRED_STRUCTURE, + // g_param_spec_uint ("pred-struct", "Prediction Structure", + // "0 : Low Delay P, 1 : Low Delay B" + // ", 2 : Random Access", + // 0, 2, PROP_PRED_STRUCTURE_DEFAULT, + // G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_GOP_SIZE, - g_param_spec_int ("gop-size", "GOP size", - "Period of Intra Frames insertion (-1 is auto)", - -1, 251, PROP_GOP_SIZE_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_GOP_SIZE, + g_param_spec_int("gop-size", + "GOP size", + "Period of Intra Frames insertion (-1 is auto)", + -1, + 251, + PROP_GOP_SIZE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH, - g_param_spec_int ("intra-refresh", "Intra refresh type", - "CRA (open GOP)" - "or IDR frames (closed GOP)", - 1, 2, PROP_INTRA_REFRESH_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP, - g_param_spec_uint ("qp", "Quantization parameter", - "Quantization parameter used in CQP mode", - 0, 63, PROP_QP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, + PROP_INTRA_REFRESH, + g_param_spec_int("intra-refresh", + "Intra refresh type", + "CRA (open GOP)" + "or IDR frames (closed GOP)", + 1, + 2, + PROP_INTRA_REFRESH_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, + PROP_QP, + g_param_spec_uint("qp", + "Quantization parameter", + "Quantization parameter used in CQP mode", + 0, + 63, + PROP_QP_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_DEBLOCKING, - g_param_spec_boolean ("deblocking", "Deblock Filter", - "Enable Deblocking Loop Filtering", - PROP_DEBLOCKING_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_DEBLOCKING, + g_param_spec_boolean("deblocking", + "Deblock Filter", + "Enable Deblocking Loop Filtering", + PROP_DEBLOCKING_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_RC_MODE, - g_param_spec_uint ("rc", "Rate-control mode", - "0 : CQP, 1 : VBR", - 0, 1, PROP_RC_MODE_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, + PROP_RC_MODE, + g_param_spec_uint("rc", + "Rate-control mode", + "0 : CQP, 1 : VBR", + 0, + 1, + PROP_RC_MODE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /* TODO: add GST_PARAM_MUTABLE_PLAYING property and handle it? */ - g_object_class_install_property (gobject_class, PROP_BITRATE, - g_param_spec_uint ("bitrate", "Target bitrate", - "Target bitrate in bits/sec. Only used when in VBR mode", - 1, G_MAXUINT, PROP_BITRATE_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /* TODO: add GST_PARAM_MUTABLE_PLAYING property and handle it? */ + g_object_class_install_property( + gobject_class, + PROP_BITRATE, + g_param_spec_uint("bitrate", + "Target bitrate", + "Target bitrate in bits/sec. Only used when in VBR mode", + 1, + G_MAXUINT, + PROP_BITRATE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MAX, - g_param_spec_uint ("max-qp", "Max Quantization parameter", - "Maximum QP value allowed for rate control use" - " Only used in VBR mode.", - 0, 63, PROP_QP_MAX_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_QP_MAX, + g_param_spec_uint("max-qp", + "Max Quantization parameter", + "Maximum QP value allowed for rate control use" + " Only used in VBR mode.", + 0, + 63, + PROP_QP_MAX_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MIN, - g_param_spec_uint ("min-qp", "Min Quantization parameter", - "Minimum QP value allowed for rate control use" - " Only used in VBR mode.", - 0, 63, PROP_QP_MIN_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_QP_MIN, + g_param_spec_uint("min-qp", + "Min Quantization parameter", + "Minimum QP value allowed for rate control use" + " Only used in VBR mode.", + 0, + 63, + PROP_QP_MIN_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_LOOKAHEAD, - g_param_spec_int ("lookahead", "Look Ahead Distance", - "Number of frames to look ahead. -1 lets the encoder pick a value", - -1, 250, PROP_LOOKAHEAD_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_LOOKAHEAD, + g_param_spec_int("lookahead", + "Look Ahead Distance", + "Number of frames to look ahead. -1 lets the encoder pick a value", + -1, + 250, + PROP_LOOKAHEAD_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_SCD, - g_param_spec_boolean ("scd", "Scene Change Detection", - "Enable Scene Change Detection algorithm", - PROP_SCD_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + gobject_class, + PROP_SCD, + g_param_spec_boolean("scd", + "Scene Change Detection", + "Enable Scene Change Detection algorithm", + PROP_SCD_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_CORES, - g_param_spec_uint ("cores", "Number of logical cores", - "Number of logical cores to be used. 0: auto", - 0, UINT_MAX, PROP_CORES_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, + PROP_CORES, + g_param_spec_uint("cores", + "Number of logical cores", + "Number of logical cores to be used. 0: auto", + 0, + UINT_MAX, + PROP_CORES_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_SOCKET, - g_param_spec_int ("socket", "Target socket", - "Target socket to run on. -1: all available", - -1, 15, PROP_SOCKET_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, + PROP_SOCKET, + g_param_spec_int("socket", + "Target socket", + "Target socket to run on. -1: all available", + -1, + 15, + PROP_SOCKET_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } -static void -gst_svtav1enc_init (GstSvtAv1Enc * svtav1enc) -{ - GST_OBJECT_LOCK (svtav1enc); - svtav1enc->svt_config = g_malloc (sizeof (EbSvtAv1EncConfiguration)); - if (!svtav1enc->svt_config) { - GST_ERROR_OBJECT (svtav1enc, "insufficient resources"); - GST_OBJECT_UNLOCK (svtav1enc); - return; - } - memset (&svtav1enc->svt_encoder, 0, sizeof (svtav1enc->svt_encoder)); - svtav1enc->frame_count = 0; +static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { + GST_OBJECT_LOCK(svtav1enc); + svtav1enc->svt_config = g_malloc(sizeof(EbSvtAv1EncConfiguration)); + if (!svtav1enc->svt_config) { + GST_ERROR_OBJECT(svtav1enc, "insufficient resources"); + GST_OBJECT_UNLOCK(svtav1enc); + return; + } + memset(&svtav1enc->svt_encoder, 0, sizeof(svtav1enc->svt_encoder)); + svtav1enc->frame_count = 0; - 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)); - GST_OBJECT_UNLOCK (svtav1enc); - return; - } - /* setting configuration here since svt_av1_enc_init_handle overrides it */ - GST_OBJECT_UNLOCK (svtav1enc); + 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)); + GST_OBJECT_UNLOCK(svtav1enc); + return; + } + /* setting configuration here since svt_av1_enc_init_handle overrides it */ + GST_OBJECT_UNLOCK(svtav1enc); } -void -gst_svtav1enc_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (object); +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; - } + /* 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); + GST_LOG_OBJECT(svtav1enc, "setting property %u", property_id); - switch (property_id) { - case PROP_ENCMODE: - svtav1enc->svt_config->enc_mode = g_value_get_uint (value); - break; + switch (property_id) { + case PROP_ENCMODE: svtav1enc->svt_config->enc_mode = g_value_get_uint(value); break; case PROP_GOP_SIZE: svtav1enc->svt_config->intra_period_length = g_value_get_int(value) - 1; break; @@ -311,491 +360,414 @@ gst_svtav1enc_set_property (GObject * object, guint property_id, svtav1enc->svt_config->intra_refresh_type = g_value_get_int(value); break; case PROP_B_PYRAMID: - svtav1enc->svt_config->hierarchical_levels = g_value_get_uint (value); - break; + svtav1enc->svt_config->hierarchical_levels = g_value_get_uint(value); + break; case PROP_PRED_STRUCTURE: svtav1enc->svt_config->pred_structure = g_value_get_uint(value); break; - - - case PROP_QP: - svtav1enc->svt_config->qp = g_value_get_uint (value); - break; + case PROP_QP: svtav1enc->svt_config->qp = g_value_get_uint(value); break; case PROP_DEBLOCKING: - svtav1enc->svt_config->enable_dlf_flag = g_value_get_boolean (value); - break; - case PROP_RC_MODE: - svtav1enc->svt_config->rate_control_mode = g_value_get_uint (value); - break; + svtav1enc->svt_config->enable_dlf_flag = g_value_get_boolean(value); + break; + case PROP_RC_MODE: svtav1enc->svt_config->rate_control_mode = g_value_get_uint(value); break; case PROP_BITRATE: - svtav1enc->svt_config->target_bit_rate = g_value_get_uint (value) * 1000; - break; - case PROP_QP_MAX: - svtav1enc->svt_config->max_qp_allowed = g_value_get_uint (value); - break; - case PROP_QP_MIN: - svtav1enc->svt_config->min_qp_allowed = g_value_get_uint (value); - break; + svtav1enc->svt_config->target_bit_rate = g_value_get_uint(value) * 1000; + break; + case PROP_QP_MAX: svtav1enc->svt_config->max_qp_allowed = g_value_get_uint(value); break; + case PROP_QP_MIN: svtav1enc->svt_config->min_qp_allowed = g_value_get_uint(value); break; case PROP_SCD: - svtav1enc->svt_config->scene_change_detection = - g_value_get_boolean (value); - break; - case PROP_CORES: - svtav1enc->svt_config->logical_processors = g_value_get_uint (value); - break; - case PROP_SOCKET: - svtav1enc->svt_config->target_socket = g_value_get_int (value); - break; - case PROP_LOOKAHEAD: - svtav1enc->svt_config->look_ahead_distance = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } + svtav1enc->svt_config->scene_change_detection = g_value_get_boolean(value); + break; + case PROP_CORES: svtav1enc->svt_config->logical_processors = g_value_get_uint(value); break; + case PROP_SOCKET: svtav1enc->svt_config->target_socket = g_value_get_int(value); break; + case PROP_LOOKAHEAD: svtav1enc->svt_config->look_ahead_distance = g_value_get_int(value); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; + } } -void -gst_svtav1enc_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (object); +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); + GST_LOG_OBJECT(svtav1enc, "getting property %u", property_id); - switch (property_id) { - case PROP_ENCMODE: - g_value_set_uint (value, svtav1enc->svt_config->enc_mode); - break; - case PROP_B_PYRAMID: - g_value_set_uint (value, svtav1enc->svt_config->hierarchical_levels); - break; + switch (property_id) { + case PROP_ENCMODE: g_value_set_uint(value, svtav1enc->svt_config->enc_mode); break; + case PROP_B_PYRAMID: g_value_set_uint(value, svtav1enc->svt_config->hierarchical_levels); break; - - - - case PROP_PRED_STRUCTURE: - g_value_set_uint (value, svtav1enc->svt_config->pred_structure); - break; + case PROP_PRED_STRUCTURE: g_value_set_uint(value, svtav1enc->svt_config->pred_structure); break; case PROP_GOP_SIZE: - g_value_set_int (value, svtav1enc->svt_config->intra_period_length + 1); - break; + g_value_set_int(value, svtav1enc->svt_config->intra_period_length + 1); + break; case PROP_INTRA_REFRESH: g_value_set_int(value, svtav1enc->svt_config->intra_refresh_type); - break; - case PROP_QP: - g_value_set_uint (value, svtav1enc->svt_config->qp); - break; + break; + case PROP_QP: g_value_set_uint(value, svtav1enc->svt_config->qp); break; case PROP_DEBLOCKING: - g_value_set_boolean (value, svtav1enc->svt_config->enable_dlf_flag == 1); - break; - case PROP_RC_MODE: - g_value_set_uint (value, svtav1enc->svt_config->rate_control_mode); - break; + g_value_set_boolean(value, svtav1enc->svt_config->enable_dlf_flag == 1); + break; + case PROP_RC_MODE: g_value_set_uint(value, svtav1enc->svt_config->rate_control_mode); break; case PROP_BITRATE: - g_value_set_uint (value, svtav1enc->svt_config->target_bit_rate / 1000); - break; - case PROP_QP_MAX: - g_value_set_uint (value, svtav1enc->svt_config->max_qp_allowed); - break; - case PROP_QP_MIN: - g_value_set_uint (value, svtav1enc->svt_config->min_qp_allowed); - break; + g_value_set_uint(value, svtav1enc->svt_config->target_bit_rate / 1000); + break; + case PROP_QP_MAX: g_value_set_uint(value, svtav1enc->svt_config->max_qp_allowed); break; + case PROP_QP_MIN: g_value_set_uint(value, svtav1enc->svt_config->min_qp_allowed); break; case PROP_SCD: - g_value_set_boolean (value, - svtav1enc->svt_config->scene_change_detection == 1); - break; - case PROP_CORES: - g_value_set_uint (value, svtav1enc->svt_config->logical_processors); - break; - case PROP_SOCKET: - g_value_set_int (value, svtav1enc->svt_config->target_socket); - break; - case PROP_LOOKAHEAD: - g_value_set_int (value, svtav1enc->svt_config->look_ahead_distance); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } + g_value_set_boolean(value, svtav1enc->svt_config->scene_change_detection == 1); + break; + case PROP_CORES: g_value_set_uint(value, svtav1enc->svt_config->logical_processors); break; + case PROP_SOCKET: g_value_set_int(value, svtav1enc->svt_config->target_socket); break; + case PROP_LOOKAHEAD: g_value_set_int(value, svtav1enc->svt_config->look_ahead_distance); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; + } } -void -gst_svtav1enc_dispose (GObject * object) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (object); +void gst_svtav1enc_dispose(GObject *object) { + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object); - GST_DEBUG_OBJECT (svtav1enc, "dispose"); + GST_DEBUG_OBJECT(svtav1enc, "dispose"); - /* clean up as possible. may be called multiple times */ - if (svtav1enc->state) - gst_video_codec_state_unref (svtav1enc->state); - svtav1enc->state = NULL; + /* clean up as possible. may be called multiple times */ + if (svtav1enc->state) + gst_video_codec_state_unref(svtav1enc->state); + svtav1enc->state = NULL; - G_OBJECT_CLASS (gst_svtav1enc_parent_class)->dispose (object); + G_OBJECT_CLASS(gst_svtav1enc_parent_class)->dispose(object); } -void -gst_svtav1enc_finalize (GObject * object) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (object); +void gst_svtav1enc_finalize(GObject *object) { + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object); - GST_DEBUG_OBJECT (svtav1enc, "finalizing svtav1enc"); + GST_DEBUG_OBJECT(svtav1enc, "finalizing svtav1enc"); - GST_OBJECT_LOCK (svtav1enc); - svt_av1_enc_deinit_handle(svtav1enc->svt_encoder); - svtav1enc->svt_encoder = NULL; - g_free (svtav1enc->svt_config); - GST_OBJECT_UNLOCK (svtav1enc); + GST_OBJECT_LOCK(svtav1enc); + svt_av1_enc_deinit_handle(svtav1enc->svt_encoder); + svtav1enc->svt_encoder = NULL; + g_free(svtav1enc->svt_config); + GST_OBJECT_UNLOCK(svtav1enc); - G_OBJECT_CLASS (gst_svtav1enc_parent_class)->finalize (object); + G_OBJECT_CLASS(gst_svtav1enc_parent_class)->finalize(object); } -gboolean -gst_svtav1enc_allocate_svt_buffers (GstSvtAv1Enc * svtav1enc) -{ - svtav1enc->input_buf = g_malloc (sizeof (EbBufferHeaderType)); - if (!svtav1enc->input_buf) { - GST_ERROR_OBJECT (svtav1enc, "insufficient resources"); - return FALSE; - } - svtav1enc->input_buf->p_buffer = g_malloc (sizeof (EbSvtIOFormat)); - if (!svtav1enc->input_buf->p_buffer) { - GST_ERROR_OBJECT (svtav1enc, "insufficient resources"); - return FALSE; - } - memset(svtav1enc->input_buf->p_buffer, 0, sizeof(EbSvtIOFormat)); - 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; +gboolean gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { + svtav1enc->input_buf = g_malloc(sizeof(EbBufferHeaderType)); + if (!svtav1enc->input_buf) { + GST_ERROR_OBJECT(svtav1enc, "insufficient resources"); + return FALSE; + } + svtav1enc->input_buf->p_buffer = g_malloc(sizeof(EbSvtIOFormat)); + if (!svtav1enc->input_buf->p_buffer) { + GST_ERROR_OBJECT(svtav1enc, "insufficient resources"); + return FALSE; + } + memset(svtav1enc->input_buf->p_buffer, 0, sizeof(EbSvtIOFormat)); + 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; - return TRUE; + return TRUE; } -void -gst_svthevenc_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; - } +void gst_svthevenc_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; + } } -gboolean -gst_svtav1enc_configure_svt (GstSvtAv1Enc * svtav1enc) -{ - if (!svtav1enc->state) { - GST_WARNING_OBJECT (svtav1enc, "no state, can't configure encoder yet"); - return FALSE; - } - - /* set properties out of GstVideoInfo */ - 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", - svtav1enc->svt_config->source_width, - svtav1enc->svt_config->source_height, - svtav1enc->svt_config->frame_rate_numerator / svtav1enc->svt_config->frame_rate_denominator); - - /* TODO: better handle HDR metadata when GStreamer will have such support - * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/400 */ - if (GST_VIDEO_INFO_COLORIMETRY (info).matrix == GST_VIDEO_COLOR_MATRIX_BT2020 - && GST_VIDEO_INFO_COMP_DEPTH (info, 0) > 8) { - svtav1enc->svt_config->high_dynamic_range_input = TRUE; - } - - 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; -} - -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; -} - -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; -} - -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); -} - -gboolean -gst_svtav1enc_flush (GstVideoEncoder * encoder) -{ - GstFlowReturn ret = - gst_svtav1enc_dequeue_encoded_frames (GST_SVTAV1ENC (encoder), TRUE, - FALSE); - - return (ret != GST_FLOW_ERROR); -} - -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:%lld pts:%" - G_GINT64_FORMAT " SliceType:%d\n", svtav1enc->frame_count, - (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); - - svtav1enc->frame_count++; +gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { + if (!svtav1enc->state) { + GST_WARNING_OBJECT(svtav1enc, "no state, can't configure encoder yet"); + return FALSE; } - } while (res == EB_ErrorNone && !encode_at_eos && ret == GST_FLOW_OK); + /* set properties out of GstVideoInfo */ + 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", + svtav1enc->svt_config->source_width, + svtav1enc->svt_config->source_height, + svtav1enc->svt_config->frame_rate_numerator / + svtav1enc->svt_config->frame_rate_denominator); - return ret; + /* TODO: better handle HDR metadata when GStreamer will have such support + * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/400 */ + if (GST_VIDEO_INFO_COLORIMETRY(info).matrix == GST_VIDEO_COLOR_MATRIX_BT2020 && + GST_VIDEO_INFO_COMP_DEPTH(info, 0) > 8) { + svtav1enc->svt_config->high_dynamic_range_input = TRUE; + } + + 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_stop (GstVideoEncoder * encoder) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); +gboolean gst_svtav1enc_start_svt(GstSvtAv1Enc *svtav1enc) { + G_LOCK(init_mutex); + EbErrorType res = svt_av1_enc_init(svtav1enc->svt_encoder); + G_UNLOCK(init_mutex); - GST_DEBUG_OBJECT (svtav1enc, "stop"); - - GST_OBJECT_LOCK (svtav1enc); - if (svtav1enc->state) - gst_video_codec_state_unref (svtav1enc->state); - svtav1enc->state = NULL; - GST_OBJECT_UNLOCK (svtav1enc); - - GST_OBJECT_LOCK (svtav1enc); - svt_av1_enc_deinit(svtav1enc->svt_encoder); - /* Destruct the buffer memory pool */ - gst_svthevenc_deallocate_svt_buffers (svtav1enc); - GST_OBJECT_UNLOCK (svtav1enc); - - return TRUE; + 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 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"); +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 (svtav1enc->state) - gst_video_codec_state_unref (svtav1enc->state); - svtav1enc->state = gst_video_codec_state_ref (state); + 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; + } - gst_svtav1enc_configure_svt (svtav1enc); - gst_svtav1enc_allocate_svt_buffers (svtav1enc); - gst_svtav1enc_start_svt (svtav1enc); + 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); - uint32_t fps = svtav1enc->svt_config->frame_rate_numerator / - svtav1enc->svt_config->frame_rate_denominator; - fps = fps > 120 ? 120 : fps; - fps = fps < 24 ? 24 : fps; + 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); - min_latency_frames = ((fps * 5) >> 2); + input_buffer->n_filled_len = GST_VIDEO_FRAME_SIZE(&video_frame); - gst_video_encoder_set_latency(encoder, - min_latency_frames * GST_SECOND / - (svtav1enc->svt_config->frame_rate_numerator / - svtav1enc->svt_config->frame_rate_denominator), - -1); + /* 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; - 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_caps_unref (src_caps); - gst_video_codec_state_unref (output_state); + if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME(frame)) { + input_buffer->pic_type = EB_AV1_KEY_PICTURE; + } - GST_DEBUG_OBJECT (svtav1enc, "output caps: %" GST_PTR_FORMAT, - svtav1enc->state->caps); + input_buffer->metadata = NULL; - return gst_video_encoder_negotiate (encoder); -} + 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); -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); +gboolean gst_svtav1enc_send_eos(GstSvtAv1Enc *svtav1enc) { + EbErrorType ret = EB_ErrorNone; - GST_DEBUG_OBJECT (svtav1enc, "finish"); + 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; - gst_svtav1enc_send_eos (svtav1enc); + ret = svt_av1_enc_send_picture(svtav1enc->svt_encoder, &input_buffer); - return gst_svtav1enc_dequeue_encoded_frames (svtav1enc, TRUE, TRUE); + 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_propose_allocation (GstVideoEncoder * encoder, GstQuery * query) -{ - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC (encoder); +gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder) { + GstFlowReturn ret = gst_svtav1enc_dequeue_encoded_frames(GST_SVTAV1ENC(encoder), TRUE, FALSE); - 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); + return (ret != GST_FLOW_ERROR); } -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "svtav1enc", GST_RANK_SECONDARY, - GST_TYPE_SVTAV1ENC); +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:%lld pts:%" G_GINT64_FORMAT " SliceType:%d\n", + svtav1enc->frame_count, + (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); + + svtav1enc->frame_count++; + } + + } while (res == EB_ErrorNone && !encode_at_eos && ret == GST_FLOW_OK); + + return ret; +} + +static gboolean gst_svtav1enc_stop(GstVideoEncoder *encoder) { + GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder); + + GST_DEBUG_OBJECT(svtav1enc, "stop"); + + GST_OBJECT_LOCK(svtav1enc); + if (svtav1enc->state) + gst_video_codec_state_unref(svtav1enc->state); + svtav1enc->state = NULL; + GST_OBJECT_UNLOCK(svtav1enc); + + GST_OBJECT_LOCK(svtav1enc); + svt_av1_enc_deinit(svtav1enc->svt_encoder); + /* Destruct the buffer memory pool */ + gst_svthevenc_deallocate_svt_buffers(svtav1enc); + GST_OBJECT_UNLOCK(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); + svtav1enc->state = gst_video_codec_state_ref(state); + + gst_svtav1enc_configure_svt(svtav1enc); + gst_svtav1enc_allocate_svt_buffers(svtav1enc); + gst_svtav1enc_start_svt(svtav1enc); + + uint32_t 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_caps_unref(src_caps); + 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 gboolean plugin_init(GstPlugin *plugin) { + return gst_element_register(plugin, "svtav1enc", GST_RANK_SECONDARY, GST_TYPE_SVTAV1ENC); } #ifndef VERSION @@ -811,8 +783,6 @@ plugin_init (GstPlugin * plugin) #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) +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) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h index 8ad8a9bcf3..e528cde2f2 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h @@ -14,44 +14,37 @@ #include #include - 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_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)) + (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; +typedef struct _GstSvtAv1Enc { + GstVideoEncoder video_encoder; - /* SVT-AV1 Encoder Handle */ - EbComponentType *svt_encoder; + /* SVT-AV1 Encoder Handle */ + EbComponentType *svt_encoder; - /* GStreamer Codec state */ - GstVideoCodecState *state; + /* GStreamer Codec state */ + GstVideoCodecState *state; - /* SVT-AV1 configuration */ - EbSvtAv1EncConfiguration *svt_config; + /* SVT-AV1 configuration */ + EbSvtAv1EncConfiguration *svt_config; - EbBufferHeaderType *input_buf; + EbBufferHeaderType *input_buf; - long long int frame_count; - int dts_offset; + long long int frame_count; + int dts_offset; } GstSvtAv1Enc; -typedef struct _GstSvtAv1EncClass -{ - GstVideoEncoderClass video_encoder_class; +typedef struct _GstSvtAv1EncClass { + GstVideoEncoderClass video_encoder_class; } GstSvtAv1EncClass; -GType gst_svtav1enc_get_type (void); +GType gst_svtav1enc_get_type(void); G_END_DECLS #endif From aba0b0e90a4e4bbefed54a2afd8cf501060224e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 24 Jan 2023 20:43:35 +0200 Subject: [PATCH 66/81] gstreamer: Use stream-format=obu-stream alignment=tu in the caps There is no byte-stream/au format for AV1 but only for H264, and the encoder actually outputs obu-stream/tu instead of the annexb stream-format that is similar to H264 byte-stream format. Without this the encoder can't be used with elements that require a specific AV1 stream-format, e.g. the MP4 or Matroska/WebM muxer. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 6caa695d6d..838ff93817 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -108,8 +108,8 @@ static GstStaticPadTemplate gst_svtav1enc_sink_pad_template = GST_STATIC_PAD_TEM 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) byte-stream, " - "alignment = (string) au, " + "stream-format = (string) obu-stream, " + "alignment = (string) tu, " "width = (int) [64, 3840], " "height = (int) [64, 2160], " "framerate = (fraction) [0, MAX]")); From 2d250439f14bba0fffa36e45e1eb7aeb560e31bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 12:59:50 +0200 Subject: [PATCH 67/81] gstreamer: Fix debug category description --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 838ff93817..5b662a8a27 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -117,7 +117,7 @@ static GstStaticPadTemplate gst_svtav1enc_src_pad_template = GST_STATIC_PAD_TEMP /* class initialization */ G_DEFINE_TYPE_WITH_CODE(GstSvtAv1Enc, gst_svtav1enc, GST_TYPE_VIDEO_ENCODER, GST_DEBUG_CATEGORY_INIT(gst_svtav1enc_debug_category, "svtav1enc", 0, - "debug category for SVT-AV1 encoder element")); + "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); From 24d6027d2ee02deb65fb74092b7fc23ae89b05e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 13:03:49 +0200 Subject: [PATCH 68/81] gstreamer: Remove unused `frame_count` and `dts_offset` --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 7 ++----- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h | 3 --- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 5b662a8a27..5040496319 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -322,7 +322,6 @@ static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { return; } memset(&svtav1enc->svt_encoder, 0, sizeof(svtav1enc->svt_encoder)); - svtav1enc->frame_count = 0; EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); if (res != EB_ErrorNone) { @@ -652,8 +651,8 @@ GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1enc, frame->pts = frame->output_buffer->pts = output_buf->pts; GST_LOG_OBJECT(svtav1enc, - "#frame:%lld pts:%" G_GINT64_FORMAT " SliceType:%d\n", - svtav1enc->frame_count, + "#frame:%u pts:%" G_GINT64_FORMAT " SliceType:%d\n", + frame->system_frame_number, (frame->pts), output_buf->pic_type); @@ -661,8 +660,6 @@ GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1enc, output_buf = NULL; ret = gst_video_encoder_finish_frame(GST_VIDEO_ENCODER(svtav1enc), frame); - - svtav1enc->frame_count++; } } while (res == EB_ErrorNone && !encode_at_eos && ret == GST_FLOW_OK); diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h index e528cde2f2..1e820a4c2e 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h @@ -35,9 +35,6 @@ typedef struct _GstSvtAv1Enc { EbSvtAv1EncConfiguration *svt_config; EbBufferHeaderType *input_buf; - - long long int frame_count; - int dts_offset; } GstSvtAv1Enc; typedef struct _GstSvtAv1EncClass { From 10769e7fe6deb985dc60175761255fbee700528a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 13:06:16 +0200 Subject: [PATCH 69/81] gstreamer: Fix encoder and buffer state life cycle Allocate/deallocate the encoder in `open()`/`close()` and its buffers in `start()` / `stop()`. Also fail correctly if configuring the encoder fails. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 122 ++++++++---------- 1 file changed, 56 insertions(+), 66 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 5040496319..56cea8bc66 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -32,11 +32,10 @@ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GParamSpec *pspec); static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec); -static void gst_svtav1enc_dispose(GObject *object); static void gst_svtav1enc_finalize(GObject *object); -gboolean gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc); -void gst_svthevenc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc); +static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc); +static void gst_svthevenc_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); @@ -44,6 +43,9 @@ static GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1en 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, @@ -141,8 +143,10 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { gobject_class->set_property = gst_svtav1enc_set_property; gobject_class->get_property = gst_svtav1enc_get_property; - gobject_class->dispose = gst_svtav1enc_dispose; 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); @@ -314,27 +318,7 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { } static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { - GST_OBJECT_LOCK(svtav1enc); - svtav1enc->svt_config = g_malloc(sizeof(EbSvtAv1EncConfiguration)); - if (!svtav1enc->svt_config) { - GST_ERROR_OBJECT(svtav1enc, "insufficient resources"); - GST_OBJECT_UNLOCK(svtav1enc); - return; - } - memset(&svtav1enc->svt_encoder, 0, sizeof(svtav1enc->svt_encoder)); - - 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)); - GST_OBJECT_UNLOCK(svtav1enc); - return; - } - /* setting configuration here since svt_av1_enc_init_handle overrides it */ - GST_OBJECT_UNLOCK(svtav1enc); + svtav1enc->svt_config = g_new0(EbSvtAv1EncConfiguration, 1); } void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value, @@ -422,51 +406,23 @@ void gst_svtav1enc_get_property(GObject *object, guint property_id, GValue *valu } } -void gst_svtav1enc_dispose(GObject *object) { - GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object); - - GST_DEBUG_OBJECT(svtav1enc, "dispose"); - - /* clean up as possible. may be called multiple times */ - if (svtav1enc->state) - gst_video_codec_state_unref(svtav1enc->state); - svtav1enc->state = NULL; - - G_OBJECT_CLASS(gst_svtav1enc_parent_class)->dispose(object); -} - void gst_svtav1enc_finalize(GObject *object) { GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object); GST_DEBUG_OBJECT(svtav1enc, "finalizing svtav1enc"); - GST_OBJECT_LOCK(svtav1enc); - svt_av1_enc_deinit_handle(svtav1enc->svt_encoder); - svtav1enc->svt_encoder = NULL; g_free(svtav1enc->svt_config); - GST_OBJECT_UNLOCK(svtav1enc); G_OBJECT_CLASS(gst_svtav1enc_parent_class)->finalize(object); } -gboolean gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { - svtav1enc->input_buf = g_malloc(sizeof(EbBufferHeaderType)); - if (!svtav1enc->input_buf) { - GST_ERROR_OBJECT(svtav1enc, "insufficient resources"); - return FALSE; - } - svtav1enc->input_buf->p_buffer = g_malloc(sizeof(EbSvtIOFormat)); - if (!svtav1enc->input_buf->p_buffer) { - GST_ERROR_OBJECT(svtav1enc, "insufficient resources"); - return FALSE; - } - memset(svtav1enc->input_buf->p_buffer, 0, sizeof(EbSvtIOFormat)); +void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { + svtav1enc->input_buf = g_new0(EbBufferHeaderType, 1); + svtav1enc->input_buf->p_buffer = (uint8_t *)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; - - return TRUE; } void gst_svthevenc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { @@ -485,7 +441,7 @@ gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { } /* set properties out of GstVideoInfo */ - GstVideoInfo *info = &svtav1enc->state->info; + 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); @@ -667,22 +623,53 @@ GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1enc, 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"); - GST_OBJECT_LOCK(svtav1enc); if (svtav1enc->state) gst_video_codec_state_unref(svtav1enc->state); svtav1enc->state = NULL; - GST_OBJECT_UNLOCK(svtav1enc); - GST_OBJECT_LOCK(svtav1enc); svt_av1_enc_deinit(svtav1enc->svt_encoder); - /* Destruct the buffer memory pool */ gst_svthevenc_deallocate_svt_buffers(svtav1enc); - GST_OBJECT_UNLOCK(svtav1enc); return TRUE; } @@ -694,13 +681,16 @@ static gboolean gst_svtav1enc_set_format(GstVideoEncoder *encoder, GstVideoCodec GstVideoCodecState *output_state; GST_DEBUG_OBJECT(svtav1enc, "set_format"); - if (svtav1enc->state) + 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); - gst_svtav1enc_configure_svt(svtav1enc); - gst_svtav1enc_allocate_svt_buffers(svtav1enc); - gst_svtav1enc_start_svt(svtav1enc); + if (!gst_svtav1enc_configure_svt(svtav1enc)) + return FALSE; + if (!gst_svtav1enc_start_svt(svtav1enc)) + return FALSE; uint32_t fps = svtav1enc->svt_config->frame_rate_numerator / svtav1enc->svt_config->frame_rate_denominator; From 78ee7e82d9bb060c196f108c54281f6b77ae02c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 13:37:15 +0200 Subject: [PATCH 70/81] gstreamer: Mark all internal functions as `static` --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 56cea8bc66..d0d76e0a4c 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -54,9 +54,6 @@ static GstFlowReturn gst_svtav1enc_finish(GstVideoEncoder *encoder); static gboolean gst_svtav1enc_propose_allocation(GstVideoEncoder *encoder, GstQuery *query); static gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder); -/* helpers */ -gint compare_video_code_frame_and_pts(const void *video_codec_frame_ptr, const void *pts_ptr); - enum { PROP_0, PROP_ENCMODE, @@ -321,8 +318,8 @@ static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { svtav1enc->svt_config = g_new0(EbSvtAv1EncConfiguration, 1); } -void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value, - GParamSpec *pspec) { +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 */ @@ -369,8 +366,8 @@ void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue } } -void gst_svtav1enc_get_property(GObject *object, guint property_id, GValue *value, - GParamSpec *pspec) { +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); @@ -406,7 +403,7 @@ void gst_svtav1enc_get_property(GObject *object, guint property_id, GValue *valu } } -void gst_svtav1enc_finalize(GObject *object) { +static void gst_svtav1enc_finalize(GObject *object) { GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(object); GST_DEBUG_OBJECT(svtav1enc, "finalizing svtav1enc"); @@ -416,7 +413,7 @@ void gst_svtav1enc_finalize(GObject *object) { G_OBJECT_CLASS(gst_svtav1enc_parent_class)->finalize(object); } -void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { +static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { svtav1enc->input_buf = g_new0(EbBufferHeaderType, 1); svtav1enc->input_buf->p_buffer = (uint8_t *)g_new0(EbSvtIOFormat, 1); svtav1enc->input_buf->size = sizeof(EbBufferHeaderType); @@ -425,7 +422,7 @@ void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { svtav1enc->input_buf->metadata = NULL; } -void gst_svthevenc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { +static void gst_svthevenc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { if (svtav1enc->input_buf) { g_free(svtav1enc->input_buf->p_buffer); svtav1enc->input_buf->p_buffer = NULL; @@ -434,7 +431,7 @@ void gst_svthevenc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { } } -gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { +static gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { if (!svtav1enc->state) { GST_WARNING_OBJECT(svtav1enc, "no state, can't configure encoder yet"); return FALSE; @@ -477,7 +474,7 @@ gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { return TRUE; } -gboolean gst_svtav1enc_start_svt(GstSvtAv1Enc *svtav1enc) { +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); @@ -490,7 +487,7 @@ gboolean gst_svtav1enc_start_svt(GstSvtAv1Enc *svtav1enc) { return TRUE; } -GstFlowReturn gst_svtav1enc_encode(GstSvtAv1Enc *svtav1enc, GstVideoCodecFrame *frame) { +static GstFlowReturn gst_svtav1enc_encode(GstSvtAv1Enc *svtav1enc, GstVideoCodecFrame *frame) { GstFlowReturn ret = GST_FLOW_OK; EbErrorType res = EB_ErrorNone; EbBufferHeaderType *input_buffer = svtav1enc->input_buf; @@ -539,7 +536,7 @@ GstFlowReturn gst_svtav1enc_encode(GstSvtAv1Enc *svtav1enc, GstVideoCodecFrame * return ret; } -gboolean gst_svtav1enc_send_eos(GstSvtAv1Enc *svtav1enc) { +static gboolean gst_svtav1enc_send_eos(GstSvtAv1Enc *svtav1enc) { EbErrorType ret = EB_ErrorNone; EbBufferHeaderType input_buffer; @@ -561,15 +558,15 @@ gboolean gst_svtav1enc_send_eos(GstSvtAv1Enc *svtav1enc) { return (ret == EB_ErrorNone); } -gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder) { +static gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder) { GstFlowReturn ret = gst_svtav1enc_dequeue_encoded_frames(GST_SVTAV1ENC(encoder), TRUE, FALSE); return (ret != GST_FLOW_ERROR); } -GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1enc, - gboolean done_sending_pics, - gboolean output_frames) { +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; From 7b1b33aff248a3bd0ebcc6512cbb74e3c460bc91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 15:25:06 +0200 Subject: [PATCH 71/81] gstreamer: Clean up property handling Use more correct types, defaults and clean up property names a bit. This now matches the configuration provided by ffmpeg. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 421 +++++++++--------- 1 file changed, 216 insertions(+), 205 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index d0d76e0a4c..c7395fe0ce 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -27,6 +27,40 @@ 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; +} + +#define GST_SVTAV1ENC_TYPE_RATE_CONTROL_MODE (gst_svtav1enc_rate_control_mode_get_type()) +static GType gst_svtav1enc_rate_control_mode_get_type(void) { + static GType rate_control_mode_type = 0; + static const GEnumValue rate_control_mode[] = { + {SVT_AV1_RC_MODE_CQP_OR_CRF, + "Constant quantization parameter/constant rate factor", + "cqp-or-crf"}, + {SVT_AV1_RC_MODE_VBR, "Variable bitrate", "vbr"}, + {SVT_AV1_RC_MODE_CBR, "Constant bitrate", "cbr"}, + {0, NULL, NULL}, + }; + + if (!rate_control_mode_type) { + rate_control_mode_type = g_enum_register_static("GstSvtAv1EncRateControlMode", + rate_control_mode); + } + return rate_control_mode_type; +} + /* prototypes */ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); @@ -56,44 +90,34 @@ static gboolean gst_svtav1enc_flush(GstVideoEncoder *encoder); enum { PROP_0, - PROP_ENCMODE, - PROP_B_PYRAMID, - PROP_P_FRAMES, - PROP_PRED_STRUCTURE, - PROP_GOP_SIZE, - PROP_INTRA_REFRESH, + PROP_PRESET, + PROP_RATE_CONTROL_MODE, + PROP_TARGET_BITRATE, + PROP_MAX_BITRATE, + PROP_MAX_QP_ALLOWED, + PROP_MIN_QP_ALLOWED, PROP_QP, - PROP_QP_MAX, - PROP_QP_MIN, - PROP_DEBLOCKING, - PROP_RC_MODE, - PROP_BITRATE, - PROP_LOOKAHEAD, - PROP_SCD, - PROP_CORES, - PROP_SOCKET + PROP_MAXIMUM_BUFFER_SIZE, + PROP_ADAPTIVE_QUANTIZATION, + PROP_INTRA_PERIOD_LENGTH, + PROP_INTRA_REFRESH_TYPE, + PROP_LOGICAL_PROCESSORS, + PROP_TARGET_SOCKET }; -#define PROP_RC_MODE_CQP 0 -#define PROP_RC_MODE_VBR 1 - -#define PROP_ENCMODE_DEFAULT 8 -#define PROP_HIERARCHICAL_LEVEL_DEFAULT 4 -#define PROP_P_FRAMES_DEFAULT 0 -#define PROP_PRED_STRUCTURE_DEFAULT 2 -#define PROP_GOP_SIZE_DEFAULT -1 -#define PROP_INTRA_REFRESH_DEFAULT 1 +#define PROP_PRESET_DEFAULT 8 +#define PROP_RATE_CONTROL_MODE_DEFAULT SVT_AV1_RC_MODE_CQP_OR_CRF +#define PROP_TARGET_BITRATE_DEFAULT 2000 +#define PROP_MAX_BITRATE_DEFAULT 0 +#define PROP_QP_MAX_QP_ALLOWED_DEFAULT 63 +#define PROP_QP_MIN_QP_ALLOWED_DEFAULT 0 #define PROP_QP_DEFAULT 50 -#define PROP_DEBLOCKING_DEFAULT TRUE -#define PROP_RC_MODE_DEFAULT PROP_RC_MODE_CQP -#define PROP_BITRATE_DEFAULT 7000000 -#define PROP_QP_MAX_DEFAULT 63 -#define PROP_QP_MIN_DEFAULT 0 -#define PROP_LOOKAHEAD_DEFAULT (unsigned int)-1 -#define PROP_SCD_DEFAULT FALSE -#define PROP_AUD_DEFAULT FALSE -#define PROP_CORES_DEFAULT 0 -#define PROP_SOCKET_DEFAULT -1 +#define PROP_MAXIMUM_BUFFER_SIZE_DEFAULT 1000 +#define PROP_ADAPTIVE_QUANTIZATION_DEFAULT 2 +#define PROP_INTRA_PERIOD_LENGTH_DEFAULT -2 +#define PROP_INTRA_REFRESH_TYPE_DEFAULT 1 +#define PROP_LOGICAL_PROCESSORS_DEFAULT 0 +#define PROP_TARGET_SOCKET_DEFAULT -1 /* pad templates */ static GstStaticPadTemplate gst_svtav1enc_sink_pad_template = GST_STATIC_PAD_TEMPLATE( @@ -153,61 +177,72 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { g_object_class_install_property( gobject_class, - PROP_ENCMODE, - g_param_spec_uint("speed", - "speed (Encoder Mode)", + 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, 12 is the highest speed) ", + " (0 is the highest quality, 13 is the highest speed) ", 0, - 12, - PROP_ENCMODE_DEFAULT, + 13, + PROP_PRESET_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(gobject_class, - PROP_B_PYRAMID, - g_param_spec_uint("hierarchical-level", - "Hierarchical levels", - "3 : 4 - Level Hierarchy," - "4 : 5 - Level Hierarchy", - 3, - 4, - PROP_HIERARCHICAL_LEVEL_DEFAULT, + PROP_RATE_CONTROL_MODE, + g_param_spec_enum("rate-control-mode", + "Rate-control mode", + "Rate Control Mode", + GST_SVTAV1ENC_TYPE_RATE_CONTROL_MODE, + PROP_RATE_CONTROL_MODE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - //g_object_class_install_property (gobject_class, PROP_P_FRAMES, - // g_param_spec_boolean ("p-frames", "P Frames", - // "Use P-frames in the base layer", - // PROP_P_FRAMES_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - //g_object_class_install_property (gobject_class, PROP_PRED_STRUCTURE, - // g_param_spec_uint ("pred-struct", "Prediction Structure", - // "0 : Low Delay P, 1 : Low Delay B" - // ", 2 : Random Access", - // 0, 2, PROP_PRED_STRUCTURE_DEFAULT, - // G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property( gobject_class, - PROP_GOP_SIZE, - g_param_spec_int("gop-size", - "GOP size", - "Period of Intra Frames insertion (-1 is auto)", - -1, - 251, - PROP_GOP_SIZE_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + PROP_TARGET_BITRATE, + g_param_spec_uint("target-bitrate", + "Target bitrate", + "Target bitrate in kbits/sec. Only used when in CBR and 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. Only used when in CBQ mode", + 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 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 VBR mode.", + 0, + 63, + PROP_MIN_QP_ALLOWED, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property(gobject_class, - PROP_INTRA_REFRESH, - g_param_spec_int("intra-refresh", - "Intra refresh type", - "CRA (open GOP)" - "or IDR frames (closed GOP)", - 1, - 2, - PROP_INTRA_REFRESH_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(gobject_class, PROP_QP, g_param_spec_uint("qp", @@ -218,100 +253,70 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { PROP_QP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property( - gobject_class, - PROP_DEBLOCKING, - g_param_spec_boolean("deblocking", - "Deblock Filter", - "Enable Deblocking Loop Filtering", - PROP_DEBLOCKING_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property(gobject_class, - PROP_RC_MODE, - g_param_spec_uint("rc", - "Rate-control mode", - "0 : CQP, 1 : VBR", - 0, - 1, - PROP_RC_MODE_DEFAULT, + 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)); - /* TODO: add GST_PARAM_MUTABLE_PLAYING property and handle it? */ g_object_class_install_property( gobject_class, - PROP_BITRATE, - g_param_spec_uint("bitrate", - "Target bitrate", - "Target bitrate in bits/sec. Only used when in VBR mode", - 1, - G_MAXUINT, - PROP_BITRATE_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property( - gobject_class, - PROP_QP_MAX, - g_param_spec_uint("max-qp", - "Max Quantization parameter", - "Maximum QP value allowed for rate control use" - " Only used in VBR mode.", + PROP_ADAPTIVE_QUANTIZATION, + g_param_spec_uint("adaptive-quantization", + "Adaptive Quantization", + "Adaptive quantization within a frame using segmentation.", 0, - 63, - PROP_QP_MAX_DEFAULT, + 2, + PROP_ADAPTIVE_QUANTIZATION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property( gobject_class, - PROP_QP_MIN, - g_param_spec_uint("min-qp", - "Min Quantization parameter", - "Minimum QP value allowed for rate control use" - " Only used in VBR mode.", - 0, - 63, - PROP_QP_MIN_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property( - gobject_class, - PROP_LOOKAHEAD, - g_param_spec_int("lookahead", - "Look Ahead Distance", - "Number of frames to look ahead. -1 lets the encoder pick a value", - -1, - 250, - PROP_LOOKAHEAD_DEFAULT, + 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_SCD, - g_param_spec_boolean("scd", - "Scene Change Detection", - "Enable Scene Change Detection algorithm", - PROP_SCD_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property(gobject_class, - PROP_CORES, - g_param_spec_uint("cores", - "Number of logical cores", - "Number of logical cores to be used. 0: auto", - 0, - UINT_MAX, - PROP_CORES_DEFAULT, + 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_SOCKET, - g_param_spec_int("socket", - "Target socket", - "Target socket to run on. -1: all available", - -1, - 15, - PROP_SOCKET_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)); } static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { @@ -332,36 +337,39 @@ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GST_LOG_OBJECT(svtav1enc, "setting property %u", property_id); switch (property_id) { - case PROP_ENCMODE: svtav1enc->svt_config->enc_mode = g_value_get_uint(value); break; - case PROP_GOP_SIZE: - svtav1enc->svt_config->intra_period_length = g_value_get_int(value) - 1; + case PROP_PRESET: svtav1enc->svt_config->enc_mode = g_value_get_uint(value); break; + case PROP_RATE_CONTROL_MODE: + svtav1enc->svt_config->rate_control_mode = g_value_get_enum(value); break; - case PROP_INTRA_REFRESH: - svtav1enc->svt_config->intra_refresh_type = g_value_get_int(value); - break; - case PROP_B_PYRAMID: - svtav1enc->svt_config->hierarchical_levels = g_value_get_uint(value); - break; - case PROP_PRED_STRUCTURE: - svtav1enc->svt_config->pred_structure = g_value_get_uint(value); - break; - - case PROP_QP: svtav1enc->svt_config->qp = g_value_get_uint(value); break; - case PROP_DEBLOCKING: - svtav1enc->svt_config->enable_dlf_flag = g_value_get_boolean(value); - break; - case PROP_RC_MODE: svtav1enc->svt_config->rate_control_mode = g_value_get_uint(value); break; - case PROP_BITRATE: + case PROP_TARGET_BITRATE: svtav1enc->svt_config->target_bit_rate = g_value_get_uint(value) * 1000; break; - case PROP_QP_MAX: svtav1enc->svt_config->max_qp_allowed = g_value_get_uint(value); break; - case PROP_QP_MIN: svtav1enc->svt_config->min_qp_allowed = g_value_get_uint(value); break; - case PROP_SCD: - svtav1enc->svt_config->scene_change_detection = g_value_get_boolean(value); + case PROP_MAX_BITRATE: + svtav1enc->svt_config->max_bit_rate = g_value_get_uint(value) * 1000; break; - case PROP_CORES: svtav1enc->svt_config->logical_processors = g_value_get_uint(value); break; - case PROP_SOCKET: svtav1enc->svt_config->target_socket = g_value_get_int(value); break; - case PROP_LOOKAHEAD: svtav1enc->svt_config->look_ahead_distance = g_value_get_int(value); break; + case PROP_MAX_QP_ALLOWED: + svtav1enc->svt_config->max_qp_allowed = g_value_get_uint(value); + break; + case PROP_MIN_QP_ALLOWED: + svtav1enc->svt_config->min_qp_allowed = g_value_get_uint(value); + break; + case PROP_QP: svtav1enc->svt_config->qp = g_value_get_uint(value); break; + case PROP_MAXIMUM_BUFFER_SIZE: + svtav1enc->svt_config->maximum_buffer_size_ms = g_value_get_uint(value); + break; + case PROP_ADAPTIVE_QUANTIZATION: + svtav1enc->svt_config->enable_adaptive_quantization = g_value_get_uint(value); + break; + case PROP_INTRA_PERIOD_LENGTH: + svtav1enc->svt_config->intra_period_length = g_value_get_int(value) - 1; + break; + case PROP_INTRA_REFRESH_TYPE: + svtav1enc->svt_config->intra_refresh_type = g_value_get_enum(value); + break; + case PROP_LOGICAL_PROCESSORS: + svtav1enc->svt_config->logical_processors = g_value_get_uint(value); + break; + case PROP_TARGET_SOCKET: svtav1enc->svt_config->target_socket = g_value_get_int(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; } } @@ -373,32 +381,35 @@ static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValu GST_LOG_OBJECT(svtav1enc, "getting property %u", property_id); switch (property_id) { - case PROP_ENCMODE: g_value_set_uint(value, svtav1enc->svt_config->enc_mode); break; - case PROP_B_PYRAMID: g_value_set_uint(value, svtav1enc->svt_config->hierarchical_levels); break; - - case PROP_PRED_STRUCTURE: g_value_set_uint(value, svtav1enc->svt_config->pred_structure); break; - case PROP_GOP_SIZE: - g_value_set_int(value, svtav1enc->svt_config->intra_period_length + 1); + case PROP_PRESET: g_value_set_uint(value, svtav1enc->svt_config->enc_mode); break; + case PROP_RATE_CONTROL_MODE: + g_value_set_enum(value, svtav1enc->svt_config->rate_control_mode); break; - case PROP_INTRA_REFRESH: - g_value_set_int(value, svtav1enc->svt_config->intra_refresh_type); - break; - case PROP_QP: g_value_set_uint(value, svtav1enc->svt_config->qp); break; - case PROP_DEBLOCKING: - g_value_set_boolean(value, svtav1enc->svt_config->enable_dlf_flag == 1); - break; - case PROP_RC_MODE: g_value_set_uint(value, svtav1enc->svt_config->rate_control_mode); break; - case PROP_BITRATE: + case PROP_TARGET_BITRATE: g_value_set_uint(value, svtav1enc->svt_config->target_bit_rate / 1000); break; - case PROP_QP_MAX: g_value_set_uint(value, svtav1enc->svt_config->max_qp_allowed); break; - case PROP_QP_MIN: g_value_set_uint(value, svtav1enc->svt_config->min_qp_allowed); break; - case PROP_SCD: - g_value_set_boolean(value, svtav1enc->svt_config->scene_change_detection == 1); + case PROP_MAX_BITRATE: + g_value_set_uint(value, svtav1enc->svt_config->max_bit_rate / 1000); break; - case PROP_CORES: g_value_set_uint(value, svtav1enc->svt_config->logical_processors); break; - case PROP_SOCKET: g_value_set_int(value, svtav1enc->svt_config->target_socket); break; - case PROP_LOOKAHEAD: g_value_set_int(value, svtav1enc->svt_config->look_ahead_distance); break; + case PROP_MAX_QP_ALLOWED: g_value_set_uint(value, svtav1enc->svt_config->max_qp_allowed); break; + case PROP_MIN_QP_ALLOWED: g_value_set_uint(value, svtav1enc->svt_config->min_qp_allowed); break; + case PROP_QP: g_value_set_uint(value, svtav1enc->svt_config->qp); break; + case PROP_MAXIMUM_BUFFER_SIZE: + g_value_set_uint(value, svtav1enc->svt_config->maximum_buffer_size_ms); + break; + case PROP_ADAPTIVE_QUANTIZATION: + g_value_set_uint(value, svtav1enc->svt_config->enable_adaptive_quantization); + break; + case PROP_INTRA_PERIOD_LENGTH: + g_value_set_int(value, svtav1enc->svt_config->intra_period_length + 1); + break; + case PROP_INTRA_REFRESH_TYPE: + g_value_set_enum(value, svtav1enc->svt_config->intra_refresh_type); + break; + case PROP_LOGICAL_PROCESSORS: + g_value_set_uint(value, svtav1enc->svt_config->logical_processors); + break; + case PROP_TARGET_SOCKET: g_value_set_int(value, svtav1enc->svt_config->target_socket); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; } } From ddb9a037e1b8355e9b8db669b19c28d01d6c240d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 15:30:24 +0200 Subject: [PATCH 72/81] gstreamer: Don't overwrite application configuration on initialization and initialize with the default configuration --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index c7395fe0ce..ca7e073457 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -61,6 +61,9 @@ static GType gst_svtav1enc_rate_control_mode_get_type(void) { return rate_control_mode_type; } +/* default configuration */ +static EbSvtAv1EncConfiguration default_configuration; + /* prototypes */ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); @@ -321,6 +324,7 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { svtav1enc->svt_config = g_new0(EbSvtAv1EncConfiguration, 1); + memcpy(svtav1enc->svt_config, &default_configuration, sizeof(default_configuration)); } static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value, @@ -633,10 +637,12 @@ static GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1en static gboolean gst_svtav1enc_open(GstVideoEncoder *encoder) { GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder); + /* don't overwrite the application's configuration */ + EbSvtAv1EncConfiguration svt_config; GST_DEBUG_OBJECT(svtav1enc, "open"); - EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); + EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, &svt_config); if (res != EB_ErrorNone) { GST_ELEMENT_ERROR(svtav1enc, LIBRARY, @@ -762,6 +768,16 @@ static gboolean gst_svtav1enc_propose_allocation(GstVideoEncoder *encoder, GstQu } static gboolean plugin_init(GstPlugin *plugin) { + EbComponentType *handle = NULL; + EbErrorType res; + + res = svt_av1_enc_init_handle(&handle, NULL, &default_configuration); + if (res != EB_ErrorNone) { + GST_ERROR("Failed to initialize SVT AV1 handle"); + return FALSE; + } + svt_av1_enc_deinit(handle); + return gst_element_register(plugin, "svtav1enc", GST_RANK_SECONDARY, GST_TYPE_SVTAV1ENC); } From d746164ba061064db316e243d8dfe42cc0a7c1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 31 Jan 2023 19:04:24 +0200 Subject: [PATCH 73/81] gstreamer: Fix naming of function name that was taken over from the SVT-HEVC encoder --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index ca7e073457..978a949f38 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -72,7 +72,7 @@ static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValu static void gst_svtav1enc_finalize(GObject *object); static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc); -static void gst_svthevenc_deallocate_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); @@ -437,7 +437,7 @@ static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { svtav1enc->input_buf->metadata = NULL; } -static void gst_svthevenc_deallocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { +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; @@ -683,7 +683,7 @@ static gboolean gst_svtav1enc_stop(GstVideoEncoder *encoder) { svtav1enc->state = NULL; svt_av1_enc_deinit(svtav1enc->svt_encoder); - gst_svthevenc_deallocate_svt_buffers(svtav1enc); + gst_svtav1enc_deallocate_svt_buffers(svtav1enc); return TRUE; } From f24643b48f862d483c85a2eb2a1fde895c490925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 1 Feb 2023 12:49:44 +0200 Subject: [PATCH 74/81] gstreamer: Add support for setting arbitrary parameters via `parameters-string` property --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 58 ++++++++++++++++++- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.h | 1 + 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 978a949f38..6c73a0986a 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -91,6 +91,8 @@ 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, const gchar *parameters); + enum { PROP_0, PROP_PRESET, @@ -105,7 +107,8 @@ enum { PROP_INTRA_PERIOD_LENGTH, PROP_INTRA_REFRESH_TYPE, PROP_LOGICAL_PROCESSORS, - PROP_TARGET_SOCKET + PROP_TARGET_SOCKET, + PROP_PARAMETERS_STRING, }; #define PROP_PRESET_DEFAULT 8 @@ -121,6 +124,7 @@ enum { #define PROP_INTRA_REFRESH_TYPE_DEFAULT 1 #define PROP_LOGICAL_PROCESSORS_DEFAULT 0 #define PROP_TARGET_SOCKET_DEFAULT -1 +#define PROP_PARAMETERS_STRING_DEFAULT NULL /* pad templates */ static GstStaticPadTemplate gst_svtav1enc_sink_pad_template = GST_STATIC_PAD_TEMPLATE( @@ -320,6 +324,16 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { 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) { @@ -374,6 +388,9 @@ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const svtav1enc->svt_config->logical_processors = g_value_get_uint(value); break; case PROP_TARGET_SOCKET: svtav1enc->svt_config->target_socket = g_value_get_int(value); break; + case PROP_PARAMETERS_STRING: + gst_svtav1enc_parse_parameters_string(svtav1enc, g_value_get_string(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; } } @@ -414,6 +431,7 @@ static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValu g_value_set_uint(value, svtav1enc->svt_config->logical_processors); break; case PROP_TARGET_SOCKET: g_value_set_int(value, svtav1enc->svt_config->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; } } @@ -424,6 +442,7 @@ static void gst_svtav1enc_finalize(GObject *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); } @@ -767,6 +786,43 @@ static gboolean gst_svtav1enc_propose_allocation(GstVideoEncoder *encoder, GstQu return GST_VIDEO_ENCODER_CLASS(gst_svtav1enc_parent_class)->propose_allocation(encoder, query); } +static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc, + const gchar *parameters) { + gchar **key_values, **p; + + g_free(svtav1enc->parameters_string); + svtav1enc->parameters_string = g_strdup(parameters); + + if (!parameters) + return; + + p = key_values = g_strsplit(parameters, ":", -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) { EbComponentType *handle = NULL; EbErrorType res; diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h index 1e820a4c2e..488c286b38 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h @@ -33,6 +33,7 @@ typedef struct _GstSvtAv1Enc { /* SVT-AV1 configuration */ EbSvtAv1EncConfiguration *svt_config; + gchar *parameters_string; EbBufferHeaderType *input_buf; } GstSvtAv1Enc; From 90fd191392b6c466e386f38b6bfbbf62908ace90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 1 Feb 2023 12:57:01 +0200 Subject: [PATCH 75/81] gstreamer: Set `force_key_frames=true` in CQP/CRF mode Other modes don't support that so keyframes can't be requested at arbitrary times. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 6c73a0986a..191b053ac7 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -358,6 +358,9 @@ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const case PROP_PRESET: svtav1enc->svt_config->enc_mode = g_value_get_uint(value); break; case PROP_RATE_CONTROL_MODE: svtav1enc->svt_config->rate_control_mode = g_value_get_enum(value); + // Forcing keyframes is only support in CQP/CRF mode + svtav1enc->svt_config->force_key_frames = (svtav1enc->svt_config->rate_control_mode == + SVT_AV1_RC_MODE_CQP_OR_CRF); break; case PROP_TARGET_BITRATE: svtav1enc->svt_config->target_bit_rate = g_value_get_uint(value) * 1000; From 65eb56e7ad20f362b3b0aa00c8a0d17cb6e4d566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 1 Feb 2023 13:02:11 +0200 Subject: [PATCH 76/81] gstreamer: Use correct 10-bit format on big endian systems --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 191b053ac7..acf09335cb 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -126,11 +126,17 @@ enum { #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, I420_10LE}, " + "format = (string) {I420, " FORMAT_I420_10 "}, " "width = (int) [64, 3840], " "height = (int) [64, 2160], " "framerate = (fraction) [0, MAX]")); From aeee6f5b6a22bd51cfb70e835a62a47140315bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 1 Feb 2023 13:03:14 +0200 Subject: [PATCH 77/81] gstreamer: Set correct maximum width/height limits --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index acf09335cb..0f76eef657 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -137,8 +137,8 @@ static GstStaticPadTemplate gst_svtav1enc_sink_pad_template = GST_STATIC_PAD_TEM "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("video/x-raw, " "format = (string) {I420, " FORMAT_I420_10 "}, " - "width = (int) [64, 3840], " - "height = (int) [64, 2160], " + "width = (int) [64, 16384], " + "height = (int) [64, 8704], " "framerate = (fraction) [0, MAX]")); static GstStaticPadTemplate gst_svtav1enc_src_pad_template = GST_STATIC_PAD_TEMPLATE( @@ -146,8 +146,8 @@ static GstStaticPadTemplate gst_svtav1enc_src_pad_template = GST_STATIC_PAD_TEMP GST_STATIC_CAPS("video/x-av1, " "stream-format = (string) obu-stream, " "alignment = (string) tu, " - "width = (int) [64, 3840], " - "height = (int) [64, 2160], " + "width = (int) [64, 16384], " + "height = (int) [64, 8704], " "framerate = (fraction) [0, MAX]")); /* class initialization */ From df064c6cc271682d682805781910a510fc83c1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 1 Feb 2023 14:06:53 +0200 Subject: [PATCH 78/81] gstreamer: Configure colorimetry and HDR metadata if present This raises the minimum GStreamer requirement to 1.16 as used by the CI and optionally makes use of 1.18 features, including HDR. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 158 +++++++++++++++++- .../gst-plugins-bad/ext/svtav1/meson.build | 4 +- 2 files changed, 155 insertions(+), 7 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 0f76eef657..15fdc4588e 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -498,13 +498,161 @@ static gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { svtav1enc->svt_config->frame_rate_numerator / svtav1enc->svt_config->frame_rate_denominator); - /* TODO: better handle HDR metadata when GStreamer will have such support - * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/400 */ - if (GST_VIDEO_INFO_COLORIMETRY(info).matrix == GST_VIDEO_COLOR_MATRIX_BT2020 && - GST_VIDEO_INFO_COMP_DEPTH(info, 0) > 8) { - svtav1enc->svt_config->high_dynamic_range_input = TRUE; + 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, diff --git a/subprojects/gst-plugins-bad/ext/svtav1/meson.build b/subprojects/gst-plugins-bad/ext/svtav1/meson.build index 408ed78255..4955be33d4 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/meson.build +++ b/subprojects/gst-plugins-bad/ext/svtav1/meson.build @@ -4,8 +4,8 @@ project('gst-svt-av1', 'c', meson_version : '>= 0.29', default_options : [ 'buildtype=debugoptimized' ]) -# standard gst-plugins-bad dependencies and configuration -gst_req = '>= 1.13.1' +# 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, From dd1db338dfc3f912fe3b0a911fa46c9a55a936cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 1 Feb 2023 17:26:01 +0200 Subject: [PATCH 79/81] gstreamer: Fix double unref The ownership of the caps is passed to `gst_video_encoder_set_output_state()`. --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 15fdc4588e..95532483e0 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -898,7 +898,6 @@ static gboolean gst_svtav1enc_set_format(GstVideoEncoder *encoder, GstVideoCodec 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_caps_unref(src_caps); gst_video_codec_state_unref(output_state); GST_DEBUG_OBJECT(svtav1enc, "output caps: %" GST_PTR_FORMAT, svtav1enc->state->caps); From 70c83bc59c08167713872f0cb797ec94d2e777de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 2 Feb 2023 09:50:16 +0200 Subject: [PATCH 80/81] gstreamer: Use GLib types instead of stdint.h types consistently --- subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index 95532483e0..c18986fd06 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -458,7 +458,7 @@ static void gst_svtav1enc_finalize(GObject *object) { static void gst_svtav1enc_allocate_svt_buffers(GstSvtAv1Enc *svtav1enc) { svtav1enc->input_buf = g_new0(EbBufferHeaderType, 1); - svtav1enc->input_buf->p_buffer = (uint8_t *)g_new0(EbSvtIOFormat, 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; @@ -882,7 +882,7 @@ static gboolean gst_svtav1enc_set_format(GstVideoEncoder *encoder, GstVideoCodec if (!gst_svtav1enc_start_svt(svtav1enc)) return FALSE; - uint32_t fps = svtav1enc->svt_config->frame_rate_numerator / + guint32 fps = svtav1enc->svt_config->frame_rate_numerator / svtav1enc->svt_config->frame_rate_denominator; fps = fps > 120 ? 120 : fps; fps = fps < 24 ? 24 : fps; From 8aa376d541bc2295a48944a53bc418d8e18b81e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 2 Feb 2023 10:34:40 +0200 Subject: [PATCH 81/81] gstreamer: Decide rate-control-mode based on the bitrate/cqp/crf settings And also keep the default encoder settings but simply override them with our own values that we care about. This mirrors the encoder configuration behaviour from ffmpeg. --- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.c | 286 ++++++++---------- .../gst-plugins-bad/ext/svtav1/gstsvtav1enc.h | 14 +- 2 files changed, 141 insertions(+), 159 deletions(-) diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c index c18986fd06..31e27bd745 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.c @@ -42,28 +42,6 @@ static GType gst_svtav1enc_intra_refresh_type_get_type(void) { return intra_refresh_type; } -#define GST_SVTAV1ENC_TYPE_RATE_CONTROL_MODE (gst_svtav1enc_rate_control_mode_get_type()) -static GType gst_svtav1enc_rate_control_mode_get_type(void) { - static GType rate_control_mode_type = 0; - static const GEnumValue rate_control_mode[] = { - {SVT_AV1_RC_MODE_CQP_OR_CRF, - "Constant quantization parameter/constant rate factor", - "cqp-or-crf"}, - {SVT_AV1_RC_MODE_VBR, "Variable bitrate", "vbr"}, - {SVT_AV1_RC_MODE_CBR, "Constant bitrate", "cbr"}, - {0, NULL, NULL}, - }; - - if (!rate_control_mode_type) { - rate_control_mode_type = g_enum_register_static("GstSvtAv1EncRateControlMode", - rate_control_mode); - } - return rate_control_mode_type; -} - -/* default configuration */ -static EbSvtAv1EncConfiguration default_configuration; - /* prototypes */ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); @@ -91,19 +69,18 @@ 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, const gchar *parameters); +static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc); enum { PROP_0, PROP_PRESET, - PROP_RATE_CONTROL_MODE, PROP_TARGET_BITRATE, PROP_MAX_BITRATE, PROP_MAX_QP_ALLOWED, PROP_MIN_QP_ALLOWED, - PROP_QP, + PROP_CQP, + PROP_CRF, PROP_MAXIMUM_BUFFER_SIZE, - PROP_ADAPTIVE_QUANTIZATION, PROP_INTRA_PERIOD_LENGTH, PROP_INTRA_REFRESH_TYPE, PROP_LOGICAL_PROCESSORS, @@ -111,17 +88,16 @@ enum { PROP_PARAMETERS_STRING, }; -#define PROP_PRESET_DEFAULT 8 -#define PROP_RATE_CONTROL_MODE_DEFAULT SVT_AV1_RC_MODE_CQP_OR_CRF -#define PROP_TARGET_BITRATE_DEFAULT 2000 +#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 0 -#define PROP_QP_DEFAULT 50 +#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_ADAPTIVE_QUANTIZATION_DEFAULT 2 #define PROP_INTRA_PERIOD_LENGTH_DEFAULT -2 -#define PROP_INTRA_REFRESH_TYPE_DEFAULT 1 +#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 @@ -201,21 +177,12 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { PROP_PRESET_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property(gobject_class, - PROP_RATE_CONTROL_MODE, - g_param_spec_enum("rate-control-mode", - "Rate-control mode", - "Rate Control Mode", - GST_SVTAV1ENC_TYPE_RATE_CONTROL_MODE, - PROP_RATE_CONTROL_MODE_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. Only used when in CBR and VBR mode", + "Target bitrate in kbits/sec. Enables CBR or VBR mode", 0, 100000, PROP_TARGET_BITRATE_DEFAULT, @@ -226,7 +193,8 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { PROP_MAX_BITRATE, g_param_spec_uint("max-bitrate", "Maximum bitrate", - "Maximum bitrate in kbits/sec. Only used when in CBQ mode", + "Maximum bitrate in kbits/sec. Enables VBR mode if a different " + "target-bitrate is provided", 0, 100000, PROP_MAX_BITRATE_DEFAULT, @@ -238,7 +206,7 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { g_param_spec_uint("max-qp-allowed", "Max Quantization parameter", "Maximum QP value allowed for rate control use" - " Only used in VBR mode.", + " Only used in CBR and VBR mode.", 0, 63, PROP_MAX_QP_ALLOWED, @@ -250,21 +218,33 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { g_param_spec_uint("min-qp-allowed", "Min Quantization parameter", "Minimum QP value allowed for rate control use" - " Only used in VBR mode.", + " 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_QP, - g_param_spec_uint("qp", - "Quantization parameter", - "Quantization parameter used in CQP mode", - 0, - 63, - PROP_QP_DEFAULT, - 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, @@ -277,17 +257,6 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { PROP_MAXIMUM_BUFFER_SIZE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property( - gobject_class, - PROP_ADAPTIVE_QUANTIZATION, - g_param_spec_uint("adaptive-quantization", - "Adaptive Quantization", - "Adaptive quantization within a frame using segmentation.", - 0, - 2, - PROP_ADAPTIVE_QUANTIZATION_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property( gobject_class, PROP_INTRA_PERIOD_LENGTH, @@ -343,8 +312,20 @@ static void gst_svtav1enc_class_init(GstSvtAv1EncClass *klass) { } static void gst_svtav1enc_init(GstSvtAv1Enc *svtav1enc) { - svtav1enc->svt_config = g_new0(EbSvtAv1EncConfiguration, 1); - memcpy(svtav1enc->svt_config, &default_configuration, sizeof(default_configuration)); + 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, @@ -361,45 +342,23 @@ static void gst_svtav1enc_set_property(GObject *object, guint property_id, const GST_LOG_OBJECT(svtav1enc, "setting property %u", property_id); switch (property_id) { - case PROP_PRESET: svtav1enc->svt_config->enc_mode = g_value_get_uint(value); break; - case PROP_RATE_CONTROL_MODE: - svtav1enc->svt_config->rate_control_mode = g_value_get_enum(value); - // Forcing keyframes is only support in CQP/CRF mode - svtav1enc->svt_config->force_key_frames = (svtav1enc->svt_config->rate_control_mode == - SVT_AV1_RC_MODE_CQP_OR_CRF); - break; - case PROP_TARGET_BITRATE: - svtav1enc->svt_config->target_bit_rate = g_value_get_uint(value) * 1000; - break; - case PROP_MAX_BITRATE: - svtav1enc->svt_config->max_bit_rate = g_value_get_uint(value) * 1000; - break; - case PROP_MAX_QP_ALLOWED: - svtav1enc->svt_config->max_qp_allowed = g_value_get_uint(value); - break; - case PROP_MIN_QP_ALLOWED: - svtav1enc->svt_config->min_qp_allowed = g_value_get_uint(value); - break; - case PROP_QP: svtav1enc->svt_config->qp = g_value_get_uint(value); break; - case PROP_MAXIMUM_BUFFER_SIZE: - svtav1enc->svt_config->maximum_buffer_size_ms = g_value_get_uint(value); - break; - case PROP_ADAPTIVE_QUANTIZATION: - svtav1enc->svt_config->enable_adaptive_quantization = g_value_get_uint(value); - break; - case PROP_INTRA_PERIOD_LENGTH: - svtav1enc->svt_config->intra_period_length = g_value_get_int(value) - 1; - break; - case PROP_INTRA_REFRESH_TYPE: - svtav1enc->svt_config->intra_refresh_type = g_value_get_enum(value); - break; - case PROP_LOGICAL_PROCESSORS: - svtav1enc->svt_config->logical_processors = g_value_get_uint(value); - break; - case PROP_TARGET_SOCKET: svtav1enc->svt_config->target_socket = g_value_get_int(value); break; - case PROP_PARAMETERS_STRING: - gst_svtav1enc_parse_parameters_string(svtav1enc, g_value_get_string(value)); + 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; } } @@ -411,35 +370,18 @@ static void gst_svtav1enc_get_property(GObject *object, guint property_id, GValu GST_LOG_OBJECT(svtav1enc, "getting property %u", property_id); switch (property_id) { - case PROP_PRESET: g_value_set_uint(value, svtav1enc->svt_config->enc_mode); break; - case PROP_RATE_CONTROL_MODE: - g_value_set_enum(value, svtav1enc->svt_config->rate_control_mode); - break; - case PROP_TARGET_BITRATE: - g_value_set_uint(value, svtav1enc->svt_config->target_bit_rate / 1000); - break; - case PROP_MAX_BITRATE: - g_value_set_uint(value, svtav1enc->svt_config->max_bit_rate / 1000); - break; - case PROP_MAX_QP_ALLOWED: g_value_set_uint(value, svtav1enc->svt_config->max_qp_allowed); break; - case PROP_MIN_QP_ALLOWED: g_value_set_uint(value, svtav1enc->svt_config->min_qp_allowed); break; - case PROP_QP: g_value_set_uint(value, svtav1enc->svt_config->qp); break; - case PROP_MAXIMUM_BUFFER_SIZE: - g_value_set_uint(value, svtav1enc->svt_config->maximum_buffer_size_ms); - break; - case PROP_ADAPTIVE_QUANTIZATION: - g_value_set_uint(value, svtav1enc->svt_config->enable_adaptive_quantization); - break; - case PROP_INTRA_PERIOD_LENGTH: - g_value_set_int(value, svtav1enc->svt_config->intra_period_length + 1); - break; - case PROP_INTRA_REFRESH_TYPE: - g_value_set_enum(value, svtav1enc->svt_config->intra_refresh_type); - break; - case PROP_LOGICAL_PROCESSORS: - g_value_set_uint(value, svtav1enc->svt_config->logical_processors); - break; - case PROP_TARGET_SOCKET: g_value_set_int(value, svtav1enc->svt_config->target_socket); break; + 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; } @@ -480,6 +422,50 @@ static gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { 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); @@ -492,11 +478,11 @@ static gboolean gst_svtav1enc_configure_svt(GstSvtAv1Enc *svtav1enc) { ? GST_VIDEO_INFO_FPS_D(info) : 1; GST_LOG_OBJECT(svtav1enc, - "width %d, height %d, framerate %d", + "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); + 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: @@ -813,12 +799,10 @@ static GstFlowReturn gst_svtav1enc_dequeue_encoded_frames(GstSvtAv1Enc *svtav1en static gboolean gst_svtav1enc_open(GstVideoEncoder *encoder) { GstSvtAv1Enc *svtav1enc = GST_SVTAV1ENC(encoder); - /* don't overwrite the application's configuration */ - EbSvtAv1EncConfiguration svt_config; GST_DEBUG_OBJECT(svtav1enc, "open"); - EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, &svt_config); + EbErrorType res = svt_av1_enc_init_handle(&svtav1enc->svt_encoder, NULL, svtav1enc->svt_config); if (res != EB_ErrorNone) { GST_ELEMENT_ERROR(svtav1enc, LIBRARY, @@ -942,17 +926,13 @@ static gboolean gst_svtav1enc_propose_allocation(GstVideoEncoder *encoder, GstQu return GST_VIDEO_ENCODER_CLASS(gst_svtav1enc_parent_class)->propose_allocation(encoder, query); } -static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc, - const gchar *parameters) { +static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc) { gchar **key_values, **p; - g_free(svtav1enc->parameters_string); - svtav1enc->parameters_string = g_strdup(parameters); - - if (!parameters) + if (!svtav1enc->parameters_string) return; - p = key_values = g_strsplit(parameters, ":", -1); + p = key_values = g_strsplit(svtav1enc->parameters_string, ":", -1); while (p && *p) { gchar *equals; EbErrorType res; @@ -980,16 +960,6 @@ static void gst_svtav1enc_parse_parameters_string(GstSvtAv1Enc *svtav1enc, } static gboolean plugin_init(GstPlugin *plugin) { - EbComponentType *handle = NULL; - EbErrorType res; - - res = svt_av1_enc_init_handle(&handle, NULL, &default_configuration); - if (res != EB_ErrorNone) { - GST_ERROR("Failed to initialize SVT AV1 handle"); - return FALSE; - } - svt_av1_enc_deinit(handle); - return gst_element_register(plugin, "svtav1enc", GST_RANK_SECONDARY, GST_TYPE_SVTAV1ENC); } diff --git a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h index 488c286b38..632f0000b6 100644 --- a/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h +++ b/subprojects/gst-plugins-bad/ext/svtav1/gstsvtav1enc.h @@ -33,7 +33,19 @@ typedef struct _GstSvtAv1Enc { /* SVT-AV1 configuration */ EbSvtAv1EncConfiguration *svt_config; - gchar *parameters_string; + /* 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;