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 // 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(¤t_params_, 0, sizeof(current_params_)); |
27 memset(¶ms_, 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) |
| 174 << "The buffer is not used by 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) |
59 ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && | 227 << "The buffer is not used by 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; |
| 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()) |
| 378 << "Device is restarted without releasing shared 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 const ControllerClients& clients) { |
| 496 for (ControllerClients::const_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 } | |
OLD | NEW |