From e2b3665ae6ed4bfbda2eb7e27e12dcccdc7c595b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 3 Aug 2009 21:24:44 +0200 Subject: rtpsv3vdepay: Properly fill codec_data and cleanup code a bite more. --- gst/rtp/gstrtpsv3vdepay.c | 223 +++++++++++++++++++++++++--------------------- 1 file changed, 119 insertions(+), 104 deletions(-) (limited to 'gst/rtp') diff --git a/gst/rtp/gstrtpsv3vdepay.c b/gst/rtp/gstrtpsv3vdepay.c index ae7cf57c..b9b03c24 100644 --- a/gst/rtp/gstrtpsv3vdepay.c +++ b/gst/rtp/gstrtpsv3vdepay.c @@ -139,128 +139,143 @@ static GstBuffer * gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpSV3VDepay *rtpsv3vdepay; - GstBuffer *outbuf; + static struct + { + guint width, height; + } resolutions[7] = { + { + 160, 128}, { + 128, 96}, { + 176, 144}, { + 352, 288}, { + 704, 576}, { + 240, 180}, { + 320, 240} + }; + gint payload_len; + guint8 *payload; + gboolean M; + gboolean C, S, E; + GstBuffer *outbuf = NULL; guint16 seq; rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload); /* flush on sequence number gaps */ seq = gst_rtp_buffer_get_seq (buf); + + GST_DEBUG ("timestamp %" GST_TIME_FORMAT ", sequence number:%d", + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), seq); + if (seq != rtpsv3vdepay->nextseq) { + GST_DEBUG ("Sequence discontinuity, clearing adapter"); gst_adapter_clear (rtpsv3vdepay->adapter); } rtpsv3vdepay->nextseq = seq + 1; - { - static struct - { - guint width, height; - } resolutions[7] = { - { - 160, 128}, { - 128, 96}, { - 176, 144}, { - 352, 288}, { - 704, 576}, { - 240, 180}, { - 320, 240} - }; - gint payload_len; - guint8 *payload; - gboolean M; - gboolean C, S, E; - - payload_len = gst_rtp_buffer_get_payload_len (buf); - if (payload_len < 3) - goto bad_packet; - - payload = gst_rtp_buffer_get_payload (buf); - - M = gst_rtp_buffer_get_marker (buf); - - /* This is all a guess: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * C: config, packet contains config info - * S: start, packet contains start of frame - * E: end, packet contains end of frame - */ - /* this seems to indicate a packet with a config string sent before each - * keyframe */ - C = (payload[0] & 0x40) == 0x40; - - /* redundant with the RTP marker bit */ - S = (payload[0] & 0x20) == 0x20; - E = (payload[0] & 0x10) == 0x10; - - GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E); - - GST_MEMDUMP ("incoming buffer", payload, payload_len); - - if (C) { - GstCaps *caps; - GstBuffer *codec_data; - GValue value = { 0 }; - guint8 res; - - /* if we already have caps, we don't need to do anything. FIXME, check if - * something changed. */ - if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload))) - return NULL; - - res = payload[2] >> 5; - - /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */ - if (res < 7) { - rtpsv3vdepay->width = resolutions[res].width; - rtpsv3vdepay->height = resolutions[res].height; - } else { - /* extended width/height, they're contained in the following 24bit */ - rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1); - rtpsv3vdepay->height = - (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5); - } - - /* we need a dummy empty codec data */ - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_deserialize (&value, ""); - codec_data = gst_value_get_buffer (&value); - - caps = gst_caps_new_simple ("video/x-svq", - "svqversion", G_TYPE_INT, 3, - "width", G_TYPE_INT, rtpsv3vdepay->width, - "height", G_TYPE_INT, rtpsv3vdepay->height, - "codec_data", GST_TYPE_BUFFER, codec_data, NULL); - gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); - gst_caps_unref (caps); - g_value_unset (&value); - - rtpsv3vdepay->configured = TRUE; - - return NULL; + payload_len = gst_rtp_buffer_get_payload_len (buf); + if (payload_len < 3) + goto bad_packet; + + payload = gst_rtp_buffer_get_payload (buf); + + M = gst_rtp_buffer_get_marker (buf); + + /* This is all a guess: + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * C: config, packet contains config info + * S: start, packet contains start of frame + * E: end, packet contains end of frame + */ + /* this seems to indicate a packet with a config string sent before each + * keyframe */ + C = (payload[0] & 0x40) == 0x40; + + /* redundant with the RTP marker bit */ + S = (payload[0] & 0x20) == 0x20; + E = (payload[0] & 0x10) == 0x10; + + GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E); + + GST_MEMDUMP ("incoming buffer", payload, payload_len); + + if (G_UNLIKELY (C)) { + GstCaps *caps; + GstBuffer *codec_data; + guint8 res; + + GST_DEBUG ("Configuration packet"); + + /* if we already have caps, we don't need to do anything. FIXME, check if + * something changed. */ + if (G_UNLIKELY (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload)))) { + GST_DEBUG ("Already configured, skipping config parsing"); + goto beach; + } + + res = payload[2] >> 5; + + /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */ + if (G_LIKELY (res < 7)) { + rtpsv3vdepay->width = resolutions[res].width; + rtpsv3vdepay->height = resolutions[res].height; + } else { + /* extended width/height, they're contained in the following 24bit */ + rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1); + rtpsv3vdepay->height = + (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5); } - if (G_LIKELY (rtpsv3vdepay->configured)) { - /* store data in adapter, stip off 2 bytes header */ - outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); - gst_adapter_push (rtpsv3vdepay->adapter, outbuf); + /* CodecData needs to be 'SEQH' + len (32bit) + data according to + * ffmpeg's libavcodec/svq3.c:svq3_decode_init */ + codec_data = gst_buffer_new_and_alloc (payload_len + 6); + memcpy (GST_BUFFER_DATA (codec_data), "SEQH", 4); + GST_WRITE_UINT32_LE (GST_BUFFER_DATA (codec_data) + 4, payload_len - 2); + memcpy (GST_BUFFER_DATA (codec_data) + 8, payload + 2, payload_len - 2); - if (M) { - /* frame is completed: push contents of adapter */ - guint avail; + GST_MEMDUMP ("codec_data", GST_BUFFER_DATA (codec_data), + GST_BUFFER_SIZE (codec_data)); - avail = gst_adapter_available (rtpsv3vdepay->adapter); - outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail); + caps = gst_caps_new_simple ("video/x-svq", + "svqversion", G_TYPE_INT, 3, + "width", G_TYPE_INT, rtpsv3vdepay->width, + "height", G_TYPE_INT, rtpsv3vdepay->height, + "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); + gst_caps_unref (caps); - return outbuf; - } + GST_DEBUG ("Depayloader now configured"); + + rtpsv3vdepay->configured = TRUE; + + goto beach; + } + + if (G_LIKELY (rtpsv3vdepay->configured)) { + GstBuffer *tmpbuf; + + GST_DEBUG ("Storing incoming payload"); + /* store data in adapter, stip off 2 bytes header */ + tmpbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); + gst_adapter_push (rtpsv3vdepay->adapter, tmpbuf); + + if (G_UNLIKELY (M)) { + /* frame is completed: push contents of adapter */ + guint avail; + + avail = gst_adapter_available (rtpsv3vdepay->adapter); + GST_DEBUG ("Returning completed output buffer [%d bytes]", avail); + outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail); } } - return NULL; + +beach: + return outbuf; /* ERRORS */ bad_packet: -- cgit