Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/decoder_stream.h" | 5 #include "media/filters/decoder_stream.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/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 13 #include "media/base/audio_decoder.h" | |
| 13 #include "media/base/bind_to_current_loop.h" | 14 #include "media/base/bind_to_current_loop.h" |
| 14 #include "media/base/decoder_buffer.h" | 15 #include "media/base/decoder_buffer.h" |
| 15 #include "media/base/demuxer_stream.h" | 16 #include "media/base/demuxer_stream.h" |
| 16 #include "media/base/video_decoder.h" | 17 #include "media/base/video_decoder.h" |
| 17 #include "media/filters/decrypting_demuxer_stream.h" | 18 #include "media/filters/decrypting_demuxer_stream.h" |
| 18 | 19 |
| 19 namespace media { | 20 namespace media { |
| 20 | 21 |
| 21 // TODO(rileya) Devise a better way of specifying trace/UMA/etc strings for | 22 // TODO(rileya) Devise a better way of specifying trace/UMA/etc strings for |
| 22 // templated classes such as this. | 23 // templated classes such as this. |
| 23 template <DemuxerStream::Type StreamType> | 24 template <DemuxerStream::Type StreamType> |
| 24 static const char* GetTraceString(); | 25 static const char* GetTraceString(); |
| 25 | 26 |
| 26 template <> | 27 template <> |
| 27 const char* GetTraceString<DemuxerStream::VIDEO>() { | 28 const char* GetTraceString<DemuxerStream::VIDEO>() { |
| 28 return "DecoderStream<VIDEO>::Decode"; | 29 return "DecoderStream<VIDEO>::Decode"; |
| 29 } | 30 } |
| 30 | 31 |
| 32 template <> | |
| 33 const char* GetTraceString<DemuxerStream::AUDIO>() { | |
| 34 return "DecoderStream<AUDIO>::Decode"; | |
| 35 } | |
| 36 | |
| 31 template <DemuxerStream::Type StreamType> | 37 template <DemuxerStream::Type StreamType> |
| 32 DecoderStream<StreamType>::DecoderStream( | 38 DecoderStream<StreamType>::DecoderStream( |
| 33 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 39 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 34 ScopedVector<Decoder> decoders, | 40 ScopedVector<Decoder> decoders, |
| 35 const SetDecryptorReadyCB& set_decryptor_ready_cb) | 41 const SetDecryptorReadyCB& set_decryptor_ready_cb) |
| 36 : task_runner_(task_runner), | 42 : task_runner_(task_runner), |
| 37 weak_factory_(this), | 43 weak_factory_(this), |
| 38 state_(STATE_UNINITIALIZED), | 44 state_(STATE_UNINITIALIZED), |
| 39 stream_(NULL), | 45 stream_(NULL), |
| 40 decoder_selector_( | 46 decoder_selector_( |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 58 DCHECK(!init_cb.is_null()); | 64 DCHECK(!init_cb.is_null()); |
| 59 | 65 |
| 60 statistics_cb_ = statistics_cb; | 66 statistics_cb_ = statistics_cb; |
| 61 init_cb_ = init_cb; | 67 init_cb_ = init_cb; |
| 62 stream_ = stream; | 68 stream_ = stream; |
| 63 | 69 |
| 64 state_ = STATE_INITIALIZING; | 70 state_ = STATE_INITIALIZING; |
| 65 // TODO(xhwang): DecoderSelector only needs a config to select a decoder. | 71 // TODO(xhwang): DecoderSelector only needs a config to select a decoder. |
| 66 decoder_selector_->SelectDecoder( | 72 decoder_selector_->SelectDecoder( |
| 67 stream, | 73 stream, |
| 68 StatisticsCB(), | |
| 69 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, | 74 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, |
| 70 weak_factory_.GetWeakPtr())); | 75 weak_factory_.GetWeakPtr())); |
| 71 } | 76 } |
| 72 | 77 |
| 73 template <DemuxerStream::Type StreamType> | 78 template <DemuxerStream::Type StreamType> |
| 74 void DecoderStream<StreamType>::Read(const ReadCB& read_cb) { | 79 void DecoderStream<StreamType>::Read(const ReadCB& read_cb) { |
| 75 DVLOG(2) << __FUNCTION__; | 80 DVLOG(2) << __FUNCTION__; |
| 76 DCHECK(task_runner_->BelongsToCurrentThread()); | 81 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 77 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || | 82 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || |
| 78 state_ == STATE_ERROR) << state_; | 83 state_ == STATE_ERROR) << state_; |
| 79 // No two reads in the flight at any time. | 84 // No two reads in the flight at any time. |
| 80 DCHECK(read_cb_.is_null()); | 85 DCHECK(read_cb_.is_null()); |
| 81 // No read during resetting or stopping process. | 86 // No read during resetting or stopping process. |
| 82 DCHECK(reset_cb_.is_null()); | 87 DCHECK(reset_cb_.is_null()); |
| 83 DCHECK(stop_cb_.is_null()); | 88 DCHECK(stop_cb_.is_null()); |
| 84 | 89 |
| 85 if (state_ == STATE_ERROR) { | 90 if (state_ == STATE_ERROR) { |
| 86 task_runner_->PostTask(FROM_HERE, base::Bind( | 91 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 87 read_cb, DECODE_ERROR, scoped_refptr<Output>())); | 92 read_cb, DECODE_ERROR, scoped_refptr<Output>())); |
| 88 return; | 93 return; |
| 89 } | 94 } |
| 90 | 95 |
| 91 read_cb_ = read_cb; | 96 read_cb_ = read_cb; |
| 92 | 97 |
| 93 if (state_ == STATE_FLUSHING_DECODER) { | 98 if (state_ == STATE_FLUSHING_DECODER) { |
| 94 FlushDecoder(); | 99 FlushDecoder(); |
| 95 return; | 100 return; |
| 96 } | 101 } |
| 97 | 102 |
| 98 ReadFromDemuxerStream(); | 103 if (!SendQueuedOutput()) |
| 104 ReadFromDemuxerStream(); | |
| 99 } | 105 } |
| 100 | 106 |
| 101 template <DemuxerStream::Type StreamType> | 107 template <DemuxerStream::Type StreamType> |
| 102 void DecoderStream<StreamType>::Reset(const base::Closure& closure) { | 108 void DecoderStream<StreamType>::Reset(const base::Closure& closure) { |
| 103 DVLOG(2) << __FUNCTION__; | 109 DVLOG(2) << __FUNCTION__; |
| 104 DCHECK(task_runner_->BelongsToCurrentThread()); | 110 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 105 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; | 111 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; |
| 106 DCHECK(reset_cb_.is_null()); | 112 DCHECK(reset_cb_.is_null()); |
| 107 DCHECK(stop_cb_.is_null()); | 113 DCHECK(stop_cb_.is_null()); |
| 108 | 114 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 decrypting_demuxer_stream_.reset(); | 184 decrypting_demuxer_stream_.reset(); |
| 179 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); | 185 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); |
| 180 } | 186 } |
| 181 | 187 |
| 182 template <DemuxerStream::Type StreamType> | 188 template <DemuxerStream::Type StreamType> |
| 183 bool DecoderStream<StreamType>::CanReadWithoutStalling() const { | 189 bool DecoderStream<StreamType>::CanReadWithoutStalling() const { |
| 184 DCHECK(task_runner_->BelongsToCurrentThread()); | 190 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 185 return decoder_->CanReadWithoutStalling(); | 191 return decoder_->CanReadWithoutStalling(); |
| 186 } | 192 } |
| 187 | 193 |
| 194 template <> | |
| 195 bool DecoderStream<DemuxerStream::AUDIO>::CanReadWithoutStalling() const { | |
| 196 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 197 return true; | |
| 198 } | |
| 199 | |
| 188 template <DemuxerStream::Type StreamType> | 200 template <DemuxerStream::Type StreamType> |
| 189 void DecoderStream<StreamType>::OnDecoderSelected( | 201 void DecoderStream<StreamType>::OnDecoderSelected( |
| 190 scoped_ptr<Decoder> selected_decoder, | 202 scoped_ptr<Decoder> selected_decoder, |
| 191 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { | 203 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { |
| 192 DVLOG(2) << __FUNCTION__; | 204 DVLOG(2) << __FUNCTION__; |
| 193 DCHECK(task_runner_->BelongsToCurrentThread()); | 205 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 194 DCHECK_EQ(state_, STATE_INITIALIZING) << state_; | 206 DCHECK_EQ(state_, STATE_INITIALIZING) << state_; |
| 195 DCHECK(!init_cb_.is_null()); | 207 DCHECK(!init_cb_.is_null()); |
| 196 DCHECK(read_cb_.is_null()); | 208 DCHECK(read_cb_.is_null()); |
| 197 DCHECK(reset_cb_.is_null()); | 209 DCHECK(reset_cb_.is_null()); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 312 } | 324 } |
| 313 | 325 |
| 314 if (status == Decoder::kNotEnoughData) { | 326 if (status == Decoder::kNotEnoughData) { |
| 315 if (state_ == STATE_NORMAL) | 327 if (state_ == STATE_NORMAL) |
| 316 ReadFromDemuxerStream(); | 328 ReadFromDemuxerStream(); |
| 317 else if (state_ == STATE_FLUSHING_DECODER) | 329 else if (state_ == STATE_FLUSHING_DECODER) |
| 318 FlushDecoder(); | 330 FlushDecoder(); |
| 319 return; | 331 return; |
| 320 } | 332 } |
| 321 | 333 |
| 334 DCHECK(output); | |
| 322 SatisfyRead(OK, output); | 335 SatisfyRead(OK, output); |
| 323 } | 336 } |
| 324 | 337 |
| 325 template <DemuxerStream::Type StreamType> | 338 template <DemuxerStream::Type StreamType> |
| 326 void DecoderStream<StreamType>::ReadFromDemuxerStream() { | 339 void DecoderStream<StreamType>::ReadFromDemuxerStream() { |
| 327 DVLOG(2) << __FUNCTION__; | 340 DVLOG(2) << __FUNCTION__; |
| 328 DCHECK_EQ(state_, STATE_NORMAL) << state_; | 341 DCHECK_EQ(state_, STATE_NORMAL) << state_; |
| 329 DCHECK(!read_cb_.is_null()); | 342 DCHECK(!read_cb_.is_null()); |
| 330 DCHECK(reset_cb_.is_null()); | 343 DCHECK(reset_cb_.is_null()); |
| 331 DCHECK(stop_cb_.is_null()); | 344 DCHECK(stop_cb_.is_null()); |
| 332 | 345 |
| 333 state_ = STATE_PENDING_DEMUXER_READ; | 346 state_ = STATE_PENDING_DEMUXER_READ; |
| 334 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady, | 347 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady, |
| 335 weak_factory_.GetWeakPtr())); | 348 weak_factory_.GetWeakPtr())); |
| 336 } | 349 } |
| 337 | 350 |
| 338 template <DemuxerStream::Type StreamType> | 351 template <DemuxerStream::Type StreamType> |
| 352 bool DecoderStream<StreamType>::SendQueuedOutput() { | |
| 353 return false; | |
| 354 } | |
| 355 | |
| 356 template <> | |
| 357 bool DecoderStream<DemuxerStream::AUDIO>::SendQueuedOutput() { | |
|
xhwang
2014/02/27 19:52:28
The name "SendQueuedOutput" is a bit odd. How abou
| |
| 358 AudioDecoder::Status status; | |
| 359 if (scoped_refptr<AudioBuffer> buffer = decoder_->GetAudioBuffer(&status)) { | |
| 360 OnDecodeOutputReady(0, status, buffer); | |
|
xhwang
2014/02/27 19:52:28
since the first parameter is always 0, how about c
| |
| 361 return true; | |
| 362 } | |
| 363 return false; | |
| 364 } | |
| 365 | |
| 366 template <DemuxerStream::Type StreamType> | |
| 339 void DecoderStream<StreamType>::OnBufferReady( | 367 void DecoderStream<StreamType>::OnBufferReady( |
| 340 DemuxerStream::Status status, | 368 DemuxerStream::Status status, |
| 341 const scoped_refptr<DecoderBuffer>& buffer) { | 369 const scoped_refptr<DecoderBuffer>& buffer) { |
| 342 DVLOG(2) << __FUNCTION__; | 370 DVLOG(2) << __FUNCTION__; |
| 343 DCHECK(task_runner_->BelongsToCurrentThread()); | 371 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 344 DCHECK_EQ(state_, STATE_PENDING_DEMUXER_READ) << state_; | 372 DCHECK_EQ(state_, STATE_PENDING_DEMUXER_READ) << state_; |
| 345 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status; | 373 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status; |
| 346 DCHECK(!read_cb_.is_null()); | 374 DCHECK(!read_cb_.is_null()); |
| 347 DCHECK(stop_cb_.is_null()); | 375 DCHECK(stop_cb_.is_null()); |
| 348 | 376 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 380 DCHECK(status == DemuxerStream::kOk) << status; | 408 DCHECK(status == DemuxerStream::kOk) << status; |
| 381 Decode(buffer); | 409 Decode(buffer); |
| 382 } | 410 } |
| 383 | 411 |
| 384 template <DemuxerStream::Type StreamType> | 412 template <DemuxerStream::Type StreamType> |
| 385 void DecoderStream<StreamType>::ReinitializeDecoder() { | 413 void DecoderStream<StreamType>::ReinitializeDecoder() { |
| 386 DVLOG(2) << __FUNCTION__; | 414 DVLOG(2) << __FUNCTION__; |
| 387 DCHECK(task_runner_->BelongsToCurrentThread()); | 415 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 388 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; | 416 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; |
| 389 | 417 |
| 390 // TODO(rileya): Specialize this for audio, or, better yet, change | 418 DCHECK(StreamTraits::GetDecoderConfig(*stream_).IsValidConfig()); |
| 391 // DemuxerStream config getters to be templated. | |
| 392 DCHECK(stream_->video_decoder_config().IsValidConfig()); | |
| 393 state_ = STATE_REINITIALIZING_DECODER; | 419 state_ = STATE_REINITIALIZING_DECODER; |
| 394 decoder_->Initialize( | 420 decoder_->Initialize( |
| 395 stream_->video_decoder_config(), | 421 StreamTraits::GetDecoderConfig(*stream_), |
| 396 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized, | 422 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized, |
| 397 weak_factory_.GetWeakPtr())); | 423 weak_factory_.GetWeakPtr())); |
| 398 } | 424 } |
| 399 | 425 |
| 400 template <DemuxerStream::Type StreamType> | 426 template <DemuxerStream::Type StreamType> |
| 401 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) { | 427 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) { |
| 402 DVLOG(2) << __FUNCTION__; | 428 DVLOG(2) << __FUNCTION__; |
| 403 DCHECK(task_runner_->BelongsToCurrentThread()); | 429 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 404 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_; | 430 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_; |
| 405 DCHECK(stop_cb_.is_null()); | 431 DCHECK(stop_cb_.is_null()); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 485 DCHECK(!stop_cb_.is_null()); | 511 DCHECK(!stop_cb_.is_null()); |
| 486 | 512 |
| 487 state_ = STATE_STOPPED; | 513 state_ = STATE_STOPPED; |
| 488 stream_ = NULL; | 514 stream_ = NULL; |
| 489 decoder_.reset(); | 515 decoder_.reset(); |
| 490 decrypting_demuxer_stream_.reset(); | 516 decrypting_demuxer_stream_.reset(); |
| 491 base::ResetAndReturn(&stop_cb_).Run(); | 517 base::ResetAndReturn(&stop_cb_).Run(); |
| 492 } | 518 } |
| 493 | 519 |
| 494 template class DecoderStream<DemuxerStream::VIDEO>; | 520 template class DecoderStream<DemuxerStream::VIDEO>; |
| 521 template class DecoderStream<DemuxerStream::AUDIO>; | |
| 495 } // namespace media | 522 } // namespace media |
| OLD | NEW |