Commit e843de1d authored by Wim Taymans's avatar Wim Taymans

gst/qtdemux/qtdemux.c: Don't make rounding errors in timestamp/duration calculations.

Original commit message from CVS:
* gst/qtdemux/qtdemux.c: (gst_qtdemux_prepare_current_sample),
(gst_qtdemux_chain), (gst_qtdemux_add_stream), (qtdemux_dump_stsz),
(qtdemux_dump_stco), (qtdemux_parse_trak):
Don't make rounding errors in timestamp/duration calculations.
Fix timestamps for AMR and IMA4.  Fixes (#337436).
Create a dummy segment even when there is no edit list.
parent bd72d30c
2006-04-08 Wim Taymans <wim@fluendo.com>
* gst/qtdemux/qtdemux.c: (gst_qtdemux_prepare_current_sample),
(gst_qtdemux_chain), (gst_qtdemux_add_stream), (qtdemux_dump_stsz),
(qtdemux_dump_stco), (qtdemux_parse_trak):
Don't make rounding errors in timestamp/duration calculations.
Fix timestamps for AMR and IMA4. Fixes (#337436).
Create a dummy segment even when there is no edit list.
2006-04-07 Julien MOUTTE <julien@moutte.net> 2006-04-07 Julien MOUTTE <julien@moutte.net>
* docs/plugins/gst-plugins-bad-plugins-decl-list.txt: Updates. * docs/plugins/gst-plugins-bad-plugins-decl-list.txt: Updates.
......
...@@ -72,7 +72,7 @@ struct _QtDemuxSample ...@@ -72,7 +72,7 @@ struct _QtDemuxSample
guint32 size; guint32 size;
guint64 offset; guint64 offset;
guint64 timestamp; /* In GstClockTime */ guint64 timestamp; /* In GstClockTime */
guint32 duration; /* in stream->timescale units */ guint32 duration; /* in GstClockTime */
gboolean keyframe; /* TRUE when this packet is a keyframe */ gboolean keyframe; /* TRUE when this packet is a keyframe */
}; };
...@@ -106,19 +106,27 @@ struct _QtDemuxStream ...@@ -106,19 +106,27 @@ struct _QtDemuxStream
QtDemuxSample *samples; QtDemuxSample *samples;
gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */ gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
/* if we use chunks or samples */
gboolean sampled;
/* video info */
gint width; gint width;
gint height; gint height;
/* Numerator/denominator framerate */ /* Numerator/denominator framerate */
gint fps_n; gint fps_n;
gint fps_d; gint fps_d;
guint16 bits_per_sample;
guint16 color_table_id;
/* audio info */
gdouble rate; gdouble rate;
gint n_channels; gint n_channels;
guint samples_per_packet;
guint samples_per_frame;
guint bytes_per_packet;
guint bytes_per_sample;
guint bytes_per_frame; guint bytes_per_frame;
guint compression; guint compression;
guint samples_per_packet;
guint16 bits_per_sample;
guint16 color_table_id;
/* when a discontinuity is pending */ /* when a discontinuity is pending */
gboolean discont; gboolean discont;
...@@ -1154,19 +1162,8 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux, ...@@ -1154,19 +1162,8 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
*offset = sample->offset; *offset = sample->offset;
*size = sample->size; *size = sample->size;
/* timestamps of AMR aren't known... FIXME */
if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
*duration = -1;
if (stream->sample_index == 0)
*timestamp = 0;
else
*timestamp = -1;
} else {
*timestamp = sample->timestamp; *timestamp = sample->timestamp;
*duration = gst_util_uint64_scale_int *duration = sample->duration;
(sample->duration, GST_SECOND, stream->timescale);
}
*keyframe = stream->all_keyframe || sample->keyframe; *keyframe = stream->all_keyframe || sample->keyframe;
return TRUE; return TRUE;
...@@ -1648,18 +1645,11 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf) ...@@ -1648,18 +1645,11 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT, GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (stream->fourcc)); GST_FOURCC_ARGS (stream->fourcc));
if (stream->fourcc != GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (outbuf) =
stream->samples[stream->sample_index].timestamp; stream->samples[stream->sample_index].timestamp;
demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf); demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf);
GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int GST_BUFFER_DURATION (outbuf) =
(stream->samples[stream->sample_index].duration, GST_SECOND, stream->samples[stream->sample_index].duration;
stream->timescale);
} else {
if (stream->sample_index == 0)
GST_BUFFER_TIMESTAMP (outbuf) = 0;
}
/* send buffer */ /* send buffer */
GST_LOG_OBJECT (demux, GST_LOG_OBJECT (demux,
...@@ -1766,6 +1756,8 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux, ...@@ -1766,6 +1756,8 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux,
stream->pad = stream->pad =
gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name); gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
g_free (name); g_free (name);
/* guess fps, FIXME */
if ((stream->n_samples == 1) && (stream->samples[0].duration == 0)) { if ((stream->n_samples == 1) && (stream->samples[0].duration == 0)) {
stream->fps_n = 0; stream->fps_n = 0;
stream->fps_d = 1; stream->fps_d = 1;
...@@ -2720,9 +2712,8 @@ qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth) ...@@ -2720,9 +2712,8 @@ qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth)
GST_LOG ("%*s version/flags: %08x", depth, "", GST_LOG ("%*s version/flags: %08x", depth, "",
QTDEMUX_GUINT32_GET (buffer + 8)); QTDEMUX_GUINT32_GET (buffer + 8));
GST_LOG ("%*s sample size: %d", depth, "",
QTDEMUX_GUINT32_GET (buffer + 12));
sample_size = QTDEMUX_GUINT32_GET (buffer + 12); sample_size = QTDEMUX_GUINT32_GET (buffer + 12);
GST_LOG ("%*s sample size: %d", depth, "", sample_size);
if (sample_size == 0) { if (sample_size == 0) {
GST_LOG ("%*s n entries: %d", depth, "", GST_LOG ("%*s n entries: %d", depth, "",
QTDEMUX_GUINT32_GET (buffer + 16)); QTDEMUX_GUINT32_GET (buffer + 16));
...@@ -2742,24 +2733,21 @@ qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth) ...@@ -2742,24 +2733,21 @@ qtdemux_dump_stsz (GstQTDemux * qtdemux, void *buffer, int depth)
static void static void
qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth) qtdemux_dump_stco (GstQTDemux * qtdemux, void *buffer, int depth)
{ {
//int i; int i;
int n; int n;
int offset; int offset;
GST_LOG ("%*s version/flags: %08x", depth, "", GST_LOG ("%*s version/flags: %08x", depth, "",
QTDEMUX_GUINT32_GET (buffer + 8)); QTDEMUX_GUINT32_GET (buffer + 8));
GST_LOG ("%*s n entries: %d", depth, "",
QTDEMUX_GUINT32_GET (buffer + 12));
n = QTDEMUX_GUINT32_GET (buffer + 12); n = QTDEMUX_GUINT32_GET (buffer + 12);
GST_LOG ("%*s n entries: %d", depth, "", n);
offset = 16; offset = 16;
#if 0
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
GST_LOG ("%*s chunk offset: %08x", depth, "", GST_LOG ("%*s chunk offset: %d", depth, "",
QTDEMUX_GUINT32_GET (buffer + offset)); QTDEMUX_GUINT32_GET (buffer + offset));
offset += 4; offset += 4;
} }
#endif
} }
static void static void
...@@ -2965,7 +2953,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -2965,7 +2953,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
int i, j, k; int i, j, k;
QtDemuxStream *stream; QtDemuxStream *stream;
int n_sample_times; int n_sample_times;
guint64 timestamp; guint64 timestamp, time;
int sample_size; int sample_size;
int sample_index; int sample_index;
GstTagList *list = NULL; GstTagList *list = NULL;
...@@ -3137,6 +3125,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3137,6 +3125,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
int version, samplesize; int version, samplesize;
guint32 fourcc; guint32 fourcc;
int len; int len;
guint16 compression_id;
len = QTDEMUX_GUINT32_GET (stsd->data + 16); len = QTDEMUX_GUINT32_GET (stsd->data + 16);
GST_LOG ("st type: %" GST_FOURCC_FORMAT, GST_LOG ("st type: %" GST_FOURCC_FORMAT,
...@@ -3145,61 +3134,75 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3145,61 +3134,75 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + 16 + 4); stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd->data + 16 + 4);
offset = 32; offset = 32;
GST_LOG ("version/rev: %08x",
QTDEMUX_GUINT32_GET (stsd->data + offset));
version = QTDEMUX_GUINT32_GET (stsd->data + offset); version = QTDEMUX_GUINT32_GET (stsd->data + offset);
GST_LOG ("vendor: %08x",
QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
GST_LOG ("n_channels: %d",
QTDEMUX_GUINT16_GET (stsd->data + offset + 8));
stream->n_channels = QTDEMUX_GUINT16_GET (stsd->data + offset + 8); stream->n_channels = QTDEMUX_GUINT16_GET (stsd->data + offset + 8);
GST_LOG ("sample_size: %d",
QTDEMUX_GUINT16_GET (stsd->data + offset + 10));
samplesize = QTDEMUX_GUINT16_GET (stsd->data + offset + 10); samplesize = QTDEMUX_GUINT16_GET (stsd->data + offset + 10);
GST_LOG ("compression_id: %d", compression_id = QTDEMUX_GUINT16_GET (stsd->data + offset + 12);
QTDEMUX_GUINT16_GET (stsd->data + offset + 12)); stream->rate = QTDEMUX_FP32_GET (stsd->data + offset + 16);
GST_LOG ("version/rev: %08x", version);
GST_LOG ("vendor: %08x",
QTDEMUX_GUINT32_GET (stsd->data + offset + 4));
GST_LOG ("n_channels: %d", stream->n_channels);
GST_LOG ("sample_size: %d", samplesize);
GST_LOG ("compression_id: %d", compression_id);
GST_LOG ("packet size: %d", GST_LOG ("packet size: %d",
QTDEMUX_GUINT16_GET (stsd->data + offset + 14)); QTDEMUX_GUINT16_GET (stsd->data + offset + 14));
GST_LOG ("sample rate: %g", GST_LOG ("sample rate: %g", stream->rate);
QTDEMUX_FP32_GET (stsd->data + offset + 16));
stream->rate = QTDEMUX_FP32_GET (stsd->data + offset + 16); if (compression_id == 0xfffe)
stream->sampled = TRUE;
offset = 52; offset = 52;
if (version == 0x00010000) { if (version == 0x00010000) {
GST_LOG ("samples/packet: %d",
QTDEMUX_GUINT32_GET (stsd->data + offset));
stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd->data + offset); stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd->data + offset);
GST_LOG ("bytes/packet: %d", stream->samples_per_frame = stream->n_channels;
QTDEMUX_GUINT32_GET (stsd->data + offset + 4)); stream->bytes_per_packet = QTDEMUX_GUINT32_GET (stsd->data + offset + 4);
GST_LOG ("bytes/frame: %d",
QTDEMUX_GUINT32_GET (stsd->data + offset + 8));
stream->bytes_per_frame = QTDEMUX_GUINT32_GET (stsd->data + offset + 8); stream->bytes_per_frame = QTDEMUX_GUINT32_GET (stsd->data + offset + 8);
GST_LOG ("bytes/sample: %d", stream->bytes_per_sample = QTDEMUX_GUINT32_GET (stsd->data + offset + 12);
QTDEMUX_GUINT32_GET (stsd->data + offset + 12));
stream->compression = 1; GST_LOG ("samples/packet: %d", stream->samples_per_packet);
GST_LOG ("bytes/packet: %d", stream->bytes_per_packet);
GST_LOG ("bytes/frame: %d", stream->bytes_per_frame);
GST_LOG ("bytes/sample: %d", stream->bytes_per_sample);
offset = 68; offset = 68;
} else if (version == 0x00000000) { } else if (version == 0x00000000) {
stream->bytes_per_frame = stream->n_channels * samplesize / 8; stream->bytes_per_sample = samplesize / 8;
stream->samples_per_packet = 1; stream->samples_per_frame = stream->n_channels;
stream->compression = 1; stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
stream->samples_per_packet = stream->samples_per_frame;
stream->bytes_per_packet = stream->bytes_per_sample;
/* Yes, these have to be hard-coded */ /* Yes, these have to be hard-coded */
if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '6')) if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '6')) {
stream->compression = 6; stream->samples_per_packet = 6;
if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '3')) stream->bytes_per_packet = 1;
stream->compression = 3; stream->bytes_per_frame = 1 * stream->n_channels;
if (fourcc == GST_MAKE_FOURCC ('i', 'm', 'a', '4')) stream->bytes_per_sample = 1;
stream->compression = 4; stream->samples_per_frame = 6 * stream->n_channels;
if (fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) { }
stream->n_channels = 1; if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '3')) {
stream->rate = 8000; stream->samples_per_packet = 3;
stream->bytes_per_frame <<= 3; stream->bytes_per_packet = 1;
} stream->bytes_per_frame = 1 * stream->n_channels;
if (fourcc == GST_MAKE_FOURCC ('u', 'l', 'a', 'w')) stream->bytes_per_sample = 1;
stream->compression = 2; stream->samples_per_frame = 3 * stream->n_channels;
if (fourcc == GST_MAKE_FOURCC ('a', 'g', 's', 'm')) { }
stream->bytes_per_frame *= 33; if (fourcc == GST_MAKE_FOURCC ('i', 'm', 'a', '4')) {
stream->compression = 320; stream->samples_per_packet = 64;
stream->bytes_per_packet = 34;
stream->bytes_per_frame = 34 * stream->n_channels;
stream->bytes_per_sample = 2;
stream->samples_per_frame = 64 * stream->n_channels;
}
if (fourcc == GST_MAKE_FOURCC ('u', 'l', 'a', 'w') ||
fourcc == GST_MAKE_FOURCC ('a', 'l', 'a', 'w')) {
stream->samples_per_packet = 1;
stream->bytes_per_packet = 1;
stream->bytes_per_frame = 1 * stream->n_channels;
stream->bytes_per_sample = 2;
stream->samples_per_frame = 6 * stream->n_channels;
} }
} else { } else {
GST_WARNING ("unknown version %08x", version); GST_WARNING ("unknown version %08x", version);
...@@ -3281,6 +3284,12 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3281,6 +3284,12 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
return; return;
} }
/* promote to sampled format */
if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r'))
stream->sampled = TRUE;
if (stream->fourcc == GST_MAKE_FOURCC ('m', 'p', '4', 'a'))
stream->sampled = TRUE;
/* sample to chunk */ /* sample to chunk */
stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc); stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc);
g_assert (stsc); g_assert (stsc);
...@@ -3298,7 +3307,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3298,7 +3307,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss); stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
sample_size = QTDEMUX_GUINT32_GET (stsz->data + 12); sample_size = QTDEMUX_GUINT32_GET (stsz->data + 12);
if (sample_size == 0) { if (sample_size == 0 || stream->sampled) {
n_samples = QTDEMUX_GUINT32_GET (stsz->data + 16); n_samples = QTDEMUX_GUINT32_GET (stsz->data + 16);
GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d", GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
n_samples); n_samples);
...@@ -3307,7 +3316,11 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3307,7 +3316,11 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
stream->samples = samples; stream->samples = samples;
for (i = 0; i < n_samples; i++) { for (i = 0; i < n_samples; i++) {
if (sample_size == 0)
samples[i].size = QTDEMUX_GUINT32_GET (stsz->data + i * 4 + 20); samples[i].size = QTDEMUX_GUINT32_GET (stsz->data + i * 4 + 20);
else
samples[i].size = sample_size;
GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size); GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
/* init other fields to defaults for this sample */ /* init other fields to defaults for this sample */
samples[i].keyframe = FALSE; samples[i].keyframe = FALSE;
...@@ -3351,6 +3364,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3351,6 +3364,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
n_sample_times = QTDEMUX_GUINT32_GET (stts->data + 12); n_sample_times = QTDEMUX_GUINT32_GET (stts->data + 12);
timestamp = 0; timestamp = 0;
time = 0;
index = 0; index = 0;
for (i = 0; i < n_sample_times; i++) { for (i = 0; i < n_sample_times; i++) {
guint32 n; guint32 n;
...@@ -3359,18 +3373,16 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3359,18 +3373,16 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
n = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i); n = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i);
duration = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i + 4); duration = QTDEMUX_GUINT32_GET (stts->data + 16 + 8 * i + 4);
for (j = 0; j < n; j++) { for (j = 0; j < n; j++) {
guint64 time;
time = gst_util_uint64_scale_int (timestamp,
GST_SECOND, stream->timescale);
GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT, GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT,
index, GST_TIME_ARGS (time)); index, GST_TIME_ARGS (timestamp));
samples[index].timestamp = time; samples[index].timestamp = timestamp;
samples[index].duration = duration;
/* add non-scaled values to avoid rounding errors */ /* add non-scaled values to avoid rounding errors */
timestamp += duration; time += duration;
timestamp = gst_util_uint64_scale_int (time,
GST_SECOND, stream->timescale);
samples[index].duration = timestamp - samples[index].timestamp;
index++; index++;
} }
} }
...@@ -3395,8 +3407,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3395,8 +3407,6 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
stream->all_keyframe = TRUE; stream->all_keyframe = TRUE;
} }
} else { } else {
guint64 timestamp = 0;
GST_DEBUG_OBJECT (qtdemux, GST_DEBUG_OBJECT (qtdemux,
"stsz sample_size %d != 0, treating chunks as samples", sample_size); "stsz sample_size %d != 0, treating chunks as samples", sample_size);
...@@ -3415,16 +3425,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3415,16 +3425,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk); GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
offset = 16; offset = 16;
sample_index = 0; sample_index = 0;
timestamp = 0;
for (i = 0; i < n_samples_per_chunk; i++) { for (i = 0; i < n_samples_per_chunk; i++) {
int first_chunk, last_chunk; guint32 first_chunk, last_chunk;
int samples_per_chunk; guint32 samples_per_chunk;
first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1; first_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 0) - 1;
/* the last chunk of each entry is calculated by taking the first chunk /* the last chunk of each entry is calculated by taking the first chunk
* of the next entry; except if there is no next, where we fake it with * of the next entry; except if there is no next, where we fake it with
* INT_MAX */ * INT_MAX */
if (i == n_samples_per_chunk - 1) { if (i == n_samples_per_chunk - 1) {
last_chunk = INT_MAX; last_chunk = G_MAXUINT32;
} else { } else {
last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1; last_chunk = QTDEMUX_GUINT32_GET (stsc->data + 16 + i * 12 + 12) - 1;
} }
...@@ -3441,35 +3452,30 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) ...@@ -3441,35 +3452,30 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
goto done2; goto done2;
if (stco) { if (stco) {
chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4); chunk_offset = QTDEMUX_GUINT32_GET (stco->data + 16 + j * 4);
GST_LOG_OBJECT (qtdemux, "stco chunk %d offset %x", j, chunk_offset);
} else { } else {
chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8); chunk_offset = QTDEMUX_GUINT64_GET (co64->data + 16 + j * 8);
GST_LOG_OBJECT (qtdemux, "co64 chunk %d offset %" G_GUINT64_FORMAT, j,
chunk_offset);
} }
GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld", GST_LOG_OBJECT (qtdemux,
j, chunk_offset); "Creating entry %d with offset %" G_GUINT64_FORMAT, j,
chunk_offset);
samples[j].chunk = j; samples[j].chunk = j;
samples[j].offset = chunk_offset; samples[j].offset = chunk_offset;
if (stream->samples_per_packet * stream->compression != 0)
samples[j].size =
samples_per_chunk * stream->bytes_per_frame /
stream->samples_per_packet / stream->compression;
else if (stream->bytes_per_frame)
samples[j].size = stream->bytes_per_frame;
else
samples[j].size = sample_size;
/* FIXME, divide by 2? must be sample size or something.. */
samples[j].duration =
samples_per_chunk * stream->timescale / (stream->rate / 2);
samples[j].timestamp = timestamp;
samples[j].keyframe = TRUE;
if (stream->rate > 0) { samples[j].size = (samples_per_chunk * stream->n_channels) /
timestamp += gst_util_uint64_scale_int (samples_per_chunk, stream->samples_per_frame * stream->bytes_per_frame;
GST_SECOND, stream->rate);
} GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
", size %u", j, GST_TIME_ARGS (timestamp), samples[j].size);
samples[j].timestamp = timestamp;
sample_index += samples_per_chunk; sample_index += samples_per_chunk;
timestamp = gst_util_uint64_scale_int (sample_index,
GST_SECOND, stream->timescale);
samples[j].duration = timestamp - samples[j].timestamp;
samples[j].keyframe = TRUE;
} }
} }
} }
...@@ -3477,6 +3483,8 @@ done2: ...@@ -3477,6 +3483,8 @@ done2:
/* parse and prepare segment info from the edit list */ /* parse and prepare segment info from the edit list */
GST_DEBUG_OBJECT (qtdemux, "looking for edit list container"); GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
stream->n_segments = 0;
stream->segments = NULL;
if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) { if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
GNode *elst; GNode *elst;
gint n_segments; gint n_segments;
...@@ -3534,23 +3542,26 @@ done2: ...@@ -3534,23 +3542,26 @@ done2:
GST_TIME_ARGS (segment->media_start), segment->rate); GST_TIME_ARGS (segment->media_start), segment->rate);
} }
GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count); GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
stream->n_segments = count;
}
done3:
if (count == 0) {
/* no segments, create one to play the complete trak */ /* no segments, create one to play the complete trak */
count = 1; if (stream->n_segments == 0) {
if (stream->segments == NULL)
stream->segments = g_new (QtDemuxSegment, 1);
stream->segments[0].time = 0; stream->segments[0].time = 0;
stream->segments[0].stop_time = stream->duration; stream->segments[0].stop_time = qtdemux->segment.duration;
stream->segments[0].duration = stream->duration; stream->segments[0].duration = qtdemux->segment.duration;
stream->segments[0].media_start = 0; stream->segments[0].media_start = 0;
stream->segments[0].media_stop = stream->duration; stream->segments[0].media_stop = qtdemux->segment.duration;
stream->segments[0].rate = 1.0; stream->segments[0].rate = 1.0;
GST_DEBUG_OBJECT (qtdemux, "created dummy segment"); GST_DEBUG_OBJECT (qtdemux, "created dummy segment");
stream->n_segments = 1;
} }
GST_DEBUG_OBJECT (qtdemux, "using %d segments", count); GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
stream->n_segments = count;
}
done3:
gst_qtdemux_add_stream (qtdemux, stream, list); gst_qtdemux_add_stream (qtdemux, stream, list);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment