diff options
author | kmackay <kmackay@chromium.org> | 2015-10-26 10:34:04 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-26 17:34:46 +0000 |
commit | 230d84b6d23f959410afc4fb810078392efa4ab8 (patch) | |
tree | 4b872e682cabb0d3e691f2042f3d97df463bea69 | |
parent | 1d8b10f21f068a8ecb7b6d5b32968b00dd8927ae (diff) | |
download | chromium_src-230d84b6d23f959410afc4fb810078392efa4ab8.zip chromium_src-230d84b6d23f959410afc4fb810078392efa4ab8.tar.gz chromium_src-230d84b6d23f959410afc4fb810078392efa4ab8.tar.bz2 |
[Chromecast] Pass DecoderBufferBase directly to backends.
The DecryptContext for a buffer is now available via buffer->decrypt_context(), which allows us to make the decrypt context live at least as long as the buffer. Currently it is owned by the buffer.
BUG= internal b/23751784
Review URL: https://codereview.chromium.org/1425523002
Cr-Commit-Position: refs/heads/master@{#356071}
22 files changed, 123 insertions, 214 deletions
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc index 9ba059f1..e283ab0 100644 --- a/chromecast/media/audio/cast_audio_output_stream.cc +++ b/chromecast/media/audio/cast_audio_output_stream.cc @@ -12,7 +12,6 @@ #include "chromecast/base/task_runner_impl.h" #include "chromecast/media/audio/cast_audio_manager.h" #include "chromecast/media/base/media_message_loop.h" -#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h" #include "chromecast/media/cma/base/decoder_buffer_adapter.h" #include "chromecast/public/media/decoder_config.h" #include "chromecast/public/media/decrypt_context.h" @@ -67,8 +66,7 @@ class CastAudioOutputStream::Backend : public MediaPipelineBackend::Delegate { : audio_params_(audio_params), decoder_(nullptr), first_start_(true), - error_(false), - backend_buffer_(nullptr) { + error_(false) { thread_checker_.DetachFromThread(); } ~Backend() override {} @@ -133,11 +131,11 @@ class CastAudioOutputStream::Backend : public MediaPipelineBackend::Delegate { return; } - backend_buffer_.set_buffer(decoder_buffer); + backend_buffer_ = decoder_buffer; completion_cb_ = completion_cb; MediaPipelineBackend::BufferStatus status = - decoder_->PushBuffer(nullptr /* decrypt_context */, &backend_buffer_); + decoder_->PushBuffer(backend_buffer_.get()); if (status != MediaPipelineBackend::kBufferPending) OnPushBufferComplete(decoder_, status); } @@ -182,7 +180,7 @@ class CastAudioOutputStream::Backend : public MediaPipelineBackend::Delegate { PushBufferCompletionCallback completion_cb_; bool first_start_; bool error_; - CastDecoderBufferImpl backend_buffer_; + scoped_refptr<DecoderBufferBase> backend_buffer_; base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(Backend); }; diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc index 4c44590..608d9b6 100644 --- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc +++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc @@ -42,15 +42,12 @@ class FakeAudioDecoder : public MediaPipelineBackend::AudioDecoder { pipeline_status_(PIPELINE_STATUS_OK), pending_push_(false), pushed_buffer_count_(0), - last_decrypt_context_(nullptr), last_buffer_(nullptr), delegate_(nullptr) {} ~FakeAudioDecoder() override {} // MediaPipelineBackend::AudioDecoder overrides. - BufferStatus PushBuffer(DecryptContext* decrypt_context, - CastDecoderBuffer* buffer) override { - last_decrypt_context_ = decrypt_context; + BufferStatus PushBuffer(CastDecoderBuffer* buffer) override { last_buffer_ = buffer; ++pushed_buffer_count_; @@ -93,7 +90,6 @@ class FakeAudioDecoder : public MediaPipelineBackend::AudioDecoder { pipeline_status_ = status; } unsigned pushed_buffer_count() const { return pushed_buffer_count_; } - DecryptContext* last_decrypt_context() { return last_decrypt_context_; } CastDecoderBuffer* last_buffer() { return last_buffer_; } void set_delegate(MediaPipelineBackend::Delegate* delegate) { delegate_ = delegate; @@ -106,7 +102,6 @@ class FakeAudioDecoder : public MediaPipelineBackend::AudioDecoder { PipelineStatus pipeline_status_; bool pending_push_; int pushed_buffer_count_; - DecryptContext* last_decrypt_context_; CastDecoderBuffer* last_buffer_; MediaPipelineBackend::Delegate* delegate_; }; @@ -471,7 +466,6 @@ TEST_F(CastAudioOutputStreamTest, PushFrame) { ASSERT_TRUE(audio_decoder); // Verify initial state. EXPECT_EQ(0u, audio_decoder->pushed_buffer_count()); - EXPECT_FALSE(audio_decoder->last_decrypt_context()); EXPECT_FALSE(audio_decoder->last_buffer()); scoped_ptr<FakeAudioSourceCallback> source_callback( @@ -481,8 +475,6 @@ TEST_F(CastAudioOutputStreamTest, PushFrame) { // Verify that the stream pushed frames to the backend. EXPECT_LT(0u, audio_decoder->pushed_buffer_count()); - // DecryptContext is always NULL becuase of "raw" audio. - EXPECT_FALSE(audio_decoder->last_decrypt_context()); EXPECT_TRUE(audio_decoder->last_buffer()); // Verify decoder buffer. diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc index 38ea193..fb0d768 100644 --- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc +++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc @@ -20,7 +20,6 @@ #include "base/threading/thread.h" #include "base/time/time.h" #include "chromecast/base/task_runner_impl.h" -#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h" #include "chromecast/media/cma/base/decoder_buffer_adapter.h" #include "chromecast/media/cma/base/decoder_config_adapter.h" #include "chromecast/media/cma/test/frame_segmenter_for_test.h" @@ -116,8 +115,8 @@ class AudioVideoPipelineDeviceTest : public testing::Test, scoped_ptr<TaskRunnerImpl> task_runner_; scoped_ptr<MediaPipelineBackend> backend_; - CastDecoderBufferImpl backend_audio_buffer_; - CastDecoderBufferImpl backend_video_buffer_; + scoped_refptr<DecoderBufferBase> backend_audio_buffer_; + scoped_refptr<DecoderBufferBase> backend_video_buffer_; // Current media time. base::TimeDelta pause_time_; @@ -138,9 +137,7 @@ class AudioVideoPipelineDeviceTest : public testing::Test, }; AudioVideoPipelineDeviceTest::AudioVideoPipelineDeviceTest() - : backend_audio_buffer_(nullptr), - backend_video_buffer_(nullptr), - pause_pattern_(), + : pause_pattern_(), audio_decoder_(nullptr), video_decoder_(nullptr), audio_feeding_completed_(true), @@ -249,18 +246,16 @@ void AudioVideoPipelineDeviceTest::FeedAudioBuffer() { if (audio_feeding_completed_) return; - scoped_refptr<DecoderBufferBase> buffer = audio_buffers_.front(); - backend_audio_buffer_.set_buffer(buffer); + backend_audio_buffer_ = audio_buffers_.front(); MediaPipelineBackend::BufferStatus status = - audio_decoder_->PushBuffer(nullptr, // decrypt_context - &backend_audio_buffer_); + audio_decoder_->PushBuffer(backend_audio_buffer_.get()); EXPECT_NE(status, MediaPipelineBackend::kBufferFailed); audio_buffers_.pop_front(); // Feeding is done, just wait for the end of stream callback. - if (buffer->end_of_stream() || audio_buffers_.empty()) { - if (audio_buffers_.empty() && !buffer->end_of_stream()) { + if (backend_audio_buffer_->end_of_stream() || audio_buffers_.empty()) { + if (audio_buffers_.empty() && !backend_audio_buffer_->end_of_stream()) { LOG(WARNING) << "Stream emptied without feeding EOS frame"; } @@ -280,18 +275,16 @@ void AudioVideoPipelineDeviceTest::FeedVideoBuffer() { if (video_feeding_completed_) return; - scoped_refptr<DecoderBufferBase> buffer = video_buffers_.front(); - backend_video_buffer_.set_buffer(buffer); + backend_video_buffer_ = video_buffers_.front(); MediaPipelineBackend::BufferStatus status = - video_decoder_->PushBuffer(nullptr, // decrypt_context - &backend_video_buffer_); + video_decoder_->PushBuffer(backend_video_buffer_.get()); EXPECT_NE(status, MediaPipelineBackend::kBufferFailed); video_buffers_.pop_front(); // Feeding is done, just wait for the end of stream callback. - if (buffer->end_of_stream() || video_buffers_.empty()) { - if (video_buffers_.empty() && !buffer->end_of_stream()) { + if (backend_video_buffer_->end_of_stream() || video_buffers_.empty()) { + if (video_buffers_.empty() && !backend_video_buffer_->end_of_stream()) { LOG(WARNING) << "Stream emptied without feeding EOS frame"; } @@ -431,6 +424,7 @@ void AudioVideoPipelineDeviceTest::Initialize() { task_runner_.reset(new TaskRunnerImpl()); MediaPipelineDeviceParams params(task_runner_.get()); backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params)); + DCHECK(backend_); } TEST_F(AudioVideoPipelineDeviceTest, Mp3Playback) { diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.cc b/chromecast/media/cma/backend/media_pipeline_backend_default.cc index bb0cc1e..61a3315 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_default.cc +++ b/chromecast/media/cma/backend/media_pipeline_backend_default.cc @@ -20,8 +20,7 @@ class MediaPipelineBackendDefault::AudioDecoderDefault } // MediaPipelineBackend::AudioDecoder implementation: - BufferStatus PushBuffer(DecryptContext* decrypt_context, - CastDecoderBuffer* buffer) override { + BufferStatus PushBuffer(CastDecoderBuffer* buffer) override { if (buffer->end_of_stream()) delegate_->OnEndOfStream(this); return MediaPipelineBackend::kBufferSuccess; @@ -52,8 +51,7 @@ class MediaPipelineBackendDefault::VideoDecoderDefault } // MediaPipelineBackend::VideoDecoder implementation: - BufferStatus PushBuffer(DecryptContext* decrypt_context, - CastDecoderBuffer* buffer) override { + BufferStatus PushBuffer(CastDecoderBuffer* buffer) override { if (buffer->end_of_stream()) delegate_->OnEndOfStream(this); return MediaPipelineBackend::kBufferSuccess; diff --git a/chromecast/media/cma/base/BUILD.gn b/chromecast/media/cma/base/BUILD.gn index d3eb811..b0ebefd 100644 --- a/chromecast/media/cma/base/BUILD.gn +++ b/chromecast/media/cma/base/BUILD.gn @@ -14,8 +14,6 @@ source_set("base") { "buffering_frame_provider.h", "buffering_state.cc", "buffering_state.h", - "cast_decoder_buffer_impl.cc", - "cast_decoder_buffer_impl.h", "cast_decrypt_config_impl.cc", "cast_decrypt_config_impl.h", "cma_logging.h", diff --git a/chromecast/media/cma/base/cast_decoder_buffer_impl.cc b/chromecast/media/cma/base/cast_decoder_buffer_impl.cc deleted file mode 100644 index e958048..0000000 --- a/chromecast/media/cma/base/cast_decoder_buffer_impl.cc +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h" - -namespace chromecast { -namespace media { - -CastDecoderBufferImpl::CastDecoderBufferImpl( - const scoped_refptr<DecoderBufferBase>& buffer) - : buffer_(buffer) {} - -CastDecoderBufferImpl::~CastDecoderBufferImpl() {} - -StreamId CastDecoderBufferImpl::stream_id() const { - return buffer_->stream_id(); -} - -int64_t CastDecoderBufferImpl::timestamp() const { - return buffer_->timestamp().InMicroseconds(); -} - -const uint8* CastDecoderBufferImpl::data() const { - return buffer_->data(); -} - -size_t CastDecoderBufferImpl::data_size() const { - return buffer_->data_size(); -} - -const CastDecryptConfig* CastDecoderBufferImpl::decrypt_config() const { - return buffer_->decrypt_config(); -} - -bool CastDecoderBufferImpl::end_of_stream() const { - return buffer_->end_of_stream(); -} - -const scoped_refptr<DecoderBufferBase>& CastDecoderBufferImpl::buffer() const { - return buffer_; -} - -void CastDecoderBufferImpl::set_buffer( - const scoped_refptr<DecoderBufferBase>& buffer) { - buffer_ = buffer; -} - -} // namespace media -} // namespace chromecast diff --git a/chromecast/media/cma/base/cast_decoder_buffer_impl.h b/chromecast/media/cma/base/cast_decoder_buffer_impl.h deleted file mode 100644 index adc663c..0000000 --- a/chromecast/media/cma/base/cast_decoder_buffer_impl.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMECAST_MEDIA_CMA_BASE_CAST_DECODER_BUFFER_IMPL_H_ -#define CHROMECAST_MEDIA_CMA_BASE_CAST_DECODER_BUFFER_IMPL_H_ - -#include "chromecast/public/media/cast_decoder_buffer.h" -#include "chromecast/media/cma/base/decoder_buffer_base.h" - -namespace chromecast { -namespace media { - -// Implementation of public DecoderBuffer interface. -// Holds a (refcounted) DecoderBufferBase. This way, ownership throughout -// the pipeline is refcounted, but without exposing RefCountedBase in -// the public API. -class CastDecoderBufferImpl : public CastDecoderBuffer { - public: - CastDecoderBufferImpl(const scoped_refptr<DecoderBufferBase>& buffer); - ~CastDecoderBufferImpl() override; - - // Returns the stream id of this decoder buffer belonging to. it's optional - // and default value is kPrimary. - StreamId stream_id() const override; - - // Returns the PTS of the frame in microseconds. - int64_t timestamp() const override; - - // Gets the frame data. - const uint8* data() const override; - - // Returns the size of the frame in bytes. - size_t data_size() const override; - - // Returns the decrypt configuration. - // Returns NULL if the buffer has no decrypt info. - const CastDecryptConfig* decrypt_config() const override; - - // Indicate if this is a special frame that indicates the end of the stream. - // If true, functions to access the frame content cannot be called. - bool end_of_stream() const override; - - const scoped_refptr<DecoderBufferBase>& buffer() const; - void set_buffer(const scoped_refptr<DecoderBufferBase>& buffer); - - private: - scoped_refptr<DecoderBufferBase> buffer_; -}; - -} // namespace media -} // namespace chromecast - -#endif // CHROMECAST_MEDIA_CMA_BASE_CAST_DECODER_BUFFER_BASE_H_ diff --git a/chromecast/media/cma/base/decoder_buffer_adapter.cc b/chromecast/media/cma/base/decoder_buffer_adapter.cc index 10ffddc..c7de81f 100644 --- a/chromecast/media/cma/base/decoder_buffer_adapter.cc +++ b/chromecast/media/cma/base/decoder_buffer_adapter.cc @@ -29,8 +29,8 @@ StreamId DecoderBufferAdapter::stream_id() const { return stream_id_; } -base::TimeDelta DecoderBufferAdapter::timestamp() const { - return buffer_->timestamp(); +int64_t DecoderBufferAdapter::timestamp() const { + return buffer_->timestamp().InMicroseconds(); } void DecoderBufferAdapter::set_timestamp(base::TimeDelta timestamp) { diff --git a/chromecast/media/cma/base/decoder_buffer_adapter.h b/chromecast/media/cma/base/decoder_buffer_adapter.h index 5118694..9eda89c 100644 --- a/chromecast/media/cma/base/decoder_buffer_adapter.h +++ b/chromecast/media/cma/base/decoder_buffer_adapter.h @@ -28,9 +28,9 @@ class DecoderBufferAdapter : public DecoderBufferBase { DecoderBufferAdapter( StreamId stream_id, const scoped_refptr<::media::DecoderBuffer>& buffer); - // DecoderBufferBase implementation. + // DecoderBufferBase implementation: StreamId stream_id() const override; - base::TimeDelta timestamp() const override; + int64_t timestamp() const override; void set_timestamp(base::TimeDelta timestamp) override; const uint8* data() const override; uint8* writable_data() const override; diff --git a/chromecast/media/cma/base/decoder_buffer_base.h b/chromecast/media/cma/base/decoder_buffer_base.h index 08cf94b..d405da4 100644 --- a/chromecast/media/cma/base/decoder_buffer_base.h +++ b/chromecast/media/cma/base/decoder_buffer_base.h @@ -5,57 +5,57 @@ #ifndef CHROMECAST_MEDIA_CMA_BASE_DECODER_BUFFER_BASE_H_ #define CHROMECAST_MEDIA_CMA_BASE_DECODER_BUFFER_BASE_H_ -#include "base/basictypes.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/time/time.h" -#include "chromecast/public/media/stream_id.h" +#include "chromecast/public/media/cast_decoder_buffer.h" +#include "chromecast/public/media/decrypt_context.h" namespace chromecast { namespace media { -class CastDecryptConfig; // DecoderBufferBase exposes only the properties of an audio/video buffer. // The way a DecoderBufferBase is created and organized in memory // is left as a detail of the implementation of derived classes. -class DecoderBufferBase - : public base::RefCountedThreadSafe<DecoderBufferBase> { +class DecoderBufferBase : public CastDecoderBuffer, + public base::RefCountedThreadSafe<DecoderBufferBase> { public: - DecoderBufferBase() {} + // Partial CastDecoderBuffer implementation: + DecryptContext* decrypt_context() const override; - // Returns the stream id of this decoder buffer belonging to. it's optional - // and default value is kPrimary. - virtual StreamId stream_id() const = 0; - - // Returns the PTS of the frame. - virtual base::TimeDelta timestamp() const = 0; + void set_decrypt_context(scoped_ptr<DecryptContext> context) { + decrypt_context_ = context.Pass(); + } // Sets the PTS of the frame. virtual void set_timestamp(base::TimeDelta timestamp) = 0; - // Gets the frame data. - virtual const uint8* data() const = 0; - virtual uint8* writable_data() const = 0; - - // Returns the size of the frame in bytes. - virtual size_t data_size() const = 0; - - // Returns the decrypt configuration. - // Returns NULL if the buffer has no decrypt info. - virtual const CastDecryptConfig* decrypt_config() const = 0; - - // Indicate if this is a special frame that indicates the end of the stream. - // If true, functions to access the frame content cannot be called. - virtual bool end_of_stream() const = 0; + // Gets a pointer to the frame data buffer. + virtual uint8_t* writable_data() const = 0; protected: friend class base::RefCountedThreadSafe<DecoderBufferBase>; - virtual ~DecoderBufferBase() {} + + DecoderBufferBase(); + ~DecoderBufferBase() override; private: + scoped_ptr<DecryptContext> decrypt_context_; + DISALLOW_COPY_AND_ASSIGN(DecoderBufferBase); }; +inline DecoderBufferBase::DecoderBufferBase() { +} + +inline DecoderBufferBase::~DecoderBufferBase() { +} + +inline DecryptContext* DecoderBufferBase::decrypt_context() const { + return decrypt_context_.get(); +} + } // namespace media } // namespace chromecast diff --git a/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc b/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc index 1bc97a5..b6af72b 100644 --- a/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc +++ b/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc @@ -27,7 +27,7 @@ class DecoderBufferFromMsg : public DecoderBufferBase { // DecoderBufferBase implementation. StreamId stream_id() const override; - base::TimeDelta timestamp() const override; + int64_t timestamp() const override; void set_timestamp(base::TimeDelta timestamp) override; const uint8* data() const override; uint8* writable_data() const override; @@ -113,8 +113,8 @@ StreamId DecoderBufferFromMsg::stream_id() const { return stream_id_; } -base::TimeDelta DecoderBufferFromMsg::timestamp() const { - return pts_; +int64_t DecoderBufferFromMsg::timestamp() const { + return pts_.InMicroseconds(); } void DecoderBufferFromMsg::set_timestamp(base::TimeDelta timestamp) { @@ -154,7 +154,7 @@ void DecoderBufferBaseMarshaller::Write( return; CHECK(msg->WritePod(buffer->stream_id())); - CHECK(msg->WritePod(buffer->timestamp().InMicroseconds())); + CHECK(msg->WritePod(buffer->timestamp())); bool has_decrypt_config = (buffer->decrypt_config() != NULL && diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc index b88f686..0edd474 100644 --- a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc @@ -73,6 +73,11 @@ void AudioPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) { base::Bind(&AudioPipelineImpl::OnFlushDone, weak_this_, status_cb)); } +void AudioPipelineImpl::BackendStopped() { + CMALOG(kLogControl) << __FUNCTION__; + av_pipeline_impl_->BackendStopped(); +} + void AudioPipelineImpl::OnFlushDone( const ::media::PipelineStatusCB& status_cb) { CMALOG(kLogControl) << __FUNCTION__; diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.h b/chromecast/media/cma/pipeline/audio_pipeline_impl.h index 9afe19b..014b041 100644 --- a/chromecast/media/cma/pipeline/audio_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.h @@ -46,6 +46,7 @@ class AudioPipelineImpl { bool StartPlayingFrom(base::TimeDelta time, const scoped_refptr<BufferingState>& buffering_state); void Flush(const ::media::PipelineStatusCB& status_cb); + void BackendStopped(); void Stop(); // Update the playback statistics for this audio stream. diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc index a8eff13..82ce75f 100644 --- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc @@ -41,7 +41,6 @@ AvPipelineImpl::AvPipelineImpl(MediaPipelineBackend::Decoder* decoder, playable_buffered_time_(::media::kNoTimestamp()), enable_feeding_(false), pending_read_(false), - pushed_buffer_(nullptr), enable_time_update_(false), pending_time_update_task_(false), media_keys_(NULL), @@ -103,14 +102,11 @@ void AvPipelineImpl::Flush(const base::Closure& done_cb) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_EQ(state_, kFlushing); - // Note: returning to idle state aborts any pending frame push. - pushed_buffer_.set_buffer(nullptr); - // Break the feeding loop. enable_feeding_ = false; // Remove any pending buffer. - pending_buffer_ = scoped_refptr<DecoderBufferBase>(); + pending_buffer_ = nullptr; // Finally, remove any frames left in the frame provider. pending_read_ = false; @@ -120,6 +116,13 @@ void AvPipelineImpl::Flush(const base::Closure& done_cb) { frame_provider_->Flush(done_cb); } +void AvPipelineImpl::BackendStopped() { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Note: returning to idle state aborts any pending frame push. + pushed_buffer_ = nullptr; +} + void AvPipelineImpl::Stop() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -149,7 +152,7 @@ void AvPipelineImpl::FetchBufferIfNeeded() { if (!enable_feeding_) return; - if (pending_read_ || pending_buffer_.get()) + if (pending_read_ || pending_buffer_) return; pending_read_ = true; @@ -179,14 +182,14 @@ void AvPipelineImpl::ProcessPendingBuffer() { return; // Initiate a read if there isn't already one. - if (!pending_buffer_.get() && !pending_read_) { + if (!pending_buffer_ && !pending_read_) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); return; } - if (!pending_buffer_.get() || pushed_buffer_.buffer()) + if (!pending_buffer_ || pushed_buffer_) return; // Break the feeding loop when the end of stream is reached. @@ -203,13 +206,12 @@ void AvPipelineImpl::ProcessPendingBuffer() { std::string key_id(pending_buffer_->decrypt_config()->key_id()); if (!media_keys_) { CMALOG(kLogControl) << "No CDM for frame: pts=" - << pending_buffer_->timestamp().InMilliseconds(); + << pending_buffer_->timestamp(); return; } decrypt_context = media_keys_->GetDecryptContext(key_id); if (!decrypt_context.get()) { - CMALOG(kLogControl) << "frame(pts=" - << pending_buffer_->timestamp().InMilliseconds() + CMALOG(kLogControl) << "frame(pts=" << pending_buffer_->timestamp() << "): waiting for key id " << base::HexEncode(&key_id[0], key_id.size()); return; @@ -225,16 +227,19 @@ void AvPipelineImpl::ProcessPendingBuffer() { } if (!pending_buffer_->end_of_stream() && buffering_state_.get()) { - base::TimeDelta timestamp = pending_buffer_->timestamp(); + base::TimeDelta timestamp = + base::TimeDelta::FromMicroseconds(pending_buffer_->timestamp()); if (timestamp != ::media::kNoTimestamp()) buffering_state_->SetMaxRenderingTime(timestamp); } - DCHECK(!pushed_buffer_.buffer()); - pushed_buffer_.set_buffer(pending_buffer_); + DCHECK(!pushed_buffer_); + pushed_buffer_ = pending_buffer_; + if (decrypt_context && decrypt_context->GetKeySystem() != KEY_SYSTEM_NONE) + pushed_buffer_->set_decrypt_context(decrypt_context.Pass()); + pending_buffer_ = nullptr; MediaPipelineBackend::BufferStatus status = - decoder_->PushBuffer(decrypt_context.release(), &pushed_buffer_); - pending_buffer_ = scoped_refptr<DecoderBufferBase>(); + decoder_->PushBuffer(pushed_buffer_.get()); if (status != MediaPipelineBackend::kBufferPending) OnBufferPushed(status); @@ -242,7 +247,7 @@ void AvPipelineImpl::ProcessPendingBuffer() { void AvPipelineImpl::OnBufferPushed(MediaPipelineBackend::BufferStatus status) { DCHECK(thread_checker_.CalledOnValidThread()); - pushed_buffer_.set_buffer(nullptr); + pushed_buffer_ = nullptr; if (status == MediaPipelineBackend::kBufferFailed) { LOG(WARNING) << "AvPipelineImpl: PushFrame failed"; enable_feeding_ = false; @@ -277,9 +282,11 @@ void AvPipelineImpl::OnDataBuffered( if (!buffering_state_.get()) return; - if (!buffer->end_of_stream() && (buffered_time_ == ::media::kNoTimestamp() || - buffered_time_ < buffer->timestamp())) { - buffered_time_ = buffer->timestamp(); + if (!buffer->end_of_stream() && + (buffered_time_ == ::media::kNoTimestamp() || + buffered_time_ < + base::TimeDelta::FromMicroseconds(buffer->timestamp()))) { + buffered_time_ = base::TimeDelta::FromMicroseconds(buffer->timestamp()); } if (is_at_max_capacity) @@ -312,8 +319,10 @@ void AvPipelineImpl::UpdatePlayableFrames() { } if (playable_buffered_time_ == ::media::kNoTimestamp() || - playable_buffered_time_ < non_playable_frame->timestamp()) { - playable_buffered_time_ = non_playable_frame->timestamp(); + playable_buffered_time_ < base::TimeDelta::FromMicroseconds( + non_playable_frame->timestamp())) { + playable_buffered_time_ = + base::TimeDelta::FromMicroseconds(non_playable_frame->timestamp()); buffering_state_->SetBufferedTime(playable_buffered_time_); } } diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromecast/media/cma/pipeline/av_pipeline_impl.h index fe1a828..28a885b 100644 --- a/chromecast/media/cma/pipeline/av_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/av_pipeline_impl.h @@ -12,7 +12,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" -#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h" #include "chromecast/public/media/media_pipeline_backend.h" #include "chromecast/public/media/stream_id.h" @@ -64,6 +63,8 @@ class AvPipelineImpl { // Flush any remaining samples in the pipeline. // Invoke |done_cb| when flush is completed. void Flush(const base::Closure& done_cb); + // Resets any pending buffers after the backend has been stopped. + void BackendStopped(); // Tear down the pipeline and release the hardware resources. void Stop(); @@ -140,7 +141,7 @@ class AvPipelineImpl { scoped_refptr<DecoderBufferBase> pending_buffer_; // Buffer that has been pushed to the device but not processed yet. - CastDecoderBufferImpl pushed_buffer_; + scoped_refptr<DecoderBufferBase> pushed_buffer_; // The media time is retrieved at regular intervals. // Indicate whether time update is enabled. diff --git a/chromecast/media/cma/pipeline/decrypt_util.cc b/chromecast/media/cma/pipeline/decrypt_util.cc index 7f57cec..2acd5ea 100644 --- a/chromecast/media/cma/pipeline/decrypt_util.cc +++ b/chromecast/media/cma/pipeline/decrypt_util.cc @@ -23,7 +23,7 @@ class DecoderBufferClear : public DecoderBufferBase { // DecoderBufferBase implementation. StreamId stream_id() const override; - base::TimeDelta timestamp() const override; + int64_t timestamp() const override; void set_timestamp(base::TimeDelta timestamp) override; const uint8* data() const override; uint8* writable_data() const override; @@ -51,7 +51,7 @@ StreamId DecoderBufferClear::stream_id() const { return buffer_->stream_id(); } -base::TimeDelta DecoderBufferClear::timestamp() const { +int64_t DecoderBufferClear::timestamp() const { return buffer_->timestamp(); } diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc index e741470..68df661 100644 --- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc @@ -345,6 +345,12 @@ void MediaPipelineImpl::OnFlushDone( return; } + // Clear pending buffers. + if (audio_pipeline_) + audio_pipeline_->BackendStopped(); + if (video_pipeline_) + video_pipeline_->BackendStopped(); + pending_flush_callbacks_.reset(); status_cb.Run(status); } diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_impl.cc index e24a7f7..2d6f803 100644 --- a/chromecast/media/cma/pipeline/video_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/video_pipeline_impl.cc @@ -76,6 +76,11 @@ void VideoPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) { base::Bind(&VideoPipelineImpl::OnFlushDone, weak_this_, status_cb)); } +void VideoPipelineImpl::BackendStopped() { + CMALOG(kLogControl) << __FUNCTION__; + av_pipeline_impl_->BackendStopped(); +} + void VideoPipelineImpl::OnFlushDone( const ::media::PipelineStatusCB& status_cb) { CMALOG(kLogControl) << __FUNCTION__; diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.h b/chromecast/media/cma/pipeline/video_pipeline_impl.h index 9fd3071..ff18c28 100644 --- a/chromecast/media/cma/pipeline/video_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/video_pipeline_impl.h @@ -48,6 +48,7 @@ class VideoPipelineImpl { bool StartPlayingFrom(base::TimeDelta time, const scoped_refptr<BufferingState>& buffering_state); void Flush(const ::media::PipelineStatusCB& status_cb); + void BackendStopped(); void Stop(); // Update the playback statistics for this video stream. diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index fe0fd7c..b3a0047 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp @@ -120,8 +120,6 @@ 'cma/base/buffering_frame_provider.h', 'cma/base/buffering_state.cc', 'cma/base/buffering_state.h', - 'cma/base/cast_decoder_buffer_impl.cc', - 'cma/base/cast_decoder_buffer_impl.h', 'cma/base/cast_decrypt_config_impl.cc', 'cma/base/cast_decrypt_config_impl.h', 'cma/base/cma_logging.h', diff --git a/chromecast/public/media/cast_decoder_buffer.h b/chromecast/public/media/cast_decoder_buffer.h index bf3d76c..f6ca422 100644 --- a/chromecast/public/media/cast_decoder_buffer.h +++ b/chromecast/public/media/cast_decoder_buffer.h @@ -15,12 +15,16 @@ namespace chromecast { namespace media { class CastDecryptConfig; +class DecryptContext; // CastDecoderBuffer provides an interface for passing a single frame of audio // or video data to the pipeline backend. End-of-stream is indicated by passing // a frame where end_of_stream() returns true. -// Buffer ownership passes to backend when they are pushed (see -// MediaComponentDevice::PushFrame). +// The buffer's lifetime is managed by the caller code - it MUST NOT be +// deleted by the MediaPipelineBackend implementation, and MUST NOT be +// dereferenced after completion of buffer push (i.e. +// kBufferSuccess/kBufferFailure for synchronous completion, OnPushComplete +// for kBufferPending case). // TODO(halliwell): consider renaming functions here to camel case. class CastDecoderBuffer { public: @@ -39,9 +43,13 @@ class CastDecoderBuffer { virtual size_t data_size() const = 0; // Returns the decrypt configuration. - // Returns NULL if and only if the buffer is unencrypted. + // Returns nullptr if and only if the buffer is unencrypted. virtual const CastDecryptConfig* decrypt_config() const = 0; + // Returns the decrypt context. Returns nullptr if and only if the buffer is + // unencrypted. + virtual DecryptContext* decrypt_context() const = 0; + // Indicates if this is a special frame that indicates the end of the stream. // If true, functions to access the frame content cannot be called. virtual bool end_of_stream() const = 0; diff --git a/chromecast/public/media/media_pipeline_backend.h b/chromecast/public/media/media_pipeline_backend.h index 53e028b..cc497b5 100644 --- a/chromecast/public/media/media_pipeline_backend.h +++ b/chromecast/public/media/media_pipeline_backend.h @@ -58,13 +58,12 @@ class MediaPipelineBackend { // further buffers until OnPushComplete is invoked. // OnPushComplete should be only be invoked to indicate completion of a // pending buffer push - not for the immediate |kBufferSuccess| return case. - // The decrypt_context and buffer's lifetimes are managed by the caller code - // - they MUST NOT be deleted by the MediaPipelineBackend implementation, - // and MUST NOT be dereferenced after completion of buffer push (i.e. + // The buffer's lifetime is managed by the caller code - it MUST NOT be + // deleted by the MediaPipelineBackend implementation, and MUST NOT be + // dereferenced after completion of buffer push (i.e. // kBufferSuccess/kBufferFailure for synchronous completion, OnPushComplete // for kBufferPending case). - virtual BufferStatus PushBuffer(DecryptContext* decrypt_context, - CastDecoderBuffer* buffer) = 0; + virtual BufferStatus PushBuffer(CastDecoderBuffer* buffer) = 0; // Returns the playback statistics since this decoder's creation. Only // called when playing or paused. |