mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 00:06:36 +00:00
qtdemux: Separate off stbl sub-atom initialisation
This commit is contained in:
parent
6a6d2c4970
commit
1f7b878d89
1 changed files with 150 additions and 110 deletions
|
@ -271,9 +271,14 @@ struct _QtDemuxStream
|
||||||
/* stts */
|
/* stts */
|
||||||
guint32 n_sample_times;
|
guint32 n_sample_times;
|
||||||
/* stss */
|
/* stss */
|
||||||
|
gboolean stss_present;
|
||||||
guint32 n_sample_syncs;
|
guint32 n_sample_syncs;
|
||||||
/* stps */
|
/* stps */
|
||||||
|
gboolean stps_present;
|
||||||
guint32 n_sample_partial_syncs;
|
guint32 n_sample_partial_syncs;
|
||||||
|
/* ctts */
|
||||||
|
gboolean ctts_present;
|
||||||
|
guint32 n_composition_times;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum QtDemuxState
|
enum QtDemuxState
|
||||||
|
@ -3734,26 +3739,93 @@ too_many_streams:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collect all samples for @stream by reading the info from @stbl
|
/* initialise bytereaders for stbl sub-atoms */
|
||||||
*/
|
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
|
||||||
GNode * stbl)
|
|
||||||
{
|
{
|
||||||
int sample_index = 0;
|
/* time-to-sample atom */
|
||||||
gint i, j, k;
|
if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
|
||||||
int index = 0;
|
goto corrupt_file;
|
||||||
guint64 timestamp = 0;
|
|
||||||
|
|
||||||
/* sample to chunk */
|
/* skip version + flags */
|
||||||
|
if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
|
||||||
|
!gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
|
||||||
|
goto corrupt_file;
|
||||||
|
GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
|
||||||
|
|
||||||
|
/* make sure there's enough data */
|
||||||
|
if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
|
||||||
|
/* sync sample atom */
|
||||||
|
stream->stps_present = FALSE;
|
||||||
|
if ((stream->stss_present =
|
||||||
|
!!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
|
||||||
|
&stream->stss) ? TRUE : FALSE) == TRUE) {
|
||||||
|
/* skip version + flags */
|
||||||
|
if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
|
||||||
|
!gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
if (stream->n_sample_syncs) {
|
||||||
|
/* make sure there's enough data */
|
||||||
|
if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
|
||||||
|
goto corrupt_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* partial sync sample atom */
|
||||||
|
if ((stream->stps_present =
|
||||||
|
!!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
|
||||||
|
&stream->stps) ? TRUE : FALSE) == TRUE) {
|
||||||
|
/* skip version + flags */
|
||||||
|
if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
|
||||||
|
!gst_byte_reader_get_uint32_be (&stream->stps,
|
||||||
|
&stream->n_sample_partial_syncs))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
/* if there are no entries, the stss table contains the real
|
||||||
|
* sync samples */
|
||||||
|
if (stream->n_sample_partial_syncs) {
|
||||||
|
/* make sure there's enough data */
|
||||||
|
if (!qt_atom_parser_has_chunks (&stream->stps,
|
||||||
|
stream->n_sample_partial_syncs, 4))
|
||||||
|
goto corrupt_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* sample-to-chunk atom */
|
||||||
if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
|
if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
|
/* skip version + flags */
|
||||||
|
if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
|
||||||
|
!gst_byte_reader_get_uint32_be (&stream->stsc,
|
||||||
|
&stream->n_samples_per_chunk))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
|
||||||
|
stream->n_samples_per_chunk);
|
||||||
|
|
||||||
|
/* make sure there's enough data */
|
||||||
|
if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
|
||||||
|
12))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
|
||||||
/* sample size */
|
/* sample size */
|
||||||
if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
|
if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
/* chunk offsets */
|
/* skip version + flags */
|
||||||
|
if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
|
||||||
|
!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
|
||||||
|
/* chunk offset */
|
||||||
if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
|
if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
|
||||||
stream->co_size = sizeof (guint32);
|
stream->co_size = sizeof (guint32);
|
||||||
else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
|
else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
|
||||||
|
@ -3762,18 +3834,11 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
else
|
else
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
/* sample time */
|
|
||||||
if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
|
|
||||||
!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
/* skip version + flags */
|
/* skip version + flags */
|
||||||
if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
|
if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
|
/* chunks_are_chunks == 0 means treat chunks as samples */
|
||||||
stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
|
stream->chunks_are_chunks = !stream->sample_size || stream->sampled;
|
||||||
if (stream->chunks_are_chunks) {
|
if (stream->chunks_are_chunks) {
|
||||||
/* skip number of entries */
|
/* skip number of entries */
|
||||||
|
@ -3782,37 +3847,85 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
|
|
||||||
if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
|
if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
|
/* make sure there are enough data in the stsz atom */
|
||||||
|
if (!stream->sample_size) {
|
||||||
|
/* different sizes for each sample */
|
||||||
|
if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
|
||||||
|
goto corrupt_file;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* treat chunks as samples */
|
/* treat chunks as samples */
|
||||||
if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
|
if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream->n_samples)
|
if (!stream->n_samples) {
|
||||||
goto no_samples;
|
GST_WARNING_OBJECT (qtdemux, "stream has no samples");
|
||||||
|
return FALSE;
|
||||||
if (stream->chunks_are_chunks)
|
}
|
||||||
GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0");
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u (%u MB)",
|
GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u (%u MB)",
|
||||||
stream->n_samples,
|
stream->n_samples,
|
||||||
(guint) (stream->n_samples * sizeof (QtDemuxSample)) >> 20);
|
(guint) (stream->n_samples * sizeof (QtDemuxSample)) >> 20);
|
||||||
|
|
||||||
if (stream->n_samples >=
|
if (stream->n_samples >=
|
||||||
QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
|
QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
|
||||||
goto index_too_big;
|
GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
|
||||||
|
"be larger than %uMB (broken file?)", stream->n_samples,
|
||||||
|
QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
|
stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
|
||||||
if (!stream->samples)
|
if (!stream->samples) {
|
||||||
goto out_of_memory;
|
GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
|
||||||
|
stream->n_samples);
|
||||||
|
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) {
|
||||||
|
/* skip version + flags */
|
||||||
|
if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
|
||||||
|
|| !gst_byte_reader_get_uint32_be (&stream->ctts,
|
||||||
|
&stream->n_composition_times))
|
||||||
|
goto corrupt_file;
|
||||||
|
|
||||||
|
/* make sure there's enough data */
|
||||||
|
if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
|
||||||
|
4 + 4))
|
||||||
|
goto corrupt_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
corrupt_file:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
|
||||||
|
(_("This file is corrupt and cannot be played.")), (NULL));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* collect all samples for @stream by reading the info from @stbl
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream)
|
||||||
|
{
|
||||||
|
int sample_index = 0;
|
||||||
|
gint i, j, k;
|
||||||
|
int index = 0;
|
||||||
|
guint64 timestamp = 0;
|
||||||
|
|
||||||
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 */
|
||||||
if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
for (i = 0; i < stream->n_samples; i++) {
|
for (i = 0; i < stream->n_samples; 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);
|
||||||
|
@ -3827,21 +3940,6 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the sample offsets in the file */
|
|
||||||
if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
|
|
||||||
!gst_byte_reader_get_uint32_be (&stream->stsc,
|
|
||||||
&stream->n_samples_per_chunk))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
if (!stream->chunks_are_chunks) {
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
|
|
||||||
stream->n_samples_per_chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
|
|
||||||
12))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
for (i = 0; i < stream->n_samples_per_chunk; i++) {
|
for (i = 0; i < stream->n_samples_per_chunk; i++) {
|
||||||
GstByteReader co_chunk;
|
GstByteReader co_chunk;
|
||||||
guint32 first_chunk, last_chunk;
|
guint32 first_chunk, last_chunk;
|
||||||
|
@ -3945,17 +4043,6 @@ done2:
|
||||||
{
|
{
|
||||||
guint32 time;
|
guint32 time;
|
||||||
|
|
||||||
if (!gst_byte_reader_skip (&stream->stts, 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
if (!gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
|
|
||||||
goto corrupt_file;
|
|
||||||
GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
|
|
||||||
|
|
||||||
/* make sure there's enough data */
|
|
||||||
if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times,
|
|
||||||
2 * 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
timestamp = 0;
|
timestamp = 0;
|
||||||
stream->min_duration = 0;
|
stream->min_duration = 0;
|
||||||
time = 0;
|
time = 0;
|
||||||
|
@ -4005,22 +4092,10 @@ done2:
|
||||||
done3:
|
done3:
|
||||||
{
|
{
|
||||||
/* sample sync, can be NULL */
|
/* sample sync, can be NULL */
|
||||||
if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss, &stream->stss)) {
|
if (stream->stss_present == TRUE) {
|
||||||
|
|
||||||
/* mark keyframes */
|
|
||||||
if (!gst_byte_reader_skip (&stream->stss, 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
if (!gst_byte_reader_get_uint32_be (&stream->stss,
|
|
||||||
&stream->n_sample_syncs))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
if (!stream->n_sample_syncs) {
|
if (!stream->n_sample_syncs) {
|
||||||
stream->all_keyframe = TRUE;
|
stream->all_keyframe = TRUE;
|
||||||
} else {
|
} else {
|
||||||
/* make sure there's enough data */
|
|
||||||
if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs,
|
|
||||||
4))
|
|
||||||
goto corrupt_file;
|
|
||||||
for (i = 0; i < stream->n_sample_syncs; i++) {
|
for (i = 0; i < stream->n_sample_syncs; i++) {
|
||||||
/* 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);
|
||||||
|
@ -4028,23 +4103,12 @@ done3:
|
||||||
stream->samples[index - 1].keyframe = TRUE;
|
stream->samples[index - 1].keyframe = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stps marks partial sync frames like open GOP I-Frames */
|
/* stps marks partial sync frames like open GOP I-Frames */
|
||||||
if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
|
if (stream->stps_present == TRUE) {
|
||||||
&stream->stps)) {
|
|
||||||
|
|
||||||
if (!gst_byte_reader_skip (&stream->stps, 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
if (!gst_byte_reader_get_uint32_be (&stream->stps,
|
|
||||||
&stream->n_sample_partial_syncs))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
/* 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) {
|
||||||
/* make sure there's enough data */
|
|
||||||
if (!qt_atom_parser_has_chunks (&stream->stps,
|
|
||||||
stream->n_sample_partial_syncs, 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
for (i = 0; i < stream->n_sample_partial_syncs; i++) {
|
for (i = 0; i < stream->n_sample_partial_syncs; i++) {
|
||||||
/* 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);
|
||||||
|
@ -4061,20 +4125,13 @@ done3:
|
||||||
|
|
||||||
ctts:
|
ctts:
|
||||||
/* composition time to sample */
|
/* composition time to sample */
|
||||||
if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts, &stream->ctts)) {
|
if (stream->ctts_present == TRUE) {
|
||||||
guint32 n_entries;
|
|
||||||
guint32 count;
|
guint32 count;
|
||||||
gint32 soffset;
|
gint32 soffset;
|
||||||
|
|
||||||
gst_byte_reader_skip (&stream->ctts, 1 + 3);
|
|
||||||
n_entries = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
|
||||||
|
|
||||||
if (!qt_atom_parser_has_chunks (&stream->ctts, n_entries, 4 + 4))
|
|
||||||
goto corrupt_file;
|
|
||||||
|
|
||||||
/* Fill in the pts_offsets */
|
/* Fill in the pts_offsets */
|
||||||
index = 0;
|
index = 0;
|
||||||
for (i = 0; i < n_entries; i++) {
|
for (i = 0; i < stream->n_composition_times; i++) {
|
||||||
count = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
count = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
||||||
soffset = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
soffset = gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
|
||||||
for (j = 0; j < count; j++) {
|
for (j = 0; j < count; j++) {
|
||||||
|
@ -4097,24 +4154,6 @@ corrupt_file:
|
||||||
(_("This file is corrupt and cannot be played.")), (NULL));
|
(_("This file is corrupt and cannot be played.")), (NULL));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
no_samples:
|
|
||||||
{
|
|
||||||
GST_WARNING_OBJECT (qtdemux, "stream has no samples");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
out_of_memory:
|
|
||||||
{
|
|
||||||
GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
|
|
||||||
stream->n_samples);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
index_too_big:
|
|
||||||
{
|
|
||||||
GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
|
|
||||||
"be larger than %uMB (broken file?)", stream->n_samples,
|
|
||||||
QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collect all segment info for @stream.
|
/* collect all segment info for @stream.
|
||||||
|
@ -5177,7 +5216,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collect sample information */
|
/* collect sample information */
|
||||||
if (!qtdemux_parse_samples (qtdemux, stream, stbl))
|
if (!qtdemux_stbl_init (qtdemux, stream, stbl) ||
|
||||||
|
!qtdemux_parse_samples (qtdemux, stream))
|
||||||
goto samples_failed;
|
goto samples_failed;
|
||||||
|
|
||||||
/* configure segments */
|
/* configure segments */
|
||||||
|
|
Loading…
Reference in a new issue