| OLD | NEW |
| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 DCHECK(config.IsValidConfig()); | 87 DCHECK(config.IsValidConfig()); |
| 88 | 88 |
| 89 InitCB bound_init_cb = BindToCurrentLoop(init_cb); | 89 InitCB bound_init_cb = BindToCurrentLoop(init_cb); |
| 90 | 90 |
| 91 if (config.is_encrypted()) { | 91 if (config.is_encrypted()) { |
| 92 bound_init_cb.Run(false); | 92 bound_init_cb.Run(false); |
| 93 return; | 93 return; |
| 94 } | 94 } |
| 95 | 95 |
| 96 FFmpegGlue::InitializeFFmpeg(); | 96 FFmpegGlue::InitializeFFmpeg(); |
| 97 config_ = config; | |
| 98 | 97 |
| 99 // TODO(xhwang): Only set |config_| after we successfully configure the | 98 if (!ConfigureDecoder(config)) { |
| 100 // decoder. Make sure we clean up all member variables upon failure. | 99 av_sample_format_ = 0; |
| 101 if (!ConfigureDecoder()) { | |
| 102 bound_init_cb.Run(false); | 100 bound_init_cb.Run(false); |
| 103 return; | 101 return; |
| 104 } | 102 } |
| 105 | 103 |
| 106 // Success! | 104 // Success! |
| 105 config_ = config; |
| 107 output_cb_ = BindToCurrentLoop(output_cb); | 106 output_cb_ = BindToCurrentLoop(output_cb); |
| 108 state_ = kNormal; | 107 state_ = kNormal; |
| 109 bound_init_cb.Run(true); | 108 bound_init_cb.Run(true); |
| 110 } | 109 } |
| 111 | 110 |
| 112 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 111 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 113 const DecodeCB& decode_cb) { | 112 const DecodeCB& decode_cb) { |
| 114 DCHECK(task_runner_->BelongsToCurrentThread()); | 113 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 115 DCHECK(!decode_cb.is_null()); | 114 DCHECK(!decode_cb.is_null()); |
| 116 CHECK_NE(state_, kUninitialized); | 115 CHECK_NE(state_, kUninitialized); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 128 } | 127 } |
| 129 | 128 |
| 130 DecodeBuffer(buffer, decode_cb_bound); | 129 DecodeBuffer(buffer, decode_cb_bound); |
| 131 } | 130 } |
| 132 | 131 |
| 133 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { | 132 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { |
| 134 DCHECK(task_runner_->BelongsToCurrentThread()); | 133 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 135 | 134 |
| 136 avcodec_flush_buffers(codec_context_.get()); | 135 avcodec_flush_buffers(codec_context_.get()); |
| 137 state_ = kNormal; | 136 state_ = kNormal; |
| 138 ResetTimestampState(); | 137 ResetTimestampState(config_); |
| 139 task_runner_->PostTask(FROM_HERE, closure); | 138 task_runner_->PostTask(FROM_HERE, closure); |
| 140 } | 139 } |
| 141 | 140 |
| 142 void FFmpegAudioDecoder::DecodeBuffer( | 141 void FFmpegAudioDecoder::DecodeBuffer( |
| 143 const scoped_refptr<DecoderBuffer>& buffer, | 142 const scoped_refptr<DecoderBuffer>& buffer, |
| 144 const DecodeCB& decode_cb) { | 143 const DecodeCB& decode_cb) { |
| 145 DCHECK(task_runner_->BelongsToCurrentThread()); | 144 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 146 DCHECK_NE(state_, kUninitialized); | 145 DCHECK_NE(state_, kUninitialized); |
| 147 DCHECK_NE(state_, kDecodeFinished); | 146 DCHECK_NE(state_, kDecodeFinished); |
| 148 DCHECK_NE(state_, kError); | 147 DCHECK_NE(state_, kError); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 << ", ChannelLayout: " << channel_layout << " vs " | 250 << ", ChannelLayout: " << channel_layout << " vs " |
| 252 << config_.channel_layout() << ", Channels: " << channels | 251 << config_.channel_layout() << ", Channels: " << channels |
| 253 << " vs " | 252 << " vs " |
| 254 << ChannelLayoutToChannelCount(config_.channel_layout()); | 253 << ChannelLayoutToChannelCount(config_.channel_layout()); |
| 255 config_.Initialize(config_.codec(), config_.sample_format(), | 254 config_.Initialize(config_.codec(), config_.sample_format(), |
| 256 channel_layout, av_frame_->sample_rate, | 255 channel_layout, av_frame_->sample_rate, |
| 257 config_.extra_data(), config_.encryption_scheme(), | 256 config_.extra_data(), config_.encryption_scheme(), |
| 258 config_.seek_preroll(), config_.codec_delay()); | 257 config_.seek_preroll(), config_.codec_delay()); |
| 259 config_changed = true; | 258 config_changed = true; |
| 260 if (is_sample_rate_change) | 259 if (is_sample_rate_change) |
| 261 ResetTimestampState(); | 260 ResetTimestampState(config_); |
| 262 } else { | 261 } else { |
| 263 MEDIA_LOG(ERROR, media_log_) | 262 MEDIA_LOG(ERROR, media_log_) |
| 264 << "Unsupported midstream configuration change!" | 263 << "Unsupported midstream configuration change!" |
| 265 << " Sample Rate: " << av_frame_->sample_rate << " vs " | 264 << " Sample Rate: " << av_frame_->sample_rate << " vs " |
| 266 << config_.samples_per_second() << ", Channels: " << channels | 265 << config_.samples_per_second() << ", Channels: " << channels |
| 267 << " vs " << ChannelLayoutToChannelCount(config_.channel_layout()) | 266 << " vs " << ChannelLayoutToChannelCount(config_.channel_layout()) |
| 268 << ", Sample Format: " << av_frame_->format << " vs " | 267 << ", Sample Format: " << av_frame_->format << " vs " |
| 269 << av_sample_format_; | 268 << av_sample_format_; |
| 270 // This is an unrecoverable error, so bail out. | 269 // This is an unrecoverable error, so bail out. |
| 271 av_frame_unref(av_frame_.get()); | 270 av_frame_unref(av_frame_.get()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 } while (packet.size > 0); | 305 } while (packet.size > 0); |
| 307 | 306 |
| 308 return true; | 307 return true; |
| 309 } | 308 } |
| 310 | 309 |
| 311 void FFmpegAudioDecoder::ReleaseFFmpegResources() { | 310 void FFmpegAudioDecoder::ReleaseFFmpegResources() { |
| 312 codec_context_.reset(); | 311 codec_context_.reset(); |
| 313 av_frame_.reset(); | 312 av_frame_.reset(); |
| 314 } | 313 } |
| 315 | 314 |
| 316 bool FFmpegAudioDecoder::ConfigureDecoder() { | 315 bool FFmpegAudioDecoder::ConfigureDecoder(const AudioDecoderConfig& config) { |
| 317 DCHECK(config_.IsValidConfig()); | 316 DCHECK(config.IsValidConfig()); |
| 318 DCHECK(!config_.is_encrypted()); | 317 DCHECK(!config.is_encrypted()); |
| 319 | 318 |
| 320 // Release existing decoder resources if necessary. | 319 // Release existing decoder resources if necessary. |
| 321 ReleaseFFmpegResources(); | 320 ReleaseFFmpegResources(); |
| 322 | 321 |
| 323 // Initialize AVCodecContext structure. | 322 // Initialize AVCodecContext structure. |
| 324 codec_context_.reset(avcodec_alloc_context3(NULL)); | 323 codec_context_.reset(avcodec_alloc_context3(NULL)); |
| 325 AudioDecoderConfigToAVCodecContext(config_, codec_context_.get()); | 324 AudioDecoderConfigToAVCodecContext(config, codec_context_.get()); |
| 326 | 325 |
| 327 codec_context_->opaque = this; | 326 codec_context_->opaque = this; |
| 328 codec_context_->get_buffer2 = GetAudioBufferImpl; | 327 codec_context_->get_buffer2 = GetAudioBufferImpl; |
| 329 codec_context_->refcounted_frames = 1; | 328 codec_context_->refcounted_frames = 1; |
| 330 | 329 |
| 331 if (config_.codec() == kCodecOpus) | 330 if (config.codec() == kCodecOpus) |
| 332 codec_context_->request_sample_fmt = AV_SAMPLE_FMT_FLT; | 331 codec_context_->request_sample_fmt = AV_SAMPLE_FMT_FLT; |
| 333 | 332 |
| 334 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); | 333 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); |
| 335 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { | 334 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { |
| 336 DLOG(ERROR) << "Could not initialize audio decoder: " | 335 DLOG(ERROR) << "Could not initialize audio decoder: " |
| 337 << codec_context_->codec_id; | 336 << codec_context_->codec_id; |
| 338 ReleaseFFmpegResources(); | 337 ReleaseFFmpegResources(); |
| 339 state_ = kUninitialized; | 338 state_ = kUninitialized; |
| 340 return false; | 339 return false; |
| 341 } | 340 } |
| 342 | 341 |
| 343 // Success! | 342 // Success! |
| 344 av_frame_.reset(av_frame_alloc()); | 343 av_frame_.reset(av_frame_alloc()); |
| 345 av_sample_format_ = codec_context_->sample_fmt; | 344 av_sample_format_ = codec_context_->sample_fmt; |
| 346 | 345 |
| 347 if (codec_context_->channels != | 346 if (codec_context_->channels != |
| 348 ChannelLayoutToChannelCount(config_.channel_layout())) { | 347 ChannelLayoutToChannelCount(config.channel_layout())) { |
| 349 MEDIA_LOG(ERROR, media_log_) | 348 MEDIA_LOG(ERROR, media_log_) |
| 350 << "Audio configuration specified " | 349 << "Audio configuration specified " |
| 351 << ChannelLayoutToChannelCount(config_.channel_layout()) | 350 << ChannelLayoutToChannelCount(config.channel_layout()) |
| 352 << " channels, but FFmpeg thinks the file contains " | 351 << " channels, but FFmpeg thinks the file contains " |
| 353 << codec_context_->channels << " channels"; | 352 << codec_context_->channels << " channels"; |
| 354 ReleaseFFmpegResources(); | 353 ReleaseFFmpegResources(); |
| 355 state_ = kUninitialized; | 354 state_ = kUninitialized; |
| 356 return false; | 355 return false; |
| 357 } | 356 } |
| 358 | 357 |
| 359 ResetTimestampState(); | 358 ResetTimestampState(config); |
| 360 return true; | 359 return true; |
| 361 } | 360 } |
| 362 | 361 |
| 363 void FFmpegAudioDecoder::ResetTimestampState() { | 362 void FFmpegAudioDecoder::ResetTimestampState(const AudioDecoderConfig& config) { |
| 364 // Opus codec delay is handled by ffmpeg. | 363 // Opus codec delay is handled by ffmpeg. |
| 365 const int codec_delay = | 364 const int codec_delay = |
| 366 config_.codec() == kCodecOpus ? 0 : config_.codec_delay(); | 365 config.codec() == kCodecOpus ? 0 : config.codec_delay(); |
| 367 discard_helper_.reset( | 366 discard_helper_.reset(new AudioDiscardHelper(config.samples_per_second(), |
| 368 new AudioDiscardHelper(config_.samples_per_second(), codec_delay, | 367 codec_delay, |
| 369 config_.codec() == kCodecVorbis)); | 368 config.codec() == kCodecVorbis)); |
| 370 discard_helper_->Reset(codec_delay); | 369 discard_helper_->Reset(codec_delay); |
| 371 } | 370 } |
| 372 | 371 |
| 373 int FFmpegAudioDecoder::GetAudioBuffer(struct AVCodecContext* s, | 372 int FFmpegAudioDecoder::GetAudioBuffer(struct AVCodecContext* s, |
| 374 AVFrame* frame, | 373 AVFrame* frame, |
| 375 int flags) { | 374 int flags) { |
| 376 DCHECK(s->codec->capabilities & CODEC_CAP_DR1); | 375 DCHECK(s->codec->capabilities & CODEC_CAP_DR1); |
| 377 DCHECK_EQ(s->codec_type, AVMEDIA_TYPE_AUDIO); | 376 DCHECK_EQ(s->codec_type, AVMEDIA_TYPE_AUDIO); |
| 378 | 377 |
| 379 // Since this routine is called by FFmpeg when a buffer is required for audio | 378 // Since this routine is called by FFmpeg when a buffer is required for audio |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 // Now create an AVBufferRef for the data just allocated. It will own the | 450 // Now create an AVBufferRef for the data just allocated. It will own the |
| 452 // reference to the AudioBuffer object. | 451 // reference to the AudioBuffer object. |
| 453 AudioBuffer* opaque = buffer.get(); | 452 AudioBuffer* opaque = buffer.get(); |
| 454 opaque->AddRef(); | 453 opaque->AddRef(); |
| 455 frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes, | 454 frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes, |
| 456 ReleaseAudioBufferImpl, opaque, 0); | 455 ReleaseAudioBufferImpl, opaque, 0); |
| 457 return 0; | 456 return 0; |
| 458 } | 457 } |
| 459 | 458 |
| 460 } // namespace media | 459 } // namespace media |
| OLD | NEW |