| 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()) { |
| 461 | 462 // TODO(vigneshv): Replace this with return false once ffmpeg demuxer code |
| 462 if (skip_samples_ > 0) | 463 // starts populating the config correctly. |
| 463 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); | 464 skip_samples_ = opus_header.skip_samples; |
| 465 } else { |
| 466 // Convert from seconds to samples. |
| 467 skip_samples_ = std::ceil(config.codec_delay().InMicroseconds() * |
| 468 config.samples_per_second() / 1000000.0); |
| 469 if (skip_samples_ < 0) { |
| 470 DVLOG(1) << "Invalid file. Incorrect value for codec delay."; |
| 471 return false; |
| 472 } |
| 473 if (skip_samples_ != opus_header.skip_samples) { |
| 474 DVLOG(1) << "Invalid file. Codec Delay in container does not match the " |
| 475 << "value in Opus header."; |
| 476 return false; |
| 477 } |
| 478 } |
| 464 | 479 |
| 465 uint8 channel_mapping[kMaxVorbisChannels]; | 480 uint8 channel_mapping[kMaxVorbisChannels]; |
| 466 memcpy(&channel_mapping, | 481 memcpy(&channel_mapping, |
| 467 kDefaultOpusChannelLayout, | 482 kDefaultOpusChannelLayout, |
| 468 kMaxChannelsWithDefaultLayout); | 483 kMaxChannelsWithDefaultLayout); |
| 469 | 484 |
| 470 if (channel_count > kMaxChannelsWithDefaultLayout) { | 485 if (channel_count > kMaxChannelsWithDefaultLayout) { |
| 471 RemapOpusChannelLayout(opus_header.stream_map, | 486 RemapOpusChannelLayout(opus_header.stream_map, |
| 472 channel_count, | 487 channel_count, |
| 473 channel_mapping); | 488 channel_mapping); |
| 474 } | 489 } |
| 475 | 490 |
| 476 // Init Opus. | 491 // Init Opus. |
| 477 int status = OPUS_INVALID_STATE; | 492 int status = OPUS_INVALID_STATE; |
| 478 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), | 493 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), |
| 479 channel_count, | 494 channel_count, |
| 480 opus_header.num_streams, | 495 opus_header.num_streams, |
| 481 opus_header.num_coupled, | 496 opus_header.num_coupled, |
| 482 channel_mapping, | 497 channel_mapping, |
| 483 &status); | 498 &status); |
| 484 if (!opus_decoder_ || status != OPUS_OK) { | 499 if (!opus_decoder_ || status != OPUS_OK) { |
| 485 LOG(ERROR) << "opus_multistream_decoder_create failed status=" | 500 LOG(ERROR) << "opus_multistream_decoder_create failed status=" |
| 486 << opus_strerror(status); | 501 << opus_strerror(status); |
| 487 return false; | 502 return false; |
| 488 } | 503 } |
| 489 | 504 |
| 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(); | 505 bits_per_channel_ = config.bits_per_channel(); |
| 494 channel_layout_ = config.channel_layout(); | 506 channel_layout_ = config.channel_layout(); |
| 495 samples_per_second_ = config.samples_per_second(); | 507 samples_per_second_ = config.samples_per_second(); |
| 496 output_timestamp_helper_.reset( | 508 output_timestamp_helper_.reset( |
| 497 new AudioTimestampHelper(config.samples_per_second())); | 509 new AudioTimestampHelper(config.samples_per_second())); |
| 498 return true; | 510 return true; |
| 499 } | 511 } |
| 500 | 512 |
| 501 void OpusAudioDecoder::CloseDecoder() { | 513 void OpusAudioDecoder::CloseDecoder() { |
| 502 if (opus_decoder_) { | 514 if (opus_decoder_) { |
| 503 opus_multistream_decoder_destroy(opus_decoder_); | 515 opus_multistream_decoder_destroy(opus_decoder_); |
| 504 opus_decoder_ = NULL; | 516 opus_decoder_ = NULL; |
| 505 } | 517 } |
| 506 } | 518 } |
| 507 | 519 |
| 508 void OpusAudioDecoder::ResetTimestampState() { | 520 void OpusAudioDecoder::ResetTimestampState() { |
| 509 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 521 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
| 510 last_input_timestamp_ = kNoTimestamp(); | 522 last_input_timestamp_ = kNoTimestamp(); |
| 511 output_bytes_to_drop_ = 0; | 523 skip_samples_ = 0; |
| 512 } | 524 } |
| 513 | 525 |
| 514 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, | 526 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, |
| 515 scoped_refptr<AudioBuffer>* output_buffer) { | 527 scoped_refptr<AudioBuffer>* output_buffer) { |
| 516 int samples_decoded = opus_multistream_decode(opus_decoder_, | 528 int samples_decoded = opus_multistream_decode(opus_decoder_, |
| 517 input->data(), | 529 input->data(), |
| 518 input->data_size(), | 530 input->data_size(), |
| 519 &output_buffer_[0], | 531 &output_buffer_[0], |
| 520 kMaxOpusOutputPacketSizeSamples, | 532 kMaxOpusOutputPacketSizeSamples, |
| 521 0); | 533 0); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 532 int decoded_audio_size = samples_decoded * | 544 int decoded_audio_size = samples_decoded * |
| 533 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | 545 demuxer_stream_->audio_decoder_config().bytes_per_frame(); |
| 534 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); | 546 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); |
| 535 | 547 |
| 536 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | 548 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
| 537 !input->end_of_stream()) { | 549 !input->end_of_stream()) { |
| 538 DCHECK(input->timestamp() != kNoTimestamp()); | 550 DCHECK(input->timestamp() != kNoTimestamp()); |
| 539 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); | 551 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); |
| 540 } | 552 } |
| 541 | 553 |
| 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) { | 554 if (decoded_audio_size > 0) { |
| 553 // Copy the audio samples into an output buffer. | 555 // Copy the audio samples into an output buffer. |
| 554 uint8* data[] = { decoded_audio_data }; | 556 uint8* data[] = { decoded_audio_data }; |
| 555 *output_buffer = AudioBuffer::CopyFrom( | 557 *output_buffer = AudioBuffer::CopyFrom( |
| 556 kSampleFormatS16, | 558 kSampleFormatS16, |
| 557 ChannelLayoutToChannelCount(channel_layout_), | 559 ChannelLayoutToChannelCount(channel_layout_), |
| 558 samples_decoded, | 560 samples_decoded, |
| 559 data, | 561 data, |
| 560 output_timestamp_helper_->GetTimestamp(), | 562 output_timestamp_helper_->GetTimestamp(), |
| 561 output_timestamp_helper_->GetFrameDuration(samples_decoded)); | 563 output_timestamp_helper_->GetFrameDuration(samples_decoded)); |
| 562 output_timestamp_helper_->AddFrames(samples_decoded); | 564 output_timestamp_helper_->AddFrames(samples_decoded); |
| 565 if (skip_samples_ > 0) { |
| 566 int dropped_size = std::min(samples_decoded, skip_samples_); |
| 567 output_buffer->get()->TrimStart(dropped_size); |
| 568 skip_samples_ -= dropped_size; |
| 569 samples_decoded -= dropped_size; |
| 570 } |
| 571 if (input->discard_padding().InMicroseconds() > 0) { |
| 572 int discard_padding = std::ceil( |
| 573 input->discard_padding().InMicroseconds() * |
| 574 samples_per_second_ / 1000000.0); |
| 575 if (discard_padding < 0 || discard_padding > samples_decoded) { |
| 576 DVLOG(1) << "Invalid file. Incorrect discard padding value."; |
| 577 return false; |
| 578 } |
| 579 output_buffer->get()->TrimEnd(std::min(samples_decoded, discard_padding)); |
| 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 |