qtdemux: Add cslg support

The cslg atom provide information about the DTS shift. This is
needed in recent version of ctts atom where the offset can be
negative. When cslg is missing, we parse the CTTS table as proposed
in the spec to calculate these values.

In this implementation, we only need to know the shift. As GStreamer
cannot transport negative timestamps, we shift the timestamps forward
using that value and adapt the segment to compensate. This patch also
removes bogus offset of ctts_soffset, this offset shall be included
in the edit list.

https://bugzilla.gnome.org/show_bug.cgi?id=751103
This commit is contained in:
Nicolas Dufresne 2015-06-18 16:06:02 -04:00 committed by Nicolas Dufresne
parent 89104e35bf
commit dd72267a8d

View file

@ -127,7 +127,7 @@ struct _QtDemuxSample
/* timestamp is the DTS */
#define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
/* timestamp + offset is the PTS */
#define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
#define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
/* timestamp + duration - dts is the duration */
#define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
@ -376,6 +376,9 @@ struct _QtDemuxStream
guint32 ctts_count;
gint32 ctts_soffset;
/* cslg */
guint32 cslg_shift;
/* fragmented */
gboolean parsed_trex;
guint32 def_sample_duration;
@ -3749,10 +3752,10 @@ gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
stream->segment.base = qtdemux->segment.base;
stream->segment.applied_rate = qtdemux->segment.applied_rate;
stream->segment.rate = rate;
stream->segment.start = start +
QTSTREAMTIME_TO_GSTTIME (stream, stream->ctts_soffset);
stream->segment.stop = stop +
QTSTREAMTIME_TO_GSTTIME (stream, stream->ctts_soffset);
stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
stream->cslg_shift);
stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
stream->cslg_shift);
stream->segment.time = time;
stream->segment.position = stream->segment.start;
@ -6740,11 +6743,12 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
return FALSE;
}
/* composition time-to-sample */
if ((stream->ctts_present =
! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
&stream->ctts) ? TRUE : FALSE) == TRUE) {
GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
/* copy atom data into a new buffer for later use */
stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
@ -6758,6 +6762,46 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
4 + 4))
goto corrupt_file;
/* This is optional, if missing we iterate the ctts */
if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
if (!gst_byte_reader_skip (&cslg, 1 + 3)
|| !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
g_free ((gpointer) cslg.data);
goto corrupt_file;
}
} else {
gint32 cslg_least = 0;
guint num_entries, pos;
gint i;
pos = gst_byte_reader_get_pos (&stream->ctts);
num_entries = stream->n_composition_times;
stream->cslg_shift = 0;
for (i = 0; i < num_entries; i++) {
gint32 offset;
gst_byte_reader_skip_unchecked (&stream->ctts, 4);
offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
if (offset < cslg_least)
cslg_least = offset;
}
if (cslg_least < 0)
stream->cslg_shift = ABS (cslg_least);
else
stream->cslg_shift = 0;
/* reset the reader so we can generate sample table */
gst_byte_reader_set_pos (&stream->ctts, pos);
}
} else {
/* Ensure the cslg_shift value is consistent so we can use it
* unconditionnally to produce TS and Segment */
stream->cslg_shift = 0;
}
return TRUE;