mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
matroska: refactor code common to matroskademux and matroskaparse
Replace the following functions with their gst_matroska_read_common_* counterparts: - gst_matroska_{demux,parse}_parse_index - gst_matroska_{demux,parse}_parse_skip - gst_matroska_{demux,parse}_stream_from_num Introduce GstMatroskaReadCommon to contain those members of GstMatroskaDemux and GstMatroskaParse that were used by the above functions. https://bugzilla.gnome.org/show_bug.cgi?id=650877
This commit is contained in:
parent
a53540346a
commit
15ce1142ca
7 changed files with 703 additions and 903 deletions
|
@ -8,6 +8,7 @@ libgstmatroska_la_SOURCES = \
|
|||
matroska-parse.c \
|
||||
matroska-ids.c \
|
||||
matroska-mux.c \
|
||||
matroska-read-common.c \
|
||||
webm-mux.c \
|
||||
lzo.c
|
||||
|
||||
|
@ -19,6 +20,7 @@ noinst_HEADERS = \
|
|||
matroska-parse.h \
|
||||
matroska-ids.h \
|
||||
matroska-mux.h \
|
||||
matroska-read-common.h \
|
||||
webm-mux.h \
|
||||
lzo.h
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "ebml-read.h"
|
||||
#include "matroska-ids.h"
|
||||
#include "matroska-read-common.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -55,14 +56,11 @@ typedef struct _GstMatroskaDemux {
|
|||
|
||||
/* < private > */
|
||||
|
||||
GstIndex *element_index;
|
||||
gint element_index_writer_id;
|
||||
GstMatroskaReadCommon common;
|
||||
|
||||
/* pads */
|
||||
GstPad *sinkpad;
|
||||
GPtrArray *src;
|
||||
GstClock *clock;
|
||||
guint num_streams;
|
||||
guint num_v_streams;
|
||||
guint num_a_streams;
|
||||
guint num_t_streams;
|
||||
|
@ -80,24 +78,15 @@ typedef struct _GstMatroskaDemux {
|
|||
gboolean seek_first;
|
||||
|
||||
/* did we parse cues/tracks/segmentinfo already? */
|
||||
gboolean index_parsed;
|
||||
gboolean tracks_parsed;
|
||||
gboolean segmentinfo_parsed;
|
||||
gboolean attachments_parsed;
|
||||
GList *tags_parsed;
|
||||
GList *seek_parsed;
|
||||
|
||||
/* start-of-segment */
|
||||
guint64 ebml_segment_start;
|
||||
|
||||
/* a cue (index) table */
|
||||
GArray *index;
|
||||
/* cluster positions (optional) */
|
||||
GArray *clusters;
|
||||
|
||||
/* timescale in the file */
|
||||
guint64 time_scale;
|
||||
|
||||
/* keeping track of playback position */
|
||||
GstSegment segment;
|
||||
gboolean segment_running;
|
||||
|
|
|
@ -170,9 +170,9 @@ gst_matroska_parse_finalize (GObject * object)
|
|||
{
|
||||
GstMatroskaParse *parse = GST_MATROSKA_PARSE (object);
|
||||
|
||||
if (parse->src) {
|
||||
g_ptr_array_free (parse->src, TRUE);
|
||||
parse->src = NULL;
|
||||
if (parse->common.src) {
|
||||
g_ptr_array_free (parse->common.src, TRUE);
|
||||
parse->common.src = NULL;
|
||||
}
|
||||
|
||||
if (parse->global_tags) {
|
||||
|
@ -232,11 +232,11 @@ gst_matroska_parse_init (GstMatroskaParse * parse,
|
|||
gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
|
||||
|
||||
/* initial stream no. */
|
||||
parse->src = NULL;
|
||||
parse->common.src = NULL;
|
||||
|
||||
parse->writing_app = NULL;
|
||||
parse->muxing_app = NULL;
|
||||
parse->index = NULL;
|
||||
parse->common.index = NULL;
|
||||
parse->global_tags = NULL;
|
||||
|
||||
parse->adapter = gst_adapter_new ();
|
||||
|
@ -295,19 +295,20 @@ gst_matroska_parse_reset (GstElement * element)
|
|||
parse->state = GST_MATROSKA_PARSE_STATE_START;
|
||||
|
||||
/* clean up existing streams */
|
||||
if (parse->src) {
|
||||
g_assert (parse->src->len == parse->num_streams);
|
||||
for (i = 0; i < parse->src->len; i++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
|
||||
if (parse->common.src) {
|
||||
g_assert (parse->common.src->len == parse->common.num_streams);
|
||||
for (i = 0; i < parse->common.src->len; i++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
|
||||
i);
|
||||
|
||||
gst_caps_replace (&context->caps, NULL);
|
||||
gst_matroska_track_free (context);
|
||||
}
|
||||
g_ptr_array_free (parse->src, TRUE);
|
||||
g_ptr_array_free (parse->common.src, TRUE);
|
||||
}
|
||||
parse->src = g_ptr_array_new ();
|
||||
parse->common.src = g_ptr_array_new ();
|
||||
|
||||
parse->num_streams = 0;
|
||||
parse->common.num_streams = 0;
|
||||
parse->num_a_streams = 0;
|
||||
parse->num_t_streams = 0;
|
||||
parse->num_v_streams = 0;
|
||||
|
@ -319,17 +320,17 @@ gst_matroska_parse_reset (GstElement * element)
|
|||
parse->muxing_app = NULL;
|
||||
|
||||
/* reset indexes */
|
||||
if (parse->index) {
|
||||
g_array_free (parse->index, TRUE);
|
||||
parse->index = NULL;
|
||||
if (parse->common.index) {
|
||||
g_array_free (parse->common.index, TRUE);
|
||||
parse->common.index = NULL;
|
||||
}
|
||||
|
||||
/* reset timers */
|
||||
parse->clock = NULL;
|
||||
parse->time_scale = 1000000;
|
||||
parse->common.time_scale = 1000000;
|
||||
parse->created = G_MININT64;
|
||||
|
||||
parse->index_parsed = FALSE;
|
||||
parse->common.index_parsed = FALSE;
|
||||
parse->tracks_parsed = FALSE;
|
||||
parse->segmentinfo_parsed = FALSE;
|
||||
parse->attachments_parsed = FALSE;
|
||||
|
@ -374,11 +375,11 @@ gst_matroska_parse_reset (GstElement * element)
|
|||
parse->new_segment = NULL;
|
||||
}
|
||||
|
||||
if (parse->element_index) {
|
||||
gst_object_unref (parse->element_index);
|
||||
parse->element_index = NULL;
|
||||
if (parse->common.element_index) {
|
||||
gst_object_unref (parse->common.element_index);
|
||||
parse->common.element_index = NULL;
|
||||
}
|
||||
parse->element_index_writer_id = -1;
|
||||
parse->common.element_index_writer_id = -1;
|
||||
|
||||
if (parse->global_tags) {
|
||||
gst_tag_list_free (parse->global_tags);
|
||||
|
@ -507,27 +508,6 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse)
|
|||
return end;
|
||||
}
|
||||
|
||||
static gint
|
||||
gst_matroska_parse_stream_from_num (GstMatroskaParse * parse, guint track_num)
|
||||
{
|
||||
guint n;
|
||||
|
||||
g_assert (parse->src->len == parse->num_streams);
|
||||
for (n = 0; n < parse->src->len; n++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, n);
|
||||
|
||||
if (context->num == track_num) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == parse->num_streams)
|
||||
GST_WARNING_OBJECT (parse,
|
||||
"Failed to find corresponding pad for tracknum %d", track_num);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gint
|
||||
gst_matroska_parse_encoding_cmp (GstMatroskaTrackEncoding * a,
|
||||
GstMatroskaTrackEncoding * b)
|
||||
|
@ -1041,9 +1021,10 @@ gst_matroska_parse_tracknumber_unique (GstMatroskaParse * parse, guint64 num)
|
|||
{
|
||||
gint i;
|
||||
|
||||
g_assert (parse->src->len == parse->num_streams);
|
||||
for (i = 0; i < parse->src->len; i++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
|
||||
g_assert (parse->common.src->len == parse->common.num_streams);
|
||||
for (i = 0; i < parse->common.src->len; i++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
|
||||
i);
|
||||
|
||||
if (context->num == num)
|
||||
return FALSE;
|
||||
|
@ -1070,8 +1051,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
/* allocate generic... if we know the type, we'll g_renew()
|
||||
* with the precise type */
|
||||
context = g_new0 (GstMatroskaTrackContext, 1);
|
||||
g_ptr_array_add (parse->src, context);
|
||||
context->index = parse->num_streams;
|
||||
g_ptr_array_add (parse->common.src, context);
|
||||
context->index = parse->common.num_streams;
|
||||
context->index_writer_id = -1;
|
||||
context->type = 0; /* no type yet */
|
||||
context->default_duration = 0;
|
||||
|
@ -1083,8 +1064,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
GST_MATROSKA_TRACK_LACING;
|
||||
context->last_flow = GST_FLOW_OK;
|
||||
context->to_offset = G_MAXINT64;
|
||||
parse->num_streams++;
|
||||
g_assert (parse->src->len == parse->num_streams);
|
||||
parse->common.num_streams++;
|
||||
g_assert (parse->common.src->len == parse->common.num_streams);
|
||||
|
||||
GST_DEBUG_OBJECT (parse, "Stream number %d", context->index);
|
||||
|
||||
|
@ -1176,7 +1157,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
context->type = 0;
|
||||
break;
|
||||
}
|
||||
g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
|
||||
g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
|
||||
= context;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1195,7 +1177,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
break;
|
||||
}
|
||||
videocontext = (GstMatroskaTrackVideoContext *) context;
|
||||
g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
|
||||
g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
|
||||
= context;
|
||||
|
||||
while (ret == GST_FLOW_OK &&
|
||||
gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
|
@ -1415,7 +1398,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
break;
|
||||
|
||||
audiocontext = (GstMatroskaTrackAudioContext *) context;
|
||||
g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
|
||||
g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
|
||||
= context;
|
||||
|
||||
while (ret == GST_FLOW_OK &&
|
||||
gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
|
@ -1715,9 +1699,9 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
|
||||
GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
|
||||
|
||||
parse->num_streams--;
|
||||
g_ptr_array_remove_index (parse->src, parse->num_streams);
|
||||
g_assert (parse->src->len == parse->num_streams);
|
||||
parse->common.num_streams--;
|
||||
g_ptr_array_remove_index (parse->common.src, parse->common.num_streams);
|
||||
g_assert (parse->common.src->len == parse->common.num_streams);
|
||||
if (context) {
|
||||
gst_matroska_track_free (context);
|
||||
}
|
||||
|
@ -1880,14 +1864,14 @@ gst_matroskaparse_do_index_seek (GstMatroskaParse * parse,
|
|||
GstMatroskaIndex *entry = NULL;
|
||||
GArray *index;
|
||||
|
||||
if (!parse->index || !parse->index->len)
|
||||
if (!parse->common.index || !parse->common.index->len)
|
||||
return NULL;
|
||||
|
||||
/* find entry just before or at the requested position */
|
||||
if (track && track->index_table)
|
||||
index = track->index_table;
|
||||
else
|
||||
index = parse->index;
|
||||
index = parse->common.index;
|
||||
|
||||
entry =
|
||||
gst_util_array_binary_search (index->data, index->len,
|
||||
|
@ -1970,10 +1954,10 @@ gst_matroska_parse_get_seek_track (GstMatroskaParse * parse,
|
|||
if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
|
||||
return track;
|
||||
|
||||
for (i = 0; i < parse->src->len; i++) {
|
||||
for (i = 0; i < parse->common.src->len; i++) {
|
||||
GstMatroskaTrackContext *stream;
|
||||
|
||||
stream = g_ptr_array_index (parse->src, i);
|
||||
stream = g_ptr_array_index (parse->common.src, i);
|
||||
if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
|
||||
track = stream;
|
||||
}
|
||||
|
@ -1989,9 +1973,10 @@ gst_matroska_parse_reset_streams (GstMatroskaParse * parse, GstClockTime time,
|
|||
|
||||
GST_DEBUG_OBJECT (parse, "resetting stream state");
|
||||
|
||||
g_assert (parse->src->len == parse->num_streams);
|
||||
for (i = 0; i < parse->src->len; i++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
|
||||
g_assert (parse->common.src->len == parse->common.num_streams);
|
||||
for (i = 0; i < parse->common.src->len; i++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
|
||||
i);
|
||||
context->pos = time;
|
||||
context->set_discont = TRUE;
|
||||
context->eos = FALSE;
|
||||
|
@ -2153,7 +2138,8 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
|
|||
/* need to seek to cluster start to pick up cluster time */
|
||||
/* upstream takes care of flushing and all that
|
||||
* ... and newsegment event handling takes care of the rest */
|
||||
return perform_seek_to_offset (parse, entry->pos + parse->ebml_segment_start);
|
||||
return perform_seek_to_offset (parse, entry->pos
|
||||
+ parse->common.ebml_segment_start);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2198,7 +2184,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad,
|
|||
}
|
||||
|
||||
/* check for having parsed index already */
|
||||
if (!parse->index_parsed) {
|
||||
if (!parse->common.index_parsed) {
|
||||
gboolean building_index;
|
||||
guint64 offset = 0;
|
||||
|
||||
|
@ -2295,24 +2281,6 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* skip unknown or alike element */
|
||||
static GstFlowReturn
|
||||
gst_matroska_parse_parse_skip (GstMatroskaParse * parse, GstEbmlRead * ebml,
|
||||
const gchar * parent_name, guint id)
|
||||
{
|
||||
if (id == GST_EBML_ID_VOID) {
|
||||
GST_DEBUG_OBJECT (parse, "Skipping EBML Void element");
|
||||
} else if (id == GST_EBML_ID_CRC32) {
|
||||
GST_DEBUG_OBJECT (parse, "Skipping EBML CRC32 element");
|
||||
} else {
|
||||
GST_WARNING_OBJECT (parse,
|
||||
"Unknown %s subelement 0x%x - ignoring", parent_name, id);
|
||||
}
|
||||
|
||||
return gst_ebml_read_skip (ebml);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
||||
{
|
||||
|
@ -2424,7 +2392,8 @@ gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "EBML header", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"EBML header", id);
|
||||
if (ret != GST_FLOW_OK)
|
||||
return ret;
|
||||
break;
|
||||
|
@ -2493,7 +2462,8 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "Track", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"Track", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2504,306 +2474,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_parse_parse_index_cuetrack (GstMatroskaParse * parse,
|
||||
GstEbmlRead * ebml, guint * nentries)
|
||||
{
|
||||
guint32 id;
|
||||
GstFlowReturn ret;
|
||||
GstMatroskaIndex idx;
|
||||
|
||||
idx.pos = (guint64) - 1;
|
||||
idx.track = 0;
|
||||
idx.time = GST_CLOCK_TIME_NONE;
|
||||
idx.block = 1;
|
||||
|
||||
DEBUG_ELEMENT_START (parse, ebml, "CueTrackPositions");
|
||||
|
||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||
DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
/* track number */
|
||||
case GST_MATROSKA_ID_CUETRACK:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
if (num == 0) {
|
||||
idx.track = 0;
|
||||
GST_WARNING_OBJECT (parse, "Invalid CueTrack 0");
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (parse, "CueTrack: %" G_GUINT64_FORMAT, num);
|
||||
idx.track = num;
|
||||
break;
|
||||
}
|
||||
|
||||
/* position in file */
|
||||
case GST_MATROSKA_ID_CUECLUSTERPOSITION:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
if (num > G_MAXINT64) {
|
||||
GST_WARNING_OBJECT (parse, "CueClusterPosition %" G_GUINT64_FORMAT
|
||||
" too large", num);
|
||||
break;
|
||||
}
|
||||
|
||||
idx.pos = num;
|
||||
break;
|
||||
}
|
||||
|
||||
/* number of block in the cluster */
|
||||
case GST_MATROSKA_ID_CUEBLOCKNUMBER:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
if (num == 0) {
|
||||
GST_WARNING_OBJECT (parse, "Invalid CueBlockNumber 0");
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (parse, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
|
||||
idx.block = num;
|
||||
|
||||
/* mild sanity check, disregard strange cases ... */
|
||||
if (idx.block > G_MAXUINT16) {
|
||||
GST_DEBUG_OBJECT (parse, "... looks suspicious, ignoring");
|
||||
idx.block = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "CueTrackPositions",
|
||||
id);
|
||||
break;
|
||||
|
||||
case GST_MATROSKA_ID_CUECODECSTATE:
|
||||
case GST_MATROSKA_ID_CUEREFERENCE:
|
||||
ret = gst_ebml_read_skip (ebml);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret);
|
||||
|
||||
if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
|
||||
&& idx.pos != (guint64) - 1 && idx.track > 0) {
|
||||
g_array_append_val (parse->index, idx);
|
||||
(*nentries)++;
|
||||
} else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
|
||||
GST_DEBUG_OBJECT (parse, "CueTrackPositions without valid content");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_parse_parse_index_pointentry (GstMatroskaParse * parse,
|
||||
GstEbmlRead * ebml)
|
||||
{
|
||||
guint32 id;
|
||||
GstFlowReturn ret;
|
||||
GstClockTime time = GST_CLOCK_TIME_NONE;
|
||||
guint nentries = 0;
|
||||
|
||||
DEBUG_ELEMENT_START (parse, ebml, "CuePoint");
|
||||
|
||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||
DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
/* one single index entry ('point') */
|
||||
case GST_MATROSKA_ID_CUETIME:
|
||||
{
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
GST_DEBUG_OBJECT (parse, "CueTime: %" G_GUINT64_FORMAT, time);
|
||||
time = time * parse->time_scale;
|
||||
break;
|
||||
}
|
||||
|
||||
/* position in the file + track to which it belongs */
|
||||
case GST_MATROSKA_ID_CUETRACKPOSITIONS:
|
||||
{
|
||||
if ((ret =
|
||||
gst_matroska_parse_parse_index_cuetrack (parse, ebml,
|
||||
&nentries)) != GST_FLOW_OK)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "CuePoint", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret);
|
||||
|
||||
if (nentries > 0) {
|
||||
if (time == GST_CLOCK_TIME_NONE) {
|
||||
GST_WARNING_OBJECT (parse, "CuePoint without valid time");
|
||||
g_array_remove_range (parse->index, parse->index->len - nentries,
|
||||
nentries);
|
||||
} else {
|
||||
gint i;
|
||||
|
||||
for (i = parse->index->len - nentries; i < parse->index->len; i++) {
|
||||
GstMatroskaIndex *idx =
|
||||
&g_array_index (parse->index, GstMatroskaIndex, i);
|
||||
|
||||
idx->time = time;
|
||||
GST_DEBUG_OBJECT (parse, "Index entry: pos=%" G_GUINT64_FORMAT
|
||||
", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
|
||||
GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (parse, "Empty CuePoint");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gint
|
||||
gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
|
||||
{
|
||||
if (i1->time < i2->time)
|
||||
return -1;
|
||||
else if (i1->time > i2->time)
|
||||
return 1;
|
||||
else if (i1->block < i2->block)
|
||||
return -1;
|
||||
else if (i1->block > i2->block)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_parse_parse_index (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
||||
{
|
||||
guint32 id;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint i;
|
||||
|
||||
if (parse->index)
|
||||
g_array_free (parse->index, TRUE);
|
||||
parse->index =
|
||||
g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
|
||||
|
||||
DEBUG_ELEMENT_START (parse, ebml, "Cues");
|
||||
|
||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||
DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
/* one single index entry ('point') */
|
||||
case GST_MATROSKA_ID_POINTENTRY:
|
||||
ret = gst_matroska_parse_parse_index_pointentry (parse, ebml);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "Cues", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret);
|
||||
|
||||
/* Sort index by time, smallest time first, for easier searching */
|
||||
g_array_sort (parse->index, (GCompareFunc) gst_matroska_index_compare);
|
||||
|
||||
/* Now sort the track specific index entries into their own arrays */
|
||||
for (i = 0; i < parse->index->len; i++) {
|
||||
GstMatroskaIndex *idx = &g_array_index (parse->index, GstMatroskaIndex, i);
|
||||
gint track_num;
|
||||
GstMatroskaTrackContext *ctx;
|
||||
|
||||
if (parse->element_index) {
|
||||
gint writer_id;
|
||||
|
||||
if (idx->track != 0 &&
|
||||
(track_num =
|
||||
gst_matroska_parse_stream_from_num (parse, idx->track)) != -1) {
|
||||
ctx = g_ptr_array_index (parse->src, track_num);
|
||||
|
||||
if (ctx->index_writer_id == -1)
|
||||
gst_index_get_writer_id (parse->element_index, GST_OBJECT (ctx->pad),
|
||||
&ctx->index_writer_id);
|
||||
writer_id = ctx->index_writer_id;
|
||||
} else {
|
||||
if (parse->element_index_writer_id == -1)
|
||||
gst_index_get_writer_id (parse->element_index, GST_OBJECT (parse),
|
||||
&parse->element_index_writer_id);
|
||||
writer_id = parse->element_index_writer_id;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %"
|
||||
G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
|
||||
idx->pos, writer_id);
|
||||
gst_index_add_association (parse->element_index, writer_id,
|
||||
GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
|
||||
GST_FORMAT_BYTES, idx->pos + parse->ebml_segment_start, NULL);
|
||||
}
|
||||
|
||||
if (idx->track == 0)
|
||||
continue;
|
||||
|
||||
track_num = gst_matroska_parse_stream_from_num (parse, idx->track);
|
||||
if (track_num == -1)
|
||||
continue;
|
||||
|
||||
ctx = g_ptr_array_index (parse->src, track_num);
|
||||
|
||||
if (ctx->index_table == NULL)
|
||||
ctx->index_table =
|
||||
g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
|
||||
|
||||
g_array_append_vals (ctx->index_table, idx, 1);
|
||||
}
|
||||
|
||||
parse->index_parsed = TRUE;
|
||||
|
||||
/* sanity check; empty index normalizes to no index */
|
||||
if (parse->index->len == 0) {
|
||||
g_array_free (parse->index, TRUE);
|
||||
parse->index = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
||||
{
|
||||
|
@ -2832,7 +2502,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
|
||||
|
||||
GST_DEBUG_OBJECT (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
|
||||
parse->time_scale = num;
|
||||
parse->common.time_scale = num;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2899,7 +2569,8 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "SegmentInfo", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"SegmentInfo", id);
|
||||
break;
|
||||
|
||||
/* fall through */
|
||||
|
@ -2920,7 +2591,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
GstClockTime dur_u;
|
||||
|
||||
dur_u = gst_gdouble_to_guint64 (dur_f *
|
||||
gst_guint64_to_gdouble (parse->time_scale));
|
||||
gst_guint64_to_gdouble (parse->common.time_scale));
|
||||
if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
|
||||
gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME, dur_u);
|
||||
}
|
||||
|
@ -2994,7 +2665,8 @@ gst_matroska_parse_parse_metadata_id_simple_tag (GstMatroskaParse * parse,
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "SimpleTag", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"SimpleTag", id);
|
||||
break;
|
||||
/* fall-through */
|
||||
|
||||
|
@ -3080,7 +2752,8 @@ gst_matroska_parse_parse_metadata_id_tag (GstMatroskaParse * parse,
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "Tag", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"Tag", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3136,7 +2809,8 @@ gst_matroska_parse_parse_metadata (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "Tags", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"Tags", id);
|
||||
break;
|
||||
/* FIXME: Use to limit the tags to specific pads */
|
||||
case GST_MATROSKA_ID_TARGETS:
|
||||
|
@ -3219,7 +2893,8 @@ gst_matroska_parse_parse_attached_file (GstMatroskaParse * parse,
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "AttachedFile", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"AttachedFile", id);
|
||||
break;
|
||||
case GST_MATROSKA_ID_FILEUID:
|
||||
ret = gst_ebml_read_skip (ebml);
|
||||
|
@ -3332,7 +3007,8 @@ gst_matroska_parse_parse_attachments (GstMatroskaParse * parse,
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "Attachments", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"Attachments", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3498,14 +3174,15 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
|||
size -= n;
|
||||
|
||||
/* fetch stream from num */
|
||||
stream_num = gst_matroska_parse_stream_from_num (parse, num);
|
||||
stream_num = gst_matroska_read_common_stream_from_num (&parse->common,
|
||||
num);
|
||||
if (G_UNLIKELY (size < 3)) {
|
||||
GST_WARNING_OBJECT (parse, "Invalid size %u", size);
|
||||
/* non-fatal, try next block(group) */
|
||||
ret = GST_FLOW_OK;
|
||||
goto done;
|
||||
} else if (G_UNLIKELY (stream_num < 0 ||
|
||||
stream_num >= parse->num_streams)) {
|
||||
stream_num >= parse->common.num_streams)) {
|
||||
/* let's not give up on a stray invalid track number */
|
||||
GST_WARNING_OBJECT (parse,
|
||||
"Invalid stream %d for track number %" G_GUINT64_FORMAT
|
||||
|
@ -3513,7 +3190,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
|||
goto done;
|
||||
}
|
||||
|
||||
stream = g_ptr_array_index (parse->src, stream_num);
|
||||
stream = g_ptr_array_index (parse->common.src, stream_num);
|
||||
|
||||
/* time (relative to cluster time) */
|
||||
time = ((gint16) GST_READ_UINT16_BE (data));
|
||||
|
@ -3640,7 +3317,8 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
|||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "BlockGroup", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"BlockGroup", id);
|
||||
break;
|
||||
|
||||
case GST_MATROSKA_ID_BLOCKVIRTUAL:
|
||||
|
@ -3667,7 +3345,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
|||
gint64 lace_time = 0;
|
||||
gboolean delta_unit;
|
||||
|
||||
stream = g_ptr_array_index (parse->src, stream_num);
|
||||
stream = g_ptr_array_index (parse->common.src, stream_num);
|
||||
|
||||
if (cluster_time != GST_CLOCK_TIME_NONE) {
|
||||
/* FIXME: What to do with negative timestamps? Give timestamp 0 or -1?
|
||||
|
@ -3676,11 +3354,11 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
|||
lace_time = 0;
|
||||
} else {
|
||||
if (stream->timecodescale == 1.0)
|
||||
lace_time = (cluster_time + time) * parse->time_scale;
|
||||
lace_time = (cluster_time + time) * parse->common.time_scale;
|
||||
else
|
||||
lace_time =
|
||||
gst_util_guint64_to_gdouble ((cluster_time + time) *
|
||||
parse->time_scale) * stream->timecodescale;
|
||||
parse->common.time_scale) * stream->timecodescale;
|
||||
}
|
||||
} else {
|
||||
lace_time = GST_CLOCK_TIME_NONE;
|
||||
|
@ -3707,11 +3385,12 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
|||
|
||||
if (block_duration) {
|
||||
if (stream->timecodescale == 1.0)
|
||||
duration = gst_util_uint64_scale (block_duration, parse->time_scale, 1);
|
||||
duration = gst_util_uint64_scale (block_duration,
|
||||
parse->common.time_scale, 1);
|
||||
else
|
||||
duration =
|
||||
gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble
|
||||
(gst_util_uint64_scale (block_duration, parse->time_scale,
|
||||
(gst_util_uint64_scale (block_duration, parse->common.time_scale,
|
||||
1)) * stream->timecodescale);
|
||||
} else if (stream->default_duration) {
|
||||
duration = stream->default_duration * laces;
|
||||
|
@ -4041,7 +3720,8 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
|
|||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"SeekHead", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -4077,17 +3757,18 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
|
|||
}
|
||||
|
||||
/* check for validity */
|
||||
if (seek_pos + parse->ebml_segment_start + 12 >= length) {
|
||||
if (seek_pos + parse->common.ebml_segment_start + 12 >= length) {
|
||||
GST_WARNING_OBJECT (parse,
|
||||
"SeekHead reference lies outside file!" " (%"
|
||||
G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %"
|
||||
G_GUINT64_FORMAT ")", seek_pos, parse->ebml_segment_start, length);
|
||||
G_GUINT64_FORMAT ")", seek_pos, parse->common.ebml_segment_start,
|
||||
length);
|
||||
break;
|
||||
}
|
||||
|
||||
/* only pick up index location when streaming */
|
||||
if (seek_id == GST_MATROSKA_ID_CUES) {
|
||||
parse->index_offset = seek_pos + parse->ebml_segment_start;
|
||||
parse->index_offset = seek_pos + parse->common.ebml_segment_start;
|
||||
GST_DEBUG_OBJECT (parse, "Cues located at offset %" G_GUINT64_FORMAT,
|
||||
parse->index_offset);
|
||||
}
|
||||
|
@ -4133,7 +3814,8 @@ gst_matroska_parse_parse_contents (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
|
||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
||||
"SeekHead", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -4442,7 +4124,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
|
|||
parse->offset);
|
||||
/* seeks are from the beginning of the segment,
|
||||
* after the segment ID/length */
|
||||
parse->ebml_segment_start = parse->offset;
|
||||
parse->common.ebml_segment_start = parse->offset;
|
||||
parse->state = GST_MATROSKA_PARSE_STATE_HEADER;
|
||||
gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
|
||||
break;
|
||||
|
@ -4514,16 +4196,17 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
|
|||
goto parse_failed;
|
||||
GST_DEBUG_OBJECT (parse, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
|
||||
parse->cluster_time = num;
|
||||
if (parse->element_index) {
|
||||
if (parse->element_index_writer_id == -1)
|
||||
gst_index_get_writer_id (parse->element_index,
|
||||
GST_OBJECT (parse), &parse->element_index_writer_id);
|
||||
if (parse->common.element_index) {
|
||||
if (parse->common.element_index_writer_id == -1)
|
||||
gst_index_get_writer_id (parse->common.element_index,
|
||||
GST_OBJECT (parse), &parse->common.element_index_writer_id);
|
||||
GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %"
|
||||
G_GUINT64_FORMAT " for writer id %d",
|
||||
GST_TIME_ARGS (parse->cluster_time), parse->cluster_offset,
|
||||
parse->element_index_writer_id);
|
||||
gst_index_add_association (parse->element_index,
|
||||
parse->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT,
|
||||
parse->common.element_index_writer_id);
|
||||
gst_index_add_association (parse->common.element_index,
|
||||
parse->common.element_index_writer_id,
|
||||
GST_ASSOCIATION_FLAG_KEY_UNIT,
|
||||
GST_FORMAT_TIME, parse->cluster_time,
|
||||
GST_FORMAT_BYTES, parse->cluster_offset, NULL);
|
||||
}
|
||||
|
@ -4576,8 +4259,8 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
|
|||
break;
|
||||
case GST_MATROSKA_ID_CUES:
|
||||
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
||||
if (!parse->index_parsed) {
|
||||
ret = gst_matroska_parse_parse_index (parse, &ebml);
|
||||
if (!parse->common.index_parsed) {
|
||||
ret = gst_matroska_read_common_parse_index (&parse->common, &ebml);
|
||||
/* only push based; delayed index building */
|
||||
if (ret == GST_FLOW_OK
|
||||
&& parse->state == GST_MATROSKA_PARSE_STATE_SEEK) {
|
||||
|
@ -4955,7 +4638,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
|
|||
gst_event_unref (event);
|
||||
GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
|
||||
(NULL), ("got eos and didn't receive a complete header object"));
|
||||
} else if (parse->num_streams == 0) {
|
||||
} else if (parse->common.num_streams == 0) {
|
||||
GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
|
||||
(NULL), ("got eos but no streams (yet)"));
|
||||
} else {
|
||||
|
@ -4988,11 +4671,12 @@ gst_matroska_parse_set_index (GstElement * element, GstIndex * index)
|
|||
GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
|
||||
|
||||
GST_OBJECT_LOCK (parse);
|
||||
if (parse->element_index)
|
||||
gst_object_unref (parse->element_index);
|
||||
parse->element_index = index ? gst_object_ref (index) : NULL;
|
||||
if (parse->common.element_index)
|
||||
gst_object_unref (parse->common.element_index);
|
||||
parse->common.element_index = index ? gst_object_ref (index) : NULL;
|
||||
GST_OBJECT_UNLOCK (parse);
|
||||
GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, parse->element_index);
|
||||
GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT,
|
||||
parse->common.element_index);
|
||||
}
|
||||
|
||||
static GstIndex *
|
||||
|
@ -5002,8 +4686,8 @@ gst_matroska_parse_get_index (GstElement * element)
|
|||
GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
|
||||
|
||||
GST_OBJECT_LOCK (parse);
|
||||
if (parse->element_index)
|
||||
result = gst_object_ref (parse->element_index);
|
||||
if (parse->common.element_index)
|
||||
result = gst_object_ref (parse->common.element_index);
|
||||
GST_OBJECT_UNLOCK (parse);
|
||||
|
||||
GST_DEBUG_OBJECT (parse, "Returning index %" GST_PTR_FORMAT, result);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "ebml-read.h"
|
||||
#include "matroska-ids.h"
|
||||
#include "matroska-read-common.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -55,15 +56,12 @@ typedef struct _GstMatroskaParse {
|
|||
|
||||
/* < private > */
|
||||
|
||||
GstIndex *element_index;
|
||||
gint element_index_writer_id;
|
||||
GstMatroskaReadCommon common;
|
||||
|
||||
/* pads */
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
GPtrArray *src;
|
||||
GstClock *clock;
|
||||
guint num_streams;
|
||||
guint num_v_streams;
|
||||
guint num_a_streams;
|
||||
guint num_t_streams;
|
||||
|
@ -85,22 +83,12 @@ typedef struct _GstMatroskaParse {
|
|||
gboolean seek_first;
|
||||
|
||||
/* did we parse cues/tracks/segmentinfo already? */
|
||||
gboolean index_parsed;
|
||||
gboolean tracks_parsed;
|
||||
gboolean segmentinfo_parsed;
|
||||
gboolean attachments_parsed;
|
||||
GList *tags_parsed;
|
||||
GList *seek_parsed;
|
||||
|
||||
/* start-of-segment */
|
||||
guint64 ebml_segment_start;
|
||||
|
||||
/* a cue (index) table */
|
||||
GArray *index;
|
||||
|
||||
/* timescale in the file */
|
||||
guint64 time_scale;
|
||||
|
||||
/* keeping track of playback position */
|
||||
GstSegment segment;
|
||||
gboolean segment_running;
|
||||
|
|
382
gst/matroska/matroska-read-common.c
Normal file
382
gst/matroska/matroska-read-common.c
Normal file
|
@ -0,0 +1,382 @@
|
|||
/* GStreamer Matroska muxer/demuxer
|
||||
* (c) 2011 Debarshi Ray <rishi@gnu.org>
|
||||
*
|
||||
* matroska-read-common.c: shared by matroska file/stream demuxer and parser
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ebml-read.h"
|
||||
#include "matroska-ids.h"
|
||||
#include "matroska-read-common.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug);
|
||||
#define GST_CAT_DEFAULT matroskareadcommon_debug
|
||||
|
||||
#define DEBUG_ELEMENT_START(common, ebml, element) \
|
||||
GST_DEBUG_OBJECT (common, "Parsing " element " element at offset %" \
|
||||
G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
|
||||
|
||||
#define DEBUG_ELEMENT_STOP(common, ebml, element, ret) \
|
||||
GST_DEBUG_OBJECT (common, "Parsing " element " element " \
|
||||
" finished with '%s'", gst_flow_get_name (ret))
|
||||
|
||||
static gint
|
||||
gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
|
||||
{
|
||||
if (i1->time < i2->time)
|
||||
return -1;
|
||||
else if (i1->time > i2->time)
|
||||
return 1;
|
||||
else if (i1->block < i2->block)
|
||||
return -1;
|
||||
else if (i1->block > i2->block)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip unknown or alike element */
|
||||
GstFlowReturn
|
||||
gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common,
|
||||
GstEbmlRead * ebml, const gchar * parent_name, guint id)
|
||||
{
|
||||
if (id == GST_EBML_ID_VOID) {
|
||||
GST_DEBUG_OBJECT (common, "Skipping EBML Void element");
|
||||
} else if (id == GST_EBML_ID_CRC32) {
|
||||
GST_DEBUG_OBJECT (common, "Skipping EBML CRC32 element");
|
||||
} else {
|
||||
GST_WARNING_OBJECT (common,
|
||||
"Unknown %s subelement 0x%x - ignoring", parent_name, id);
|
||||
}
|
||||
|
||||
return gst_ebml_read_skip (ebml);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
||||
GstEbmlRead * ebml, guint * nentries)
|
||||
{
|
||||
guint32 id;
|
||||
GstFlowReturn ret;
|
||||
GstMatroskaIndex idx;
|
||||
|
||||
idx.pos = (guint64) - 1;
|
||||
idx.track = 0;
|
||||
idx.time = GST_CLOCK_TIME_NONE;
|
||||
idx.block = 1;
|
||||
|
||||
DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
|
||||
|
||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||
DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
/* track number */
|
||||
case GST_MATROSKA_ID_CUETRACK:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
if (num == 0) {
|
||||
idx.track = 0;
|
||||
GST_WARNING_OBJECT (common, "Invalid CueTrack 0");
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (common, "CueTrack: %" G_GUINT64_FORMAT, num);
|
||||
idx.track = num;
|
||||
break;
|
||||
}
|
||||
|
||||
/* position in file */
|
||||
case GST_MATROSKA_ID_CUECLUSTERPOSITION:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
if (num > G_MAXINT64) {
|
||||
GST_WARNING_OBJECT (common, "CueClusterPosition %" G_GUINT64_FORMAT
|
||||
" too large", num);
|
||||
break;
|
||||
}
|
||||
|
||||
idx.pos = num;
|
||||
break;
|
||||
}
|
||||
|
||||
/* number of block in the cluster */
|
||||
case GST_MATROSKA_ID_CUEBLOCKNUMBER:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
if (num == 0) {
|
||||
GST_WARNING_OBJECT (common, "Invalid CueBlockNumber 0");
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (common, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
|
||||
idx.block = num;
|
||||
|
||||
/* mild sanity check, disregard strange cases ... */
|
||||
if (idx.block > G_MAXUINT16) {
|
||||
GST_DEBUG_OBJECT (common, "... looks suspicious, ignoring");
|
||||
idx.block = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_read_common_parse_skip (common, ebml,
|
||||
"CueTrackPositions", id);
|
||||
break;
|
||||
|
||||
case GST_MATROSKA_ID_CUECODECSTATE:
|
||||
case GST_MATROSKA_ID_CUEREFERENCE:
|
||||
ret = gst_ebml_read_skip (ebml);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
|
||||
|
||||
if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
|
||||
&& idx.pos != (guint64) - 1 && idx.track > 0) {
|
||||
g_array_append_val (common->index, idx);
|
||||
(*nentries)++;
|
||||
} else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
|
||||
GST_DEBUG_OBJECT (common, "CueTrackPositions without valid content");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon *
|
||||
common, GstEbmlRead * ebml)
|
||||
{
|
||||
guint32 id;
|
||||
GstFlowReturn ret;
|
||||
GstClockTime time = GST_CLOCK_TIME_NONE;
|
||||
guint nentries = 0;
|
||||
|
||||
DEBUG_ELEMENT_START (common, ebml, "CuePoint");
|
||||
|
||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||
DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
/* one single index entry ('point') */
|
||||
case GST_MATROSKA_ID_CUETIME:
|
||||
{
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
GST_DEBUG_OBJECT (common, "CueTime: %" G_GUINT64_FORMAT, time);
|
||||
time = time * common->time_scale;
|
||||
break;
|
||||
}
|
||||
|
||||
/* position in the file + track to which it belongs */
|
||||
case GST_MATROSKA_ID_CUETRACKPOSITIONS:
|
||||
{
|
||||
if ((ret =
|
||||
gst_matroska_read_common_parse_index_cuetrack (common, ebml,
|
||||
&nentries)) != GST_FLOW_OK)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_read_common_parse_skip (common, ebml, "CuePoint",
|
||||
id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
|
||||
|
||||
if (nentries > 0) {
|
||||
if (time == GST_CLOCK_TIME_NONE) {
|
||||
GST_WARNING_OBJECT (common, "CuePoint without valid time");
|
||||
g_array_remove_range (common->index, common->index->len - nentries,
|
||||
nentries);
|
||||
} else {
|
||||
gint i;
|
||||
|
||||
for (i = common->index->len - nentries; i < common->index->len; i++) {
|
||||
GstMatroskaIndex *idx =
|
||||
&g_array_index (common->index, GstMatroskaIndex, i);
|
||||
|
||||
idx->time = time;
|
||||
GST_DEBUG_OBJECT (common, "Index entry: pos=%" G_GUINT64_FORMAT
|
||||
", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
|
||||
GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (common, "Empty CuePoint");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gint
|
||||
gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
|
||||
guint track_num)
|
||||
{
|
||||
guint n;
|
||||
|
||||
g_assert (common->src->len == common->num_streams);
|
||||
for (n = 0; n < common->src->len; n++) {
|
||||
GstMatroskaTrackContext *context = g_ptr_array_index (common->src, n);
|
||||
|
||||
if (context->num == track_num) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == common->num_streams)
|
||||
GST_WARNING_OBJECT (common,
|
||||
"Failed to find corresponding pad for tracknum %d", track_num);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
GstFlowReturn
|
||||
gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
|
||||
GstEbmlRead * ebml)
|
||||
{
|
||||
guint32 id;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint i;
|
||||
|
||||
if (common->index)
|
||||
g_array_free (common->index, TRUE);
|
||||
common->index =
|
||||
g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
|
||||
|
||||
DEBUG_ELEMENT_START (common, ebml, "Cues");
|
||||
|
||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||
DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
/* one single index entry ('point') */
|
||||
case GST_MATROSKA_ID_POINTENTRY:
|
||||
ret = gst_matroska_read_common_parse_index_pointentry (common, ebml);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = gst_matroska_read_common_parse_skip (common, ebml, "Cues", id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
|
||||
|
||||
/* Sort index by time, smallest time first, for easier searching */
|
||||
g_array_sort (common->index, (GCompareFunc) gst_matroska_index_compare);
|
||||
|
||||
/* Now sort the track specific index entries into their own arrays */
|
||||
for (i = 0; i < common->index->len; i++) {
|
||||
GstMatroskaIndex *idx = &g_array_index (common->index, GstMatroskaIndex,
|
||||
i);
|
||||
gint track_num;
|
||||
GstMatroskaTrackContext *ctx;
|
||||
|
||||
if (common->element_index) {
|
||||
gint writer_id;
|
||||
|
||||
if (idx->track != 0 &&
|
||||
(track_num =
|
||||
gst_matroska_read_common_stream_from_num (common,
|
||||
idx->track)) != -1) {
|
||||
ctx = g_ptr_array_index (common->src, track_num);
|
||||
|
||||
if (ctx->index_writer_id == -1)
|
||||
gst_index_get_writer_id (common->element_index,
|
||||
GST_OBJECT (ctx->pad), &ctx->index_writer_id);
|
||||
writer_id = ctx->index_writer_id;
|
||||
} else {
|
||||
if (common->element_index_writer_id == -1)
|
||||
gst_index_get_writer_id (common->element_index, GST_OBJECT (common),
|
||||
&common->element_index_writer_id);
|
||||
writer_id = common->element_index_writer_id;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (common, "adding association %" GST_TIME_FORMAT "-> %"
|
||||
G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
|
||||
idx->pos, writer_id);
|
||||
gst_index_add_association (common->element_index, writer_id,
|
||||
GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
|
||||
GST_FORMAT_BYTES, idx->pos + common->ebml_segment_start, NULL);
|
||||
}
|
||||
|
||||
if (idx->track == 0)
|
||||
continue;
|
||||
|
||||
track_num = gst_matroska_read_common_stream_from_num (common, idx->track);
|
||||
if (track_num == -1)
|
||||
continue;
|
||||
|
||||
ctx = g_ptr_array_index (common->src, track_num);
|
||||
|
||||
if (ctx->index_table == NULL)
|
||||
ctx->index_table =
|
||||
g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
|
||||
|
||||
g_array_append_vals (ctx->index_table, idx, 1);
|
||||
}
|
||||
|
||||
common->index_parsed = TRUE;
|
||||
|
||||
/* sanity check; empty index normalizes to no index */
|
||||
if (common->index->len == 0) {
|
||||
g_array_free (common->index, TRUE);
|
||||
common->index = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
69
gst/matroska/matroska-read-common.h
Normal file
69
gst/matroska/matroska-read-common.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* GStreamer Matroska muxer/demuxer
|
||||
* (c) 2011 Debarshi Ray <rishi@gnu.org>
|
||||
*
|
||||
* matroska-read-common.h: shared by matroska file/stream demuxer and parser
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_MATROSKA_READ_COMMON_H__
|
||||
#define __GST_MATROSKA_READ_COMMON_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
GST_MATROSKA_READ_COMMON_STATE_START,
|
||||
GST_MATROSKA_READ_COMMON_STATE_SEGMENT,
|
||||
GST_MATROSKA_READ_COMMON_STATE_HEADER,
|
||||
GST_MATROSKA_READ_COMMON_STATE_DATA,
|
||||
GST_MATROSKA_READ_COMMON_STATE_SEEK,
|
||||
GST_MATROSKA_READ_COMMON_STATE_SCANNING
|
||||
} GstMatroskaReadCommonState;
|
||||
|
||||
typedef struct _GstMatroskaReadCommon {
|
||||
GstIndex *element_index;
|
||||
gint element_index_writer_id;
|
||||
|
||||
/* pads */
|
||||
GPtrArray *src;
|
||||
guint num_streams;
|
||||
|
||||
/* did we parse cues/tracks/segmentinfo already? */
|
||||
gboolean index_parsed;
|
||||
|
||||
/* start-of-segment */
|
||||
guint64 ebml_segment_start;
|
||||
|
||||
/* a cue (index) table */
|
||||
GArray *index;
|
||||
|
||||
/* timescale in the file */
|
||||
guint64 time_scale;
|
||||
} GstMatroskaReadCommon;
|
||||
|
||||
GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
|
||||
common, GstEbmlRead * ebml);
|
||||
GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
|
||||
common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
|
||||
gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
|
||||
guint track_num);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MATROSKA_READ_COMMON_H__ */
|
Loading…
Reference in a new issue