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" |
11 #include "media/base/audio_decoder_config.h" | 11 #include "media/base/audio_decoder_config.h" |
12 #include "media/base/audio_timestamp_helper.h" | 12 #include "media/base/audio_discard_helper.h" |
13 #include "media/base/bind_to_current_loop.h" | 13 #include "media/base/bind_to_current_loop.h" |
14 #include "media/base/decoder_buffer.h" | 14 #include "media/base/decoder_buffer.h" |
15 #include "media/base/limits.h" | 15 #include "media/base/limits.h" |
16 #include "media/base/sample_format.h" | 16 #include "media/base/sample_format.h" |
17 #include "media/ffmpeg/ffmpeg_common.h" | 17 #include "media/ffmpeg/ffmpeg_common.h" |
18 #include "media/filters/ffmpeg_glue.h" | 18 #include "media/filters/ffmpeg_glue.h" |
19 | 19 |
20 namespace media { | 20 namespace media { |
21 | 21 |
22 // Returns true if the decode result was end of stream. | 22 // Returns true if the decode result was end of stream. |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
122 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); | 122 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); |
123 frame->buf[0] = av_buffer_create( | 123 frame->buf[0] = av_buffer_create( |
124 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); | 124 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); |
125 return 0; | 125 return 0; |
126 } | 126 } |
127 | 127 |
128 FFmpegAudioDecoder::FFmpegAudioDecoder( | 128 FFmpegAudioDecoder::FFmpegAudioDecoder( |
129 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 129 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
130 : task_runner_(task_runner), | 130 : task_runner_(task_runner), |
131 state_(kUninitialized), | 131 state_(kUninitialized), |
132 av_sample_format_(0), | 132 av_sample_format_(0) {} |
133 last_input_timestamp_(kNoTimestamp()), | |
134 output_frames_to_drop_(0) {} | |
135 | 133 |
136 FFmpegAudioDecoder::~FFmpegAudioDecoder() { | 134 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
137 DCHECK_EQ(state_, kUninitialized); | 135 DCHECK_EQ(state_, kUninitialized); |
138 DCHECK(!codec_context_); | 136 DCHECK(!codec_context_); |
139 DCHECK(!av_frame_); | 137 DCHECK(!av_frame_); |
140 } | 138 } |
141 | 139 |
142 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, | 140 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, |
143 const PipelineStatusCB& status_cb) { | 141 const PipelineStatusCB& status_cb) { |
144 DCHECK(task_runner_->BelongsToCurrentThread()); | 142 DCHECK(task_runner_->BelongsToCurrentThread()); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 // A decoding error occurs and decoding needs to stop. | 245 // A decoding error occurs and decoding needs to stop. |
248 // kFlushCodec -> kDecodeFinished: | 246 // kFlushCodec -> kDecodeFinished: |
249 // When avcodec_decode_audio4() returns 0 data. | 247 // When avcodec_decode_audio4() returns 0 data. |
250 // kFlushCodec -> kError: | 248 // kFlushCodec -> kError: |
251 // When avcodec_decode_audio4() errors out. | 249 // When avcodec_decode_audio4() errors out. |
252 // (any state) -> kNormal: | 250 // (any state) -> kNormal: |
253 // Any time Reset() is called. | 251 // Any time Reset() is called. |
254 | 252 |
255 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 253 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
256 // occurs with some damaged files. | 254 // occurs with some damaged files. |
257 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp() && | 255 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { |
wolenetz
2014/04/28 21:52:07
Was it incorrect previously to also condition this
DaleCurtis
2014/04/28 22:03:51
I've removed this exception as the only time this
| |
258 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { | |
259 DVLOG(1) << "Received a buffer without timestamps!"; | 256 DVLOG(1) << "Received a buffer without timestamps!"; |
260 decode_cb.Run(kDecodeError, NULL); | 257 decode_cb.Run(kDecodeError, NULL); |
261 return; | 258 return; |
262 } | 259 } |
263 | 260 |
264 if (!buffer->end_of_stream()) { | 261 if (!buffer->end_of_stream() && |
265 DCHECK(buffer->timestamp() != kNoTimestamp()); | 262 !discard_helper_->initialized() && |
266 const bool first_buffer = | 263 codec_context_->codec_id == AV_CODEC_ID_VORBIS && |
267 last_input_timestamp_ == kNoTimestamp() && | 264 buffer->timestamp() < base::TimeDelta()) { |
268 output_timestamp_helper_->base_timestamp() == kNoTimestamp(); | 265 // Dropping frames for negative timestamps as outlined in section A.2 |
269 if (first_buffer && codec_context_->codec_id == AV_CODEC_ID_VORBIS && | 266 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
270 buffer->timestamp() < base::TimeDelta()) { | 267 const int discard_frames = |
wolenetz
2014/04/28 21:52:07
If a stream has both a codec_delay and a negative
DaleCurtis
2014/04/28 22:03:51
For now this code is sufficient since it just impl
| |
271 // Dropping frames for negative timestamps as outlined in section A.2 | 268 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); |
wolenetz
2014/04/28 21:52:07
Previously, we rounded vs currently using ceil. Wh
DaleCurtis
2014/04/28 22:03:51
ceil(). It doesn't make sense to discard 1.5 fram
wolenetz
2014/04/28 22:37:56
Suppose we have frame rate of 48000 frames/sec and
DaleCurtis
2014/04/28 23:09:03
You can see how the values are converted in ffmpeg
| |
272 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 269 discard_helper_->Reset(discard_frames); |
wolenetz
2014/04/28 21:52:07
Is the following piece of that section A.2 Vorbis
DaleCurtis
2014/04/28 22:03:51
This is not verified. I'd fix that in a separate
wolenetz
2014/04/29 00:22:44
Seems low-pri (we might reject streams that are sl
DaleCurtis
2014/04/29 00:28:59
I don't think it's necessary to worry about.
| |
273 DCHECK_EQ(output_frames_to_drop_, 0); | |
274 output_frames_to_drop_ = | |
275 0.5 + | |
276 -buffer->timestamp().InSecondsF() * config_.samples_per_second(); | |
277 | |
278 // If we are dropping samples for Vorbis, the timeline always starts at 0. | |
279 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | |
280 } else { | |
281 if (first_buffer) { | |
282 output_timestamp_helper_->SetBaseTimestamp(buffer->timestamp()); | |
283 } else if (buffer->timestamp() < last_input_timestamp_) { | |
284 const base::TimeDelta diff = | |
285 buffer->timestamp() - last_input_timestamp_; | |
286 DLOG(WARNING) << "Input timestamps are not monotonically increasing! " | |
287 << " ts " << buffer->timestamp().InMicroseconds() << " us" | |
288 << " diff " << diff.InMicroseconds() << " us"; | |
289 } | |
290 | |
291 last_input_timestamp_ = buffer->timestamp(); | |
292 } | |
293 } | 270 } |
294 | 271 |
295 // Transition to kFlushCodec on the first end of stream buffer. | 272 // Transition to kFlushCodec on the first end of stream buffer. |
296 if (state_ == kNormal && buffer->end_of_stream()) { | 273 if (state_ == kNormal && buffer->end_of_stream()) { |
297 state_ = kFlushCodec; | 274 state_ = kFlushCodec; |
298 } | 275 } |
299 | 276 |
300 if (!FFmpegDecode(buffer)) { | 277 if (!FFmpegDecode(buffer)) { |
301 state_ = kError; | 278 state_ = kError; |
302 decode_cb.Run(kDecodeError, NULL); | 279 decode_cb.Run(kDecodeError, NULL); |
(...skipping 11 matching lines...) Expand all Loading... | |
314 decode_cb.Run(kNotEnoughData, NULL); | 291 decode_cb.Run(kNotEnoughData, NULL); |
315 return; | 292 return; |
316 } | 293 } |
317 | 294 |
318 decode_cb.Run(kOk, queued_audio_.front()); | 295 decode_cb.Run(kOk, queued_audio_.front()); |
319 queued_audio_.pop_front(); | 296 queued_audio_.pop_front(); |
320 } | 297 } |
321 | 298 |
322 bool FFmpegAudioDecoder::FFmpegDecode( | 299 bool FFmpegAudioDecoder::FFmpegDecode( |
323 const scoped_refptr<DecoderBuffer>& buffer) { | 300 const scoped_refptr<DecoderBuffer>& buffer) { |
324 | |
325 DCHECK(queued_audio_.empty()); | 301 DCHECK(queued_audio_.empty()); |
326 | 302 |
327 AVPacket packet; | 303 AVPacket packet; |
328 av_init_packet(&packet); | 304 av_init_packet(&packet); |
329 if (buffer->end_of_stream()) { | 305 if (buffer->end_of_stream()) { |
330 packet.data = NULL; | 306 packet.data = NULL; |
331 packet.size = 0; | 307 packet.size = 0; |
332 } else { | 308 } else { |
333 packet.data = const_cast<uint8*>(buffer->data()); | 309 packet.data = const_cast<uint8*>(buffer->data()); |
334 packet.size = buffer->data_size(); | 310 packet.size = buffer->data_size(); |
335 } | 311 } |
336 | 312 |
337 // Each audio packet may contain several frames, so we must call the decoder | 313 // Each audio packet may contain several frames, so we must call the decoder |
338 // until we've exhausted the packet. Regardless of the packet size we always | 314 // until we've exhausted the packet. Regardless of the packet size we always |
339 // want to hand it to the decoder at least once, otherwise we would end up | 315 // want to hand it to the decoder at least once, otherwise we would end up |
340 // skipping end of stream packets since they have a size of zero. | 316 // skipping end of stream packets since they have a size of zero. |
341 do { | 317 do { |
342 int frame_decoded = 0; | 318 int frame_decoded = 0; |
343 int result = avcodec_decode_audio4( | 319 const int result = avcodec_decode_audio4( |
344 codec_context_.get(), av_frame_.get(), &frame_decoded, &packet); | 320 codec_context_.get(), av_frame_.get(), &frame_decoded, &packet); |
345 | 321 |
346 if (result < 0) { | 322 if (result < 0) { |
347 DCHECK(!buffer->end_of_stream()) | 323 DCHECK(!buffer->end_of_stream()) |
348 << "End of stream buffer produced an error! " | 324 << "End of stream buffer produced an error! " |
349 << "This is quite possibly a bug in the audio decoder not handling " | 325 << "This is quite possibly a bug in the audio decoder not handling " |
350 << "end of stream AVPackets correctly."; | 326 << "end of stream AVPackets correctly."; |
351 | 327 |
352 DLOG(WARNING) | 328 DLOG(WARNING) |
353 << "Failed to decode an audio frame with timestamp: " | 329 << "Failed to decode an audio frame with timestamp: " |
354 << buffer->timestamp().InMicroseconds() << " us, duration: " | 330 << buffer->timestamp().InMicroseconds() << " us, duration: " |
355 << buffer->duration().InMicroseconds() << " us, packet size: " | 331 << buffer->duration().InMicroseconds() << " us, packet size: " |
356 << buffer->data_size() << " bytes"; | 332 << buffer->data_size() << " bytes"; |
357 | 333 |
358 break; | 334 break; |
359 } | 335 } |
360 | 336 |
361 // Update packet size and data pointer in case we need to call the decoder | 337 // Update packet size and data pointer in case we need to call the decoder |
362 // with the remaining bytes from this packet. | 338 // with the remaining bytes from this packet. |
363 packet.size -= result; | 339 packet.size -= result; |
364 packet.data += result; | 340 packet.data += result; |
365 | 341 |
366 scoped_refptr<AudioBuffer> output; | 342 scoped_refptr<AudioBuffer> output; |
367 int decoded_frames = 0; | 343 const int channels = DetermineChannels(av_frame_.get()); |
368 int original_frames = 0; | |
369 int channels = DetermineChannels(av_frame_.get()); | |
370 if (frame_decoded) { | 344 if (frame_decoded) { |
371 if (av_frame_->sample_rate != config_.samples_per_second() || | 345 if (av_frame_->sample_rate != config_.samples_per_second() || |
372 channels != ChannelLayoutToChannelCount(config_.channel_layout()) || | 346 channels != ChannelLayoutToChannelCount(config_.channel_layout()) || |
373 av_frame_->format != av_sample_format_) { | 347 av_frame_->format != av_sample_format_) { |
374 DLOG(ERROR) << "Unsupported midstream configuration change!" | 348 DLOG(ERROR) << "Unsupported midstream configuration change!" |
375 << " Sample Rate: " << av_frame_->sample_rate << " vs " | 349 << " Sample Rate: " << av_frame_->sample_rate << " vs " |
376 << config_.samples_per_second() | 350 << config_.samples_per_second() |
377 << ", Channels: " << channels << " vs " | 351 << ", Channels: " << channels << " vs " |
378 << ChannelLayoutToChannelCount(config_.channel_layout()) | 352 << ChannelLayoutToChannelCount(config_.channel_layout()) |
379 << ", Sample Format: " << av_frame_->format << " vs " | 353 << ", Sample Format: " << av_frame_->format << " vs " |
380 << av_sample_format_; | 354 << av_sample_format_; |
381 | 355 |
382 // This is an unrecoverable error, so bail out. | 356 // This is an unrecoverable error, so bail out. |
383 queued_audio_.clear(); | 357 queued_audio_.clear(); |
384 av_frame_unref(av_frame_.get()); | 358 av_frame_unref(av_frame_.get()); |
385 return false; | 359 return false; |
386 } | 360 } |
387 | 361 |
388 // Get the AudioBuffer that the data was decoded into. Adjust the number | 362 // Get the AudioBuffer that the data was decoded into. Adjust the number |
389 // of frames, in case fewer than requested were actually decoded. | 363 // of frames, in case fewer than requested were actually decoded. |
390 output = reinterpret_cast<AudioBuffer*>( | 364 output = reinterpret_cast<AudioBuffer*>( |
391 av_buffer_get_opaque(av_frame_->buf[0])); | 365 av_buffer_get_opaque(av_frame_->buf[0])); |
392 | 366 |
393 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), | 367 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), |
394 output->channel_count()); | 368 output->channel_count()); |
395 original_frames = av_frame_->nb_samples; | 369 const int unread_frames = output->frame_count() - av_frame_->nb_samples; |
396 int unread_frames = output->frame_count() - original_frames; | |
397 DCHECK_GE(unread_frames, 0); | 370 DCHECK_GE(unread_frames, 0); |
398 if (unread_frames > 0) | 371 if (unread_frames > 0) |
399 output->TrimEnd(unread_frames); | 372 output->TrimEnd(unread_frames); |
400 | 373 |
401 // If there are frames to drop, get rid of as many as we can. | |
402 if (output_frames_to_drop_ > 0) { | |
403 int drop = std::min(output->frame_count(), output_frames_to_drop_); | |
404 output->TrimStart(drop); | |
405 output_frames_to_drop_ -= drop; | |
406 } | |
407 | |
408 decoded_frames = output->frame_count(); | |
409 av_frame_unref(av_frame_.get()); | 374 av_frame_unref(av_frame_.get()); |
410 } | 375 } |
411 | 376 |
412 // WARNING: |av_frame_| no longer has valid data at this point. | 377 // WARNING: |av_frame_| no longer has valid data at this point. |
413 | 378 const int decoded_frames = frame_decoded ? output->frame_count() : 0; |
414 if (decoded_frames > 0) { | 379 if (IsEndOfStream(result, decoded_frames, buffer)) { |
415 // Set the timestamp/duration once all the extra frames have been | |
416 // discarded. | |
417 output->set_timestamp(output_timestamp_helper_->GetTimestamp()); | |
418 output->set_duration( | |
419 output_timestamp_helper_->GetFrameDuration(decoded_frames)); | |
420 output_timestamp_helper_->AddFrames(decoded_frames); | |
421 } else if (IsEndOfStream(result, original_frames, buffer)) { | |
422 DCHECK_EQ(packet.size, 0); | 380 DCHECK_EQ(packet.size, 0); |
423 output = AudioBuffer::CreateEOSBuffer(); | 381 queued_audio_.push_back(AudioBuffer::CreateEOSBuffer()); |
424 } else { | 382 } else if (discard_helper_->ProcessBuffers(buffer, output)) { |
wolenetz
2014/04/28 21:52:07
Should any encoded buffer originating from ffmpeg_
DaleCurtis
2014/04/28 22:03:51
It's possible for buffers originating from ffmpeg
| |
425 // In case all the frames in the buffer were dropped. | 383 queued_audio_.push_back(output); |
426 output = NULL; | |
427 } | 384 } |
428 | |
429 if (output.get()) | |
430 queued_audio_.push_back(output); | |
431 | |
432 } while (packet.size > 0); | 385 } while (packet.size > 0); |
433 | 386 |
434 return true; | 387 return true; |
435 } | 388 } |
436 | 389 |
437 void FFmpegAudioDecoder::ReleaseFFmpegResources() { | 390 void FFmpegAudioDecoder::ReleaseFFmpegResources() { |
438 codec_context_.reset(); | 391 codec_context_.reset(); |
439 av_frame_.reset(); | 392 av_frame_.reset(); |
440 } | 393 } |
441 | 394 |
(...skipping 27 matching lines...) Expand all Loading... | |
469 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { | 422 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { |
470 DLOG(ERROR) << "Could not initialize audio decoder: " | 423 DLOG(ERROR) << "Could not initialize audio decoder: " |
471 << codec_context_->codec_id; | 424 << codec_context_->codec_id; |
472 ReleaseFFmpegResources(); | 425 ReleaseFFmpegResources(); |
473 state_ = kUninitialized; | 426 state_ = kUninitialized; |
474 return false; | 427 return false; |
475 } | 428 } |
476 | 429 |
477 // Success! | 430 // Success! |
478 av_frame_.reset(av_frame_alloc()); | 431 av_frame_.reset(av_frame_alloc()); |
479 output_timestamp_helper_.reset( | 432 discard_helper_.reset(new AudioDiscardHelper(config_.samples_per_second())); |
480 new AudioTimestampHelper(config_.samples_per_second())); | |
481 ResetTimestampState(); | |
482 | |
483 av_sample_format_ = codec_context_->sample_fmt; | 433 av_sample_format_ = codec_context_->sample_fmt; |
484 | 434 |
485 if (codec_context_->channels != | 435 if (codec_context_->channels != |
486 ChannelLayoutToChannelCount(config_.channel_layout())) { | 436 ChannelLayoutToChannelCount(config_.channel_layout())) { |
487 DLOG(ERROR) << "Audio configuration specified " | 437 DLOG(ERROR) << "Audio configuration specified " |
488 << ChannelLayoutToChannelCount(config_.channel_layout()) | 438 << ChannelLayoutToChannelCount(config_.channel_layout()) |
489 << " channels, but FFmpeg thinks the file contains " | 439 << " channels, but FFmpeg thinks the file contains " |
490 << codec_context_->channels << " channels"; | 440 << codec_context_->channels << " channels"; |
491 ReleaseFFmpegResources(); | 441 ReleaseFFmpegResources(); |
492 state_ = kUninitialized; | 442 state_ = kUninitialized; |
493 return false; | 443 return false; |
494 } | 444 } |
495 | 445 |
496 output_frames_to_drop_ = config_.codec_delay(); | 446 ResetTimestampState(); |
497 return true; | 447 return true; |
498 } | 448 } |
499 | 449 |
500 void FFmpegAudioDecoder::ResetTimestampState() { | 450 void FFmpegAudioDecoder::ResetTimestampState() { |
501 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 451 discard_helper_->Reset(config_.codec_delay()); |
502 last_input_timestamp_ = kNoTimestamp(); | |
503 output_frames_to_drop_ = 0; | |
504 } | 452 } |
505 | 453 |
506 } // namespace media | 454 } // namespace media |
OLD | NEW |