Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: media/filters/opus_audio_decoder.cc

Issue 23014009: media: Opus support for WebM in Media Source (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: adding pipeline integration test Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698