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/opus_audio_decoder.h" | 5 #include "media/filters/opus_audio_decoder.h" |
6 | 6 |
7 #include <cmath> | |
8 | |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
9 #include "base/location.h" | 11 #include "base/location.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 12 #include "base/message_loop/message_loop_proxy.h" |
11 #include "base/sys_byteorder.h" | 13 #include "base/sys_byteorder.h" |
12 #include "media/base/audio_buffer.h" | 14 #include "media/base/audio_buffer.h" |
13 #include "media/base/audio_decoder_config.h" | 15 #include "media/base/audio_decoder_config.h" |
14 #include "media/base/audio_timestamp_helper.h" | 16 #include "media/base/audio_timestamp_helper.h" |
15 #include "media/base/bind_to_loop.h" | 17 #include "media/base/bind_to_loop.h" |
16 #include "media/base/buffers.h" | 18 #include "media/base/buffers.h" |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 OpusAudioDecoder::OpusAudioDecoder( | 245 OpusAudioDecoder::OpusAudioDecoder( |
244 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 246 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
245 : message_loop_(message_loop), | 247 : message_loop_(message_loop), |
246 weak_factory_(this), | 248 weak_factory_(this), |
247 demuxer_stream_(NULL), | 249 demuxer_stream_(NULL), |
248 opus_decoder_(NULL), | 250 opus_decoder_(NULL), |
249 bits_per_channel_(0), | 251 bits_per_channel_(0), |
250 channel_layout_(CHANNEL_LAYOUT_NONE), | 252 channel_layout_(CHANNEL_LAYOUT_NONE), |
251 samples_per_second_(0), | 253 samples_per_second_(0), |
252 last_input_timestamp_(kNoTimestamp()), | 254 last_input_timestamp_(kNoTimestamp()), |
253 output_bytes_to_drop_(0), | |
254 skip_samples_(0) { | 255 skip_samples_(0) { |
255 } | 256 } |
256 | 257 |
257 void OpusAudioDecoder::Initialize( | 258 void OpusAudioDecoder::Initialize( |
258 DemuxerStream* stream, | 259 DemuxerStream* stream, |
259 const PipelineStatusCB& status_cb, | 260 const PipelineStatusCB& status_cb, |
260 const StatisticsCB& statistics_cb) { | 261 const StatisticsCB& statistics_cb) { |
261 DCHECK(message_loop_->BelongsToCurrentThread()); | 262 DCHECK(message_loop_->BelongsToCurrentThread()); |
262 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 263 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
263 | 264 |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
450 // Allocate the output buffer if necessary. | 451 // Allocate the output buffer if necessary. |
451 if (!output_buffer_) | 452 if (!output_buffer_) |
452 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); | 453 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); |
453 | 454 |
454 // Parse the Opus header. | 455 // Parse the Opus header. |
455 OpusHeader opus_header; | 456 OpusHeader opus_header; |
456 ParseOpusHeader(config.extra_data(), config.extra_data_size(), | 457 ParseOpusHeader(config.extra_data(), config.extra_data_size(), |
457 config, | 458 config, |
458 &opus_header); | 459 &opus_header); |
459 | 460 |
460 skip_samples_ = opus_header.skip_samples; | 461 if (!config.codec_delay().InMicroseconds()) { |
acolwell GONE FROM CHROMIUM
2013/09/03 20:14:01
Shouldn't this return false to trigger a decode er
vignesh
2013/09/03 22:43:03
Agreed. Done.
But doing this stricter check will
acolwell GONE FROM CHROMIUM
2013/09/03 23:53:43
Hmm. I don't want people who have been experimenti
| |
461 | 462 skip_samples_ = opus_header.skip_samples; |
462 if (skip_samples_ > 0) | 463 } else { |
463 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); | 464 // Convert from seconds to samples. |
465 skip_samples_ = std::ceil(config.codec_delay().InMicroseconds() * | |
466 config.samples_per_second() / | |
467 static_cast<double>(1000000)); | |
acolwell GONE FROM CHROMIUM
2013/09/03 20:14:01
nit: 1000000.0 should remove the need for a static
vignesh
2013/09/03 22:43:03
Done.
| |
468 if (skip_samples_ < 0) { | |
469 DVLOG(1) << "Invalid file. Incorrect value for codec delay."; | |
470 return false; | |
471 } | |
472 if (skip_samples_ != opus_header.skip_samples) { | |
473 DVLOG(1) << "Invalid file. Codec Delay in container does not match the " | |
474 << "value in Opus header."; | |
475 return false; | |
476 } | |
477 } | |
464 | 478 |
465 uint8 channel_mapping[kMaxVorbisChannels]; | 479 uint8 channel_mapping[kMaxVorbisChannels]; |
466 memcpy(&channel_mapping, | 480 memcpy(&channel_mapping, |
467 kDefaultOpusChannelLayout, | 481 kDefaultOpusChannelLayout, |
468 kMaxChannelsWithDefaultLayout); | 482 kMaxChannelsWithDefaultLayout); |
469 | 483 |
470 if (channel_count > kMaxChannelsWithDefaultLayout) { | 484 if (channel_count > kMaxChannelsWithDefaultLayout) { |
471 RemapOpusChannelLayout(opus_header.stream_map, | 485 RemapOpusChannelLayout(opus_header.stream_map, |
472 channel_count, | 486 channel_count, |
473 channel_mapping); | 487 channel_mapping); |
474 } | 488 } |
475 | 489 |
476 // Init Opus. | 490 // Init Opus. |
477 int status = OPUS_INVALID_STATE; | 491 int status = OPUS_INVALID_STATE; |
478 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), | 492 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), |
479 channel_count, | 493 channel_count, |
480 opus_header.num_streams, | 494 opus_header.num_streams, |
481 opus_header.num_coupled, | 495 opus_header.num_coupled, |
482 channel_mapping, | 496 channel_mapping, |
483 &status); | 497 &status); |
484 if (!opus_decoder_ || status != OPUS_OK) { | 498 if (!opus_decoder_ || status != OPUS_OK) { |
485 LOG(ERROR) << "opus_multistream_decoder_create failed status=" | 499 LOG(ERROR) << "opus_multistream_decoder_create failed status=" |
486 << opus_strerror(status); | 500 << opus_strerror(status); |
487 return false; | 501 return false; |
488 } | 502 } |
489 | 503 |
490 // TODO(tomfinegan): Handle audio delay once the matroska spec is updated | |
491 // to represent the value. | |
492 | |
493 bits_per_channel_ = config.bits_per_channel(); | 504 bits_per_channel_ = config.bits_per_channel(); |
494 channel_layout_ = config.channel_layout(); | 505 channel_layout_ = config.channel_layout(); |
495 samples_per_second_ = config.samples_per_second(); | 506 samples_per_second_ = config.samples_per_second(); |
496 output_timestamp_helper_.reset( | 507 output_timestamp_helper_.reset( |
497 new AudioTimestampHelper(config.samples_per_second())); | 508 new AudioTimestampHelper(config.samples_per_second())); |
498 return true; | 509 return true; |
499 } | 510 } |
500 | 511 |
501 void OpusAudioDecoder::CloseDecoder() { | 512 void OpusAudioDecoder::CloseDecoder() { |
502 if (opus_decoder_) { | 513 if (opus_decoder_) { |
503 opus_multistream_decoder_destroy(opus_decoder_); | 514 opus_multistream_decoder_destroy(opus_decoder_); |
504 opus_decoder_ = NULL; | 515 opus_decoder_ = NULL; |
505 } | 516 } |
506 } | 517 } |
507 | 518 |
508 void OpusAudioDecoder::ResetTimestampState() { | 519 void OpusAudioDecoder::ResetTimestampState() { |
509 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 520 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
510 last_input_timestamp_ = kNoTimestamp(); | 521 last_input_timestamp_ = kNoTimestamp(); |
511 output_bytes_to_drop_ = 0; | 522 skip_samples_ = 0; |
512 } | 523 } |
513 | 524 |
514 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, | 525 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, |
515 scoped_refptr<AudioBuffer>* output_buffer) { | 526 scoped_refptr<AudioBuffer>* output_buffer) { |
516 int samples_decoded = opus_multistream_decode(opus_decoder_, | 527 int samples_decoded = opus_multistream_decode(opus_decoder_, |
517 input->data(), | 528 input->data(), |
518 input->data_size(), | 529 input->data_size(), |
519 &output_buffer_[0], | 530 &output_buffer_[0], |
520 kMaxOpusOutputPacketSizeSamples, | 531 kMaxOpusOutputPacketSizeSamples, |
521 0); | 532 0); |
(...skipping 10 matching lines...) Expand all Loading... | |
532 int decoded_audio_size = samples_decoded * | 543 int decoded_audio_size = samples_decoded * |
533 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | 544 demuxer_stream_->audio_decoder_config().bytes_per_frame(); |
534 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); | 545 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); |
535 | 546 |
536 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | 547 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
537 !input->end_of_stream()) { | 548 !input->end_of_stream()) { |
538 DCHECK(input->timestamp() != kNoTimestamp()); | 549 DCHECK(input->timestamp() != kNoTimestamp()); |
539 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); | 550 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); |
540 } | 551 } |
541 | 552 |
542 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { | |
543 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); | |
544 DCHECK_EQ(dropped_size % kBytesPerChannel, 0); | |
545 decoded_audio_data += dropped_size; | |
546 decoded_audio_size -= dropped_size; | |
547 output_bytes_to_drop_ -= dropped_size; | |
548 samples_decoded = decoded_audio_size / | |
549 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | |
550 } | |
551 | |
552 if (decoded_audio_size > 0) { | 553 if (decoded_audio_size > 0) { |
553 // Copy the audio samples into an output buffer. | 554 // Copy the audio samples into an output buffer. |
554 uint8* data[] = { decoded_audio_data }; | 555 uint8* data[] = { decoded_audio_data }; |
555 *output_buffer = AudioBuffer::CopyFrom( | 556 *output_buffer = AudioBuffer::CopyFrom( |
556 kSampleFormatS16, | 557 kSampleFormatS16, |
557 ChannelLayoutToChannelCount(channel_layout_), | 558 ChannelLayoutToChannelCount(channel_layout_), |
558 samples_decoded, | 559 samples_decoded, |
559 data, | 560 data, |
560 output_timestamp_helper_->GetTimestamp(), | 561 output_timestamp_helper_->GetTimestamp(), |
561 output_timestamp_helper_->GetFrameDuration(samples_decoded)); | 562 output_timestamp_helper_->GetFrameDuration(samples_decoded)); |
562 output_timestamp_helper_->AddFrames(samples_decoded); | 563 output_timestamp_helper_->AddFrames(samples_decoded); |
564 if (skip_samples_ > 0) { | |
565 int dropped_size = std::min(samples_decoded, skip_samples_); | |
566 output_buffer->get()->TrimStart(dropped_size); | |
567 skip_samples_ -= dropped_size; | |
568 samples_decoded -= dropped_size; | |
569 } | |
570 if (input->discard_padding().InMicroseconds() > 0) { | |
571 int discard_padding = std::ceil( | |
572 input->discard_padding().InMicroseconds() * | |
573 samples_per_second_ / | |
574 static_cast<double>(1000000)); | |
acolwell GONE FROM CHROMIUM
2013/09/03 20:14:01
ditto
vignesh
2013/09/03 22:43:03
Done.
| |
575 if (discard_padding < 0) { | |
576 DVLOG(1) << "Invalid file. Incorrect discard padding value."; | |
577 return false; | |
578 } | |
579 output_buffer->get()->TrimEnd(std::min(samples_decoded, discard_padding)); | |
acolwell GONE FROM CHROMIUM
2013/09/03 20:14:01
An error should probably be triggered if the disca
vignesh
2013/09/03 22:43:03
Done.
| |
580 samples_decoded -= discard_padding; | |
581 } | |
563 } | 582 } |
564 | 583 |
584 decoded_audio_size = | |
585 samples_decoded * | |
586 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | |
565 // Decoding finished successfully, update statistics. | 587 // Decoding finished successfully, update statistics. |
566 PipelineStatistics statistics; | 588 PipelineStatistics statistics; |
567 statistics.audio_bytes_decoded = decoded_audio_size; | 589 statistics.audio_bytes_decoded = decoded_audio_size; |
568 statistics_cb_.Run(statistics); | 590 statistics_cb_.Run(statistics); |
569 | 591 |
570 return true; | 592 return true; |
571 } | 593 } |
572 | 594 |
573 } // namespace media | 595 } // namespace media |
OLD | NEW |