OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 | 4 |
5 #include "content/browser/renderer_host/media/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "content/browser/renderer_host/media/media_stream_manager.h" | 9 #include "content/browser/renderer_host/media/media_stream_manager.h" |
10 #include "content/browser/renderer_host/media/video_capture_manager.h" | 10 #include "content/browser/renderer_host/media/video_capture_manager.h" |
11 #include "content/public/browser/browser_thread.h" | 11 #include "content/public/browser/browser_thread.h" |
12 #include "media/base/yuv_convert.h" | 12 #include "media/base/yuv_convert.h" |
13 | 13 |
14 // The number of TransportDIBs VideoCaptureController allocate. | 14 // The number of DIBs VideoCaptureController allocate. |
15 static const size_t kNoOfDIBS = 3; | 15 static const size_t kNoOfDIBS = 3; |
16 | 16 |
17 struct VideoCaptureController::ControllerClient { | |
18 ControllerClient( | |
19 const VideoCaptureControllerID& id, | |
20 VideoCaptureControllerEventHandler* handler, | |
21 base::ProcessHandle render_process, | |
22 const media::VideoCaptureParams& params) | |
23 : controller_id(id), | |
24 event_handler(handler), | |
25 render_process_handle(render_process), | |
26 parameters(params), | |
27 report_ready_to_delete(false) { | |
28 } | |
29 | |
30 ~ControllerClient() {} | |
31 | |
32 // ID used for identifying this object. | |
33 VideoCaptureControllerID controller_id; | |
34 VideoCaptureControllerEventHandler* event_handler; | |
35 | |
36 // Handle to the render process that will receive the DIBs. | |
37 base::ProcessHandle render_process_handle; | |
38 media::VideoCaptureParams parameters; | |
39 | |
40 // Buffers used by this client. | |
41 std::list<int> buffers; | |
42 | |
43 // Record client's status when it has called StopCapture, but haven't | |
44 // returned all buffers. | |
45 bool report_ready_to_delete; | |
46 }; | |
47 | |
48 struct VideoCaptureController::SharedDIB { | |
49 SharedDIB(base::SharedMemory* ptr) | |
50 : shared_memory(ptr), | |
51 references(0) { | |
52 } | |
53 | |
54 ~SharedDIB() {} | |
55 | |
56 scoped_ptr<base::SharedMemory> shared_memory; | |
57 int references; | |
scherkus (not reviewing)
2011/11/01 02:18:38
documentation for these fields
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
58 }; | |
59 | |
17 VideoCaptureController::VideoCaptureController( | 60 VideoCaptureController::VideoCaptureController( |
18 const VideoCaptureControllerID& id, | |
19 base::ProcessHandle render_process, | |
20 VideoCaptureControllerEventHandler* event_handler, | |
21 media_stream::VideoCaptureManager* video_capture_manager) | 61 media_stream::VideoCaptureManager* video_capture_manager) |
22 : render_handle_(render_process), | 62 : frame_info_available_(false), |
23 report_ready_to_delete_(false), | 63 video_capture_manager_(video_capture_manager), |
24 event_handler_(event_handler), | 64 device_in_use_(false), |
25 id_(id), | 65 state_(media::VideoCapture::kStopped) { |
26 video_capture_manager_(video_capture_manager) { | 66 memset(¤t_params_, 0, sizeof(current_params_)); |
27 memset(¶ms_, 0, sizeof(params_)); | |
28 } | 67 } |
29 | 68 |
30 VideoCaptureController::~VideoCaptureController() { | 69 VideoCaptureController::~VideoCaptureController() { |
31 // Delete all TransportDIBs. | 70 // Delete all DIBs. |
32 STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), | 71 STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), |
33 owned_dibs_.end()); | 72 owned_dibs_.end()); |
73 STLDeleteContainerPointers(controller_clients_.begin(), | |
74 controller_clients_.end()); | |
75 STLDeleteContainerPointers(pending_clients_.begin(), | |
76 pending_clients_.end()); | |
34 } | 77 } |
35 | 78 |
36 void VideoCaptureController::StartCapture( | 79 void VideoCaptureController::StartCapture( |
80 const VideoCaptureControllerID& id, | |
81 VideoCaptureControllerEventHandler* event_handler, | |
82 base::ProcessHandle render_process, | |
37 const media::VideoCaptureParams& params) { | 83 const media::VideoCaptureParams& params) { |
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
39 | 85 // Signal error in case device is already in error state. |
40 params_ = params; | 86 if (state_ == media::VideoCapture::kError) { |
87 event_handler->OnError(id); | |
88 return; | |
89 } | |
90 | |
91 // Do nothing if this client has called StartCapture before. | |
92 if (FindClient(id, event_handler, controller_clients_) || | |
93 FindClient(id, event_handler, pending_clients_)) | |
94 return; | |
95 | |
96 ControllerClient* client = new ControllerClient(id, event_handler, | |
97 render_process, params); | |
98 // In case capture has been started, need to check different condtions. | |
99 if (state_ == media::VideoCapture::kStarted) { | |
100 // This client has higher resolution than what is currently requested. | |
101 // Need restart capturing. | |
102 if (params.width > current_params_.width || | |
103 params.height > current_params_.height) { | |
104 video_capture_manager_->Stop(current_params_.session_id, | |
105 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); | |
106 frame_info_available_ = false; | |
107 state_ = media::VideoCapture::kStopping; | |
108 pending_clients_.push_back(client); | |
109 return; | |
110 } | |
111 | |
112 // This client's resolution is no larger than what's currently requested. | |
113 // When frame_info has been returned by device, send them to client. | |
114 if (frame_info_available_) { | |
115 int buffer_size = (frame_info_.width * frame_info_.height * 3) / 2; | |
116 SendFrameInfoAndBuffers(client, buffer_size); | |
117 } | |
118 controller_clients_.push_back(client); | |
119 return; | |
120 } | |
121 | |
122 // In case the device is in the middle of stopping, put the client in | |
123 // pending queue. | |
124 if (state_ == media::VideoCapture::kStopping) { | |
125 pending_clients_.push_back(client); | |
126 return; | |
127 } | |
128 | |
129 // Fresh start. | |
130 controller_clients_.push_back(client); | |
131 current_params_ = params; | |
41 // Order the manager to start the actual capture. | 132 // Order the manager to start the actual capture. |
42 video_capture_manager_->Start(params, this); | 133 video_capture_manager_->Start(params, this); |
43 } | 134 state_ = media::VideoCapture::kStarted; |
44 | 135 } |
45 void VideoCaptureController::StopCapture(base::Closure stopped_cb) { | 136 |
137 void VideoCaptureController::StopCapture( | |
138 const VideoCaptureControllerID& id, | |
139 VideoCaptureControllerEventHandler* event_handler, | |
140 bool force_buffer_return) { | |
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
47 | 142 |
48 video_capture_manager_->Stop(params_.session_id, | 143 ControllerClient* client = FindClient(id, event_handler, pending_clients_); |
49 base::Bind(&VideoCaptureController::OnDeviceStopped, this, stopped_cb)); | 144 // If the client is still in pending queue, just remove it. |
50 } | 145 if (client) { |
51 | 146 client->event_handler->OnReadyToDelete(client->controller_id); |
52 void VideoCaptureController::ReturnBuffer(int buffer_id) { | 147 pending_clients_.remove(client); |
148 return; | |
149 } | |
150 | |
151 client = FindClient(id, event_handler, controller_clients_); | |
152 // The client should have called StartCapture. | |
153 DCHECK(client); | |
scherkus (not reviewing)
2011/11/01 02:18:38
what about making the comment into a string?
DCHE
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
154 | |
155 if (force_buffer_return) { | |
156 // The client requests to return buffers which means it can't return | |
157 // buffers normally. After buffers are returned, client is free to | |
158 // delete itself. No need to call OnReadyToDelete. | |
159 | |
160 // Return all buffers held by the clients. | |
161 for (std::list<int>::iterator buffer_it = client->buffers.begin(); | |
162 buffer_it != client->buffers.end(); ++buffer_it) { | |
163 int buffer_id = *buffer_it; | |
164 DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); | |
165 if (dib_it == owned_dibs_.end()) | |
166 continue; | |
167 | |
168 if (--dib_it->second->references > 0) | |
scherkus (not reviewing)
2011/11/01 02:18:38
from a quick glance this isn't very clear -- what
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
169 continue; | |
170 | |
171 // Now this |buffer_id| is not used by any client. | |
172 { | |
173 base::AutoLock lock(lock_); | |
174 free_dibs_.push_back(buffer_id); | |
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
175 } | |
176 } | |
177 client->buffers.clear(); | |
178 } else { | |
179 // Normal way to stop capture. | |
180 if (!client->buffers.empty()) { | |
181 // There are still some buffers held by the client. | |
182 client->report_ready_to_delete = true; | |
183 return; | |
184 } | |
185 // No buffer is held by the client. Ready to delete. | |
186 client->event_handler->OnReadyToDelete(client->controller_id); | |
187 } | |
188 | |
189 delete client; | |
190 controller_clients_.remove(client); | |
191 | |
192 // No more clients. Stop device. | |
193 if (controller_clients_.empty()) { | |
194 video_capture_manager_->Stop(current_params_.session_id, | |
195 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); | |
196 frame_info_available_ = false; | |
197 state_ = media::VideoCapture::kStopping; | |
198 } | |
199 } | |
200 | |
201 void VideoCaptureController::ReturnBuffer( | |
202 const VideoCaptureControllerID& id, | |
203 VideoCaptureControllerEventHandler* event_handler, | |
204 int buffer_id) { | |
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
54 | 206 |
55 bool ready_to_delete; | 207 ControllerClient* client = FindClient(id, event_handler, |
208 controller_clients_); | |
scherkus (not reviewing)
2011/11/01 02:18:38
indentation
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
209 DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); | |
210 // If this buffer is not held by this client, or this client doesn't exist | |
211 // in controller, do nothing. | |
212 if (!client || dib_it == owned_dibs_.end()) | |
213 return; | |
214 | |
215 client->buffers.remove(buffer_id); | |
216 // If this client has called StopCapture and doesn't hold any buffer after | |
217 // after this return, ready to delete this client. | |
218 if (client->report_ready_to_delete && client->buffers.empty()) { | |
219 client->event_handler->OnReadyToDelete(client->controller_id); | |
220 delete client; | |
221 controller_clients_.remove(client); | |
222 } | |
223 if (--dib_it->second->references > 0) | |
scherkus (not reviewing)
2011/11/01 02:18:38
ditto
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
224 return; | |
225 | |
226 // Now this |buffer_id| is not used by any client. | |
56 { | 227 { |
57 base::AutoLock lock(lock_); | 228 base::AutoLock lock(lock_); |
58 free_dibs_.push_back(buffer_id); | 229 free_dibs_.push_back(buffer_id); |
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
59 ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && | 230 } |
60 report_ready_to_delete_; | 231 |
61 } | 232 // When all buffers have been returned by clients and device has been |
62 if (ready_to_delete) { | 233 // called to stop, check if restart is needed. This could happen when |
63 event_handler_->OnReadyToDelete(id_); | 234 // some clients call StopCapture before returning all buffers. |
64 } | 235 if (!ClientHasDIB() && state_ == media::VideoCapture::kStopping) { |
65 } | 236 PostStopping(); |
66 | 237 } |
238 } | |
239 | |
67 /////////////////////////////////////////////////////////////////////////////// | 240 /////////////////////////////////////////////////////////////////////////////// |
68 // Implements VideoCaptureDevice::EventHandler. | 241 // Implements VideoCaptureDevice::EventHandler. |
69 // OnIncomingCapturedFrame is called the thread running the capture device. | 242 // OnIncomingCapturedFrame is called the thread running the capture device. |
70 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 243 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
71 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | 244 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, |
72 int length, | 245 int length, |
73 base::Time timestamp) { | 246 base::Time timestamp) { |
74 int buffer_id = 0; | 247 int buffer_id = 0; |
75 base::SharedMemory* dib = NULL; | 248 base::SharedMemory* dib = NULL; |
76 // Check if there is a TransportDIB to fill. | |
77 bool buffer_exist = false; | |
78 { | 249 { |
79 base::AutoLock lock(lock_); | 250 base::AutoLock lock(lock_); |
80 if (!report_ready_to_delete_ && free_dibs_.size() > 0) { | 251 if (!free_dibs_.empty()) { |
scherkus (not reviewing)
2011/11/01 02:18:38
using free_dibs_ isn't really any more efficient b
wjia(left Chromium)
2011/11/01 21:34:23
removed free_dibss_. I have to use a special value
| |
81 buffer_id = free_dibs_.front(); | 252 buffer_id = free_dibs_.front(); |
82 free_dibs_.pop_front(); | 253 free_dibs_.pop_front(); |
83 DIBMap::iterator it = owned_dibs_.find(buffer_id); | 254 DIBMap::iterator it = owned_dibs_.find(buffer_id); |
84 if (it != owned_dibs_.end()) { | 255 if (it != owned_dibs_.end()) { |
85 dib = it->second; | 256 dib = it->second->shared_memory.get(); |
86 buffer_exist = true; | |
87 } | 257 } |
88 } | 258 } |
89 } | 259 } |
90 | 260 |
91 if (!buffer_exist) { | 261 if (!dib) { |
92 return; | 262 return; |
93 } | 263 } |
94 | 264 |
95 uint8* target = static_cast<uint8*>(dib->memory()); | 265 uint8* target = static_cast<uint8*>(dib->memory()); |
96 CHECK(dib->created_size() >= static_cast<size_t> (frame_info_.width * | 266 CHECK(dib->created_size() >= static_cast<size_t> (frame_info_.width * |
97 frame_info_.height * 3) / | 267 frame_info_.height * 3) / |
98 2); | 268 2); |
269 uint8* yplane = target; | |
270 uint8* uplane = target + frame_info_.width * frame_info_.height; | |
271 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | |
99 | 272 |
100 // Do color conversion from the camera format to I420. | 273 // Do color conversion from the camera format to I420. |
101 switch (frame_info_.color) { | 274 switch (frame_info_.color) { |
102 case media::VideoCaptureDevice::kColorUnknown: // Color format not set. | 275 case media::VideoCaptureDevice::kColorUnknown: // Color format not set. |
103 break; | 276 break; |
104 case media::VideoCaptureDevice::kI420: { | 277 case media::VideoCaptureDevice::kI420: { |
105 memcpy(target, data, (frame_info_.width * frame_info_.height * 3) / 2); | 278 memcpy(target, data, (frame_info_.width * frame_info_.height * 3) / 2); |
106 break; | 279 break; |
107 } | 280 } |
108 case media::VideoCaptureDevice::kYUY2: { | 281 case media::VideoCaptureDevice::kYUY2: { |
109 uint8* yplane = target; | |
110 uint8* uplane = target + frame_info_.width * frame_info_.height; | |
111 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | |
112 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 282 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
113 frame_info_.height); | 283 frame_info_.height); |
114 break; | 284 break; |
115 } | 285 } |
116 case media::VideoCaptureDevice::kRGB24: { | 286 case media::VideoCaptureDevice::kRGB24: { |
117 #if defined(OS_WIN) // RGB on Windows start at the bottom line. | |
118 uint8* yplane = target; | |
119 uint8* uplane = target + frame_info_.width * frame_info_.height; | |
120 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | |
121 int ystride = frame_info_.width; | 287 int ystride = frame_info_.width; |
122 int uvstride = frame_info_.width / 2; | 288 int uvstride = frame_info_.width / 2; |
123 int rgb_stride = - 3 * frame_info_.width; | 289 #if defined(OS_WIN) // RGB on Windows start at the bottom line. |
290 int rgb_stride = -3 * frame_info_.width; | |
124 const uint8* rgb_src = data + 3 * frame_info_.width * | 291 const uint8* rgb_src = data + 3 * frame_info_.width * |
125 (frame_info_.height -1); | 292 (frame_info_.height -1); |
126 #else | 293 #else |
127 uint8* yplane = target; | |
128 uint8* uplane = target + frame_info_.width * frame_info_.height; | |
129 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | |
130 int ystride = frame_info_.width; | |
131 int uvstride = frame_info_.width / 2; | |
132 int rgb_stride = 3 * frame_info_.width; | 294 int rgb_stride = 3 * frame_info_.width; |
133 const uint8* rgb_src = data; | 295 const uint8* rgb_src = data; |
134 #endif | 296 #endif |
135 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, | 297 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, |
136 frame_info_.width, frame_info_.height, | 298 frame_info_.width, frame_info_.height, |
137 rgb_stride, ystride, uvstride); | 299 rgb_stride, ystride, uvstride); |
138 break; | 300 break; |
139 } | 301 } |
140 case media::VideoCaptureDevice::kARGB: { | 302 case media::VideoCaptureDevice::kARGB: { |
141 uint8* yplane = target; | |
142 uint8* uplane = target + frame_info_.width * frame_info_.height; | |
143 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | |
144 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 303 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
145 frame_info_.height, frame_info_.width * 4, | 304 frame_info_.height, frame_info_.width * 4, |
146 frame_info_.width, frame_info_.width / 2); | 305 frame_info_.width, frame_info_.width / 2); |
147 break; | 306 break; |
148 } | 307 } |
149 default: | 308 default: |
150 NOTREACHED(); | 309 NOTREACHED(); |
151 } | 310 } |
152 | 311 |
153 event_handler_->OnBufferReady(id_, buffer_id, timestamp); | 312 BrowserThread::PostTask(BrowserThread::IO, |
313 FROM_HERE, | |
314 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
315 this, buffer_id, timestamp)); | |
154 } | 316 } |
155 | 317 |
156 void VideoCaptureController::OnError() { | 318 void VideoCaptureController::OnError() { |
157 event_handler_->OnError(id_); | 319 video_capture_manager_->Error(current_params_.session_id); |
158 video_capture_manager_->Error(params_.session_id); | 320 BrowserThread::PostTask(BrowserThread::IO, |
321 FROM_HERE, | |
322 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | |
159 } | 323 } |
160 | 324 |
161 void VideoCaptureController::OnFrameInfo( | 325 void VideoCaptureController::OnFrameInfo( |
162 const media::VideoCaptureDevice::Capability& info) { | 326 const media::VideoCaptureDevice::Capability& info) { |
327 BrowserThread::PostTask(BrowserThread::IO, | |
328 FROM_HERE, | |
329 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, | |
330 this, info)); | |
331 } | |
332 | |
333 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | |
334 int buffer_id, base::Time timestamp) { | |
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
336 | |
337 if (state_ != media::VideoCapture::kStarted) { | |
scherkus (not reviewing)
2011/11/01 02:18:38
without free_dibs_ you could rewrite this whole fu
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
338 base::AutoLock lock(lock_); | |
339 free_dibs_.push_back(buffer_id); | |
340 return; | |
341 } | |
342 | |
343 int count = 0; | |
344 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
345 client_it != controller_clients_.end(); client_it++) { | |
346 if ((*client_it)->report_ready_to_delete) | |
347 continue; | |
348 | |
349 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, | |
350 buffer_id, timestamp); | |
351 (*client_it)->buffers.push_back(buffer_id); | |
352 count++; | |
353 } | |
354 if (count > 0) { | |
355 owned_dibs_[buffer_id]->references = count; | |
356 } else { | |
357 base::AutoLock lock(lock_); | |
358 free_dibs_.push_back(buffer_id); | |
359 } | |
360 } | |
361 | |
362 void VideoCaptureController::DoErrorOnIOThread() { | |
363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
364 state_ = media::VideoCapture::kError; | |
365 ControllerClients::iterator client_it; | |
366 for (client_it = controller_clients_.begin(); | |
367 client_it != controller_clients_.end(); client_it++) { | |
368 (*client_it)->event_handler->OnError((*client_it)->controller_id); | |
369 } | |
370 for (client_it = pending_clients_.begin(); | |
371 client_it != pending_clients_.end(); client_it++) { | |
372 (*client_it)->event_handler->OnError((*client_it)->controller_id); | |
373 } | |
374 } | |
375 | |
376 void VideoCaptureController::DoFrameInfoOnIOThread( | |
377 const media::VideoCaptureDevice::Capability info) { | |
378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
163 DCHECK(owned_dibs_.empty()); | 379 DCHECK(owned_dibs_.empty()); |
380 | |
164 bool frames_created = true; | 381 bool frames_created = true; |
165 const size_t needed_size = (info.width * info.height * 3) / 2; | 382 const size_t needed_size = (info.width * info.height * 3) / 2; |
166 for (size_t i = 1; i <= kNoOfDIBS; ++i) { | 383 { |
167 base::SharedMemory* shared_memory = new base::SharedMemory(); | 384 base::AutoLock lock(lock_); |
168 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { | 385 for (size_t i = 1; i <= kNoOfDIBS; ++i) { |
169 frames_created = false; | 386 base::SharedMemory* shared_memory = new base::SharedMemory(); |
170 break; | 387 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { |
388 frames_created = false; | |
389 break; | |
390 } | |
391 SharedDIB* dib = new SharedDIB(shared_memory); | |
392 owned_dibs_.insert(std::make_pair(i, dib)); | |
393 free_dibs_.push_back(i); | |
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
171 } | 394 } |
395 } | |
396 // Check whether all DIBs were created successfully. | |
397 if (!frames_created) { | |
398 state_ = media::VideoCapture::kError; | |
399 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
400 client_it != controller_clients_.end(); client_it++) { | |
401 (*client_it)->event_handler->OnError((*client_it)->controller_id); | |
402 } | |
403 return; | |
404 } | |
405 frame_info_= info; | |
406 frame_info_available_ = true; | |
407 | |
408 for (ControllerClients::iterator client_it = controller_clients_.begin(); | |
409 client_it != controller_clients_.end(); client_it++) { | |
410 SendFrameInfoAndBuffers((*client_it), static_cast<int>(needed_size)); | |
411 } | |
412 } | |
413 | |
414 void VideoCaptureController::SendFrameInfoAndBuffers( | |
415 ControllerClient* client, int buffer_size) { | |
416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
417 DCHECK(frame_info_available_); | |
418 client->event_handler->OnFrameInfo(client->controller_id, | |
419 frame_info_.width, frame_info_.height, | |
420 frame_info_.frame_rate); | |
421 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | |
422 dib_it != owned_dibs_.end(); dib_it++) { | |
423 base::SharedMemory* shared_memory = dib_it->second->shared_memory.get(); | |
424 int index = dib_it->first; | |
172 base::SharedMemoryHandle remote_handle; | 425 base::SharedMemoryHandle remote_handle; |
173 shared_memory->ShareToProcess(render_handle_, &remote_handle); | 426 shared_memory->ShareToProcess(client->render_process_handle, |
174 | 427 &remote_handle); |
175 base::AutoLock lock(lock_); | 428 client->event_handler->OnBufferCreated(client->controller_id, |
176 owned_dibs_.insert(std::make_pair(i, shared_memory)); | 429 remote_handle, |
177 free_dibs_.push_back(i); | 430 buffer_size, |
178 event_handler_->OnBufferCreated(id_, remote_handle, | 431 index); |
179 static_cast<int>(needed_size), | 432 } |
180 static_cast<int>(i)); | 433 } |
181 } | 434 |
182 frame_info_= info; | 435 // This function is called when all buffers have been returned to controller, |
183 | 436 // or when device is stopped. It decides whether the device needs to be |
184 // Check that all DIBs where created successfully. | 437 // restarted. |
185 if (!frames_created) { | 438 void VideoCaptureController::PostStopping() { |
186 event_handler_->OnError(id_); | 439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
187 } | 440 DCHECK_EQ(state_, media::VideoCapture::kStopping); |
188 event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); | 441 |
442 // When clients still have some buffers, or device has not been stopped yet, | |
443 // do nothing. | |
444 if (ClientHasDIB() || device_in_use_) | |
445 return; | |
446 | |
447 // It's safe to free all DIB's on IO thread since device won't send | |
448 // buffer over. | |
449 free_dibs_.clear(); | |
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
| |
450 STLDeleteValues(&owned_dibs_); | |
451 | |
452 // No more client. Therefore the controller is stopped. | |
453 if (controller_clients_.empty() && pending_clients_.empty()) { | |
454 state_ = media::VideoCapture::kStopped; | |
455 return; | |
456 } | |
457 | |
458 // Restart the device. | |
459 current_params_.width = 0; | |
460 current_params_.height = 0; | |
461 ControllerClients::iterator client_it; | |
462 for (client_it = controller_clients_.begin(); | |
463 client_it != controller_clients_.end(); client_it++) { | |
464 if (current_params_.width < (*client_it)->parameters.width) | |
465 current_params_.width = (*client_it)->parameters.width; | |
466 if (current_params_.height < (*client_it)->parameters.height) | |
467 current_params_.height = (*client_it)->parameters.height; | |
468 } | |
469 for (client_it = pending_clients_.begin(); | |
470 client_it != pending_clients_.end(); ) { | |
471 if (current_params_.width < (*client_it)->parameters.width) | |
472 current_params_.width = (*client_it)->parameters.width; | |
473 if (current_params_.height < (*client_it)->parameters.height) | |
474 current_params_.height = (*client_it)->parameters.height; | |
475 controller_clients_.push_back((*client_it)); | |
476 pending_clients_.erase(client_it++); | |
477 } | |
478 // Request the manager to start the actual capture. | |
479 video_capture_manager_->Start(current_params_, this); | |
480 state_ = media::VideoCapture::kStarted; | |
481 } | |
482 | |
483 bool VideoCaptureController::ClientHasDIB() { | |
484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
485 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | |
486 dib_it != owned_dibs_.end(); dib_it++) { | |
487 if (dib_it->second->references > 0) | |
488 return true; | |
489 } | |
490 return false; | |
491 } | |
492 | |
493 VideoCaptureController::ControllerClient* | |
494 VideoCaptureController::FindClient( | |
495 const VideoCaptureControllerID& id, | |
496 VideoCaptureControllerEventHandler* handler, | |
497 ControllerClients& clients) { | |
498 for (ControllerClients::iterator client_it = clients.begin(); | |
499 client_it != clients.end(); client_it++) { | |
500 if ((*client_it)->controller_id == id && | |
501 (*client_it)->event_handler == handler) { | |
502 return *client_it; | |
503 } | |
504 } | |
505 return NULL; | |
189 } | 506 } |
190 | 507 |
191 /////////////////////////////////////////////////////////////////////////////// | 508 /////////////////////////////////////////////////////////////////////////////// |
192 // Called by VideoCaptureManager when a device have been stopped. | 509 // Called by VideoCaptureManager when a device have been stopped. |
193 // This will report to the event handler that this object is ready to be deleted | 510 void VideoCaptureController::OnDeviceStopped() { |
194 // if all DIBS have been returned. | 511 BrowserThread::PostTask(BrowserThread::IO, |
195 void VideoCaptureController::OnDeviceStopped(base::Closure stopped_cb) { | 512 FROM_HERE, |
196 bool ready_to_delete_now; | 513 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); |
197 | 514 } |
198 { | 515 |
199 base::AutoLock lock(lock_); | 516 void VideoCaptureController::DoDeviceStoppedOnIOThread() { |
200 // Set flag to indicate we need to report when all DIBs have been returned. | 517 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
201 report_ready_to_delete_ = true; | 518 device_in_use_ = false; |
202 ready_to_delete_now = (free_dibs_.size() == owned_dibs_.size()); | 519 if (state_ == media::VideoCapture::kStopping) { |
203 } | 520 PostStopping(); |
204 | 521 } |
205 if (ready_to_delete_now) { | 522 } |
206 event_handler_->OnReadyToDelete(id_); | 523 |
207 } | |
208 | |
209 if (!stopped_cb.is_null()) | |
210 stopped_cb.Run(); | |
211 } | |
OLD | NEW |