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