summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--gst/real/gstrealaudiodec.c58
-rw-r--r--gst/real/gstrealvideodec.c422
3 files changed, 116 insertions, 374 deletions
diff --git a/ChangeLog b/ChangeLog
index 430b37c7..cdaf56eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2007-08-07 Wim Taymans <wim.taymans@gmail.com>
+
+ * gst/real/gstrealaudiodec.c: (gst_real_audio_dec_setcaps):
+ Small cleanups.
+
+ * gst/real/gstrealvideodec.c: (gst_real_video_dec_chain),
+ (open_library):
+ Remove fragment and timestamp correction code from the decoder to make
+ the caps and buffer contents compatible with matroska/ffdec_rvx0/...
+
2007-07-30 Tim-Philipp Müller <tim at centricular dot net>
* po/POTFILES.skip:
diff --git a/gst/real/gstrealaudiodec.c b/gst/real/gstrealaudiodec.c
index 9427ea2e..1045e11f 100644
--- a/gst/real/gstrealaudiodec.c
+++ b/gst/real/gstrealaudiodec.c
@@ -354,36 +354,48 @@ codec_search_done:
return TRUE;
missing_keys:
- GST_DEBUG_OBJECT (dec, "Could not find all necessary keys in structure.");
- return FALSE;
+ {
+ GST_DEBUG_OBJECT (dec, "Could not find all necessary keys in structure.");
+ return FALSE;
+ }
unknown_version:
- GST_DEBUG_OBJECT (dec, "Cannot handle version %i.", version);
- return FALSE;
+ {
+ GST_DEBUG_OBJECT (dec, "Cannot handle version %i.", version);
+ return FALSE;
+ }
could_not_open:
- g_strfreev (split_path);
- GST_DEBUG_OBJECT (dec, "Could not find library '%s' in '%s'", names, path);
- return FALSE;
+ {
+ g_strfreev (split_path);
+ GST_DEBUG_OBJECT (dec, "Could not find library '%s' in '%s'", names, path);
+ return FALSE;
+ }
could_not_load:
- g_module_close (module);
- g_strfreev (split_path);
- GST_DEBUG_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
- return FALSE;
+ {
+ g_module_close (module);
+ g_strfreev (split_path);
+ GST_DEBUG_OBJECT (dec, "Could not load all symbols: %s", g_module_error ());
+ return FALSE;
+ }
could_not_initialize:
- if (context) {
- funcs.RACloseCodec (context);
- funcs.RAFreeDecoder (context);
+ {
+ if (context) {
+ funcs.RACloseCodec (context);
+ funcs.RAFreeDecoder (context);
+ }
+ g_module_close (module);
+ GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
+ return FALSE;
}
- g_module_close (module);
- GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
- return FALSE;
could_not_set_caps:
- if (context) {
- funcs.RACloseCodec (context);
- funcs.RAFreeDecoder (context);
+ {
+ if (context) {
+ funcs.RACloseCodec (context);
+ funcs.RAFreeDecoder (context);
+ }
+ g_module_close (module);
+ GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps.");
+ return FALSE;
}
- g_module_close (module);
- GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps.");
- return FALSE;
}
static void
diff --git a/gst/real/gstrealvideodec.c b/gst/real/gstrealvideodec.c
index 2678e699..076918fb 100644
--- a/gst/real/gstrealvideodec.c
+++ b/gst/real/gstrealvideodec.c
@@ -87,345 +87,110 @@ typedef struct
} RVOutData;
static GstFlowReturn
-gst_real_video_dec_alloc_buffer (GstRealVideoDec * dec, GstClockTime timestamp,
- GstBuffer ** buf)
+gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
{
+ GstRealVideoDec *dec;
+ guint8 *data;
+ guint size;
GstFlowReturn ret;
- const guint8 *b;
- guint8 frame_type;
- guint16 seq;
- GstClockTime ts = timestamp;
+ RVInData tin;
+ RVOutData tout;
+ GstClockTime timestamp, duration;
+ GstBuffer *out;
+ guint32 result;
+ guint frag_count;
- GST_LOG_OBJECT (dec, "timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+ dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
- /* Fix timestamp. */
- b = gst_adapter_peek (dec->adapter, 4);
- switch (dec->version) {
- case GST_REAL_VIDEO_DEC_VERSION_2:
- {
+ if (G_UNLIKELY (dec->hooks.transform == NULL || dec->hooks.module == NULL))
+ goto not_negotiated;
- /*
- * Bit 1- 2: frame type
- * Bit 3- 9: ?
- * Bit 10-22: sequence number
- * Bit 23-32: ?
- */
- frame_type = (b[0] >> 6) & 0x03;
- seq = ((b[1] & 0x7f) << 6) + ((b[2] & 0xfc) >> 2);
- break;
- }
- case GST_REAL_VIDEO_DEC_VERSION_3:
- {
- /*
- * Bit 1- 2: ?
- * Bit 3: skip packet if 1
- * Bit 4- 5: frame type
- * Bit 6-12: ?
- * Bit 13-25: sequence number
- * Bit 26-32: ?
- */
- frame_type = (b[0] >> 3) & 0x03;
- seq = ((b[1] & 0x0f) << 9) + (b[2] << 1) + ((b[3] & 0x80) >> 7);
- break;
- }
- case GST_REAL_VIDEO_DEC_VERSION_4:
- {
- /*
- * Bit 1: skip packet if 1
- * Bit 2- 3: frame type
- * Bit 4-13: ?
- * Bit 14-26: sequence number
- * Bit 27-32: ?
- */
- frame_type = (b[0] >> 5) & 0x03;
- seq = ((b[1] & 0x07) << 10) + (b[2] << 2) + ((b[3] & 0xc0) >> 6);
- break;
- }
- default:
- goto unknown_version;
- }
+ data = GST_BUFFER_DATA (in);
+ size = GST_BUFFER_SIZE (in);
+ timestamp = GST_BUFFER_TIMESTAMP (in);
+ duration = GST_BUFFER_DURATION (in);
- GST_LOG_OBJECT (dec, "frame_type:%d", frame_type);
+ /* alloc output buffer */
+ ret = gst_pad_alloc_buffer (dec->src, GST_BUFFER_OFFSET_NONE,
+ dec->width * dec->height * 3 / 2, GST_PAD_CAPS (dec->src), &out);
+ if (ret != GST_FLOW_OK)
+ goto alloc_failed;
- switch (frame_type) {
- case 0:
- case 1:
- {
- /* I frame */
- timestamp = dec->next_ts;
- dec->last_ts = dec->next_ts;
- dec->next_ts = ts;
- dec->last_seq = dec->next_seq;
- dec->next_seq = seq;
+ GST_BUFFER_TIMESTAMP (out) = timestamp;
+ GST_BUFFER_DURATION (out) = duration;
- break;
- }
- case 2:
- {
- /* P frame */
- timestamp = dec->last_ts = dec->next_ts;
- if (seq < dec->next_seq)
- dec->next_ts += (seq + 0x2000 - dec->next_seq) * GST_MSECOND;
- else
- dec->next_ts += (seq - dec->next_seq) * GST_MSECOND;
- dec->last_seq = dec->next_seq;
- dec->next_seq = seq;
- break;
- }
- case 3:
- {
- /* B frame */
- if (seq < dec->last_seq) {
- timestamp = (seq + 0x2000 - dec->last_seq) * GST_MSECOND + dec->last_ts;
- } else {
- timestamp = (seq - dec->last_seq) * GST_MSECOND + dec->last_ts;
- }
+ frag_count = *data++;
- break;
- }
- default:
- goto unknown_frame_type;
- }
+ /* Decode */
+ tin.datalen = size;
+ tin.interpolate = 0;
+ tin.nfragments = frag_count;
+ tin.fragments = data;
+ tin.flags = 0;
+ tin.timestamp = timestamp;
- ret = gst_pad_alloc_buffer (dec->src, GST_BUFFER_OFFSET_NONE,
- dec->width * dec->height * 3 / 2, GST_PAD_CAPS (dec->src), buf);
+ /* jump over the frag table to the fragments */
+ data += (frag_count + 1) * 8;
- if (ret == GST_FLOW_OK)
- GST_BUFFER_TIMESTAMP (*buf) = timestamp;
+ result = dec->hooks.transform (
+ (gchar *) data,
+ (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->hooks.context);
+ if (result)
+ goto could_not_transform;
- return ret;
+ gst_buffer_unref (in);
- /* Errors */
-unknown_version:
- {
- GST_ELEMENT_ERROR (dec, STREAM, DECODE,
- ("Unknown version: %i.", dec->version), (NULL));
- return GST_FLOW_ERROR;
- }
+ /* Check for new dimensions */
+ if (tout.frames && ((dec->width != tout.width)
+ || (dec->height != tout.height))) {
+ GstCaps *caps = gst_caps_copy (GST_PAD_CAPS (dec->src));
+ GstStructure *s = gst_caps_get_structure (caps, 0);
-unknown_frame_type:
- {
- GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Unknown frame type."), (NULL));
- return GST_FLOW_ERROR;
- }
-}
+ GST_DEBUG_OBJECT (dec, "New dimensions: %"
+ G_GUINT32_FORMAT " x %" G_GUINT32_FORMAT, tout.width, tout.height);
-static GstFlowReturn
-gst_real_video_dec_decode (GstRealVideoDec * dec, GstBuffer * in, guint offset)
-{
- guint32 result;
- GstBuffer *out = NULL;
- GstFlowReturn ret;
- guint8 *data, hdr_subseq, hdr_seqnum;
- guint32 hdr_offset, hdr_length;
- guint16 n;
- gboolean bres;
- guint8 *buf = GST_BUFFER_DATA (in) + offset;
- guint len = GST_BUFFER_SIZE (in) - offset;
- GstClockTime timestamp = GST_BUFFER_TIMESTAMP (in);
-
- GST_LOG_OBJECT (dec,
- "Got buffer %p with timestamp %" GST_TIME_FORMAT " offset %d", in,
- GST_TIME_ARGS (timestamp), offset);
-
- /* Subsequence */
- if (len < 1)
- goto not_enough_data;
- if (*buf != 0x40 && *buf != 0x41 && *buf != 0x42 &&
- *buf != 0x43 && *buf != 0x44 && *buf != 0x45) {
- hdr_subseq = *buf & 0x7f;
- buf++;
- len--;
- if (hdr_subseq == 64)
- hdr_subseq = 1;
- } else {
- hdr_subseq = 1;
- }
+ gst_structure_set (s, "width", G_TYPE_LONG, tout.width,
+ "height", G_TYPE_LONG, tout.height, NULL);
- /* Length */
- if (len < 2)
- goto not_enough_data;
- hdr_length = GST_READ_UINT16_BE (buf);
- if (!(hdr_length & 0xc000)) {
- if (len < 4)
- goto not_enough_data;
- hdr_length = GST_READ_UINT32_BE (buf);
- buf += 4;
- len -= 4;
- } else {
- hdr_length &= 0x3fff;
- buf += 2;
- len -= 2;
- }
+ gst_pad_set_caps (dec->src, caps);
+ gst_buffer_set_caps (out, caps);
+ gst_caps_unref (caps);
- /* Offset */
- if (len < 2)
- goto not_enough_data;
- hdr_offset = GST_READ_UINT16_BE (buf);
- if (!(hdr_offset & 0xc000)) {
- if (len < 4)
- goto not_enough_data;
- hdr_offset = GST_READ_UINT32_BE (buf);
- buf += 4;
- len -= 4;
- } else {
- hdr_offset &= 0x3fff;
- buf += 2;
- len -= 2;
+ dec->width = tout.width;
+ dec->height = tout.height;
}
- /* Sequence number */
- if (len < 1)
- goto not_enough_data;
- hdr_seqnum = *buf;
- buf++;
- len--;
- if (len < 1)
- goto not_enough_data;
-
- /* Verify the sequence numbers. */
- if (hdr_subseq == 1) {
- n = gst_adapter_available_fast (dec->adapter);
- if (n > 0) {
- GST_DEBUG_OBJECT (dec, "Dropping data for sequence %i "
- "because we are already receiving data for sequence %i.",
- dec->seqnum, hdr_seqnum);
- gst_adapter_clear (dec->adapter);
- }
- dec->seqnum = hdr_seqnum;
- dec->length = hdr_length;
- dec->fragment_count = 1;
- } else {
- if (dec->seqnum != hdr_seqnum) {
- GST_DEBUG_OBJECT (dec, "Expected sequence %i, got sequence %i "
- "(subseq=%i). Dropping packet.", dec->seqnum, hdr_seqnum, hdr_subseq);
- return GST_FLOW_OK;
- } else if (dec->subseq + 1 != hdr_subseq) {
- GST_DEBUG_OBJECT (dec, "Expected subsequence %i, got subseqence %i. "
- "Dropping packet.", dec->subseq + 1, hdr_subseq);
- return GST_FLOW_OK;
- }
- dec->fragment_count++;
- }
- dec->subseq = hdr_subseq;
-
- /* Remember the offset */
- if (sizeof (dec->fragments) < 2 * (dec->fragment_count - 1) + 1)
- goto too_many_fragments;
- dec->fragments[2 * (dec->fragment_count - 1)] = 1;
- dec->fragments[2 * (dec->fragment_count - 1) + 1] =
- gst_adapter_available (dec->adapter);
-
- /* Some buffers need to be skipped. */
- if (((dec->version == GST_REAL_VIDEO_DEC_VERSION_3) && (*buf & 0x20)) ||
- ((dec->version == GST_REAL_VIDEO_DEC_VERSION_4) && (*buf & 0x80))) {
- dec->fragment_count--;
- dec->length -= len;
- } else {
- gst_adapter_push (dec->adapter,
- gst_buffer_create_sub (in, GST_BUFFER_SIZE (in) - len, len));
- }
-
- /* All bytes received? */
- n = gst_adapter_available (dec->adapter);
- GST_LOG_OBJECT (dec, "We know have %d bytes, and we need %d", n, dec->length);
- if (dec->length <= n) {
- RVInData tin;
- RVOutData tout;
-
- if ((ret =
- gst_real_video_dec_alloc_buffer (dec, timestamp,
- &out)) != GST_FLOW_OK)
- return ret;
-
- /* Decode */
- tin.datalen = dec->length;
- tin.interpolate = 0;
- tin.nfragments = dec->fragment_count - 1;
- tin.fragments = dec->fragments;
- tin.flags = 0;
- tin.timestamp = GST_BUFFER_TIMESTAMP (out);
- data = gst_adapter_take (dec->adapter, dec->length);
-
- result = dec->hooks.transform (
- (gchar *) data,
- (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->hooks.context);
-
- g_free (data);
- if (result)
- goto could_not_transform;
-
- /* Check for new dimensions */
- if (tout.frames && ((dec->width != tout.width)
- || (dec->height != tout.height))) {
- GstCaps *caps = gst_caps_copy (GST_PAD_CAPS (dec->src));
- GstStructure *s = gst_caps_get_structure (caps, 0);
-
- GST_DEBUG_OBJECT (dec, "New dimensions: %"
- G_GUINT32_FORMAT " x %" G_GUINT32_FORMAT, tout.width, tout.height);
- gst_structure_set (s, "width", G_TYPE_LONG, tout.width,
- "height", G_TYPE_LONG, tout.height, NULL);
- bres = gst_pad_set_caps (dec->src, caps);
- gst_caps_unref (caps);
- if (!bres)
- goto new_dimensions_failed;
- dec->width = tout.width;
- dec->height = tout.height;
- }
+ GST_DEBUG_OBJECT (dec,
+ "Pushing out buffer with timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));
- GST_DEBUG_OBJECT (dec,
- "Pushing out buffer with timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));
-
- if ((ret = gst_pad_push (dec->src, out)) != GST_FLOW_OK)
- goto could_not_push;
-
- n = gst_adapter_available (dec->adapter);
- if (n > 0) {
- GST_LOG_OBJECT (dec, "Data left in the adapter: %d", n);
- in = gst_adapter_take_buffer (dec->adapter, n);
- ret = gst_real_video_dec_decode (dec, in, 0);
- gst_buffer_unref (in);
- if (ret != GST_FLOW_OK)
- return ret;
- }
- }
+ if ((ret = gst_pad_push (dec->src, out)) != GST_FLOW_OK)
+ goto could_not_push;
- return GST_FLOW_OK;
+ return ret;
/* Errors */
-not_enough_data:
+not_negotiated:
{
- GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Not enough data."), (NULL));
- return GST_FLOW_ERROR;
+ GST_WARNING_OBJECT (dec, "decoder not open, probably no input caps set "
+ "yet, caps on input buffer: %" GST_PTR_FORMAT, GST_BUFFER_CAPS (in));
+ gst_buffer_unref (in);
+ return GST_FLOW_NOT_NEGOTIATED;
}
-
-too_many_fragments:
+alloc_failed:
{
+ GST_DEBUG_OBJECT (dec, "buffer alloc failed: %s", gst_flow_get_name (ret));
gst_buffer_unref (in);
- GST_ELEMENT_ERROR (dec, STREAM, DECODE,
- ("Got more fragments (%u) than can be handled (%u)",
- dec->fragment_count, (guint) G_N_ELEMENTS (dec->fragments)),
- (NULL));
- return GST_FLOW_ERROR;
+ return ret;
}
-
could_not_transform:
{
gst_buffer_unref (out);
+ gst_buffer_unref (in);
GST_ELEMENT_ERROR (dec, STREAM, DECODE,
("Could not decode buffer: %" G_GUINT32_FORMAT, result), (NULL));
return GST_FLOW_ERROR;
}
-
-new_dimensions_failed:
- {
- gst_buffer_unref (out);
- GST_ELEMENT_ERROR (dec, STREAM, DECODE,
- ("Could not set new dimensions."), (NULL));
- return GST_FLOW_ERROR;
- }
-
could_not_push:
{
GST_DEBUG_OBJECT (dec, "Could not push buffer: %s",
@@ -434,52 +199,6 @@ could_not_push:
}
}
-static GstFlowReturn
-gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
-{
- GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
- guint8 flags, *buf = GST_BUFFER_DATA (in);
- guint len = GST_BUFFER_SIZE (in);
- GstFlowReturn ret;
-
- if (G_UNLIKELY (dec->hooks.transform == NULL || dec->hooks.module == NULL))
- goto not_negotiated;
-
- /* Flags */
- if (len < 1)
- goto not_enough_data;
- flags = *buf;
- buf++;
- len--;
-
- if (flags == 0x40) {
- GST_DEBUG_OBJECT (dec, "Don't know how to handle buffer of type 0x40 "
- "(size=%i).", len);
- return GST_FLOW_OK;
- }
-
- ret = gst_real_video_dec_decode (dec, in, 1);
- gst_buffer_unref (in);
- if (ret != GST_FLOW_OK)
- return ret;
- return GST_FLOW_OK;
-
- /* Errors */
-not_enough_data:
- {
- GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Not enough data."), (NULL));
- gst_buffer_unref (in);
- return GST_FLOW_ERROR;
- }
-not_negotiated:
- {
- GST_WARNING_OBJECT (dec, "decoder not open, probably no input caps set "
- "yet, caps on input buffer: %" GST_PTR_FORMAT, GST_BUFFER_CAPS (in));
- gst_buffer_unref (in);
- return GST_FLOW_NOT_NEGOTIATED;
- }
-}
-
static gboolean
gst_real_video_dec_activate_push (GstPad * pad, gboolean active)
{
@@ -709,7 +428,8 @@ unknown_version:
could_not_open:
{
- GST_ERROR_OBJECT (dec, "Could not find library '%s' in '%s'", names, path);
+ GST_ERROR_OBJECT (dec, "Could not open library '%s' in '%s': %s", names,
+ path, g_module_error ());
return FALSE;
}