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

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: fixing errors causing try bot failure 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
« no previous file with comments | « media/filters/opus_audio_decoder.h ('k') | media/filters/pipeline_integration_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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()) {
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
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
OLDNEW
« no previous file with comments | « media/filters/opus_audio_decoder.h ('k') | media/filters/pipeline_integration_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698