mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-20 14:18:34 +00:00
qtdemux: add some more micro optimisations
This commit is contained in:
parent
ab0d1bc942
commit
1619c09e3e
1 changed files with 92 additions and 55 deletions
|
@ -83,7 +83,6 @@ struct _QtNode
|
||||||
|
|
||||||
struct _QtDemuxSample
|
struct _QtDemuxSample
|
||||||
{
|
{
|
||||||
guint32 chunk;
|
|
||||||
guint32 size;
|
guint32 size;
|
||||||
guint64 offset;
|
guint64 offset;
|
||||||
GstClockTimeDiff pts_offset; /* Add this value to timestamp to get the pts */
|
GstClockTimeDiff pts_offset; /* Add this value to timestamp to get the pts */
|
||||||
|
@ -2429,10 +2428,9 @@ next_entry_size (GstQTDemux * demux)
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (demux,
|
GST_LOG_OBJECT (demux,
|
||||||
"Checking Stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
|
"Checking Stream %d (sample_index:%d / offset:%lld / size:%d)",
|
||||||
i, stream->sample_index, stream->samples[stream->sample_index].offset,
|
i, stream->sample_index, stream->samples[stream->sample_index].offset,
|
||||||
stream->samples[stream->sample_index].size,
|
stream->samples[stream->sample_index].size);
|
||||||
stream->samples[stream->sample_index].chunk);
|
|
||||||
|
|
||||||
if (((smalloffs == -1)
|
if (((smalloffs == -1)
|
||||||
|| (stream->samples[stream->sample_index].offset < smalloffs))
|
|| (stream->samples[stream->sample_index].offset < smalloffs))
|
||||||
|
@ -2620,11 +2618,10 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
|
||||||
if (stream->sample_index >= stream->n_samples)
|
if (stream->sample_index >= stream->n_samples)
|
||||||
continue;
|
continue;
|
||||||
GST_LOG_OBJECT (demux,
|
GST_LOG_OBJECT (demux,
|
||||||
"Checking stream %d (sample_index:%d / offset:%lld / size:%d / chunk:%d)",
|
"Checking stream %d (sample_index:%d / offset:%lld / size:%d)",
|
||||||
i, stream->sample_index,
|
i, stream->sample_index,
|
||||||
stream->samples[stream->sample_index].offset,
|
stream->samples[stream->sample_index].offset,
|
||||||
stream->samples[stream->sample_index].size,
|
stream->samples[stream->sample_index].size);
|
||||||
stream->samples[stream->sample_index].chunk);
|
|
||||||
|
|
||||||
if (stream->samples[stream->sample_index].offset == demux->offset)
|
if (stream->samples[stream->sample_index].offset == demux->offset)
|
||||||
break;
|
break;
|
||||||
|
@ -3337,7 +3334,6 @@ static gboolean
|
||||||
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
GNode * stbl)
|
GNode * stbl)
|
||||||
{
|
{
|
||||||
int offset;
|
|
||||||
GNode *stsc;
|
GNode *stsc;
|
||||||
GNode *stsz;
|
GNode *stsz;
|
||||||
GNode *stco;
|
GNode *stco;
|
||||||
|
@ -3346,7 +3342,7 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
GNode *stss;
|
GNode *stss;
|
||||||
GNode *stps;
|
GNode *stps;
|
||||||
GNode *ctts;
|
GNode *ctts;
|
||||||
const guint8 *stsc_data, *stsz_data, *stco_data;
|
const guint8 *stsc_data, *stsz_data, *stco_data, *co64_data, *stts_data;
|
||||||
int sample_size;
|
int sample_size;
|
||||||
int sample_index;
|
int sample_index;
|
||||||
int n_samples;
|
int n_samples;
|
||||||
|
@ -3361,43 +3357,59 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc)))
|
if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc)))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
stsc_data = (const guint8 *) stsc->data;
|
stsc_data = (const guint8 *) stsc->data;
|
||||||
|
|
||||||
/* sample size */
|
/* sample size */
|
||||||
if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz)))
|
if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz)))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
stsz_data = (const guint8 *) stsz->data;
|
stsz_data = (const guint8 *) stsz->data;
|
||||||
|
|
||||||
/* chunk offsets */
|
/* chunk offsets */
|
||||||
stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
|
stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
|
||||||
co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
|
co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
|
||||||
if (stco) {
|
if (stco) {
|
||||||
stco_data = (const guint8 *) stco->data;
|
stco_data = (const guint8 *) stco->data;
|
||||||
|
co64_data = NULL;
|
||||||
} else {
|
} else {
|
||||||
stco_data = NULL;
|
stco_data = NULL;
|
||||||
if (co64 == NULL)
|
if (co64 == NULL)
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
co64_data = (const guint8 *) co64->data;
|
||||||
}
|
}
|
||||||
/* sample time */
|
/* sample time */
|
||||||
if (!(stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts)))
|
if (!(stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts)))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
stts_data = (const guint8 *) stts->data;
|
||||||
|
|
||||||
sample_size = QT_UINT32 (stsz_data + 12);
|
sample_size = QT_UINT32 (stsz_data + 12);
|
||||||
if (sample_size == 0 || stream->sampled) {
|
if (sample_size == 0 || stream->sampled) {
|
||||||
n_samples = QT_UINT32 (stsz_data + 16);
|
n_samples = QT_UINT32 (stsz_data + 16);
|
||||||
|
|
||||||
|
if (n_samples == 0)
|
||||||
|
goto no_samples;
|
||||||
|
|
||||||
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);
|
||||||
stream->n_samples = n_samples;
|
stream->n_samples = n_samples;
|
||||||
samples = g_new0 (QtDemuxSample, n_samples);
|
samples = g_new0 (QtDemuxSample, n_samples);
|
||||||
stream->samples = samples;
|
stream->samples = samples;
|
||||||
|
|
||||||
for (i = 0; i < n_samples; i++) {
|
/* set the sample sizes */
|
||||||
if (sample_size == 0)
|
if (sample_size == 0) {
|
||||||
samples[i].size = QT_UINT32 (stsz_data + i * 4 + 20);
|
const guint8 *stsz_p = stsz_data + 20;
|
||||||
else
|
/* different sizes for each sample */
|
||||||
|
for (i = 0; i < n_samples; i++) {
|
||||||
|
samples[i].size = QT_UINT32 (stsz_p);
|
||||||
|
GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
|
||||||
|
stsz_p += 4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* samples have the same size */
|
||||||
|
GST_LOG_OBJECT (qtdemux, "all samples have size %d", sample_size);
|
||||||
|
for (i = 0; i < n_samples; i++)
|
||||||
samples[i].size = sample_size;
|
samples[i].size = sample_size;
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
|
|
||||||
/* init other fields to defaults for this sample */
|
|
||||||
samples[i].keyframe = FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the sample offsets in the file */
|
||||||
n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
|
n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
|
||||||
index = 0;
|
index = 0;
|
||||||
for (i = 0; i < n_samples_per_chunk; i++) {
|
for (i = 0; i < n_samples_per_chunk; i++) {
|
||||||
|
@ -3405,7 +3417,7 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
guint32 samples_per_chunk;
|
guint32 samples_per_chunk;
|
||||||
|
|
||||||
first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
|
first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
|
||||||
if (i == n_samples_per_chunk - 1) {
|
if (G_UNLIKELY (i == n_samples_per_chunk - 1)) {
|
||||||
last_chunk = G_MAXUINT32;
|
last_chunk = G_MAXUINT32;
|
||||||
} else {
|
} else {
|
||||||
last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
|
last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
|
||||||
|
@ -3418,49 +3430,56 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
if (stco) {
|
if (stco) {
|
||||||
chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
|
chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
|
||||||
} else {
|
} else {
|
||||||
chunk_offset = QT_UINT64 ((guint8 *) co64->data + 16 + j * 8);
|
chunk_offset = QT_UINT64 (co64_data + 16 + j * 8);
|
||||||
}
|
}
|
||||||
for (k = 0; k < samples_per_chunk; k++) {
|
for (k = 0; k < samples_per_chunk; k++) {
|
||||||
GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
|
GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
|
||||||
index, chunk_offset);
|
index, chunk_offset);
|
||||||
samples[index].chunk = j;
|
|
||||||
samples[index].offset = chunk_offset;
|
samples[index].offset = chunk_offset;
|
||||||
chunk_offset += samples[index].size;
|
chunk_offset += samples[index].size;
|
||||||
index++;
|
index++;
|
||||||
if (index >= n_samples)
|
if (G_UNLIKELY (index >= n_samples))
|
||||||
goto done2;
|
goto done2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done2:
|
done2:
|
||||||
|
|
||||||
n_sample_times = QT_UINT32 ((guint8 *) stts->data + 12);
|
n_sample_times = QT_UINT32 (stts_data + 12);
|
||||||
timestamp = 0;
|
timestamp = 0;
|
||||||
stream->min_duration = 0;
|
stream->min_duration = 0;
|
||||||
time = 0;
|
time = 0;
|
||||||
index = 0;
|
index = 0;
|
||||||
for (i = 0; (i < n_sample_times) && (index < stream->n_samples); i++) {
|
stts_data += 16;
|
||||||
|
for (i = 0; i < n_sample_times; i++) {
|
||||||
guint32 n;
|
guint32 n;
|
||||||
guint32 duration;
|
guint32 duration;
|
||||||
|
|
||||||
n = QT_UINT32 ((guint8 *) stts->data + 16 + 8 * i);
|
n = QT_UINT32 (stts_data);
|
||||||
duration = QT_UINT32 ((guint8 *) stts->data + 16 + 8 * i + 4);
|
stts_data += 4;
|
||||||
for (j = 0; (j < n) && (index < stream->n_samples); j++) {
|
duration = QT_UINT32 (stts_data);
|
||||||
|
stts_data += 4;
|
||||||
|
|
||||||
|
/* take first duration for fps */
|
||||||
|
if (G_UNLIKELY (stream->min_duration == 0))
|
||||||
|
stream->min_duration = duration;
|
||||||
|
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT,
|
||||||
index, GST_TIME_ARGS (timestamp));
|
index, GST_TIME_ARGS (timestamp));
|
||||||
|
|
||||||
samples[index].timestamp = timestamp;
|
samples[index].timestamp = timestamp;
|
||||||
/* take first duration for fps */
|
|
||||||
if (stream->min_duration == 0)
|
|
||||||
stream->min_duration = duration;
|
|
||||||
/* add non-scaled values to avoid rounding errors */
|
/* add non-scaled values to avoid rounding errors */
|
||||||
time += duration;
|
time += duration;
|
||||||
timestamp = gst_util_uint64_scale (time, GST_SECOND, stream->timescale);
|
timestamp = gst_util_uint64_scale (time, GST_SECOND, stream->timescale);
|
||||||
samples[index].duration = timestamp - samples[index].timestamp;
|
samples[index].duration = timestamp - samples[index].timestamp;
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
|
if (G_UNLIKELY (index >= n_samples))
|
||||||
|
goto done3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
done3:
|
||||||
|
|
||||||
/* sample sync, can be NULL */
|
/* sample sync, can be NULL */
|
||||||
stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
|
stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
|
||||||
|
@ -3468,38 +3487,39 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
if (stss) {
|
if (stss) {
|
||||||
/* mark keyframes */
|
/* mark keyframes */
|
||||||
guint32 n_sample_syncs;
|
guint32 n_sample_syncs;
|
||||||
|
const guint8 *stss_p = (guint8 *) stss->data;
|
||||||
|
|
||||||
n_sample_syncs = QT_UINT32 ((guint8 *) stss->data + 12);
|
stss_p += 12;
|
||||||
|
n_sample_syncs = QT_UINT32 (stss_p);
|
||||||
if (n_sample_syncs == 0) {
|
if (n_sample_syncs == 0) {
|
||||||
stream->all_keyframe = TRUE;
|
stream->all_keyframe = TRUE;
|
||||||
} else {
|
} else {
|
||||||
offset = 16;
|
|
||||||
for (i = 0; i < n_sample_syncs; i++) {
|
for (i = 0; i < n_sample_syncs; i++) {
|
||||||
|
stss_p += 4;
|
||||||
/* note that the first sample is index 1, not 0 */
|
/* note that the first sample is index 1, not 0 */
|
||||||
index = QT_UINT32 ((guint8 *) stss->data + offset);
|
index = QT_UINT32 (stss_p);
|
||||||
if (index > 0 && index <= stream->n_samples) {
|
if (G_LIKELY (index > 0 && index <= n_samples))
|
||||||
samples[index - 1].keyframe = TRUE;
|
samples[index - 1].keyframe = TRUE;
|
||||||
offset += 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stps = qtdemux_tree_get_child_by_type (stbl, FOURCC_stps);
|
stps = qtdemux_tree_get_child_by_type (stbl, FOURCC_stps);
|
||||||
if (stps) {
|
if (stps) {
|
||||||
/* mark keyframes */
|
/* stps marks partial sync frames like open GOP I-Frames */
|
||||||
guint32 n_sample_syncs;
|
guint32 n_sample_syncs;
|
||||||
|
const guint8 *stps_p = (guint8 *) stps->data;
|
||||||
|
|
||||||
n_sample_syncs = QT_UINT32 ((guint8 *) stps->data + 12);
|
stps_p += 12;
|
||||||
if (n_sample_syncs == 0) {
|
n_sample_syncs = QT_UINT32 (stps_p);
|
||||||
//stream->all_keyframe = TRUE;
|
if (n_sample_syncs != 0) {
|
||||||
|
/* no entries, the stss table contains the real sync
|
||||||
|
* samples */
|
||||||
} else {
|
} else {
|
||||||
offset = 16;
|
|
||||||
for (i = 0; i < n_sample_syncs; i++) {
|
for (i = 0; i < n_sample_syncs; i++) {
|
||||||
|
stps_p += 4;
|
||||||
/* note that the first sample is index 1, not 0 */
|
/* note that the first sample is index 1, not 0 */
|
||||||
index = QT_UINT32 ((guint8 *) stps->data + offset);
|
index = QT_UINT32 (stps_p);
|
||||||
if (index > 0 && index <= stream->n_samples) {
|
if (G_LIKELY (index > 0 && index <= n_samples))
|
||||||
samples[index - 1].keyframe = TRUE;
|
samples[index - 1].keyframe = TRUE;
|
||||||
offset += 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3510,13 +3530,16 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
} else {
|
} else {
|
||||||
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);
|
||||||
|
|
||||||
/* treat chunks as samples */
|
/* treat chunks as samples */
|
||||||
if (stco) {
|
if (stco) {
|
||||||
n_samples = QT_UINT32 (stco_data + 12);
|
n_samples = QT_UINT32 (stco_data + 12);
|
||||||
} else {
|
} else {
|
||||||
n_samples = QT_UINT32 ((guint8 *) co64->data + 12);
|
n_samples = QT_UINT32 (co64_data + 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n_samples == 0)
|
||||||
|
goto no_samples;
|
||||||
|
|
||||||
stream->n_samples = n_samples;
|
stream->n_samples = n_samples;
|
||||||
GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
|
GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
|
||||||
samples = g_new0 (QtDemuxSample, n_samples);
|
samples = g_new0 (QtDemuxSample, n_samples);
|
||||||
|
@ -3554,13 +3577,12 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
if (stco) {
|
if (stco) {
|
||||||
chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
|
chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
|
||||||
} else {
|
} else {
|
||||||
chunk_offset = QT_UINT64 ((guint8 *) co64->data + 16 + j * 8);
|
chunk_offset = QT_UINT64 (co64_data + 16 + j * 8);
|
||||||
}
|
}
|
||||||
GST_LOG_OBJECT (qtdemux,
|
GST_LOG_OBJECT (qtdemux,
|
||||||
"Creating entry %d with offset %" G_GUINT64_FORMAT, j,
|
"Creating entry %d with offset %" G_GUINT64_FORMAT, j,
|
||||||
chunk_offset);
|
chunk_offset);
|
||||||
|
|
||||||
samples[j].chunk = j;
|
|
||||||
samples[j].offset = chunk_offset;
|
samples[j].offset = chunk_offset;
|
||||||
|
|
||||||
if (stream->samples_per_frame * stream->bytes_per_frame) {
|
if (stream->samples_per_frame * stream->bytes_per_frame) {
|
||||||
|
@ -3587,18 +3609,28 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
|
|
||||||
/* composition time to sample */
|
/* composition time to sample */
|
||||||
if ((ctts = qtdemux_tree_get_child_by_type (stbl, FOURCC_ctts))) {
|
if ((ctts = qtdemux_tree_get_child_by_type (stbl, FOURCC_ctts))) {
|
||||||
const guint8 *ctts_data = (const guint8 *) ctts->data;
|
const guint8 *ctts_data, *ctts_p;
|
||||||
guint32 n_entries = QT_UINT32 (ctts_data + 12);
|
guint32 n_entries;
|
||||||
guint32 count;
|
guint32 count;
|
||||||
gint32 soffset;
|
gint32 soffset;
|
||||||
|
|
||||||
|
ctts_data = (const guint8 *) ctts->data;
|
||||||
|
n_entries = QT_UINT32 (ctts_data + 12);
|
||||||
|
|
||||||
/* Fill in the pts_offsets */
|
/* Fill in the pts_offsets */
|
||||||
for (i = 0, j = 0; (j < stream->n_samples) && (i < n_entries); i++) {
|
index = 0;
|
||||||
count = QT_UINT32 (ctts_data + 16 + i * 8);
|
ctts_p = ctts_data + 16;
|
||||||
soffset = QT_UINT32 (ctts_data + 20 + i * 8);
|
for (i = 0; i < n_entries; i++) {
|
||||||
for (k = 0; (k < count) && (j < stream->n_samples); k++, j++) {
|
count = QT_UINT32 (ctts_p);
|
||||||
|
ctts_p += 4;
|
||||||
|
soffset = QT_UINT32 (ctts_p);
|
||||||
|
ctts_p += 4;
|
||||||
|
for (j = 0; j < 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 */
|
||||||
samples[j].pts_offset = soffset * GST_SECOND / stream->timescale;
|
samples[index].pts_offset = soffset * GST_SECOND / stream->timescale;
|
||||||
|
index++;
|
||||||
|
if (G_UNLIKELY (index >= n_samples))
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3612,6 +3644,11 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* collect all segment info for @stream.
|
/* collect all segment info for @stream.
|
||||||
|
|
Loading…
Reference in a new issue