Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Unified Diff: chromecast/media/cma/adapter/backend_adapter.cc

Issue 1372393007: [Chromecast] Upgrade to new CMA backend API (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Add V1 adapter Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chromecast/media/cma/adapter/backend_adapter.cc
diff --git a/chromecast/media/cma/adapter/backend_adapter.cc b/chromecast/media/cma/adapter/backend_adapter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ba49ad7a556d135b57502b12c7ef17e0680e114c
--- /dev/null
+++ b/chromecast/media/cma/adapter/backend_adapter.cc
@@ -0,0 +1,398 @@
+// 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/adapter/backend_adapter.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "chromecast/base/task_runner_impl.h"
+#include "chromecast/media/cma/adapter/audio_pipeline_device.h"
+#include "chromecast/media/cma/adapter/media_clock_device.h"
+#include "chromecast/media/cma/adapter/media_pipeline_backend_v1.h"
+#include "chromecast/media/cma/adapter/video_pipeline_device.h"
+#include "chromecast/public/graphics_types.h"
+#include "chromecast/public/media/cast_decoder_buffer.h"
+#include "chromecast/public/media/decrypt_context.h"
+#include "chromecast/public/media/media_pipeline_device_params.h"
+
+namespace chromecast {
+namespace media {
+
+#define RUN_ON_MEDIA_THREAD(type, method, ...) \
+ media_task_runner_->PostTask( \
+ FROM_HERE, \
+ base::Bind(&type::method, base::Unretained(this), ##__VA_ARGS__));
+
+#define MAKE_SURE_MEDIA_THREAD(type, method, ...) \
+ DCHECK(media_task_runner_); \
+ if (!media_task_runner_->BelongsToCurrentThread()) { \
+ RUN_ON_MEDIA_THREAD(type, method, ##__VA_ARGS__) \
+ return; \
+ }
+
+namespace {
+
+MediaPipelineBackend::BufferStatus ConvertStatus(
+ MediaComponentDevice::FrameStatus status_in) {
+ switch (status_in) {
+ case MediaComponentDevice::kFrameSuccess:
+ return MediaPipelineBackend::kBufferSuccess;
+ case MediaComponentDevice::kFrameFailed:
+ return MediaPipelineBackend::kBufferFailed;
+ default:
+ NOTREACHED();
+ case MediaComponentDevice::kFramePending:
+ return MediaPipelineBackend::kBufferPending;
+ }
+}
+
+// Since the ownership model has changed from "callee-owned" to "caller-owned",
+// we need wrappers to pass to the V1 interface that can safely be deleted
+// at any time.
+class DecryptContextWrapper : public DecryptContext {
+ public:
+ DecryptContextWrapper(DecryptContext* wrapped_in) : wrapped_(wrapped_in) {}
+
+ ~DecryptContextWrapper() override {}
+
+ // DecryptContext implementation:
+ CastKeySystem GetKeySystem() override {
+ return wrapped_ ? wrapped_->GetKeySystem() : KEY_SYSTEM_NONE;
+ }
+
+ bool Decrypt(CastDecoderBuffer* buffer,
+ std::vector<uint8_t>* output) override {
+ return wrapped_->Decrypt(buffer, output);
+ }
+
+ private:
+ DecryptContext* wrapped_;
+
+ DISALLOW_COPY_AND_ASSIGN(DecryptContextWrapper);
+};
+
+class CastDecoderBufferWrapper : public CastDecoderBuffer {
+ public:
+ CastDecoderBufferWrapper(CastDecoderBuffer* wrapped_in)
+ : wrapped_(wrapped_in) {
+ DCHECK(wrapped_);
+ }
+
+ ~CastDecoderBufferWrapper() override {}
+
+ // CastDecoderBuffer implementation:
+ StreamId stream_id() const override { return wrapped_->stream_id(); }
+ int64_t timestamp() const override { return wrapped_->timestamp(); }
+ const uint8_t* data() const override { return wrapped_->data(); }
+ size_t data_size() const override { return wrapped_->data_size(); }
+ const CastDecryptConfig* decrypt_config() const override {
+ return wrapped_->decrypt_config();
+ }
+ bool end_of_stream() const override { return wrapped_->end_of_stream(); }
+
+ private:
+ CastDecoderBuffer* wrapped_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastDecoderBufferWrapper);
+};
+
+class FrameStatusCallback : public MediaComponentDevice::FrameStatusCB {
+ public:
+ FrameStatusCallback(
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ const base::WeakPtr<MediaPipelineBackendAdapter>& adapter,
+ bool video)
+ : media_task_runner_(media_task_runner),
+ adapter_(adapter),
+ video_(video) {
+ DCHECK(adapter_);
+ }
+
+ ~FrameStatusCallback() override {}
+
+ // MediaComponentDevice::FrameStatusCB implementation:
+ void Run(MediaComponentDevice::FrameStatus status) override {
+ MAKE_SURE_MEDIA_THREAD(FrameStatusCallback, Run, status);
+ if (adapter_) {
+ MediaPipelineBackend::BufferStatus status_out;
+ switch (status) {
+ case MediaComponentDevice::kFrameSuccess:
+ status_out = MediaPipelineBackend::kBufferSuccess;
+ break;
+ default:
+ NOTREACHED();
+ case MediaComponentDevice::kFrameFailed:
+ status_out = MediaPipelineBackend::kBufferFailed;
+ break;
+ }
+ adapter_->OnPushBufferComplete(video_, status_out);
+ }
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+ base::WeakPtr<MediaPipelineBackendAdapter> adapter_;
+ bool video_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameStatusCallback);
+};
+
+class V2AudioDecoder : public MediaPipelineBackend::AudioDecoder {
+ public:
+ V2AudioDecoder(
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ const base::WeakPtr<MediaPipelineBackendAdapter>& adapter,
+ media::AudioPipelineDevice* device)
+ : media_task_runner_(media_task_runner),
+ device_(device),
+ adapter_(adapter) {}
+
+ BufferStatus PushBuffer(DecryptContext* decrypt_context,
+ CastDecoderBuffer* buffer) override {
+ return ConvertStatus(device_->PushFrame(
+ new DecryptContextWrapper(decrypt_context),
+ new CastDecoderBufferWrapper(buffer),
+ new FrameStatusCallback(
+ media_task_runner_, adapter_, false /* video */)));
+ }
+
+ void GetStatistics(Statistics* statistics) override {
+ device_->GetStatistics(statistics);
+ }
+
+ bool SetConfig(const AudioConfig& config) override {
+ return device_->SetConfig(config);
+ }
+
+ bool SetVolume(float multiplier) override {
+ device_->SetStreamVolumeMultiplier(multiplier);
+ return true;
+ }
+
+ RenderingDelay GetRenderingDelay() override {
+ return device_->GetRenderingDelay();
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+ media::AudioPipelineDevice* device_;
+ base::WeakPtr<MediaPipelineBackendAdapter> adapter_;
+};
+
+class V2VideoDecoder : public MediaPipelineBackend::VideoDecoder {
+ public:
+ V2VideoDecoder(
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ base::WeakPtr<MediaPipelineBackendAdapter> adapter,
+ media::VideoPipelineDevice* device)
+ : media_task_runner_(media_task_runner),
+ device_(device),
+ adapter_(adapter) {}
+
+ BufferStatus PushBuffer(DecryptContext* decrypt_context,
+ CastDecoderBuffer* buffer) override {
+ return ConvertStatus(device_->PushFrame(
+ new DecryptContextWrapper(decrypt_context),
+ new CastDecoderBufferWrapper(buffer),
+ new FrameStatusCallback(
+ media_task_runner_, adapter_, true /* video */)));
+ }
+
+ void GetStatistics(MediaComponentDevice::Statistics* statistics) override {
+ device_->GetStatistics(statistics);
+ }
+
+ bool SetConfig(const VideoConfig& config) override {
+ return device_->SetConfig(config);
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+ media::VideoPipelineDevice* device_;
+ base::WeakPtr<MediaPipelineBackendAdapter> adapter_;
+};
+
+class AudioClientAdapter : public MediaComponentDevice::Client {
+ public:
+ AudioClientAdapter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ const base::WeakPtr<MediaPipelineBackendAdapter>& adapter)
+ : media_task_runner_(media_task_runner), adapter_(adapter) {}
+ void OnEndOfStream() override {
+ MAKE_SURE_MEDIA_THREAD(AudioClientAdapter, OnEndOfStream);
+ if (adapter_)
+ adapter_->OnEndOfAudioStream();
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+ base::WeakPtr<MediaPipelineBackendAdapter> adapter_;
+};
+
+class VideoClientAdapter : public MediaComponentDevice::Client,
+ public VideoPipelineDevice::VideoClient {
+ public:
+ VideoClientAdapter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ const base::WeakPtr<MediaPipelineBackendAdapter>& adapter)
+ : media_task_runner_(media_task_runner), adapter_(adapter) {}
+ void OnEndOfStream() override {
+ MAKE_SURE_MEDIA_THREAD(VideoClientAdapter, OnEndOfStream);
+ if (adapter_)
+ adapter_->OnEndOfVideoStream();
+ }
+ void OnNaturalSizeChanged(const Size& size) override {
+ MAKE_SURE_MEDIA_THREAD(VideoClientAdapter, OnNaturalSizeChanged, size);
+ if (adapter_)
+ adapter_->OnNaturalSizeChanged(size);
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
+ base::WeakPtr<MediaPipelineBackendAdapter> adapter_;
+};
+
+} // namespace
+
+MediaPipelineBackendAdapter::MediaPipelineBackendAdapter(
+ const MediaPipelineDeviceParams& params,
+ scoped_ptr<media::MediaPipelineBackendV1> backend_v1)
+ : backend_v1_(backend_v1.Pass()),
+ clock_(backend_v1_->GetClock()),
+ audio_(nullptr),
+ video_(nullptr),
+ playing_(false),
+ rate_(1.0f),
+ weak_factory_(this) {
+ DCHECK(clock_);
+
+ media_task_runner_ =
+ static_cast<TaskRunnerImpl*>(params.task_runner)->runner();
+}
+
+MediaPipelineBackendAdapter::~MediaPipelineBackendAdapter() {
+}
+
+MediaPipelineBackend::AudioDecoder*
+MediaPipelineBackendAdapter::CreateAudioDecoder() {
+ DCHECK(!audio_);
+ audio_ = backend_v1_->GetAudio();
+ audio_->SetClient(
+ new AudioClientAdapter(media_task_runner_, weak_factory_.GetWeakPtr()));
+ audio_decoder_ = new V2AudioDecoder(
+ media_task_runner_, weak_factory_.GetWeakPtr(), audio_);
+ return audio_decoder_;
+}
+
+MediaPipelineBackend::VideoDecoder*
+MediaPipelineBackendAdapter::CreateVideoDecoder() {
+ DCHECK(!video_);
+ video_ = backend_v1_->GetVideo();
+ video_->SetClient(
+ new VideoClientAdapter(media_task_runner_, weak_factory_.GetWeakPtr()));
+ video_->SetVideoClient(
+ new VideoClientAdapter(media_task_runner_, weak_factory_.GetWeakPtr()));
+ video_decoder_ = new V2VideoDecoder(
+ media_task_runner_, weak_factory_.GetWeakPtr(), video_);
+ return video_decoder_;
+}
+
+bool MediaPipelineBackendAdapter::Initialize(Delegate* delegate) {
+ DCHECK(delegate);
+ delegate_ = delegate;
+
+ if (!clock_->SetState(MediaClockDevice::kStateIdle))
+ return false;
+
+ if (audio_ && !audio_->SetState(MediaComponentDevice::kStateIdle))
+ return false;
+
+ if (video_ && !video_->SetState(MediaComponentDevice::kStateIdle))
+ return false;
+
+ return true;
+}
+
+bool MediaPipelineBackendAdapter::Start(int64_t start_pts) {
+ DCHECK(!playing_);
+ if (!clock_->ResetTimeline(start_pts))
+ return false;
+ if (audio_ && !audio_->SetStartPts(start_pts))
+ return false;
+ if (video_ && !video_->SetStartPts(start_pts))
+ return false;
+
+ if (!clock_->SetRate(rate_))
+ return false;
+ if (!clock_->SetState(MediaClockDevice::kStateRunning))
+ return false;
+ if (audio_ && !audio_->SetState(MediaComponentDevice::kStateRunning))
+ return false;
+ if (video_ && !video_->SetState(MediaComponentDevice::kStateRunning))
+ return false;
+
+ playing_ = true;
+ return true;
+}
+
+bool MediaPipelineBackendAdapter::Stop() {
+ DCHECK(playing_);
+ playing_ = false;
+ if (!clock_->SetState(MediaClockDevice::kStateIdle))
+ return false;
+ if (audio_ && !audio_->SetState(MediaComponentDevice::kStateIdle))
+ return false;
+ if (video_ && !video_->SetState(MediaComponentDevice::kStateIdle))
+ return false;
+ return true;
+}
+
+bool MediaPipelineBackendAdapter::Pause() {
+ DCHECK(playing_);
+ return clock_->SetRate(0.0f);
+}
+
+bool MediaPipelineBackendAdapter::Resume() {
+ DCHECK(playing_);
+ return clock_->SetRate(rate_);
+}
+
+int64_t MediaPipelineBackendAdapter::GetCurrentPts() {
+ return clock_->GetTimeMicroseconds();
+}
+
+bool MediaPipelineBackendAdapter::SetPlaybackRate(float rate) {
+ DCHECK_GE(rate, 0.0f);
+ DCHECK_LE(rate, 1.0f);
+ rate_ = rate;
+ if (playing_)
+ return clock_->SetRate(rate);
+ return true;
+}
+
+void MediaPipelineBackendAdapter::OnEndOfAudioStream() {
+ delegate_->OnEndOfStream(audio_decoder_);
+}
+
+void MediaPipelineBackendAdapter::OnEndOfVideoStream() {
+ delegate_->OnEndOfStream(video_decoder_);
+}
+
+void MediaPipelineBackendAdapter::OnPushBufferComplete(bool video,
+ BufferStatus status) {
+ MAKE_SURE_MEDIA_THREAD(
+ MediaPipelineBackendAdapter, OnPushBufferComplete, video, status);
+ if (video)
+ delegate_->OnPushBufferComplete(video_decoder_, status);
+ else
+ delegate_->OnPushBufferComplete(audio_decoder_, status);
+}
+
+void MediaPipelineBackendAdapter::OnNaturalSizeChanged(const Size& size) {
+ delegate_->OnVideoResolutionChanged(video_decoder_, size);
+}
+
+} // namespace media
+} // namespace chromecast

Powered by Google App Engine
This is Rietveld 408576698