summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--gst/matroska/matroska-demux.c147
-rw-r--r--gst/matroska/matroska-ids.h14
3 files changed, 141 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 51d9fddc..37066f96 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2008-06-19 Sebastian Dröge <slomo@circular-chaos.org>
+ * gst/matroska/matroska-demux.c: (gst_matroska_track_free),
+ (gst_matroska_demux_add_mpeg_seq_header),
+ (gst_matroska_demux_add_wvpk_header),
+ (gst_matroska_demux_check_subtitle_buffer),
+ (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+ (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps),
+ (gst_matroska_demux_subtitle_caps):
+ * gst/matroska/matroska-ids.h:
+ Add a "vfunc" to the track context for postprocessing frames and
+ convert the wavpack and subtitle postprocessing to this vfunc.
+ Copy buffer flags in those functions to the new buffers too.
+
+ Parse CodecState elements of Blocks.
+
+ Add a postprocessing function for MPEG video that adds the sequence
+ header from the codec private data or codec state to the frames if
+ it's not already there.
+
+2008-06-19 Sebastian Dröge <slomo@circular-chaos.org>
+
* gst/matroska/matroska-demux.c:
(gst_matroska_demux_parse_blockgroup_or_simpleblock):
If a gap of more than 1/2 second is found in one stream send a
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index f73715f1..a09dc89c 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -219,6 +219,7 @@ gst_matroska_track_free (GstMatroskaTrackContext * track)
g_free (track->name);
g_free (track->language);
g_free (track->codec_priv);
+ g_free (track->codec_state);
if (track->encodings != NULL) {
int i;
@@ -3248,20 +3249,72 @@ gst_matroska_demux_push_dvd_clut_change_event (GstMatroskaDemux * demux,
g_free (buf);
}
-static gboolean
-gst_matroska_demux_stream_is_wavpack (GstMatroskaTrackContext * stream)
+static GstFlowReturn
+gst_matroska_demux_add_mpeg_seq_header (GstElement * element,
+ GstMatroskaTrackContext * stream, GstBuffer ** buf)
{
- if (stream->type == GST_MATROSKA_TRACK_TYPE_AUDIO) {
- return (strcmp (stream->codec_id,
- GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4) == 0);
+ GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
+ guint8 *seq_header;
+
+ guint seq_header_len;
+
+ guint32 header;
+
+ if (stream->codec_state) {
+ seq_header = stream->codec_state;
+ seq_header_len = stream->codec_state_size;
+ } else if (stream->codec_priv) {
+ seq_header = stream->codec_priv;
+ seq_header_len = stream->codec_priv_size;
+ } else {
+ return GST_FLOW_OK;
}
- return FALSE;
+
+ /* Sequence header only needed for keyframes */
+ if (GST_BUFFER_FLAG_IS_SET (*buf, GST_BUFFER_FLAG_DELTA_UNIT))
+ return GST_FLOW_OK;
+
+ if (GST_BUFFER_SIZE (*buf) < 4)
+ return GST_FLOW_OK;
+
+ header = GST_READ_UINT32_BE (GST_BUFFER_DATA (*buf));
+ /* Sequence start code, if not found prepend */
+ if (header != 0x000001b3) {
+ GstBuffer *newbuf;
+
+ GstFlowReturn ret, cret;
+
+ ret = gst_pad_alloc_buffer_and_set_caps (stream->pad,
+ GST_BUFFER_OFFSET_NONE, GST_BUFFER_SIZE (*buf) + seq_header_len,
+ stream->caps, &newbuf);
+ cret = gst_matroska_demux_combine_flows (demux, stream, ret);
+ if (ret != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (demux, "Reallocating buffer for sequence header "
+ "failed: %s, combined flow return: %s", gst_flow_get_name (ret),
+ gst_flow_get_name (cret));
+ return cret;
+ }
+
+ GST_DEBUG_OBJECT (demux, "Prepending MPEG sequence header");
+ gst_buffer_copy_metadata (newbuf, *buf, GST_BUFFER_COPY_TIMESTAMPS |
+ GST_BUFFER_COPY_FLAGS);
+ g_memmove (GST_BUFFER_DATA (newbuf), seq_header, seq_header_len);
+ g_memmove (GST_BUFFER_DATA (newbuf) + seq_header_len,
+ GST_BUFFER_DATA (*buf), GST_BUFFER_SIZE (*buf));
+ gst_buffer_unref (*buf);
+ *buf = newbuf;
+ }
+
+ return GST_FLOW_OK;
}
static GstFlowReturn
-gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
- GstMatroskaTrackContext * stream, gint block_length, GstBuffer ** buf)
+gst_matroska_demux_add_wvpk_header (GstElement * element,
+ GstMatroskaTrackContext * stream, GstBuffer ** buf)
{
+ GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
GstBuffer *newbuf;
guint8 *data;
@@ -3283,7 +3336,7 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
/* -20 because ck_size is the size of the wavpack block -8
* and lace_size is the size of the wavpack block + 12
* (the three guint32 of the header that already are in the buffer) */
- wvh.ck_size = block_length + sizeof (Wavpack4Header) - 20;
+ wvh.ck_size = GST_BUFFER_SIZE (*buf) + sizeof (Wavpack4Header) - 20;
wvh.version = GST_READ_UINT16_LE (stream->codec_priv);
wvh.track_no = 0;
wvh.index_no = 0;
@@ -3291,7 +3344,7 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
wvh.block_index = 0;
/* block_samples, flags and crc are already in the buffer */
- newlen = block_length + sizeof (Wavpack4Header) - 12;
+ newlen = GST_BUFFER_SIZE (*buf) + sizeof (Wavpack4Header) - 12;
ret = gst_pad_alloc_buffer_and_set_caps (stream->pad, GST_BUFFER_OFFSET_NONE,
newlen, stream->caps, &newbuf);
cret = gst_matroska_demux_combine_flows (demux, stream, ret);
@@ -3312,18 +3365,21 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaDemux * demux,
GST_WRITE_UINT8 (data + 11, wvh.index_no);
GST_WRITE_UINT32_LE (data + 12, wvh.total_samples);
GST_WRITE_UINT32_LE (data + 16, wvh.block_index);
- g_memmove (data + 20, GST_BUFFER_DATA (*buf), block_length);
- gst_buffer_copy_metadata (newbuf, *buf, GST_BUFFER_COPY_TIMESTAMPS);
+ g_memmove (data + 20, GST_BUFFER_DATA (*buf), GST_BUFFER_SIZE (*buf));
+ gst_buffer_copy_metadata (newbuf, *buf,
+ GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
gst_buffer_unref (*buf);
*buf = newbuf;
return cret;
}
-static GstBuffer *
-gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
- GstMatroskaTrackContext * stream, GstBuffer * buf)
+static GstFlowReturn
+gst_matroska_demux_check_subtitle_buffer (GstElement * element,
+ GstMatroskaTrackContext * stream, GstBuffer ** buf)
{
+ GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
+
GstMatroskaTrackSubtitleContext *sub_stream;
const gchar *encoding, *data;
@@ -3338,15 +3394,12 @@ gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
sub_stream = (GstMatroskaTrackSubtitleContext *) stream;
- if (!sub_stream->check_utf8)
- return buf;
-
- data = (const gchar *) GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
+ data = (const gchar *) GST_BUFFER_DATA (*buf);
+ size = GST_BUFFER_SIZE (*buf);
if (!sub_stream->invalid_utf8) {
if (g_utf8_validate (data, size, NULL)) {
- return buf;
+ return GST_FLOW_OK;
}
GST_WARNING_OBJECT (demux, "subtitle stream %d is not valid UTF-8, this "
"is broken according to the matroska specification", stream->num);
@@ -3388,10 +3441,12 @@ gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
GST_BUFFER_MALLOCDATA (newbuf) = (guint8 *) utf8;
GST_BUFFER_DATA (newbuf) = (guint8 *) utf8;
GST_BUFFER_SIZE (newbuf) = strlen (utf8);
- gst_buffer_copy_metadata (newbuf, buf, GST_BUFFER_COPY_TIMESTAMPS);
+ gst_buffer_copy_metadata (newbuf, *buf,
+ GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
gst_buffer_unref (buf);
- return newbuf;
+ *buf = newbuf;
+ return GST_FLOW_OK;
}
static GstBuffer *
@@ -3709,6 +3764,25 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
break;
}
+ case GST_MATROSKA_ID_CODECSTATE:{
+ guint8 *data;
+
+ guint64 data_len = 0;
+
+ if ((ret =
+ gst_ebml_read_binary (ebml, &id, &data,
+ &data_len)) != GST_FLOW_OK)
+ break;
+
+ g_free (stream->codec_state);
+ stream->codec_state = data;
+ stream->codec_state_size = data_len;
+ /* TODO: decompress/decrypt if necessary */
+ GST_DEBUG_OBJECT (demux, "CodecState of %u bytes",
+ stream->codec_state_size);
+ break;
+ }
+
default:
GST_WARNING_OBJECT (demux,
"Unknown BlockGroup subelement 0x%x - ignoring", id);
@@ -3718,7 +3792,6 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
case GST_MATROSKA_ID_BLOCKADDITIONS:
case GST_MATROSKA_ID_REFERENCEPRIORITY:
case GST_MATROSKA_ID_REFERENCEVIRTUAL:
- case GST_MATROSKA_ID_CODECSTATE:
case GST_MATROSKA_ID_SLICES:
ret = gst_ebml_read_skip (ebml);
break;
@@ -3802,11 +3875,6 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
gst_matroska_demux_sync_streams (demux);
- if (gst_matroska_demux_stream_is_wavpack (stream)) {
- ret =
- gst_matroska_demux_add_wvpk_header (demux, stream, lace_size[n],
- &sub);
- }
if (duration) {
GST_BUFFER_DURATION (sub) = duration / laces;
@@ -3848,9 +3916,9 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
gst_buffer_set_caps (sub, GST_PAD_CAPS (stream->pad));
- /* Fix up broken files with subtitles that are not UTF8 */
- if (stream->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
- sub = gst_matroska_demux_check_subtitle_buffer (demux, stream, sub);
+ /* Postprocess the buffers depending on the codec used */
+ if (stream->postprocess_frame) {
+ ret = stream->postprocess_frame (GST_ELEMENT (demux), stream, &sub);
}
ret = gst_pad_push (stream->pad, sub);
@@ -4639,6 +4707,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
"systemstream", G_TYPE_BOOLEAN, FALSE,
"mpegversion", G_TYPE_INT, mpegversion, NULL);
*codec_name = g_strdup_printf ("MPEG-%d video", mpegversion);
+ context->postprocess_frame = gst_matroska_demux_add_mpeg_seq_header;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_MJPEG)) {
caps = gst_caps_new_simple ("image/jpeg", NULL);
*codec_name = g_strdup ("Motion-JPEG");
@@ -4996,6 +5065,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
"width", G_TYPE_INT, audiocontext->bitdepth,
"framed", G_TYPE_BOOLEAN, TRUE, NULL);
*codec_name = g_strdup ("Wavpack audio");
+ context->postprocess_frame = gst_matroska_demux_add_wvpk_header;
} else if ((!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4)) ||
(!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4)) ||
(!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK))) {
@@ -5047,6 +5117,9 @@ gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
{
GstCaps *caps = NULL;
+ GstMatroskaTrackContext *context =
+ (GstMatroskaTrackContext *) subtitlecontext;
+
/* for backwards compatibility */
if (!g_ascii_strcasecmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASCII))
codec_id = GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8;
@@ -5061,24 +5134,22 @@ gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
* Check if we have to do something with codec_private */
if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8)) {
caps = gst_caps_new_simple ("text/plain", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA)) {
caps = gst_caps_new_simple ("application/x-ssa", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS)) {
caps = gst_caps_new_simple ("application/x-ass", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_USF)) {
caps = gst_caps_new_simple ("application/x-usf", NULL);
- subtitlecontext->check_utf8 = TRUE;
+ context->postprocess_frame = gst_matroska_demux_check_subtitle_buffer;
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB)) {
caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
((GstMatroskaTrackContext *) subtitlecontext)->send_dvd_event = TRUE;
- subtitlecontext->check_utf8 = FALSE;
} else {
GST_DEBUG ("Unknown subtitle stream: codec_id='%s'", codec_id);
caps = gst_caps_new_simple ("application/x-subtitle-unknown", NULL);
- subtitlecontext->check_utf8 = FALSE;
}
if (data != NULL && size > 0) {
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index 6ad20607..fcf6e60d 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -452,8 +452,11 @@ typedef enum {
GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0)
} GstMatroskaVideoTrackFlags;
+
+typedef struct _GstMatroskaTrackContext GstMatroskaTrackContext;
+
/* TODO: check if all fields are used */
-typedef struct _GstMatroskaTrackContext {
+struct _GstMatroskaTrackContext {
GstPad *pad;
GstCaps *caps;
guint index;
@@ -463,6 +466,8 @@ typedef struct _GstMatroskaTrackContext {
gchar *codec_id, *codec_name, *name, *language;
gpointer codec_priv;
guint codec_priv_size;
+ gpointer codec_state;
+ guint codec_state_size;
GstMatroskaTrackType type;
guint uid, num;
GstMatroskaTrackFlags flags;
@@ -491,13 +496,18 @@ typedef struct _GstMatroskaTrackContext {
* they are put into codec private data, not muxed into the stream */
guint xiph_headers_to_skip;
+ /* Used for postprocessing a frame before it is pushed from the demuxer */
+ GstFlowReturn (*postprocess_frame) (GstElement *element,
+ GstMatroskaTrackContext *context,
+ GstBuffer **buffer);
+
/* Tags to send after newsegment event */
GstTagList *pending_tags;
/* A GArray of GstMatroskaTrackEncoding structures which contain the
* encoding (compression/encryption) settings for this track, if any */
GArray *encodings;
-} GstMatroskaTrackContext;
+};
typedef struct _GstMatroskaTrackVideoContext {
GstMatroskaTrackContext parent;