Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: media/filters/ffmpeg_demuxer.cc

Issue 1260193005: Fix incorrect opus seek preroll and flaky pre-skip removal. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add test cases. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/ffmpeg_demuxer.h" 5 #include "media/filters/ffmpeg_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 packet.get()->size - data_offset); 247 packet.get()->size - data_offset);
248 } 248 }
249 249
250 int skip_samples_size = 0; 250 int skip_samples_size = 0;
251 const uint32* skip_samples_ptr = 251 const uint32* skip_samples_ptr =
252 reinterpret_cast<const uint32*>(av_packet_get_side_data( 252 reinterpret_cast<const uint32*>(av_packet_get_side_data(
253 packet.get(), AV_PKT_DATA_SKIP_SAMPLES, &skip_samples_size)); 253 packet.get(), AV_PKT_DATA_SKIP_SAMPLES, &skip_samples_size));
254 const int kSkipSamplesValidSize = 10; 254 const int kSkipSamplesValidSize = 10;
255 const int kSkipEndSamplesOffset = 1; 255 const int kSkipEndSamplesOffset = 1;
256 if (skip_samples_size >= kSkipSamplesValidSize) { 256 if (skip_samples_size >= kSkipSamplesValidSize) {
257 // Because FFmpeg rolls codec delay and skip samples into one we can only 257 // Because FFmpeg rolls codec delay and skip samples into one we can only
wolenetz 2015/07/29 21:57:27 Is there any AV_PKT_DATA_SKIP_SAMPLES (front skip)
DaleCurtis 2015/07/30 01:28:14 Added a DCHECK and reflowed the conditional for su
258 // allow front discard padding on the first buffer. Otherwise the discard 258 // allow front discard padding on the first buffer. Otherwise the discard
259 // helper can't figure out which data to discard. See AudioDiscardHelper. 259 // helper can't figure out which data to discard. See AudioDiscardHelper.
260 int discard_front_samples = base::ByteSwapToLE32(*skip_samples_ptr); 260 int discard_front_samples = base::ByteSwapToLE32(*skip_samples_ptr);
261 if (last_packet_timestamp_ != kNoTimestamp() && discard_front_samples) { 261 if (last_packet_timestamp_ != kNoTimestamp() && discard_front_samples) {
262 DLOG(ERROR) << "Skip samples are only allowed for the first packet."; 262 DLOG(ERROR) << "Skip samples are only allowed for the first packet.";
263 discard_front_samples = 0; 263 discard_front_samples = 0;
264 } 264 }
265 265
266 const int discard_end_samples = 266 const int discard_end_samples =
267 base::ByteSwapToLE32(*(skip_samples_ptr + kSkipEndSamplesOffset)); 267 base::ByteSwapToLE32(*(skip_samples_ptr + kSkipEndSamplesOffset));
268 const int samples_per_second = 268 const int samples_per_second =
269 audio_decoder_config().samples_per_second(); 269 audio_decoder_config().samples_per_second();
270 buffer->set_discard_padding(std::make_pair( 270 buffer->set_discard_padding(std::make_pair(
271 FramesToTimeDelta(discard_front_samples, samples_per_second), 271 FramesToTimeDelta(discard_front_samples, samples_per_second),
272 FramesToTimeDelta(discard_end_samples, samples_per_second))); 272 FramesToTimeDelta(discard_end_samples, samples_per_second)));
273 } else if (type() == AUDIO && stream_->codec->delay > 0 &&
274 packet->pts <= stream_->start_time &&
275 stream_->codec->codec_id == AV_CODEC_ID_OPUS) {
276 // FFmpeg does not encode the opus pre-skip value within the packet side
277 // data, so when we encounter the first packet in a stream ensure the
278 // codec delay is applied per spec.
279 //
280 // |stream_->codec->delay| has been added to packet->pts automatically by
281 // ffmpeg, so the delta between the start time and the packet pts is the
282 // amount of delay remaining to trim.
283 buffer->set_discard_padding(std::make_pair(
284 FramesToTimeDelta(std::min(static_cast<int64_t>(packet->duration),
285 stream_->start_time - packet->pts),
286 audio_decoder_config().samples_per_second()),
287 base::TimeDelta()));
wolenetz 2015/07/29 21:57:27 Could there be a single packet that is both the st
DaleCurtis 2015/07/30 01:28:14 Done.
273 } 288 }
274 289
275 if (decrypt_config) 290 if (decrypt_config)
276 buffer->set_decrypt_config(decrypt_config.Pass()); 291 buffer->set_decrypt_config(decrypt_config.Pass());
277 } 292 }
278 293
279 if (packet->duration >= 0) { 294 if (packet->duration >= 0) {
280 buffer->set_duration( 295 buffer->set_duration(
281 ConvertStreamTimestamp(stream_->time_base, packet->duration)); 296 ConvertStreamTimestamp(stream_->time_base, packet->duration));
282 } else { 297 } else {
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 // otherwise we can end up waiting for a pre-seek read to complete even though 636 // otherwise we can end up waiting for a pre-seek read to complete even though
622 // we know we're going to drop it on the floor. 637 // we know we're going to drop it on the floor.
623 638
624 // FFmpeg requires seeks to be adjusted according to the lowest starting time. 639 // FFmpeg requires seeks to be adjusted according to the lowest starting time.
625 // Since EnqueuePacket() rebased negative timestamps by the start time, we 640 // Since EnqueuePacket() rebased negative timestamps by the start time, we
626 // must correct the shift here. 641 // must correct the shift here.
627 // 642 //
628 // Additionally, to workaround limitations in how we expose seekable ranges to 643 // Additionally, to workaround limitations in how we expose seekable ranges to
629 // Blink (http://crbug.com/137275), we also want to clamp seeks before the 644 // Blink (http://crbug.com/137275), we also want to clamp seeks before the
630 // start time to the start time. 645 // start time to the start time.
631 const base::TimeDelta seek_time = 646 base::TimeDelta seek_time = start_time_ < base::TimeDelta()
632 start_time_ < base::TimeDelta() ? time + start_time_ 647 ? time + start_time_
633 : time < start_time_ ? start_time_ : time; 648 : time < start_time_ ? start_time_ : time;
649
650 // When seeking in an opus stream we need to ensure we deliver enough data to
651 // satisfy the seek preroll; otherwise the audio at the actual seek time will
652 // not be entirely accurate.
653 FFmpegDemuxerStream* audio_stream = GetFFmpegStream(DemuxerStream::AUDIO);
654 if (audio_stream) {
655 const AudioDecoderConfig& config = audio_stream->audio_decoder_config();
656 if (config.codec() == kCodecOpus)
657 seek_time = std::max(start_time_, seek_time - config.seek_preroll());
658 }
634 659
635 // Choose the seeking stream based on whether it contains the seek time, if no 660 // Choose the seeking stream based on whether it contains the seek time, if no
636 // match can be found prefer the preferred stream. 661 // match can be found prefer the preferred stream.
637 // 662 //
638 // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a 663 // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a
639 // given container will demux all packets after the seek point. Instead it 664 // given container will demux all packets after the seek point. Instead it
640 // only guarantees that all packets after the file position of the seek will 665 // only guarantees that all packets after the file position of the seek will
641 // be demuxed. It's an open question whether FFmpeg should fix this: 666 // be demuxed. It's an open question whether FFmpeg should fix this:
642 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html 667 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html
643 // Tracked by http://crbug.com/387996. 668 // Tracked by http://crbug.com/387996.
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after
1197 // when av_read_frame() returns success code. See bug comment for ideas: 1222 // when av_read_frame() returns success code. See bug comment for ideas:
1198 // 1223 //
1199 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 1224 // https://code.google.com/p/chromium/issues/detail?id=169133#c10
1200 if (!packet->data) { 1225 if (!packet->data) {
1201 ScopedAVPacket new_packet(new AVPacket()); 1226 ScopedAVPacket new_packet(new AVPacket());
1202 av_new_packet(new_packet.get(), 0); 1227 av_new_packet(new_packet.get(), 0);
1203 av_packet_copy_props(new_packet.get(), packet.get()); 1228 av_packet_copy_props(new_packet.get(), packet.get());
1204 packet.swap(new_packet); 1229 packet.swap(new_packet);
1205 } 1230 }
1206 1231
1207 // Special case for opus in ogg. FFmpeg is pre-trimming the codec delay
1208 // from the packet timestamp. Chrome expects to handle this itself inside
1209 // the decoder, so shift timestamps by the delay in this case.
1210 // TODO(dalecurtis): Try to get fixed upstream. See http://crbug.com/328207
1211 if (strcmp(glue_->format_context()->iformat->name, "ogg") == 0) {
1212 const AVCodecContext* codec_context =
1213 glue_->format_context()->streams[packet->stream_index]->codec;
1214 if (codec_context->codec_id == AV_CODEC_ID_OPUS &&
1215 codec_context->delay > 0) {
1216 packet->pts += codec_context->delay;
1217 }
1218 }
1219
1220 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; 1232 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index];
1221 demuxer_stream->EnqueuePacket(packet.Pass()); 1233 demuxer_stream->EnqueuePacket(packet.Pass());
1222 } 1234 }
1223 1235
1224 // Keep reading until we've reached capacity. 1236 // Keep reading until we've reached capacity.
1225 ReadFrameIfNeeded(); 1237 ReadFrameIfNeeded();
1226 } 1238 }
1227 1239
1228 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { 1240 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() {
1229 DCHECK(task_runner_->BelongsToCurrentThread()); 1241 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 1315
1304 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { 1316 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) {
1305 DCHECK(task_runner_->BelongsToCurrentThread()); 1317 DCHECK(task_runner_->BelongsToCurrentThread());
1306 for (const auto& stream : streams_) { // |stream| is a ref to a pointer. 1318 for (const auto& stream : streams_) { // |stream| is a ref to a pointer.
1307 if (stream) 1319 if (stream)
1308 stream->SetLiveness(liveness); 1320 stream->SetLiveness(liveness);
1309 } 1321 }
1310 } 1322 }
1311 1323
1312 } // namespace media 1324 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698