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

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

Issue 100503006: Cleanup OPUS decoder. Remove extraneous transforms and copies. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Patch demuxer. Created 7 years 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 | Annotate | Revision Log
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> 7 #include <cmath>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/message_loop/message_loop_proxy.h" 12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/sys_byteorder.h" 13 #include "base/sys_byteorder.h"
14 #include "media/base/audio_buffer.h" 14 #include "media/base/audio_buffer.h"
15 #include "media/base/audio_decoder_config.h" 15 #include "media/base/audio_decoder_config.h"
16 #include "media/base/audio_timestamp_helper.h" 16 #include "media/base/audio_timestamp_helper.h"
17 #include "media/base/bind_to_loop.h" 17 #include "media/base/bind_to_loop.h"
18 #include "media/base/buffers.h" 18 #include "media/base/buffers.h"
19 #include "media/base/decoder_buffer.h" 19 #include "media/base/decoder_buffer.h"
20 #include "media/base/demuxer.h" 20 #include "media/base/demuxer.h"
21 #include "media/base/pipeline.h" 21 #include "media/base/pipeline.h"
22 #include "third_party/opus/src/include/opus.h" 22 #include "third_party/opus/src/include/opus.h"
23 #include "third_party/opus/src/include/opus_multistream.h" 23 #include "third_party/opus/src/include/opus_multistream.h"
24 24
25 namespace media { 25 namespace media {
26 26
27 static uint16 ReadLE16(const uint8* data, size_t data_size, int read_offset) { 27 static uint16 ReadLE16(const uint8* data, size_t data_size, int read_offset) {
28 DCHECK(data);
29 uint16 value = 0; 28 uint16 value = 0;
30 DCHECK_LE(read_offset + sizeof(value), data_size); 29 DCHECK_LE(read_offset + sizeof(value), data_size);
31 memcpy(&value, data + read_offset, sizeof(value)); 30 memcpy(&value, data + read_offset, sizeof(value));
32 return base::ByteSwapToLE16(value); 31 return base::ByteSwapToLE16(value);
33 } 32 }
34 33
35 static int TimeDeltaToAudioFrames(base::TimeDelta time_delta, 34 static int TimeDeltaToAudioFrames(base::TimeDelta time_delta,
36 int frame_rate) { 35 int frame_rate) {
37 return std::ceil(time_delta.InSecondsF() * frame_rate); 36 return std::ceil(time_delta.InSecondsF() * frame_rate);
38 } 37 }
39 38
40 // The Opus specification is part of IETF RFC 6716: 39 // The Opus specification is part of IETF RFC 6716:
41 // http://tools.ietf.org/html/rfc6716 40 // http://tools.ietf.org/html/rfc6716
42 41
43 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies 42 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
44 // mappings for up to 8 channels. This information is part of the Vorbis I 43 // mappings for up to 8 channels. This information is part of the Vorbis I
45 // Specification: 44 // Specification:
46 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html 45 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
47 static const int kMaxVorbisChannels = 8; 46 static const int kMaxVorbisChannels = 8;
48 47
49 // Opus allows for decode of S16 or float samples. OpusAudioDecoder always uses
50 // S16 samples.
51 static const int kBitsPerChannel = 16;
52 static const int kBytesPerChannel = kBitsPerChannel / 8;
53
54 // Maximum packet size used in Xiph's opusdec and FFmpeg's libopusdec. 48 // Maximum packet size used in Xiph's opusdec and FFmpeg's libopusdec.
55 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6 * kMaxVorbisChannels; 49 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
56 static const int kMaxOpusOutputPacketSizeBytes =
57 kMaxOpusOutputPacketSizeSamples * kBytesPerChannel;
58 50
59 static void RemapOpusChannelLayout(const uint8* opus_mapping, 51 static void RemapOpusChannelLayout(const uint8* opus_mapping,
60 int num_channels, 52 int num_channels,
61 uint8* channel_layout) { 53 uint8* channel_layout) {
62 DCHECK_LE(num_channels, kMaxVorbisChannels); 54 DCHECK_LE(num_channels, kMaxVorbisChannels);
63 55
64 // Opus uses Vorbis channel layout. 56 // Opus uses Vorbis channel layout.
65 const int32 num_layouts = kMaxVorbisChannels; 57 const int32 num_layouts = kMaxVorbisChannels;
66 const int32 num_layout_values = kMaxVorbisChannels; 58 const int32 num_layout_values = kMaxVorbisChannels;
67 59
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 int num_coupled; 191 int num_coupled;
200 uint8 stream_map[kMaxVorbisChannels]; 192 uint8 stream_map[kMaxVorbisChannels];
201 }; 193 };
202 194
203 // Returns true when able to successfully parse and store Opus extra data in 195 // Returns true when able to successfully parse and store Opus extra data in
204 // |extra_data|. Based on opus header parsing code in libopusdec from FFmpeg, 196 // |extra_data|. Based on opus header parsing code in libopusdec from FFmpeg,
205 // and opus_header from Xiph's opus-tools project. 197 // and opus_header from Xiph's opus-tools project.
206 static bool ParseOpusExtraData(const uint8* data, int data_size, 198 static bool ParseOpusExtraData(const uint8* data, int data_size,
207 const AudioDecoderConfig& config, 199 const AudioDecoderConfig& config,
208 OpusExtraData* extra_data) { 200 OpusExtraData* extra_data) {
209 if (data_size < kOpusExtraDataSize) 201 if (data_size < kOpusExtraDataSize) {
202 DLOG(ERROR) << "Extra data size is too small:" << data_size;
210 return false; 203 return false;
204 }
211 205
212 extra_data->channels = *(data + kOpusExtraDataChannelsOffset); 206 extra_data->channels = *(data + kOpusExtraDataChannelsOffset);
213 207
214 if (extra_data->channels <= 0 || extra_data->channels > kMaxVorbisChannels) { 208 if (extra_data->channels <= 0 || extra_data->channels > kMaxVorbisChannels) {
215 DVLOG(0) << "invalid channel count in extra data: " << extra_data->channels; 209 DLOG(ERROR) << "invalid channel count in extra data: "
210 << extra_data->channels;
216 return false; 211 return false;
217 } 212 }
218 213
219 extra_data->skip_samples = 214 extra_data->skip_samples =
220 ReadLE16(data, data_size, kOpusExtraDataSkipSamplesOffset); 215 ReadLE16(data, data_size, kOpusExtraDataSkipSamplesOffset);
221 216
222 extra_data->channel_mapping = *(data + kOpusExtraDataChannelMappingOffset); 217 extra_data->channel_mapping = *(data + kOpusExtraDataChannelMappingOffset);
223 218
224 if (!extra_data->channel_mapping) { 219 if (!extra_data->channel_mapping) {
225 if (extra_data->channels > kMaxChannelsWithDefaultLayout) { 220 if (extra_data->channels > kMaxChannelsWithDefaultLayout) {
226 DVLOG(0) << "Invalid extra data, missing stream map."; 221 DLOG(ERROR) << "Invalid extra data, missing stream map.";
227 return false; 222 return false;
228 } 223 }
229 224
230 extra_data->num_streams = 1; 225 extra_data->num_streams = 1;
231 extra_data->num_coupled = 226 extra_data->num_coupled =
232 (ChannelLayoutToChannelCount(config.channel_layout()) > 1) ? 1 : 0; 227 (ChannelLayoutToChannelCount(config.channel_layout()) > 1) ? 1 : 0;
233 return true; 228 return true;
234 } 229 }
235 230
236 if (data_size < kOpusExtraDataStreamMapOffset + extra_data->channels) { 231 if (data_size < kOpusExtraDataStreamMapOffset + extra_data->channels) {
237 DVLOG(0) << "Invalid stream map; insufficient data for current channel " 232 DLOG(ERROR) << "Invalid stream map; insufficient data for current channel "
238 << "count: " << extra_data->channels; 233 << "count: " << extra_data->channels;
239 return false; 234 return false;
240 } 235 }
241 236
242 extra_data->num_streams = *(data + kOpusExtraDataNumStreamsOffset); 237 extra_data->num_streams = *(data + kOpusExtraDataNumStreamsOffset);
243 extra_data->num_coupled = *(data + kOpusExtraDataNumCoupledOffset); 238 extra_data->num_coupled = *(data + kOpusExtraDataNumCoupledOffset);
244 239
245 if (extra_data->num_streams + extra_data->num_coupled != extra_data->channels) 240 if (extra_data->num_streams + extra_data->num_coupled != extra_data->channels)
246 DVLOG(1) << "Inconsistent channel mapping."; 241 DVLOG(1) << "Inconsistent channel mapping.";
247 242
248 for (int i = 0; i < extra_data->channels; ++i) 243 for (int i = 0; i < extra_data->channels; ++i)
249 extra_data->stream_map[i] = *(data + kOpusExtraDataStreamMapOffset + i); 244 extra_data->stream_map[i] = *(data + kOpusExtraDataStreamMapOffset + i);
250 return true; 245 return true;
251 } 246 }
252 247
253 OpusAudioDecoder::OpusAudioDecoder( 248 OpusAudioDecoder::OpusAudioDecoder(
254 const scoped_refptr<base::MessageLoopProxy>& message_loop) 249 const scoped_refptr<base::MessageLoopProxy>& message_loop)
255 : message_loop_(message_loop), 250 : message_loop_(message_loop),
256 weak_factory_(this), 251 weak_factory_(this),
257 demuxer_stream_(NULL), 252 demuxer_stream_(NULL),
258 opus_decoder_(NULL), 253 opus_decoder_(NULL),
259 bits_per_channel_(0),
260 channel_layout_(CHANNEL_LAYOUT_NONE), 254 channel_layout_(CHANNEL_LAYOUT_NONE),
261 samples_per_second_(0), 255 samples_per_second_(0),
256 // Android uses a fixed point build of the opus decoder.
257 #if defined(OS_ANDROID)
258 sample_format_(kSampleFormatS16),
259 #else
260 sample_format_(kSampleFormatF32),
261 #endif
262 bits_per_channel_(SampleFormatToBytesPerChannel(sample_format_) * 8),
262 last_input_timestamp_(kNoTimestamp()), 263 last_input_timestamp_(kNoTimestamp()),
263 frames_to_discard_(0), 264 frames_to_discard_(0),
264 frame_delay_at_start_(0) { 265 frame_delay_at_start_(0),
266 first_output_frame_(kNoTimestamp()),
267 partial_frame_delay_at_start_(0) {
265 } 268 }
266 269
267 void OpusAudioDecoder::Initialize( 270 void OpusAudioDecoder::Initialize(
268 DemuxerStream* stream, 271 DemuxerStream* stream,
269 const PipelineStatusCB& status_cb, 272 const PipelineStatusCB& status_cb,
270 const StatisticsCB& statistics_cb) { 273 const StatisticsCB& statistics_cb) {
271 DCHECK(message_loop_->BelongsToCurrentThread()); 274 DCHECK(message_loop_->BelongsToCurrentThread());
272 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); 275 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
273 276
274 if (demuxer_stream_) { 277 if (demuxer_stream_) {
275 // TODO(scherkus): initialization currently happens more than once in 278 // TODO(scherkus): initialization currently happens more than once in
276 // PipelineIntegrationTest.BasicPlayback. 279 // PipelineIntegrationTest.BasicPlayback.
277 DVLOG(0) << "Initialize has already been called."; 280 DLOG(ERROR) << "Initialize has already been called.";
278 CHECK(false); 281 CHECK(false);
279 } 282 }
280 283
281 weak_this_ = weak_factory_.GetWeakPtr(); 284 weak_this_ = weak_factory_.GetWeakPtr();
282 demuxer_stream_ = stream; 285 demuxer_stream_ = stream;
283 286
284 if (!ConfigureDecoder()) { 287 if (!ConfigureDecoder()) {
285 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 288 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
286 return; 289 return;
287 } 290 }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 // input buffer is received. 371 // input buffer is received.
369 if (input->end_of_stream()) { 372 if (input->end_of_stream()) {
370 base::ResetAndReturn(&read_cb_).Run(kOk, AudioBuffer::CreateEOSBuffer()); 373 base::ResetAndReturn(&read_cb_).Run(kOk, AudioBuffer::CreateEOSBuffer());
371 return; 374 return;
372 } 375 }
373 376
374 // Make sure we are notified if http://crbug.com/49709 returns. Issue also 377 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
375 // occurs with some damaged files. 378 // occurs with some damaged files.
376 if (input->timestamp() == kNoTimestamp() && 379 if (input->timestamp() == kNoTimestamp() &&
377 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { 380 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) {
378 DVLOG(1) << "Received a buffer without timestamps!"; 381 DLOG(ERROR) << "Received a buffer without timestamps!";
379 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 382 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
380 return; 383 return;
381 } 384 }
382 385
383 if (last_input_timestamp_ != kNoTimestamp() && 386 if (last_input_timestamp_ != kNoTimestamp() &&
384 input->timestamp() != kNoTimestamp() && 387 input->timestamp() != kNoTimestamp() &&
385 input->timestamp() < last_input_timestamp_) { 388 input->timestamp() < last_input_timestamp_) {
386 base::TimeDelta diff = input->timestamp() - last_input_timestamp_; 389 base::TimeDelta diff = input->timestamp() - last_input_timestamp_;
387 DVLOG(1) << "Input timestamps are not monotonically increasing! " 390 DLOG(ERROR) << "Input timestamps are not monotonically increasing! "
388 << " ts " << input->timestamp().InMicroseconds() << " us" 391 << " ts " << input->timestamp().InMicroseconds() << " us"
389 << " diff " << diff.InMicroseconds() << " us"; 392 << " diff " << diff.InMicroseconds() << " us";
390 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 393 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
391 return; 394 return;
392 } 395 }
393 396
397 // Skip samples should be equal to codec delay when the file starts and when
398 // there is a seek to zero. Note: We're implicitly relying on FFmpeg to treat
399 // seek to zero as a seek to the actual first frame (which may be negative).
400 if (last_input_timestamp_ == kNoTimestamp() &&
acolwell GONE FROM CHROMIUM 2013/12/12 22:40:46 This doesn't seem quite right. Shouldn't this be s
DaleCurtis 2013/12/12 23:36:04 Done. Required fixing AudioRendererImpl preroll!
401 input->timestamp() <= base::TimeDelta()) {
402 if (first_output_frame_ == kNoTimestamp())
403 frames_to_discard_ = frame_delay_at_start_;
404 }
405
394 last_input_timestamp_ = input->timestamp(); 406 last_input_timestamp_ = input->timestamp();
395 407
396 scoped_refptr<AudioBuffer> output_buffer; 408 scoped_refptr<AudioBuffer> output_buffer;
397 409
398 if (!Decode(input, &output_buffer)) { 410 if (!Decode(input, &output_buffer)) {
399 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 411 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
400 return; 412 return;
401 } 413 }
402 414
403 if (output_buffer.get()) { 415 if (output_buffer.get()) {
404 // Execute callback to return the decoded audio. 416 // Execute callback to return the decoded audio.
405 base::ResetAndReturn(&read_cb_).Run(kOk, output_buffer); 417 base::ResetAndReturn(&read_cb_).Run(kOk, output_buffer);
406 } else { 418 } else {
407 // We exhausted the input data, but it wasn't enough for a frame. Ask for 419 // We exhausted the input data, but it wasn't enough for a frame. Ask for
408 // more data in order to fulfill this read. 420 // more data in order to fulfill this read.
409 ReadFromDemuxerStream(); 421 ReadFromDemuxerStream();
410 } 422 }
411 } 423 }
412 424
413 bool OpusAudioDecoder::ConfigureDecoder() { 425 bool OpusAudioDecoder::ConfigureDecoder() {
414 const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config(); 426 const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config();
415 427
416 if (config.codec() != kCodecOpus) { 428 if (config.codec() != kCodecOpus) {
417 DVLOG(0) << "codec must be kCodecOpus."; 429 DVLOG(1) << "Codec must be kCodecOpus.";
418 return false; 430 return false;
419 } 431 }
420 432
421 const int channel_count = 433 const int channel_count =
422 ChannelLayoutToChannelCount(config.channel_layout()); 434 ChannelLayoutToChannelCount(config.channel_layout());
423 if (!config.IsValidConfig() || channel_count > kMaxVorbisChannels) { 435 if (!config.IsValidConfig() || channel_count > kMaxVorbisChannels) {
424 DVLOG(0) << "Invalid or unsupported audio stream -" 436 DLOG(ERROR) << "Invalid or unsupported audio stream -"
425 << " codec: " << config.codec() 437 << " codec: " << config.codec()
426 << " channel count: " << channel_count 438 << " channel count: " << channel_count
427 << " channel layout: " << config.channel_layout() 439 << " channel layout: " << config.channel_layout()
428 << " bits per channel: " << config.bits_per_channel() 440 << " bits per channel: " << config.bits_per_channel()
429 << " samples per second: " << config.samples_per_second(); 441 << " samples per second: " << config.samples_per_second();
430 return false;
431 }
432
433 if (config.bits_per_channel() != kBitsPerChannel) {
434 DVLOG(0) << "16 bit samples required.";
435 return false; 442 return false;
436 } 443 }
437 444
438 if (config.is_encrypted()) { 445 if (config.is_encrypted()) {
439 DVLOG(0) << "Encrypted audio stream not supported."; 446 DLOG(ERROR) << "Encrypted audio stream not supported.";
440 return false; 447 return false;
441 } 448 }
442 449
443 if (opus_decoder_ && 450 if (opus_decoder_ &&
444 (bits_per_channel_ != config.bits_per_channel() || 451 (channel_layout_ != config.channel_layout() ||
445 channel_layout_ != config.channel_layout() ||
446 samples_per_second_ != config.samples_per_second())) { 452 samples_per_second_ != config.samples_per_second())) {
447 DVLOG(1) << "Unsupported config change :"; 453 DLOG(ERROR) << "Unsupported config change -"
448 DVLOG(1) << "\tbits_per_channel : " << bits_per_channel_ 454 << ", channel_layout: " << channel_layout_
449 << " -> " << config.bits_per_channel(); 455 << " -> " << config.channel_layout()
450 DVLOG(1) << "\tchannel_layout : " << channel_layout_ 456 << ", sample_rate: " << samples_per_second_
451 << " -> " << config.channel_layout(); 457 << " -> " << config.samples_per_second();
452 DVLOG(1) << "\tsample_rate : " << samples_per_second_
453 << " -> " << config.samples_per_second();
454 return false; 458 return false;
455 } 459 }
456 460
457 // Clean up existing decoder if necessary. 461 // Clean up existing decoder if necessary.
458 CloseDecoder(); 462 CloseDecoder();
459 463
460 // Allocate the output buffer if necessary.
461 if (!output_buffer_)
462 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]);
463
464 // Parse the Opus Extra Data. 464 // Parse the Opus Extra Data.
465 OpusExtraData opus_extra_data; 465 OpusExtraData opus_extra_data;
466 if (!ParseOpusExtraData(config.extra_data(), config.extra_data_size(), 466 if (!ParseOpusExtraData(config.extra_data(), config.extra_data_size(),
467 config, 467 config,
468 &opus_extra_data)) 468 &opus_extra_data))
469 return false; 469 return false;
470 470
471 if (!config.codec_delay().InMicroseconds())
472 return false;
473
474 // Convert from seconds to samples. 471 // Convert from seconds to samples.
475 timestamp_offset_ = config.codec_delay(); 472 timestamp_offset_ = config.codec_delay();
476 frame_delay_at_start_ = TimeDeltaToAudioFrames(config.codec_delay(), 473 frame_delay_at_start_ = TimeDeltaToAudioFrames(config.codec_delay(),
477 config.samples_per_second()); 474 config.samples_per_second());
478 if (frame_delay_at_start_ < 0) { 475 if (timestamp_offset_ <= base::TimeDelta() || frame_delay_at_start_ < 0) {
479 DVLOG(1) << "Invalid file. Incorrect value for codec delay."; 476 DLOG(ERROR) << "Invalid file. Incorrect value for codec delay: "
480 return false; 477 << config.codec_delay().InMicroseconds();
481 }
482 if (frame_delay_at_start_ != opus_extra_data.skip_samples) {
483 DVLOG(1) << "Invalid file. Codec Delay in container does not match the "
484 << "value in Opus Extra Data.";
485 return false; 478 return false;
486 } 479 }
487 480
488 uint8 channel_mapping[kMaxVorbisChannels]; 481 if (frame_delay_at_start_ != opus_extra_data.skip_samples) {
482 DLOG(ERROR) << "Invalid file. Codec Delay in container does not match the "
483 << "value in Opus Extra Data.";
484 return false;
485 }
486
487 uint8 channel_mapping[kMaxVorbisChannels] = {0};
489 memcpy(&channel_mapping, 488 memcpy(&channel_mapping,
490 kDefaultOpusChannelLayout, 489 kDefaultOpusChannelLayout,
491 kMaxChannelsWithDefaultLayout); 490 kMaxChannelsWithDefaultLayout);
492 491
493 if (channel_count > kMaxChannelsWithDefaultLayout) { 492 if (channel_count > kMaxChannelsWithDefaultLayout) {
494 RemapOpusChannelLayout(opus_extra_data.stream_map, 493 RemapOpusChannelLayout(opus_extra_data.stream_map,
495 channel_count, 494 channel_count,
496 channel_mapping); 495 channel_mapping);
497 } 496 }
498 497
499 // Init Opus. 498 // Init Opus.
500 int status = OPUS_INVALID_STATE; 499 int status = OPUS_INVALID_STATE;
501 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), 500 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(),
502 channel_count, 501 channel_count,
503 opus_extra_data.num_streams, 502 opus_extra_data.num_streams,
504 opus_extra_data.num_coupled, 503 opus_extra_data.num_coupled,
505 channel_mapping, 504 channel_mapping,
506 &status); 505 &status);
507 if (!opus_decoder_ || status != OPUS_OK) { 506 if (!opus_decoder_ || status != OPUS_OK) {
508 DVLOG(0) << "opus_multistream_decoder_create failed status=" 507 DLOG(ERROR) << "opus_multistream_decoder_create failed status="
509 << opus_strerror(status); 508 << opus_strerror(status);
510 return false; 509 return false;
511 } 510 }
512 511
513 bits_per_channel_ = config.bits_per_channel();
514 channel_layout_ = config.channel_layout(); 512 channel_layout_ = config.channel_layout();
515 samples_per_second_ = config.samples_per_second(); 513 samples_per_second_ = config.samples_per_second();
516 output_timestamp_helper_.reset( 514 output_timestamp_helper_.reset(
517 new AudioTimestampHelper(config.samples_per_second())); 515 new AudioTimestampHelper(config.samples_per_second()));
516 first_output_frame_ = kNoTimestamp();
517 partial_frame_delay_at_start_ = 0;
518 return true; 518 return true;
519 } 519 }
520 520
521 void OpusAudioDecoder::CloseDecoder() { 521 void OpusAudioDecoder::CloseDecoder() {
522 if (opus_decoder_) { 522 if (opus_decoder_) {
523 opus_multistream_decoder_destroy(opus_decoder_); 523 opus_multistream_decoder_destroy(opus_decoder_);
524 opus_decoder_ = NULL; 524 opus_decoder_ = NULL;
525 } 525 }
526 } 526 }
527 527
528 void OpusAudioDecoder::ResetTimestampState() { 528 void OpusAudioDecoder::ResetTimestampState() {
529 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); 529 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp());
530 last_input_timestamp_ = kNoTimestamp(); 530 last_input_timestamp_ = kNoTimestamp();
531 frames_to_discard_ = TimeDeltaToAudioFrames( 531 frames_to_discard_ = TimeDeltaToAudioFrames(
532 demuxer_stream_->audio_decoder_config().seek_preroll(), 532 demuxer_stream_->audio_decoder_config().seek_preroll(),
533 samples_per_second_); 533 samples_per_second_);
534 } 534 }
535 535
536 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, 536 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input,
537 scoped_refptr<AudioBuffer>* output_buffer) { 537 scoped_refptr<AudioBuffer>* output_buffer) {
538 int frames_decoded = opus_multistream_decode(opus_decoder_, 538 // Allocate a buffer for the output samples.
539 input->data(), 539 *output_buffer = AudioBuffer::CreateBuffer(
540 input->data_size(), 540 sample_format_,
541 &output_buffer_[0], 541 ChannelLayoutToChannelCount(channel_layout_),
542 kMaxOpusOutputPacketSizeSamples, 542 kMaxOpusOutputPacketSizeSamples);
543 0); 543 const int buffer_size =
544 output_buffer->get()->channel_count() *
545 output_buffer->get()->frame_count() *
546 SampleFormatToBytesPerChannel(sample_format_);
547
548 // Android uses a fixed point build of the opus decoder.
549 #if defined(OS_ANDROID)
550 int16* int16_output_buffer = reinterpret_cast<int16*>(
551 output_buffer->get()->channel_data()[0]);
552 const int frames_decoded =
553 opus_multistream_decode(opus_decoder_,
554 input->data(),
555 input->data_size(),
556 int16_output_buffer,
557 buffer_size,
558 0);
559 #else
560 float* float_output_buffer = reinterpret_cast<float*>(
561 output_buffer->get()->channel_data()[0]);
562 const int frames_decoded =
563 opus_multistream_decode_float(opus_decoder_,
564 input->data(),
565 input->data_size(),
566 float_output_buffer,
567 buffer_size,
568 0);
569 #endif
570
544 if (frames_decoded < 0) { 571 if (frames_decoded < 0) {
545 DVLOG(0) << "opus_multistream_decode failed for" 572 DLOG(ERROR) << "opus_multistream_decode failed for"
546 << " timestamp: " << input->timestamp().InMicroseconds() 573 << " timestamp: " << input->timestamp().InMicroseconds()
547 << " us, duration: " << input->duration().InMicroseconds() 574 << " us, duration: " << input->duration().InMicroseconds()
548 << " us, packet size: " << input->data_size() << " bytes with" 575 << " us, packet size: " << input->data_size() << " bytes with"
549 << " status: " << opus_strerror(frames_decoded); 576 << " status: " << opus_strerror(frames_decoded);
550 return false; 577 return false;
551 } 578 }
552 579
553 uint8* decoded_audio_data = reinterpret_cast<uint8*>(&output_buffer_[0]);
554 int bytes_decoded = frames_decoded *
555 demuxer_stream_->audio_decoder_config().bytes_per_frame();
556 DCHECK_LE(bytes_decoded, kMaxOpusOutputPacketSizeBytes);
557
558 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && 580 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() &&
559 !input->end_of_stream()) { 581 !input->end_of_stream()) {
560 DCHECK(input->timestamp() != kNoTimestamp()); 582 DCHECK(input->timestamp() != kNoTimestamp());
561 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); 583 output_timestamp_helper_->SetBaseTimestamp(input->timestamp());
562 } 584 }
563 585
564 // Skip samples should be equal to codec delay when the file starts and when 586 // Trim off any extraneous allocation.
565 // there is a seek to zero. 587 DCHECK_LE(frames_decoded, output_buffer->get()->frame_count());
566 // TODO(vigneshv): This should be checked for start of stream rather than 588 const int trim_frames = output_buffer->get()->frame_count() - frames_decoded;
567 // input timestamp of zero to accomodate streams that don't start at zero. 589 if (trim_frames > 0)
568 if (input->timestamp() == base::TimeDelta()) 590 output_buffer->get()->TrimEnd(trim_frames);
569 frames_to_discard_ = frame_delay_at_start_;
570 591
571 if (bytes_decoded > 0 && frames_decoded > frames_to_discard_) { 592 // Handle frame discard and trimming.
572 // Copy the audio samples into an output buffer. 593 int frames_to_output = frames_decoded;
573 uint8* data[] = { decoded_audio_data }; 594 if (first_output_frame_ != kNoTimestamp()) {
574 *output_buffer = AudioBuffer::CopyFrom( 595 if (input->timestamp() < first_output_frame_)
575 kSampleFormatS16, 596 frames_to_discard_ = frames_decoded;
576 ChannelLayoutToChannelCount(channel_layout_), 597 else if (input->timestamp() == first_output_frame_)
577 frames_decoded, 598 frames_to_discard_ = partial_frame_delay_at_start_;
578 data, 599 }
579 output_timestamp_helper_->GetTimestamp() - timestamp_offset_, 600 if (frames_decoded > frames_to_discard_) {
580 output_timestamp_helper_->GetFrameDuration(frames_decoded));
581 output_timestamp_helper_->AddFrames(frames_decoded);
582 if (frames_to_discard_ > 0) { 601 if (frames_to_discard_ > 0) {
583 output_buffer->get()->TrimStart(frames_to_discard_); 602 output_buffer->get()->TrimStart(frames_to_discard_);
584 frames_decoded -= frames_to_discard_; 603 frames_to_output -= frames_to_discard_;
585 frames_to_discard_ = 0; 604 frames_to_discard_ = 0;
586 } 605 }
587 if (input->discard_padding().InMicroseconds() > 0) { 606 if (input->discard_padding().InMicroseconds() > 0) {
588 int discard_padding = TimeDeltaToAudioFrames(input->discard_padding(), 607 int discard_padding = TimeDeltaToAudioFrames(input->discard_padding(),
589 samples_per_second_); 608 samples_per_second_);
590 if (discard_padding < 0 || discard_padding > frames_decoded) { 609 if (discard_padding < 0 || discard_padding > frames_to_output) {
591 DVLOG(1) << "Invalid file. Incorrect discard padding value."; 610 DVLOG(1) << "Invalid file. Incorrect discard padding value.";
592 return false; 611 return false;
593 } 612 }
594 output_buffer->get()->TrimEnd(discard_padding); 613 output_buffer->get()->TrimEnd(discard_padding);
595 frames_decoded -= discard_padding; 614 frames_to_output -= discard_padding;
596 } 615 }
597 } else if (bytes_decoded > 0) { 616 } else {
598 frames_to_discard_ -= frames_decoded; 617 frames_to_discard_ -= frames_to_output;
599 frames_decoded = 0; 618 frames_to_output = 0;
600 } 619 }
601 620
602 // Decoding finished successfully, update statistics. 621 // Decoding finished successfully, update statistics.
603 PipelineStatistics statistics; 622 PipelineStatistics statistics;
604 statistics.audio_bytes_decoded = input->data_size(); 623 statistics.audio_bytes_decoded = input->data_size();
605 statistics_cb_.Run(statistics); 624 statistics_cb_.Run(statistics);
606 625
626 // Assign timestamp and duration to the buffer.
627 output_buffer->get()->set_timestamp(
628 output_timestamp_helper_->GetTimestamp() - timestamp_offset_);
629 output_buffer->get()->set_duration(
630 output_timestamp_helper_->GetFrameDuration(frames_to_output));
631 output_timestamp_helper_->AddFrames(frames_decoded);
632
607 // Discard the buffer to indicate we need more data. 633 // Discard the buffer to indicate we need more data.
608 if (!frames_decoded) 634 if (!frames_to_output) {
609 *output_buffer = NULL; 635 *output_buffer = NULL;
636 } else if (first_output_frame_ == kNoTimestamp()) {
637 first_output_frame_ = input->timestamp();
638 partial_frame_delay_at_start_ = frames_decoded - frames_to_output;
639 }
610 640
611 return true; 641 return true;
612 } 642 }
613 643
614 } // namespace media 644 } // namespace media
OLDNEW
« media/filters/ffmpeg_demuxer.cc ('K') | « media/filters/opus_audio_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698