Chromium Code Reviews| Index: media/filters/ffmpeg_demuxer.cc |
| diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc |
| index 80cb7adcbee7a0c13c7630b2d14d4b676db7af61..805517fe9293ab7de2fc9c025c64dc86f04da08c 100644 |
| --- a/media/filters/ffmpeg_demuxer.cc |
| +++ b/media/filters/ffmpeg_demuxer.cc |
| @@ -94,7 +94,7 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, |
| last_packet_timestamp_(kNoTimestamp()), |
| last_packet_duration_(kNoTimestamp()), |
| video_rotation_(VIDEO_ROTATION_0), |
| - fixup_negative_ogg_timestamps_(false) { |
| + fixup_negative_timestamps_(false) { |
| DCHECK(demuxer_); |
| bool is_encrypted = false; |
| @@ -297,7 +297,7 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { |
| // If this is an OGG file with negative timestamps don't rebase any other |
|
wolenetz
2015/08/06 22:21:27
nit: s/an OGG/a/ ?
DaleCurtis
2015/08/06 23:45:27
Already fixed in later patch set.
|
| // stream types against the negative starting time. |
| base::TimeDelta start_time = demuxer_->start_time(); |
| - if (fixup_negative_ogg_timestamps_ && !is_audio && |
| + if (fixup_negative_timestamps_ && !is_audio && |
| start_time < base::TimeDelta()) { |
| start_time = base::TimeDelta(); |
| } |
| @@ -310,19 +310,22 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { |
| buffer->set_timestamp(stream_timestamp - start_time); |
| - // If enabled, mark audio packets with negative timestamps for post-decode |
| - // discard. |
| - if (fixup_negative_ogg_timestamps_ && is_audio && |
| + // If enabled, and no codec delay is present, mark audio packets with |
| + // negative timestamps for post-decode discard. |
|
chcunningham
2015/07/31 19:48:44
just to check my understanding....
1. we see nega
DaleCurtis
2015/08/03 22:49:53
Yes that is correct. We're confident because this
|
| + if (fixup_negative_timestamps_ && is_audio && |
| stream_timestamp < base::TimeDelta() && |
| - buffer->duration() != kNoTimestamp()) { |
| + buffer->duration() != kNoTimestamp() && !stream_->codec->delay) { |
| + DCHECK_EQ(buffer->discard_padding().first, base::TimeDelta()); |
| + |
| if (stream_timestamp + buffer->duration() < base::TimeDelta()) { |
| + DCHECK_EQ(buffer->discard_padding().second, base::TimeDelta()); |
| + |
| // Discard the entire packet if it's entirely before zero. |
| buffer->set_discard_padding( |
| std::make_pair(kInfiniteDuration(), base::TimeDelta())); |
| } else { |
| - // Only discard part of the frame if it overlaps zero. |
|
chcunningham
2015/07/31 19:48:44
Did you mean to kill the comment?
DaleCurtis
2015/08/03 22:49:53
Nope, reverted.
|
| - buffer->set_discard_padding( |
| - std::make_pair(-stream_timestamp, base::TimeDelta())); |
| + buffer->set_discard_padding(std::make_pair( |
| + -stream_timestamp, buffer->discard_padding().second)); |
|
chcunningham
2015/07/31 19:48:44
I can see why this is more correct, but I'm curiou
DaleCurtis
2015/08/03 22:49:53
Just fixing this as wolenetz@ complained about it
|
| } |
| } |
| } else { |
| @@ -344,7 +347,7 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { |
| // Fixing chained ogg is non-trivial, so for now just reuse the last good |
| // timestamp. The decoder will rewrite the timestamps to be sample accurate |
| // later. See http://crbug.com/396864. |
| - if (fixup_negative_ogg_timestamps_ && |
| + if (fixup_negative_timestamps_ && |
| (buffer->timestamp() == kNoTimestamp() || |
| buffer->timestamp() < last_packet_timestamp_)) { |
| buffer->set_timestamp(last_packet_timestamp_ + |
| @@ -628,9 +631,19 @@ void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
| // Additionally, to workaround limitations in how we expose seekable ranges to |
| // Blink (http://crbug.com/137275), we also want to clamp seeks before the |
| // start time to the start time. |
| - const base::TimeDelta seek_time = |
| - start_time_ < base::TimeDelta() ? time + start_time_ |
| - : time < start_time_ ? start_time_ : time; |
| + base::TimeDelta seek_time = start_time_ < base::TimeDelta() |
| + ? time + start_time_ |
| + : time < start_time_ ? start_time_ : time; |
|
chcunningham
2015/07/31 19:48:44
I don't follow why we only add start_time_ in the
DaleCurtis
2015/08/03 22:49:53
See l.305, the gist is that we don't rebase positi
chcunningham
2015/08/04 20:38:09
I see. This is a fragile contract between two meth
|
| + |
| + // When seeking in an opus stream we need to ensure we deliver enough data to |
| + // satisfy the seek preroll; otherwise the audio at the actual seek time will |
| + // not be entirely accurate. |
| + FFmpegDemuxerStream* audio_stream = GetFFmpegStream(DemuxerStream::AUDIO); |
| + if (audio_stream) { |
| + const AudioDecoderConfig& config = audio_stream->audio_decoder_config(); |
| + if (config.codec() == kCodecOpus) |
|
chcunningham
2015/07/31 19:48:44
How does this work for other codecs that need pre-
DaleCurtis
2015/08/03 22:49:53
It doesn't :) No other codecs specify this informa
chcunningham
2015/08/04 20:38:09
Is this something we can extract into a utility us
DaleCurtis
2015/08/04 21:38:34
This is already encoded in the seek_preroll() and
|
| + seek_time = std::max(start_time_, seek_time - config.seek_preroll()); |
| + } |
| // Choose the seeking stream based on whether it contains the seek time, if no |
| // match can be found prefer the preferred stream. |
| @@ -960,17 +973,28 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
| max_duration = kInfiniteDuration(); |
| } |
| - // Ogg has some peculiarities around negative timestamps, so use this flag to |
| - // setup the FFmpegDemuxerStreams appropriately. |
| + // FFmpeg represents audio data marked as before the beginning of stream as |
| + // having negative timestamps. This data must be discarded after it has been |
| + // decoded, not before since it is used to warmup the decoder. There are |
| + // currently two known cases for this: vorbis in ogg and opus in ogg and webm. |
| + // |
| + // For API clarity, it was decided that the rest of the media pipeline should |
| + // not be exposed to negative timestamps. Which means we need to rebase these |
| + // negative timestamps and mark them for discard post decoding. |
| // |
| // Post-decode frame dropping for packets with negative timestamps is outlined |
| // in section A.2 in the Ogg Vorbis spec: |
| // http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
| - if (strcmp(format_context->iformat->name, "ogg") == 0 && audio_stream && |
| - audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS) { |
| + // |
| + // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but |
| + // for more information on pre-skip see section 4.2 of the Ogg Opus spec: |
| + // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 |
| + if (audio_stream && (audio_stream->codec->codec_id == AV_CODEC_ID_OPUS || |
| + (strcmp(format_context->iformat->name, "ogg") == 0 && |
| + audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS))) { |
| for (size_t i = 0; i < streams_.size(); ++i) { |
| if (streams_[i]) |
| - streams_[i]->enable_negative_timestamp_fixups_for_ogg(); |
| + streams_[i]->enable_negative_timestamp_fixups(); |
|
chcunningham
2015/07/31 19:48:44
Why do we do this for all streams and not just the
DaleCurtis
2015/08/03 22:49:53
Because we need to tell the video stream that it s
chcunningham
2015/08/04 20:38:09
I see. I feel like this should really be called
e
DaleCurtis
2015/08/04 21:38:34
Well, it has different effects on audio and video,
|
| } |
| // Fixup the seeking information to avoid selecting the audio stream simply |
| @@ -1204,19 +1228,6 @@ void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { |
| packet.swap(new_packet); |
| } |
| - // Special case for opus in ogg. FFmpeg is pre-trimming the codec delay |
| - // from the packet timestamp. Chrome expects to handle this itself inside |
| - // the decoder, so shift timestamps by the delay in this case. |
| - // TODO(dalecurtis): Try to get fixed upstream. See http://crbug.com/328207 |
| - if (strcmp(glue_->format_context()->iformat->name, "ogg") == 0) { |
| - const AVCodecContext* codec_context = |
| - glue_->format_context()->streams[packet->stream_index]->codec; |
| - if (codec_context->codec_id == AV_CODEC_ID_OPUS && |
| - codec_context->delay > 0) { |
| - packet->pts += codec_context->delay; |
| - } |
| - } |
| - |
| FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; |
| demuxer_stream->EnqueuePacket(packet.Pass()); |
| } |