OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | |
5 // Notes about usage of this object by VideoCaptureImplManager. | |
6 // | |
7 // VideoCaptureImplManager access this object by using a Unretained() | |
8 // binding and tasks on the IO thread. It is then important that | |
9 // VideoCaptureImpl never post task to itself. All operations must be | |
10 // synchronous. | |
11 | 4 |
12 #include "content/renderer/media/video_capture_impl.h" | 5 #include "content/renderer/media/video_capture_impl.h" |
13 | 6 |
14 #include "base/bind.h" | 7 #include "base/bind.h" |
15 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
16 #include "content/child/child_process.h" | 9 #include "content/child/child_process.h" |
17 #include "content/common/media/video_capture_messages.h" | 10 #include "content/common/media/video_capture_messages.h" |
18 #include "media/base/bind_to_current_loop.h" | 11 #include "media/base/bind_to_current_loop.h" |
19 #include "media/base/limits.h" | 12 #include "media/base/limits.h" |
20 #include "media/base/video_frame.h" | 13 #include "media/base/video_frame.h" |
(...skipping 11 matching lines...) Expand all Loading... |
32 const size_t buffer_size; | 25 const size_t buffer_size; |
33 | 26 |
34 private: | 27 private: |
35 friend class base::RefCountedThreadSafe<ClientBuffer>; | 28 friend class base::RefCountedThreadSafe<ClientBuffer>; |
36 | 29 |
37 virtual ~ClientBuffer() {} | 30 virtual ~ClientBuffer() {} |
38 | 31 |
39 DISALLOW_COPY_AND_ASSIGN(ClientBuffer); | 32 DISALLOW_COPY_AND_ASSIGN(ClientBuffer); |
40 }; | 33 }; |
41 | 34 |
42 VideoCaptureImpl::ClientInfo::ClientInfo() {} | 35 bool VideoCaptureImpl::CaptureStarted() { |
43 VideoCaptureImpl::ClientInfo::~ClientInfo() {} | 36 return state_ == VIDEO_CAPTURE_STATE_STARTED; |
| 37 } |
| 38 |
| 39 int VideoCaptureImpl::CaptureFrameRate() { |
| 40 return last_frame_format_.frame_rate; |
| 41 } |
44 | 42 |
45 VideoCaptureImpl::VideoCaptureImpl( | 43 VideoCaptureImpl::VideoCaptureImpl( |
46 const media::VideoCaptureSessionId session_id, | 44 const media::VideoCaptureSessionId session_id, |
47 VideoCaptureMessageFilter* filter) | 45 VideoCaptureMessageFilter* filter) |
48 : message_filter_(filter), | 46 : VideoCapture(), |
| 47 message_filter_(filter), |
| 48 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), |
49 device_id_(0), | 49 device_id_(0), |
50 session_id_(session_id), | 50 session_id_(session_id), |
51 suspended_(false), | 51 suspended_(false), |
52 state_(VIDEO_CAPTURE_STATE_STOPPED), | 52 state_(VIDEO_CAPTURE_STATE_STOPPED), |
53 weak_factory_(this) { | 53 weak_factory_(this) { |
54 DCHECK(filter); | 54 DCHECK(filter); |
55 thread_checker_.DetachFromThread(); | |
56 } | 55 } |
57 | 56 |
58 VideoCaptureImpl::~VideoCaptureImpl() { | 57 VideoCaptureImpl::~VideoCaptureImpl() {} |
59 DCHECK(thread_checker_.CalledOnValidThread()); | 58 |
| 59 void VideoCaptureImpl::Init() { |
| 60 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 61 base::Bind(&VideoCaptureImpl::InitOnIOThread, |
| 62 base::Unretained(this))); |
60 } | 63 } |
61 | 64 |
62 void VideoCaptureImpl::Init() { | 65 void VideoCaptureImpl::DeInit(base::Closure done_cb) { |
63 DCHECK(thread_checker_.CalledOnValidThread()); | 66 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 67 base::Bind(&VideoCaptureImpl::DeInitOnIOThread, |
| 68 base::Unretained(this), |
| 69 done_cb)); |
| 70 } |
| 71 |
| 72 void VideoCaptureImpl::SuspendCapture(bool suspend) { |
| 73 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 74 base::Bind(&VideoCaptureImpl::SuspendCaptureOnIOThread, |
| 75 base::Unretained(this), |
| 76 suspend)); |
| 77 } |
| 78 |
| 79 void VideoCaptureImpl::StartCapture( |
| 80 media::VideoCapture::EventHandler* handler, |
| 81 const media::VideoCaptureParams& params) { |
| 82 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 83 base::Bind(&VideoCaptureImpl::StartCaptureOnIOThread, |
| 84 base::Unretained(this), handler, params)); |
| 85 } |
| 86 |
| 87 void VideoCaptureImpl::StopCapture( |
| 88 media::VideoCapture::EventHandler* handler) { |
| 89 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 90 base::Bind(&VideoCaptureImpl::StopCaptureOnIOThread, |
| 91 base::Unretained(this), handler)); |
| 92 } |
| 93 |
| 94 void VideoCaptureImpl::GetDeviceSupportedFormats( |
| 95 const DeviceFormatsCallback& callback) { |
| 96 DCHECK(!callback.is_null()); |
| 97 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 98 base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormatsOnIOThread, |
| 99 base::Unretained(this), media::BindToCurrentLoop(callback))); |
| 100 } |
| 101 |
| 102 void VideoCaptureImpl::GetDeviceFormatsInUse( |
| 103 const DeviceFormatsInUseCallback& callback) { |
| 104 DCHECK(!callback.is_null()); |
| 105 io_message_loop_proxy_->PostTask(FROM_HERE, |
| 106 base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUseOnIOThread, |
| 107 base::Unretained(this), media::BindToCurrentLoop(callback))); |
| 108 } |
| 109 |
| 110 void VideoCaptureImpl::InitOnIOThread() { |
| 111 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
64 message_filter_->AddDelegate(this); | 112 message_filter_->AddDelegate(this); |
65 } | 113 } |
66 | 114 |
67 void VideoCaptureImpl::DeInit() { | 115 void VideoCaptureImpl::DeInitOnIOThread(base::Closure done_cb) { |
68 DCHECK(thread_checker_.CalledOnValidThread()); | 116 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
69 if (state_ == VIDEO_CAPTURE_STATE_STARTED) | 117 if (state_ == VIDEO_CAPTURE_STATE_STARTED) |
70 Send(new VideoCaptureHostMsg_Stop(device_id_)); | 118 Send(new VideoCaptureHostMsg_Stop(device_id_)); |
71 message_filter_->RemoveDelegate(this); | 119 message_filter_->RemoveDelegate(this); |
| 120 done_cb.Run(); |
72 } | 121 } |
73 | 122 |
74 void VideoCaptureImpl::SuspendCapture(bool suspend) { | 123 void VideoCaptureImpl::SuspendCaptureOnIOThread(bool suspend) { |
75 DCHECK(thread_checker_.CalledOnValidThread()); | 124 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
76 suspended_ = suspend; | 125 suspended_ = suspend; |
77 } | 126 } |
78 | 127 |
79 void VideoCaptureImpl::StartCapture( | 128 void VideoCaptureImpl::StartCaptureOnIOThread( |
80 int client_id, | 129 media::VideoCapture::EventHandler* handler, |
81 const media::VideoCaptureParams& params, | 130 const media::VideoCaptureParams& params) { |
82 const VideoCaptureStateUpdateCB& state_update_cb, | 131 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
83 const VideoCaptureDeliverFrameCB& deliver_frame_cb) { | |
84 DCHECK(thread_checker_.CalledOnValidThread()); | |
85 ClientInfo client_info; | |
86 client_info.params = params; | |
87 client_info.state_update_cb = state_update_cb; | |
88 client_info.deliver_frame_cb = deliver_frame_cb; | |
89 | |
90 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { | 132 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { |
91 state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); | 133 handler->OnError(this, 1); |
92 } else if (clients_pending_on_filter_.count(client_id) || | 134 handler->OnRemoved(this); |
93 clients_pending_on_restart_.count(client_id) || | 135 } else if ((clients_pending_on_filter_.find(handler) != |
94 clients_.count(client_id)) { | 136 clients_pending_on_filter_.end()) || |
95 LOG(FATAL) << "This client has already started."; | 137 (clients_pending_on_restart_.find(handler) != |
| 138 clients_pending_on_restart_.end()) || |
| 139 clients_.find(handler) != clients_.end() ) { |
| 140 // This client has started. |
96 } else if (!device_id_) { | 141 } else if (!device_id_) { |
97 clients_pending_on_filter_[client_id] = client_info; | 142 clients_pending_on_filter_[handler] = params; |
98 } else { | 143 } else { |
99 // Note: |state_| might not be started at this point. But we tell | 144 handler->OnStarted(this); |
100 // client that we have started. | |
101 state_update_cb.Run(VIDEO_CAPTURE_STATE_STARTED); | |
102 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 145 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
103 clients_[client_id] = client_info; | 146 clients_[handler] = params; |
104 // TODO(sheu): Allowing resolution change will require that all | 147 // TODO(sheu): Allowing resolution change will require that all |
105 // outstanding clients of a capture session support resolution change. | 148 // outstanding clients of a capture session support resolution change. |
106 DCHECK_EQ(params_.allow_resolution_change, | 149 DCHECK_EQ(params_.allow_resolution_change, |
107 params.allow_resolution_change); | 150 params.allow_resolution_change); |
108 } else if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 151 } else if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
109 clients_pending_on_restart_[client_id] = client_info; | 152 clients_pending_on_restart_[handler] = params; |
110 DVLOG(1) << "StartCapture: Got new resolution " | 153 DVLOG(1) << "StartCapture: Got new resolution " |
111 << params.requested_format.frame_size.ToString() | 154 << params.requested_format.frame_size.ToString() |
112 << " during stopping."; | 155 << " during stopping."; |
113 } else { | 156 } else { |
114 clients_[client_id] = client_info; | 157 clients_[handler] = params; |
115 if (state_ == VIDEO_CAPTURE_STATE_STARTED) | 158 DCHECK_EQ(1ul, clients_.size()); |
116 return; | |
117 params_ = params; | 159 params_ = params; |
118 if (params_.requested_format.frame_rate > | 160 if (params_.requested_format.frame_rate > |
119 media::limits::kMaxFramesPerSecond) { | 161 media::limits::kMaxFramesPerSecond) { |
120 params_.requested_format.frame_rate = | 162 params_.requested_format.frame_rate = |
121 media::limits::kMaxFramesPerSecond; | 163 media::limits::kMaxFramesPerSecond; |
122 } | 164 } |
123 DVLOG(1) << "StartCapture: starting with first resolution " | 165 DVLOG(1) << "StartCapture: starting with first resolution " |
124 << params_.requested_format.frame_size.ToString(); | 166 << params_.requested_format.frame_size.ToString(); |
125 first_frame_timestamp_ = base::TimeTicks(); | 167 first_frame_timestamp_ = base::TimeTicks(); |
126 StartCaptureInternal(); | 168 StartCaptureInternal(); |
127 } | 169 } |
128 } | 170 } |
129 } | 171 } |
130 | 172 |
131 void VideoCaptureImpl::StopCapture(int client_id) { | 173 void VideoCaptureImpl::StopCaptureOnIOThread( |
132 DCHECK(thread_checker_.CalledOnValidThread()); | 174 media::VideoCapture::EventHandler* handler) { |
| 175 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
133 | 176 |
134 // A client ID can be in only one client list. | 177 // A handler can be in only one client list. |
135 // If this ID is in any client list, we can just remove it from | 178 // If this handler is in any client list, we can just remove it from |
136 // that client list and don't have to run the other following RemoveClient(). | 179 // that client list and don't have to run the other following RemoveClient(). |
137 if (!RemoveClient(client_id, &clients_pending_on_filter_)) { | 180 RemoveClient(handler, &clients_pending_on_filter_) || |
138 if (!RemoveClient(client_id, &clients_pending_on_restart_)) { | 181 RemoveClient(handler, &clients_pending_on_restart_) || |
139 bool removed = RemoveClient(client_id, &clients_); | 182 RemoveClient(handler, &clients_); |
140 DCHECK(removed) << "Removing a non-existent client."; | |
141 } | |
142 } | |
143 | 183 |
144 if (clients_.empty()) { | 184 if (clients_.empty()) { |
145 DVLOG(1) << "StopCapture: No more client, stopping ..."; | 185 DVLOG(1) << "StopCapture: No more client, stopping ..."; |
146 StopDevice(); | 186 StopDevice(); |
147 client_buffers_.clear(); | 187 client_buffers_.clear(); |
148 weak_factory_.InvalidateWeakPtrs(); | 188 weak_factory_.InvalidateWeakPtrs(); |
149 } | 189 } |
150 } | 190 } |
151 | 191 |
152 void VideoCaptureImpl::GetDeviceSupportedFormats( | 192 void VideoCaptureImpl::GetDeviceSupportedFormatsOnIOThread( |
153 const VideoCaptureDeviceFormatsCB& callback) { | 193 const DeviceFormatsCallback& callback) { |
154 DCHECK(thread_checker_.CalledOnValidThread()); | 194 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
155 device_formats_cb_queue_.push_back(callback); | 195 device_formats_callback_queue_.push_back(callback); |
156 if (device_formats_cb_queue_.size() == 1) | 196 if (device_formats_callback_queue_.size() == 1) |
157 Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_, | 197 Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_, |
158 session_id_)); | 198 session_id_)); |
159 } | 199 } |
160 | 200 |
161 void VideoCaptureImpl::GetDeviceFormatsInUse( | 201 void VideoCaptureImpl::GetDeviceFormatsInUseOnIOThread( |
162 const VideoCaptureDeviceFormatsCB& callback) { | 202 const DeviceFormatsInUseCallback& callback) { |
163 DCHECK(thread_checker_.CalledOnValidThread()); | 203 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
164 device_formats_in_use_cb_queue_.push_back(callback); | 204 device_formats_in_use_callback_queue_.push_back(callback); |
165 if (device_formats_in_use_cb_queue_.size() == 1) | 205 if (device_formats_in_use_callback_queue_.size() == 1) |
166 Send( | 206 Send( |
167 new VideoCaptureHostMsg_GetDeviceFormatsInUse(device_id_, session_id_)); | 207 new VideoCaptureHostMsg_GetDeviceFormatsInUse(device_id_, session_id_)); |
168 } | 208 } |
169 | 209 |
170 void VideoCaptureImpl::OnBufferCreated( | 210 void VideoCaptureImpl::OnBufferCreated( |
171 base::SharedMemoryHandle handle, | 211 base::SharedMemoryHandle handle, |
172 int length, int buffer_id) { | 212 int length, int buffer_id) { |
173 DCHECK(thread_checker_.CalledOnValidThread()); | 213 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
174 | 214 |
175 // In case client calls StopCapture before the arrival of created buffer, | 215 // In case client calls StopCapture before the arrival of created buffer, |
176 // just close this buffer and return. | 216 // just close this buffer and return. |
177 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { | 217 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { |
178 base::SharedMemory::CloseHandle(handle); | 218 base::SharedMemory::CloseHandle(handle); |
179 return; | 219 return; |
180 } | 220 } |
181 | 221 |
182 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false)); | 222 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false)); |
183 if (!shm->Map(length)) { | 223 if (!shm->Map(length)) { |
184 DLOG(ERROR) << "OnBufferCreated: Map failed."; | 224 DLOG(ERROR) << "OnBufferCreated: Map failed."; |
185 return; | 225 return; |
186 } | 226 } |
187 | 227 |
188 bool inserted = | 228 bool inserted = |
189 client_buffers_.insert(std::make_pair( | 229 client_buffers_.insert(std::make_pair( |
190 buffer_id, | 230 buffer_id, |
191 new ClientBuffer(shm.Pass(), | 231 new ClientBuffer(shm.Pass(), |
192 length))).second; | 232 length))).second; |
193 DCHECK(inserted); | 233 DCHECK(inserted); |
194 } | 234 } |
195 | 235 |
196 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { | 236 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { |
197 DCHECK(thread_checker_.CalledOnValidThread()); | 237 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
198 | 238 |
199 ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); | 239 ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); |
200 if (iter == client_buffers_.end()) | 240 if (iter == client_buffers_.end()) |
201 return; | 241 return; |
202 | 242 |
203 DCHECK(!iter->second || iter->second->HasOneRef()) | 243 DCHECK(!iter->second || iter->second->HasOneRef()) |
204 << "Instructed to delete buffer we are still using."; | 244 << "Instructed to delete buffer we are still using."; |
205 client_buffers_.erase(iter); | 245 client_buffers_.erase(iter); |
206 } | 246 } |
207 | 247 |
208 void VideoCaptureImpl::OnBufferReceived(int buffer_id, | 248 void VideoCaptureImpl::OnBufferReceived(int buffer_id, |
209 const media::VideoCaptureFormat& format, | 249 const media::VideoCaptureFormat& format, |
210 base::TimeTicks timestamp) { | 250 base::TimeTicks timestamp) { |
211 DCHECK(thread_checker_.CalledOnValidThread()); | 251 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
212 | 252 |
213 // The capture pipeline supports only I420 for now. | 253 // The capture pipeline supports only I420 for now. |
214 DCHECK_EQ(format.pixel_format, media::PIXEL_FORMAT_I420); | 254 DCHECK_EQ(format.pixel_format, media::PIXEL_FORMAT_I420); |
215 | 255 |
216 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 256 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
217 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); | 257 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); |
218 return; | 258 return; |
219 } | 259 } |
220 | 260 |
221 last_frame_format_ = format; | 261 last_frame_format_ = format; |
(...skipping 20 matching lines...) Expand all Loading... |
242 buffer->buffer_size, | 282 buffer->buffer_size, |
243 buffer->buffer->handle(), | 283 buffer->buffer->handle(), |
244 timestamp - first_frame_timestamp_, | 284 timestamp - first_frame_timestamp_, |
245 media::BindToCurrentLoop(base::Bind( | 285 media::BindToCurrentLoop(base::Bind( |
246 &VideoCaptureImpl::OnClientBufferFinished, | 286 &VideoCaptureImpl::OnClientBufferFinished, |
247 weak_factory_.GetWeakPtr(), | 287 weak_factory_.GetWeakPtr(), |
248 buffer_id, | 288 buffer_id, |
249 buffer, | 289 buffer, |
250 base::Passed(scoped_ptr<gpu::MailboxHolder>().Pass())))); | 290 base::Passed(scoped_ptr<gpu::MailboxHolder>().Pass())))); |
251 | 291 |
252 for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end(); | 292 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) |
253 ++it) { | 293 it->first->OnFrameReady(this, frame); |
254 it->second.deliver_frame_cb.Run(frame, format); | |
255 } | |
256 } | 294 } |
257 | 295 |
258 static void NullReadPixelsCB(const SkBitmap& bitmap) { NOTIMPLEMENTED(); } | 296 static void NullReadPixelsCB(const SkBitmap& bitmap) { NOTIMPLEMENTED(); } |
259 | 297 |
260 void VideoCaptureImpl::OnMailboxBufferReceived( | 298 void VideoCaptureImpl::OnMailboxBufferReceived( |
261 int buffer_id, | 299 int buffer_id, |
262 const gpu::MailboxHolder& mailbox_holder, | 300 const gpu::MailboxHolder& mailbox_holder, |
263 const media::VideoCaptureFormat& format, | 301 const media::VideoCaptureFormat& format, |
264 base::TimeTicks timestamp) { | 302 base::TimeTicks timestamp) { |
265 DCHECK(thread_checker_.CalledOnValidThread()); | 303 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
266 | 304 |
267 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 305 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
268 Send(new VideoCaptureHostMsg_BufferReady( | 306 Send(new VideoCaptureHostMsg_BufferReady( |
269 device_id_, buffer_id, mailbox_holder.sync_point)); | 307 device_id_, buffer_id, mailbox_holder.sync_point)); |
270 return; | 308 return; |
271 } | 309 } |
272 | 310 |
273 last_frame_format_ = format; | 311 last_frame_format_ = format; |
274 if (first_frame_timestamp_.is_null()) | 312 if (first_frame_timestamp_.is_null()) |
275 first_frame_timestamp_ = timestamp; | 313 first_frame_timestamp_ = timestamp; |
276 | 314 |
277 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture( | 315 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture( |
278 make_scoped_ptr(new gpu::MailboxHolder(mailbox_holder)), | 316 make_scoped_ptr(new gpu::MailboxHolder(mailbox_holder)), |
279 media::BindToCurrentLoop( | 317 media::BindToCurrentLoop( |
280 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, | 318 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, |
281 weak_factory_.GetWeakPtr(), | 319 weak_factory_.GetWeakPtr(), |
282 buffer_id, | 320 buffer_id, |
283 scoped_refptr<ClientBuffer>())), | 321 scoped_refptr<ClientBuffer>())), |
284 last_frame_format_.frame_size, | 322 last_frame_format_.frame_size, |
285 gfx::Rect(last_frame_format_.frame_size), | 323 gfx::Rect(last_frame_format_.frame_size), |
286 last_frame_format_.frame_size, | 324 last_frame_format_.frame_size, |
287 timestamp - first_frame_timestamp_, | 325 timestamp - first_frame_timestamp_, |
288 base::Bind(&NullReadPixelsCB)); | 326 base::Bind(&NullReadPixelsCB)); |
289 | 327 |
290 for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end(); | 328 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) |
291 ++it) { | 329 it->first->OnFrameReady(this, frame); |
292 it->second.deliver_frame_cb.Run(frame, format); | |
293 } | |
294 } | 330 } |
295 | 331 |
296 void VideoCaptureImpl::OnClientBufferFinished( | 332 void VideoCaptureImpl::OnClientBufferFinished( |
297 int buffer_id, | 333 int buffer_id, |
298 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, | 334 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, |
299 scoped_ptr<gpu::MailboxHolder> mailbox_holder) { | 335 scoped_ptr<gpu::MailboxHolder> mailbox_holder) { |
300 DCHECK(thread_checker_.CalledOnValidThread()); | 336 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
301 const uint32 sync_point = (mailbox_holder ? mailbox_holder->sync_point : 0); | 337 const uint32 sync_point = (mailbox_holder ? mailbox_holder->sync_point : 0); |
302 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, sync_point)); | 338 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, sync_point)); |
303 } | 339 } |
304 | 340 |
305 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { | 341 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { |
306 DCHECK(thread_checker_.CalledOnValidThread()); | 342 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
307 | 343 |
308 switch (state) { | 344 switch (state) { |
309 case VIDEO_CAPTURE_STATE_STARTED: | 345 case VIDEO_CAPTURE_STATE_STARTED: |
310 // Camera has started in the browser process. Since we have already | |
311 // told all clients that we have started there's nothing to do. | |
312 break; | 346 break; |
313 case VIDEO_CAPTURE_STATE_STOPPED: | 347 case VIDEO_CAPTURE_STATE_STOPPED: |
314 state_ = VIDEO_CAPTURE_STATE_STOPPED; | 348 state_ = VIDEO_CAPTURE_STATE_STOPPED; |
315 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; | 349 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; |
316 client_buffers_.clear(); | 350 client_buffers_.clear(); |
317 weak_factory_.InvalidateWeakPtrs(); | 351 weak_factory_.InvalidateWeakPtrs(); |
318 if (!clients_.empty() || !clients_pending_on_restart_.empty()) | 352 if (!clients_.empty() || !clients_pending_on_restart_.empty()) |
319 RestartCapture(); | 353 RestartCapture(); |
320 break; | 354 break; |
321 case VIDEO_CAPTURE_STATE_PAUSED: | 355 case VIDEO_CAPTURE_STATE_PAUSED: |
322 for (ClientInfoMap::iterator it = clients_.begin(); | 356 for (ClientInfo::iterator it = clients_.begin(); |
323 it != clients_.end(); ++it) { | 357 it != clients_.end(); ++it) { |
324 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED); | 358 it->first->OnPaused(this); |
325 } | 359 } |
326 break; | 360 break; |
327 case VIDEO_CAPTURE_STATE_ERROR: | 361 case VIDEO_CAPTURE_STATE_ERROR: |
328 DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; | 362 DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; |
329 for (ClientInfoMap::iterator it = clients_.begin(); | 363 for (ClientInfo::iterator it = clients_.begin(); |
330 it != clients_.end(); ++it) { | 364 it != clients_.end(); ++it) { |
331 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); | 365 // TODO(wjia): browser process would send error code. |
| 366 it->first->OnError(this, 1); |
| 367 it->first->OnRemoved(this); |
332 } | 368 } |
333 clients_.clear(); | 369 clients_.clear(); |
334 state_ = VIDEO_CAPTURE_STATE_ERROR; | 370 state_ = VIDEO_CAPTURE_STATE_ERROR; |
335 break; | 371 break; |
336 case VIDEO_CAPTURE_STATE_ENDED: | 372 case VIDEO_CAPTURE_STATE_ENDED: |
337 DVLOG(1) << "OnStateChanged: ended!, device_id = " << device_id_; | 373 DVLOG(1) << "OnStateChanged: ended!, device_id = " << device_id_; |
338 for (ClientInfoMap::iterator it = clients_.begin(); | 374 for (ClientInfo::iterator it = clients_.begin(); |
339 it != clients_.end(); ++it) { | 375 it != clients_.end(); ++it) { |
340 // We'll only notify the client that the stream has stopped. | 376 it->first->OnRemoved(this); |
341 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); | |
342 } | 377 } |
343 clients_.clear(); | 378 clients_.clear(); |
344 state_ = VIDEO_CAPTURE_STATE_ENDED; | 379 state_ = VIDEO_CAPTURE_STATE_ENDED; |
345 break; | 380 break; |
346 default: | 381 default: |
347 break; | 382 break; |
348 } | 383 } |
349 } | 384 } |
350 | 385 |
351 void VideoCaptureImpl::OnDeviceSupportedFormatsEnumerated( | 386 void VideoCaptureImpl::OnDeviceSupportedFormatsEnumerated( |
352 const media::VideoCaptureFormats& supported_formats) { | 387 const media::VideoCaptureFormats& supported_formats) { |
353 DCHECK(thread_checker_.CalledOnValidThread()); | 388 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
354 for (size_t i = 0; i < device_formats_cb_queue_.size(); ++i) | 389 for (size_t i = 0; i < device_formats_callback_queue_.size(); ++i) |
355 device_formats_cb_queue_[i].Run(supported_formats); | 390 device_formats_callback_queue_[i].Run(supported_formats); |
356 device_formats_cb_queue_.clear(); | 391 device_formats_callback_queue_.clear(); |
357 } | 392 } |
358 | 393 |
359 void VideoCaptureImpl::OnDeviceFormatsInUseReceived( | 394 void VideoCaptureImpl::OnDeviceFormatsInUseReceived( |
360 const media::VideoCaptureFormats& formats_in_use) { | 395 const media::VideoCaptureFormats& formats_in_use) { |
361 DCHECK(thread_checker_.CalledOnValidThread()); | 396 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
362 for (size_t i = 0; i < device_formats_in_use_cb_queue_.size(); ++i) | 397 for (size_t i = 0; i < device_formats_in_use_callback_queue_.size(); ++i) |
363 device_formats_in_use_cb_queue_[i].Run(formats_in_use); | 398 device_formats_in_use_callback_queue_[i].Run(formats_in_use); |
364 device_formats_in_use_cb_queue_.clear(); | 399 device_formats_in_use_callback_queue_.clear(); |
365 } | 400 } |
366 | 401 |
367 void VideoCaptureImpl::OnDelegateAdded(int32 device_id) { | 402 void VideoCaptureImpl::OnDelegateAdded(int32 device_id) { |
368 DCHECK(thread_checker_.CalledOnValidThread()); | |
369 DVLOG(1) << "OnDelegateAdded: device_id " << device_id; | 403 DVLOG(1) << "OnDelegateAdded: device_id " << device_id; |
| 404 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
370 | 405 |
371 device_id_ = device_id; | 406 device_id_ = device_id; |
372 for (ClientInfoMap::iterator it = clients_pending_on_filter_.begin(); | 407 for (ClientInfo::iterator it = clients_pending_on_filter_.begin(); |
373 it != clients_pending_on_filter_.end(); ) { | 408 it != clients_pending_on_filter_.end(); ) { |
374 int client_id = it->first; | 409 media::VideoCapture::EventHandler* handler = it->first; |
375 VideoCaptureStateUpdateCB state_update_cb = | 410 const media::VideoCaptureParams params = it->second; |
376 it->second.state_update_cb; | |
377 VideoCaptureDeliverFrameCB deliver_frame_cb = | |
378 it->second.deliver_frame_cb; | |
379 const media::VideoCaptureParams params = it->second.params; | |
380 clients_pending_on_filter_.erase(it++); | 411 clients_pending_on_filter_.erase(it++); |
381 StartCapture(client_id, params, state_update_cb, | 412 StartCapture(handler, params); |
382 deliver_frame_cb); | |
383 } | 413 } |
384 } | 414 } |
385 | 415 |
386 void VideoCaptureImpl::StopDevice() { | 416 void VideoCaptureImpl::StopDevice() { |
387 DCHECK(thread_checker_.CalledOnValidThread()); | 417 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
388 | 418 |
389 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 419 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
390 state_ = VIDEO_CAPTURE_STATE_STOPPING; | 420 state_ = VIDEO_CAPTURE_STATE_STOPPING; |
391 Send(new VideoCaptureHostMsg_Stop(device_id_)); | 421 Send(new VideoCaptureHostMsg_Stop(device_id_)); |
392 params_.requested_format.frame_size.SetSize(0, 0); | 422 params_.requested_format.frame_size.SetSize(0, 0); |
393 } | 423 } |
394 } | 424 } |
395 | 425 |
396 void VideoCaptureImpl::RestartCapture() { | 426 void VideoCaptureImpl::RestartCapture() { |
397 DCHECK(thread_checker_.CalledOnValidThread()); | 427 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
398 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED); | 428 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED); |
399 | 429 |
400 int width = 0; | 430 int width = 0; |
401 int height = 0; | 431 int height = 0; |
402 clients_.insert(clients_pending_on_restart_.begin(), | 432 for (ClientInfo::iterator it = clients_.begin(); |
403 clients_pending_on_restart_.end()); | |
404 clients_pending_on_restart_.clear(); | |
405 for (ClientInfoMap::iterator it = clients_.begin(); | |
406 it != clients_.end(); ++it) { | 433 it != clients_.end(); ++it) { |
407 width = std::max(width, | 434 width = std::max(width, it->second.requested_format.frame_size.width()); |
408 it->second.params.requested_format.frame_size.width()); | 435 height = std::max(height, it->second.requested_format.frame_size.height()); |
409 height = std::max(height, | 436 } |
410 it->second.params.requested_format.frame_size.height()); | 437 for (ClientInfo::iterator it = clients_pending_on_restart_.begin(); |
| 438 it != clients_pending_on_restart_.end(); ) { |
| 439 width = std::max(width, it->second.requested_format.frame_size.width()); |
| 440 height = std::max(height, it->second.requested_format.frame_size.height()); |
| 441 clients_[it->first] = it->second; |
| 442 clients_pending_on_restart_.erase(it++); |
411 } | 443 } |
412 params_.requested_format.frame_size.SetSize(width, height); | 444 params_.requested_format.frame_size.SetSize(width, height); |
413 DVLOG(1) << "RestartCapture, " | 445 DVLOG(1) << "RestartCapture, " |
414 << params_.requested_format.frame_size.ToString(); | 446 << params_.requested_format.frame_size.ToString(); |
415 StartCaptureInternal(); | 447 StartCaptureInternal(); |
416 } | 448 } |
417 | 449 |
418 void VideoCaptureImpl::StartCaptureInternal() { | 450 void VideoCaptureImpl::StartCaptureInternal() { |
419 DCHECK(thread_checker_.CalledOnValidThread()); | 451 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
420 DCHECK(device_id_); | 452 DCHECK(device_id_); |
421 | 453 |
422 Send(new VideoCaptureHostMsg_Start(device_id_, session_id_, params_)); | 454 Send(new VideoCaptureHostMsg_Start(device_id_, session_id_, params_)); |
423 state_ = VIDEO_CAPTURE_STATE_STARTED; | 455 state_ = VIDEO_CAPTURE_STATE_STARTED; |
424 } | 456 } |
425 | 457 |
426 void VideoCaptureImpl::Send(IPC::Message* message) { | 458 void VideoCaptureImpl::Send(IPC::Message* message) { |
427 DCHECK(thread_checker_.CalledOnValidThread()); | 459 io_message_loop_proxy_->PostTask(FROM_HERE, |
428 message_filter_->Send(message); | 460 base::Bind(base::IgnoreResult(&VideoCaptureMessageFilter::Send), |
| 461 message_filter_.get(), message)); |
429 } | 462 } |
430 | 463 |
431 bool VideoCaptureImpl::RemoveClient(int client_id, ClientInfoMap* clients) { | 464 bool VideoCaptureImpl::RemoveClient( |
432 DCHECK(thread_checker_.CalledOnValidThread()); | 465 media::VideoCapture::EventHandler* handler, |
| 466 ClientInfo* clients) { |
| 467 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
433 bool found = false; | 468 bool found = false; |
434 | 469 |
435 ClientInfoMap::iterator it = clients->find(client_id); | 470 ClientInfo::iterator it = clients->find(handler); |
436 if (it != clients->end()) { | 471 if (it != clients->end()) { |
437 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); | 472 handler->OnStopped(this); |
| 473 handler->OnRemoved(this); |
438 clients->erase(it); | 474 clients->erase(it); |
439 found = true; | 475 found = true; |
440 } | 476 } |
441 return found; | 477 return found; |
442 } | 478 } |
443 | 479 |
444 } // namespace content | 480 } // namespace content |
OLD | NEW |