OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |