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

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

Issue 177333003: Add support for midstream audio configuration changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ABS
Patch Set: add Reset() tests. Only enable ABC in MSE case. Created 6 years, 9 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_audio_decoder.h" 5 #include "media/filters/ffmpeg_audio_decoder.h"
6 6
7 #include "base/callback_helpers.h" 7 #include "base/callback_helpers.h"
8 #include "base/single_thread_task_runner.h" 8 #include "base/single_thread_task_runner.h"
9 #include "media/base/audio_buffer.h" 9 #include "media/base/audio_buffer.h"
10 #include "media/base/audio_bus.h" 10 #include "media/base/audio_bus.h"
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); 116 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque));
117 frame->buf[0] = av_buffer_create( 117 frame->buf[0] = av_buffer_create(
118 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); 118 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0);
119 return 0; 119 return 0;
120 } 120 }
121 121
122 FFmpegAudioDecoder::FFmpegAudioDecoder( 122 FFmpegAudioDecoder::FFmpegAudioDecoder(
123 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) 123 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
124 : task_runner_(task_runner), 124 : task_runner_(task_runner),
125 state_(kUninitialized), 125 state_(kUninitialized),
126 bytes_per_channel_(0),
127 channel_layout_(CHANNEL_LAYOUT_NONE),
128 channels_(0),
129 samples_per_second_(0),
130 av_sample_format_(0), 126 av_sample_format_(0),
131 last_input_timestamp_(kNoTimestamp()), 127 last_input_timestamp_(kNoTimestamp()),
132 output_frames_to_drop_(0) {} 128 output_frames_to_drop_(0) {}
133 129
134 FFmpegAudioDecoder::~FFmpegAudioDecoder() { 130 FFmpegAudioDecoder::~FFmpegAudioDecoder() {
135 DCHECK_EQ(state_, kUninitialized); 131 DCHECK_EQ(state_, kUninitialized);
136 DCHECK(!codec_context_); 132 DCHECK(!codec_context_);
137 DCHECK(!av_frame_); 133 DCHECK(!av_frame_);
138 } 134 }
139 135
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 181
186 scoped_refptr<AudioBuffer> FFmpegAudioDecoder::GetDecodeOutput() { 182 scoped_refptr<AudioBuffer> FFmpegAudioDecoder::GetDecodeOutput() {
187 DCHECK(task_runner_->BelongsToCurrentThread()); 183 DCHECK(task_runner_->BelongsToCurrentThread());
188 if (queued_audio_.empty()) 184 if (queued_audio_.empty())
189 return NULL; 185 return NULL;
190 scoped_refptr<AudioBuffer> out = queued_audio_.front(); 186 scoped_refptr<AudioBuffer> out = queued_audio_.front();
191 queued_audio_.pop_front(); 187 queued_audio_.pop_front();
192 return out; 188 return out;
193 } 189 }
194 190
195 int FFmpegAudioDecoder::bits_per_channel() {
196 DCHECK(task_runner_->BelongsToCurrentThread());
197 return bytes_per_channel_ * 8;
198 }
199
200 ChannelLayout FFmpegAudioDecoder::channel_layout() {
201 DCHECK(task_runner_->BelongsToCurrentThread());
202 return channel_layout_;
203 }
204
205 int FFmpegAudioDecoder::samples_per_second() {
206 DCHECK(task_runner_->BelongsToCurrentThread());
207 return samples_per_second_;
208 }
209
210 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { 191 void FFmpegAudioDecoder::Reset(const base::Closure& closure) {
211 DCHECK(task_runner_->BelongsToCurrentThread()); 192 DCHECK(task_runner_->BelongsToCurrentThread());
212 193
213 avcodec_flush_buffers(codec_context_.get()); 194 avcodec_flush_buffers(codec_context_.get());
214 state_ = kNormal; 195 state_ = kNormal;
215 ResetTimestampState(); 196 ResetTimestampState();
216 task_runner_->PostTask(FROM_HERE, closure); 197 task_runner_->PostTask(FROM_HERE, closure);
217 } 198 }
218 199
219 void FFmpegAudioDecoder::Stop(const base::Closure& closure) { 200 void FFmpegAudioDecoder::Stop(const base::Closure& closure) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 decode_cb.Run(kDecodeError, NULL); 255 decode_cb.Run(kDecodeError, NULL);
275 return; 256 return;
276 } 257 }
277 258
278 if (!buffer->end_of_stream()) { 259 if (!buffer->end_of_stream()) {
279 if (last_input_timestamp_ == kNoTimestamp() && 260 if (last_input_timestamp_ == kNoTimestamp() &&
280 codec_context_->codec_id == AV_CODEC_ID_VORBIS && 261 codec_context_->codec_id == AV_CODEC_ID_VORBIS &&
281 buffer->timestamp() < base::TimeDelta()) { 262 buffer->timestamp() < base::TimeDelta()) {
282 // Dropping frames for negative timestamps as outlined in section A.2 263 // Dropping frames for negative timestamps as outlined in section A.2
283 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html 264 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html
284 output_frames_to_drop_ = floor( 265 output_frames_to_drop_ = floor(0.5 + -buffer->timestamp().InSecondsF() *
285 0.5 + -buffer->timestamp().InSecondsF() * samples_per_second_); 266 config_.samples_per_second());
286 } else { 267 } else {
287 if (last_input_timestamp_ != kNoTimestamp() && 268 if (last_input_timestamp_ != kNoTimestamp() &&
288 buffer->timestamp() < last_input_timestamp_) { 269 buffer->timestamp() < last_input_timestamp_) {
289 const base::TimeDelta diff = 270 const base::TimeDelta diff =
290 buffer->timestamp() - last_input_timestamp_; 271 buffer->timestamp() - last_input_timestamp_;
291 DLOG(WARNING) 272 DLOG(WARNING)
292 << "Input timestamps are not monotonically increasing! " 273 << "Input timestamps are not monotonically increasing! "
293 << " ts " << buffer->timestamp().InMicroseconds() << " us" 274 << " ts " << buffer->timestamp().InMicroseconds() << " us"
294 << " diff " << diff.InMicroseconds() << " us"; 275 << " diff " << diff.InMicroseconds() << " us";
295 } 276 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 } else { 361 } else {
381 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp()); 362 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp());
382 } 363 }
383 } 364 }
384 365
385 scoped_refptr<AudioBuffer> output; 366 scoped_refptr<AudioBuffer> output;
386 int decoded_frames = 0; 367 int decoded_frames = 0;
387 int original_frames = 0; 368 int original_frames = 0;
388 int channels = DetermineChannels(av_frame_.get()); 369 int channels = DetermineChannels(av_frame_.get());
389 if (frame_decoded) { 370 if (frame_decoded) {
390
391 // TODO(rileya) Remove this check once we properly support midstream audio
392 // config changes.
393 if (av_frame_->sample_rate != config_.samples_per_second() || 371 if (av_frame_->sample_rate != config_.samples_per_second() ||
394 channels != channels_ || 372 channels != ChannelLayoutToChannelCount(config_.channel_layout()) ||
395 av_frame_->format != av_sample_format_) { 373 av_frame_->format != av_sample_format_) {
396 DLOG(ERROR) << "Unsupported midstream configuration change!" 374 DLOG(ERROR) << "Unsupported midstream configuration change!"
397 << " Sample Rate: " << av_frame_->sample_rate << " vs " 375 << " Sample Rate: " << av_frame_->sample_rate << " vs "
398 << samples_per_second_ 376 << config_.samples_per_second()
399 << ", Channels: " << channels << " vs " 377 << ", Channels: " << channels << " vs "
400 << channels_ 378 << ChannelLayoutToChannelCount(config_.channel_layout())
401 << ", Sample Format: " << av_frame_->format << " vs " 379 << ", Sample Format: " << av_frame_->format << " vs "
402 << av_sample_format_; 380 << av_sample_format_;
403 381
404 // This is an unrecoverable error, so bail out. 382 // This is an unrecoverable error, so bail out.
405 queued_audio_.clear(); 383 queued_audio_.clear();
406 av_frame_unref(av_frame_.get()); 384 av_frame_unref(av_frame_.get());
407 return false; 385 return false;
408 } 386 }
409 387
410 // Get the AudioBuffer that the data was decoded into. Adjust the number 388 // Get the AudioBuffer that the data was decoded into. Adjust the number
411 // of frames, in case fewer than requested were actually decoded. 389 // of frames, in case fewer than requested were actually decoded.
412 output = reinterpret_cast<AudioBuffer*>( 390 output = reinterpret_cast<AudioBuffer*>(
413 av_buffer_get_opaque(av_frame_->buf[0])); 391 av_buffer_get_opaque(av_frame_->buf[0]));
414 392
415 DCHECK_EQ(channels_, output->channel_count()); 393 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()),
394 output->channel_count());
416 original_frames = av_frame_->nb_samples; 395 original_frames = av_frame_->nb_samples;
417 int unread_frames = output->frame_count() - original_frames; 396 int unread_frames = output->frame_count() - original_frames;
418 DCHECK_GE(unread_frames, 0); 397 DCHECK_GE(unread_frames, 0);
419 if (unread_frames > 0) 398 if (unread_frames > 0)
420 output->TrimEnd(unread_frames); 399 output->TrimEnd(unread_frames);
421 400
422 // If there are frames to drop, get rid of as many as we can. 401 // If there are frames to drop, get rid of as many as we can.
423 if (output_frames_to_drop_ > 0) { 402 if (output_frames_to_drop_ > 0) {
424 int drop = std::min(output->frame_count(), output_frames_to_drop_); 403 int drop = std::min(output->frame_count(), output_frames_to_drop_);
425 output->TrimStart(drop); 404 output->TrimStart(drop);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 << " bits per channel: " << config_.bits_per_channel() 447 << " bits per channel: " << config_.bits_per_channel()
469 << " samples per second: " << config_.samples_per_second(); 448 << " samples per second: " << config_.samples_per_second();
470 return false; 449 return false;
471 } 450 }
472 451
473 if (config_.is_encrypted()) { 452 if (config_.is_encrypted()) {
474 DLOG(ERROR) << "Encrypted audio stream not supported"; 453 DLOG(ERROR) << "Encrypted audio stream not supported";
475 return false; 454 return false;
476 } 455 }
477 456
478 // TODO(rileya) Remove this check once we properly support midstream audio
479 // config changes.
480 if (codec_context_.get() &&
481 (bytes_per_channel_ != config_.bytes_per_channel() ||
482 channel_layout_ != config_.channel_layout() ||
483 samples_per_second_ != config_.samples_per_second())) {
484 DVLOG(1) << "Unsupported config change :";
485 DVLOG(1) << "\tbytes_per_channel : " << bytes_per_channel_
486 << " -> " << config_.bytes_per_channel();
487 DVLOG(1) << "\tchannel_layout : " << channel_layout_
488 << " -> " << config_.channel_layout();
489 DVLOG(1) << "\tsample_rate : " << samples_per_second_
490 << " -> " << config_.samples_per_second();
491 return false;
492 }
493
494 // Release existing decoder resources if necessary. 457 // Release existing decoder resources if necessary.
495 ReleaseFFmpegResources(); 458 ReleaseFFmpegResources();
496 459
497 // Initialize AVCodecContext structure. 460 // Initialize AVCodecContext structure.
498 codec_context_.reset(avcodec_alloc_context3(NULL)); 461 codec_context_.reset(avcodec_alloc_context3(NULL));
499 AudioDecoderConfigToAVCodecContext(config_, codec_context_.get()); 462 AudioDecoderConfigToAVCodecContext(config_, codec_context_.get());
500 463
501 codec_context_->opaque = this; 464 codec_context_->opaque = this;
502 codec_context_->get_buffer2 = GetAudioBuffer; 465 codec_context_->get_buffer2 = GetAudioBuffer;
503 codec_context_->refcounted_frames = 1; 466 codec_context_->refcounted_frames = 1;
504 467
505 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); 468 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
506 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { 469 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) {
507 DLOG(ERROR) << "Could not initialize audio decoder: " 470 DLOG(ERROR) << "Could not initialize audio decoder: "
508 << codec_context_->codec_id; 471 << codec_context_->codec_id;
509 ReleaseFFmpegResources(); 472 ReleaseFFmpegResources();
510 state_ = kUninitialized; 473 state_ = kUninitialized;
511 return false; 474 return false;
512 } 475 }
513 476
514 // Success! 477 // Success!
515 av_frame_.reset(av_frame_alloc()); 478 av_frame_.reset(av_frame_alloc());
516 channel_layout_ = config_.channel_layout();
517 samples_per_second_ = config_.samples_per_second();
518 output_timestamp_helper_.reset( 479 output_timestamp_helper_.reset(
519 new AudioTimestampHelper(config_.samples_per_second())); 480 new AudioTimestampHelper(config_.samples_per_second()));
520 481
521 // Store initial values to guard against midstream configuration changes. 482 av_sample_format_ = codec_context_->sample_fmt;
522 channels_ = codec_context_->channels; 483
523 if (channels_ != ChannelLayoutToChannelCount(channel_layout_)) { 484 if (codec_context_->channels !=
485 ChannelLayoutToChannelCount(config_.channel_layout())) {
524 DLOG(ERROR) << "Audio configuration specified " 486 DLOG(ERROR) << "Audio configuration specified "
525 << ChannelLayoutToChannelCount(channel_layout_) 487 << ChannelLayoutToChannelCount(config_.channel_layout())
526 << " channels, but FFmpeg thinks the file contains " 488 << " channels, but FFmpeg thinks the file contains "
527 << channels_ << " channels"; 489 << codec_context_->channels << " channels";
528 ReleaseFFmpegResources(); 490 ReleaseFFmpegResources();
529 state_ = kUninitialized; 491 state_ = kUninitialized;
530 return false; 492 return false;
531 } 493 }
532 av_sample_format_ = codec_context_->sample_fmt;
533 sample_format_ = AVSampleFormatToSampleFormat(
534 static_cast<AVSampleFormat>(av_sample_format_));
535 bytes_per_channel_ = SampleFormatToBytesPerChannel(sample_format_);
536
537 return true; 494 return true;
538 } 495 }
539 496
540 void FFmpegAudioDecoder::ResetTimestampState() { 497 void FFmpegAudioDecoder::ResetTimestampState() {
541 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); 498 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp());
542 last_input_timestamp_ = kNoTimestamp(); 499 last_input_timestamp_ = kNoTimestamp();
543 output_frames_to_drop_ = 0; 500 output_frames_to_drop_ = 0;
544 } 501 }
545 502
546 } // namespace media 503 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698