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 |