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 |
103 // If the decoder has queued output ready to go we don't need a demuxer read. | |
104 if (scoped_refptr<Output> output = decoder_->GetDecodeOutput()) { | |
xhwang
2014/03/05 00:40:46
This is neat, but I am not sure whether it's more
rileya (GONE FROM CHROMIUM)
2014/03/05 08:08:28
Done.
| |
105 SatisfyRead(OK, output); | |
xhwang
2014/03/05 00:40:46
Can we add a unit test to cover this logic?
rileya (GONE FROM CHROMIUM)
2014/03/05 08:08:28
Sounds good, will do.
rileya (GONE FROM CHROMIUM)
2014/03/06 22:11:56
Done. There's currently no tests for DecoderStream
| |
106 return; | |
107 } | |
108 | |
98 ReadFromDemuxerStream(); | 109 ReadFromDemuxerStream(); |
99 } | 110 } |
100 | 111 |
101 template <DemuxerStream::Type StreamType> | 112 template <DemuxerStream::Type StreamType> |
102 void DecoderStream<StreamType>::Reset(const base::Closure& closure) { | 113 void DecoderStream<StreamType>::Reset(const base::Closure& closure) { |
103 DVLOG(2) << __FUNCTION__; | 114 DVLOG(2) << __FUNCTION__; |
104 DCHECK(task_runner_->BelongsToCurrentThread()); | 115 DCHECK(task_runner_->BelongsToCurrentThread()); |
105 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; | 116 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; |
106 DCHECK(reset_cb_.is_null()); | 117 DCHECK(reset_cb_.is_null()); |
107 DCHECK(stop_cb_.is_null()); | 118 DCHECK(stop_cb_.is_null()); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 decrypting_demuxer_stream_.reset(); | 189 decrypting_demuxer_stream_.reset(); |
179 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); | 190 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); |
180 } | 191 } |
181 | 192 |
182 template <DemuxerStream::Type StreamType> | 193 template <DemuxerStream::Type StreamType> |
183 bool DecoderStream<StreamType>::CanReadWithoutStalling() const { | 194 bool DecoderStream<StreamType>::CanReadWithoutStalling() const { |
184 DCHECK(task_runner_->BelongsToCurrentThread()); | 195 DCHECK(task_runner_->BelongsToCurrentThread()); |
185 return decoder_->CanReadWithoutStalling(); | 196 return decoder_->CanReadWithoutStalling(); |
186 } | 197 } |
187 | 198 |
199 template <> | |
200 bool DecoderStream<DemuxerStream::AUDIO>::CanReadWithoutStalling() const { | |
201 DCHECK(task_runner_->BelongsToCurrentThread()); | |
202 return true; | |
203 } | |
204 | |
188 template <DemuxerStream::Type StreamType> | 205 template <DemuxerStream::Type StreamType> |
189 void DecoderStream<StreamType>::OnDecoderSelected( | 206 void DecoderStream<StreamType>::OnDecoderSelected( |
190 scoped_ptr<Decoder> selected_decoder, | 207 scoped_ptr<Decoder> selected_decoder, |
191 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { | 208 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { |
192 DVLOG(2) << __FUNCTION__; | 209 DVLOG(2) << __FUNCTION__; |
193 DCHECK(task_runner_->BelongsToCurrentThread()); | 210 DCHECK(task_runner_->BelongsToCurrentThread()); |
194 DCHECK_EQ(state_, STATE_INITIALIZING) << state_; | 211 DCHECK_EQ(state_, STATE_INITIALIZING) << state_; |
195 DCHECK(!init_cb_.is_null()); | 212 DCHECK(!init_cb_.is_null()); |
196 DCHECK(read_cb_.is_null()); | 213 DCHECK(read_cb_.is_null()); |
197 DCHECK(reset_cb_.is_null()); | 214 DCHECK(reset_cb_.is_null()); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
312 } | 329 } |
313 | 330 |
314 if (status == Decoder::kNotEnoughData) { | 331 if (status == Decoder::kNotEnoughData) { |
315 if (state_ == STATE_NORMAL) | 332 if (state_ == STATE_NORMAL) |
316 ReadFromDemuxerStream(); | 333 ReadFromDemuxerStream(); |
317 else if (state_ == STATE_FLUSHING_DECODER) | 334 else if (state_ == STATE_FLUSHING_DECODER) |
318 FlushDecoder(); | 335 FlushDecoder(); |
319 return; | 336 return; |
320 } | 337 } |
321 | 338 |
339 DCHECK(output); | |
322 SatisfyRead(OK, output); | 340 SatisfyRead(OK, output); |
323 } | 341 } |
324 | 342 |
325 template <DemuxerStream::Type StreamType> | 343 template <DemuxerStream::Type StreamType> |
326 void DecoderStream<StreamType>::ReadFromDemuxerStream() { | 344 void DecoderStream<StreamType>::ReadFromDemuxerStream() { |
327 DVLOG(2) << __FUNCTION__; | 345 DVLOG(2) << __FUNCTION__; |
328 DCHECK_EQ(state_, STATE_NORMAL) << state_; | 346 DCHECK_EQ(state_, STATE_NORMAL) << state_; |
329 DCHECK(!read_cb_.is_null()); | 347 DCHECK(!read_cb_.is_null()); |
330 DCHECK(reset_cb_.is_null()); | 348 DCHECK(reset_cb_.is_null()); |
331 DCHECK(stop_cb_.is_null()); | 349 DCHECK(stop_cb_.is_null()); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 DCHECK(status == DemuxerStream::kOk) << status; | 398 DCHECK(status == DemuxerStream::kOk) << status; |
381 Decode(buffer); | 399 Decode(buffer); |
382 } | 400 } |
383 | 401 |
384 template <DemuxerStream::Type StreamType> | 402 template <DemuxerStream::Type StreamType> |
385 void DecoderStream<StreamType>::ReinitializeDecoder() { | 403 void DecoderStream<StreamType>::ReinitializeDecoder() { |
386 DVLOG(2) << __FUNCTION__; | 404 DVLOG(2) << __FUNCTION__; |
387 DCHECK(task_runner_->BelongsToCurrentThread()); | 405 DCHECK(task_runner_->BelongsToCurrentThread()); |
388 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; | 406 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; |
389 | 407 |
390 // TODO(rileya): Specialize this for audio, or, better yet, change | 408 DCHECK(StreamTraits::GetDecoderConfig(*stream_).IsValidConfig()); |
391 // DemuxerStream config getters to be templated. | |
392 DCHECK(stream_->video_decoder_config().IsValidConfig()); | |
393 state_ = STATE_REINITIALIZING_DECODER; | 409 state_ = STATE_REINITIALIZING_DECODER; |
394 decoder_->Initialize( | 410 decoder_->Initialize( |
395 stream_->video_decoder_config(), | 411 StreamTraits::GetDecoderConfig(*stream_), |
396 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized, | 412 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized, |
397 weak_factory_.GetWeakPtr())); | 413 weak_factory_.GetWeakPtr())); |
398 } | 414 } |
399 | 415 |
400 template <DemuxerStream::Type StreamType> | 416 template <DemuxerStream::Type StreamType> |
401 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) { | 417 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) { |
402 DVLOG(2) << __FUNCTION__; | 418 DVLOG(2) << __FUNCTION__; |
403 DCHECK(task_runner_->BelongsToCurrentThread()); | 419 DCHECK(task_runner_->BelongsToCurrentThread()); |
404 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_; | 420 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_; |
405 DCHECK(stop_cb_.is_null()); | 421 DCHECK(stop_cb_.is_null()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
485 DCHECK(!stop_cb_.is_null()); | 501 DCHECK(!stop_cb_.is_null()); |
486 | 502 |
487 state_ = STATE_STOPPED; | 503 state_ = STATE_STOPPED; |
488 stream_ = NULL; | 504 stream_ = NULL; |
489 decoder_.reset(); | 505 decoder_.reset(); |
490 decrypting_demuxer_stream_.reset(); | 506 decrypting_demuxer_stream_.reset(); |
491 base::ResetAndReturn(&stop_cb_).Run(); | 507 base::ResetAndReturn(&stop_cb_).Run(); |
492 } | 508 } |
493 | 509 |
494 template class DecoderStream<DemuxerStream::VIDEO>; | 510 template class DecoderStream<DemuxerStream::VIDEO>; |
511 template class DecoderStream<DemuxerStream::AUDIO>; | |
495 | 512 |
496 } // namespace media | 513 } // namespace media |
OLD | NEW |