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