From be1c97d3c920750c36a5ee04cc52166f4260ba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 13 Jan 2020 11:55:42 +0200 Subject: [PATCH] qtdemux: Add a minimum buffer size for raw audio to not output one buffer per frame Outputting 48000 buffers per second is not a good idea performance-wise. If a container sample is less than 1024 raw audio frames, combine multiple samples to get at least 1024 raw audio samples as long as they're stored contiguous in the file. For the other direction, if a container sample contains more than 4096 samples there is already code for splitting them up. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692750 --- gst/isomp4/qtdemux.c | 64 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 086bd92c1e..0ad9178529 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -322,6 +322,8 @@ struct _QtDemuxStream * streams which have got exceedingly big * sample size (such as 24s of raw audio). * Only used when max_buffer_size is non-NULL */ + guint32 min_buffer_size; /* Minimum allowed size for output buffers. + * Currently only set for raw audio streams*/ guint32 max_buffer_size; /* Maximum allowed size for output buffers. * Currently only set for raw audio streams*/ @@ -6314,6 +6316,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) GstClockTime duration = 0; gboolean keyframe = FALSE; guint sample_size = 0; + guint num_samples = 1; gboolean empty = 0; guint size; gint i; @@ -6457,14 +6460,58 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)) goto next; - if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) { - size = sample_size; - } else { + if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) { GST_DEBUG_OBJECT (qtdemux, "size %d larger than stream max_buffer_size %d, trimming", sample_size, stream->max_buffer_size); size = MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size); + } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0 + && sample_size < stream->min_buffer_size) { + guint start_sample_index = stream->sample_index; + guint accumulated_size = sample_size; + guint64 expected_next_offset = offset + sample_size; + + GST_DEBUG_OBJECT (qtdemux, + "size %d smaller than stream min_buffer_size %d, combining with the next", + sample_size, stream->min_buffer_size); + + while (stream->sample_index < stream->to_sample + && stream->sample_index + 1 < stream->n_samples) { + const QtDemuxSample *next_sample; + + /* Increment temporarily */ + stream->sample_index++; + + /* Failed to parse sample so let's go back to the previous one that was + * still successful */ + if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) { + stream->sample_index--; + break; + } + + next_sample = &stream->samples[stream->sample_index]; + + /* Not contiguous with the previous sample so let's go back to the + * previous one that was still successful */ + if (next_sample->offset != expected_next_offset) { + stream->sample_index--; + break; + } + + accumulated_size += next_sample->size; + expected_next_offset += next_sample->size; + if (accumulated_size >= stream->min_buffer_size) + break; + } + + num_samples = stream->sample_index + 1 - start_sample_index; + stream->sample_index = start_sample_index; + GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once", + num_samples, accumulated_size); + size = accumulated_size; + } else { + size = sample_size; } if (qtdemux->cenc_aux_info_offset > 0) { @@ -6506,6 +6553,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; + /* Update for both splitting and combining of samples */ if (size != sample_size) { pts += gst_util_uint64_scale_int (GST_SECOND, stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame, @@ -6522,7 +6570,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf, dts, pts, duration, keyframe, min_time, offset); - if (size != sample_size) { + if (size < sample_size) { QtDemuxSample *sample = &stream->samples[stream->sample_index]; QtDemuxSegment *segment = &stream->segments[stream->segment_index]; @@ -6540,6 +6588,10 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) * decode the first sample of the segment. */ stream->time_position = segment->time; } + } else if (size > sample_size) { + /* Increase to the last sample we already pulled so that advancing + * below brings us to the next sample we need to pull */ + stream->sample_index += num_samples - 1; } /* combine flows */ @@ -15490,8 +15542,10 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, name = gst_structure_get_name (s); if (g_str_has_prefix (name, "audio/x-raw")) { stream->need_clip = TRUE; + stream->min_buffer_size = 1024 * entry->bytes_per_frame; stream->max_buffer_size = 4096 * entry->bytes_per_frame; - GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size); + GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size, + stream->max_buffer_size); } return caps; }