From 9984bd8f4646ce48b4d9b3645ffc67ffcdc75161 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Nov 2023 15:31:05 -0500 Subject: [PATCH 61/68] v4l2codecs: h264enc: Add profile negotiation We currently only support main, constrained-baseline and baseline. Some work on the SPS is needed to generate a valid header for high. Upstream-Status: Pending --- sys/v4l2codecs/gstv4l2codech264enc.c | 80 ++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c index e7ae63a..b1617c9 100644 --- a/sys/v4l2codecs/gstv4l2codech264enc.c +++ b/sys/v4l2codecs/gstv4l2codech264enc.c @@ -47,10 +47,17 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SINK_NAME, GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS))); -static GstStaticPadTemplate src_template = -GST_STATIC_PAD_TEMPLATE (GST_VIDEO_ENCODER_SRC_NAME, - GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-h264,alignment=au,stream-format=byte-stream")); +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h264, " + "framerate = (fraction) [0/1, MAX], " + "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], " + "stream-format = (string) byte-stream, " + "alignment = (string) au, " + "profile = (string) { main, constrained-baseline, baseline}") + ); + #define H264ENC_DEFAULT_KEYFRAME_INTERVAL 30 @@ -90,6 +97,7 @@ struct _GstV4l2CodecH264Enc guint64 targeted_bitrate; gboolean cabac; guint cabac_init_idc; + gchar *profile_name; GstV4l2CodecAllocator *sink_allocator; GstV4l2CodecAllocator *src_allocator; @@ -234,6 +242,8 @@ gst_v4l2_codec_h264_enc_stop (GstVideoEncoder * encoder) gst_video_codec_state_unref (self->output_state); self->output_state = NULL; + g_clear_pointer (&self->profile_name, g_free); + return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (encoder); } @@ -445,9 +455,19 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self, memset (&self->sps, 0, sizeof (self->pps)); /* SPS */ - self->sps.profile_idc = 66; - self->sps.constraint_set0_flag = 1; - self->sps.constraint_set1_flag = 0; + if (g_str_equal (self->profile_name, "baseline")) { + self->sps.profile_idc = GST_H264_PROFILE_BASELINE; + self->sps.constraint_set0_flag = 1; + self->sps.constraint_set1_flag = 0; + } else if (g_str_equal (self->profile_name, "constrained-baseline")) { + self->sps.profile_idc = GST_H264_PROFILE_BASELINE; + self->sps.constraint_set0_flag = 1; + self->sps.constraint_set1_flag = 1; + } else if (g_str_equal (self->profile_name, "main")) { + self->sps.profile_idc = GST_H264_PROFILE_MAIN; + } else if (g_str_equal (self->profile_name, "high")) { + self->sps.profile_idc = GST_H264_PROFILE_HIGH; + } self->sps.chroma_format_idc = 1; /* YUV 4:2:0 */ @@ -573,6 +593,43 @@ gst_v4l2_codec_h264_enc_init_sps_pps (GstV4l2CodecH264Enc * self, self->pps.entropy_coding_mode_flag = self->cabac; } +static gchar * +gst_v4l2_codec_h264_enc_decide_profile (GstV4l2CodecH264Enc * self) +{ + GstCaps *allowed_caps = NULL; + const gchar *profile_name; + GstStructure *structure; + gchar *ret; + + g_object_get (self, "cabac", &self->cabac, "cabac-init-idc", + &self->cabac_init_idc, NULL); + + /* First, check whether the downstream requires a specified profile. */ + allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self)); + if (!allowed_caps) + allowed_caps = gst_pad_query_caps (GST_VIDEO_ENCODER_SRC_PAD (self), NULL); + + allowed_caps = gst_caps_make_writable (allowed_caps); + allowed_caps = gst_caps_fixate (allowed_caps); + structure = gst_caps_get_structure (allowed_caps, 0); + profile_name = gst_structure_get_string (structure, "profile"); + + if (self->cabac) { + if (!g_strstr_len (profile_name, -1, "main") + && !g_strstr_len (profile_name, -1, "high")) { + GST_WARNING_OBJECT (self, + "CABAC is not support by user selected profile '%s'" + ", disabling this features", profile_name); + self->cabac = FALSE; + } + } + + ret = g_strdup (profile_name); + gst_caps_unref (allowed_caps); + + return ret; +} + static gboolean gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) @@ -615,9 +672,13 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder, if (self->output_state) gst_video_codec_state_unref (self->output_state); + g_free (self->profile_name); + self->profile_name = gst_v4l2_codec_h264_enc_decide_profile (self); + caps = gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "au", NULL); + "alignment", G_TYPE_STRING, "au", + "profile", G_TYPE_STRING, self->profile_name, NULL); self->output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), @@ -641,9 +702,6 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder, gst_v4l2_codec_h264_enc_get_qp_range (self->encoder, &self->qp_min, &self->qp_max); - g_object_get (self, "cabac", &self->cabac, "cabac-init-idc", - &self->cabac_init_idc, NULL); - gst_v4l2_codec_h264_enc_init_sps_pps (self, state); return TRUE; -- 2.25.1