OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/filters/opus_audio_decoder.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" |
| 9 #include "base/location.h" |
| 10 #include "base/message_loop_proxy.h" |
| 11 #include "base/sys_byteorder.h" |
| 12 #include "media/base/audio_decoder_config.h" |
| 13 #include "media/base/audio_timestamp_helper.h" |
| 14 #include "media/base/data_buffer.h" |
| 15 #include "media/base/decoder_buffer.h" |
| 16 #include "media/base/demuxer.h" |
| 17 #include "media/base/pipeline.h" |
| 18 #include "third_party/opus/src/include/opus.h" |
| 19 #include "third_party/opus/src/include/opus_multistream.h" |
| 20 |
| 21 namespace media { |
| 22 |
| 23 static uint16 ReadLE16(const uint8* data, size_t data_size, int read_offset) { |
| 24 DCHECK(data); |
| 25 uint16 value = 0; |
| 26 DCHECK_LE(read_offset + sizeof(value), data_size); |
| 27 memcpy(&value, data + read_offset, sizeof(value)); |
| 28 return base::ByteSwapToLE16(value); |
| 29 } |
| 30 |
| 31 // Returns true if the decode result was end of stream. |
| 32 static inline bool IsEndOfStream(int decoded_size, Buffer* input) { |
| 33 // Two conditions to meet to declare end of stream for this decoder: |
| 34 // 1. Opus didn't output anything. |
| 35 // 2. An end of stream buffer is received. |
| 36 return decoded_size == 0 && input->IsEndOfStream(); |
| 37 } |
| 38 |
| 39 // The Opus specification is part of IETF RFC 6716: |
| 40 // http://tools.ietf.org/html/rfc6716 |
| 41 |
| 42 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies |
| 43 // mappings for up to 8 channels. See section 4.3.9 of the vorbis |
| 44 // specification: |
| 45 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html |
| 46 static const int kMaxVorbisChannels = 8; |
| 47 |
| 48 // Opus allows for decode of S16 or float samples. OpusAudioDecoder always uses |
| 49 // S16 samples. |
| 50 static const int kBitsPerChannel = 16; |
| 51 static const int kBytesPerChannel = kBitsPerChannel / 8; |
| 52 |
| 53 // Maximum packet size used in Xiph's opusdec and FFmpeg's libopusdec. |
| 54 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6; |
| 55 static const int kMaxOpusOutputPacketSizeBytes = |
| 56 kMaxOpusOutputPacketSizeSamples * kBytesPerChannel; |
| 57 |
| 58 static void RemapOpusChannelLayout(const uint8* opus_mapping, |
| 59 int num_channels, |
| 60 uint8* channel_layout) { |
| 61 DCHECK_LE(num_channels, kMaxVorbisChannels); |
| 62 |
| 63 // Opus uses Vorbis channel layout. |
| 64 const int32 num_layouts = kMaxVorbisChannels; |
| 65 const int32 num_layout_values = kMaxVorbisChannels; |
| 66 const uint8 kVorbisChannelLayouts[num_layouts][num_layout_values] = { |
| 67 { 0 }, |
| 68 { 0, 1 }, |
| 69 { 0, 2, 1 }, |
| 70 { 0, 1, 2, 3 }, |
| 71 { 0, 2, 1, 3, 4 }, |
| 72 { 0, 2, 1, 5, 3, 4 }, |
| 73 { 0, 2, 1, 6, 5, 3, 4 }, |
| 74 { 0, 2, 1, 7, 5, 6, 3, 4 }, |
| 75 }; |
| 76 |
| 77 // Reorder the channels to produce the same ordering as FFmpeg, which is |
| 78 // what the pipeline expects. |
| 79 const uint8* vorbis_layout_offset = kVorbisChannelLayouts[num_channels - 1]; |
| 80 for (int channel = 0; channel < num_channels; ++channel) |
| 81 channel_layout[channel] = opus_mapping[vorbis_layout_offset[channel]]; |
| 82 } |
| 83 |
| 84 // Opus Header contents: |
| 85 // - "OpusHead" (64 bits) |
| 86 // - version number (8 bits) |
| 87 // - Channels C (8 bits) |
| 88 // - Pre-skip (16 bits) |
| 89 // - Sampling rate (32 bits) |
| 90 // - Gain in dB (16 bits, S7.8) |
| 91 // - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping, |
| 92 // 2..254: reserved, 255: multistream with no mapping) |
| 93 // |
| 94 // - if (mapping != 0) |
| 95 // - N = totel number of streams (8 bits) |
| 96 // - M = number of paired streams (8 bits) |
| 97 // - C times channel origin |
| 98 // - if (C<2*M) |
| 99 // - stream = byte/2 |
| 100 // - if (byte&0x1 == 0) |
| 101 // - left |
| 102 // else |
| 103 // - right |
| 104 // - else |
| 105 // - stream = byte-M |
| 106 |
| 107 // Default audio output channel layout. Used to initialize |stream_map| in |
| 108 // OpusHeader, and passed to opus_multistream_decoder_create() when the header |
| 109 // does not contain mapping information. The values are valid only for mono and |
| 110 // stereo output: Opus streams with more than 2 channels require a stream map. |
| 111 static const int kMaxChannelsWithDefaultLayout = 2; |
| 112 static const uint8 kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { |
| 113 0, 1 }; |
| 114 |
| 115 // Size of the Opus header excluding optional mapping information. |
| 116 static const int kOpusHeaderSize = 19; |
| 117 |
| 118 // Offset to the channel count byte in the Opus header. |
| 119 static const int kOpusHeaderChannelsOffset = 9; |
| 120 |
| 121 // Offset to the pre-skip value in the Opus header. |
| 122 static const int kOpusHeaderSkipSamplesOffset = 10; |
| 123 |
| 124 // Offset to the channel mapping byte in the Opus header. |
| 125 static const int kOpusHeaderChannelMappingOffset = 18; |
| 126 |
| 127 // Header contains a stream map. The mapping values are in extra data beyond |
| 128 // the always present |kOpusHeaderSize| bytes of data. The mapping data |
| 129 // contains stream count, coupling information, and per channel mapping values: |
| 130 // - Byte 0: Number of streams. |
| 131 // - Byte 1: Number coupled. |
| 132 // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping values. |
| 133 static const int kOpusHeaderNumStreamsOffset = kOpusHeaderSize; |
| 134 static const int kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; |
| 135 static const int kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; |
| 136 |
| 137 struct OpusHeader { |
| 138 OpusHeader() |
| 139 : channels(0), |
| 140 skip_samples(0), |
| 141 channel_mapping(0), |
| 142 num_streams(0), |
| 143 num_coupled(0) { |
| 144 memcpy(stream_map, |
| 145 kDefaultOpusChannelLayout, |
| 146 kMaxChannelsWithDefaultLayout); |
| 147 } |
| 148 int channels; |
| 149 int skip_samples; |
| 150 int channel_mapping; |
| 151 int num_streams; |
| 152 int num_coupled; |
| 153 uint8 stream_map[kMaxVorbisChannels]; |
| 154 }; |
| 155 |
| 156 // Returns true when able to successfully parse and store Opus header data in |
| 157 // data parsed in |header|. Based on opus header parsing code in libopusdec |
| 158 // from FFmpeg, and opus_header from Xiph's opus-tools project. |
| 159 static void ParseOpusHeader(const uint8* data, int data_size, |
| 160 const AudioDecoderConfig& config, |
| 161 OpusHeader* header) { |
| 162 CHECK_GE(data_size, kOpusHeaderSize); |
| 163 |
| 164 header->channels = *(data + kOpusHeaderChannelsOffset); |
| 165 |
| 166 CHECK(header->channels > 0 && header->channels <= kMaxVorbisChannels) |
| 167 << "invalid channel count in header: " << header->channels; |
| 168 |
| 169 header->skip_samples = |
| 170 ReadLE16(data, data_size, kOpusHeaderSkipSamplesOffset); |
| 171 |
| 172 header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset); |
| 173 |
| 174 if (!header->channel_mapping) { |
| 175 CHECK_LE(header->channels, kMaxChannelsWithDefaultLayout) |
| 176 << "Invalid header, missing stream map."; |
| 177 |
| 178 header->num_streams = 1; |
| 179 header->num_coupled = |
| 180 (ChannelLayoutToChannelCount(config.channel_layout()) > 1) ? 1 : 0; |
| 181 return; |
| 182 } |
| 183 |
| 184 CHECK_GE(data_size, kOpusHeaderStreamMapOffset + header->channels) |
| 185 << "Invalid stream map."; |
| 186 |
| 187 header->num_streams = *(data + kOpusHeaderNumStreamsOffset); |
| 188 header->num_coupled = *(data + kOpusHeaderNumCoupledOffset); |
| 189 |
| 190 if (header->num_streams + header->num_coupled != header->channels) |
| 191 LOG(WARNING) << "Inconsistent channel mapping."; |
| 192 |
| 193 for (int i = 0; i < kMaxVorbisChannels; ++i) |
| 194 header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i); |
| 195 } |
| 196 |
| 197 OpusAudioDecoder::OpusAudioDecoder( |
| 198 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
| 199 : message_loop_(message_loop), |
| 200 opus_decoder_(NULL), |
| 201 bits_per_channel_(0), |
| 202 channel_layout_(CHANNEL_LAYOUT_NONE), |
| 203 samples_per_second_(0), |
| 204 last_input_timestamp_(kNoTimestamp()), |
| 205 output_bytes_to_drop_(0), |
| 206 skip_samples_(0) { |
| 207 } |
| 208 |
| 209 void OpusAudioDecoder::Initialize( |
| 210 const scoped_refptr<DemuxerStream>& stream, |
| 211 const PipelineStatusCB& status_cb, |
| 212 const StatisticsCB& statistics_cb) { |
| 213 if (!message_loop_->BelongsToCurrentThread()) { |
| 214 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 215 &OpusAudioDecoder::DoInitialize, this, |
| 216 stream, status_cb, statistics_cb)); |
| 217 return; |
| 218 } |
| 219 DoInitialize(stream, status_cb, statistics_cb); |
| 220 } |
| 221 |
| 222 void OpusAudioDecoder::Read(const ReadCB& read_cb) { |
| 223 // Complete operation asynchronously on different stack of execution as per |
| 224 // the API contract of AudioDecoder::Read() |
| 225 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 226 &OpusAudioDecoder::DoRead, this, read_cb)); |
| 227 } |
| 228 |
| 229 int OpusAudioDecoder::bits_per_channel() { |
| 230 return bits_per_channel_; |
| 231 } |
| 232 |
| 233 ChannelLayout OpusAudioDecoder::channel_layout() { |
| 234 return channel_layout_; |
| 235 } |
| 236 |
| 237 int OpusAudioDecoder::samples_per_second() { |
| 238 return samples_per_second_; |
| 239 } |
| 240 |
| 241 void OpusAudioDecoder::Reset(const base::Closure& closure) { |
| 242 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 243 &OpusAudioDecoder::DoReset, this, closure)); |
| 244 } |
| 245 |
| 246 OpusAudioDecoder::~OpusAudioDecoder() { |
| 247 // TODO(scherkus): should we require Stop() to be called? this might end up |
| 248 // getting called on a random thread due to refcounting. |
| 249 CloseDecoder(); |
| 250 } |
| 251 |
| 252 void OpusAudioDecoder::DoInitialize( |
| 253 const scoped_refptr<DemuxerStream>& stream, |
| 254 const PipelineStatusCB& status_cb, |
| 255 const StatisticsCB& statistics_cb) { |
| 256 if (demuxer_stream_) { |
| 257 // TODO(scherkus): initialization currently happens more than once in |
| 258 // PipelineIntegrationTest.BasicPlayback. |
| 259 LOG(ERROR) << "Initialize has already been called."; |
| 260 CHECK(false); |
| 261 } |
| 262 |
| 263 demuxer_stream_ = stream; |
| 264 |
| 265 if (!ConfigureDecoder()) { |
| 266 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
| 267 return; |
| 268 } |
| 269 |
| 270 statistics_cb_ = statistics_cb; |
| 271 status_cb.Run(PIPELINE_OK); |
| 272 } |
| 273 |
| 274 void OpusAudioDecoder::DoReset(const base::Closure& closure) { |
| 275 opus_multistream_decoder_ctl(opus_decoder_, OPUS_RESET_STATE); |
| 276 ResetTimestampState(); |
| 277 closure.Run(); |
| 278 } |
| 279 |
| 280 void OpusAudioDecoder::DoRead(const ReadCB& read_cb) { |
| 281 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 282 DCHECK(!read_cb.is_null()); |
| 283 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| 284 |
| 285 read_cb_ = read_cb; |
| 286 ReadFromDemuxerStream(); |
| 287 } |
| 288 |
| 289 void OpusAudioDecoder::DoDecodeBuffer( |
| 290 DemuxerStream::Status status, |
| 291 const scoped_refptr<DecoderBuffer>& input) { |
| 292 if (!message_loop_->BelongsToCurrentThread()) { |
| 293 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 294 &OpusAudioDecoder::DoDecodeBuffer, this, status, input)); |
| 295 return; |
| 296 } |
| 297 |
| 298 DCHECK(!read_cb_.is_null()); |
| 299 DCHECK_EQ(status != DemuxerStream::kOk, !input) << status; |
| 300 |
| 301 if (status == DemuxerStream::kAborted) { |
| 302 DCHECK(!input); |
| 303 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); |
| 304 return; |
| 305 } |
| 306 |
| 307 if (status == DemuxerStream::kConfigChanged) { |
| 308 DCHECK(!input); |
| 309 |
| 310 scoped_refptr<DataBuffer> output_buffer; |
| 311 |
| 312 // Send a "end of stream" buffer to the decode loop |
| 313 // to output any remaining data still in the decoder. |
| 314 if (!Decode(DecoderBuffer::CreateEOSBuffer(), true, &output_buffer)) { |
| 315 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
| 316 return; |
| 317 } |
| 318 |
| 319 DVLOG(1) << "Config changed."; |
| 320 |
| 321 if (!ConfigureDecoder()) { |
| 322 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
| 323 return; |
| 324 } |
| 325 |
| 326 ResetTimestampState(); |
| 327 |
| 328 if (output_buffer) { |
| 329 // Execute callback to return the decoded audio. |
| 330 base::ResetAndReturn(&read_cb_).Run(kOk, output_buffer); |
| 331 } else { |
| 332 // We exhausted the input data, but it wasn't enough for a frame. Ask for |
| 333 // more data in order to fulfill this read. |
| 334 ReadFromDemuxerStream(); |
| 335 } |
| 336 |
| 337 return; |
| 338 } |
| 339 |
| 340 DCHECK_EQ(status, DemuxerStream::kOk); |
| 341 DCHECK(input); |
| 342 |
| 343 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
| 344 // occurs with some damaged files. |
| 345 if (!input->IsEndOfStream() && input->GetTimestamp() == kNoTimestamp() && |
| 346 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { |
| 347 DVLOG(1) << "Received a buffer without timestamps!"; |
| 348 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
| 349 return; |
| 350 } |
| 351 |
| 352 if (!input->IsEndOfStream()) { |
| 353 if (last_input_timestamp_ != kNoTimestamp() && |
| 354 input->GetTimestamp() != kNoTimestamp() && |
| 355 input->GetTimestamp() < last_input_timestamp_) { |
| 356 base::TimeDelta diff = input->GetTimestamp() - last_input_timestamp_; |
| 357 DVLOG(1) << "Input timestamps are not monotonically increasing! " |
| 358 << " ts " << input->GetTimestamp().InMicroseconds() << " us" |
| 359 << " diff " << diff.InMicroseconds() << " us"; |
| 360 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
| 361 } |
| 362 |
| 363 last_input_timestamp_ = input->GetTimestamp(); |
| 364 } |
| 365 |
| 366 scoped_refptr<DataBuffer> output_buffer; |
| 367 |
| 368 if (!Decode(input, false, &output_buffer)) { |
| 369 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
| 370 return; |
| 371 } |
| 372 |
| 373 if (output_buffer) { |
| 374 // Execute callback to return the decoded audio. |
| 375 base::ResetAndReturn(&read_cb_).Run(kOk, output_buffer); |
| 376 } else { |
| 377 // We exhausted the input data, but it wasn't enough for a frame. Ask for |
| 378 // more data in order to fulfill this read. |
| 379 ReadFromDemuxerStream(); |
| 380 } |
| 381 } |
| 382 |
| 383 void OpusAudioDecoder::ReadFromDemuxerStream() { |
| 384 DCHECK(!read_cb_.is_null()); |
| 385 |
| 386 demuxer_stream_->Read(base::Bind(&OpusAudioDecoder::DoDecodeBuffer, this)); |
| 387 } |
| 388 |
| 389 bool OpusAudioDecoder::ConfigureDecoder() { |
| 390 const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config(); |
| 391 |
| 392 if (config.codec() != kCodecOpus) { |
| 393 DLOG(ERROR) << "ConfigureDecoder(): codec must be kCodecOpus."; |
| 394 return false; |
| 395 } |
| 396 |
| 397 const int channel_count = |
| 398 ChannelLayoutToChannelCount(config.channel_layout()); |
| 399 if (!config.IsValidConfig() || channel_count > kMaxVorbisChannels) { |
| 400 DLOG(ERROR) << "ConfigureDecoder(): Invalid or unsupported audio stream -" |
| 401 << " codec: " << config.codec() |
| 402 << " channel count: " << channel_count |
| 403 << " channel layout: " << config.channel_layout() |
| 404 << " bits per channel: " << config.bits_per_channel() |
| 405 << " samples per second: " << config.samples_per_second(); |
| 406 return false; |
| 407 } |
| 408 |
| 409 if (config.bits_per_channel() != kBitsPerChannel) { |
| 410 DLOG(ERROR) << "ConfigureDecoder(): 16 bit samples required."; |
| 411 return false; |
| 412 } |
| 413 |
| 414 if (config.is_encrypted()) { |
| 415 DLOG(ERROR) << "ConfigureDecoder(): Encrypted audio stream not supported."; |
| 416 return false; |
| 417 } |
| 418 |
| 419 if (opus_decoder_ && |
| 420 (bits_per_channel_ != config.bits_per_channel() || |
| 421 channel_layout_ != config.channel_layout() || |
| 422 samples_per_second_ != config.samples_per_second())) { |
| 423 DVLOG(1) << "Unsupported config change :"; |
| 424 DVLOG(1) << "\tbits_per_channel : " << bits_per_channel_ |
| 425 << " -> " << config.bits_per_channel(); |
| 426 DVLOG(1) << "\tchannel_layout : " << channel_layout_ |
| 427 << " -> " << config.channel_layout(); |
| 428 DVLOG(1) << "\tsample_rate : " << samples_per_second_ |
| 429 << " -> " << config.samples_per_second(); |
| 430 return false; |
| 431 } |
| 432 |
| 433 // Clean up existing decoder if necessary. |
| 434 CloseDecoder(); |
| 435 |
| 436 // Allocate the output buffer if necessary. |
| 437 if (!output_buffer_) |
| 438 output_buffer_.reset(new int16[kMaxOpusOutputPacketSizeSamples]); |
| 439 |
| 440 // Parse the Opus header. |
| 441 OpusHeader opus_header; |
| 442 ParseOpusHeader(config.extra_data(), config.extra_data_size(), |
| 443 config, |
| 444 &opus_header); |
| 445 |
| 446 skip_samples_ = opus_header.skip_samples; |
| 447 |
| 448 if (skip_samples_ > 0) |
| 449 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); |
| 450 |
| 451 uint8 channel_mapping[kMaxVorbisChannels]; |
| 452 memcpy(&channel_mapping, |
| 453 kDefaultOpusChannelLayout, |
| 454 kMaxChannelsWithDefaultLayout); |
| 455 |
| 456 if (channel_count > kMaxChannelsWithDefaultLayout) { |
| 457 RemapOpusChannelLayout(opus_header.stream_map, |
| 458 channel_count, |
| 459 channel_mapping); |
| 460 } |
| 461 |
| 462 // Init Opus. |
| 463 int status = OPUS_INVALID_STATE; |
| 464 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(), |
| 465 channel_count, |
| 466 opus_header.num_streams, |
| 467 opus_header.num_coupled, |
| 468 channel_mapping, |
| 469 &status); |
| 470 if (!opus_decoder_ || status != OPUS_OK) { |
| 471 LOG(ERROR) << "ConfigureDecoder(): opus_multistream_decoder_create failed" |
| 472 << " status=" << opus_strerror(status); |
| 473 return false; |
| 474 } |
| 475 |
| 476 // TODO(tomfinegan): Handle audio delay once the matroska spec is updated |
| 477 // to represent the value. |
| 478 |
| 479 bits_per_channel_ = config.bits_per_channel(); |
| 480 channel_layout_ = config.channel_layout(); |
| 481 samples_per_second_ = config.samples_per_second(); |
| 482 output_timestamp_helper_.reset(new AudioTimestampHelper( |
| 483 config.bytes_per_frame(), config.samples_per_second())); |
| 484 return true; |
| 485 } |
| 486 |
| 487 void OpusAudioDecoder::CloseDecoder() { |
| 488 if (opus_decoder_) { |
| 489 opus_multistream_decoder_destroy(opus_decoder_); |
| 490 opus_decoder_ = NULL; |
| 491 } |
| 492 } |
| 493 |
| 494 void OpusAudioDecoder::ResetTimestampState() { |
| 495 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
| 496 last_input_timestamp_ = kNoTimestamp(); |
| 497 output_bytes_to_drop_ = 0; |
| 498 } |
| 499 |
| 500 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, |
| 501 bool skip_eos_append, |
| 502 scoped_refptr<DataBuffer>* output_buffer) { |
| 503 int samples_decoded = |
| 504 opus_multistream_decode(opus_decoder_, |
| 505 input->GetData(), input->GetDataSize(), |
| 506 &output_buffer_[0], |
| 507 kMaxOpusOutputPacketSizeSamples, |
| 508 0); |
| 509 if (samples_decoded < 0) { |
| 510 DCHECK(!input->IsEndOfStream()) |
| 511 << "Decode(): End of stream buffer produced an error!"; |
| 512 |
| 513 LOG(ERROR) << "ConfigureDecoder(): opus_multistream_decode failed for" |
| 514 << " timestamp: " << input->GetTimestamp().InMicroseconds() |
| 515 << " us, duration: " << input->GetDuration().InMicroseconds() |
| 516 << " us, packet size: " << input->GetDataSize() << " bytes with" |
| 517 << " status: " << opus_strerror(samples_decoded); |
| 518 return false; |
| 519 } |
| 520 |
| 521 uint8* decoded_audio_data = reinterpret_cast<uint8*>(&output_buffer_[0]); |
| 522 int decoded_audio_size = samples_decoded * |
| 523 demuxer_stream_->audio_decoder_config().bytes_per_frame(); |
| 524 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes); |
| 525 |
| 526 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
| 527 !input->IsEndOfStream()) { |
| 528 DCHECK(input->GetTimestamp() != kNoTimestamp()); |
| 529 output_timestamp_helper_->SetBaseTimestamp(input->GetTimestamp()); |
| 530 } |
| 531 |
| 532 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { |
| 533 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); |
| 534 DCHECK_EQ(dropped_size % kBytesPerChannel, 0); |
| 535 decoded_audio_data += dropped_size; |
| 536 decoded_audio_size -= dropped_size; |
| 537 output_bytes_to_drop_ -= dropped_size; |
| 538 } |
| 539 |
| 540 if (decoded_audio_size > 0) { |
| 541 // Copy the audio samples into an output buffer. |
| 542 *output_buffer = new DataBuffer(decoded_audio_data, decoded_audio_size); |
| 543 (*output_buffer)->SetTimestamp(output_timestamp_helper_->GetTimestamp()); |
| 544 (*output_buffer)->SetDuration( |
| 545 output_timestamp_helper_->GetDuration(decoded_audio_size)); |
| 546 output_timestamp_helper_->AddBytes(decoded_audio_size); |
| 547 } else if (IsEndOfStream(decoded_audio_size, input) && !skip_eos_append) { |
| 548 DCHECK_EQ(input->GetDataSize(), 0); |
| 549 // Create an end of stream output buffer. |
| 550 *output_buffer = new DataBuffer(0); |
| 551 } |
| 552 |
| 553 // Decoding finished successfully, update statistics. |
| 554 PipelineStatistics statistics; |
| 555 statistics.audio_bytes_decoded = decoded_audio_size; |
| 556 statistics_cb_.Run(statistics); |
| 557 |
| 558 return true; |
| 559 } |
| 560 |
| 561 } // namespace media |
OLD | NEW |