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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 memcpy(&value, data + read_offset, sizeof(value)); | 29 memcpy(&value, data + read_offset, sizeof(value)); |
30 return base::ByteSwapToLE16(value); | 30 return base::ByteSwapToLE16(value); |
31 } | 31 } |
32 | 32 |
33 // Returns true if the decode result was end of stream. | 33 // Returns true if the decode result was end of stream. |
34 static inline bool IsEndOfStream(int decoded_size, | 34 static inline bool IsEndOfStream(int decoded_size, |
35 const scoped_refptr<DecoderBuffer>& input) { | 35 const scoped_refptr<DecoderBuffer>& input) { |
36 // Two conditions to meet to declare end of stream for this decoder: | 36 // Two conditions to meet to declare end of stream for this decoder: |
37 // 1. Opus didn't output anything. | 37 // 1. Opus didn't output anything. |
38 // 2. An end of stream buffer is received. | 38 // 2. An end of stream buffer is received. |
39 return decoded_size == 0 && input->IsEndOfStream(); | 39 return decoded_size == 0 && input->end_of_stream(); |
40 } | 40 } |
41 | 41 |
42 // The Opus specification is part of IETF RFC 6716: | 42 // The Opus specification is part of IETF RFC 6716: |
43 // http://tools.ietf.org/html/rfc6716 | 43 // http://tools.ietf.org/html/rfc6716 |
44 | 44 |
45 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies | 45 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies |
46 // mappings for up to 8 channels. This information is part of the Vorbis I | 46 // mappings for up to 8 channels. This information is part of the Vorbis I |
47 // Specification: | 47 // Specification: |
48 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html | 48 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html |
49 static const int kMaxVorbisChannels = 8; | 49 static const int kMaxVorbisChannels = 8; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 // 8 Channels (7.1) | 83 // 8 Channels (7.1) |
84 // Front L, Center, Front R, Side L, Side R, Back L, Back R, LFE | 84 // Front L, Center, Front R, Side L, Side R, Back L, Back R, LFE |
85 // | 85 // |
86 // Channel ordering information is taken from section 4.3.9 of the Vorbis I | 86 // Channel ordering information is taken from section 4.3.9 of the Vorbis I |
87 // Specification: | 87 // Specification: |
88 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 | 88 // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 |
89 | 89 |
90 // These are the FFmpeg channel layouts expressed using the position of each | 90 // These are the FFmpeg channel layouts expressed using the position of each |
91 // channel in the output stream from libopus. | 91 // channel in the output stream from libopus. |
92 const uint8 kFFmpegChannelLayouts[num_layouts][num_layout_values] = { | 92 const uint8 kFFmpegChannelLayouts[num_layouts][num_layout_values] = { |
93 { 0 }, | 93 {0}, |
94 | 94 |
95 // Stereo: No reorder. | 95 // Stereo: No reorder. |
96 { 0, 1 }, | 96 {0, 1}, |
97 | 97 |
98 // 3 Channels, from Vorbis order to: | 98 // 3 Channels, from Vorbis order to: |
99 // L, R, Center | 99 // L, R, Center |
100 { 0, 2, 1 }, | 100 {0, 2, 1}, |
101 | 101 |
102 // 4 Channels: No reorder. | 102 // 4 Channels: No reorder. |
103 { 0, 1, 2, 3 }, | 103 {0, 1, 2, 3}, |
104 | 104 |
105 // 5 Channels, from Vorbis order to: | 105 // 5 Channels, from Vorbis order to: |
106 // Front L, Front R, Center, Back L, Back R | 106 // Front L, Front R, Center, Back L, Back R |
107 { 0, 2, 1, 3, 4 }, | 107 {0, 2, 1, 3, 4}, |
108 | 108 |
109 // 6 Channels (5.1), from Vorbis order to: | 109 // 6 Channels (5.1), from Vorbis order to: |
110 // Front L, Front R, Center, LFE, Back L, Back R | 110 // Front L, Front R, Center, LFE, Back L, Back R |
111 { 0, 2, 1, 5, 3, 4 }, | 111 {0, 2, 1, 5, 3, 4}, |
112 | 112 |
113 // 7 Channels (6.1), from Vorbis order to: | 113 // 7 Channels (6.1), from Vorbis order to: |
114 // Front L, Front R, Front Center, LFE, Side L, Side R, Back Center | 114 // Front L, Front R, Front Center, LFE, Side L, Side R, Back Center |
115 { 0, 2, 1, 6, 3, 4, 5 }, | 115 {0, 2, 1, 6, 3, 4, 5}, |
116 | 116 |
117 // 8 Channels (7.1), from Vorbis order to: | 117 // 8 Channels (7.1), from Vorbis order to: |
118 // Front L, Front R, Center, LFE, Back L, Back R, Side L, Side R | 118 // Front L, Front R, Center, LFE, Back L, Back R, Side L, Side R |
119 { 0, 2, 1, 7, 5, 6, 3, 4 }, | 119 {0, 2, 1, 7, 5, 6, 3, 4}, |
120 }; | 120 }; |
121 | 121 |
122 // Reorder the channels to produce the same ordering as FFmpeg, which is | 122 // Reorder the channels to produce the same ordering as FFmpeg, which is |
123 // what the pipeline expects. | 123 // what the pipeline expects. |
124 const uint8* vorbis_layout_offset = kFFmpegChannelLayouts[num_channels - 1]; | 124 const uint8* vorbis_layout_offset = kFFmpegChannelLayouts[num_channels - 1]; |
125 for (int channel = 0; channel < num_channels; ++channel) | 125 for (int channel = 0; channel < num_channels; ++channel) |
126 channel_layout[channel] = opus_mapping[vorbis_layout_offset[channel]]; | 126 channel_layout[channel] = opus_mapping[vorbis_layout_offset[channel]]; |
127 } | 127 } |
128 | 128 |
129 // Opus Header contents: | 129 // Opus Header contents: |
(...skipping 18 matching lines...) Expand all Loading... |
148 // - right | 148 // - right |
149 // - else | 149 // - else |
150 // - stream = byte-M | 150 // - stream = byte-M |
151 | 151 |
152 // Default audio output channel layout. Used to initialize |stream_map| in | 152 // Default audio output channel layout. Used to initialize |stream_map| in |
153 // OpusHeader, and passed to opus_multistream_decoder_create() when the header | 153 // OpusHeader, and passed to opus_multistream_decoder_create() when the header |
154 // does not contain mapping information. The values are valid only for mono and | 154 // does not contain mapping information. The values are valid only for mono and |
155 // stereo output: Opus streams with more than 2 channels require a stream map. | 155 // stereo output: Opus streams with more than 2 channels require a stream map. |
156 static const int kMaxChannelsWithDefaultLayout = 2; | 156 static const int kMaxChannelsWithDefaultLayout = 2; |
157 static const uint8 kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { | 157 static const uint8 kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { |
158 0, 1 }; | 158 0, 1 |
| 159 }; |
159 | 160 |
160 // Size of the Opus header excluding optional mapping information. | 161 // Size of the Opus header excluding optional mapping information. |
161 static const int kOpusHeaderSize = 19; | 162 static const int kOpusHeaderSize = 19; |
162 | 163 |
163 // Offset to the channel count byte in the Opus header. | 164 // Offset to the channel count byte in the Opus header. |
164 static const int kOpusHeaderChannelsOffset = 9; | 165 static const int kOpusHeaderChannelsOffset = 9; |
165 | 166 |
166 // Offset to the pre-skip value in the Opus header. | 167 // Offset to the pre-skip value in the Opus header. |
167 static const int kOpusHeaderSkipSamplesOffset = 10; | 168 static const int kOpusHeaderSkipSamplesOffset = 10; |
168 | 169 |
(...skipping 10 matching lines...) Expand all Loading... |
179 static const int kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; | 180 static const int kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; |
180 static const int kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; | 181 static const int kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; |
181 | 182 |
182 struct OpusHeader { | 183 struct OpusHeader { |
183 OpusHeader() | 184 OpusHeader() |
184 : channels(0), | 185 : channels(0), |
185 skip_samples(0), | 186 skip_samples(0), |
186 channel_mapping(0), | 187 channel_mapping(0), |
187 num_streams(0), | 188 num_streams(0), |
188 num_coupled(0) { | 189 num_coupled(0) { |
189 memcpy(stream_map, | 190 memcpy( |
190 kDefaultOpusChannelLayout, | 191 stream_map, kDefaultOpusChannelLayout, kMaxChannelsWithDefaultLayout); |
191 kMaxChannelsWithDefaultLayout); | |
192 } | 192 } |
193 int channels; | 193 int channels; |
194 int skip_samples; | 194 int skip_samples; |
195 int channel_mapping; | 195 int channel_mapping; |
196 int num_streams; | 196 int num_streams; |
197 int num_coupled; | 197 int num_coupled; |
198 uint8 stream_map[kMaxVorbisChannels]; | 198 uint8 stream_map[kMaxVorbisChannels]; |
199 }; | 199 }; |
200 | 200 |
201 // Returns true when able to successfully parse and store Opus header data in | 201 // Returns true when able to successfully parse and store Opus header data in |
202 // data parsed in |header|. Based on opus header parsing code in libopusdec | 202 // data parsed in |header|. Based on opus header parsing code in libopusdec |
203 // from FFmpeg, and opus_header from Xiph's opus-tools project. | 203 // from FFmpeg, and opus_header from Xiph's opus-tools project. |
204 static void ParseOpusHeader(const uint8* data, int data_size, | 204 static void ParseOpusHeader(const uint8* data, |
| 205 int data_size, |
205 const AudioDecoderConfig& config, | 206 const AudioDecoderConfig& config, |
206 OpusHeader* header) { | 207 OpusHeader* header) { |
207 CHECK_GE(data_size, kOpusHeaderSize); | 208 CHECK_GE(data_size, kOpusHeaderSize); |
208 | 209 |
209 header->channels = *(data + kOpusHeaderChannelsOffset); | 210 header->channels = *(data + kOpusHeaderChannelsOffset); |
210 | 211 |
211 CHECK(header->channels > 0 && header->channels <= kMaxVorbisChannels) | 212 CHECK(header->channels > 0 && header->channels <= kMaxVorbisChannels) |
212 << "invalid channel count in header: " << header->channels; | 213 << "invalid channel count in header: " << header->channels; |
213 | 214 |
214 header->skip_samples = | 215 header->skip_samples = |
(...skipping 29 matching lines...) Expand all Loading... |
244 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 245 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
245 : message_loop_(message_loop), | 246 : message_loop_(message_loop), |
246 weak_factory_(this), | 247 weak_factory_(this), |
247 demuxer_stream_(NULL), | 248 demuxer_stream_(NULL), |
248 opus_decoder_(NULL), | 249 opus_decoder_(NULL), |
249 bits_per_channel_(0), | 250 bits_per_channel_(0), |
250 channel_layout_(CHANNEL_LAYOUT_NONE), | 251 channel_layout_(CHANNEL_LAYOUT_NONE), |
251 samples_per_second_(0), | 252 samples_per_second_(0), |
252 last_input_timestamp_(kNoTimestamp()), | 253 last_input_timestamp_(kNoTimestamp()), |
253 output_bytes_to_drop_(0), | 254 output_bytes_to_drop_(0), |
254 skip_samples_(0) { | 255 skip_samples_(0) {} |
255 } | |
256 | 256 |
257 void OpusAudioDecoder::Initialize( | 257 void OpusAudioDecoder::Initialize(DemuxerStream* stream, |
258 DemuxerStream* stream, | 258 const PipelineStatusCB& status_cb, |
259 const PipelineStatusCB& status_cb, | 259 const StatisticsCB& statistics_cb) { |
260 const StatisticsCB& statistics_cb) { | |
261 DCHECK(message_loop_->BelongsToCurrentThread()); | 260 DCHECK(message_loop_->BelongsToCurrentThread()); |
262 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 261 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
263 | 262 |
264 if (demuxer_stream_) { | 263 if (demuxer_stream_) { |
265 // TODO(scherkus): initialization currently happens more than once in | 264 // TODO(scherkus): initialization currently happens more than once in |
266 // PipelineIntegrationTest.BasicPlayback. | 265 // PipelineIntegrationTest.BasicPlayback. |
267 LOG(ERROR) << "Initialize has already been called."; | 266 LOG(ERROR) << "Initialize has already been called."; |
268 CHECK(false); | 267 CHECK(false); |
269 } | 268 } |
270 | 269 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 // TODO(scherkus): should we require Stop() to be called? this might end up | 316 // TODO(scherkus): should we require Stop() to be called? this might end up |
318 // getting called on a random thread due to refcounting. | 317 // getting called on a random thread due to refcounting. |
319 CloseDecoder(); | 318 CloseDecoder(); |
320 } | 319 } |
321 | 320 |
322 void OpusAudioDecoder::ReadFromDemuxerStream() { | 321 void OpusAudioDecoder::ReadFromDemuxerStream() { |
323 DCHECK(!read_cb_.is_null()); | 322 DCHECK(!read_cb_.is_null()); |
324 demuxer_stream_->Read(base::Bind(&OpusAudioDecoder::BufferReady, weak_this_)); | 323 demuxer_stream_->Read(base::Bind(&OpusAudioDecoder::BufferReady, weak_this_)); |
325 } | 324 } |
326 | 325 |
327 void OpusAudioDecoder::BufferReady( | 326 void OpusAudioDecoder::BufferReady(DemuxerStream::Status status, |
328 DemuxerStream::Status status, | 327 const scoped_refptr<DecoderBuffer>& input) { |
329 const scoped_refptr<DecoderBuffer>& input) { | |
330 DCHECK(message_loop_->BelongsToCurrentThread()); | 328 DCHECK(message_loop_->BelongsToCurrentThread()); |
331 DCHECK(!read_cb_.is_null()); | 329 DCHECK(!read_cb_.is_null()); |
332 DCHECK_EQ(status != DemuxerStream::kOk, !input.get()) << status; | 330 DCHECK_EQ(status != DemuxerStream::kOk, !input.get()) << status; |
333 | 331 |
334 if (status == DemuxerStream::kAborted) { | 332 if (status == DemuxerStream::kAborted) { |
335 DCHECK(!input.get()); | 333 DCHECK(!input.get()); |
336 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); | 334 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); |
337 return; | 335 return; |
338 } | 336 } |
339 | 337 |
340 if (status == DemuxerStream::kConfigChanged) { | 338 if (status == DemuxerStream::kConfigChanged) { |
341 DCHECK(!input.get()); | 339 DCHECK(!input.get()); |
342 DVLOG(1) << "Config changed."; | 340 DVLOG(1) << "Config changed."; |
343 | 341 |
344 if (!ConfigureDecoder()) { | 342 if (!ConfigureDecoder()) { |
345 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 343 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
346 return; | 344 return; |
347 } | 345 } |
348 | 346 |
349 ResetTimestampState(); | 347 ResetTimestampState(); |
350 ReadFromDemuxerStream(); | 348 ReadFromDemuxerStream(); |
351 return; | 349 return; |
352 } | 350 } |
353 | 351 |
354 DCHECK_EQ(status, DemuxerStream::kOk); | 352 DCHECK_EQ(status, DemuxerStream::kOk); |
355 DCHECK(input.get()); | 353 DCHECK(input.get()); |
356 | 354 |
357 // Libopus does not buffer output. Decoding is complete when an end of stream | 355 // Libopus does not buffer output. Decoding is complete when an end of stream |
358 // input buffer is received. | 356 // input buffer is received. |
359 if (input->IsEndOfStream()) { | 357 if (input->end_of_stream()) { |
360 base::ResetAndReturn(&read_cb_).Run(kOk, DataBuffer::CreateEOSBuffer()); | 358 base::ResetAndReturn(&read_cb_).Run(kOk, DataBuffer::CreateEOSBuffer()); |
361 return; | 359 return; |
362 } | 360 } |
363 | 361 |
364 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 362 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
365 // occurs with some damaged files. | 363 // occurs with some damaged files. |
366 if (input->GetTimestamp() == kNoTimestamp() && | 364 if (input->timestamp() == kNoTimestamp() && |
367 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { | 365 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { |
368 DVLOG(1) << "Received a buffer without timestamps!"; | 366 DVLOG(1) << "Received a buffer without timestamps!"; |
369 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 367 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
370 return; | 368 return; |
371 } | 369 } |
372 | 370 |
373 if (last_input_timestamp_ != kNoTimestamp() && | 371 if (last_input_timestamp_ != kNoTimestamp() && |
374 input->GetTimestamp() != kNoTimestamp() && | 372 input->timestamp() != kNoTimestamp() && |
375 input->GetTimestamp() < last_input_timestamp_) { | 373 input->timestamp() < last_input_timestamp_) { |
376 base::TimeDelta diff = input->GetTimestamp() - last_input_timestamp_; | 374 base::TimeDelta diff = input->timestamp() - last_input_timestamp_; |
377 DVLOG(1) << "Input timestamps are not monotonically increasing! " | 375 DVLOG(1) << "Input timestamps are not monotonically increasing! " |
378 << " ts " << input->GetTimestamp().InMicroseconds() << " us" | 376 << " ts " << input->timestamp().InMicroseconds() << " us" |
379 << " diff " << diff.InMicroseconds() << " us"; | 377 << " diff " << diff.InMicroseconds() << " us"; |
380 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 378 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
381 return; | 379 return; |
382 } | 380 } |
383 | 381 |
384 last_input_timestamp_ = input->GetTimestamp(); | 382 last_input_timestamp_ = input->timestamp(); |
385 | 383 |
386 scoped_refptr<DataBuffer> output_buffer; | 384 scoped_refptr<DataBuffer> output_buffer; |
387 | 385 |
388 if (!Decode(input, &output_buffer)) { | 386 if (!Decode(input, &output_buffer)) { |
389 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 387 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
390 return; | 388 return; |
391 } | 389 } |
392 | 390 |
393 if (output_buffer.get()) { | 391 if (output_buffer.get()) { |
394 // Execute callback to return the decoded audio. | 392 // Execute callback to return the decoded audio. |
(...skipping 28 matching lines...) Expand all Loading... |
423 if (config.bits_per_channel() != kBitsPerChannel) { | 421 if (config.bits_per_channel() != kBitsPerChannel) { |
424 DLOG(ERROR) << "16 bit samples required."; | 422 DLOG(ERROR) << "16 bit samples required."; |
425 return false; | 423 return false; |
426 } | 424 } |
427 | 425 |
428 if (config.is_encrypted()) { | 426 if (config.is_encrypted()) { |
429 DLOG(ERROR) << "Encrypted audio stream not supported."; | 427 DLOG(ERROR) << "Encrypted audio stream not supported."; |
430 return false; | 428 return false; |
431 } | 429 } |
432 | 430 |
433 if (opus_decoder_ && | 431 if (opus_decoder_ && (bits_per_channel_ != config.bits_per_channel() || |
434 (bits_per_channel_ != config.bits_per_channel() || | 432 channel_layout_ != config.channel_layout() || |
435 channel_layout_ != config.channel_layout() || | 433 samples_per_second_ != config.samples_per_second())) { |
436 samples_per_second_ != config.samples_per_second())) { | |
437 DVLOG(1) << "Unsupported config change :"; | 434 DVLOG(1) << "Unsupported config change :"; |
438 DVLOG(1) << "\tbits_per_channel : " << bits_per_channel_ | 435 DVLOG(1) << "\tbits_per_channel : " << bits_per_channel_ << " -> " |
439 << " -> " << config.bits_per_channel(); | 436 << config.bits_per_channel(); |
440 DVLOG(1) << "\tchannel_layout : " << channel_layout_ | 437 DVLOG(1) << "\tchannel_layout : " << channel_layout_ << " -> " |
441 << " -> " << config.channel_layout(); | 438 << config.channel_layout(); |
442 DVLOG(1) << "\tsample_rate : " << samples_per_second_ | 439 DVLOG(1) << "\tsample_rate : " << samples_per_second_ << " -> " |
443 << " -> " << config.samples_per_second(); | 440 << config.samples_per_second(); |
444 return false; | 441 return false; |
445 } | 442 } |
446 | 443 |
447 // Clean up existing decoder if necessary. | 444 // Clean up existing decoder if necessary. |
448 CloseDecoder(); | 445 CloseDecoder(); |
449 | 446 |
450 // Allocate the output buffer if necessary. | 447 // Allocate the output buffer if necessary. |
451 if (!output_buffer_) | 448 if (!output_buffer_) |
452 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); | 449 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); |
453 | 450 |
454 // Parse the Opus header. | 451 // Parse the Opus header. |
455 OpusHeader opus_header; | 452 OpusHeader opus_header; |
456 ParseOpusHeader(config.extra_data(), config.extra_data_size(), | 453 ParseOpusHeader( |
457 config, | 454 config.extra_data(), config.extra_data_size(), config, &opus_header); |
458 &opus_header); | |
459 | 455 |
460 skip_samples_ = opus_header.skip_samples; | 456 skip_samples_ = opus_header.skip_samples; |
461 | 457 |
462 if (skip_samples_ > 0) | 458 if (skip_samples_ > 0) |
463 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); | 459 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); |
464 | 460 |
465 uint8 channel_mapping[kMaxVorbisChannels]; | 461 uint8 channel_mapping[kMaxVorbisChannels]; |
466 memcpy(&channel_mapping, | 462 memcpy(&channel_mapping, |
467 kDefaultOpusChannelLayout, | 463 kDefaultOpusChannelLayout, |
468 kMaxChannelsWithDefaultLayout); | 464 kMaxChannelsWithDefaultLayout); |
469 | 465 |
470 if (channel_count > kMaxChannelsWithDefaultLayout) { | 466 if (channel_count > kMaxChannelsWithDefaultLayout) { |
471 RemapOpusChannelLayout(opus_header.stream_map, | 467 RemapOpusChannelLayout( |
472 channel_count, | 468 opus_header.stream_map, channel_count, channel_mapping); |
473 channel_mapping); | |
474 } | 469 } |
475 | 470 |
476 // Init Opus. | 471 // Init Opus. |
477 int status = OPUS_INVALID_STATE; | 472 int status = OPUS_INVALID_STATE; |
478 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), | 473 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), |
479 channel_count, | 474 channel_count, |
480 opus_header.num_streams, | 475 opus_header.num_streams, |
481 opus_header.num_coupled, | 476 opus_header.num_coupled, |
482 channel_mapping, | 477 channel_mapping, |
483 &status); | 478 &status); |
(...skipping 24 matching lines...) Expand all Loading... |
508 void OpusAudioDecoder::ResetTimestampState() { | 503 void OpusAudioDecoder::ResetTimestampState() { |
509 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 504 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
510 last_input_timestamp_ = kNoTimestamp(); | 505 last_input_timestamp_ = kNoTimestamp(); |
511 output_bytes_to_drop_ = 0; | 506 output_bytes_to_drop_ = 0; |
512 } | 507 } |
513 | 508 |
514 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, | 509 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, |
515 scoped_refptr<DataBuffer>* output_buffer) { | 510 scoped_refptr<DataBuffer>* output_buffer) { |
516 const int samples_decoded = | 511 const int samples_decoded = |
517 opus_multistream_decode(opus_decoder_, | 512 opus_multistream_decode(opus_decoder_, |
518 input->GetData(), input->GetDataSize(), | 513 input->data(), |
| 514 input->data_size(), |
519 &output_buffer_[0], | 515 &output_buffer_[0], |
520 kMaxOpusOutputPacketSizeSamples, | 516 kMaxOpusOutputPacketSizeSamples, |
521 0); | 517 0); |
522 if (samples_decoded < 0) { | 518 if (samples_decoded < 0) { |
523 LOG(ERROR) << "opus_multistream_decode failed for" | 519 LOG(ERROR) << "opus_multistream_decode failed for" |
524 << " timestamp: " << input->GetTimestamp().InMicroseconds() | 520 << " timestamp: " << input->timestamp().InMicroseconds() |
525 << " us, duration: " << input->GetDuration().InMicroseconds() | 521 << " us, duration: " << input->duration().InMicroseconds() |
526 << " us, packet size: " << input->GetDataSize() << " bytes with" | 522 << " us, packet size: " << input->data_size() << " bytes with" |
527 << " status: " << opus_strerror(samples_decoded); | 523 << " status: " << opus_strerror(samples_decoded); |
528 return false; | 524 return false; |
529 } | 525 } |
530 | 526 |
531 uint8* decoded_audio_data = reinterpret_cast<uint8*>(&output_buffer_[0]); | 527 uint8* decoded_audio_data = reinterpret_cast<uint8*>(&output_buffer_[0]); |
532 int decoded_audio_size = samples_decoded * | 528 int decoded_audio_size = |
| 529 samples_decoded * |
533 demuxer_stream_->audio_decoder_config().bytes_per_frame(); | 530 demuxer_stream_->audio_decoder_config().bytes_per_frame(); |
534 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); | 531 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); |
535 | 532 |
536 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | 533 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
537 !input->IsEndOfStream()) { | 534 !input->end_of_stream()) { |
538 DCHECK(input->GetTimestamp() != kNoTimestamp()); | 535 DCHECK(input->timestamp() != kNoTimestamp()); |
539 output_timestamp_helper_->SetBaseTimestamp(input->GetTimestamp()); | 536 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); |
540 } | 537 } |
541 | 538 |
542 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { | 539 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { |
543 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); | 540 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); |
544 DCHECK_EQ(dropped_size % kBytesPerChannel, 0); | 541 DCHECK_EQ(dropped_size % kBytesPerChannel, 0); |
545 decoded_audio_data += dropped_size; | 542 decoded_audio_data += dropped_size; |
546 decoded_audio_size -= dropped_size; | 543 decoded_audio_size -= dropped_size; |
547 output_bytes_to_drop_ -= dropped_size; | 544 output_bytes_to_drop_ -= dropped_size; |
548 } | 545 } |
549 | 546 |
550 if (decoded_audio_size > 0) { | 547 if (decoded_audio_size > 0) { |
551 // Copy the audio samples into an output buffer. | 548 // Copy the audio samples into an output buffer. |
552 *output_buffer = DataBuffer::CopyFrom( | 549 *output_buffer = |
553 decoded_audio_data, decoded_audio_size); | 550 DataBuffer::CopyFrom(decoded_audio_data, decoded_audio_size); |
554 (*output_buffer)->set_timestamp(output_timestamp_helper_->GetTimestamp()); | 551 (*output_buffer)->set_timestamp(output_timestamp_helper_->GetTimestamp()); |
555 (*output_buffer)->set_duration( | 552 (*output_buffer)->set_duration( |
556 output_timestamp_helper_->GetDuration(decoded_audio_size)); | 553 output_timestamp_helper_->GetDuration(decoded_audio_size)); |
557 output_timestamp_helper_->AddBytes(decoded_audio_size); | 554 output_timestamp_helper_->AddBytes(decoded_audio_size); |
558 } | 555 } |
559 | 556 |
560 // Decoding finished successfully, update statistics. | 557 // Decoding finished successfully, update statistics. |
561 PipelineStatistics statistics; | 558 PipelineStatistics statistics; |
562 statistics.audio_bytes_decoded = decoded_audio_size; | 559 statistics.audio_bytes_decoded = decoded_audio_size; |
563 statistics_cb_.Run(statistics); | 560 statistics_cb_.Run(statistics); |
564 | 561 |
565 return true; | 562 return true; |
566 } | 563 } |
567 | 564 |
568 } // namespace media | 565 } // namespace media |
OLD | NEW |