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 |