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

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: addressing comments. using base::TimeDelta for relevant fields. 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 <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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698