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

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

Powered by Google App Engine
This is Rietveld 408576698