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

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

Powered by Google App Engine
This is Rietveld 408576698