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