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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 OpusAudioDecoder::OpusAudioDecoder( | 243 OpusAudioDecoder::OpusAudioDecoder( |
244 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 244 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
245 : message_loop_(message_loop), | 245 : message_loop_(message_loop), |
246 weak_factory_(this), | 246 weak_factory_(this), |
247 demuxer_stream_(NULL), | 247 demuxer_stream_(NULL), |
248 opus_decoder_(NULL), | 248 opus_decoder_(NULL), |
249 bits_per_channel_(0), | 249 bits_per_channel_(0), |
250 channel_layout_(CHANNEL_LAYOUT_NONE), | 250 channel_layout_(CHANNEL_LAYOUT_NONE), |
251 samples_per_second_(0), | 251 samples_per_second_(0), |
252 last_input_timestamp_(kNoTimestamp()), | 252 last_input_timestamp_(kNoTimestamp()), |
253 output_bytes_to_drop_(0), | |
acolwell GONE FROM CHROMIUM
2013/08/28 20:44:47
nit:It looks like you didn't remove this from the
vignesh
2013/08/29 21:37:31
Done.
| |
254 skip_samples_(0) { | 253 skip_samples_(0) { |
255 } | 254 } |
256 | 255 |
257 void OpusAudioDecoder::Initialize( | 256 void OpusAudioDecoder::Initialize( |
258 DemuxerStream* stream, | 257 DemuxerStream* stream, |
259 const PipelineStatusCB& status_cb, | 258 const PipelineStatusCB& status_cb, |
260 const StatisticsCB& statistics_cb) { | 259 const StatisticsCB& statistics_cb) { |
261 DCHECK(message_loop_->BelongsToCurrentThread()); | 260 DCHECK(message_loop_->BelongsToCurrentThread()); |
262 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 261 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
263 | 262 |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
450 // Allocate the output buffer if necessary. | 449 // Allocate the output buffer if necessary. |
451 if (!output_buffer_) | 450 if (!output_buffer_) |
452 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); | 451 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); |
453 | 452 |
454 // Parse the Opus header. | 453 // Parse the Opus header. |
455 OpusHeader opus_header; | 454 OpusHeader opus_header; |
456 ParseOpusHeader(config.extra_data(), config.extra_data_size(), | 455 ParseOpusHeader(config.extra_data(), config.extra_data_size(), |
457 config, | 456 config, |
458 &opus_header); | 457 &opus_header); |
459 | 458 |
460 skip_samples_ = opus_header.skip_samples; | 459 if (!config.codec_delay()) { |
461 | 460 skip_samples_ = opus_header.skip_samples; |
acolwell GONE FROM CHROMIUM
2013/08/28 20:44:47
Why do we special case this?
vignesh
2013/08/29 21:37:31
In case of some old opus files, the container valu
| |
462 if (skip_samples_ > 0) | 461 } else { |
463 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); | 462 // WebM container stores codec delay in nanoseconds. Convert it to samples. |
463 skip_samples_ = config.codec_delay() * config.samples_per_second() / | |
acolwell GONE FROM CHROMIUM
2013/08/28 20:44:47
nit: This looks like it could potentially overflow
vignesh
2013/08/29 21:37:31
Done.
| |
464 1000000000; | |
465 if (skip_samples_ != opus_header.skip_samples) { | |
acolwell GONE FROM CHROMIUM
2013/08/28 20:44:47
Shouldn't the codec_delay() header always match th
vignesh
2013/08/29 21:37:31
As of now, both the fields should match. But some
| |
466 DVLOG(1) << "Codec Delay in container does not match the value in Opus " | |
467 << "header. Using the value in container."; | |
acolwell GONE FROM CHROMIUM
2013/08/28 20:44:47
nit: return false here if the expectation that the
vignesh
2013/08/29 21:37:31
Done.
| |
468 } | |
469 } | |
464 | 470 |
465 uint8 channel_mapping[kMaxVorbisChannels]; | 471 uint8 channel_mapping[kMaxVorbisChannels]; |
466 memcpy(&channel_mapping, | 472 memcpy(&channel_mapping, |
467 kDefaultOpusChannelLayout, | 473 kDefaultOpusChannelLayout, |
468 kMaxChannelsWithDefaultLayout); | 474 kMaxChannelsWithDefaultLayout); |
469 | 475 |
470 if (channel_count > kMaxChannelsWithDefaultLayout) { | 476 if (channel_count > kMaxChannelsWithDefaultLayout) { |
471 RemapOpusChannelLayout(opus_header.stream_map, | 477 RemapOpusChannelLayout(opus_header.stream_map, |
472 channel_count, | 478 channel_count, |
473 channel_mapping); | 479 channel_mapping); |
(...skipping 27 matching lines...) Expand all Loading... | |
501 void OpusAudioDecoder::CloseDecoder() { | 507 void OpusAudioDecoder::CloseDecoder() { |
502 if (opus_decoder_) { | 508 if (opus_decoder_) { |
503 opus_multistream_decoder_destroy(opus_decoder_); | 509 opus_multistream_decoder_destroy(opus_decoder_); |
504 opus_decoder_ = NULL; | 510 opus_decoder_ = NULL; |
505 } | 511 } |
506 } | 512 } |
507 | 513 |
508 void OpusAudioDecoder::ResetTimestampState() { | 514 void OpusAudioDecoder::ResetTimestampState() { |
509 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 515 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
510 last_input_timestamp_ = kNoTimestamp(); | 516 last_input_timestamp_ = kNoTimestamp(); |
511 output_bytes_to_drop_ = 0; | 517 skip_samples_ = 0; |
512 } | 518 } |
513 | 519 |
514 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, | 520 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, |
515 scoped_refptr<AudioBuffer>* output_buffer) { | 521 scoped_refptr<AudioBuffer>* output_buffer) { |
516 int samples_decoded = opus_multistream_decode(opus_decoder_, | 522 int samples_decoded = opus_multistream_decode(opus_decoder_, |
Tom Finegan
2013/08/28 01:35:35
I thought you were going to handle S16 and F32 on
vignesh
2013/08/28 17:17:15
I did not change my mind. I will be doing that cha
| |
517 input->data(), | 523 input->data(), |
518 input->data_size(), | 524 input->data_size(), |
519 &output_buffer_[0], | 525 &output_buffer_[0], |
520 kMaxOpusOutputPacketSizeSamples, | 526 kMaxOpusOutputPacketSizeSamples, |
521 0); | 527 0); |
522 if (samples_decoded < 0) { | 528 if (samples_decoded < 0) { |
523 LOG(ERROR) << "opus_multistream_decode failed for" | 529 LOG(ERROR) << "opus_multistream_decode failed for" |
524 << " timestamp: " << input->timestamp().InMicroseconds() | 530 << " timestamp: " << input->timestamp().InMicroseconds() |
525 << " us, duration: " << input->duration().InMicroseconds() | 531 << " us, duration: " << input->duration().InMicroseconds() |
526 << " us, packet size: " << input->data_size() << " bytes with" | 532 << " us, packet size: " << input->data_size() << " bytes with" |
527 << " status: " << opus_strerror(samples_decoded); | 533 << " status: " << opus_strerror(samples_decoded); |
528 return false; | 534 return false; |
529 } | 535 } |
530 | 536 |
531 uint8* decoded_audio_data = reinterpret_cast<uint8*>(&output_buffer_[0]); | 537 uint8* decoded_audio_data = reinterpret_cast<uint8*>(&output_buffer_[0]); |
532 int decoded_audio_size = samples_decoded * | 538 int decoded_audio_size = samples_decoded * |
533 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | 539 demuxer_stream_->audio_decoder_config().bytes_per_frame(); |
534 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); | 540 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); |
535 | 541 |
536 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | 542 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
537 !input->end_of_stream()) { | 543 !input->end_of_stream()) { |
538 DCHECK(input->timestamp() != kNoTimestamp()); | 544 DCHECK(input->timestamp() != kNoTimestamp()); |
539 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); | 545 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); |
540 } | 546 } |
541 | 547 |
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) { | 548 if (decoded_audio_size > 0) { |
553 // Copy the audio samples into an output buffer. | 549 // Copy the audio samples into an output buffer. |
554 uint8* data[] = { decoded_audio_data }; | 550 uint8* data[] = { decoded_audio_data }; |
555 *output_buffer = AudioBuffer::CopyFrom( | 551 *output_buffer = AudioBuffer::CopyFrom( |
556 kSampleFormatS16, | 552 kSampleFormatS16, |
557 ChannelLayoutToChannelCount(channel_layout_), | 553 ChannelLayoutToChannelCount(channel_layout_), |
558 samples_decoded, | 554 samples_decoded, |
559 data, | 555 data, |
560 output_timestamp_helper_->GetTimestamp(), | 556 output_timestamp_helper_->GetTimestamp(), |
561 output_timestamp_helper_->GetFrameDuration(samples_decoded)); | 557 output_timestamp_helper_->GetFrameDuration(samples_decoded)); |
562 output_timestamp_helper_->AddFrames(samples_decoded); | 558 output_timestamp_helper_->AddFrames(samples_decoded); |
559 if (skip_samples_ > 0) { | |
560 int dropped_size = std::min(samples_decoded, skip_samples_); | |
561 output_buffer->get()->TrimStart(dropped_size); | |
562 skip_samples_ -= dropped_size; | |
563 samples_decoded -= dropped_size; | |
564 } | |
565 if (input->discard_padding() > 0) { | |
566 int discard_padding = input->discard_padding() * samples_per_second_ / | |
567 1000000000; | |
acolwell GONE FROM CHROMIUM
2013/08/28 20:44:47
nit: This may need overflow protection as well.
vignesh
2013/08/29 21:37:31
Done.
| |
568 output_buffer->get()->TrimEnd(std::min(samples_decoded, discard_padding)); | |
569 samples_decoded -= discard_padding; | |
570 } | |
563 } | 571 } |
564 | 572 |
573 decoded_audio_size = | |
574 samples_decoded * | |
575 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | |
565 // Decoding finished successfully, update statistics. | 576 // Decoding finished successfully, update statistics. |
566 PipelineStatistics statistics; | 577 PipelineStatistics statistics; |
567 statistics.audio_bytes_decoded = decoded_audio_size; | 578 statistics.audio_bytes_decoded = decoded_audio_size; |
568 statistics_cb_.Run(statistics); | 579 statistics_cb_.Run(statistics); |
569 | 580 |
570 return true; | 581 return true; |
571 } | 582 } |
572 | 583 |
573 } // namespace media | 584 } // namespace media |
OLD | NEW |