demux->muxing_app = NULL;
/* reset indexes */
- demux->num_indexes = 0;
- g_free (demux->index);
- demux->index = NULL;
+ if (demux->index) {
+ g_array_free (demux->index, TRUE);
+ demux->index = NULL;
+ }
/* reset timers */
demux->clock = NULL;
gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, gint64 seek_pos,
gint64 segment_stop, gboolean keyunit)
{
- guint entry;
+ GstMatroskaIndex *entry = NULL;
- guint n = 0;
+ guint n;
- if (!demux->num_indexes)
+ if (!demux->index || !demux->index->len)
return NULL;
+ /* find entry just before or at the requested position */
+ for (n = 0; n < demux->index->len; n++) {
+ GstMatroskaIndex *index;
+
+ index = &g_array_index (demux->index, GstMatroskaIndex, n);
+
+ if (index->time <= seek_pos)
+ entry = index;
+ else
+ break;
+ }
+
if (keyunit) {
- /* find index entry closest to the requested position */
- entry = 0;
- for (n = 0; n < demux->num_indexes; ++n) {
- gdouble d_entry, d_this;
+ /* find index entry closest to the requested position.
+ * n contains the index of the GstMatroskaIndex after
+ * entry
+ */
+ if (entry && n < demux->index->len) {
+ GstMatroskaIndex *index;
- d_entry = fabs (gst_guint64_to_gdouble (demux->index[entry].time) -
- gst_guint64_to_gdouble (seek_pos));
- d_this = fabs (gst_guint64_to_gdouble (demux->index[n].time) -
- gst_guint64_to_gdouble (seek_pos));
+ GstClockTimeDiff d_this, d_entry;
- if (d_this < d_entry &&
- (demux->index[n].time < segment_stop || segment_stop == -1)) {
- entry = n;
- }
- }
- } else {
- /* find index entry at or before the requested position */
- entry = demux->num_indexes - 1;
+ index = &g_array_index (demux->index, GstMatroskaIndex, n);
- while (n < demux->num_indexes - 1) {
- if ((demux->index[n].time <= seek_pos) &&
- (demux->index[n + 1].time > seek_pos)) {
- entry = n;
- break;
+ d_entry = GST_CLOCK_DIFF (entry->time, seek_pos);
+ if (d_entry < 0)
+ d_entry = -d_entry;
+
+ d_this = GST_CLOCK_DIFF (index->time, seek_pos);
+ if (d_this < 0)
+ d_this = -d_this;
+
+ if (d_this < d_entry &&
+ (index->time < segment_stop || segment_stop == -1)) {
+ entry = index;
}
- n++;
}
}
- return &demux->index[entry];
+ return entry;
}
/* takes ownership of the passed event! */
static GstFlowReturn
gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
- gboolean prevent_eos, GstMatroskaIndex * idx, guint64 length)
+ gboolean prevent_eos, guint * nentries, guint64 length)
{
GstEbmlRead *ebml = GST_EBML_READ (demux);
GstFlowReturn ret;
+ GstMatroskaIndex idx;
+
+ idx.pos = (guint64) - 1;
+ idx.track = 0;
+ idx.time = GST_CLOCK_TIME_NONE;
+ idx.block = 1;
+
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
return ret;
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
goto error;
if (num == 0) {
- idx->track = -1;
+ idx.track = 0;
GST_WARNING ("Invalid cue track number (0)");
goto error;
break;
}
- idx->track = num;
+ idx.track = num;
break;
}
/* FIXME: may overflow, our seeks, etc are int64 based */
- idx->pos = num;
+ 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)
+ goto error;
+
+ if (num == 0) {
+ GST_WARNING_OBJECT (demux, "Invalid CueBlockNumber (0)");
+ } else {
+ idx.block = num;
+ }
break;
}
GST_WARNING ("Unknown entry 0x%x in CuesTrackPositions", id);
/* fall-through */
- case GST_MATROSKA_ID_CUEBLOCKNUMBER:
case GST_MATROSKA_ID_CUECODECSTATE:
case GST_MATROSKA_ID_CUEREFERENCE:
if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
}
}
+ if (ret == GST_FLOW_OK && idx.pos != (guint64) - 1 && idx.track > 0) {
+ g_array_append_val (demux->index, idx);
+ (*nentries)++;
+ } else {
+ GST_DEBUG_OBJECT (demux, "CueTrackPositions without valid content");
+ }
+
return ret;
error:
{
GstEbmlRead *ebml = GST_EBML_READ (demux);
- GstMatroskaIndex idx;
-
guint32 id;
GstFlowReturn ret;
+ GstClockTime time = GST_CLOCK_TIME_NONE;
+
+ guint nentries = 0;
+
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
return ret;
- /* in the end, we hope to fill one entry with a
- * timestamp, a file position and a tracknum */
- idx.pos = (guint64) - 1;
- idx.time = (guint64) - 1;
- idx.track = (guint16) - 1;
-
while (ret == GST_FLOW_OK) {
if (prevent_eos && length == ebml->offset)
break;
/* one single index entry ('point') */
case GST_MATROSKA_ID_CUETIME:
{
- guint64 time;
+ if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
+ return ret;
- if ((ret = gst_ebml_read_uint (ebml, &id, &time)) == GST_FLOW_OK) {
- idx.time = time * demux->time_scale;
- }
+ time = time * demux->time_scale;
break;
}
/* position in the file + track to which it belongs */
case GST_MATROSKA_ID_CUETRACKPOSITIONS:
{
- ret = gst_matroska_demux_parse_index_cuetrack (demux, prevent_eos, &idx,
- length);
+ if ((ret =
+ gst_matroska_demux_parse_index_cuetrack (demux, prevent_eos,
+ &nentries, length)) != GST_FLOW_OK)
+ return ret;
break;
}
default:
GST_WARNING ("Unknown entry 0x%x in cuespoint index", id);
- ret = gst_ebml_read_skip (ebml);
+ if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
+ return ret;
break;
}
}
}
- /* so let's see if we got what we wanted */
- if (idx.pos != (guint64) - 1 &&
- idx.time != (guint64) - 1 && idx.track != (guint16) - 1) {
- if (demux->num_indexes % 32 == 0) {
- /* re-allocate bigger index */
- demux->index = g_renew (GstMatroskaIndex, demux->index,
- demux->num_indexes + 32);
+ if (nentries > 0) {
+ if (time == GST_CLOCK_TIME_NONE) {
+ GST_WARNING_OBJECT (demux, "CuePoint without valid time");
+ g_array_remove_range (demux->index, demux->index->len - nentries,
+ nentries);
+ } else {
+ gint i;
+
+ for (i = demux->index->len - nentries; i < demux->index->len; i++) {
+ GstMatroskaIndex *idx =
+ &g_array_index (demux->index, GstMatroskaIndex, i);
+
+ idx->time = time;
+ GST_DEBUG_OBJECT (demux, "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);
+ }
}
- GST_DEBUG_OBJECT (demux, "Index entry: pos=%" G_GUINT64_FORMAT
- ", time=%" GST_TIME_FORMAT ", track=%u", idx.pos,
- GST_TIME_ARGS (idx.time), (guint) idx.track);
- demux->index[demux->num_indexes].pos = idx.pos;
- demux->index[demux->num_indexes].time = idx.time;
- demux->index[demux->num_indexes].track = idx.track;
- demux->num_indexes++;
+ } else {
+ GST_DEBUG_OBJECT (demux, "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
+ return 0;
+}
+
static GstFlowReturn
gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos)
{
length = gst_ebml_read_get_length (ebml);
}
+ if (demux->index)
+ g_array_free (demux->index, TRUE);
+ demux->index =
+ g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
+
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
}
}
+ /* Sort index by time, smallest time first, for easier searching */
+ g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare);
+
demux->index_parsed = TRUE;
return ret;
{
GstEbmlRead *ebml = GST_EBML_READ (demux);
- GstTagList *taglist = gst_tag_list_new ();
+ GstTagList *taglist;
GstFlowReturn ret = GST_FLOW_OK;
}
}
+ taglist = gst_tag_list_new ();
+
GST_DEBUG_OBJECT (demux, "Parsing Tags at offset %" G_GUINT64_FORMAT,
ebml->offset);
/* TODO: g_slice_dup() if we depend on GLib 2.14 */