summaryrefslogtreecommitdiffstats
path: root/gst/rtp/gstrtph264depay.c
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2008-05-20 11:33:05 +0000
committerWim Taymans <wim.taymans@gmail.com>2008-05-20 11:33:05 +0000
commitbe0e73ee6bd042a349a79b0d4b34fdc6d5366a47 (patch)
tree4f67b41ccf070337c0fe75ace68a3303f0f946d9 /gst/rtp/gstrtph264depay.c
parent3d3f7cd6dafbf0b5a49f94627fa638e493e6ca8f (diff)
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.
Diffstat (limited to 'gst/rtp/gstrtph264depay.c')
-rw-r--r--gst/rtp/gstrtph264depay.c204
1 files changed, 191 insertions, 13 deletions
diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c
index 9b798a34..dc4ed830 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);