gst/matroska/: Use a GArray for storing the Cue (i.e. seek) information, store the CueTrackPositions for every track,...
Original commit message from CVS: * gst/matroska/matroska-demux.c: (gst_matroska_demux_reset), (gst_matroskademux_do_index_seek), (gst_matroska_demux_parse_index_cuetrack), (gst_matroska_demux_parse_index_pointentry), (gst_matroska_index_compare), (gst_matroska_demux_parse_index), (gst_matroska_demux_parse_metadata): * gst/matroska/matroska-demux.h: * gst/matroska/matroska-ids.h: Use a GArray for storing the Cue (i.e. seek) information, store the CueTrackPositions for every track, store the block number and optimize searching in the array by sorting it after the last element was added. Fix a small memory leak when trying to parse a tags element that was already parsed.
This commit is contained in:
parent
25e2770edf
commit
94f778f952
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
|||||||
|
2008-06-15 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
|
* gst/matroska/matroska-demux.c: (gst_matroska_demux_reset),
|
||||||
|
(gst_matroskademux_do_index_seek),
|
||||||
|
(gst_matroska_demux_parse_index_cuetrack),
|
||||||
|
(gst_matroska_demux_parse_index_pointentry),
|
||||||
|
(gst_matroska_index_compare), (gst_matroska_demux_parse_index),
|
||||||
|
(gst_matroska_demux_parse_metadata):
|
||||||
|
* gst/matroska/matroska-demux.h:
|
||||||
|
* gst/matroska/matroska-ids.h:
|
||||||
|
Use a GArray for storing the Cue (i.e. seek) information, store
|
||||||
|
the CueTrackPositions for every track, store the block number
|
||||||
|
and optimize searching in the array by sorting it after the last
|
||||||
|
element was added.
|
||||||
|
|
||||||
|
Fix a small memory leak when trying to parse a tags element that was
|
||||||
|
already parsed.
|
||||||
|
|
||||||
2008-06-15 Sebastian Dröge <slomo@circular-chaos.org>
|
2008-06-15 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
* gst/matroska/matroska-mux.c: (gst_matroska_mux_reset),
|
* gst/matroska/matroska-mux.c: (gst_matroska_mux_reset),
|
||||||
|
@ -299,9 +299,10 @@ gst_matroska_demux_reset (GstElement * element)
|
|||||||
demux->muxing_app = NULL;
|
demux->muxing_app = NULL;
|
||||||
|
|
||||||
/* reset indexes */
|
/* reset indexes */
|
||||||
demux->num_indexes = 0;
|
if (demux->index) {
|
||||||
g_free (demux->index);
|
g_array_free (demux->index, TRUE);
|
||||||
demux->index = NULL;
|
demux->index = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* reset timers */
|
/* reset timers */
|
||||||
demux->clock = NULL;
|
demux->clock = NULL;
|
||||||
@ -1400,44 +1401,53 @@ static GstMatroskaIndex *
|
|||||||
gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, gint64 seek_pos,
|
gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, gint64 seek_pos,
|
||||||
gint64 segment_stop, gboolean keyunit)
|
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;
|
return NULL;
|
||||||
|
|
||||||
if (keyunit) {
|
/* find entry just before or at the requested position */
|
||||||
/* find index entry closest to the requested position */
|
for (n = 0; n < demux->index->len; n++) {
|
||||||
entry = 0;
|
GstMatroskaIndex *index;
|
||||||
for (n = 0; n < demux->num_indexes; ++n) {
|
|
||||||
gdouble d_entry, d_this;
|
|
||||||
|
|
||||||
d_entry = fabs (gst_guint64_to_gdouble (demux->index[entry].time) -
|
index = &g_array_index (demux->index, GstMatroskaIndex, n);
|
||||||
gst_guint64_to_gdouble (seek_pos));
|
|
||||||
d_this = fabs (gst_guint64_to_gdouble (demux->index[n].time) -
|
|
||||||
gst_guint64_to_gdouble (seek_pos));
|
|
||||||
|
|
||||||
if (d_this < d_entry &&
|
if (index->time <= seek_pos)
|
||||||
(demux->index[n].time < segment_stop || segment_stop == -1)) {
|
entry = index;
|
||||||
entry = n;
|
else
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* find index entry at or before the requested position */
|
|
||||||
entry = demux->num_indexes - 1;
|
|
||||||
|
|
||||||
while (n < demux->num_indexes - 1) {
|
|
||||||
if ((demux->index[n].time <= seek_pos) &&
|
|
||||||
(demux->index[n + 1].time > seek_pos)) {
|
|
||||||
entry = n;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n++;
|
|
||||||
|
if (keyunit) {
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
GstClockTimeDiff d_this, d_entry;
|
||||||
|
|
||||||
|
index = &g_array_index (demux->index, GstMatroskaIndex, n);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &demux->index[entry];
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* takes ownership of the passed event! */
|
/* takes ownership of the passed event! */
|
||||||
@ -1811,7 +1821,7 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux)
|
|||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
|
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);
|
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
||||||
|
|
||||||
@ -1819,6 +1829,13 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
|
|||||||
|
|
||||||
GstFlowReturn ret;
|
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)
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1843,13 +1860,13 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
|
|||||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||||
goto error;
|
goto error;
|
||||||
if (num == 0) {
|
if (num == 0) {
|
||||||
idx->track = -1;
|
idx.track = 0;
|
||||||
GST_WARNING ("Invalid cue track number (0)");
|
GST_WARNING ("Invalid cue track number (0)");
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
idx->track = num;
|
idx.track = num;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1863,7 +1880,23 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
|
|||||||
|
|
||||||
/* FIXME: may overflow, our seeks, etc are int64 based */
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1871,7 +1904,6 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
|
|||||||
GST_WARNING ("Unknown entry 0x%x in CuesTrackPositions", id);
|
GST_WARNING ("Unknown entry 0x%x in CuesTrackPositions", id);
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
case GST_MATROSKA_ID_CUEBLOCKNUMBER:
|
|
||||||
case GST_MATROSKA_ID_CUECODECSTATE:
|
case GST_MATROSKA_ID_CUECODECSTATE:
|
||||||
case GST_MATROSKA_ID_CUEREFERENCE:
|
case GST_MATROSKA_ID_CUEREFERENCE:
|
||||||
if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
|
if ((ret = gst_ebml_read_skip (ebml)) != GST_FLOW_OK)
|
||||||
@ -1885,6 +1917,13 @@ gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -1900,21 +1939,17 @@ gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux,
|
|||||||
{
|
{
|
||||||
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
||||||
|
|
||||||
GstMatroskaIndex idx;
|
|
||||||
|
|
||||||
guint32 id;
|
guint32 id;
|
||||||
|
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
GstClockTime time = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
guint nentries = 0;
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK)
|
||||||
return ret;
|
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) {
|
while (ret == GST_FLOW_OK) {
|
||||||
if (prevent_eos && length == ebml->offset)
|
if (prevent_eos && length == ebml->offset)
|
||||||
break;
|
break;
|
||||||
@ -1931,25 +1966,27 @@ gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux,
|
|||||||
/* one single index entry ('point') */
|
/* one single index entry ('point') */
|
||||||
case GST_MATROSKA_ID_CUETIME:
|
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) {
|
time = time * demux->time_scale;
|
||||||
idx.time = time * demux->time_scale;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* position in the file + track to which it belongs */
|
/* position in the file + track to which it belongs */
|
||||||
case GST_MATROSKA_ID_CUETRACKPOSITIONS:
|
case GST_MATROSKA_ID_CUETRACKPOSITIONS:
|
||||||
{
|
{
|
||||||
ret = gst_matroska_demux_parse_index_cuetrack (demux, prevent_eos, &idx,
|
if ((ret =
|
||||||
length);
|
gst_matroska_demux_parse_index_cuetrack (demux, prevent_eos,
|
||||||
|
&nentries, length)) != GST_FLOW_OK)
|
||||||
|
return ret;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GST_WARNING ("Unknown entry 0x%x in cuespoint index", id);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1959,26 +1996,42 @@ gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* so let's see if we got what we wanted */
|
if (nentries > 0) {
|
||||||
if (idx.pos != (guint64) - 1 &&
|
if (time == GST_CLOCK_TIME_NONE) {
|
||||||
idx.time != (guint64) - 1 && idx.track != (guint16) - 1) {
|
GST_WARNING_OBJECT (demux, "CuePoint without valid time");
|
||||||
if (demux->num_indexes % 32 == 0) {
|
g_array_remove_range (demux->index, demux->index->len - nentries,
|
||||||
/* re-allocate bigger index */
|
nentries);
|
||||||
demux->index = g_renew (GstMatroskaIndex, demux->index,
|
} else {
|
||||||
demux->num_indexes + 32);
|
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
|
GST_DEBUG_OBJECT (demux, "Index entry: pos=%" G_GUINT64_FORMAT
|
||||||
", time=%" GST_TIME_FORMAT ", track=%u", idx.pos,
|
", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
|
||||||
GST_TIME_ARGS (idx.time), (guint) idx.track);
|
GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
|
||||||
demux->index[demux->num_indexes].pos = idx.pos;
|
}
|
||||||
demux->index[demux->num_indexes].time = idx.time;
|
}
|
||||||
demux->index[demux->num_indexes].track = idx.track;
|
} else {
|
||||||
demux->num_indexes++;
|
GST_DEBUG_OBJECT (demux, "Empty CuePoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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
|
static GstFlowReturn
|
||||||
gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos)
|
gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos)
|
||||||
{
|
{
|
||||||
@ -1994,6 +2047,11 @@ gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos)
|
|||||||
length = gst_ebml_read_get_length (ebml);
|
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) {
|
while (ret == GST_FLOW_OK) {
|
||||||
/* We're an element that can be seeked to. If we are, then
|
/* 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
|
* we want to prevent EOS, since that'll kill us. So we cache
|
||||||
@ -2028,6 +2086,9 @@ gst_matroska_demux_parse_index (GstMatroskaDemux * demux, gboolean prevent_eos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sort index by time, smallest time first, for easier searching */
|
||||||
|
g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare);
|
||||||
|
|
||||||
demux->index_parsed = TRUE;
|
demux->index_parsed = TRUE;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -2314,7 +2375,7 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux,
|
|||||||
{
|
{
|
||||||
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
||||||
|
|
||||||
GstTagList *taglist = gst_tag_list_new ();
|
GstTagList *taglist;
|
||||||
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
@ -2348,6 +2409,8 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taglist = gst_tag_list_new ();
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (demux, "Parsing Tags at offset %" G_GUINT64_FORMAT,
|
GST_DEBUG_OBJECT (demux, "Parsing Tags at offset %" G_GUINT64_FORMAT,
|
||||||
ebml->offset);
|
ebml->offset);
|
||||||
/* TODO: g_slice_dup() if we depend on GLib 2.14 */
|
/* TODO: g_slice_dup() if we depend on GLib 2.14 */
|
||||||
|
@ -87,8 +87,7 @@ typedef struct _GstMatroskaDemux {
|
|||||||
guint64 ebml_segment_start;
|
guint64 ebml_segment_start;
|
||||||
|
|
||||||
/* a cue (index) table */
|
/* a cue (index) table */
|
||||||
GstMatroskaIndex *index;
|
GArray *index;
|
||||||
guint num_indexes;
|
|
||||||
|
|
||||||
/* timescale in the file */
|
/* timescale in the file */
|
||||||
guint64 time_scale;
|
guint64 time_scale;
|
||||||
|
@ -533,7 +533,8 @@ typedef struct _GstMatroskaTrackSubtitleContext {
|
|||||||
typedef struct _GstMatroskaIndex {
|
typedef struct _GstMatroskaIndex {
|
||||||
guint64 pos; /* of the corresponding *cluster*! */
|
guint64 pos; /* of the corresponding *cluster*! */
|
||||||
guint16 track; /* reference to 'num' */
|
guint16 track; /* reference to 'num' */
|
||||||
guint64 time; /* in nanoseconds */
|
GstClockTime time; /* in nanoseconds */
|
||||||
|
guint32 block; /* number of the block in the cluster */
|
||||||
} GstMatroskaIndex;
|
} GstMatroskaIndex;
|
||||||
|
|
||||||
typedef struct _Wavpack4Header {
|
typedef struct _Wavpack4Header {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user