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
3 // found in the LICENSE file.
4
5 #include "media/filters/decoder_stream.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/debug/trace_event.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "media/base/audio_decoder.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/decoder_buffer.h"
16 #include "media/base/demuxer_stream.h"
17 #include "media/base/video_decoder.h"
18 #include "media/filters/decrypting_demuxer_stream.h"
19
20 namespace media {
21
22 // TODO(rileya): Devise a better way of specifying trace/UMA/etc strings for
23 // templated classes such as this.
24 template <DemuxerStream::Type StreamType>
25 static const char* GetTraceString();
26
27 #define FUNCTION_DVLOG(level) \
28 DVLOG(level) << __FUNCTION__ << \
29 "<" << DecoderStreamTraits<StreamType>::ToString() << ">"
30
31 template <>
GetTraceString()32 const char* GetTraceString<DemuxerStream::VIDEO>() {
33 return "DecoderStream<VIDEO>::Decode";
34 }
35
36 template <>
GetTraceString()37 const char* GetTraceString<DemuxerStream::AUDIO>() {
38 return "DecoderStream<AUDIO>::Decode";
39 }
40
41 template <DemuxerStream::Type StreamType>
DecoderStream(const scoped_refptr<base::SingleThreadTaskRunner> & task_runner,ScopedVector<Decoder> decoders,const SetDecryptorReadyCB & set_decryptor_ready_cb)42 DecoderStream<StreamType>::DecoderStream(
43 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
44 ScopedVector<Decoder> decoders,
45 const SetDecryptorReadyCB& set_decryptor_ready_cb)
46 : task_runner_(task_runner),
47 state_(STATE_UNINITIALIZED),
48 stream_(NULL),
49 decoder_selector_(
50 new DecoderSelector<StreamType>(task_runner,
51 decoders.Pass(),
52 set_decryptor_ready_cb)),
53 active_splice_(false),
54 pending_decode_requests_(0),
55 weak_factory_(this) {}
56
57 template <DemuxerStream::Type StreamType>
~DecoderStream()58 DecoderStream<StreamType>::~DecoderStream() {
59 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_STOPPED) << state_;
60 }
61
62 template <DemuxerStream::Type StreamType>
Initialize(DemuxerStream * stream,bool low_delay,const StatisticsCB & statistics_cb,const InitCB & init_cb)63 void DecoderStream<StreamType>::Initialize(DemuxerStream* stream,
64 bool low_delay,
65 const StatisticsCB& statistics_cb,
66 const InitCB& init_cb) {
67 FUNCTION_DVLOG(2);
68 DCHECK(task_runner_->BelongsToCurrentThread());
69 DCHECK_EQ(state_, STATE_UNINITIALIZED) << state_;
70 DCHECK(init_cb_.is_null());
71 DCHECK(!init_cb.is_null());
72
73 statistics_cb_ = statistics_cb;
74 init_cb_ = init_cb;
75 stream_ = stream;
76 low_delay_ = low_delay;
77
78 state_ = STATE_INITIALIZING;
79 // TODO(xhwang): DecoderSelector only needs a config to select a decoder.
80 decoder_selector_->SelectDecoder(
81 stream, low_delay,
82 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected,
83 weak_factory_.GetWeakPtr()),
84 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
85 weak_factory_.GetWeakPtr()));
86 }
87
88 template <DemuxerStream::Type StreamType>
Read(const ReadCB & read_cb)89 void DecoderStream<StreamType>::Read(const ReadCB& read_cb) {
90 FUNCTION_DVLOG(2);
91 DCHECK(task_runner_->BelongsToCurrentThread());
92 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_INITIALIZING &&
93 state_ != STATE_STOPPED) << state_;
94 // No two reads in the flight at any time.
95 DCHECK(read_cb_.is_null());
96 // No read during resetting or stopping process.
97 DCHECK(reset_cb_.is_null());
98 DCHECK(stop_cb_.is_null());
99
100 if (state_ == STATE_ERROR) {
101 task_runner_->PostTask(
102 FROM_HERE, base::Bind(read_cb, DECODE_ERROR, scoped_refptr<Output>()));
103 return;
104 }
105
106 if (state_ == STATE_END_OF_STREAM && ready_outputs_.empty()) {
107 task_runner_->PostTask(
108 FROM_HERE, base::Bind(read_cb, OK, StreamTraits::CreateEOSOutput()));
109 return;
110 }
111
112 if (!ready_outputs_.empty()) {
113 task_runner_->PostTask(FROM_HERE,
114 base::Bind(read_cb, OK, ready_outputs_.front()));
115 ready_outputs_.pop_front();
116 } else {
117 read_cb_ = read_cb;
118 }
119
120 if (state_ == STATE_NORMAL && CanDecodeMore())
121 ReadFromDemuxerStream();
122 }
123
124 template <DemuxerStream::Type StreamType>
Reset(const base::Closure & closure)125 void DecoderStream<StreamType>::Reset(const base::Closure& closure) {
126 FUNCTION_DVLOG(2);
127 DCHECK(task_runner_->BelongsToCurrentThread());
128 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_;
129 DCHECK(reset_cb_.is_null());
130 DCHECK(stop_cb_.is_null());
131
132 reset_cb_ = closure;
133
134 if (!read_cb_.is_null()) {
135 task_runner_->PostTask(FROM_HERE, base::Bind(
136 base::ResetAndReturn(&read_cb_), ABORTED, scoped_refptr<Output>()));
137 }
138
139 ready_outputs_.clear();
140
141 // During decoder reinitialization, the Decoder does not need to be and
142 // cannot be Reset(). |decrypting_demuxer_stream_| was reset before decoder
143 // reinitialization.
144 if (state_ == STATE_REINITIALIZING_DECODER)
145 return;
146
147 // During pending demuxer read and when not using DecryptingDemuxerStream,
148 // the Decoder will be reset after demuxer read is returned
149 // (in OnBufferReady()).
150 if (state_ == STATE_PENDING_DEMUXER_READ && !decrypting_demuxer_stream_)
151 return;
152
153 if (decrypting_demuxer_stream_) {
154 decrypting_demuxer_stream_->Reset(base::Bind(
155 &DecoderStream<StreamType>::ResetDecoder, weak_factory_.GetWeakPtr()));
156 return;
157 }
158
159 ResetDecoder();
160 }
161
162 template <DemuxerStream::Type StreamType>
Stop(const base::Closure & closure)163 void DecoderStream<StreamType>::Stop(const base::Closure& closure) {
164 FUNCTION_DVLOG(2);
165 DCHECK(task_runner_->BelongsToCurrentThread());
166 DCHECK_NE(state_, STATE_STOPPED) << state_;
167 DCHECK(stop_cb_.is_null());
168
169 stop_cb_ = closure;
170
171 if (state_ == STATE_INITIALIZING) {
172 decoder_selector_->Abort();
173 return;
174 }
175
176 DCHECK(init_cb_.is_null());
177
178 // All pending callbacks will be dropped.
179 weak_factory_.InvalidateWeakPtrs();
180
181 // Post callbacks to prevent reentrance into this object.
182 if (!read_cb_.is_null()) {
183 task_runner_->PostTask(FROM_HERE, base::Bind(
184 base::ResetAndReturn(&read_cb_), ABORTED, scoped_refptr<Output>()));
185 }
186 if (!reset_cb_.is_null())
187 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_));
188
189 if (decrypting_demuxer_stream_) {
190 decrypting_demuxer_stream_->Stop(base::Bind(
191 &DecoderStream<StreamType>::StopDecoder, weak_factory_.GetWeakPtr()));
192 return;
193 }
194
195 // We may not have a |decoder_| if Stop() was called during initialization.
196 if (decoder_) {
197 StopDecoder();
198 return;
199 }
200
201 state_ = STATE_STOPPED;
202 stream_ = NULL;
203 decoder_.reset();
204 decrypting_demuxer_stream_.reset();
205 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
206 }
207
208 template <DemuxerStream::Type StreamType>
CanReadWithoutStalling() const209 bool DecoderStream<StreamType>::CanReadWithoutStalling() const {
210 DCHECK(task_runner_->BelongsToCurrentThread());
211 return !ready_outputs_.empty() || decoder_->CanReadWithoutStalling();
212 }
213
214 template <>
CanReadWithoutStalling() const215 bool DecoderStream<DemuxerStream::AUDIO>::CanReadWithoutStalling() const {
216 DCHECK(task_runner_->BelongsToCurrentThread());
217 return true;
218 }
219
220 template <DemuxerStream::Type StreamType>
GetMaxDecodeRequests() const221 int DecoderStream<StreamType>::GetMaxDecodeRequests() const {
222 return decoder_->GetMaxDecodeRequests();
223 }
224
225 template <>
GetMaxDecodeRequests() const226 int DecoderStream<DemuxerStream::AUDIO>::GetMaxDecodeRequests() const {
227 return 1;
228 }
229
230 template <DemuxerStream::Type StreamType>
CanDecodeMore() const231 bool DecoderStream<StreamType>::CanDecodeMore() const {
232 DCHECK(task_runner_->BelongsToCurrentThread());
233
234 // Limit total number of outputs stored in |ready_outputs_| and being decoded.
235 // It only makes sense to saturate decoder completely when output queue is
236 // empty.
237 int num_decodes =
238 static_cast<int>(ready_outputs_.size()) + pending_decode_requests_;
239 return num_decodes < GetMaxDecodeRequests();
240 }
241
242 template <DemuxerStream::Type StreamType>
OnDecoderSelected(scoped_ptr<Decoder> selected_decoder,scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream)243 void DecoderStream<StreamType>::OnDecoderSelected(
244 scoped_ptr<Decoder> selected_decoder,
245 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) {
246 FUNCTION_DVLOG(2);
247 DCHECK(task_runner_->BelongsToCurrentThread());
248 DCHECK_EQ(state_, STATE_INITIALIZING) << state_;
249 DCHECK(!init_cb_.is_null());
250 DCHECK(read_cb_.is_null());
251 DCHECK(reset_cb_.is_null());
252
253 decoder_selector_.reset();
254 if (decrypting_demuxer_stream)
255 stream_ = decrypting_demuxer_stream.get();
256
257 if (!selected_decoder) {
258 state_ = STATE_UNINITIALIZED;
259 StreamTraits::FinishInitialization(
260 base::ResetAndReturn(&init_cb_), selected_decoder.get(), stream_);
261 } else {
262 state_ = STATE_NORMAL;
263 decoder_ = selected_decoder.Pass();
264 decrypting_demuxer_stream_ = decrypting_demuxer_stream.Pass();
265 StreamTraits::FinishInitialization(
266 base::ResetAndReturn(&init_cb_), decoder_.get(), stream_);
267 }
268
269 // Stop() called during initialization.
270 if (!stop_cb_.is_null()) {
271 Stop(base::ResetAndReturn(&stop_cb_));
272 return;
273 }
274 }
275
276 template <DemuxerStream::Type StreamType>
SatisfyRead(Status status,const scoped_refptr<Output> & output)277 void DecoderStream<StreamType>::SatisfyRead(
278 Status status,
279 const scoped_refptr<Output>& output) {
280 DCHECK(!read_cb_.is_null());
281 base::ResetAndReturn(&read_cb_).Run(status, output);
282 }
283
284 template <DemuxerStream::Type StreamType>
Decode(const scoped_refptr<DecoderBuffer> & buffer)285 void DecoderStream<StreamType>::Decode(
286 const scoped_refptr<DecoderBuffer>& buffer) {
287 FUNCTION_DVLOG(2);
288 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER) << state_;
289 DCHECK_LT(pending_decode_requests_, GetMaxDecodeRequests());
290 DCHECK(reset_cb_.is_null());
291 DCHECK(stop_cb_.is_null());
292 DCHECK(buffer);
293
294 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size();
295
296 TRACE_EVENT_ASYNC_BEGIN0("media", GetTraceString<StreamType>(), this);
297 ++pending_decode_requests_;
298 decoder_->Decode(buffer,
299 base::Bind(&DecoderStream<StreamType>::OnDecodeDone,
300 weak_factory_.GetWeakPtr(),
301 buffer_size,
302 buffer->end_of_stream()));
303 }
304
305 template <DemuxerStream::Type StreamType>
FlushDecoder()306 void DecoderStream<StreamType>::FlushDecoder() {
307 Decode(DecoderBuffer::CreateEOSBuffer());
308 }
309
310 template <DemuxerStream::Type StreamType>
OnDecodeDone(int buffer_size,bool end_of_stream,typename Decoder::Status status)311 void DecoderStream<StreamType>::OnDecodeDone(int buffer_size,
312 bool end_of_stream,
313 typename Decoder::Status status) {
314 FUNCTION_DVLOG(2) << status;
315 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
316 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
317 << state_;
318 DCHECK(stop_cb_.is_null());
319 DCHECK_GT(pending_decode_requests_, 0);
320
321 --pending_decode_requests_;
322
323 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this);
324
325 if (state_ == STATE_ERROR) {
326 DCHECK(read_cb_.is_null());
327 return;
328 }
329
330 // Drop decoding result if Reset() was called during decoding.
331 // The resetting process will be handled when the decoder is reset.
332 if (!reset_cb_.is_null())
333 return;
334
335 switch (status) {
336 case Decoder::kDecodeError:
337 case Decoder::kDecryptError:
338 state_ = STATE_ERROR;
339 ready_outputs_.clear();
340 if (!read_cb_.is_null())
341 SatisfyRead(DECODE_ERROR, NULL);
342 return;
343
344 case Decoder::kAborted:
345 // Decoder can return kAborted only when Reset is pending.
346 NOTREACHED();
347 return;
348
349 case Decoder::kOk:
350 // Any successful decode counts!
351 if (buffer_size > 0)
352 StreamTraits::ReportStatistics(statistics_cb_, buffer_size);
353
354 if (state_ == STATE_NORMAL) {
355 if (end_of_stream) {
356 state_ = STATE_END_OF_STREAM;
357 if (ready_outputs_.empty() && !read_cb_.is_null())
358 SatisfyRead(OK, StreamTraits::CreateEOSOutput());
359 return;
360 }
361
362 if (CanDecodeMore())
363 ReadFromDemuxerStream();
364 return;
365 }
366
367 if (state_ == STATE_FLUSHING_DECODER && !pending_decode_requests_)
368 ReinitializeDecoder();
369 return;
370 }
371 }
372
373 template <DemuxerStream::Type StreamType>
OnDecodeOutputReady(const scoped_refptr<Output> & output)374 void DecoderStream<StreamType>::OnDecodeOutputReady(
375 const scoped_refptr<Output>& output) {
376 FUNCTION_DVLOG(2) << ": " << output->timestamp().InMilliseconds() << " ms";
377 DCHECK(output);
378 DCHECK(!output->end_of_stream());
379 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
380 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
381 << state_;
382
383 if (state_ == STATE_ERROR) {
384 DCHECK(read_cb_.is_null());
385 return;
386 }
387
388 // Drop decoding result if Reset() was called during decoding.
389 // The resetting process will be handled when the decoder is reset.
390 if (!reset_cb_.is_null())
391 return;
392
393 // TODO(xhwang): VideoDecoder doesn't need to return EOS after it's flushed.
394 // Fix all decoders and remove this block.
395 // Store decoded output.
396 ready_outputs_.push_back(output);
397
398 if (read_cb_.is_null())
399 return;
400
401 // Satisfy outstanding read request, if any.
402 scoped_refptr<Output> read_result = ready_outputs_.front();
403 ready_outputs_.pop_front();
404 SatisfyRead(OK, output);
405 }
406
407 template <DemuxerStream::Type StreamType>
ReadFromDemuxerStream()408 void DecoderStream<StreamType>::ReadFromDemuxerStream() {
409 FUNCTION_DVLOG(2);
410 DCHECK_EQ(state_, STATE_NORMAL) << state_;
411 DCHECK(CanDecodeMore());
412 DCHECK(reset_cb_.is_null());
413 DCHECK(stop_cb_.is_null());
414
415 state_ = STATE_PENDING_DEMUXER_READ;
416 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady,
417 weak_factory_.GetWeakPtr()));
418 }
419
420 template <DemuxerStream::Type StreamType>
OnBufferReady(DemuxerStream::Status status,const scoped_refptr<DecoderBuffer> & buffer)421 void DecoderStream<StreamType>::OnBufferReady(
422 DemuxerStream::Status status,
423 const scoped_refptr<DecoderBuffer>& buffer) {
424 FUNCTION_DVLOG(2) << ": " << status << ", "
425 << buffer->AsHumanReadableString();
426
427 DCHECK(task_runner_->BelongsToCurrentThread());
428 DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR ||
429 state_ == STATE_STOPPED)
430 << state_;
431 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status;
432 DCHECK(stop_cb_.is_null());
433
434 // Decoding has been stopped (e.g due to an error).
435 if (state_ != STATE_PENDING_DEMUXER_READ) {
436 DCHECK(state_ == STATE_ERROR || state_ == STATE_STOPPED);
437 DCHECK(read_cb_.is_null());
438 return;
439 }
440
441 state_ = STATE_NORMAL;
442
443 if (status == DemuxerStream::kConfigChanged) {
444 FUNCTION_DVLOG(2) << ": " << "ConfigChanged";
445 DCHECK(stream_->SupportsConfigChanges());
446
447 if (!config_change_observer_cb_.is_null())
448 config_change_observer_cb_.Run();
449
450 state_ = STATE_FLUSHING_DECODER;
451 if (!reset_cb_.is_null()) {
452 // If we are using DecryptingDemuxerStream, we already called DDS::Reset()
453 // which will continue the resetting process in it's callback.
454 if (!decrypting_demuxer_stream_)
455 Reset(base::ResetAndReturn(&reset_cb_));
456 // Reinitialization will continue after Reset() is done.
457 } else {
458 FlushDecoder();
459 }
460 return;
461 }
462
463 if (!reset_cb_.is_null()) {
464 // If we are using DecryptingDemuxerStream, we already called DDS::Reset()
465 // which will continue the resetting process in it's callback.
466 if (!decrypting_demuxer_stream_)
467 Reset(base::ResetAndReturn(&reset_cb_));
468 return;
469 }
470
471 if (status == DemuxerStream::kAborted) {
472 if (!read_cb_.is_null())
473 SatisfyRead(DEMUXER_READ_ABORTED, NULL);
474 return;
475 }
476
477 if (!splice_observer_cb_.is_null() && !buffer->end_of_stream()) {
478 const bool has_splice_ts = buffer->splice_timestamp() != kNoTimestamp();
479 if (active_splice_ || has_splice_ts) {
480 splice_observer_cb_.Run(buffer->splice_timestamp());
481 active_splice_ = has_splice_ts;
482 }
483 }
484
485 DCHECK(status == DemuxerStream::kOk) << status;
486 Decode(buffer);
487
488 // Read more data if the decoder supports multiple parallel decoding requests.
489 if (CanDecodeMore() && !buffer->end_of_stream())
490 ReadFromDemuxerStream();
491 }
492
493 template <DemuxerStream::Type StreamType>
ReinitializeDecoder()494 void DecoderStream<StreamType>::ReinitializeDecoder() {
495 FUNCTION_DVLOG(2);
496 DCHECK(task_runner_->BelongsToCurrentThread());
497 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_;
498 DCHECK_EQ(pending_decode_requests_, 0);
499
500 DCHECK(StreamTraits::GetDecoderConfig(*stream_).IsValidConfig());
501 state_ = STATE_REINITIALIZING_DECODER;
502 DecoderStreamTraits<StreamType>::Initialize(
503 decoder_.get(),
504 StreamTraits::GetDecoderConfig(*stream_),
505 low_delay_,
506 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized,
507 weak_factory_.GetWeakPtr()),
508 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
509 weak_factory_.GetWeakPtr()));
510 }
511
512 template <DemuxerStream::Type StreamType>
OnDecoderReinitialized(PipelineStatus status)513 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) {
514 FUNCTION_DVLOG(2);
515 DCHECK(task_runner_->BelongsToCurrentThread());
516 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_;
517 DCHECK(stop_cb_.is_null());
518
519 // ReinitializeDecoder() can be called in two cases:
520 // 1, Flushing decoder finished (see OnDecodeOutputReady()).
521 // 2, Reset() was called during flushing decoder (see OnDecoderReset()).
522 // Also, Reset() can be called during pending ReinitializeDecoder().
523 // This function needs to handle them all!
524
525 state_ = (status == PIPELINE_OK) ? STATE_NORMAL : STATE_ERROR;
526
527 if (!reset_cb_.is_null()) {
528 base::ResetAndReturn(&reset_cb_).Run();
529 return;
530 }
531
532 if (read_cb_.is_null())
533 return;
534
535 if (state_ == STATE_ERROR) {
536 SatisfyRead(DECODE_ERROR, NULL);
537 return;
538 }
539
540 ReadFromDemuxerStream();
541 }
542
543 template <DemuxerStream::Type StreamType>
ResetDecoder()544 void DecoderStream<StreamType>::ResetDecoder() {
545 FUNCTION_DVLOG(2);
546 DCHECK(task_runner_->BelongsToCurrentThread());
547 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
548 state_ == STATE_ERROR || state_ == STATE_END_OF_STREAM) << state_;
549 DCHECK(!reset_cb_.is_null());
550
551 decoder_->Reset(base::Bind(&DecoderStream<StreamType>::OnDecoderReset,
552 weak_factory_.GetWeakPtr()));
553 }
554
555 template <DemuxerStream::Type StreamType>
OnDecoderReset()556 void DecoderStream<StreamType>::OnDecoderReset() {
557 FUNCTION_DVLOG(2);
558 DCHECK(task_runner_->BelongsToCurrentThread());
559 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
560 state_ == STATE_ERROR || state_ == STATE_END_OF_STREAM) << state_;
561 // If Reset() was called during pending read, read callback should be fired
562 // before the reset callback is fired.
563 DCHECK(read_cb_.is_null());
564 DCHECK(!reset_cb_.is_null());
565 DCHECK(stop_cb_.is_null());
566
567 if (state_ != STATE_FLUSHING_DECODER) {
568 state_ = STATE_NORMAL;
569 active_splice_ = false;
570 base::ResetAndReturn(&reset_cb_).Run();
571 return;
572 }
573
574 // The resetting process will be continued in OnDecoderReinitialized().
575 ReinitializeDecoder();
576 }
577
578 template <DemuxerStream::Type StreamType>
StopDecoder()579 void DecoderStream<StreamType>::StopDecoder() {
580 FUNCTION_DVLOG(2);
581 DCHECK(task_runner_->BelongsToCurrentThread());
582 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_;
583 DCHECK(!stop_cb_.is_null());
584
585 state_ = STATE_STOPPED;
586 decoder_->Stop();
587 stream_ = NULL;
588 decoder_.reset();
589 decrypting_demuxer_stream_.reset();
590 // Post |stop_cb_| because pending |read_cb_| and/or |reset_cb_| are also
591 // posted in Stop().
592 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
593 }
594
595 template class DecoderStream<DemuxerStream::VIDEO>;
596 template class DecoderStream<DemuxerStream::AUDIO>;
597
598 } // namespace media
599