1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/message_loop/message_loop_proxy.h" 10#include "chromecast/media/cma/base/coded_frame_provider.h" 11#include "chromecast/media/cma/base/decoder_buffer_base.h" 12#include "chromecast/media/cma/ipc/media_memory_chunk.h" 13#include "chromecast/media/cma/ipc/media_message.h" 14#include "chromecast/media/cma/ipc/media_message_fifo.h" 15#include "chromecast/media/cma/ipc/media_message_type.h" 16#include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h" 17#include "chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.h" 18#include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h" 19 20namespace chromecast { 21namespace media { 22 23AvStreamerProxy::AvStreamerProxy() 24 : is_running_(false), 25 pending_read_(false), 26 pending_av_data_(false), 27 weak_factory_(this), 28 weak_this_(weak_factory_.GetWeakPtr()) { 29 thread_checker_.DetachFromThread(); 30} 31 32AvStreamerProxy::~AvStreamerProxy() { 33 DCHECK(thread_checker_.CalledOnValidThread()); 34} 35 36void AvStreamerProxy::SetCodedFrameProvider( 37 scoped_ptr<CodedFrameProvider> frame_provider) { 38 DCHECK(thread_checker_.CalledOnValidThread()); 39 DCHECK(!frame_provider_); 40 frame_provider_.reset(frame_provider.release()); 41} 42 43void AvStreamerProxy::SetMediaMessageFifo( 44 scoped_ptr<MediaMessageFifo> fifo) { 45 DCHECK(thread_checker_.CalledOnValidThread()); 46 DCHECK(!fifo_); 47 fifo_.reset(fifo.release()); 48} 49 50void AvStreamerProxy::Start() { 51 DCHECK(!is_running_); 52 53 is_running_ = true; 54 RequestBufferIfNeeded(); 55} 56 57void AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) { 58 is_running_ = false; 59 60 pending_av_data_ = false; 61 pending_audio_config_ = ::media::AudioDecoderConfig(); 62 pending_video_config_ = ::media::VideoDecoderConfig(); 63 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); 64 65 pending_read_ = false; 66 frame_provider_->Flush(done_cb); 67} 68 69void AvStreamerProxy::OnFifoReadEvent() { 70 DCHECK(thread_checker_.CalledOnValidThread()); 71 72 // Some enough space might have been released 73 // to accommodate the pending data. 74 if (pending_av_data_) 75 ProcessPendingData(); 76} 77 78void AvStreamerProxy::RequestBufferIfNeeded() { 79 DCHECK(thread_checker_.CalledOnValidThread()); 80 81 if (!is_running_ || pending_read_ || pending_av_data_) 82 return; 83 84 // |frame_provider_| is assumed to run on the same message loop. 85 // Add a BindToCurrentLoop if that's not the case in the future. 86 pending_read_ = true; 87 frame_provider_->Read(base::Bind(&AvStreamerProxy::OnNewBuffer, weak_this_)); 88} 89 90void AvStreamerProxy::OnNewBuffer( 91 const scoped_refptr<DecoderBufferBase>& buffer, 92 const ::media::AudioDecoderConfig& audio_config, 93 const ::media::VideoDecoderConfig& video_config) { 94 DCHECK(thread_checker_.CalledOnValidThread()); 95 96 pending_read_ = false; 97 98 if (buffer->end_of_stream()) 99 is_running_ = false; 100 101 DCHECK(!pending_av_data_); 102 pending_av_data_ = true; 103 104 pending_buffer_ = buffer; 105 pending_audio_config_ = audio_config; 106 pending_video_config_ = video_config; 107 108 ProcessPendingData(); 109} 110 111void AvStreamerProxy::ProcessPendingData() { 112 if (pending_audio_config_.IsValidConfig()) { 113 if (!SendAudioDecoderConfig(pending_audio_config_)) 114 return; 115 pending_audio_config_ = ::media::AudioDecoderConfig(); 116 } 117 118 if (pending_video_config_.IsValidConfig()) { 119 if (!SendVideoDecoderConfig(pending_video_config_)) 120 return; 121 pending_video_config_ = ::media::VideoDecoderConfig(); 122 } 123 124 if (pending_buffer_.get()) { 125 if (!SendBuffer(pending_buffer_)) 126 return; 127 pending_buffer_ = scoped_refptr<DecoderBufferBase>(); 128 } 129 130 pending_av_data_ = false; 131 base::MessageLoopProxy::current()->PostTask( 132 FROM_HERE, 133 base::Bind(&AvStreamerProxy::RequestBufferIfNeeded, weak_this_)); 134} 135 136bool AvStreamerProxy::SendAudioDecoderConfig( 137 const ::media::AudioDecoderConfig& config) { 138 // Create a dummy message to calculate first the message size. 139 scoped_ptr<MediaMessage> dummy_msg( 140 MediaMessage::CreateDummyMessage(AudioConfigMediaMsg)); 141 AudioDecoderConfigMarshaller::Write(config, dummy_msg.get()); 142 143 // Create the real message and write the actual content. 144 scoped_ptr<MediaMessage> msg( 145 MediaMessage::CreateMessage( 146 AudioConfigMediaMsg, 147 base::Bind(&MediaMessageFifo::ReserveMemory, 148 base::Unretained(fifo_.get())), 149 dummy_msg->content_size())); 150 if (!msg) 151 return false; 152 153 AudioDecoderConfigMarshaller::Write(config, msg.get()); 154 return true; 155} 156 157bool AvStreamerProxy::SendVideoDecoderConfig( 158 const ::media::VideoDecoderConfig& config) { 159 // Create a dummy message to calculate first the message size. 160 scoped_ptr<MediaMessage> dummy_msg( 161 MediaMessage::CreateDummyMessage(VideoConfigMediaMsg)); 162 VideoDecoderConfigMarshaller::Write(config, dummy_msg.get()); 163 164 // Create the real message and write the actual content. 165 scoped_ptr<MediaMessage> msg( 166 MediaMessage::CreateMessage( 167 VideoConfigMediaMsg, 168 base::Bind(&MediaMessageFifo::ReserveMemory, 169 base::Unretained(fifo_.get())), 170 dummy_msg->content_size())); 171 if (!msg) 172 return false; 173 174 VideoDecoderConfigMarshaller::Write(config, msg.get()); 175 return true; 176} 177 178bool AvStreamerProxy::SendBuffer( 179 const scoped_refptr<DecoderBufferBase>& buffer) { 180 // Create a dummy message to calculate first the message size. 181 scoped_ptr<MediaMessage> dummy_msg( 182 MediaMessage::CreateDummyMessage(FrameMediaMsg)); 183 DecoderBufferBaseMarshaller::Write(buffer, dummy_msg.get()); 184 185 // Create the real message and write the actual content. 186 scoped_ptr<MediaMessage> msg( 187 MediaMessage::CreateMessage( 188 FrameMediaMsg, 189 base::Bind(&MediaMessageFifo::ReserveMemory, 190 base::Unretained(fifo_.get())), 191 dummy_msg->content_size())); 192 if (!msg) 193 return false; 194 195 DecoderBufferBaseMarshaller::Write(buffer, msg.get()); 196 return true; 197} 198 199} // namespace media 200} // namespace chromecast 201