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

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

Issue 8304017: enable video capture to support sharing across multiple renderer processes (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months 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/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(&params_, 0, sizeof(params_)); 22 memset(&params_, 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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698