Chromium Code Reviews| 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/single_thread_task_runner.h" | 9 #include "base/single_thread_task_runner.h" |
| 10 #include "base/sys_byteorder.h" | 10 #include "base/sys_byteorder.h" |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 if (extra_data->num_streams + extra_data->num_coupled != extra_data->channels) | 238 if (extra_data->num_streams + extra_data->num_coupled != extra_data->channels) |
| 239 DVLOG(1) << "Inconsistent channel mapping."; | 239 DVLOG(1) << "Inconsistent channel mapping."; |
| 240 | 240 |
| 241 for (int i = 0; i < extra_data->channels; ++i) | 241 for (int i = 0; i < extra_data->channels; ++i) |
| 242 extra_data->stream_map[i] = *(data + kOpusExtraDataStreamMapOffset + i); | 242 extra_data->stream_map[i] = *(data + kOpusExtraDataStreamMapOffset + i); |
| 243 return true; | 243 return true; |
| 244 } | 244 } |
| 245 | 245 |
| 246 OpusAudioDecoder::OpusAudioDecoder( | 246 OpusAudioDecoder::OpusAudioDecoder( |
| 247 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 247 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
| 248 : task_runner_(task_runner), | 248 : task_runner_(task_runner), opus_decoder_(nullptr) {} |
| 249 opus_decoder_(NULL), | |
| 250 start_input_timestamp_(kNoTimestamp()) {} | |
| 251 | 249 |
| 252 std::string OpusAudioDecoder::GetDisplayName() const { | 250 std::string OpusAudioDecoder::GetDisplayName() const { |
| 253 return "OpusAudioDecoder"; | 251 return "OpusAudioDecoder"; |
| 254 } | 252 } |
| 255 | 253 |
| 256 void OpusAudioDecoder::Initialize(const AudioDecoderConfig& config, | 254 void OpusAudioDecoder::Initialize(const AudioDecoderConfig& config, |
| 257 const InitCB& init_cb, | 255 const InitCB& init_cb, |
| 258 const OutputCB& output_cb) { | 256 const OutputCB& output_cb) { |
| 259 DCHECK(task_runner_->BelongsToCurrentThread()); | 257 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 260 InitCB bound_init_cb = BindToCurrentLoop(init_cb); | 258 InitCB bound_init_cb = BindToCurrentLoop(init_cb); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 286 task_runner_->PostTask(FROM_HERE, closure); | 284 task_runner_->PostTask(FROM_HERE, closure); |
| 287 } | 285 } |
| 288 | 286 |
| 289 OpusAudioDecoder::~OpusAudioDecoder() { | 287 OpusAudioDecoder::~OpusAudioDecoder() { |
| 290 DCHECK(task_runner_->BelongsToCurrentThread()); | 288 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 291 | 289 |
| 292 if (!opus_decoder_) | 290 if (!opus_decoder_) |
| 293 return; | 291 return; |
| 294 | 292 |
| 295 opus_multistream_decoder_ctl(opus_decoder_, OPUS_RESET_STATE); | 293 opus_multistream_decoder_ctl(opus_decoder_, OPUS_RESET_STATE); |
| 296 ResetTimestampState(); | |
| 297 CloseDecoder(); | 294 CloseDecoder(); |
| 298 } | 295 } |
| 299 | 296 |
| 300 void OpusAudioDecoder::DecodeBuffer( | 297 void OpusAudioDecoder::DecodeBuffer( |
| 301 const scoped_refptr<DecoderBuffer>& input, | 298 const scoped_refptr<DecoderBuffer>& input, |
| 302 const DecodeCB& decode_cb) { | 299 const DecodeCB& decode_cb) { |
| 303 DCHECK(task_runner_->BelongsToCurrentThread()); | 300 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 304 DCHECK(!decode_cb.is_null()); | 301 DCHECK(!decode_cb.is_null()); |
| 305 DCHECK(input.get()); | 302 DCHECK(input.get()); |
| 306 | 303 |
| 307 // Libopus does not buffer output. Decoding is complete when an end of stream | 304 // Libopus does not buffer output. Decoding is complete when an end of stream |
| 308 // input buffer is received. | 305 // input buffer is received. |
| 309 if (input->end_of_stream()) { | 306 if (input->end_of_stream()) { |
| 310 decode_cb.Run(kOk); | 307 decode_cb.Run(kOk); |
| 311 return; | 308 return; |
| 312 } | 309 } |
| 313 | 310 |
| 314 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 311 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
| 315 // occurs with some damaged files. | 312 // occurs with some damaged files. |
| 316 if (input->timestamp() == kNoTimestamp()) { | 313 if (input->timestamp() == kNoTimestamp()) { |
| 317 DLOG(ERROR) << "Received a buffer without timestamps!"; | 314 DLOG(ERROR) << "Received a buffer without timestamps!"; |
| 318 decode_cb.Run(kDecodeError); | 315 decode_cb.Run(kDecodeError); |
| 319 return; | 316 return; |
| 320 } | 317 } |
| 321 | 318 |
| 322 // Apply the necessary codec delay. | |
| 323 if (start_input_timestamp_ == kNoTimestamp()) | |
|
chcunningham
2015/07/31 19:48:44
Am I right that what you removed here is equivalen
DaleCurtis
2015/08/03 22:49:53
Kind of, in the first playback case the behavior i
| |
| 324 start_input_timestamp_ = input->timestamp(); | |
| 325 if (!discard_helper_->initialized() && | |
| 326 input->timestamp() == start_input_timestamp_) { | |
| 327 discard_helper_->Reset(config_.codec_delay()); | |
| 328 } | |
| 329 | |
| 330 scoped_refptr<AudioBuffer> output_buffer; | 319 scoped_refptr<AudioBuffer> output_buffer; |
| 331 | 320 |
| 332 if (!Decode(input, &output_buffer)) { | 321 if (!Decode(input, &output_buffer)) { |
| 333 decode_cb.Run(kDecodeError); | 322 decode_cb.Run(kDecodeError); |
| 334 return; | 323 return; |
| 335 } | 324 } |
| 336 | 325 |
| 337 if (output_buffer.get()) { | 326 if (output_buffer.get()) { |
| 338 output_cb_.Run(output_buffer); | 327 output_cb_.Run(output_buffer); |
| 339 } | 328 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 } | 402 } |
| 414 | 403 |
| 415 status = opus_multistream_decoder_ctl( | 404 status = opus_multistream_decoder_ctl( |
| 416 opus_decoder_, OPUS_SET_GAIN(opus_extra_data.gain_db)); | 405 opus_decoder_, OPUS_SET_GAIN(opus_extra_data.gain_db)); |
| 417 if (status != OPUS_OK) { | 406 if (status != OPUS_OK) { |
| 418 DLOG(ERROR) << "Failed to set OPUS header gain; status=" | 407 DLOG(ERROR) << "Failed to set OPUS header gain; status=" |
| 419 << opus_strerror(status); | 408 << opus_strerror(status); |
| 420 return false; | 409 return false; |
| 421 } | 410 } |
| 422 | 411 |
| 423 discard_helper_.reset( | 412 ResetTimestampState(); |
| 424 new AudioDiscardHelper(config_.samples_per_second(), 0)); | |
| 425 start_input_timestamp_ = kNoTimestamp(); | |
| 426 return true; | 413 return true; |
| 427 } | 414 } |
| 428 | 415 |
| 429 void OpusAudioDecoder::CloseDecoder() { | 416 void OpusAudioDecoder::CloseDecoder() { |
| 430 if (opus_decoder_) { | 417 if (opus_decoder_) { |
| 431 opus_multistream_decoder_destroy(opus_decoder_); | 418 opus_multistream_decoder_destroy(opus_decoder_); |
| 432 opus_decoder_ = NULL; | 419 opus_decoder_ = nullptr; |
| 433 } | 420 } |
| 434 } | 421 } |
| 435 | 422 |
| 436 void OpusAudioDecoder::ResetTimestampState() { | 423 void OpusAudioDecoder::ResetTimestampState() { |
| 437 discard_helper_->Reset( | 424 discard_helper_.reset( |
| 438 discard_helper_->TimeDeltaToFrames(config_.seek_preroll())); | 425 new AudioDiscardHelper(config_.samples_per_second(), 0)); |
| 426 discard_helper_->Reset(config_.codec_delay()); | |
| 439 } | 427 } |
| 440 | 428 |
| 441 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, | 429 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, |
| 442 scoped_refptr<AudioBuffer>* output_buffer) { | 430 scoped_refptr<AudioBuffer>* output_buffer) { |
| 443 // Allocate a buffer for the output samples. | 431 // Allocate a buffer for the output samples. |
| 444 *output_buffer = AudioBuffer::CreateBuffer( | 432 *output_buffer = AudioBuffer::CreateBuffer( |
| 445 config_.sample_format(), | 433 config_.sample_format(), |
| 446 config_.channel_layout(), | 434 config_.channel_layout(), |
| 447 ChannelLayoutToChannelCount(config_.channel_layout()), | 435 ChannelLayoutToChannelCount(config_.channel_layout()), |
| 448 config_.samples_per_second(), | 436 config_.samples_per_second(), |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 472 } | 460 } |
| 473 | 461 |
| 474 // Trim off any extraneous allocation. | 462 // Trim off any extraneous allocation. |
| 475 DCHECK_LE(frames_decoded, output_buffer->get()->frame_count()); | 463 DCHECK_LE(frames_decoded, output_buffer->get()->frame_count()); |
| 476 const int trim_frames = output_buffer->get()->frame_count() - frames_decoded; | 464 const int trim_frames = output_buffer->get()->frame_count() - frames_decoded; |
| 477 if (trim_frames > 0) | 465 if (trim_frames > 0) |
| 478 output_buffer->get()->TrimEnd(trim_frames); | 466 output_buffer->get()->TrimEnd(trim_frames); |
| 479 | 467 |
| 480 // Handles discards and timestamping. Discard the buffer if more data needed. | 468 // Handles discards and timestamping. Discard the buffer if more data needed. |
| 481 if (!discard_helper_->ProcessBuffers(input, *output_buffer)) | 469 if (!discard_helper_->ProcessBuffers(input, *output_buffer)) |
| 482 *output_buffer = NULL; | 470 *output_buffer = nullptr; |
| 483 | 471 |
| 484 return true; | 472 return true; |
| 485 } | 473 } |
| 486 | 474 |
| 487 } // namespace media | 475 } // namespace media |
| OLD | NEW |