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

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

Issue 2871263003: Set |config_| only after decoder has been successfully configured (Closed)
Patch Set: fixed unittests Created 3 years, 7 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
« no previous file with comments | « media/filters/ffmpeg_audio_decoder.h ('k') | media/filters/ffmpeg_video_decoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_audio_decoder.h ('k') | media/filters/ffmpeg_video_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698