mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
qtdemux: Parse from the previously parsed sample up to sample n
This commit is contained in:
parent
52b1040219
commit
29c33806c1
1 changed files with 160 additions and 99 deletions
|
@ -262,23 +262,47 @@ struct _QtDemuxStream
|
||||||
GstByteReader ctts;
|
GstByteReader ctts;
|
||||||
|
|
||||||
gboolean chunks_are_chunks;
|
gboolean chunks_are_chunks;
|
||||||
|
gint64 stbl_index;
|
||||||
/* stco */
|
/* stco */
|
||||||
guint co_size;
|
guint co_size;
|
||||||
|
GstByteReader co_chunk;
|
||||||
|
guint32 first_chunk;
|
||||||
|
guint32 current_chunk;
|
||||||
|
guint32 last_chunk;
|
||||||
|
guint32 samples_per_chunk;
|
||||||
|
guint32 stco_timestamp;
|
||||||
|
guint32 stco_sample_index;
|
||||||
/* stsz */
|
/* stsz */
|
||||||
guint32 sample_size; /* 0 means variable sizes are stored in stsz */
|
guint32 sample_size; /* 0 means variable sizes are stored in stsz */
|
||||||
/* stsc */
|
/* stsc */
|
||||||
|
guint32 stsc_index;
|
||||||
guint32 n_samples_per_chunk;
|
guint32 n_samples_per_chunk;
|
||||||
|
guint32 stsc_chunk_index;
|
||||||
|
guint32 stsc_sample_index;
|
||||||
|
guint64 chunk_offset;
|
||||||
/* stts */
|
/* stts */
|
||||||
|
guint32 stts_index;
|
||||||
|
guint32 stts_samples;
|
||||||
guint32 n_sample_times;
|
guint32 n_sample_times;
|
||||||
|
guint32 stts_sample_index;
|
||||||
|
guint64 stts_timestamp;
|
||||||
|
guint64 stts_time;
|
||||||
|
guint64 stts_duration;
|
||||||
/* stss */
|
/* stss */
|
||||||
gboolean stss_present;
|
gboolean stss_present;
|
||||||
guint32 n_sample_syncs;
|
guint32 n_sample_syncs;
|
||||||
|
guint32 stss_index;
|
||||||
/* stps */
|
/* stps */
|
||||||
gboolean stps_present;
|
gboolean stps_present;
|
||||||
guint32 n_sample_partial_syncs;
|
guint32 n_sample_partial_syncs;
|
||||||
|
guint32 stps_index;
|
||||||
/* ctts */
|
/* ctts */
|
||||||
gboolean ctts_present;
|
gboolean ctts_present;
|
||||||
guint32 n_composition_times;
|
guint32 n_composition_times;
|
||||||
|
guint32 ctts_index;
|
||||||
|
guint32 ctts_sample_index;
|
||||||
|
guint32 ctts_count;
|
||||||
|
gint32 ctts_soffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum QtDemuxState
|
enum QtDemuxState
|
||||||
|
@ -3901,6 +3925,8 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stream->stbl_index = -1; /* no samples have yet been parsed */
|
||||||
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -3912,15 +3938,14 @@ corrupt_file:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collect samples up to sample @n for @stream by reading the info from @stbl
|
/* collect samples from the next sample to be parsed up to sample @n for @stream
|
||||||
|
* by reading the info from @stbl
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
||||||
{
|
{
|
||||||
int sample_index = 0;
|
|
||||||
gint i, j, k;
|
gint i, j, k;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
guint64 timestamp = 0;
|
|
||||||
|
|
||||||
if (n >= stream->n_samples) {
|
if (n >= stream->n_samples) {
|
||||||
GST_LOG_OBJECT (qtdemux,
|
GST_LOG_OBJECT (qtdemux,
|
||||||
|
@ -3929,11 +3954,19 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n <= stream->stbl_index) {
|
||||||
|
GST_LOG_OBJECT (qtdemux,
|
||||||
|
"Tried to parse up to sample %u but this sample has already been parsed",
|
||||||
|
n);
|
||||||
|
return TRUE;
|
||||||
|
} else
|
||||||
|
stream->stbl_index++;
|
||||||
|
|
||||||
if (stream->chunks_are_chunks) {
|
if (stream->chunks_are_chunks) {
|
||||||
/* set the sample sizes */
|
/* set the sample sizes */
|
||||||
if (stream->sample_size == 0) {
|
if (stream->sample_size == 0) {
|
||||||
/* different sizes for each sample */
|
/* different sizes for each sample */
|
||||||
for (i = 0; i <= n; i++) {
|
for (i = stream->stbl_index; i <= n; i++) {
|
||||||
stream->samples[i].size =
|
stream->samples[i].size =
|
||||||
gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
|
gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
|
||||||
GST_LOG_OBJECT (qtdemux, "sample %d has size %u", i,
|
GST_LOG_OBJECT (qtdemux, "sample %d has size %u", i,
|
||||||
|
@ -3942,157 +3975,176 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
||||||
} else {
|
} else {
|
||||||
/* samples have the same size */
|
/* samples have the same size */
|
||||||
GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
|
GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
|
||||||
for (i = 0; i <= n; i++)
|
for (i = stream->stbl_index; i <= n; i++)
|
||||||
stream->samples[i].size = stream->sample_size;
|
stream->samples[i].size = stream->sample_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < stream->n_samples_per_chunk; i++) {
|
index = stream->stbl_index;
|
||||||
GstByteReader co_chunk;
|
for (i = stream->stsc_index; i < stream->n_samples_per_chunk; i++) {
|
||||||
guint32 first_chunk, last_chunk;
|
if (stream->stsc_chunk_index >= stream->last_chunk
|
||||||
guint32 samples_per_chunk;
|
|| stream->stsc_chunk_index < stream->first_chunk) {
|
||||||
|
stream->first_chunk =
|
||||||
|
gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
|
||||||
|
stream->samples_per_chunk =
|
||||||
|
gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
|
||||||
|
gst_byte_reader_skip_unchecked (&stream->stsc, 4);
|
||||||
|
|
||||||
first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
|
/* chunk numbers are counted from 1 it seems */
|
||||||
samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
|
if (G_UNLIKELY (stream->first_chunk == 0))
|
||||||
gst_byte_reader_skip_unchecked (&stream->stsc, 4);
|
|
||||||
|
|
||||||
/* chunk numbers are counted from 1 it seems */
|
|
||||||
if (G_UNLIKELY (first_chunk == 0))
|
|
||||||
goto corrupt_file;
|
|
||||||
else
|
|
||||||
--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
|
|
||||||
* INT_MAX */
|
|
||||||
if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
|
|
||||||
last_chunk = G_MAXUINT32;
|
|
||||||
} else {
|
|
||||||
last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
|
|
||||||
if (G_UNLIKELY (last_chunk == 0))
|
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
else
|
else
|
||||||
--last_chunk;
|
--stream->first_chunk;
|
||||||
}
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux,
|
/* the last chunk of each entry is calculated by taking the first chunk
|
||||||
"entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
|
* of the next entry; except if there is no next, where we fake it with
|
||||||
first_chunk, last_chunk, samples_per_chunk);
|
* INT_MAX */
|
||||||
|
if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
|
||||||
|
stream->last_chunk = G_MAXUINT32;
|
||||||
|
} else {
|
||||||
|
stream->last_chunk =
|
||||||
|
gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
|
||||||
|
if (G_UNLIKELY (stream->last_chunk == 0))
|
||||||
|
goto corrupt_file;
|
||||||
|
else
|
||||||
|
--stream->last_chunk;
|
||||||
|
}
|
||||||
|
|
||||||
if (G_UNLIKELY (last_chunk < first_chunk))
|
GST_LOG_OBJECT (qtdemux,
|
||||||
goto corrupt_file;
|
"entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
|
||||||
|
stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
|
||||||
|
|
||||||
if (last_chunk != G_MAXUINT32) {
|
if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
|
||||||
if (!qt_atom_parser_peek_sub (&stream->stco,
|
|
||||||
first_chunk * stream->co_size,
|
|
||||||
(last_chunk - first_chunk) * stream->co_size, &co_chunk))
|
|
||||||
goto corrupt_file;
|
|
||||||
} else {
|
|
||||||
co_chunk = stream->stco;
|
|
||||||
if (!gst_byte_reader_skip (&co_chunk, first_chunk * stream->co_size))
|
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
|
if (stream->last_chunk != G_MAXUINT32) {
|
||||||
|
if (!qt_atom_parser_peek_sub (&stream->stco,
|
||||||
|
stream->first_chunk * stream->co_size,
|
||||||
|
(stream->last_chunk - stream->first_chunk) * stream->co_size,
|
||||||
|
&stream->co_chunk))
|
||||||
|
goto corrupt_file;
|
||||||
|
} else {
|
||||||
|
stream->co_chunk = stream->stco;
|
||||||
|
if (!gst_byte_reader_skip (&stream->co_chunk,
|
||||||
|
stream->first_chunk * stream->co_size))
|
||||||
|
goto corrupt_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->stsc_chunk_index = stream->first_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->chunks_are_chunks) {
|
if (stream->chunks_are_chunks) {
|
||||||
for (j = first_chunk; j < last_chunk; j++) {
|
for (j = stream->stsc_chunk_index; j < stream->last_chunk; j++) {
|
||||||
guint64 chunk_offset;
|
if (!stream->stsc_sample_index
|
||||||
|
&& !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
|
||||||
if (!qt_atom_parser_get_offset (&co_chunk, stream->co_size,
|
&stream->chunk_offset))
|
||||||
&chunk_offset))
|
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
for (k = 0; k < samples_per_chunk; k++) {
|
for (k = stream->stsc_sample_index; k < stream->samples_per_chunk; k++) {
|
||||||
GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
|
GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %"
|
||||||
G_GUINT64_FORMAT, index, chunk_offset);
|
G_GUINT64_FORMAT, index, stream->chunk_offset);
|
||||||
stream->samples[index].offset = chunk_offset;
|
stream->samples[index].offset = stream->chunk_offset;
|
||||||
chunk_offset += stream->samples[index].size;
|
stream->chunk_offset += stream->samples[index].size;
|
||||||
|
stream->stsc_sample_index++;
|
||||||
index++;
|
index++;
|
||||||
if (G_UNLIKELY (index > n))
|
if (G_UNLIKELY (index > n))
|
||||||
goto done2;
|
goto done2;
|
||||||
}
|
}
|
||||||
|
stream->stsc_sample_index = 0;
|
||||||
|
stream->stsc_chunk_index++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (j = first_chunk; j < last_chunk; j++) {
|
for (j = stream->stsc_chunk_index; j < stream->last_chunk; j++) {
|
||||||
if (j > n)
|
if (j > n)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
stream->samples[j].offset =
|
stream->samples[j].offset =
|
||||||
qt_atom_parser_get_offset_unchecked (&co_chunk, stream->co_size);
|
qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
|
||||||
|
stream->co_size);
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
|
GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
|
||||||
"%" G_GUINT64_FORMAT, j, stream->samples[j].offset);
|
"%" G_GUINT64_FORMAT, j, stream->samples[j].offset);
|
||||||
|
|
||||||
if (stream->samples_per_frame * stream->bytes_per_frame) {
|
if (stream->samples_per_frame * stream->bytes_per_frame) {
|
||||||
stream->samples[j].size = (samples_per_chunk * stream->n_channels) /
|
stream->samples[j].size =
|
||||||
|
(stream->samples_per_chunk * stream->n_channels) /
|
||||||
stream->samples_per_frame * stream->bytes_per_frame;
|
stream->samples_per_frame * stream->bytes_per_frame;
|
||||||
} else {
|
} else {
|
||||||
stream->samples[j].size = samples_per_chunk;
|
stream->samples[j].size = stream->samples_per_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
|
||||||
", size %u", j, GST_TIME_ARGS (timestamp), stream->samples[j].size);
|
", size %u", j, GST_TIME_ARGS (stream->stco_timestamp),
|
||||||
|
stream->samples[j].size);
|
||||||
|
|
||||||
stream->samples[j].timestamp = timestamp;
|
stream->samples[j].timestamp = stream->stco_timestamp;
|
||||||
sample_index += samples_per_chunk;
|
stream->stco_sample_index += stream->samples_per_chunk;
|
||||||
|
|
||||||
timestamp = gst_util_uint64_scale (sample_index,
|
stream->stco_timestamp =
|
||||||
GST_SECOND, stream->timescale);
|
gst_util_uint64_scale (stream->stco_sample_index, GST_SECOND,
|
||||||
stream->samples[j].duration = timestamp - stream->samples[j].timestamp;
|
stream->timescale);
|
||||||
|
stream->samples[j].duration =
|
||||||
|
stream->stco_timestamp - stream->samples[j].timestamp;
|
||||||
|
|
||||||
stream->samples[j].keyframe = TRUE;
|
stream->samples[j].keyframe = TRUE;
|
||||||
|
stream->stsc_chunk_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stream->stsc_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream->chunks_are_chunks)
|
if (!stream->chunks_are_chunks)
|
||||||
goto ctts;
|
goto ctts;
|
||||||
done2:
|
done2:
|
||||||
{
|
{
|
||||||
guint32 time;
|
index = stream->stbl_index;
|
||||||
|
for (i = stream->stts_index; i < stream->n_sample_times; i++) {
|
||||||
|
if (stream->stts_sample_index >= stream->stts_samples
|
||||||
|
|| !stream->stts_sample_index) {
|
||||||
|
stream->stts_samples =
|
||||||
|
gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
|
||||||
|
stream->stts_duration =
|
||||||
|
gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
|
||||||
|
GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u ", i,
|
||||||
|
stream->stts_samples, stream->stts_duration);
|
||||||
|
|
||||||
timestamp = 0;
|
/* take first duration for fps */
|
||||||
stream->min_duration = 0;
|
if (G_UNLIKELY (stream->min_duration == 0))
|
||||||
time = 0;
|
stream->min_duration = stream->stts_duration;
|
||||||
index = 0;
|
|
||||||
for (i = 0; i < stream->n_sample_times; i++) {
|
|
||||||
guint32 stts_samples;
|
|
||||||
guint32 duration;
|
|
||||||
|
|
||||||
stts_samples = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
|
stream->stts_sample_index = 0;
|
||||||
duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
|
}
|
||||||
GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u ", i,
|
|
||||||
stts_samples, duration);
|
|
||||||
|
|
||||||
/* take first duration for fps */
|
for (j = stream->stts_sample_index; j < stream->stts_samples; j++) {
|
||||||
if (G_UNLIKELY (stream->min_duration == 0))
|
|
||||||
stream->min_duration = duration;
|
|
||||||
|
|
||||||
for (j = 0; j < stts_samples; j++) {
|
|
||||||
GST_DEBUG_OBJECT (qtdemux,
|
GST_DEBUG_OBJECT (qtdemux,
|
||||||
"sample %d: index %d, timestamp %" GST_TIME_FORMAT, index, j,
|
"sample %d: index %d, timestamp %" GST_TIME_FORMAT, index, j,
|
||||||
GST_TIME_ARGS (timestamp));
|
GST_TIME_ARGS (stream->stts_timestamp));
|
||||||
|
|
||||||
stream->samples[index].timestamp = timestamp;
|
stream->samples[index].timestamp = stream->stts_timestamp;
|
||||||
/* add non-scaled values to avoid rounding errors */
|
/* add non-scaled values to avoid rounding errors */
|
||||||
time += duration;
|
stream->stts_time += stream->stts_duration;
|
||||||
timestamp = gst_util_uint64_scale (time, GST_SECOND, stream->timescale);
|
stream->stts_timestamp =
|
||||||
|
gst_util_uint64_scale (stream->stts_time, GST_SECOND,
|
||||||
|
stream->timescale);
|
||||||
stream->samples[index].duration =
|
stream->samples[index].duration =
|
||||||
timestamp - stream->samples[index].timestamp;
|
stream->stts_timestamp - stream->samples[index].timestamp;
|
||||||
|
|
||||||
|
stream->stts_sample_index++;
|
||||||
index++;
|
index++;
|
||||||
if (G_UNLIKELY (index > n))
|
if (G_UNLIKELY (index > n))
|
||||||
goto done3;
|
goto done3;
|
||||||
}
|
}
|
||||||
|
stream->stts_index++;
|
||||||
}
|
}
|
||||||
/* fill up empty timestamps with the last timestamp, this can happen when
|
/* fill up empty timestamps with the last timestamp, this can happen when
|
||||||
* the last samples do not decode and so we don't have timestamps for them.
|
* the last samples do not decode and so we don't have timestamps for them.
|
||||||
* We however look at the last timestamp to estimate the track length so we
|
* We however look at the last timestamp to estimate the track length so we
|
||||||
* need something in here. */
|
* need something in here. */
|
||||||
for (; index < stream->n_samples; index++) {
|
for (; index < n; index++) {
|
||||||
GST_DEBUG_OBJECT (qtdemux,
|
GST_DEBUG_OBJECT (qtdemux,
|
||||||
"fill sample %d: timestamp %" GST_TIME_FORMAT, index,
|
"fill sample %d: timestamp %" GST_TIME_FORMAT, index,
|
||||||
GST_TIME_ARGS (timestamp));
|
GST_TIME_ARGS (stream->stts_timestamp));
|
||||||
stream->samples[index].timestamp = timestamp;
|
stream->samples[index].timestamp = stream->stts_timestamp;
|
||||||
stream->samples[index].duration = -1;
|
stream->samples[index].duration = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4103,14 +4155,15 @@ done3:
|
||||||
if (!stream->n_sample_syncs) {
|
if (!stream->n_sample_syncs) {
|
||||||
stream->all_keyframe = TRUE;
|
stream->all_keyframe = TRUE;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < stream->n_sample_syncs; i++) {
|
for (i = stream->stss_index; i < stream->n_sample_syncs; i++) {
|
||||||
if (G_UNLIKELY (gst_byte_reader_peek_uint32_be_unchecked
|
if (G_UNLIKELY (gst_byte_reader_peek_uint32_be_unchecked
|
||||||
(&stream->stss) > n))
|
(&stream->stss) - 1 > n))
|
||||||
break;
|
break;
|
||||||
/* note that the first sample is index 1, not 0 */
|
/* note that the first sample is index 1, not 0 */
|
||||||
index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
|
index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
|
||||||
if (G_LIKELY (index > 0 && index <= stream->n_samples))
|
if (G_LIKELY (index > 0 && index <= stream->n_samples))
|
||||||
stream->samples[index - 1].keyframe = TRUE;
|
stream->samples[index - 1].keyframe = TRUE;
|
||||||
|
stream->stss_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4119,14 +4172,15 @@ done3:
|
||||||
/* if there are no entries, the stss table contains the real
|
/* if there are no entries, the stss table contains the real
|
||||||
* sync samples */
|
* sync samples */
|
||||||
if (stream->n_sample_partial_syncs) {
|
if (stream->n_sample_partial_syncs) {
|
||||||
for (i = 0; i < stream->n_sample_partial_syncs; i++) {
|
for (i = stream->stps_index; i < stream->n_sample_partial_syncs; i++) {
|
||||||
if (G_UNLIKELY (gst_byte_reader_peek_uint32_be_unchecked
|
if (G_UNLIKELY (gst_byte_reader_peek_uint32_be_unchecked
|
||||||
(&stream->stps) > n))
|
(&stream->stps) - 1 > n))
|
||||||
break;
|
break;
|
||||||
/* note that the first sample is index 1, not 0 */
|
/* note that the first sample is index 1, not 0 */
|
||||||
index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
|
index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
|
||||||
if (G_LIKELY (index > 0 && index <= stream->n_samples))
|
if (G_LIKELY (index > 0 && index <= stream->n_samples))
|
||||||
stream->samples[index - 1].keyframe = TRUE;
|
stream->samples[index - 1].keyframe = TRUE;
|
||||||
|
stream->stps_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4139,25 +4193,32 @@ done3:
|
||||||
ctts:
|
ctts:
|
||||||
/* composition time to sample */
|
/* composition time to sample */
|
||||||
if (stream->ctts_present == TRUE) {
|
if (stream->ctts_present == TRUE) {
|
||||||
guint32 count;
|
|
||||||
gint32 soffset;
|
|
||||||
|
|
||||||
/* Fill in the pts_offsets */
|
/* Fill in the pts_offsets */
|
||||||
index = 0;
|
index = stream->stbl_index;
|
||||||
for (i = 0; i < stream->n_composition_times; i++) {
|
for (i = stream->ctts_index; i < stream->n_composition_times; i++) {
|
||||||
count = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
if (stream->ctts_sample_index >= stream->ctts_count
|
||||||
soffset = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
|| !stream->ctts_sample_index) {
|
||||||
for (j = 0; j < count; j++) {
|
stream->ctts_count =
|
||||||
|
gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
||||||
|
stream->ctts_soffset =
|
||||||
|
gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
|
||||||
|
stream->ctts_sample_index = 0;
|
||||||
|
}
|
||||||
|
for (j = stream->ctts_sample_index; j < stream->ctts_count; j++) {
|
||||||
/* we operate with very small soffset values here, it shouldn't overflow */
|
/* we operate with very small soffset values here, it shouldn't overflow */
|
||||||
stream->samples[index].pts_offset =
|
stream->samples[index].pts_offset =
|
||||||
soffset * GST_SECOND / stream->timescale;
|
stream->ctts_soffset * GST_SECOND / stream->timescale;
|
||||||
|
stream->ctts_sample_index++;
|
||||||
index++;
|
index++;
|
||||||
if (G_UNLIKELY (index > n))
|
if (G_UNLIKELY (index > n))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
stream->ctts_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
stream->stbl_index = n;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
|
Loading…
Reference in a new issue