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

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: Comments. Fix pre-skip. 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
« no previous file with comments | « media/filters/opus_audio_decoder.h ('k') | no next file » | 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> 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) {
265 } 266 }
266 267
267 void OpusAudioDecoder::Initialize( 268 void OpusAudioDecoder::Initialize(
268 DemuxerStream* stream, 269 DemuxerStream* stream,
269 const PipelineStatusCB& status_cb, 270 const PipelineStatusCB& status_cb,
270 const StatisticsCB& statistics_cb) { 271 const StatisticsCB& statistics_cb) {
271 DCHECK(message_loop_->BelongsToCurrentThread()); 272 DCHECK(message_loop_->BelongsToCurrentThread());
272 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); 273 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
273 274
274 if (demuxer_stream_) { 275 if (demuxer_stream_) {
275 // TODO(scherkus): initialization currently happens more than once in 276 // TODO(scherkus): initialization currently happens more than once in
276 // PipelineIntegrationTest.BasicPlayback. 277 // PipelineIntegrationTest.BasicPlayback.
277 DVLOG(0) << "Initialize has already been called."; 278 DLOG(ERROR) << "Initialize has already been called.";
278 CHECK(false); 279 CHECK(false);
279 } 280 }
280 281
281 weak_this_ = weak_factory_.GetWeakPtr(); 282 weak_this_ = weak_factory_.GetWeakPtr();
282 demuxer_stream_ = stream; 283 demuxer_stream_ = stream;
283 284
284 if (!ConfigureDecoder()) { 285 if (!ConfigureDecoder()) {
285 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 286 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
286 return; 287 return;
287 } 288 }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 // input buffer is received. 369 // input buffer is received.
369 if (input->end_of_stream()) { 370 if (input->end_of_stream()) {
370 base::ResetAndReturn(&read_cb_).Run(kOk, AudioBuffer::CreateEOSBuffer()); 371 base::ResetAndReturn(&read_cb_).Run(kOk, AudioBuffer::CreateEOSBuffer());
371 return; 372 return;
372 } 373 }
373 374
374 // Make sure we are notified if http://crbug.com/49709 returns. Issue also 375 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
375 // occurs with some damaged files. 376 // occurs with some damaged files.
376 if (input->timestamp() == kNoTimestamp() && 377 if (input->timestamp() == kNoTimestamp() &&
377 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { 378 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) {
378 DVLOG(1) << "Received a buffer without timestamps!"; 379 DLOG(ERROR) << "Received a buffer without timestamps!";
379 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 380 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
380 return; 381 return;
381 } 382 }
382 383
383 if (last_input_timestamp_ != kNoTimestamp() && 384 if (last_input_timestamp_ != kNoTimestamp() &&
384 input->timestamp() != kNoTimestamp() && 385 input->timestamp() != kNoTimestamp() &&
385 input->timestamp() < last_input_timestamp_) { 386 input->timestamp() < last_input_timestamp_) {
386 base::TimeDelta diff = input->timestamp() - last_input_timestamp_; 387 base::TimeDelta diff = input->timestamp() - last_input_timestamp_;
387 DVLOG(1) << "Input timestamps are not monotonically increasing! " 388 DLOG(ERROR) << "Input timestamps are not monotonically increasing! "
388 << " ts " << input->timestamp().InMicroseconds() << " us" 389 << " ts " << input->timestamp().InMicroseconds() << " us"
389 << " diff " << diff.InMicroseconds() << " us"; 390 << " diff " << diff.InMicroseconds() << " us";
390 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 391 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
391 return; 392 return;
392 } 393 }
393 394
395 // Skip samples should be equal to codec delay when the file starts and when
396 // there is a seek to zero. Note: We're implicitly relying on FFmpeg to treat
397 // seek to zero as a seek to the actual first frame (which may be negative).
398 if (last_input_timestamp_ == kNoTimestamp() &&
DaleCurtis 2013/12/12 00:03:25 Hackish detection I'm talking about... suggestions
acolwell GONE FROM CHROMIUM 2013/12/12 00:53:14 :( This is needed because the decoder doesn't get
DaleCurtis 2013/12/12 03:07:08 Correct, and this actually isn't enough to fix the
DaleCurtis 2013/12/12 04:12:13 (Or if it's an uncommon case we can probably avoid
399 input->timestamp() <= base::TimeDelta()) {
400 frames_to_discard_ = frame_delay_at_start_;
401 }
402
394 last_input_timestamp_ = input->timestamp(); 403 last_input_timestamp_ = input->timestamp();
395 404
396 scoped_refptr<AudioBuffer> output_buffer; 405 scoped_refptr<AudioBuffer> output_buffer;
397 406
398 if (!Decode(input, &output_buffer)) { 407 if (!Decode(input, &output_buffer)) {
399 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 408 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
400 return; 409 return;
401 } 410 }
402 411
403 if (output_buffer.get()) { 412 if (output_buffer.get()) {
404 // Execute callback to return the decoded audio. 413 // Execute callback to return the decoded audio.
405 base::ResetAndReturn(&read_cb_).Run(kOk, output_buffer); 414 base::ResetAndReturn(&read_cb_).Run(kOk, output_buffer);
406 } else { 415 } else {
407 // We exhausted the input data, but it wasn't enough for a frame. Ask for 416 // We exhausted the input data, but it wasn't enough for a frame. Ask for
408 // more data in order to fulfill this read. 417 // more data in order to fulfill this read.
409 ReadFromDemuxerStream(); 418 ReadFromDemuxerStream();
410 } 419 }
411 } 420 }
412 421
413 bool OpusAudioDecoder::ConfigureDecoder() { 422 bool OpusAudioDecoder::ConfigureDecoder() {
414 const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config(); 423 const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config();
415 424
416 if (config.codec() != kCodecOpus) { 425 if (config.codec() != kCodecOpus) {
417 DVLOG(0) << "codec must be kCodecOpus."; 426 DVLOG(1) << "codec must be kCodecOpus.";
418 return false; 427 return false;
419 } 428 }
420 429
421 const int channel_count = 430 const int channel_count =
422 ChannelLayoutToChannelCount(config.channel_layout()); 431 ChannelLayoutToChannelCount(config.channel_layout());
423 if (!config.IsValidConfig() || channel_count > kMaxVorbisChannels) { 432 if (!config.IsValidConfig() || channel_count > kMaxVorbisChannels) {
424 DVLOG(0) << "Invalid or unsupported audio stream -" 433 DLOG(ERROR) << "Invalid or unsupported audio stream -"
425 << " codec: " << config.codec() 434 << " codec: " << config.codec()
426 << " channel count: " << channel_count 435 << " channel count: " << channel_count
427 << " channel layout: " << config.channel_layout() 436 << " channel layout: " << config.channel_layout()
428 << " bits per channel: " << config.bits_per_channel() 437 << " bits per channel: " << config.bits_per_channel()
429 << " samples per second: " << config.samples_per_second(); 438 << " 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; 439 return false;
436 } 440 }
437 441
438 if (config.is_encrypted()) { 442 if (config.is_encrypted()) {
439 DVLOG(0) << "Encrypted audio stream not supported."; 443 DLOG(ERROR) << "Encrypted audio stream not supported.";
440 return false; 444 return false;
441 } 445 }
442 446
443 if (opus_decoder_ && 447 if (opus_decoder_ &&
444 (bits_per_channel_ != config.bits_per_channel() || 448 (channel_layout_ != config.channel_layout() ||
445 channel_layout_ != config.channel_layout() ||
446 samples_per_second_ != config.samples_per_second())) { 449 samples_per_second_ != config.samples_per_second())) {
447 DVLOG(1) << "Unsupported config change :"; 450 DLOG(ERROR) << "Unsupported config change -"
448 DVLOG(1) << "\tbits_per_channel : " << bits_per_channel_ 451 << ", channel_layout: " << channel_layout_
449 << " -> " << config.bits_per_channel(); 452 << " -> " << config.channel_layout()
450 DVLOG(1) << "\tchannel_layout : " << channel_layout_ 453 << ", sample_rate: " << samples_per_second_
451 << " -> " << config.channel_layout(); 454 << " -> " << config.samples_per_second();
452 DVLOG(1) << "\tsample_rate : " << samples_per_second_
453 << " -> " << config.samples_per_second();
454 return false; 455 return false;
455 } 456 }
456 457
457 // Clean up existing decoder if necessary. 458 // Clean up existing decoder if necessary.
458 CloseDecoder(); 459 CloseDecoder();
459 460
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. 461 // Parse the Opus Extra Data.
465 OpusExtraData opus_extra_data; 462 OpusExtraData opus_extra_data;
466 if (!ParseOpusExtraData(config.extra_data(), config.extra_data_size(), 463 if (!ParseOpusExtraData(config.extra_data(), config.extra_data_size(),
467 config, 464 config,
468 &opus_extra_data)) 465 &opus_extra_data))
469 return false; 466 return false;
470 467
471 if (!config.codec_delay().InMicroseconds())
472 return false;
473
474 // Convert from seconds to samples. 468 // Convert from seconds to samples.
475 timestamp_offset_ = config.codec_delay(); 469 timestamp_offset_ = config.codec_delay();
476 frame_delay_at_start_ = TimeDeltaToAudioFrames(config.codec_delay(), 470 frame_delay_at_start_ = TimeDeltaToAudioFrames(config.codec_delay(),
477 config.samples_per_second()); 471 config.samples_per_second());
478 if (frame_delay_at_start_ < 0) { 472 if (timestamp_offset_ <= base::TimeDelta() || frame_delay_at_start_ < 0) {
479 DVLOG(1) << "Invalid file. Incorrect value for codec delay."; 473 DLOG(ERROR) << "Invalid file. Incorrect value for codec delay: "
480 return false; 474 << 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; 475 return false;
486 } 476 }
487 477
488 uint8 channel_mapping[kMaxVorbisChannels]; 478 if (frame_delay_at_start_ != opus_extra_data.skip_samples) {
479 DLOG(ERROR) << "Invalid file. Codec Delay in container does not match the "
480 << "value in Opus Extra Data.";
481 return false;
482 }
483
484 uint8 channel_mapping[kMaxVorbisChannels] = {0};
489 memcpy(&channel_mapping, 485 memcpy(&channel_mapping,
490 kDefaultOpusChannelLayout, 486 kDefaultOpusChannelLayout,
491 kMaxChannelsWithDefaultLayout); 487 kMaxChannelsWithDefaultLayout);
492 488
493 if (channel_count > kMaxChannelsWithDefaultLayout) { 489 if (channel_count > kMaxChannelsWithDefaultLayout) {
494 RemapOpusChannelLayout(opus_extra_data.stream_map, 490 RemapOpusChannelLayout(opus_extra_data.stream_map,
495 channel_count, 491 channel_count,
496 channel_mapping); 492 channel_mapping);
497 } 493 }
498 494
499 // Init Opus. 495 // Init Opus.
500 int status = OPUS_INVALID_STATE; 496 int status = OPUS_INVALID_STATE;
501 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), 497 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(),
502 channel_count, 498 channel_count,
503 opus_extra_data.num_streams, 499 opus_extra_data.num_streams,
504 opus_extra_data.num_coupled, 500 opus_extra_data.num_coupled,
505 channel_mapping, 501 channel_mapping,
506 &status); 502 &status);
507 if (!opus_decoder_ || status != OPUS_OK) { 503 if (!opus_decoder_ || status != OPUS_OK) {
508 DVLOG(0) << "opus_multistream_decoder_create failed status=" 504 DLOG(ERROR) << "opus_multistream_decoder_create failed status="
509 << opus_strerror(status); 505 << opus_strerror(status);
510 return false; 506 return false;
511 } 507 }
512 508
513 bits_per_channel_ = config.bits_per_channel();
514 channel_layout_ = config.channel_layout(); 509 channel_layout_ = config.channel_layout();
515 samples_per_second_ = config.samples_per_second(); 510 samples_per_second_ = config.samples_per_second();
516 output_timestamp_helper_.reset( 511 output_timestamp_helper_.reset(
517 new AudioTimestampHelper(config.samples_per_second())); 512 new AudioTimestampHelper(config.samples_per_second()));
513
518 return true; 514 return true;
519 } 515 }
520 516
521 void OpusAudioDecoder::CloseDecoder() { 517 void OpusAudioDecoder::CloseDecoder() {
522 if (opus_decoder_) { 518 if (opus_decoder_) {
523 opus_multistream_decoder_destroy(opus_decoder_); 519 opus_multistream_decoder_destroy(opus_decoder_);
524 opus_decoder_ = NULL; 520 opus_decoder_ = NULL;
525 } 521 }
526 } 522 }
527 523
528 void OpusAudioDecoder::ResetTimestampState() { 524 void OpusAudioDecoder::ResetTimestampState() {
529 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); 525 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp());
530 last_input_timestamp_ = kNoTimestamp(); 526 last_input_timestamp_ = kNoTimestamp();
531 frames_to_discard_ = TimeDeltaToAudioFrames( 527 frames_to_discard_ = TimeDeltaToAudioFrames(
532 demuxer_stream_->audio_decoder_config().seek_preroll(), 528 demuxer_stream_->audio_decoder_config().seek_preroll(),
533 samples_per_second_); 529 samples_per_second_);
534 } 530 }
535 531
536 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, 532 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input,
537 scoped_refptr<AudioBuffer>* output_buffer) { 533 scoped_refptr<AudioBuffer>* output_buffer) {
538 int frames_decoded = opus_multistream_decode(opus_decoder_, 534 // Allocate a buffer for the output samples.
539 input->data(), 535 *output_buffer = AudioBuffer::CreateBuffer(
540 input->data_size(), 536 sample_format_,
541 &output_buffer_[0], 537 ChannelLayoutToChannelCount(channel_layout_),
542 kMaxOpusOutputPacketSizeSamples, 538 kMaxOpusOutputPacketSizeSamples);
543 0); 539 const int buffer_size =
540 output_buffer->get()->channel_count() *
541 output_buffer->get()->frame_count() *
542 SampleFormatToBytesPerChannel(sample_format_);
543
544 // Android uses a fixed point build of the opus decoder.
545 #if defined(OS_ANDROID)
546 int16* int16_output_buffer = reinterpret_cast<int16*>(
547 output_buffer->get()->channel_data()[0]);
548 const int frames_decoded =
549 opus_multistream_decode(opus_decoder_,
550 input->data(),
551 input->data_size(),
552 int16_output_buffer,
553 buffer_size,
554 0);
555 #else
556 float* float_output_buffer = reinterpret_cast<float*>(
557 output_buffer->get()->channel_data()[0]);
558 const int frames_decoded =
559 opus_multistream_decode_float(opus_decoder_,
560 input->data(),
561 input->data_size(),
562 float_output_buffer,
563 buffer_size,
564 0);
565 #endif
566
544 if (frames_decoded < 0) { 567 if (frames_decoded < 0) {
545 DVLOG(0) << "opus_multistream_decode failed for" 568 DLOG(ERROR) << "opus_multistream_decode failed for"
546 << " timestamp: " << input->timestamp().InMicroseconds() 569 << " timestamp: " << input->timestamp().InMicroseconds()
547 << " us, duration: " << input->duration().InMicroseconds() 570 << " us, duration: " << input->duration().InMicroseconds()
548 << " us, packet size: " << input->data_size() << " bytes with" 571 << " us, packet size: " << input->data_size() << " bytes with"
549 << " status: " << opus_strerror(frames_decoded); 572 << " status: " << opus_strerror(frames_decoded);
550 return false; 573 return false;
551 } 574 }
552 575
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() && 576 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() &&
559 !input->end_of_stream()) { 577 !input->end_of_stream()) {
560 DCHECK(input->timestamp() != kNoTimestamp()); 578 DCHECK(input->timestamp() != kNoTimestamp());
561 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); 579 output_timestamp_helper_->SetBaseTimestamp(input->timestamp());
562 } 580 }
563 581
564 // Skip samples should be equal to codec delay when the file starts and when 582 // Trim off any extraneous allocation.
565 // there is a seek to zero. 583 DCHECK_LE(frames_decoded, output_buffer->get()->frame_count());
566 // TODO(vigneshv): This should be checked for start of stream rather than 584 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. 585 if (trim_frames > 0)
568 if (input->timestamp() == base::TimeDelta()) 586 output_buffer->get()->TrimEnd(trim_frames);
569 frames_to_discard_ = frame_delay_at_start_;
570 587
571 if (bytes_decoded > 0 && frames_decoded > frames_to_discard_) { 588 // Handle frame discard and trimming.
572 // Copy the audio samples into an output buffer. 589 int frames_to_output = frames_decoded;
573 uint8* data[] = { decoded_audio_data }; 590 if (frames_decoded > frames_to_discard_) {
574 *output_buffer = AudioBuffer::CopyFrom(
575 kSampleFormatS16,
576 ChannelLayoutToChannelCount(channel_layout_),
577 frames_decoded,
578 data,
579 output_timestamp_helper_->GetTimestamp() - timestamp_offset_,
580 output_timestamp_helper_->GetFrameDuration(frames_decoded));
581 output_timestamp_helper_->AddFrames(frames_decoded);
582 if (frames_to_discard_ > 0) { 591 if (frames_to_discard_ > 0) {
583 output_buffer->get()->TrimStart(frames_to_discard_); 592 output_buffer->get()->TrimStart(frames_to_discard_);
584 frames_decoded -= frames_to_discard_; 593 frames_to_output -= frames_to_discard_;
585 frames_to_discard_ = 0; 594 frames_to_discard_ = 0;
586 } 595 }
587 if (input->discard_padding().InMicroseconds() > 0) { 596 if (input->discard_padding().InMicroseconds() > 0) {
588 int discard_padding = TimeDeltaToAudioFrames(input->discard_padding(), 597 int discard_padding = TimeDeltaToAudioFrames(input->discard_padding(),
589 samples_per_second_); 598 samples_per_second_);
590 if (discard_padding < 0 || discard_padding > frames_decoded) { 599 if (discard_padding < 0 || discard_padding > frames_to_output) {
591 DVLOG(1) << "Invalid file. Incorrect discard padding value."; 600 DVLOG(1) << "Invalid file. Incorrect discard padding value.";
592 return false; 601 return false;
593 } 602 }
594 output_buffer->get()->TrimEnd(discard_padding); 603 output_buffer->get()->TrimEnd(discard_padding);
595 frames_decoded -= discard_padding; 604 frames_to_output -= discard_padding;
596 } 605 }
597 } else if (bytes_decoded > 0) { 606 } else {
598 frames_to_discard_ -= frames_decoded; 607 frames_to_discard_ -= frames_to_output;
599 frames_decoded = 0; 608 frames_to_output = 0;
600 } 609 }
601 610
602 // Decoding finished successfully, update statistics. 611 // Decoding finished successfully, update statistics.
603 PipelineStatistics statistics; 612 PipelineStatistics statistics;
604 statistics.audio_bytes_decoded = input->data_size(); 613 statistics.audio_bytes_decoded = input->data_size();
605 statistics_cb_.Run(statistics); 614 statistics_cb_.Run(statistics);
606 615
616 // Assign timestamp and duration to the buffer.
617 output_buffer->get()->set_timestamp(
618 output_timestamp_helper_->GetTimestamp() - timestamp_offset_);
acolwell GONE FROM CHROMIUM 2013/12/12 00:53:14 We may be double subtracting off the offset here d
619 output_buffer->get()->set_duration(
620 output_timestamp_helper_->GetFrameDuration(frames_to_output));
621 output_timestamp_helper_->AddFrames(frames_decoded);
622
607 // Discard the buffer to indicate we need more data. 623 // Discard the buffer to indicate we need more data.
608 if (!frames_decoded) 624 if (!frames_to_output)
609 *output_buffer = NULL; 625 *output_buffer = NULL;
610 626
611 return true; 627 return true;
612 } 628 }
613 629
614 } // namespace media 630 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/opus_audio_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698