mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-03 16:09:39 +00:00
qtdemux: split large raw audio samples
In order to deal with a file that has samples that are 24 seconds long. Seeking still doesn't work with such files.
This commit is contained in:
parent
364433c105
commit
5bd2864101
1 changed files with 67 additions and 8 deletions
|
@ -219,6 +219,8 @@ struct _QtDemuxStream
|
||||||
gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
|
gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
|
||||||
guint32 min_duration; /* duration in timescale of first sample, used for figuring out
|
guint32 min_duration; /* duration in timescale of first sample, used for figuring out
|
||||||
the framerate, in timescale units */
|
the framerate, in timescale units */
|
||||||
|
guint32 offset_in_sample;
|
||||||
|
guint32 max_buffer_size;
|
||||||
|
|
||||||
/* if we use chunks or samples */
|
/* if we use chunks or samples */
|
||||||
gboolean sampled;
|
gboolean sampled;
|
||||||
|
@ -1089,6 +1091,7 @@ gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
|
||||||
|
|
||||||
/* position changed, we have a discont */
|
/* position changed, we have a discont */
|
||||||
str->sample_index = index;
|
str->sample_index = index;
|
||||||
|
str->offset_in_sample = 0;
|
||||||
/* Each time we move in the stream we store the position where we are
|
/* Each time we move in the stream we store the position where we are
|
||||||
* starting from */
|
* starting from */
|
||||||
str->from_sample = index;
|
str->from_sample = index;
|
||||||
|
@ -1327,6 +1330,7 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
|
||||||
|
|
||||||
stream->time_position = desired_offset;
|
stream->time_position = desired_offset;
|
||||||
stream->sample_index = -1;
|
stream->sample_index = -1;
|
||||||
|
stream->offset_in_sample = 0;
|
||||||
stream->segment_index = -1;
|
stream->segment_index = -1;
|
||||||
stream->last_ret = GST_FLOW_OK;
|
stream->last_ret = GST_FLOW_OK;
|
||||||
stream->sent_eos = FALSE;
|
stream->sent_eos = FALSE;
|
||||||
|
@ -3303,6 +3307,7 @@ gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
|
||||||
|
|
||||||
/* move to next sample */
|
/* move to next sample */
|
||||||
stream->sample_index++;
|
stream->sample_index++;
|
||||||
|
stream->offset_in_sample = 0;
|
||||||
|
|
||||||
/* get current segment */
|
/* get current segment */
|
||||||
segment = &stream->segments[stream->segment_index];
|
segment = &stream->segments[stream->segment_index];
|
||||||
|
@ -3773,7 +3778,8 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
|
||||||
guint64 pts = GST_CLOCK_TIME_NONE;
|
guint64 pts = GST_CLOCK_TIME_NONE;
|
||||||
guint64 duration = 0;
|
guint64 duration = 0;
|
||||||
gboolean keyframe = FALSE;
|
gboolean keyframe = FALSE;
|
||||||
guint size = 0;
|
guint sample_size = 0;
|
||||||
|
guint size;
|
||||||
gint index;
|
gint index;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
|
@ -3830,23 +3836,33 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
|
||||||
|
|
||||||
/* fetch info for the current sample of this stream */
|
/* fetch info for the current sample of this stream */
|
||||||
if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
|
if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
|
||||||
&size, &dts, &pts, &duration, &keyframe)))
|
&sample_size, &dts, &pts, &duration, &keyframe)))
|
||||||
goto eos_stream;
|
goto eos_stream;
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux,
|
GST_DEBUG_OBJECT (qtdemux,
|
||||||
"pushing from stream %d, offset %" G_GUINT64_FORMAT
|
"pushing from stream %d, offset %" G_GUINT64_FORMAT
|
||||||
", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
|
", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
|
||||||
", duration %" GST_TIME_FORMAT, index, offset, size,
|
", duration %" GST_TIME_FORMAT, index, offset, sample_size,
|
||||||
GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
|
GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
|
||||||
|
|
||||||
/* hmm, empty sample, skip and move to next sample */
|
/* hmm, empty sample, skip and move to next sample */
|
||||||
if (G_UNLIKELY (size <= 0))
|
if (G_UNLIKELY (sample_size <= 0))
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
/* last pushed sample was out of boundary, goto next sample */
|
/* last pushed sample was out of boundary, goto next sample */
|
||||||
if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
|
if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
|
if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
|
||||||
|
size = sample_size;
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
|
GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
|
||||||
offset);
|
offset);
|
||||||
|
|
||||||
|
@ -3855,13 +3871,43 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
|
||||||
buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
|
buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
|
ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
|
||||||
|
size, &buf);
|
||||||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||||
goto beach;
|
goto beach;
|
||||||
|
|
||||||
|
if (size != sample_size) {
|
||||||
|
pts += gst_util_uint64_scale_int (GST_SECOND,
|
||||||
|
stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
|
||||||
|
dts += gst_util_uint64_scale_int (GST_SECOND,
|
||||||
|
stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
|
||||||
|
duration = gst_util_uint64_scale_int (GST_SECOND,
|
||||||
|
size / stream->bytes_per_frame, stream->timescale);
|
||||||
|
}
|
||||||
|
|
||||||
ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
|
ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
|
||||||
dts, pts, duration, keyframe, min_time, offset);
|
dts, pts, duration, keyframe, min_time, offset);
|
||||||
|
|
||||||
|
if (size != sample_size) {
|
||||||
|
QtDemuxSample *sample = &stream->samples[stream->sample_index];
|
||||||
|
QtDemuxSegment *segment = &stream->segments[stream->segment_index];
|
||||||
|
|
||||||
|
GstClockTime time_position = gst_util_uint64_scale (sample->timestamp +
|
||||||
|
stream->offset_in_sample / stream->bytes_per_frame, GST_SECOND,
|
||||||
|
stream->timescale);
|
||||||
|
if (time_position >= segment->media_start) {
|
||||||
|
/* inside the segment, update time_position, looks very familiar to
|
||||||
|
* GStreamer segments, doesn't it? */
|
||||||
|
stream->time_position = (time_position - segment->media_start) +
|
||||||
|
segment->time;
|
||||||
|
} else {
|
||||||
|
/* not yet in segment, time does not yet increment. This means
|
||||||
|
* that we are still prerolling keyframes to the decoder so it can
|
||||||
|
* decode the first sample of the segment. */
|
||||||
|
stream->time_position = segment->time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* combine flows */
|
/* combine flows */
|
||||||
ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
|
ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
|
||||||
/* ignore unlinked, we will not push on the pad anymore and we will EOS when
|
/* ignore unlinked, we will not push on the pad anymore and we will EOS when
|
||||||
|
@ -3869,6 +3915,12 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
|
||||||
if (ret == GST_FLOW_EOS)
|
if (ret == GST_FLOW_EOS)
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
|
||||||
|
stream->offset_in_sample += size;
|
||||||
|
if (stream->offset_in_sample >= sample_size) {
|
||||||
|
gst_qtdemux_advance_sample (qtdemux, stream);
|
||||||
|
}
|
||||||
|
goto beach;
|
||||||
|
|
||||||
next:
|
next:
|
||||||
gst_qtdemux_advance_sample (qtdemux, stream);
|
gst_qtdemux_advance_sample (qtdemux, stream);
|
||||||
|
|
||||||
|
@ -4009,8 +4061,10 @@ next_entry_size (GstQTDemux * demux)
|
||||||
for (i = 0; i < demux->n_streams; i++) {
|
for (i = 0; i < demux->n_streams; i++) {
|
||||||
stream = demux->streams[i];
|
stream = demux->streams[i];
|
||||||
|
|
||||||
if (stream->sample_index == -1)
|
if (stream->sample_index == -1) {
|
||||||
stream->sample_index = 0;
|
stream->sample_index = 0;
|
||||||
|
stream->offset_in_sample = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream->sample_index >= stream->n_samples) {
|
if (stream->sample_index >= stream->n_samples) {
|
||||||
GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
|
GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
|
||||||
|
@ -4469,6 +4523,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
|
||||||
ret = gst_qtdemux_combine_flows (demux, stream, ret);
|
ret = gst_qtdemux_combine_flows (demux, stream, ret);
|
||||||
|
|
||||||
stream->sample_index++;
|
stream->sample_index++;
|
||||||
|
stream->offset_in_sample = 0;
|
||||||
|
|
||||||
/* update current offset and figure out size of next buffer */
|
/* update current offset and figure out size of next buffer */
|
||||||
GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
|
GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
|
||||||
|
@ -5805,7 +5860,8 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
||||||
|
|
||||||
for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
|
for (k = stream->stsc_sample_index; k < 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, (guint) (cur - samples), stream->chunk_offset);
|
G_GUINT64_FORMAT "and size %d",
|
||||||
|
(guint) (cur - samples), stream->chunk_offset, cur->size);
|
||||||
|
|
||||||
cur->offset = chunk_offset;
|
cur->offset = chunk_offset;
|
||||||
chunk_offset += cur->size;
|
chunk_offset += cur->size;
|
||||||
|
@ -6504,6 +6560,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
||||||
stream->segment_index = -1;
|
stream->segment_index = -1;
|
||||||
stream->time_position = 0;
|
stream->time_position = 0;
|
||||||
stream->sample_index = -1;
|
stream->sample_index = -1;
|
||||||
|
stream->offset_in_sample = 0;
|
||||||
stream->last_ret = GST_FLOW_OK;
|
stream->last_ret = GST_FLOW_OK;
|
||||||
|
|
||||||
if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
|
if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
|
||||||
|
@ -9987,6 +10044,8 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
name = gst_structure_get_name (s);
|
name = gst_structure_get_name (s);
|
||||||
if (g_str_has_prefix (name, "audio/x-raw")) {
|
if (g_str_has_prefix (name, "audio/x-raw")) {
|
||||||
stream->need_clip = TRUE;
|
stream->need_clip = TRUE;
|
||||||
|
stream->max_buffer_size = 4096 * stream->bytes_per_frame;
|
||||||
|
GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
|
||||||
}
|
}
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue