From be0e73ee6bd042a349a79b0d4b34fdc6d5366a47 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 20 May 2008 11:33:05 +0000 Subject: [PATCH] gst/rtp/gstrtph264depay.*: Add experimental support for outputting quicktime-like AVC output in addition to the exist... Original commit message from CVS: * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init), (gst_rtp_h264_depay_init), (gst_rtp_h264_depay_set_property), (gst_rtp_h264_depay_get_property), (gst_rtp_h264_depay_setcaps), (gst_rtp_h264_depay_process): * gst/rtp/gstrtph264depay.h: Add experimental support for outputting quicktime-like AVC output in addition to the existing bytestream output. * gst/rtp/gstrtph264pay.c: (gst_h264_scan_mode_get_type), (gst_rtp_h264_pay_class_init), (gst_rtp_h264_pay_init), (gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_payload_nal), (gst_rtp_h264_pay_handle_buffer), (gst_rtp_h264_pay_set_property), (gst_rtp_h264_pay_get_property): * gst/rtp/gstrtph264pay.h: Make the parsing mode configurable, for some inputs we don't need to scan every byte for start codes. Only set the marker bit on ACCESS units. --- ChangeLog | 20 ++++ gst/rtp/gstrtph264depay.c | 204 +++++++++++++++++++++++++++++++++++--- gst/rtp/gstrtph264depay.h | 3 + gst/rtp/gstrtph264pay.c | 109 ++++++++++++++++---- gst/rtp/gstrtph264pay.h | 8 ++ 5 files changed, 309 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index 930511d9b0..ff8d36ce38 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2008-05-20 Wim Taymans + + * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init), + (gst_rtp_h264_depay_init), (gst_rtp_h264_depay_set_property), + (gst_rtp_h264_depay_get_property), (gst_rtp_h264_depay_setcaps), + (gst_rtp_h264_depay_process): + * gst/rtp/gstrtph264depay.h: + Add experimental support for outputting quicktime-like AVC output in + addition to the existing bytestream output. + + * gst/rtp/gstrtph264pay.c: (gst_h264_scan_mode_get_type), + (gst_rtp_h264_pay_class_init), (gst_rtp_h264_pay_init), + (gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_payload_nal), + (gst_rtp_h264_pay_handle_buffer), (gst_rtp_h264_pay_set_property), + (gst_rtp_h264_pay_get_property): + * gst/rtp/gstrtph264pay.h: + Make the parsing mode configurable, for some inputs we don't need to + scan every byte for start codes. + Only set the marker bit on ACCESS units. + 2008-05-20 Sebastian Dröge * gst/equalizer/gstiirequalizer.c: diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c index 9b798a3412..dc4ed83024 100644 --- a/gst/rtp/gstrtph264depay.c +++ b/gst/rtp/gstrtph264depay.c @@ -29,6 +29,16 @@ GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug); #define GST_CAT_DEFAULT (rtph264depay_debug) +#define DEFAULT_BYTE_STREAM TRUE + +enum +{ + PROP_0, + PROP_BYTE_STREAM, + PROP_LAST +}; + + /* 3 zero bytes syncword */ static const guint8 sync_bytes[] = { 0, 0, 0, 1 }; @@ -77,6 +87,10 @@ GST_BOILERPLATE (GstRtpH264Depay, gst_rtp_h264_depay, GstBaseRTPDepayload, GST_TYPE_BASE_RTP_DEPAYLOAD); static void gst_rtp_h264_depay_finalize (GObject * object); +static void gst_rtp_h264_depay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_rtp_h264_depay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); static GstStateChangeReturn gst_rtp_h264_depay_change_state (GstElement * element, GstStateChange transition); @@ -112,6 +126,14 @@ gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass) gobject_class->finalize = gst_rtp_h264_depay_finalize; + gobject_class->set_property = gst_rtp_h264_depay_set_property; + gobject_class->get_property = gst_rtp_h264_depay_get_property; + + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BYTE_STREAM, + g_param_spec_boolean ("byte-stream", "Byte Stream", + "Generate byte stream format of NALU", DEFAULT_BYTE_STREAM, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = gst_rtp_h264_depay_change_state; gstbasertpdepayload_class->process = gst_rtp_h264_depay_process; @@ -126,6 +148,7 @@ gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay, GstRtpH264DepayClass * klass) { rtph264depay->adapter = gst_adapter_new (); + rtph264depay->byte_stream = DEFAULT_BYTE_STREAM; } static void @@ -143,6 +166,42 @@ gst_rtp_h264_depay_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +gst_rtp_h264_depay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRtpH264Depay *rtph264depay; + + rtph264depay = GST_RTP_H264_DEPAY (object); + + switch (prop_id) { + case PROP_BYTE_STREAM: + rtph264depay->byte_stream = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtp_h264_depay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRtpH264Depay *rtph264depay; + + rtph264depay = GST_RTP_H264_DEPAY (object); + + switch (prop_id) { + case PROP_BYTE_STREAM: + g_value_set_boolean (value, rtph264depay->byte_stream); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static const guint8 a2bin[256] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, @@ -198,6 +257,9 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) gint clock_rate = 90000; GstStructure *structure = gst_caps_get_structure (caps, 0); GstRtpH264Depay *rtph264depay; + const gchar *ps, *profile; + GstBuffer *codec_data; + guint8 *b64; rtph264depay = GST_RTP_H264_DEPAY (depayload); @@ -206,16 +268,18 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) srccaps = gst_caps_new_simple ("video/x-h264", NULL); - if (gst_structure_has_field (structure, "sprop-parameter-sets")) { - const gchar *ps; + /* Base64 encoded, comma separated config NALs */ + ps = gst_structure_get_string (structure, "sprop-parameter-sets"); + /* hex: AVCProfileIndication:8 | profile_compat:8 | AVCLevelIndication:8 */ + profile = gst_structure_get_string (structure, "profile-level-id"); + + if (rtph264depay->byte_stream && ps != NULL) { + /* for bytestream we only need the parameter sets but we don't error out + * when they are not there, we assume they are in the stream. */ gchar **params; guint len, total; gint i; - GstBuffer *codec_data; - guint8 *b64; - /* Base64 encoded, comma separated config NALs */ - ps = gst_structure_get_string (structure, "sprop-parameter-sets"); params = g_strsplit (ps, ",", 0); /* count total number of bytes in base64. Also include the sync bytes in @@ -246,14 +310,106 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) if (rtph264depay->codec_data) gst_buffer_unref (rtph264depay->codec_data); rtph264depay->codec_data = codec_data; + } else if (!rtph264depay->byte_stream) { + gchar **params; + guint8 **sps, **pps; + guint len, num_sps, num_pps; + gint i; + guint8 *data; + guint32 profile_id; + + if (ps == NULL || profile == NULL) + goto incomplete_caps; + + params = g_strsplit (ps, ",", 0); + len = g_strv_length (params); + + GST_DEBUG_OBJECT (depayload, "we have %d params", len); + + sps = g_new0 (guint8 *, len + 1); + pps = g_new0 (guint8 *, len + 1); + num_sps = num_pps = 0; + + /* start with 7 bytes header */ + len = 7; + for (i = 0; params[i]; i++) { + gint nal_len; + guint8 *nalp; + + nal_len = strlen (params[i]); + nalp = g_malloc (nal_len + 2); + nal_len = decode_base64 (params[i], nalp + 2); + nalp[0] = (nal_len >> 8) & 0xff; + nalp[1] = nal_len & 0xff; + len += nal_len + 2; + + /* copy to the right list */ + if ((nalp[2] & 0x1f) == 7) { + GST_DEBUG_OBJECT (depayload, "adding param %d as SPS %d", i, num_sps); + sps[num_sps++] = nalp; + } else { + GST_DEBUG_OBJECT (depayload, "adding param %d as PPS %d", i, num_pps); + pps[num_pps++] = nalp; + } + } + g_strfreev (params); + + codec_data = gst_buffer_new_and_alloc (len); + data = GST_BUFFER_DATA (codec_data); + + /* 8 bits version == 1 */ + *data++ = 1; + /* hex: AVCProfileIndication:8 | profile_compat:8 | AVCLevelIndication:8 */ + sscanf (profile, "%6x", &profile_id); + *data++ = (profile_id >> 16) & 0xff; + *data++ = (profile_id >> 8) & 0xff; + *data++ = profile_id & 0xff; + /* 6 bits reserved | 2 bits lengthSizeMinusOn */ + *data++ = 0xff; + /* 3 bits reserved | 5 bits numOfSequenceParameterSets */ + *data++ = 0xe0 | (num_sps & 0x1f); + + /* copy all SPS */ + for (i = 0; sps[i]; i++) { + len = ((sps[i][0] << 8) | sps[i][1]) + 2; + GST_DEBUG_OBJECT (depayload, "copy SPS %d of length %d", i, len); + memcpy (data, sps[i], len); + g_free (sps[i]); + data += len; + } + g_free (sps); + /* 8 bits numOfPictureParameterSets */ + *data++ = num_pps; + /* copy all PPS */ + for (i = 0; pps[i]; i++) { + len = ((pps[i][0] << 8) | pps[i][1]) + 2; + GST_DEBUG_OBJECT (depayload, "copy PPS %d of length %d", i, len); + memcpy (data, pps[i], len); + g_free (pps[i]); + data += len; + } + g_free (pps); + GST_BUFFER_SIZE (codec_data) = data - GST_BUFFER_DATA (codec_data); + + gst_caps_set_simple (srccaps, + "codec_data", GST_TYPE_BUFFER, codec_data, NULL); } gst_pad_set_caps (depayload->srcpad, srccaps); gst_caps_unref (srccaps); return TRUE; + + /* ERRORS */ +incomplete_caps: + { + GST_DEBUG_OBJECT (depayload, "we have incomplete caps"); + return FALSE; + } } +/* FIXME, non-bytestream handling is freaking out ffmpeg. Apparently we need to + * group all NAL units belonging to one frame together */ static GstBuffer * gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { @@ -337,17 +493,24 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) */ nalu_size = (payload[0] << 8) | payload[1]; - /* strip NALU size */ - payload += 2; - payload_len -= 2; - if (nalu_size > payload_len) nalu_size = payload_len; outsize = nalu_size + sizeof (sync_bytes); outbuf = gst_buffer_new_and_alloc (outsize); outdata = GST_BUFFER_DATA (outbuf); - memcpy (outdata, sync_bytes, sizeof (sync_bytes)); + if (rtph264depay->byte_stream) { + memcpy (outdata, sync_bytes, sizeof (sync_bytes)); + } else { + outdata[0] = outdata[1] = 0; + outdata[2] = payload[0]; + outdata[3] = payload[1]; + } + + /* strip NALU size */ + payload += 2; + payload_len -= 2; + outdata += sizeof (sync_bytes); memcpy (outdata, payload, nalu_size); @@ -414,7 +577,6 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outsize = nalu_size + sizeof (sync_bytes); outbuf = gst_buffer_new_and_alloc (outsize); outdata = GST_BUFFER_DATA (outbuf); - memcpy (outdata, sync_bytes, sizeof (sync_bytes)); outdata += sizeof (sync_bytes); memcpy (outdata, payload, nalu_size); outdata[0] = nal_header; @@ -445,7 +607,17 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outsize = gst_adapter_available (rtph264depay->adapter); outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize); + outdata = GST_BUFFER_DATA (outbuf); + if (rtph264depay->byte_stream) { + memcpy (outdata, sync_bytes, sizeof (sync_bytes)); + } else { + outsize -= 4; + outdata[0] = (outsize >> 24); + outdata[1] = (outsize >> 16); + outdata[2] = (outsize >> 8); + outdata[3] = (outsize); + } gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad)); /* push codec_data first */ @@ -469,7 +641,13 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) outsize = nalu_size + sizeof (sync_bytes); outbuf = gst_buffer_new_and_alloc (outsize); outdata = GST_BUFFER_DATA (outbuf); - memcpy (outdata, sync_bytes, sizeof (sync_bytes)); + if (rtph264depay->byte_stream) { + memcpy (outdata, sync_bytes, sizeof (sync_bytes)); + } else { + outdata[0] = outdata[1] = 0; + outdata[2] = nalu_size >> 8; + outdata[3] = nalu_size & 0xff; + } outdata += sizeof (sync_bytes); memcpy (outdata, payload, nalu_size); diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h index 41c4fc076c..d701ecf946 100644 --- a/gst/rtp/gstrtph264depay.h +++ b/gst/rtp/gstrtph264depay.h @@ -44,9 +44,12 @@ struct _GstRtpH264Depay { GstBaseRTPDepayload depayload; + gboolean byte_stream; + GstBuffer *codec_data; GstAdapter *adapter; gboolean wait_start; + }; struct _GstRtpH264DepayClass diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c index f638b174aa..4c014b9a78 100644 --- a/gst/rtp/gstrtph264pay.c +++ b/gst/rtp/gstrtph264pay.c @@ -64,16 +64,46 @@ GST_STATIC_PAD_TEMPLATE ("src", "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"") ); +#define GST_TYPE_H264_SCAN_MODE (gst_h264_scan_mode_get_type()) +static GType +gst_h264_scan_mode_get_type (void) +{ + static GType h264_scan_mode_type = 0; + static const GEnumValue h264_scan_modes[] = { + {GST_H264_SCAN_MODE_BYTESTREAM, + "Scan complete bytestream for NALUs (not implemented)", + "bytestream"}, + {GST_H264_SCAN_MODE_MULTI_NAL, "Buffers contain multiple complete NALUs", + "multiple"}, + {GST_H264_SCAN_MODE_SINLE_NAL, "Buffers contain a single complete NALU", + "single"}, + {0, NULL, NULL}, + }; + + if (!h264_scan_mode_type) { + h264_scan_mode_type = + g_enum_register_static ("GstH264PayScanMode", h264_scan_modes); + } + return h264_scan_mode_type; +} + #define DEFAULT_PROFILE_LEVEL_ID NULL #define DEFAULT_SPROP_PARAMETER_SETS NULL +#define DEFAULT_SPROP_PARAMETER_SETS NULL +#define DEFAULT_SCAN_MODE GST_H264_SCAN_MODE_MULTI_NAL enum { - ARG_0, - ARG_PROFILE_LEVEL_ID, - ARG_SPROP_PARAMETER_SETS + PROP_0, + PROP_PROFILE_LEVEL_ID, + PROP_SPROP_PARAMETER_SETS, + PROP_SCAN_MODE, + PROP_LAST }; + +#define IS_ACCESS_UNIT(x) (((x) > 0x00) && ((x) < 0x06)) + static void gst_rtp_h264_pay_finalize (GObject * object); static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement * element, @@ -119,19 +149,29 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass) gobject_class->set_property = gst_rtp_h264_pay_set_property; gobject_class->get_property = gst_rtp_h264_pay_get_property; - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROFILE_LEVEL_ID, - g_param_spec_string ("profile-level-id", "profile-level-id", - "The base64 profile-level-id to set in out caps (set to NULL to extract from stream)", + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_PROFILE_LEVEL_ID, g_param_spec_string ("profile-level-id", + "profile-level-id", + "The base64 profile-level-id to set in out caps (set to NULL to " + "extract from stream)", DEFAULT_PROFILE_LEVEL_ID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), - ARG_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets", + PROP_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets", "sprop-parameter-sets", - "The base64 sprop-parameter-sets to set in out caps (set to NULL to extract from stream)", + "The base64 sprop-parameter-sets to set in out caps (set to NULL to " + "extract from stream)", DEFAULT_SPROP_PARAMETER_SETS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCAN_MODE, + g_param_spec_enum ("scan-mode", "Scan Mode", + "How to scan the input buffers for NAL units. Performance can be " + "increased when certain assumptions are made about the input buffers", + GST_TYPE_H264_SCAN_MODE, DEFAULT_SCAN_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gobject_class->finalize = gst_rtp_h264_pay_finalize; gstelement_class->change_state = gst_rtp_h264_pay_change_state; @@ -149,6 +189,7 @@ gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay, GstRtpH264PayClass * klass) rtph264pay->profile = 0; rtph264pay->sps = NULL; rtph264pay->pps = NULL; + rtph264pay->scan_mode = GST_H264_SCAN_MODE_MULTI_NAL; } static void @@ -239,6 +280,8 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps) GST_DEBUG_OBJECT (rtph264pay, "profile %06x", profile); /* 6 bits reserved | 2 bits lengthSizeMinusOne */ + /* this is the number of bytes in front of the NAL units to mark their + * length */ rtph264pay->nal_length_size = (data[4] & 0x03) + 1; GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size); /* 3 bits reserved | 5 bits numOfSequenceParameterSets */ @@ -277,6 +320,7 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps) if (size < 1) goto avcc_error; + /* 8 bits numOfPictureParameterSets */ num_pps = data[0]; data += 1; size -= 1; @@ -579,7 +623,10 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload, guint8 * data, outbuf = gst_rtp_buffer_new_allocate (size, 0, 0); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - gst_rtp_buffer_set_marker (outbuf, 1); + /* only set the marker bit on packets containing access units */ + if (IS_ACCESS_UNIT (nalType)) { + gst_rtp_buffer_set_marker (outbuf, 1); + } payload = gst_rtp_buffer_get_payload (outbuf); GST_DEBUG_OBJECT (basepayload, "Copying %d bytes to outbuf", size); @@ -621,7 +668,9 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload, guint8 * data, GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii); end = 1; } - gst_rtp_buffer_set_marker (outbuf, end); + if (IS_ACCESS_UNIT (nalType)) { + gst_rtp_buffer_set_marker (outbuf, end); + } /* FU indicator */ payload[0] = (nalHeader & 0x60) | 28; @@ -723,14 +772,20 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload, data += 4; size -= 4; - /* use next_start_code() to scan buffer. - * next_start_code() returns the offset in data, - * starting from zero to the first byte of 0.0.0.1 - * If no start code is found, it returns the value of the - * 'size' parameter. - * data is unchanged by the call to next_start_code() - */ - next = next_start_code (data, size); + if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_SINLE_NAL) { + /* we are told that there is only a single NAL in this packet so that we + * can avoid scanning for the next NAL. */ + next = size; + } else { + /* use next_start_code() to scan buffer. + * next_start_code() returns the offset in data, + * starting from zero to the first byte of 0.0.0.1 + * If no start code is found, it returns the value of the + * 'size' parameter. + * data is unchanged by the call to next_start_code() + */ + next = next_start_code (data, size); + } /* nal length is distance to next start code */ nal_len = next; @@ -804,15 +859,21 @@ gst_rtp_h264_pay_set_property (GObject * object, guint prop_id, rtph264pay = GST_RTP_H264_PAY (object); switch (prop_id) { - case ARG_PROFILE_LEVEL_ID: + case PROP_PROFILE_LEVEL_ID: + g_free (rtph264pay->profile_level_id); rtph264pay->profile_level_id = g_value_dup_string (value); rtph264pay->update_caps = TRUE; break; - case ARG_SPROP_PARAMETER_SETS: + case PROP_SPROP_PARAMETER_SETS: + g_free (rtph264pay->sprop_parameter_sets); rtph264pay->sprop_parameter_sets = g_value_dup_string (value); rtph264pay->update_caps = TRUE; break; + case PROP_SCAN_MODE: + rtph264pay->scan_mode = g_value_get_enum (value); + break; default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -826,13 +887,17 @@ gst_rtp_h264_pay_get_property (GObject * object, guint prop_id, rtph264pay = GST_RTP_H264_PAY (object); switch (prop_id) { - case ARG_PROFILE_LEVEL_ID: + case PROP_PROFILE_LEVEL_ID: g_value_set_string (value, rtph264pay->profile_level_id); break; - case ARG_SPROP_PARAMETER_SETS: + case PROP_SPROP_PARAMETER_SETS: g_value_set_string (value, rtph264pay->sprop_parameter_sets); break; + case PROP_SCAN_MODE: + g_value_set_enum (value, rtph264pay->scan_mode); + break; default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h index b0ac096520..f48fb98b5d 100644 --- a/gst/rtp/gstrtph264pay.h +++ b/gst/rtp/gstrtph264pay.h @@ -36,6 +36,13 @@ G_BEGIN_DECLS #define GST_IS_RTP_H264_PAY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H264_PAY)) +typedef enum +{ + GST_H264_SCAN_MODE_BYTESTREAM, + GST_H264_SCAN_MODE_MULTI_NAL, + GST_H264_SCAN_MODE_SINLE_NAL +} GstH264ScanMode; + typedef struct _GstRtpH264Pay GstRtpH264Pay; typedef struct _GstRtpH264PayClass GstRtpH264PayClass; @@ -53,6 +60,7 @@ struct _GstRtpH264Pay gchar *profile_level_id; gchar *sprop_parameter_sets; gboolean update_caps; + GstH264ScanMode scan_mode; }; struct _GstRtpH264PayClass