| Index: chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
|
| diff --git a/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc b/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..de8dd54f6b3ae673203aedd885cfef60c84d2c8a
|
| --- /dev/null
|
| +++ b/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
|
| @@ -0,0 +1,200 @@
|
| +// Copyright 2014 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/ipc_streamer/av_streamer_proxy.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/location.h"
|
| +#include "base/message_loop/message_loop_proxy.h"
|
| +#include "chromecast/media/cma/base/coded_frame_provider.h"
|
| +#include "chromecast/media/cma/base/decoder_buffer_base.h"
|
| +#include "chromecast/media/cma/ipc/media_memory_chunk.h"
|
| +#include "chromecast/media/cma/ipc/media_message.h"
|
| +#include "chromecast/media/cma/ipc/media_message_fifo.h"
|
| +#include "chromecast/media/cma/ipc/media_message_type.h"
|
| +#include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h"
|
| +#include "chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.h"
|
| +#include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h"
|
| +
|
| +namespace chromecast {
|
| +namespace media {
|
| +
|
| +AvStreamerProxy::AvStreamerProxy()
|
| + : is_running_(false),
|
| + pending_read_(false),
|
| + pending_av_data_(false),
|
| + weak_factory_(this),
|
| + weak_this_(weak_factory_.GetWeakPtr()) {
|
| + thread_checker_.DetachFromThread();
|
| +}
|
| +
|
| +AvStreamerProxy::~AvStreamerProxy() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +}
|
| +
|
| +void AvStreamerProxy::SetCodedFrameProvider(
|
| + scoped_ptr<CodedFrameProvider> frame_provider) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!frame_provider_);
|
| + frame_provider_.reset(frame_provider.release());
|
| +}
|
| +
|
| +void AvStreamerProxy::SetMediaMessageFifo(
|
| + scoped_ptr<MediaMessageFifo> fifo) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!fifo_);
|
| + fifo_.reset(fifo.release());
|
| +}
|
| +
|
| +void AvStreamerProxy::Start() {
|
| + DCHECK(!is_running_);
|
| +
|
| + is_running_ = true;
|
| + RequestBufferIfNeeded();
|
| +}
|
| +
|
| +void AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) {
|
| + is_running_ = false;
|
| +
|
| + pending_av_data_ = false;
|
| + pending_audio_config_ = ::media::AudioDecoderConfig();
|
| + pending_video_config_ = ::media::VideoDecoderConfig();
|
| + pending_buffer_ = scoped_refptr<DecoderBufferBase>();
|
| +
|
| + pending_read_ = false;
|
| + frame_provider_->Flush(done_cb);
|
| +}
|
| +
|
| +void AvStreamerProxy::OnFifoReadEvent() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // Some enough space might have been released
|
| + // to accommodate the pending data.
|
| + if (pending_av_data_)
|
| + ProcessPendingData();
|
| +}
|
| +
|
| +void AvStreamerProxy::RequestBufferIfNeeded() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (!is_running_ || pending_read_ || pending_av_data_)
|
| + return;
|
| +
|
| + // |frame_provider_| is assumed to run on the same message loop.
|
| + // Add a BindToCurrentLoop if that's not the case in the future.
|
| + pending_read_ = true;
|
| + frame_provider_->Read(base::Bind(&AvStreamerProxy::OnNewBuffer, weak_this_));
|
| +}
|
| +
|
| +void AvStreamerProxy::OnNewBuffer(
|
| + const scoped_refptr<DecoderBufferBase>& buffer,
|
| + const ::media::AudioDecoderConfig& audio_config,
|
| + const ::media::VideoDecoderConfig& video_config) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + pending_read_ = false;
|
| +
|
| + if (buffer->end_of_stream())
|
| + is_running_ = false;
|
| +
|
| + DCHECK(!pending_av_data_);
|
| + pending_av_data_ = true;
|
| +
|
| + pending_buffer_ = buffer;
|
| + pending_audio_config_ = audio_config;
|
| + pending_video_config_ = video_config;
|
| +
|
| + ProcessPendingData();
|
| +}
|
| +
|
| +void AvStreamerProxy::ProcessPendingData() {
|
| + if (pending_audio_config_.IsValidConfig()) {
|
| + if (!SendAudioDecoderConfig(pending_audio_config_))
|
| + return;
|
| + pending_audio_config_ = ::media::AudioDecoderConfig();
|
| + }
|
| +
|
| + if (pending_video_config_.IsValidConfig()) {
|
| + if (!SendVideoDecoderConfig(pending_video_config_))
|
| + return;
|
| + pending_video_config_ = ::media::VideoDecoderConfig();
|
| + }
|
| +
|
| + if (pending_buffer_.get()) {
|
| + if (!SendBuffer(pending_buffer_))
|
| + return;
|
| + pending_buffer_ = scoped_refptr<DecoderBufferBase>();
|
| + }
|
| +
|
| + pending_av_data_ = false;
|
| + base::MessageLoopProxy::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&AvStreamerProxy::RequestBufferIfNeeded, weak_this_));
|
| +}
|
| +
|
| +bool AvStreamerProxy::SendAudioDecoderConfig(
|
| + const ::media::AudioDecoderConfig& config) {
|
| + // Create a dummy message to calculate first the message size.
|
| + scoped_ptr<MediaMessage> dummy_msg(
|
| + MediaMessage::CreateDummyMessage(AudioConfigMediaMsg));
|
| + AudioDecoderConfigMarshaller::Write(config, dummy_msg.get());
|
| +
|
| + // Create the real message and write the actual content.
|
| + scoped_ptr<MediaMessage> msg(
|
| + MediaMessage::CreateMessage(
|
| + AudioConfigMediaMsg,
|
| + base::Bind(&MediaMessageFifo::ReserveMemory,
|
| + base::Unretained(fifo_.get())),
|
| + dummy_msg->content_size()));
|
| + if (!msg)
|
| + return false;
|
| +
|
| + AudioDecoderConfigMarshaller::Write(config, msg.get());
|
| + return true;
|
| +}
|
| +
|
| +bool AvStreamerProxy::SendVideoDecoderConfig(
|
| + const ::media::VideoDecoderConfig& config) {
|
| + // Create a dummy message to calculate first the message size.
|
| + scoped_ptr<MediaMessage> dummy_msg(
|
| + MediaMessage::CreateDummyMessage(VideoConfigMediaMsg));
|
| + VideoDecoderConfigMarshaller::Write(config, dummy_msg.get());
|
| +
|
| + // Create the real message and write the actual content.
|
| + scoped_ptr<MediaMessage> msg(
|
| + MediaMessage::CreateMessage(
|
| + VideoConfigMediaMsg,
|
| + base::Bind(&MediaMessageFifo::ReserveMemory,
|
| + base::Unretained(fifo_.get())),
|
| + dummy_msg->content_size()));
|
| + if (!msg)
|
| + return false;
|
| +
|
| + VideoDecoderConfigMarshaller::Write(config, msg.get());
|
| + return true;
|
| +}
|
| +
|
| +bool AvStreamerProxy::SendBuffer(
|
| + const scoped_refptr<DecoderBufferBase>& buffer) {
|
| + // Create a dummy message to calculate first the message size.
|
| + scoped_ptr<MediaMessage> dummy_msg(
|
| + MediaMessage::CreateDummyMessage(FrameMediaMsg));
|
| + DecoderBufferBaseMarshaller::Write(buffer, dummy_msg.get());
|
| +
|
| + // Create the real message and write the actual content.
|
| + scoped_ptr<MediaMessage> msg(
|
| + MediaMessage::CreateMessage(
|
| + FrameMediaMsg,
|
| + base::Bind(&MediaMessageFifo::ReserveMemory,
|
| + base::Unretained(fifo_.get())),
|
| + dummy_msg->content_size()));
|
| + if (!msg)
|
| + return false;
|
| +
|
| + DecoderBufferBaseMarshaller::Write(buffer, msg.get());
|
| + return true;
|
| +}
|
| +
|
| +} // namespace media
|
| +} // namespace chromecast
|
|
|