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 VideoCaptureController::VideoCaptureController( | 17 VideoCaptureController::VideoCaptureController( |
| 18 const VideoCaptureControllerID& id, | |
| 19 base::ProcessHandle render_process, | |
| 20 VideoCaptureControllerEventHandler* event_handler, | |
| 21 media_stream::VideoCaptureManager* video_capture_manager) | 18 media_stream::VideoCaptureManager* video_capture_manager) |
| 22 : render_handle_(render_process), | 19 : frame_info_available_(false), |
| 23 report_ready_to_delete_(false), | 20 video_capture_manager_(video_capture_manager), |
| 24 event_handler_(event_handler), | 21 state_(media::VideoCapture::kStopped) { |
| 25 id_(id), | |
| 26 video_capture_manager_(video_capture_manager) { | |
| 27 memset(¶ms_, 0, sizeof(params_)); | 22 memset(¶ms_, 0, sizeof(params_)); |
| 28 } | 23 } |
| 29 | 24 |
| 30 VideoCaptureController::~VideoCaptureController() { | 25 VideoCaptureController::~VideoCaptureController() { |
| 31 // Delete all TransportDIBs. | 26 // Delete all DIBs. |
| 32 STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), | 27 STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), |
| 33 owned_dibs_.end()); | 28 owned_dibs_.end()); |
| 29 STLDeleteContainerPointers(controller_clients_.begin(), | |
| 30 controller_clients_.end()); | |
| 34 } | 31 } |
| 35 | 32 |
| 36 void VideoCaptureController::StartCapture( | 33 void VideoCaptureController::StartCapture( |
| 34 const VideoCaptureControllerID& id, | |
| 35 VideoCaptureControllerEventHandler* event_handler, | |
| 36 base::ProcessHandle render_process, | |
| 37 const media::VideoCaptureParams& params) { | 37 const media::VideoCaptureParams& params) { |
| 38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 39 if (state_ == media::VideoCapture::kError) { | |
| 40 event_handler->OnError(id); | |
| 41 return; | |
| 42 } | |
| 43 | |
| 44 if (FindClient(id, event_handler) != controller_clients_.end()) | |
| 45 return; | |
| 46 | |
| 47 ControllerClient* client = new ControllerClient(id, event_handler, | |
| 48 render_process, params); | |
| 49 controller_clients_.push_front(client); | |
| 50 if (state_ == media::VideoCapture::kStarted) { | |
|
perkj_chrome
2011/10/17 08:39:43
What if you run webrtc? First you start a local pr
wjia(left Chromium)
2011/10/21 00:56:13
The resolution change in webrtc is handled in rend
| |
| 51 if (frame_info_available_) { | |
| 52 SendFrameInfoAndBuffers(client); | |
| 53 } | |
| 54 return; | |
| 55 } | |
| 39 | 56 |
| 40 params_ = params; | 57 params_ = params; |
| 41 // Order the manager to start the actual capture. | 58 // Order the manager to start the actual capture. |
| 42 video_capture_manager_->Start(params, this); | 59 video_capture_manager_->Start(params, this); |
| 60 state_ = media::VideoCapture::kStarted; | |
| 43 } | 61 } |
| 44 | 62 |
| 45 void VideoCaptureController::StopCapture(base::Closure stopped_cb) { | 63 void VideoCaptureController::StopCapture( |
| 64 const VideoCaptureControllerID& id, | |
| 65 VideoCaptureControllerEventHandler* event_handler, | |
| 66 bool force_buffer_return) { | |
| 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 47 | 68 |
| 48 video_capture_manager_->Stop(params_.session_id, | 69 ControllerClients::iterator cit = FindClient(id, event_handler); |
| 49 base::Bind(&VideoCaptureController::OnDeviceStopped, this, stopped_cb)); | 70 if (cit == controller_clients_.end()) |
| 71 return; | |
|
perkj_chrome
2011/10/17 08:39:43
DCHECK ?
wjia(left Chromium)
2011/10/21 00:56:13
Done.
| |
| 72 | |
| 73 if (force_buffer_return) { | |
| 74 for (std::list<int>::iterator bit = (*cit)->buffers.begin(); | |
| 75 bit != (*cit)->buffers.end(); ++bit) { | |
| 76 ReturnBuffer(id, event_handler, *bit); | |
| 77 } | |
| 78 } else { | |
| 79 if ((*cit)->buffers.size() > 0) { | |
| 80 (*cit)->report_ready_to_delete = true; | |
| 81 return; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); | |
| 86 controller_clients_.erase(cit); | |
| 87 | |
| 88 if (controller_clients_.size() == 0) { | |
| 89 video_capture_manager_->Stop(params_.session_id, base::Closure()); | |
|
perkj_chrome
2011/10/17 08:39:43
I think you will need to make sure that the first
mflodman_chromium_OOO
2011/10/19 18:18:23
Or allowing changing settings as long as there is
wjia(left Chromium)
2011/10/21 00:56:13
In the latest design, the final capture resolution
wjia(left Chromium)
2011/10/21 00:56:13
There are two levels of clients: VideoCaptureImpl
| |
| 90 frame_info_available_ = false; | |
| 91 state_ = media::VideoCapture::kStopped; | |
| 92 } | |
| 50 } | 93 } |
| 51 | 94 |
| 52 void VideoCaptureController::ReturnBuffer(int buffer_id) { | 95 void VideoCaptureController::ReturnBuffer( |
| 96 const VideoCaptureControllerID& id, | |
| 97 VideoCaptureControllerEventHandler* event_handler, | |
| 98 int buffer_id) { | |
| 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 54 | 100 |
| 55 bool ready_to_delete; | 101 ControllerClients::iterator cit = FindClient(id, event_handler); |
| 102 UsedDIBsCount::iterator dit = used_dibs_count_.find(buffer_id); | |
| 103 if (cit == controller_clients_.end() || dit == used_dibs_count_.end()) | |
| 104 return; | |
| 105 | |
| 106 (*cit)->buffers.remove(buffer_id); | |
| 107 if ((*cit)->report_ready_to_delete && (*cit)->buffers.size() == 0) { | |
| 108 (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); | |
| 109 controller_clients_.erase(cit); | |
| 110 } | |
| 111 if (--dit->second > 0) | |
| 112 return; | |
| 113 | |
| 114 // Now this |buffer_id| is not used by any client. | |
| 115 used_dibs_count_.erase(buffer_id); | |
| 56 { | 116 { |
| 57 base::AutoLock lock(lock_); | 117 base::AutoLock lock(lock_); |
| 58 free_dibs_.push_back(buffer_id); | 118 free_dibs_.push_back(buffer_id); |
| 59 ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && | |
| 60 report_ready_to_delete_; | |
| 61 } | |
| 62 if (ready_to_delete) { | |
| 63 event_handler_->OnReadyToDelete(id_); | |
| 64 } | 119 } |
| 65 } | 120 } |
| 66 | 121 |
| 67 /////////////////////////////////////////////////////////////////////////////// | 122 /////////////////////////////////////////////////////////////////////////////// |
| 68 // Implements VideoCaptureDevice::EventHandler. | 123 // Implements VideoCaptureDevice::EventHandler. |
| 69 // OnIncomingCapturedFrame is called the thread running the capture device. | 124 // OnIncomingCapturedFrame is called the thread running the capture device. |
| 70 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 125 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
| 71 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | 126 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, |
| 72 int length, | 127 int length, |
| 73 base::Time timestamp) { | 128 base::Time timestamp) { |
| 74 int buffer_id = 0; | 129 int buffer_id = 0; |
| 75 base::SharedMemory* dib = NULL; | 130 base::SharedMemory* dib = NULL; |
| 76 // Check if there is a TransportDIB to fill. | 131 // Check if there is a DIB to fill. |
| 77 bool buffer_exist = false; | 132 bool buffer_exist = false; |
| 78 { | 133 { |
| 79 base::AutoLock lock(lock_); | 134 base::AutoLock lock(lock_); |
| 80 if (!report_ready_to_delete_ && free_dibs_.size() > 0) { | 135 if (free_dibs_.size() > 0) { |
| 81 buffer_id = free_dibs_.front(); | 136 buffer_id = free_dibs_.front(); |
| 82 free_dibs_.pop_front(); | 137 free_dibs_.pop_front(); |
| 83 DIBMap::iterator it = owned_dibs_.find(buffer_id); | 138 DIBMap::iterator it = owned_dibs_.find(buffer_id); |
| 84 if (it != owned_dibs_.end()) { | 139 if (it != owned_dibs_.end()) { |
| 85 dib = it->second; | 140 dib = it->second; |
| 86 buffer_exist = true; | 141 buffer_exist = true; |
| 87 } | 142 } |
| 88 } | 143 } |
| 89 } | 144 } |
| 90 | 145 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | 198 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
| 144 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, | 199 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| 145 frame_info_.height, frame_info_.width * 4, | 200 frame_info_.height, frame_info_.width * 4, |
| 146 frame_info_.width, frame_info_.width / 2); | 201 frame_info_.width, frame_info_.width / 2); |
| 147 break; | 202 break; |
| 148 } | 203 } |
| 149 default: | 204 default: |
| 150 NOTREACHED(); | 205 NOTREACHED(); |
| 151 } | 206 } |
| 152 | 207 |
| 153 event_handler_->OnBufferReady(id_, buffer_id, timestamp); | 208 BrowserThread::PostTask(BrowserThread::IO, |
| 209 FROM_HERE, | |
| 210 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 211 this, buffer_id, timestamp)); | |
| 154 } | 212 } |
| 155 | 213 |
| 156 void VideoCaptureController::OnError() { | 214 void VideoCaptureController::OnError() { |
| 157 event_handler_->OnError(id_); | |
| 158 video_capture_manager_->Error(params_.session_id); | 215 video_capture_manager_->Error(params_.session_id); |
| 216 BrowserThread::PostTask(BrowserThread::IO, | |
| 217 FROM_HERE, | |
| 218 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | |
| 159 } | 219 } |
| 160 | 220 |
| 161 void VideoCaptureController::OnFrameInfo( | 221 void VideoCaptureController::OnFrameInfo( |
| 162 const media::VideoCaptureDevice::Capability& info) { | 222 const media::VideoCaptureDevice::Capability& info) { |
| 223 BrowserThread::PostTask(BrowserThread::IO, | |
| 224 FROM_HERE, | |
| 225 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, | |
| 226 this, info)); | |
| 227 } | |
| 228 | |
| 229 void VideoCaptureController::OnDeviceState(bool in_use) { | |
| 230 BrowserThread::PostTask(BrowserThread::IO, | |
| 231 FROM_HERE, | |
| 232 base::Bind(&VideoCaptureController::DoDeviceStateOnIOThread, this, | |
| 233 in_use)); | |
| 234 } | |
| 235 | |
| 236 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | |
| 237 int buffer_id, base::Time timestamp) { | |
| 238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 239 | |
| 240 if (state_ != media::VideoCapture::kStarted) | |
| 241 return; | |
| 242 | |
| 243 int count = 0; | |
| 244 for (ControllerClients::iterator cit = controller_clients_.begin(); | |
| 245 cit != controller_clients_.end(); cit++) { | |
| 246 if ((*cit)->report_ready_to_delete) | |
| 247 continue; | |
| 248 | |
| 249 (*cit)->event_handler->OnBufferReady((*cit)->controller_id, | |
| 250 buffer_id, timestamp); | |
| 251 (*cit)->buffers.push_back(buffer_id); | |
| 252 count++; | |
| 253 } | |
| 254 if (count > 0) { | |
| 255 used_dibs_count_[buffer_id] = count; | |
| 256 } else { | |
| 257 base::AutoLock lock(lock_); | |
| 258 free_dibs_.push_back(buffer_id); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 void VideoCaptureController::DoErrorOnIOThread() { | |
| 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 264 state_ = media::VideoCapture::kError; | |
| 265 for (ControllerClients::iterator cit = controller_clients_.begin(); | |
| 266 cit != controller_clients_.end(); cit++) { | |
| 267 (*cit)->event_handler->OnError((*cit)->controller_id); | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 void VideoCaptureController::DoDeviceStateOnIOThread(bool in_use) { | |
| 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 273 video_capture_manager_->DeviceStatusFromController(this, in_use); | |
| 274 } | |
| 275 | |
| 276 void VideoCaptureController::DoFrameInfoOnIOThread( | |
| 277 const media::VideoCaptureDevice::Capability info) { | |
| 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 163 DCHECK(owned_dibs_.empty()); | 279 DCHECK(owned_dibs_.empty()); |
| 164 bool frames_created = true; | 280 bool frames_created = true; |
| 165 const size_t needed_size = (info.width * info.height * 3) / 2; | 281 const size_t needed_size = (info.width * info.height * 3) / 2; |
| 282 base::AutoLock lock(lock_); | |
| 166 for (size_t i = 1; i <= kNoOfDIBS; ++i) { | 283 for (size_t i = 1; i <= kNoOfDIBS; ++i) { |
| 167 base::SharedMemory* shared_memory = new base::SharedMemory(); | 284 base::SharedMemory* shared_memory = new base::SharedMemory(); |
| 168 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { | 285 if (!shared_memory->CreateAndMapAnonymous(needed_size)) { |
| 169 frames_created = false; | 286 frames_created = false; |
| 170 break; | 287 break; |
| 171 } | 288 } |
| 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)); | 289 owned_dibs_.insert(std::make_pair(i, shared_memory)); |
| 177 free_dibs_.push_back(i); | 290 free_dibs_.push_back(i); |
| 178 event_handler_->OnBufferCreated(id_, remote_handle, | 291 } |
| 179 static_cast<int>(needed_size), | 292 // Check whether all DIBs were created successfully. |
| 180 static_cast<int>(i)); | 293 if (!frames_created) { |
| 294 state_ = media::VideoCapture::kError; | |
| 295 for (ControllerClients::iterator it = controller_clients_.begin(); | |
| 296 it != controller_clients_.end(); it++) { | |
| 297 (*it)->event_handler->OnError((*it)->controller_id); | |
| 298 } | |
| 299 return; | |
| 181 } | 300 } |
| 182 frame_info_= info; | 301 frame_info_= info; |
| 302 frame_info_available_ = true; | |
| 183 | 303 |
| 184 // Check that all DIBs where created successfully. | 304 for (ControllerClients::iterator cit = controller_clients_.begin(); |
| 185 if (!frames_created) { | 305 cit != controller_clients_.end(); cit++) { |
| 186 event_handler_->OnError(id_); | 306 for (DIBMap::iterator dit = owned_dibs_.begin(); |
| 307 dit != owned_dibs_.end(); dit++) { | |
| 308 int index = dit->first; | |
| 309 base::SharedMemory* shared_memory = dit->second; | |
| 310 base::SharedMemoryHandle remote_handle; | |
| 311 shared_memory->ShareToProcess((*cit)->render_process_handle, | |
| 312 &remote_handle); | |
| 313 (*cit)->event_handler->OnBufferCreated((*cit)->controller_id, | |
| 314 remote_handle, | |
| 315 static_cast<int>(needed_size), | |
| 316 index); | |
| 317 } | |
| 318 (*cit)->event_handler->OnFrameInfo((*cit)->controller_id, | |
| 319 info.width, info.height, | |
| 320 info.frame_rate); | |
| 187 } | 321 } |
| 188 event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); | |
| 189 } | 322 } |
| 190 | 323 |
| 191 /////////////////////////////////////////////////////////////////////////////// | 324 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { |
| 192 // Called by VideoCaptureManager when a device have been stopped. | 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 193 // This will report to the event handler that this object is ready to be deleted | 326 DCHECK(frame_info_available_); |
| 194 // if all DIBS have been returned. | 327 const size_t needed_size = (frame_info_.width * frame_info_.height * 3) / 2; |
| 195 void VideoCaptureController::OnDeviceStopped(base::Closure stopped_cb) { | 328 base::AutoLock lock(lock_); |
| 196 bool ready_to_delete_now; | 329 for (DIBMap::iterator dit = owned_dibs_.begin(); |
| 330 dit != owned_dibs_.end(); dit++) { | |
| 331 base::SharedMemory* shared_memory = dit->second; | |
| 332 int index = dit->first; | |
| 333 base::SharedMemoryHandle remote_handle; | |
| 334 shared_memory->ShareToProcess(client->render_process_handle, | |
| 335 &remote_handle); | |
| 336 client->event_handler->OnBufferCreated(client->controller_id, | |
| 337 remote_handle, | |
| 338 static_cast<int>(needed_size), | |
| 339 index); | |
| 340 } | |
| 341 client->event_handler->OnFrameInfo(client->controller_id, | |
| 342 frame_info_.width, frame_info_.height, | |
| 343 frame_info_.frame_rate); | |
| 344 } | |
| 197 | 345 |
| 198 { | 346 VideoCaptureController::ControllerClients::iterator |
| 199 base::AutoLock lock(lock_); | 347 VideoCaptureController::FindClient( |
| 200 // Set flag to indicate we need to report when all DIBs have been returned. | 348 const VideoCaptureControllerID& id, |
| 201 report_ready_to_delete_ = true; | 349 VideoCaptureControllerEventHandler* handler) { |
| 202 ready_to_delete_now = (free_dibs_.size() == owned_dibs_.size()); | 350 for (ControllerClients::iterator cit = controller_clients_.begin(); |
| 351 cit != controller_clients_.end(); cit++) { | |
| 352 if ((*cit)->controller_id == id && (*cit)->event_handler == handler) { | |
| 353 return cit; | |
| 354 } | |
| 203 } | 355 } |
| 356 return controller_clients_.end(); | |
| 357 } | |
| 204 | 358 |
| 205 if (ready_to_delete_now) { | 359 VideoCaptureController::ControllerClient::ControllerClient( |
| 206 event_handler_->OnReadyToDelete(id_); | 360 const VideoCaptureControllerID& id, |
| 207 } | 361 VideoCaptureControllerEventHandler* handler, |
| 362 base::ProcessHandle render_process, | |
| 363 const media::VideoCaptureParams& params) | |
| 364 : controller_id(id), | |
|
scherkus (not reviewing)
2011/10/19 18:02:21
indent by 2 more spaces
wjia(left Chromium)
2011/10/21 00:56:13
Done.
| |
| 365 event_handler(handler), | |
| 366 render_process_handle(render_process), | |
| 367 parameters(params), | |
| 368 report_ready_to_delete(false) { | |
| 369 } | |
| 208 | 370 |
| 209 if (!stopped_cb.is_null()) | 371 VideoCaptureController::ControllerClient::~ControllerClient() {} |
| 210 stopped_cb.Run(); | |
| 211 } | |
| OLD | NEW |