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: