| 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
|
|
|