Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: content/browser/renderer_host/media/video_capture_controller.cc

Issue 8417046: refactor video capture in browser process to support device sharing across multiple renderer proc... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: code review Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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(&current_params_, 0, sizeof(current_params_));
27 memset(&params_, 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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698