Chromium Code Reviews| Index: media/filters/fake_video_decoder.cc |
| diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc |
| index 0f171999783f161a65bf38c2662f76d15655ad6b..e2c2e5092277496429252afdb09af37d8312fd7b 100644 |
| --- a/media/filters/fake_video_decoder.cc |
| +++ b/media/filters/fake_video_decoder.cc |
| @@ -14,11 +14,13 @@ |
| namespace media { |
| FakeVideoDecoder::FakeVideoDecoder(int decoding_delay, |
| - bool supports_get_decode_output) |
| - : task_runner_(base::MessageLoopProxy::current()), |
| - decoding_delay_(decoding_delay), |
| + bool supports_get_decode_output, |
| + int max_parallel_decoding_requests) |
| + : decoding_delay_(decoding_delay), |
| supports_get_decode_output_(supports_get_decode_output), |
| + max_parallel_decoding_requests_(max_parallel_decoding_requests), |
| state_(UNINITIALIZED), |
| + hold_decode_(false), |
| total_bytes_decoded_(0), |
| weak_factory_(this) { |
| DCHECK_GE(decoding_delay, 0); |
| @@ -30,9 +32,10 @@ FakeVideoDecoder::~FakeVideoDecoder() { |
| void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| const PipelineStatusCB& status_cb) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(config.IsValidConfig()); |
| - DCHECK(decode_cb_.IsNull()) << "No reinitialization during pending decode."; |
| + DCHECK(held_decode_callbacks_.empty()) |
| + << "No reinitialization during pending decode."; |
| DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset."; |
| current_config_ = config; |
| @@ -49,58 +52,58 @@ void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| void FakeVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| const DecodeCB& decode_cb) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(decode_cb_.IsNull()) << "Overlapping decodes are not supported."; |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(reset_cb_.IsNull()); |
| - DCHECK_LE(decoded_frames_.size(), static_cast<size_t>(decoding_delay_)); |
| + DCHECK_LE( |
| + decoded_frames_.size(), |
| + static_cast<size_t>(decoding_delay_) + max_parallel_decoding_requests_); |
| + DCHECK_LT(static_cast<int>(held_decode_callbacks_.size()), |
| + max_parallel_decoding_requests_); |
| int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); |
| - decode_cb_.SetCallback( |
| + DecodeCB wrapped_decode_cb = |
| BindToCurrentLoop(base::Bind(&FakeVideoDecoder::OnFrameDecoded, |
| weak_factory_.GetWeakPtr(), |
| buffer_size, |
| - decode_cb))); |
| + decode_cb)); |
| - if (buffer->end_of_stream() && decoded_frames_.empty()) { |
| - decode_cb_.RunOrHold(kOk, VideoFrame::CreateEOSFrame()); |
| + if (state_ == ERROR) { |
| + wrapped_decode_cb.Run(kDecodeError, scoped_refptr<VideoFrame>()); |
| return; |
| } |
| - if (!buffer->end_of_stream()) { |
| + if (buffer->end_of_stream()) { |
| + state_ = END_OF_STREAM; |
| + } else { |
| DCHECK(VerifyFakeVideoBufferForTest(buffer, current_config_)); |
| scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateColorFrame( |
| current_config_.coded_size(), 0, 0, 0, buffer->timestamp()); |
| decoded_frames_.push_back(video_frame); |
| - |
| - if (decoded_frames_.size() <= static_cast<size_t>(decoding_delay_)) { |
| - decode_cb_.RunOrHold(kNotEnoughData, scoped_refptr<VideoFrame>()); |
| - return; |
| - } |
| } |
| - scoped_refptr<VideoFrame> frame = decoded_frames_.front(); |
| - decoded_frames_.pop_front(); |
| - decode_cb_.RunOrHold(kOk, frame); |
| + RunOrHoldDecode(wrapped_decode_cb); |
| } |
| void FakeVideoDecoder::Reset(const base::Closure& closure) { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(reset_cb_.IsNull()); |
| + |
| reset_cb_.SetCallback(BindToCurrentLoop(closure)); |
| + decoded_frames_.clear(); |
| // Defer the reset if a decode is pending. |
| - if (!decode_cb_.IsNull()) |
| + if (!held_decode_callbacks_.empty()) |
| return; |
| DoReset(); |
| } |
| void FakeVideoDecoder::Stop() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| if (!init_cb_.IsNull()) |
| SatisfyInit(); |
| - if (!decode_cb_.IsNull()) |
| + if (!held_decode_callbacks_.empty()) |
| SatisfyDecode(); |
| if (!reset_cb_.IsNull()) |
| SatisfyReset(); |
| @@ -110,7 +113,7 @@ void FakeVideoDecoder::Stop() { |
| } |
| scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| if (!supports_get_decode_output_ || decoded_frames_.empty()) |
| return NULL; |
| scoped_refptr<VideoFrame> out = decoded_frames_.front(); |
| @@ -119,49 +122,70 @@ scoped_refptr<VideoFrame> FakeVideoDecoder::GetDecodeOutput() { |
| } |
| void FakeVideoDecoder::HoldNextInit() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| init_cb_.HoldCallback(); |
| } |
| -void FakeVideoDecoder::HoldNextDecode() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - decode_cb_.HoldCallback(); |
| +void FakeVideoDecoder::HoldDecode() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + hold_decode_ = true; |
| } |
| void FakeVideoDecoder::HoldNextReset() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| reset_cb_.HoldCallback(); |
| } |
| void FakeVideoDecoder::SatisfyInit() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(decode_cb_.IsNull()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(held_decode_callbacks_.empty()); |
| DCHECK(reset_cb_.IsNull()); |
| init_cb_.RunHeldCallback(); |
| } |
| void FakeVideoDecoder::SatisfyDecode() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - decode_cb_.RunHeldCallback(); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK_NE(hold_decode_, 0); |
| - if (!reset_cb_.IsNull()) |
| + hold_decode_ = 0; |
| + |
| + while (!held_decode_callbacks_.empty()) { |
| + SatisfySingleDecode(); |
| + } |
| +} |
| + |
| +void FakeVideoDecoder::SatisfySingleDecode() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(!held_decode_callbacks_.empty()); |
| + |
| + RunDecodeCallback(held_decode_callbacks_.front()); |
| + held_decode_callbacks_.pop_front(); |
| + |
| + if (!reset_cb_.IsNull() && held_decode_callbacks_.empty()) |
| DoReset(); |
| } |
| void FakeVideoDecoder::SatisfyReset() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(decode_cb_.IsNull()); |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(held_decode_callbacks_.empty()); |
| reset_cb_.RunHeldCallback(); |
| } |
| -void FakeVideoDecoder::DoReset() { |
| - DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(decode_cb_.IsNull()); |
| - DCHECK(!reset_cb_.IsNull()); |
| +void FakeVideoDecoder::SimulateError() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + state_ = ERROR; |
| + while (!held_decode_callbacks_.empty()) { |
| + held_decode_callbacks_.front().Run(kDecodeError, |
| + scoped_refptr<VideoFrame>()); |
| + held_decode_callbacks_.pop_front(); |
| + } |
| decoded_frames_.clear(); |
| - reset_cb_.RunOrHold(); |
| +} |
| + |
| +int FakeVideoDecoder::GetMaxDecodeRequests() const { |
| + return max_parallel_decoding_requests_; |
| } |
| void FakeVideoDecoder::OnFrameDecoded( |
| @@ -169,9 +193,52 @@ void FakeVideoDecoder::OnFrameDecoded( |
| const DecodeCB& decode_cb, |
| Status status, |
| const scoped_refptr<VideoFrame>& video_frame) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| if (status == kOk || status == kNotEnoughData) |
| total_bytes_decoded_ += buffer_size; |
| decode_cb.Run(status, video_frame); |
| } |
| +void FakeVideoDecoder::RunOrHoldDecode(const DecodeCB& decode_cb) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + if (hold_decode_) { |
| + held_decode_callbacks_.push_back(decode_cb); |
| + } else { |
|
xhwang
2014/04/25 00:36:03
DCHECK(held_decode_callbacks_.empty());
We should
Sergey Ulanov
2014/04/26 00:59:29
Done.
|
| + RunDecodeCallback(decode_cb); |
| + } |
| +} |
| + |
| +void FakeVideoDecoder::RunDecodeCallback(const DecodeCB& decode_cb) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + if (!reset_cb_.IsNull()) { |
|
xhwang
2014/04/25 00:36:03
DCHECK(decoded_frames_.empty());
Sergey Ulanov
2014/04/26 00:59:29
Done.
|
| + decode_cb.Run(kAborted, scoped_refptr<VideoFrame>()); |
| + return; |
| + } |
| + if (static_cast<int>(decoded_frames_.size()) <= decoding_delay_ && |
|
xhwang
2014/04/25 00:36:03
The two cases we use |decoding_delay_| both involv
Sergey Ulanov
2014/04/26 00:59:29
Done.
|
| + state_ != END_OF_STREAM) { |
| + decode_cb.Run(kNotEnoughData, scoped_refptr<VideoFrame>()); |
|
xhwang
2014/04/25 00:36:03
Return early here then we don't need the "else" in
Sergey Ulanov
2014/04/26 00:59:29
Done.
|
| + } else { |
| + scoped_refptr<VideoFrame> frame; |
| + if (decoded_frames_.empty()) { |
| + DCHECK_EQ(state_, END_OF_STREAM); |
| + frame = VideoFrame::CreateEOSFrame(); |
| + } else { |
| + frame = decoded_frames_.front(); |
| + decoded_frames_.pop_front(); |
| + } |
| + decode_cb.Run(kOk, frame); |
| + } |
| +} |
| + |
| +void FakeVideoDecoder::DoReset() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(held_decode_callbacks_.empty()); |
| + DCHECK(!reset_cb_.IsNull()); |
| + |
| + reset_cb_.RunOrHold(); |
| +} |
| + |
| } // namespace media |