| OLD | NEW |
| (Empty) |
| 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/renderer/media/video_pipeline_proxy.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/callback_helpers.h" | |
| 11 #include "base/macros.h" | |
| 12 #include "base/memory/shared_memory.h" | |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "base/threading/thread_checker.h" | |
| 15 #include "chromecast/common/media/cma_ipc_common.h" | |
| 16 #include "chromecast/common/media/cma_messages.h" | |
| 17 #include "chromecast/common/media/shared_memory_chunk.h" | |
| 18 #include "chromecast/media/cma/base/buffering_defs.h" | |
| 19 #include "chromecast/media/cma/base/cma_logging.h" | |
| 20 #include "chromecast/media/cma/base/coded_frame_provider.h" | |
| 21 #include "chromecast/media/cma/ipc/media_message_fifo.h" | |
| 22 #include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h" | |
| 23 #include "chromecast/media/cma/pipeline/video_pipeline_client.h" | |
| 24 #include "chromecast/renderer/media/cma_message_filter_proxy.h" | |
| 25 #include "chromecast/renderer/media/media_channel_proxy.h" | |
| 26 #include "media/base/bind_to_current_loop.h" | |
| 27 #include "media/base/pipeline_status.h" | |
| 28 | |
| 29 namespace chromecast { | |
| 30 namespace media { | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 void IgnoreResult() { | |
| 35 } | |
| 36 | |
| 37 } // namespace | |
| 38 | |
| 39 // VideoPipelineProxyInternal - | |
| 40 // This class is not thread safe and should run on the same thread | |
| 41 // as the media channel proxy. | |
| 42 class VideoPipelineProxyInternal { | |
| 43 public: | |
| 44 typedef base::Callback<void(std::unique_ptr<base::SharedMemory>)> SharedMemCB; | |
| 45 | |
| 46 static void Release(std::unique_ptr<VideoPipelineProxyInternal> proxy); | |
| 47 | |
| 48 explicit VideoPipelineProxyInternal( | |
| 49 scoped_refptr<MediaChannelProxy> media_channel_proxy); | |
| 50 virtual ~VideoPipelineProxyInternal(); | |
| 51 | |
| 52 // Notify the other side (browser process) of some activity on the video pipe. | |
| 53 // TODO(erickung): either send an IPC message or write a byte on the | |
| 54 // SyncSocket. | |
| 55 void NotifyPipeWrite(); | |
| 56 | |
| 57 // These functions are almost a one to one correspondence with VideoPipeline | |
| 58 // but this is an internal class and there is no reason to derive from | |
| 59 // VideoPipeline. | |
| 60 void SetClient(const base::Closure& pipe_read_cb, | |
| 61 const VideoPipelineClient& client); | |
| 62 void CreateAvPipe(const SharedMemCB& shared_mem_cb); | |
| 63 void Initialize(const std::vector<::media::VideoDecoderConfig>& configs, | |
| 64 const ::media::PipelineStatusCB& status_cb); | |
| 65 | |
| 66 private: | |
| 67 void Shutdown(); | |
| 68 | |
| 69 // Callbacks for CmaMessageFilterHost::VideoDelegate. | |
| 70 void OnAvPipeCreated(bool status, | |
| 71 base::SharedMemoryHandle shared_mem_handle, | |
| 72 base::FileDescriptor socket); | |
| 73 void OnStateChanged(::media::PipelineStatus status); | |
| 74 | |
| 75 base::ThreadChecker thread_checker_; | |
| 76 | |
| 77 scoped_refptr<MediaChannelProxy> media_channel_proxy_; | |
| 78 | |
| 79 // Store the callback for a pending state transition. | |
| 80 ::media::PipelineStatusCB status_cb_; | |
| 81 | |
| 82 SharedMemCB shared_mem_cb_; | |
| 83 | |
| 84 DISALLOW_COPY_AND_ASSIGN(VideoPipelineProxyInternal); | |
| 85 }; | |
| 86 | |
| 87 // static | |
| 88 void VideoPipelineProxyInternal::Release( | |
| 89 std::unique_ptr<VideoPipelineProxyInternal> proxy) { | |
| 90 proxy->Shutdown(); | |
| 91 } | |
| 92 | |
| 93 VideoPipelineProxyInternal::VideoPipelineProxyInternal( | |
| 94 scoped_refptr<MediaChannelProxy> media_channel_proxy) | |
| 95 : media_channel_proxy_(media_channel_proxy) { | |
| 96 DCHECK(media_channel_proxy.get()); | |
| 97 | |
| 98 // Creation can be done on a different thread. | |
| 99 thread_checker_.DetachFromThread(); | |
| 100 } | |
| 101 | |
| 102 VideoPipelineProxyInternal::~VideoPipelineProxyInternal() { | |
| 103 } | |
| 104 | |
| 105 void VideoPipelineProxyInternal::Shutdown() { | |
| 106 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 107 | |
| 108 // Remove any callback on VideoPipelineProxyInternal. | |
| 109 media_channel_proxy_->SetVideoDelegate( | |
| 110 CmaMessageFilterProxy::VideoDelegate()); | |
| 111 } | |
| 112 | |
| 113 void VideoPipelineProxyInternal::NotifyPipeWrite() { | |
| 114 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 115 | |
| 116 // TODO(damienv): An alternative way would be to use a dedicated socket for | |
| 117 // this event. | |
| 118 bool success = media_channel_proxy_->Send( | |
| 119 std::unique_ptr<IPC::Message>(new CmaHostMsg_NotifyPipeWrite( | |
| 120 media_channel_proxy_->GetId(), kVideoTrackId))); | |
| 121 VLOG_IF(4, !success) << "Sending msg failed"; | |
| 122 } | |
| 123 | |
| 124 void VideoPipelineProxyInternal::SetClient( | |
| 125 const base::Closure& pipe_read_cb, | |
| 126 const VideoPipelineClient& video_client) { | |
| 127 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 128 | |
| 129 CmaMessageFilterProxy::VideoDelegate delegate; | |
| 130 delegate.av_pipe_cb = | |
| 131 base::Bind(&VideoPipelineProxyInternal::OnAvPipeCreated, | |
| 132 base::Unretained(this)); | |
| 133 delegate.state_changed_cb = | |
| 134 base::Bind(&VideoPipelineProxyInternal::OnStateChanged, | |
| 135 base::Unretained(this)); | |
| 136 delegate.pipe_read_cb = pipe_read_cb; | |
| 137 delegate.client = video_client; | |
| 138 bool success = media_channel_proxy_->SetVideoDelegate(delegate); | |
| 139 CHECK(success); | |
| 140 } | |
| 141 | |
| 142 void VideoPipelineProxyInternal::CreateAvPipe( | |
| 143 const SharedMemCB& shared_mem_cb) { | |
| 144 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 145 DCHECK(shared_mem_cb_.is_null()); | |
| 146 bool success = media_channel_proxy_->Send( | |
| 147 std::unique_ptr<IPC::Message>(new CmaHostMsg_CreateAvPipe( | |
| 148 media_channel_proxy_->GetId(), kVideoTrackId, kAppVideoBufferSize))); | |
| 149 if (!success) { | |
| 150 shared_mem_cb.Run(std::unique_ptr<base::SharedMemory>()); | |
| 151 return; | |
| 152 } | |
| 153 shared_mem_cb_ = shared_mem_cb; | |
| 154 } | |
| 155 | |
| 156 void VideoPipelineProxyInternal::OnAvPipeCreated( | |
| 157 bool success, | |
| 158 base::SharedMemoryHandle shared_mem_handle, | |
| 159 base::FileDescriptor socket) { | |
| 160 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 161 DCHECK(!shared_mem_cb_.is_null()); | |
| 162 if (!success) { | |
| 163 shared_mem_cb_.Run(std::unique_ptr<base::SharedMemory>()); | |
| 164 return; | |
| 165 } | |
| 166 | |
| 167 CHECK(base::SharedMemory::IsHandleValid(shared_mem_handle)); | |
| 168 shared_mem_cb_.Run(std::unique_ptr<base::SharedMemory>( | |
| 169 new base::SharedMemory(shared_mem_handle, false))); | |
| 170 } | |
| 171 | |
| 172 void VideoPipelineProxyInternal::Initialize( | |
| 173 const std::vector<::media::VideoDecoderConfig>& configs, | |
| 174 const ::media::PipelineStatusCB& status_cb) { | |
| 175 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 176 bool success = media_channel_proxy_->Send( | |
| 177 std::unique_ptr<IPC::Message>(new CmaHostMsg_VideoInitialize( | |
| 178 media_channel_proxy_->GetId(), kVideoTrackId, configs))); | |
| 179 if (!success) { | |
| 180 status_cb.Run( ::media::PIPELINE_ERROR_INITIALIZATION_FAILED); | |
| 181 return; | |
| 182 } | |
| 183 DCHECK(status_cb_.is_null()); | |
| 184 status_cb_ = status_cb; | |
| 185 } | |
| 186 | |
| 187 void VideoPipelineProxyInternal::OnStateChanged( | |
| 188 ::media::PipelineStatus status) { | |
| 189 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 190 DCHECK(!status_cb_.is_null()); | |
| 191 base::ResetAndReturn(&status_cb_).Run(status); | |
| 192 } | |
| 193 | |
| 194 // A macro runs current member function on |io_task_runner_| thread. | |
| 195 #define FORWARD_ON_IO_THREAD(param_fn, ...) \ | |
| 196 io_task_runner_->PostTask( \ | |
| 197 FROM_HERE, base::Bind(&VideoPipelineProxyInternal::param_fn, \ | |
| 198 base::Unretained(proxy_.get()), ##__VA_ARGS__)) | |
| 199 | |
| 200 VideoPipelineProxy::VideoPipelineProxy( | |
| 201 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | |
| 202 scoped_refptr<MediaChannelProxy> media_channel_proxy) | |
| 203 : io_task_runner_(io_task_runner), | |
| 204 proxy_(new VideoPipelineProxyInternal(media_channel_proxy)), | |
| 205 video_streamer_(new AvStreamerProxy()), | |
| 206 weak_factory_(this) { | |
| 207 DCHECK(io_task_runner_.get()); | |
| 208 weak_this_ = weak_factory_.GetWeakPtr(); | |
| 209 thread_checker_.DetachFromThread(); | |
| 210 } | |
| 211 | |
| 212 VideoPipelineProxy::~VideoPipelineProxy() { | |
| 213 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 214 // Release the underlying object on the right thread. | |
| 215 io_task_runner_->PostTask( | |
| 216 FROM_HERE, | |
| 217 base::Bind(&VideoPipelineProxyInternal::Release, base::Passed(&proxy_))); | |
| 218 } | |
| 219 | |
| 220 void VideoPipelineProxy::SetClient(const VideoPipelineClient& video_client) { | |
| 221 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 222 base::Closure pipe_read_cb = | |
| 223 ::media::BindToCurrentLoop( | |
| 224 base::Bind(&VideoPipelineProxy::OnPipeRead, weak_this_)); | |
| 225 FORWARD_ON_IO_THREAD(SetClient, pipe_read_cb, video_client); | |
| 226 } | |
| 227 | |
| 228 void VideoPipelineProxy::Initialize( | |
| 229 const std::vector<::media::VideoDecoderConfig>& configs, | |
| 230 std::unique_ptr<CodedFrameProvider> frame_provider, | |
| 231 const ::media::PipelineStatusCB& status_cb) { | |
| 232 CMALOG(kLogControl) << "VideoPipelineProxy::Initialize"; | |
| 233 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 234 video_streamer_->SetCodedFrameProvider(std::move(frame_provider)); | |
| 235 | |
| 236 VideoPipelineProxyInternal::SharedMemCB shared_mem_cb = | |
| 237 ::media::BindToCurrentLoop(base::Bind( | |
| 238 &VideoPipelineProxy::OnAvPipeCreated, weak_this_, | |
| 239 configs, status_cb)); | |
| 240 FORWARD_ON_IO_THREAD(CreateAvPipe, shared_mem_cb); | |
| 241 } | |
| 242 | |
| 243 void VideoPipelineProxy::OnAvPipeCreated( | |
| 244 const std::vector<::media::VideoDecoderConfig>& configs, | |
| 245 const ::media::PipelineStatusCB& status_cb, | |
| 246 std::unique_ptr<base::SharedMemory> shared_memory) { | |
| 247 CMALOG(kLogControl) << "VideoPipelineProxy::OnAvPipeCreated"; | |
| 248 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 249 if (!shared_memory || | |
| 250 !shared_memory->Map(kAppVideoBufferSize)) { | |
| 251 status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED); | |
| 252 return; | |
| 253 } | |
| 254 CHECK(shared_memory->memory()); | |
| 255 | |
| 256 std::unique_ptr<MediaMemoryChunk> shared_memory_chunk( | |
| 257 new SharedMemoryChunk(std::move(shared_memory), kAppVideoBufferSize)); | |
| 258 std::unique_ptr<MediaMessageFifo> video_pipe( | |
| 259 new MediaMessageFifo(std::move(shared_memory_chunk), false)); | |
| 260 video_pipe->ObserveWriteActivity( | |
| 261 base::Bind(&VideoPipelineProxy::OnPipeWrite, weak_this_)); | |
| 262 | |
| 263 video_streamer_->SetMediaMessageFifo(std::move(video_pipe)); | |
| 264 | |
| 265 // Now proceed to the decoder/renderer initialization. | |
| 266 FORWARD_ON_IO_THREAD(Initialize, configs, status_cb); | |
| 267 } | |
| 268 | |
| 269 void VideoPipelineProxy::StartFeeding() { | |
| 270 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 271 DCHECK(video_streamer_); | |
| 272 video_streamer_->Start(); | |
| 273 } | |
| 274 | |
| 275 void VideoPipelineProxy::Flush(const base::Closure& done_cb) { | |
| 276 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 277 DCHECK(video_streamer_); | |
| 278 video_streamer_->StopAndFlush(done_cb); | |
| 279 } | |
| 280 | |
| 281 void VideoPipelineProxy::Stop() { | |
| 282 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 283 if (!video_streamer_) | |
| 284 return; | |
| 285 video_streamer_->StopAndFlush(base::Bind(&IgnoreResult)); | |
| 286 } | |
| 287 | |
| 288 void VideoPipelineProxy::OnPipeWrite() { | |
| 289 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 290 FORWARD_ON_IO_THREAD(NotifyPipeWrite); | |
| 291 } | |
| 292 | |
| 293 void VideoPipelineProxy::OnPipeRead() { | |
| 294 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 295 if (video_streamer_) | |
| 296 video_streamer_->OnFifoReadEvent(); | |
| 297 } | |
| 298 | |
| 299 } // namespace media | |
| 300 } // namespace chromecast | |
| OLD | NEW |