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

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

Powered by Google App Engine
This is Rietveld 408576698