| 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 "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 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 log_cb_(log_cb) { | 134 log_cb_(log_cb) { |
| 135 } | 135 } |
| 136 | 136 |
| 137 FFmpegAudioDecoder::~FFmpegAudioDecoder() { | 137 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
| 138 DCHECK_EQ(state_, kUninitialized); | 138 DCHECK_EQ(state_, kUninitialized); |
| 139 DCHECK(!codec_context_); | 139 DCHECK(!codec_context_); |
| 140 DCHECK(!av_frame_); | 140 DCHECK(!av_frame_); |
| 141 } | 141 } |
| 142 | 142 |
| 143 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, | 143 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, |
| 144 const PipelineStatusCB& status_cb, | 144 const PipelineStatusCB& status_cb) { |
| 145 const OutputCB& output_cb) { | |
| 146 DCHECK(task_runner_->BelongsToCurrentThread()); | 145 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 147 DCHECK(!config.is_encrypted()); | 146 DCHECK(!config.is_encrypted()); |
| 148 | 147 |
| 149 FFmpegGlue::InitializeFFmpeg(); | 148 FFmpegGlue::InitializeFFmpeg(); |
| 150 | 149 |
| 151 config_ = config; | 150 config_ = config; |
| 152 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 151 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
| 153 | 152 |
| 154 if (!config.IsValidConfig() || !ConfigureDecoder()) { | 153 if (!config.IsValidConfig() || !ConfigureDecoder()) { |
| 155 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 154 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
| 156 return; | 155 return; |
| 157 } | 156 } |
| 158 | 157 |
| 159 // Success! | 158 // Success! |
| 160 output_cb_ = BindToCurrentLoop(output_cb); | |
| 161 state_ = kNormal; | 159 state_ = kNormal; |
| 162 initialize_cb.Run(PIPELINE_OK); | 160 initialize_cb.Run(PIPELINE_OK); |
| 163 } | 161 } |
| 164 | 162 |
| 165 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 163 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 166 const DecodeCB& decode_cb) { | 164 const DecodeCB& decode_cb) { |
| 167 DCHECK(task_runner_->BelongsToCurrentThread()); | 165 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 168 DCHECK(!decode_cb.is_null()); | 166 DCHECK(!decode_cb.is_null()); |
| 169 CHECK_NE(state_, kUninitialized); | 167 CHECK_NE(state_, kUninitialized); |
| 170 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); | 168 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); |
| 171 | 169 |
| 172 if (state_ == kError) { | 170 if (state_ == kError) { |
| 173 decode_cb_bound.Run(kDecodeError); | 171 decode_cb_bound.Run(kDecodeError, NULL); |
| 174 return; | 172 return; |
| 175 } | 173 } |
| 176 | 174 |
| 177 // Do nothing if decoding has finished. | 175 // Return empty frames if decoding has finished. |
| 178 if (state_ == kDecodeFinished) { | 176 if (state_ == kDecodeFinished) { |
| 179 decode_cb_bound.Run(kOk); | 177 decode_cb_bound.Run(kOk, AudioBuffer::CreateEOSBuffer()); |
| 178 return; |
| 179 } |
| 180 |
| 181 if (!buffer) { |
| 182 decode_cb_bound.Run(kAborted, NULL); |
| 180 return; | 183 return; |
| 181 } | 184 } |
| 182 | 185 |
| 183 DecodeBuffer(buffer, decode_cb_bound); | 186 DecodeBuffer(buffer, decode_cb_bound); |
| 184 } | 187 } |
| 185 | 188 |
| 189 scoped_refptr<AudioBuffer> FFmpegAudioDecoder::GetDecodeOutput() { |
| 190 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 191 if (queued_audio_.empty()) |
| 192 return NULL; |
| 193 scoped_refptr<AudioBuffer> out = queued_audio_.front(); |
| 194 queued_audio_.pop_front(); |
| 195 return out; |
| 196 } |
| 197 |
| 186 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { | 198 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { |
| 187 DCHECK(task_runner_->BelongsToCurrentThread()); | 199 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 188 | 200 |
| 189 avcodec_flush_buffers(codec_context_.get()); | 201 avcodec_flush_buffers(codec_context_.get()); |
| 190 state_ = kNormal; | 202 state_ = kNormal; |
| 191 ResetTimestampState(); | 203 ResetTimestampState(); |
| 192 task_runner_->PostTask(FROM_HERE, closure); | 204 task_runner_->PostTask(FROM_HERE, closure); |
| 193 } | 205 } |
| 194 | 206 |
| 195 void FFmpegAudioDecoder::Stop() { | 207 void FFmpegAudioDecoder::Stop() { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 // When avcodec_decode_audio4() returns 0 data. | 250 // When avcodec_decode_audio4() returns 0 data. |
| 239 // kFlushCodec -> kError: | 251 // kFlushCodec -> kError: |
| 240 // When avcodec_decode_audio4() errors out. | 252 // When avcodec_decode_audio4() errors out. |
| 241 // (any state) -> kNormal: | 253 // (any state) -> kNormal: |
| 242 // Any time Reset() is called. | 254 // Any time Reset() is called. |
| 243 | 255 |
| 244 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 256 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
| 245 // occurs with some damaged files. | 257 // occurs with some damaged files. |
| 246 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { | 258 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { |
| 247 DVLOG(1) << "Received a buffer without timestamps!"; | 259 DVLOG(1) << "Received a buffer without timestamps!"; |
| 248 decode_cb.Run(kDecodeError); | 260 decode_cb.Run(kDecodeError, NULL); |
| 249 return; | 261 return; |
| 250 } | 262 } |
| 251 | 263 |
| 252 if (!buffer->end_of_stream() && !discard_helper_->initialized() && | 264 if (!buffer->end_of_stream() && !discard_helper_->initialized() && |
| 253 codec_context_->codec_id == AV_CODEC_ID_VORBIS && | 265 codec_context_->codec_id == AV_CODEC_ID_VORBIS && |
| 254 buffer->timestamp() < base::TimeDelta()) { | 266 buffer->timestamp() < base::TimeDelta()) { |
| 255 // Dropping frames for negative timestamps as outlined in section A.2 | 267 // Dropping frames for negative timestamps as outlined in section A.2 |
| 256 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 268 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
| 257 const int discard_frames = | 269 const int discard_frames = |
| 258 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); | 270 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); |
| 259 discard_helper_->Reset(discard_frames); | 271 discard_helper_->Reset(discard_frames); |
| 260 } | 272 } |
| 261 | 273 |
| 274 // Transition to kFlushCodec on the first end of stream buffer. |
| 275 if (state_ == kNormal && buffer->end_of_stream()) { |
| 276 state_ = kFlushCodec; |
| 277 } |
| 278 |
| 262 if (!FFmpegDecode(buffer)) { | 279 if (!FFmpegDecode(buffer)) { |
| 263 state_ = kError; | 280 state_ = kError; |
| 264 decode_cb.Run(kDecodeError); | 281 decode_cb.Run(kDecodeError, NULL); |
| 265 return; | 282 return; |
| 266 } | 283 } |
| 267 | 284 |
| 268 if (buffer->end_of_stream()) { | 285 if (queued_audio_.empty()) { |
| 269 state_ = kDecodeFinished; | 286 if (state_ == kFlushCodec) { |
| 270 output_cb_.Run(AudioBuffer::CreateEOSBuffer()); | 287 DCHECK(buffer->end_of_stream()); |
| 288 state_ = kDecodeFinished; |
| 289 decode_cb.Run(kOk, AudioBuffer::CreateEOSBuffer()); |
| 290 return; |
| 291 } |
| 292 |
| 293 decode_cb.Run(kNotEnoughData, NULL); |
| 294 return; |
| 271 } | 295 } |
| 272 | 296 |
| 273 decode_cb.Run(kOk); | 297 decode_cb.Run(kOk, queued_audio_.front()); |
| 298 queued_audio_.pop_front(); |
| 274 } | 299 } |
| 275 | 300 |
| 276 bool FFmpegAudioDecoder::FFmpegDecode( | 301 bool FFmpegAudioDecoder::FFmpegDecode( |
| 277 const scoped_refptr<DecoderBuffer>& buffer) { | 302 const scoped_refptr<DecoderBuffer>& buffer) { |
| 303 DCHECK(queued_audio_.empty()); |
| 304 |
| 278 AVPacket packet; | 305 AVPacket packet; |
| 279 av_init_packet(&packet); | 306 av_init_packet(&packet); |
| 280 if (buffer->end_of_stream()) { | 307 if (buffer->end_of_stream()) { |
| 281 packet.data = NULL; | 308 packet.data = NULL; |
| 282 packet.size = 0; | 309 packet.size = 0; |
| 283 } else { | 310 } else { |
| 284 packet.data = const_cast<uint8*>(buffer->data()); | 311 packet.data = const_cast<uint8*>(buffer->data()); |
| 285 packet.size = buffer->data_size(); | 312 packet.size = buffer->data_size(); |
| 286 } | 313 } |
| 287 | 314 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 << ", Sample Format: " << av_frame_->format << " vs " | 355 << ", Sample Format: " << av_frame_->format << " vs " |
| 329 << av_sample_format_; | 356 << av_sample_format_; |
| 330 | 357 |
| 331 if (config_.codec() == kCodecAAC && | 358 if (config_.codec() == kCodecAAC && |
| 332 av_frame_->sample_rate == 2 * config_.samples_per_second()) { | 359 av_frame_->sample_rate == 2 * config_.samples_per_second()) { |
| 333 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used." | 360 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used." |
| 334 << " Please use mp4a.40.5 instead of mp4a.40.2 in" | 361 << " Please use mp4a.40.5 instead of mp4a.40.2 in" |
| 335 << " the mimetype."; | 362 << " the mimetype."; |
| 336 } | 363 } |
| 337 // This is an unrecoverable error, so bail out. | 364 // This is an unrecoverable error, so bail out. |
| 365 queued_audio_.clear(); |
| 338 av_frame_unref(av_frame_.get()); | 366 av_frame_unref(av_frame_.get()); |
| 339 return false; | 367 return false; |
| 340 } | 368 } |
| 341 | 369 |
| 342 // Get the AudioBuffer that the data was decoded into. Adjust the number | 370 // Get the AudioBuffer that the data was decoded into. Adjust the number |
| 343 // of frames, in case fewer than requested were actually decoded. | 371 // of frames, in case fewer than requested were actually decoded. |
| 344 output = reinterpret_cast<AudioBuffer*>( | 372 output = reinterpret_cast<AudioBuffer*>( |
| 345 av_buffer_get_opaque(av_frame_->buf[0])); | 373 av_buffer_get_opaque(av_frame_->buf[0])); |
| 346 | 374 |
| 347 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), | 375 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), |
| 348 output->channel_count()); | 376 output->channel_count()); |
| 349 const int unread_frames = output->frame_count() - av_frame_->nb_samples; | 377 const int unread_frames = output->frame_count() - av_frame_->nb_samples; |
| 350 DCHECK_GE(unread_frames, 0); | 378 DCHECK_GE(unread_frames, 0); |
| 351 if (unread_frames > 0) | 379 if (unread_frames > 0) |
| 352 output->TrimEnd(unread_frames); | 380 output->TrimEnd(unread_frames); |
| 353 av_frame_unref(av_frame_.get()); | 381 av_frame_unref(av_frame_.get()); |
| 354 } | 382 } |
| 355 | 383 |
| 356 // WARNING: |av_frame_| no longer has valid data at this point. | 384 // WARNING: |av_frame_| no longer has valid data at this point. |
| 357 const int decoded_frames = frame_decoded ? output->frame_count() : 0; | 385 const int decoded_frames = frame_decoded ? output->frame_count() : 0; |
| 358 if (IsEndOfStream(result, decoded_frames, buffer)) { | 386 if (IsEndOfStream(result, decoded_frames, buffer)) { |
| 359 DCHECK_EQ(packet.size, 0); | 387 DCHECK_EQ(packet.size, 0); |
| 360 output_cb_.Run(AudioBuffer::CreateEOSBuffer()); | 388 queued_audio_.push_back(AudioBuffer::CreateEOSBuffer()); |
| 361 } else if (discard_helper_->ProcessBuffers(buffer, output)) { | 389 } else if (discard_helper_->ProcessBuffers(buffer, output)) { |
| 362 output_cb_.Run(output); | 390 queued_audio_.push_back(output); |
| 363 } | 391 } |
| 364 } while (packet.size > 0); | 392 } while (packet.size > 0); |
| 365 | 393 |
| 366 return true; | 394 return true; |
| 367 } | 395 } |
| 368 | 396 |
| 369 void FFmpegAudioDecoder::ReleaseFFmpegResources() { | 397 void FFmpegAudioDecoder::ReleaseFFmpegResources() { |
| 370 codec_context_.reset(); | 398 codec_context_.reset(); |
| 371 av_frame_.reset(); | 399 av_frame_.reset(); |
| 372 } | 400 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 | 453 |
| 426 ResetTimestampState(); | 454 ResetTimestampState(); |
| 427 return true; | 455 return true; |
| 428 } | 456 } |
| 429 | 457 |
| 430 void FFmpegAudioDecoder::ResetTimestampState() { | 458 void FFmpegAudioDecoder::ResetTimestampState() { |
| 431 discard_helper_->Reset(config_.codec_delay()); | 459 discard_helper_->Reset(config_.codec_delay()); |
| 432 } | 460 } |
| 433 | 461 |
| 434 } // namespace media | 462 } // namespace media |
| OLD | NEW |