X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fmedia%2Ffilters%2Fdecoder_stream.cc;h=4f712be2f2227883e37710fd9ae5a1b6b9bd9751;hb=004985e17e624662a4c85c76a7654039dc83f028;hp=2863d228eb526538cf48b3cf2b4edd830f39a2d4;hpb=2f108dbacb161091e42a3479f4e171339b7e7623;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/media/filters/decoder_stream.cc b/src/media/filters/decoder_stream.cc index 2863d22..4f712be 100644 --- a/src/media/filters/decoder_stream.cc +++ b/src/media/filters/decoder_stream.cc @@ -50,6 +50,8 @@ DecoderStream::DecoderStream( new DecoderSelector(task_runner, decoders.Pass(), set_decryptor_ready_cb)), + active_splice_(false), + pending_decode_requests_(0), weak_factory_(this) {} template @@ -59,6 +61,7 @@ DecoderStream::~DecoderStream() { template void DecoderStream::Initialize(DemuxerStream* stream, + bool low_delay, const StatisticsCB& statistics_cb, const InitCB& init_cb) { FUNCTION_DVLOG(2); @@ -70,11 +73,12 @@ void DecoderStream::Initialize(DemuxerStream* stream, statistics_cb_ = statistics_cb; init_cb_ = init_cb; stream_ = stream; + low_delay_ = low_delay; state_ = STATE_INITIALIZING; // TODO(xhwang): DecoderSelector only needs a config to select a decoder. decoder_selector_->SelectDecoder( - stream, + stream, low_delay, base::Bind(&DecoderStream::OnDecoderSelected, weak_factory_.GetWeakPtr())); } @@ -84,36 +88,45 @@ void DecoderStream::Read(const ReadCB& read_cb) { FUNCTION_DVLOG(2); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || - state_ == STATE_ERROR) << state_; + state_ == STATE_ERROR || state_ == STATE_REINITIALIZING_DECODER || + state_ == STATE_PENDING_DEMUXER_READ) + << state_; // No two reads in the flight at any time. DCHECK(read_cb_.is_null()); // No read during resetting or stopping process. DCHECK(reset_cb_.is_null()); DCHECK(stop_cb_.is_null()); + read_cb_ = read_cb; + if (state_ == STATE_ERROR) { - task_runner_->PostTask(FROM_HERE, base::Bind( - read_cb, DECODE_ERROR, scoped_refptr())); + task_runner_->PostTask(FROM_HERE, + base::Bind(base::ResetAndReturn(&read_cb_), + DECODE_ERROR, + scoped_refptr())); return; } - read_cb_ = read_cb; + if (!ready_outputs_.empty()) { + task_runner_->PostTask(FROM_HERE, base::Bind( + base::ResetAndReturn(&read_cb_), OK, ready_outputs_.front())); + ready_outputs_.pop_front(); + } - if (state_ == STATE_FLUSHING_DECODER) { - FlushDecoder(); + // Decoder may be in reinitializing state as result of the previous Read(). + if (state_ == STATE_REINITIALIZING_DECODER) return; - } - scoped_refptr output = decoder_->GetDecodeOutput(); + if (!CanDecodeMore()) + return; - // If the decoder has queued output ready to go we don't need a demuxer read. - if (output) { - task_runner_->PostTask( - FROM_HERE, base::Bind(base::ResetAndReturn(&read_cb_), OK, output)); + if (state_ == STATE_FLUSHING_DECODER) { + FlushDecoder(); return; } - ReadFromDemuxerStream(); + if (state_ != STATE_PENDING_DEMUXER_READ) + ReadFromDemuxerStream(); } template @@ -126,6 +139,13 @@ void DecoderStream::Reset(const base::Closure& closure) { reset_cb_ = closure; + if (!read_cb_.is_null()) { + task_runner_->PostTask(FROM_HERE, base::Bind( + base::ResetAndReturn(&read_cb_), ABORTED, scoped_refptr())); + } + + ready_outputs_.clear(); + // During decoder reinitialization, the Decoder does not need to be and // cannot be Reset(). |decrypting_demuxer_stream_| was reset before decoder // reinitialization. @@ -138,11 +158,6 @@ void DecoderStream::Reset(const base::Closure& closure) { if (state_ == STATE_PENDING_DEMUXER_READ && !decrypting_demuxer_stream_) return; - // The Decoder API guarantees that if Decoder::Reset() is called during - // a pending decode, the decode callback must be fired before the reset - // callback is fired. Therefore, we can call Decoder::Reset() regardless - // of if we have a pending decode and always satisfy the reset callback when - // the decoder reset is finished. if (decrypting_demuxer_stream_) { decrypting_demuxer_stream_->Reset(base::Bind( &DecoderStream::ResetDecoder, weak_factory_.GetWeakPtr())); @@ -172,9 +187,10 @@ void DecoderStream::Stop(const base::Closure& closure) { weak_factory_.InvalidateWeakPtrs(); // Post callbacks to prevent reentrance into this object. - if (!read_cb_.is_null()) + if (!read_cb_.is_null()) { task_runner_->PostTask(FROM_HERE, base::Bind( base::ResetAndReturn(&read_cb_), ABORTED, scoped_refptr())); + } if (!reset_cb_.is_null()) task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_)); @@ -210,6 +226,24 @@ bool DecoderStream::CanReadWithoutStalling() const { } template +bool DecoderStream::CanDecodeMore() const { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // Limit total number of outputs stored in |ready_outputs_| and being decoded. + // It only makes sense to saturate decoder completely when output queue is + // empty. + int num_decodes = + static_cast(ready_outputs_.size()) + pending_decode_requests_; + return num_decodes < decoder_->GetMaxDecodeRequests(); +} + +template <> +bool DecoderStream::CanDecodeMore() const { + DCHECK(task_runner_->BelongsToCurrentThread()); + return !pending_decode_requests_ && ready_outputs_.empty(); +} + +template void DecoderStream::OnDecoderSelected( scoped_ptr selected_decoder, scoped_ptr decrypting_demuxer_stream) { @@ -252,22 +286,11 @@ void DecoderStream::SatisfyRead( } template -void DecoderStream::AbortRead() { - // Abort read during pending reset. It is safe to fire the |read_cb_| directly - // instead of posting it because the renderer won't call into this class - // again when it's in kFlushing state. - // TODO(xhwang): Improve the resetting process to avoid this dependency on the - // caller. - DCHECK(!reset_cb_.is_null()); - SatisfyRead(ABORTED, NULL); -} - -template void DecoderStream::Decode( const scoped_refptr& buffer) { FUNCTION_DVLOG(2); DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER) << state_; - DCHECK(!read_cb_.is_null()); + DCHECK(CanDecodeMore()); DCHECK(reset_cb_.is_null()); DCHECK(stop_cb_.is_null()); DCHECK(buffer); @@ -275,6 +298,7 @@ void DecoderStream::Decode( int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); TRACE_EVENT_ASYNC_BEGIN0("media", GetTraceString(), this); + ++pending_decode_requests_; decoder_->Decode(buffer, base::Bind(&DecoderStream::OnDecodeOutputReady, weak_factory_.GetWeakPtr(), @@ -283,7 +307,8 @@ void DecoderStream::Decode( template void DecoderStream::FlushDecoder() { - Decode(DecoderBuffer::CreateEOSBuffer()); + if (pending_decode_requests_ == 0) + Decode(DecoderBuffer::CreateEOSBuffer()); } template @@ -291,28 +316,42 @@ void DecoderStream::OnDecodeOutputReady( int buffer_size, typename Decoder::Status status, const scoped_refptr& output) { - FUNCTION_DVLOG(2); - DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER) << state_; - DCHECK(!read_cb_.is_null()); + FUNCTION_DVLOG(2) << status << " " << output; + DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || + state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) + << state_; DCHECK(stop_cb_.is_null()); DCHECK_EQ(status == Decoder::kOk, output != NULL); + DCHECK_GT(pending_decode_requests_, 0); + + --pending_decode_requests_; TRACE_EVENT_ASYNC_END0("media", GetTraceString(), this); + if (state_ == STATE_ERROR) { + DCHECK(read_cb_.is_null()); + return; + } + if (status == Decoder::kDecodeError) { state_ = STATE_ERROR; - SatisfyRead(DECODE_ERROR, NULL); + ready_outputs_.clear(); + if (!read_cb_.is_null()) + SatisfyRead(DECODE_ERROR, NULL); return; } if (status == Decoder::kDecryptError) { state_ = STATE_ERROR; - SatisfyRead(DECRYPT_ERROR, NULL); + ready_outputs_.clear(); + if (!read_cb_.is_null()) + SatisfyRead(DECRYPT_ERROR, NULL); return; } if (status == Decoder::kAborted) { - SatisfyRead(ABORTED, NULL); + if (!read_cb_.is_null()) + SatisfyRead(ABORTED, NULL); return; } @@ -323,10 +362,8 @@ void DecoderStream::OnDecodeOutputReady( // Drop decoding result if Reset() was called during decoding. // The resetting process will be handled when the decoder is reset. - if (!reset_cb_.is_null()) { - AbortRead(); + if (!reset_cb_.is_null()) return; - } // Decoder flushed. Reinitialize the decoder. if (state_ == STATE_FLUSHING_DECODER && @@ -344,14 +381,27 @@ void DecoderStream::OnDecodeOutputReady( } DCHECK(output); - SatisfyRead(OK, output); + + // Store decoded output. + ready_outputs_.push_back(output); + scoped_refptr extra_output; + while ((extra_output = decoder_->GetDecodeOutput()) != NULL) { + ready_outputs_.push_back(extra_output); + } + + // Satisfy outstanding read request, if any. + if (!read_cb_.is_null()) { + scoped_refptr read_result = ready_outputs_.front(); + ready_outputs_.pop_front(); + SatisfyRead(OK, output); + } } template void DecoderStream::ReadFromDemuxerStream() { FUNCTION_DVLOG(2); DCHECK_EQ(state_, STATE_NORMAL) << state_; - DCHECK(!read_cb_.is_null()); + DCHECK(CanDecodeMore()); DCHECK(reset_cb_.is_null()); DCHECK(stop_cb_.is_null()); @@ -366,11 +416,19 @@ void DecoderStream::OnBufferReady( const scoped_refptr& buffer) { FUNCTION_DVLOG(2) << ": " << status; DCHECK(task_runner_->BelongsToCurrentThread()); - DCHECK_EQ(state_, STATE_PENDING_DEMUXER_READ) << state_; + DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR || + state_ == STATE_STOPPED) + << state_; DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status; - DCHECK(!read_cb_.is_null()); DCHECK(stop_cb_.is_null()); + // Decoding has been stopped (e.g due to an error). + if (state_ != STATE_PENDING_DEMUXER_READ) { + DCHECK(state_ == STATE_ERROR || state_ == STATE_STOPPED); + DCHECK(read_cb_.is_null()); + return; + } + state_ = STATE_NORMAL; if (status == DemuxerStream::kConfigChanged) { @@ -382,7 +440,6 @@ void DecoderStream::OnBufferReady( state_ = STATE_FLUSHING_DECODER; if (!reset_cb_.is_null()) { - AbortRead(); // If we are using DecryptingDemuxerStream, we already called DDS::Reset() // which will continue the resetting process in it's callback. if (!decrypting_demuxer_stream_) @@ -395,7 +452,6 @@ void DecoderStream::OnBufferReady( } if (!reset_cb_.is_null()) { - AbortRead(); // If we are using DecryptingDemuxerStream, we already called DDS::Reset() // which will continue the resetting process in it's callback. if (!decrypting_demuxer_stream_) @@ -408,13 +464,20 @@ void DecoderStream::OnBufferReady( return; } - if (!splice_observer_cb_.is_null() && !buffer->end_of_stream() && - buffer->splice_timestamp() != kNoTimestamp()) { - splice_observer_cb_.Run(buffer->splice_timestamp()); + if (!splice_observer_cb_.is_null() && !buffer->end_of_stream()) { + const bool has_splice_ts = buffer->splice_timestamp() != kNoTimestamp(); + if (active_splice_ || has_splice_ts) { + splice_observer_cb_.Run(buffer->splice_timestamp()); + active_splice_ = has_splice_ts; + } } DCHECK(status == DemuxerStream::kOk) << status; Decode(buffer); + + // Read more data if the decoder supports multiple parallel decoding requests. + if (CanDecodeMore() && !buffer->end_of_stream()) + ReadFromDemuxerStream(); } template @@ -422,11 +485,14 @@ void DecoderStream::ReinitializeDecoder() { FUNCTION_DVLOG(2); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, STATE_FLUSHING_DECODER) << state_; + DCHECK_EQ(pending_decode_requests_, 0); DCHECK(StreamTraits::GetDecoderConfig(*stream_).IsValidConfig()); state_ = STATE_REINITIALIZING_DECODER; - decoder_->Initialize( + DecoderStreamTraits::Initialize( + decoder_.get(), StreamTraits::GetDecoderConfig(*stream_), + low_delay_, base::Bind(&DecoderStream::OnDecoderReinitialized, weak_factory_.GetWeakPtr())); } @@ -447,9 +513,8 @@ void DecoderStream::OnDecoderReinitialized(PipelineStatus status) { state_ = (status == PIPELINE_OK) ? STATE_NORMAL : STATE_ERROR; if (!reset_cb_.is_null()) { - if (!read_cb_.is_null()) - AbortRead(); base::ResetAndReturn(&reset_cb_).Run(); + return; } if (read_cb_.is_null()) @@ -503,26 +568,14 @@ void DecoderStream::StopDecoder() { DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; DCHECK(!stop_cb_.is_null()); - decoder_->Stop(base::Bind(&DecoderStream::OnDecoderStopped, - weak_factory_.GetWeakPtr())); -} - -template -void DecoderStream::OnDecoderStopped() { - FUNCTION_DVLOG(2); - DCHECK(task_runner_->BelongsToCurrentThread()); - DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_STOPPED) << state_; - // If Stop() was called during pending read/reset, read/reset callback should - // be fired before the stop callback is fired. - DCHECK(read_cb_.is_null()); - DCHECK(reset_cb_.is_null()); - DCHECK(!stop_cb_.is_null()); - state_ = STATE_STOPPED; + decoder_->Stop(); stream_ = NULL; decoder_.reset(); decrypting_demuxer_stream_.reset(); - base::ResetAndReturn(&stop_cb_).Run(); + // Post |stop_cb_| because pending |read_cb_| and/or |reset_cb_| are also + // posted in Stop(). + task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_)); } template class DecoderStream;