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" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 statistics_cb_ = statistics_cb; | 73 statistics_cb_ = statistics_cb; |
| 74 init_cb_ = init_cb; | 74 init_cb_ = init_cb; |
| 75 stream_ = stream; | 75 stream_ = stream; |
| 76 low_delay_ = low_delay; | 76 low_delay_ = low_delay; |
| 77 | 77 |
| 78 state_ = STATE_INITIALIZING; | 78 state_ = STATE_INITIALIZING; |
| 79 // TODO(xhwang): DecoderSelector only needs a config to select a decoder. | 79 // TODO(xhwang): DecoderSelector only needs a config to select a decoder. |
| 80 decoder_selector_->SelectDecoder( | 80 decoder_selector_->SelectDecoder( |
| 81 stream, low_delay, | 81 stream, low_delay, |
| 82 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, | 82 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, |
| 83 weak_factory_.GetWeakPtr()), | |
| 84 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady, | |
| 83 weak_factory_.GetWeakPtr())); | 85 weak_factory_.GetWeakPtr())); |
| 84 } | 86 } |
| 85 | 87 |
| 86 template <DemuxerStream::Type StreamType> | 88 template <DemuxerStream::Type StreamType> |
| 87 void DecoderStream<StreamType>::Read(const ReadCB& read_cb) { | 89 void DecoderStream<StreamType>::Read(const ReadCB& read_cb) { |
| 88 FUNCTION_DVLOG(2); | 90 FUNCTION_DVLOG(2); |
| 89 DCHECK(task_runner_->BelongsToCurrentThread()); | 91 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 90 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || | 92 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || |
| 91 state_ == STATE_ERROR || state_ == STATE_REINITIALIZING_DECODER || | 93 state_ == STATE_ERROR || state_ == STATE_REINITIALIZING_DECODER || |
| 92 state_ == STATE_PENDING_DEMUXER_READ) | 94 state_ == STATE_PENDING_DEMUXER_READ) |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 106 scoped_refptr<Output>())); | 108 scoped_refptr<Output>())); |
| 107 return; | 109 return; |
| 108 } | 110 } |
| 109 | 111 |
| 110 if (!ready_outputs_.empty()) { | 112 if (!ready_outputs_.empty()) { |
| 111 task_runner_->PostTask(FROM_HERE, base::Bind( | 113 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 112 base::ResetAndReturn(&read_cb_), OK, ready_outputs_.front())); | 114 base::ResetAndReturn(&read_cb_), OK, ready_outputs_.front())); |
| 113 ready_outputs_.pop_front(); | 115 ready_outputs_.pop_front(); |
| 114 } | 116 } |
| 115 | 117 |
| 116 // Decoder may be in reinitializing state as result of the previous Read(). | 118 if (state_ == STATE_NORMAL && CanDecodeMore()) |
| 117 if (state_ == STATE_REINITIALIZING_DECODER) | |
| 118 return; | |
| 119 | |
| 120 if (!CanDecodeMore()) | |
| 121 return; | |
| 122 | |
| 123 if (state_ == STATE_FLUSHING_DECODER) { | |
| 124 FlushDecoder(); | |
| 125 return; | |
| 126 } | |
| 127 | |
| 128 if (state_ != STATE_PENDING_DEMUXER_READ) | |
| 129 ReadFromDemuxerStream(); | 119 ReadFromDemuxerStream(); |
| 130 } | 120 } |
| 131 | 121 |
| 132 template <DemuxerStream::Type StreamType> | 122 template <DemuxerStream::Type StreamType> |
| 133 void DecoderStream<StreamType>::Reset(const base::Closure& closure) { | 123 void DecoderStream<StreamType>::Reset(const base::Closure& closure) { |
| 134 FUNCTION_DVLOG(2); | 124 FUNCTION_DVLOG(2); |
| 135 DCHECK(task_runner_->BelongsToCurrentThread()); | 125 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 136 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; | 126 DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; |
| 137 DCHECK(reset_cb_.is_null()); | 127 DCHECK(reset_cb_.is_null()); |
| 138 DCHECK(stop_cb_.is_null()); | 128 DCHECK(stop_cb_.is_null()); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 state_ = STATE_STOPPED; | 199 state_ = STATE_STOPPED; |
| 210 stream_ = NULL; | 200 stream_ = NULL; |
| 211 decoder_.reset(); | 201 decoder_.reset(); |
| 212 decrypting_demuxer_stream_.reset(); | 202 decrypting_demuxer_stream_.reset(); |
| 213 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); | 203 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); |
| 214 } | 204 } |
| 215 | 205 |
| 216 template <DemuxerStream::Type StreamType> | 206 template <DemuxerStream::Type StreamType> |
| 217 bool DecoderStream<StreamType>::CanReadWithoutStalling() const { | 207 bool DecoderStream<StreamType>::CanReadWithoutStalling() const { |
| 218 DCHECK(task_runner_->BelongsToCurrentThread()); | 208 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 219 return decoder_->CanReadWithoutStalling(); | 209 return decoder_->CanReadWithoutStalling(); |
|
xhwang
2014/05/29 22:15:14
!ready_outputs_.empty() || decoder_->CanReadWithou
Sergey Ulanov
2014/06/03 00:08:11
Done.
| |
| 220 } | 210 } |
| 221 | 211 |
| 222 template <> | 212 template <> |
| 223 bool DecoderStream<DemuxerStream::AUDIO>::CanReadWithoutStalling() const { | 213 bool DecoderStream<DemuxerStream::AUDIO>::CanReadWithoutStalling() const { |
| 224 DCHECK(task_runner_->BelongsToCurrentThread()); | 214 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 225 return true; | 215 return true; |
| 226 } | 216 } |
| 227 | 217 |
| 228 template <DemuxerStream::Type StreamType> | 218 template <DemuxerStream::Type StreamType> |
| 229 bool DecoderStream<StreamType>::CanDecodeMore() const { | 219 bool DecoderStream<StreamType>::CanDecodeMore() const { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 DCHECK(CanDecodeMore()); | 283 DCHECK(CanDecodeMore()); |
| 294 DCHECK(reset_cb_.is_null()); | 284 DCHECK(reset_cb_.is_null()); |
| 295 DCHECK(stop_cb_.is_null()); | 285 DCHECK(stop_cb_.is_null()); |
| 296 DCHECK(buffer); | 286 DCHECK(buffer); |
| 297 | 287 |
| 298 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); | 288 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); |
| 299 | 289 |
| 300 TRACE_EVENT_ASYNC_BEGIN0("media", GetTraceString<StreamType>(), this); | 290 TRACE_EVENT_ASYNC_BEGIN0("media", GetTraceString<StreamType>(), this); |
| 301 ++pending_decode_requests_; | 291 ++pending_decode_requests_; |
| 302 decoder_->Decode(buffer, | 292 decoder_->Decode(buffer, |
| 303 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady, | 293 base::Bind(&DecoderStream<StreamType>::OnDecodeDone, |
| 304 weak_factory_.GetWeakPtr(), | 294 weak_factory_.GetWeakPtr(), |
| 305 buffer_size)); | 295 buffer_size, |
| 296 buffer->end_of_stream())); | |
| 306 } | 297 } |
| 307 | 298 |
| 308 template <DemuxerStream::Type StreamType> | 299 template <DemuxerStream::Type StreamType> |
| 309 void DecoderStream<StreamType>::FlushDecoder() { | 300 void DecoderStream<StreamType>::FlushDecoder() { |
| 310 if (pending_decode_requests_ == 0) | 301 Decode(DecoderBuffer::CreateEOSBuffer()); |
| 311 Decode(DecoderBuffer::CreateEOSBuffer()); | |
| 312 } | 302 } |
| 313 | 303 |
| 314 template <DemuxerStream::Type StreamType> | 304 template <DemuxerStream::Type StreamType> |
| 315 void DecoderStream<StreamType>::OnDecodeOutputReady( | 305 void DecoderStream<StreamType>::OnDecodeDone(int buffer_size, |
| 316 int buffer_size, | 306 bool end_of_stream, |
| 317 typename Decoder::Status status, | 307 typename Decoder::Status status) { |
| 318 const scoped_refptr<Output>& output) { | 308 FUNCTION_DVLOG(2) << status; |
| 319 FUNCTION_DVLOG(2) << status << " " << output; | |
| 320 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || | 309 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || |
| 321 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) | 310 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) |
| 322 << state_; | 311 << state_; |
| 323 DCHECK(stop_cb_.is_null()); | 312 DCHECK(stop_cb_.is_null()); |
| 324 DCHECK_EQ(status == Decoder::kOk, output != NULL); | |
| 325 DCHECK_GT(pending_decode_requests_, 0); | 313 DCHECK_GT(pending_decode_requests_, 0); |
| 326 | 314 |
| 327 --pending_decode_requests_; | 315 --pending_decode_requests_; |
| 328 | 316 |
| 329 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this); | 317 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this); |
| 330 | 318 |
| 331 if (state_ == STATE_ERROR) { | 319 if (state_ == STATE_ERROR) { |
| 332 DCHECK(read_cb_.is_null()); | 320 DCHECK(read_cb_.is_null()); |
| 333 return; | 321 return; |
| 334 } | 322 } |
| 335 | 323 |
| 336 if (status == Decoder::kDecodeError) { | 324 // Drop decoding result if Reset() was called during decoding. |
| 337 state_ = STATE_ERROR; | 325 // The resetting process will be handled when the decoder is reset. |
| 338 ready_outputs_.clear(); | 326 if (!reset_cb_.is_null()) |
| 339 if (!read_cb_.is_null()) | 327 return; |
| 340 SatisfyRead(DECODE_ERROR, NULL); | 328 |
| 329 switch (status) { | |
| 330 case Decoder::kDecodeError: | |
| 331 state_ = STATE_ERROR; | |
| 332 ready_outputs_.clear(); | |
| 333 if (!read_cb_.is_null()) | |
| 334 SatisfyRead(DECODE_ERROR, NULL); | |
| 335 break; | |
| 336 | |
| 337 case Decoder::kDecryptError: | |
| 338 state_ = STATE_ERROR; | |
| 339 ready_outputs_.clear(); | |
| 340 if (!read_cb_.is_null()) | |
| 341 SatisfyRead(DECRYPT_ERROR, NULL); | |
| 342 break; | |
|
xhwang
2014/05/29 22:15:14
nit: DECRYPT_ERROR is going to be obsolete. Feel f
Sergey Ulanov
2014/06/03 00:08:11
Done.
| |
| 343 | |
| 344 case Decoder::kAborted: | |
|
xhwang
2014/05/29 22:15:14
IIUIC, This should only happen during Reset(), whi
Sergey Ulanov
2014/06/03 00:08:11
No. This came up with a previous CL as well: https
xhwang
2014/06/05 21:53:48
hmm... Thanks for reminding me of that discussion!
Sergey Ulanov
2014/06/06 22:49:39
Done.
| |
| 345 if (!read_cb_.is_null()) | |
| 346 SatisfyRead(ABORTED, NULL); | |
| 347 break; | |
| 348 | |
| 349 case Decoder::kOk: | |
| 350 // Any successful decode counts! | |
| 351 if (buffer_size > 0) { | |
| 352 StreamTraits::ReportStatistics(statistics_cb_, buffer_size); | |
| 353 } | |
| 354 | |
| 355 if (state_ == STATE_NORMAL) { | |
| 356 if (CanDecodeMore() && !end_of_stream) | |
| 357 ReadFromDemuxerStream(); | |
| 358 } else if (state_ == STATE_FLUSHING_DECODER) { | |
| 359 if (!pending_decode_requests_) | |
| 360 ReinitializeDecoder(); | |
|
xhwang
2014/05/29 22:15:14
Hmm, we should only ReinitializeDecoder() after th
Sergey Ulanov
2014/06/03 00:08:11
ReinitializeDecoder() should be called only after
xhwang
2014/06/05 21:53:48
Now I understand that comment. Thanks.
| |
| 361 } | |
| 362 break; | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 template <DemuxerStream::Type StreamType> | |
| 367 void DecoderStream<StreamType>::OnDecodeOutputReady( | |
| 368 const scoped_refptr<Output>& output) { | |
| 369 FUNCTION_DVLOG(2) << output; | |
| 370 DCHECK(output); | |
| 371 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || | |
| 372 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) | |
| 373 << state_; | |
| 374 | |
| 375 if (state_ == STATE_ERROR) { | |
| 376 DCHECK(read_cb_.is_null()); | |
| 341 return; | 377 return; |
| 342 } | 378 } |
| 343 | 379 |
| 344 if (status == Decoder::kDecryptError) { | |
| 345 state_ = STATE_ERROR; | |
| 346 ready_outputs_.clear(); | |
| 347 if (!read_cb_.is_null()) | |
| 348 SatisfyRead(DECRYPT_ERROR, NULL); | |
| 349 return; | |
| 350 } | |
| 351 | |
| 352 if (status == Decoder::kAborted) { | |
| 353 if (!read_cb_.is_null()) | |
| 354 SatisfyRead(ABORTED, NULL); | |
| 355 return; | |
| 356 } | |
| 357 | |
| 358 // Any successful decode counts! | |
| 359 if (buffer_size > 0) { | |
| 360 StreamTraits::ReportStatistics(statistics_cb_, buffer_size); | |
| 361 } | |
| 362 | |
| 363 // Drop decoding result if Reset() was called during decoding. | 380 // Drop decoding result if Reset() was called during decoding. |
| 364 // The resetting process will be handled when the decoder is reset. | 381 // The resetting process will be handled when the decoder is reset. |
| 365 if (!reset_cb_.is_null()) | 382 if (!reset_cb_.is_null()) |
| 366 return; | 383 return; |
| 367 | 384 |
| 368 // Decoder flushed. Reinitialize the decoder. | 385 if (state_ == STATE_FLUSHING_DECODER && output->end_of_stream()) { |
| 369 if (state_ == STATE_FLUSHING_DECODER && | 386 // ReinitializeDecoder() will be called from OnDecodeDone(). |
|
xhwang
2014/05/29 22:15:14
See comment above about when to ReinitializeDecode
Sergey Ulanov
2014/06/03 00:08:11
See my comment - it's better to keep it in OnDecod
| |
| 370 status == Decoder::kOk && output->end_of_stream()) { | |
| 371 ReinitializeDecoder(); | |
| 372 return; | 387 return; |
| 373 } | 388 } |
| 374 | 389 |
| 375 if (status == Decoder::kNotEnoughData) { | |
| 376 if (state_ == STATE_NORMAL) | |
| 377 ReadFromDemuxerStream(); | |
| 378 else if (state_ == STATE_FLUSHING_DECODER) | |
| 379 FlushDecoder(); | |
| 380 return; | |
| 381 } | |
| 382 | |
| 383 DCHECK(output); | |
| 384 | |
| 385 // Store decoded output. | 390 // Store decoded output. |
| 386 ready_outputs_.push_back(output); | 391 ready_outputs_.push_back(output); |
| 387 scoped_refptr<Output> extra_output; | |
| 388 while ((extra_output = decoder_->GetDecodeOutput()) != NULL) { | |
| 389 ready_outputs_.push_back(extra_output); | |
| 390 } | |
| 391 | 392 |
| 392 // Satisfy outstanding read request, if any. | 393 // Satisfy outstanding read request, if any. |
| 393 if (!read_cb_.is_null()) { | 394 if (!read_cb_.is_null()) { |
| 394 scoped_refptr<Output> read_result = ready_outputs_.front(); | 395 scoped_refptr<Output> read_result = ready_outputs_.front(); |
| 395 ready_outputs_.pop_front(); | 396 ready_outputs_.pop_front(); |
| 396 SatisfyRead(OK, output); | 397 SatisfyRead(OK, output); |
| 397 } | 398 } |
| 398 } | 399 } |
| 399 | 400 |
| 400 template <DemuxerStream::Type StreamType> | 401 template <DemuxerStream::Type StreamType> |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 | 454 |
| 454 if (!reset_cb_.is_null()) { | 455 if (!reset_cb_.is_null()) { |
| 455 // If we are using DecryptingDemuxerStream, we already called DDS::Reset() | 456 // If we are using DecryptingDemuxerStream, we already called DDS::Reset() |
| 456 // which will continue the resetting process in it's callback. | 457 // which will continue the resetting process in it's callback. |
| 457 if (!decrypting_demuxer_stream_) | 458 if (!decrypting_demuxer_stream_) |
| 458 Reset(base::ResetAndReturn(&reset_cb_)); | 459 Reset(base::ResetAndReturn(&reset_cb_)); |
| 459 return; | 460 return; |
| 460 } | 461 } |
| 461 | 462 |
| 462 if (status == DemuxerStream::kAborted) { | 463 if (status == DemuxerStream::kAborted) { |
| 463 SatisfyRead(DEMUXER_READ_ABORTED, NULL); | 464 SatisfyRead(DEMUXER_READ_ABORTED, NULL); |
|
xhwang
2014/06/05 21:53:48
hmm, actually, shall we check whether read_cb_.is_
| |
| 464 return; | 465 return; |
| 465 } | 466 } |
| 466 | 467 |
| 467 if (!splice_observer_cb_.is_null() && !buffer->end_of_stream()) { | 468 if (!splice_observer_cb_.is_null() && !buffer->end_of_stream()) { |
| 468 const bool has_splice_ts = buffer->splice_timestamp() != kNoTimestamp(); | 469 const bool has_splice_ts = buffer->splice_timestamp() != kNoTimestamp(); |
| 469 if (active_splice_ || has_splice_ts) { | 470 if (active_splice_ || has_splice_ts) { |
| 470 splice_observer_cb_.Run(buffer->splice_timestamp()); | 471 splice_observer_cb_.Run(buffer->splice_timestamp()); |
| 471 active_splice_ = has_splice_ts; | 472 active_splice_ = has_splice_ts; |
| 472 } | 473 } |
| 473 } | 474 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 487 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; | 488 DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; |
| 488 DCHECK_EQ(pending_decode_requests_, 0); | 489 DCHECK_EQ(pending_decode_requests_, 0); |
| 489 | 490 |
| 490 DCHECK(StreamTraits::GetDecoderConfig(*stream_).IsValidConfig()); | 491 DCHECK(StreamTraits::GetDecoderConfig(*stream_).IsValidConfig()); |
| 491 state_ = STATE_REINITIALIZING_DECODER; | 492 state_ = STATE_REINITIALIZING_DECODER; |
| 492 DecoderStreamTraits<StreamType>::Initialize( | 493 DecoderStreamTraits<StreamType>::Initialize( |
| 493 decoder_.get(), | 494 decoder_.get(), |
| 494 StreamTraits::GetDecoderConfig(*stream_), | 495 StreamTraits::GetDecoderConfig(*stream_), |
| 495 low_delay_, | 496 low_delay_, |
| 496 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized, | 497 base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized, |
| 498 weak_factory_.GetWeakPtr()), | |
| 499 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady, | |
| 497 weak_factory_.GetWeakPtr())); | 500 weak_factory_.GetWeakPtr())); |
| 498 } | 501 } |
| 499 | 502 |
| 500 template <DemuxerStream::Type StreamType> | 503 template <DemuxerStream::Type StreamType> |
| 501 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) { | 504 void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) { |
| 502 FUNCTION_DVLOG(2); | 505 FUNCTION_DVLOG(2); |
| 503 DCHECK(task_runner_->BelongsToCurrentThread()); | 506 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 504 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_; | 507 DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER) << state_; |
| 505 DCHECK(stop_cb_.is_null()); | 508 DCHECK(stop_cb_.is_null()); |
| 506 | 509 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 decrypting_demuxer_stream_.reset(); | 578 decrypting_demuxer_stream_.reset(); |
| 576 // Post |stop_cb_| because pending |read_cb_| and/or |reset_cb_| are also | 579 // Post |stop_cb_| because pending |read_cb_| and/or |reset_cb_| are also |
| 577 // posted in Stop(). | 580 // posted in Stop(). |
| 578 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); | 581 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); |
| 579 } | 582 } |
| 580 | 583 |
| 581 template class DecoderStream<DemuxerStream::VIDEO>; | 584 template class DecoderStream<DemuxerStream::VIDEO>; |
| 582 template class DecoderStream<DemuxerStream::AUDIO>; | 585 template class DecoderStream<DemuxerStream::AUDIO>; |
| 583 | 586 |
| 584 } // namespace media | 587 } // namespace media |
| OLD | NEW |