From 6a8d66728f0c88c4e087d489084ecc31071dc251 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Sun, 15 May 2011 13:23:39 +0200 Subject: [PATCH] h264parse: allow full negotiation for packetized input ... by defaulting to allow splitting packetized input and having negotiation with downstream deciding whether or not this applies. Also enable pass-through parsing mode if input and output format (stream-format and alignment) match. API: GstH264Parse:split-packetized (removed) Fixes #650228. --- gst/videoparsers/gsth264parse.c | 156 ++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 70 deletions(-) diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c index fd633015fb..2b55f2feae 100644 --- a/gst/videoparsers/gsth264parse.c +++ b/gst/videoparsers/gsth264parse.c @@ -33,13 +33,11 @@ GST_DEBUG_CATEGORY (h264_parse_debug); #define GST_CAT_DEFAULT h264_parse_debug -#define DEFAULT_SPLIT_PACKETIZED FALSE #define DEFAULT_CONFIG_INTERVAL (0) enum { PROP_0, - PROP_SPLIT_PACKETIZED, PROP_CONFIG_INTERVAL, PROP_LAST }; @@ -118,10 +116,6 @@ gst_h264_parse_class_init (GstH264ParseClass * klass) gobject_class->set_property = gst_h264_parse_set_property; gobject_class->get_property = gst_h264_parse_get_property; - g_object_class_install_property (gobject_class, PROP_SPLIT_PACKETIZED, - g_param_spec_boolean ("split-packetized", "Split packetized", - "Split NAL units of packetized streams", DEFAULT_SPLIT_PACKETIZED, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL, g_param_spec_uint ("config-interval", "SPS PPS Send Interval", @@ -252,6 +246,40 @@ gst_h264_parse_get_string (GstH264Parse * parse, gboolean format, gint code) } } +static void +gst_h264_parse_format_from_caps (GstCaps * caps, guint * format, guint * align) +{ + + if (format) + *format = GST_H264_PARSE_FORMAT_NONE; + + if (align) + *align = GST_H264_PARSE_ALIGN_NONE; + + if (caps && gst_caps_get_size (caps) > 0) { + GstStructure *s = gst_caps_get_structure (caps, 0); + const gchar *str = NULL; + + if (format) { + if ((str = gst_structure_get_string (s, "stream-format"))) { + if (strcmp (str, "avc") == 0) + *format = GST_H264_PARSE_FORMAT_AVC; + else if (strcmp (str, "byte-stream") == 0) + *format = GST_H264_PARSE_FORMAT_BYTE; + } + } + + if (align) { + if ((str = gst_structure_get_string (s, "alignment"))) { + if (strcmp (str, "au") == 0) + *align = GST_H264_PARSE_ALIGN_AU; + else if (strcmp (str, "nal") == 0) + *align = GST_H264_PARSE_ALIGN_NAL; + } + } + } +} + /* check downstream caps to configure format and alignment */ static void gst_h264_parse_negotiate (GstH264Parse * h264parse) @@ -263,30 +291,7 @@ gst_h264_parse_negotiate (GstH264Parse * h264parse) caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (h264parse)); GST_DEBUG_OBJECT (h264parse, "allowed caps: %" GST_PTR_FORMAT, caps); - if (caps && gst_caps_get_size (caps) > 0) { - GstStructure *s = gst_caps_get_structure (caps, 0); - const gchar *str = NULL; - - if ((str = gst_structure_get_string (s, "stream-format"))) { - if (strcmp (str, "avc") == 0) { - format = GST_H264_PARSE_FORMAT_AVC; - } else if (strcmp (str, "byte-stream") == 0) { - format = GST_H264_PARSE_FORMAT_BYTE; - } else { - GST_DEBUG_OBJECT (h264parse, "unknown stream-format: %s", str); - } - } - - if ((str = gst_structure_get_string (s, "alignment"))) { - if (strcmp (str, "au") == 0) { - align = GST_H264_PARSE_ALIGN_AU; - } else if (strcmp (str, "nal") == 0) { - align = GST_H264_PARSE_ALIGN_NAL; - } else { - GST_DEBUG_OBJECT (h264parse, "unknown alignment: %s", str); - } - } - } + gst_h264_parse_format_from_caps (caps, &format, &align); if (caps) gst_caps_unref (caps); @@ -662,10 +667,10 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse) } static void -gst_h264_parse_update_src_caps (GstH264Parse * h264parse) +gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps) { GstH264ParamsSPS *sps; - GstCaps *caps = NULL, *sink_caps; + GstCaps *sink_caps; gboolean modified = FALSE; GstBuffer *buf = NULL; @@ -674,8 +679,14 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse) else if (G_UNLIKELY (!h264parse->update_caps)) return; + /* if this is being called from the first _setcaps call, caps on the sinkpad + * aren't set yet and so they need to be passed as an argument */ + if (caps) + sink_caps = caps; + else + sink_caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (h264parse)); + /* carry over input caps as much as possible; override with our own stuff */ - sink_caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (h264parse)); if (sink_caps) gst_caps_ref (sink_caps); else @@ -700,6 +711,7 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse) } } + caps = NULL; if (G_UNLIKELY (!sps)) { caps = gst_caps_copy (sink_caps); } else if (G_UNLIKELY (h264parse->width != sps->width || @@ -759,7 +771,7 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) h264parse = GST_H264_PARSE (parse); buffer = frame->buffer; - gst_h264_parse_update_src_caps (h264parse); + gst_h264_parse_update_src_caps (h264parse, NULL); gst_h264_params_get_timestamp (h264parse->params, &GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer), @@ -921,8 +933,8 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps) GstH264Parse *h264parse; GstStructure *str; const GValue *value; - GstBuffer *buffer = NULL; - guint size; + GstBuffer *codec_data = NULL; + guint size, format, align; h264parse = GST_H264_PARSE (parse); @@ -947,11 +959,11 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps) /* make note for optional split processing */ h264parse->packetized = TRUE; - buffer = gst_value_get_buffer (value); - if (!buffer) + codec_data = gst_value_get_buffer (value); + if (!codec_data) goto wrong_type; - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); + data = GST_BUFFER_DATA (codec_data); + size = GST_BUFFER_SIZE (codec_data); /* parse the avcC data */ if (size < 7) @@ -996,6 +1008,8 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps) data += len + 2; size -= len + 2; } + + h264parse->codec_data = gst_buffer_ref (codec_data); } else { GST_DEBUG_OBJECT (h264parse, "have bytestream h264"); /* nothing to pre-process */ @@ -1004,32 +1018,35 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps) h264parse->nal_length_size = 4; } - if (h264parse->packetized) { - if (h264parse->split_packetized) { - GST_DEBUG_OBJECT (h264parse, - "converting AVC to nal bytestream prior to parsing"); - /* negotiate behaviour with upstream */ - gst_h264_parse_negotiate (h264parse); - if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE) { - /* arrange to insert codec-data in-stream if needed */ - h264parse->push_codec = h264parse->packetized; - } - gst_base_parse_set_passthrough (parse, FALSE); - } else { - GST_DEBUG_OBJECT (h264parse, "passing on packetized AVC"); - /* no choice to negotiate */ - h264parse->format = GST_H264_PARSE_FORMAT_AVC; - h264parse->align = GST_H264_PARSE_ALIGN_AU; - /* fallback codec-data */ - h264parse->codec_data = gst_buffer_ref (buffer); - /* pass through unharmed, though _chain will parse a bit */ - gst_base_parse_set_passthrough (parse, TRUE); - /* we did parse codec-data and might supplement src caps */ - gst_h264_parse_update_src_caps (h264parse); - } + /* negotiate with downstream, sets ->format and ->align */ + gst_h264_parse_negotiate (h264parse); + + /* get upstream format and align from caps */ + gst_h264_parse_format_from_caps (caps, &format, &align); + + /* if upstream sets codec_data without setting stream-format and alignment, we + * assume stream-format=avc,alignment=au */ + if (format == GST_H264_PARSE_FORMAT_NONE) { + if (codec_data == NULL) + goto unknown_input_format; + + format = GST_H264_PARSE_FORMAT_AVC; + align = GST_H264_PARSE_ALIGN_AU; + } + + if (format == h264parse->format && align == h264parse->align) { + gst_base_parse_set_passthrough (parse, TRUE); + + /* we did parse codec-data and might supplement src caps */ + gst_h264_parse_update_src_caps (h264parse, caps); + } else if (format == GST_H264_PARSE_FORMAT_AVC && + h264parse->format == GST_H264_PARSE_FORMAT_BYTE) { + /* arrange to insert codec-data in-stream if needed. + * src caps are only arranged for later on */ + h264parse->push_codec = TRUE; + h264parse->split_packetized = TRUE; } - /* src caps are only arranged for later on */ return TRUE; /* ERRORS */ @@ -1048,6 +1065,11 @@ wrong_type: GST_DEBUG_OBJECT (h264parse, "wrong codec-data type"); goto refuse_caps; } +unknown_input_format: + { + GST_DEBUG_OBJECT (h264parse, "unknown stream-format and no codec_data"); + goto refuse_caps; + } refuse_caps: { GST_WARNING_OBJECT (h264parse, "refused caps %" GST_PTR_FORMAT, caps); @@ -1155,9 +1177,6 @@ gst_h264_parse_set_property (GObject * object, guint prop_id, parse = GST_H264_PARSE (object); switch (prop_id) { - case PROP_SPLIT_PACKETIZED: - parse->split_packetized = g_value_get_boolean (value); - break; case PROP_CONFIG_INTERVAL: parse->interval = g_value_get_uint (value); break; @@ -1176,9 +1195,6 @@ gst_h264_parse_get_property (GObject * object, guint prop_id, GValue * value, parse = GST_H264_PARSE (object); switch (prop_id) { - case PROP_SPLIT_PACKETIZED: - g_value_set_boolean (value, parse->split_packetized); - break; case PROP_CONFIG_INTERVAL: g_value_set_uint (value, parse->interval); break;