summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Dröge <slomo@circular-chaos.org>2008-06-13 19:07:03 +0000
committerSebastian Dröge <slomo@circular-chaos.org>2008-06-13 19:07:03 +0000
commit04d1c49ef7c6fe497c4b1d9d67590952e0d1266a (patch)
tree0b4db2215cd8d55d263eaa21e886e1fe840760e5
parent764f5106a5c6fddbaeca142bc68441ca234295fb (diff)
gst/matroska/matroska-demux.*: Only parse Tracks, SeekHead and SegmentInfo elements once but allow
Original commit message from CVS: * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset), (gst_matroska_demux_parse_tracks), (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info), (gst_matroska_demux_parse_attachments), (gst_matroska_demux_parse_chapters), (gst_matroska_demux_parse_contents_seekentry), (gst_matroska_demux_loop_stream_parse_id): * gst/matroska/matroska-demux.h: Only parse Tracks, SeekHead and SegmentInfo elements once but allow Tags multiple times. The first ones can appear more than once but must contain the same content as the first for backup purposes so we ignore all but the first one. Tags can appear multiple times with different content. Jump to all elements except Clusters that are available from a SeekHead to make it more likely to have all required informations before getting to the first Clusters. Add dummy functions for parsing Attachments and Chapters.
-rw-r--r--ChangeLog22
-rw-r--r--gst/matroska/matroska-demux.c296
-rw-r--r--gst/matroska/matroska-demux.h5
3 files changed, 264 insertions, 59 deletions
diff --git a/ChangeLog b/ChangeLog
index 7929a211..2f1b33c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2008-06-13 Sebastian Dröge <slomo@circular-chaos.org>
+
+ * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
+ (gst_matroska_demux_parse_tracks),
+ (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_info),
+ (gst_matroska_demux_parse_attachments),
+ (gst_matroska_demux_parse_chapters),
+ (gst_matroska_demux_parse_contents_seekentry),
+ (gst_matroska_demux_loop_stream_parse_id):
+ * gst/matroska/matroska-demux.h:
+ Only parse Tracks, SeekHead and SegmentInfo elements once but allow
+ Tags multiple times. The first ones can appear more than once but must
+ contain the same content as the first for backup purposes so we ignore
+ all but the first one. Tags can appear multiple times with different
+ content.
+
+ Jump to all elements except Clusters that are available from a
+ SeekHead to make it more likely to have all required informations
+ before getting to the first Clusters.
+
+ Add dummy functions for parsing Attachments and Chapters.
+
2008-06-13 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init), (gst_udpsrc_init),
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index 1f1456fa..66a4938c 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -99,6 +99,9 @@ static GstStaticPadTemplate subtitle_src_templ =
"application/x-subtitle-unknown")
);
+static GstFlowReturn gst_matroska_demux_parse_contents (GstMatroskaDemux *
+ demux, gboolean * p_run_loop);
+
/* element functions */
static void gst_matroska_demux_loop (GstPad * pad);
@@ -306,8 +309,9 @@ gst_matroska_demux_reset (GstElement * element)
demux->time_scale = 1000000;
demux->created = G_MININT64;
- demux->metadata_parsed = FALSE;
demux->index_parsed = FALSE;
+ demux->tracks_parsed = FALSE;
+ demux->segmentinfo_parsed = FALSE;
gst_segment_init (&demux->segment, GST_FORMAT_TIME);
}
@@ -1807,6 +1811,8 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux)
}
}
+ demux->tracks_parsed = TRUE;
+
return ret;
}
@@ -2036,6 +2042,8 @@ gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos)
}
}
+ demux->index_parsed = TRUE;
+
return ret;
}
@@ -2148,6 +2156,8 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux)
}
}
+ demux->segmentinfo_parsed = TRUE;
+
return ret;
}
@@ -2388,6 +2398,107 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux,
return ret;
}
+static GstFlowReturn
+gst_matroska_demux_parse_attachments (GstMatroskaDemux * demux,
+ gboolean prevent_eos)
+{
+ GstEbmlRead *ebml = GST_EBML_READ (demux);
+
+ guint64 length = 0;
+
+ guint32 id;
+
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ GST_WARNING_OBJECT (demux, "Parsing of attachments not implemented yet");
+
+ /* TODO: implement parsing of attachments */
+
+ if (prevent_eos) {
+ length = gst_ebml_read_get_length (ebml);
+ }
+
+ while (ret == GST_FLOW_OK) {
+ /* We're an element that can be seeked to. If we are, then
+ * we want to prevent EOS, since that'll kill us. So we cache
+ * file size and seek until there, and don't call EOS upon os. */
+ if (prevent_eos && length == ebml->offset)
+ break;
+
+ if ((ret = gst_ebml_peek_id (ebml, &demux->level_up, &id)) != GST_FLOW_OK)
+ return ret;
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+
+ switch (id) {
+ default:
+ case GST_EBML_ID_VOID:
+ ret = gst_ebml_read_skip (ebml);
+ break;
+ }
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_matroska_demux_parse_chapters (GstMatroskaDemux * demux,
+ gboolean prevent_eos)
+{
+ GstEbmlRead *ebml = GST_EBML_READ (demux);
+
+ guint64 length = 0;
+
+ guint32 id;
+
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ GST_WARNING_OBJECT (demux, "Parsing of chapters not implemented yet");
+
+ /* TODO: implement parsing of chapters */
+ if (prevent_eos) {
+ length = gst_ebml_read_get_length (ebml);
+ }
+
+ while (ret == GST_FLOW_OK) {
+ /* We're an element that can be seeked to. If we are, then
+ * we want to prevent EOS, since that'll kill us. So we cache
+ * file size and seek until there, and don't call EOS upon os. */
+ if (prevent_eos && length == ebml->offset)
+ break;
+
+ if ((ret = gst_ebml_peek_id (ebml, &demux->level_up, &id)) != GST_FLOW_OK)
+ return ret;
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+
+ switch (id) {
+ default:
+ case GST_EBML_ID_VOID:
+ ret = gst_ebml_read_skip (ebml);
+ break;
+ }
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+ }
+
+ return ret;
+}
+
/*
* Read signed/unsigned "EBML" numbers.
* Return: number of bytes processed.
@@ -3434,11 +3545,14 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
return GST_FLOW_OK;
}
- /* FIXME: Do this for the other elements except CLUSTERS too.
- * We can't know that they will come before the CLUSTERS */
switch (seek_id) {
case GST_MATROSKA_ID_CUES:
case GST_MATROSKA_ID_TAGS:
+ case GST_MATROSKA_ID_TRACKS:
+ case GST_MATROSKA_ID_SEEKHEAD:
+ case GST_MATROSKA_ID_SEGMENTINFO:
+ case GST_MATROSKA_ID_ATTACHMENTS:
+ case GST_MATROSKA_ID_CHAPTERS:
{
guint level_up = demux->level_up;
@@ -3485,29 +3599,93 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
/* read master + parse */
switch (id) {
case GST_MATROSKA_ID_CUES:
+ if (!demux->index_parsed) {
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret =
+ gst_matroska_demux_parse_index (demux,
+ TRUE)) != GST_FLOW_OK)
+ return ret;
+ }
+ if (gst_ebml_read_get_length (ebml) == ebml->offset)
+ *p_run_loop = FALSE;
+ break;
+ case GST_MATROSKA_ID_TAGS:
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
return ret;
if ((ret =
- gst_matroska_demux_parse_index (demux, TRUE)) != GST_FLOW_OK)
+ gst_matroska_demux_parse_metadata (demux,
+ TRUE)) != GST_FLOW_OK)
return ret;
- /* FIXME: why is this here? */
if (gst_ebml_read_get_length (ebml) == ebml->offset)
*p_run_loop = FALSE;
- else
- demux->index_parsed = TRUE;
break;
- case GST_MATROSKA_ID_TAGS:
+ case GST_MATROSKA_ID_TRACKS:
+ if (!demux->tracks_parsed) {
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret = gst_matroska_demux_parse_tracks (demux)) != GST_FLOW_OK)
+ return ret;
+ }
+ if (gst_ebml_read_get_length (ebml) == ebml->offset)
+ *p_run_loop = FALSE;
+ break;
+
+ case GST_MATROSKA_ID_SEGMENTINFO:
+ if (!demux->segmentinfo_parsed) {
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret = gst_matroska_demux_parse_info (demux)) != GST_FLOW_OK)
+ return ret;
+ }
+ if (gst_ebml_read_get_length (ebml) == ebml->offset)
+ *p_run_loop = FALSE;
+ break;
+ case GST_MATROSKA_ID_SEEKHEAD:
+ {
+ GList *l;
+
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
return ret;
+
+ /* Prevent infinite recursion if there's a cycle from
+ * one seekhead to the same again. Simply break if
+ * we already had this seekhead, finish will clean up
+ * everything. */
+ for (l = ebml->level; l; l = l->next) {
+ GstEbmlLevel *level = (GstEbmlLevel *) l->data;
+
+ if (level->start == ebml->offset && l->next)
+ goto finish;
+ }
+
if ((ret =
- gst_matroska_demux_parse_metadata (demux,
+ gst_matroska_demux_parse_contents (demux,
+ p_run_loop)) != GST_FLOW_OK)
+ return ret;
+ if (gst_ebml_read_get_length (ebml) == ebml->offset)
+ *p_run_loop = FALSE;
+ break;
+ }
+ case GST_MATROSKA_ID_ATTACHMENTS:
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret =
+ gst_matroska_demux_parse_attachments (demux,
+ TRUE)) != GST_FLOW_OK)
+ return ret;
+ if (gst_ebml_read_get_length (ebml) == ebml->offset)
+ *p_run_loop = FALSE;
+ break;
+ case GST_MATROSKA_ID_CHAPTERS:
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret =
+ gst_matroska_demux_parse_chapters (demux,
TRUE)) != GST_FLOW_OK)
return ret;
- /* FIXME: why is this here? */
if (gst_ebml_read_get_length (ebml) == ebml->offset)
*p_run_loop = FALSE;
- else
- demux->metadata_parsed = TRUE;
break;
}
@@ -3596,32 +3774,41 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux,
GstFlowReturn ret;
switch (id) {
- /* FIXME: not mandatory... will things break?
- * Can only happen exactly once, ignore second
- * occurences! */
- /* stream info */
+ /* stream info
+ * Can exist more than once but following occurences
+ * must have the same content so ignore them */
case GST_MATROSKA_ID_SEGMENTINFO:
- if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
- return ret;
- if ((ret = gst_matroska_demux_parse_info (demux)) != GST_FLOW_OK)
- return ret;
+ if (!demux->segmentinfo_parsed) {
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret = gst_matroska_demux_parse_info (demux)) != GST_FLOW_OK)
+ return ret;
+ } else {
+ if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
+ return ret;
+ }
break;
- /* FIXME: might happen more than once, second
- * occurences must be exactly the same so drop them */
- /* track info headers */
+ /* track info headers
+ * Can exist more than once but following occurences
+ * must have the same content so ignore them */
case GST_MATROSKA_ID_TRACKS:
{
- if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
- return ret;
- if ((ret = gst_matroska_demux_parse_tracks (demux)) != GST_FLOW_OK)
- return ret;
+ if (!demux->tracks_parsed) {
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret = gst_matroska_demux_parse_tracks (demux)) != GST_FLOW_OK)
+ return ret;
+ } else {
+ if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
+ return ret;
+ }
break;
}
- /* FIXME: can only happen once or never but
- * for the sake of sanity ignore second occurences */
- /* stream index */
+ /* cues - seek table
+ * Either exists exactly one time or never but ignore
+ * following occurences for the sake of sanity */
case GST_MATROSKA_ID_CUES:
{
if (!demux->index_parsed) {
@@ -3637,28 +3824,19 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux,
break;
}
- /* FIXME: can be there more than once, why do we have
- * ->metadata_parsed? */
- /* metadata */
+ /* metadata
+ * can exist more than one time with different content */
case GST_MATROSKA_ID_TAGS:
{
- if (!demux->metadata_parsed) {
- if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
- return ret;
- if ((ret =
- gst_matroska_demux_parse_metadata (demux,
- FALSE)) != GST_FLOW_OK)
- return ret;
- } else {
- if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
- return ret;
- }
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret =
+ gst_matroska_demux_parse_metadata (demux, FALSE)) != GST_FLOW_OK)
+ return ret;
break;
}
- /* FIXME: must not be there but can happen more than once with
- * different content */
- /* file index (if seekable, seek to Cues/Tags to parse it) */
+ /* file index (if seekable, seek to Cues/Tags/etc to parse it) */
case GST_MATROSKA_ID_SEEKHEAD:
{
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
@@ -3670,7 +3848,7 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux,
break;
}
- /* FIXME: must not be there */
+ /* cluster - contains the payload */
case GST_MATROSKA_ID_CLUSTER:
{
if (demux->state != GST_MATROSKA_DEMUX_STATE_DATA) {
@@ -3704,21 +3882,25 @@ gst_matroska_demux_loop_stream_parse_id (GstMatroskaDemux * demux,
break;
}
- /* TODO: Implement parsing of attachments and push them
- * through an attachment pad, one for each attachment */
- /* FIXME: must not be there but can only be once */
+ /* attachments - contains files attached to the mkv container
+ * like album art, etc */
case GST_MATROSKA_ID_ATTACHMENTS:{
- GST_INFO ("Attachments elements are not supported yet");
- if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret =
+ gst_matroska_demux_parse_attachments (demux,
+ FALSE)) != GST_FLOW_OK)
return ret;
break;
}
- /* TODO: Implement parsing of chapters */
- /* FIXME: Must not be there but can only be once */
+ /* chapters - contains meta information about how to group
+ * the file into chapters, similar to DVD */
case GST_MATROSKA_ID_CHAPTERS:{
- GST_INFO ("Chapters elements are not supported yet");
- if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
+ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
+ return ret;
+ if ((ret =
+ gst_matroska_demux_parse_chapters (demux, FALSE)) != GST_FLOW_OK)
return ret;
break;
}
diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h
index 9da56603..413cdc8a 100644
--- a/gst/matroska/matroska-demux.h
+++ b/gst/matroska/matroska-demux.h
@@ -77,9 +77,10 @@ typedef struct _GstMatroskaDemux {
GstMatroskaDemuxState state;
guint level_up;
- /* did we parse metadata/cues already? */
- gboolean metadata_parsed;
+ /* did we parse cues/tracks/segmentinfo already? */
gboolean index_parsed;
+ gboolean tracks_parsed;
+ gboolean segmentinfo_parsed;
/* start-of-segment */
guint64 ebml_segment_start;