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

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

Issue 12090109: Tab Capture: Backing store readbacks to YV12 VideoFrames. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Trim some trailing whitespace. Created 7 years, 10 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <set> 7 #include <set>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "content/browser/renderer_host/media/media_stream_manager.h" 12 #include "content/browser/renderer_host/media/media_stream_manager.h"
13 #include "content/browser/renderer_host/media/video_capture_manager.h" 13 #include "content/browser/renderer_host/media/video_capture_manager.h"
14 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
15 #include "media/base/video_frame.h"
16 #include "media/base/video_util.h"
15 #include "media/base/yuv_convert.h" 17 #include "media/base/yuv_convert.h"
16 18
17 #if !defined(OS_IOS) && !defined(OS_ANDROID) 19 #if !defined(OS_IOS) && !defined(OS_ANDROID)
18 #include "third_party/libyuv/include/libyuv.h" 20 #include "third_party/libyuv/include/libyuv.h"
19 #endif 21 #endif
20 22
21 namespace content { 23 namespace content {
22 24
23 // The number of DIBs VideoCaptureController allocate. 25 // The number of DIBs VideoCaptureController allocate.
24 static const size_t kNoOfDIBS = 3; 26 static const size_t kNoOfDIBS = 3;
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 } 240 }
239 241
240 // When all buffers have been returned by clients and device has been 242 // When all buffers have been returned by clients and device has been
241 // called to stop, check if restart is needed. This could happen when 243 // called to stop, check if restart is needed. This could happen when
242 // capture needs to be restarted due to resolution change. 244 // capture needs to be restarted due to resolution change.
243 if (!ClientHasDIB() && state_ == VIDEO_CAPTURE_STATE_STOPPING) { 245 if (!ClientHasDIB() && state_ == VIDEO_CAPTURE_STATE_STOPPING) {
244 PostStopping(); 246 PostStopping();
245 } 247 }
246 } 248 }
247 249
248 /////////////////////////////////////////////////////////////////////////////// 250 bool VideoCaptureController::ReserveSharedMemory(int* buffer_id_out,
249 // Implements VideoCaptureDevice::EventHandler. 251 uint8** yplane,
250 // OnIncomingCapturedFrame is called the thread running the capture device. 252 uint8** uplane,
251 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. 253 uint8** vplane) {
252 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data,
253 int length,
254 base::Time timestamp) {
255 int buffer_id = 0; 254 int buffer_id = 0;
256 base::SharedMemory* dib = NULL; 255 base::SharedMemory* dib = NULL;
257 { 256 {
258 base::AutoLock lock(lock_); 257 base::AutoLock lock(lock_);
259 for (DIBMap::iterator dib_it = owned_dibs_.begin(); 258 for (DIBMap::iterator dib_it = owned_dibs_.begin();
260 dib_it != owned_dibs_.end(); dib_it++) { 259 dib_it != owned_dibs_.end(); dib_it++) {
261 if (dib_it->second->references == 0) { 260 if (dib_it->second->references == 0) {
262 buffer_id = dib_it->first; 261 buffer_id = dib_it->first;
263 // Use special value "-1" in order to not be treated as buffer at 262 // Use special value "-1" in order to not be treated as buffer at
264 // renderer side. 263 // renderer side.
265 dib_it->second->references = -1; 264 dib_it->second->references = -1;
266 dib = dib_it->second->shared_memory.get(); 265 dib = dib_it->second->shared_memory.get();
267 break; 266 break;
268 } 267 }
269 } 268 }
270 } 269 }
271 270
272 if (!dib) { 271 if (!dib)
272 return false;
273
274 *buffer_id_out = buffer_id;
275 CHECK(dib->created_size() >= static_cast<size_t>(frame_info_.width *
scherkus (not reviewing) 2013/02/05 22:40:44 nit: CHECK_GE()?
ncarter (slow) 2013/02/06 23:54:44 Done.
276 frame_info_.height * 3) / 2);
277 uint8* target = static_cast<uint8*>(dib->memory());
278 *yplane = target;
279 *uplane = *yplane + frame_info_.width * frame_info_.height;
280 *vplane = *uplane + (frame_info_.width * frame_info_.height) / 4;
281 return true;
282 }
283
284 ///////////////////////////////////////////////////////////////////////////////
285 // Implements VideoCaptureDevice::EventHandler.
286 // OnIncomingCapturedFrame is called the thread running the capture device.
287 // I.e.- DirectShow thread on windows and v4l2_thread on Linux.
288 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data,
289 int length,
290 base::Time timestamp) {
291 int buffer_id = 0;
292 uint8* yplane = NULL;
293 uint8* uplane = NULL;
294 uint8* vplane = NULL;
295 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane))
273 return; 296 return;
274 }
275
276 uint8* target = static_cast<uint8*>(dib->memory());
277 CHECK(dib->created_size() >= static_cast<size_t> (frame_info_.width *
278 frame_info_.height * 3) /
279 2);
280 uint8* yplane = target;
281 uint8* uplane = target + frame_info_.width * frame_info_.height;
282 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4;
283 297
284 // Do color conversion from the camera format to I420. 298 // Do color conversion from the camera format to I420.
285 switch (frame_info_.color) { 299 switch (frame_info_.color) {
286 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. 300 case media::VideoCaptureCapability::kColorUnknown: // Color format not set.
287 break; 301 break;
288 case media::VideoCaptureCapability::kI420: { 302 case media::VideoCaptureCapability::kI420: {
289 DCHECK(!chopped_width_ && !chopped_height_); 303 DCHECK(!chopped_width_ && !chopped_height_);
290 memcpy(target, data, (frame_info_.width * frame_info_.height * 3) / 2); 304 memcpy(yplane, data, (frame_info_.width * frame_info_.height * 3) / 2);
291 break; 305 break;
292 } 306 }
293 case media::VideoCaptureCapability::kYV12: { 307 case media::VideoCaptureCapability::kYV12: {
294 DCHECK(!chopped_width_ && !chopped_height_); 308 DCHECK(!chopped_width_ && !chopped_height_);
295 const uint8* ptr = data; 309 const uint8* ptr = data;
296 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); 310 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height));
297 ptr += frame_info_.width * frame_info_.height; 311 ptr += frame_info_.width * frame_info_.height;
298 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); 312 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2);
299 ptr += (frame_info_.width * frame_info_.height) >> 2; 313 ptr += (frame_info_.width * frame_info_.height) >> 2;
300 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); 314 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 default: 366 default:
353 NOTREACHED(); 367 NOTREACHED();
354 } 368 }
355 369
356 BrowserThread::PostTask(BrowserThread::IO, 370 BrowserThread::PostTask(BrowserThread::IO,
357 FROM_HERE, 371 FROM_HERE,
358 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, 372 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
359 this, buffer_id, timestamp)); 373 this, buffer_id, timestamp));
360 } 374 }
361 375
376 // OnIncomingCapturedVideoFrame is called the thread running the capture device.
377 void VideoCaptureController::OnIncomingCapturedVideoFrame(
378 media::VideoFrame* frame,
379 base::Time timestamp) {
380 int buffer_id = 0;
381 uint8* yplane = NULL;
382 uint8* uplane = NULL;
383 uint8* vplane = NULL;
384 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane))
385 return;
386
387 gfx::Size target_size = gfx::Size(frame_info_.width, frame_info_.height);
388
389 if (frame->coded_size() != target_size)
390 return; // Only exact copies are supported.
scherkus (not reviewing) 2013/02/05 22:40:44 if you reserve a DIB but return here, does the DIB
ncarter (slow) 2013/02/06 23:54:44 Good catch! Reordered these operations.
391
392 scoped_refptr<media::VideoFrame> target_as_frame(
393 media::VideoFrame::WrapExternalYuvData(
394 media::VideoFrame::YV12, // Actually I420, but it's equivalent here.
395 target_size, gfx::Rect(target_size), target_size,
396 frame_info_.width, // y stride
397 frame_info_.width / 2, // v stride
398 frame_info_.width / 2, // u stride
399 yplane,
400 uplane,
401 vplane,
402 base::TimeDelta(),
403 base::Bind(&base::DoNothing)));
404
405 const int kYPlane = media::VideoFrame::kYPlane;
406 const int kUPlane = media::VideoFrame::kUPlane;
407 const int kVPlane = media::VideoFrame::kVPlane;
408 const int kRGBPlane = media::VideoFrame::kRGBPlane;
409
410 // Do color conversion from the camera format to I420.
411 switch (frame->format()) {
412 case media::VideoFrame::EMPTY:
413 case media::VideoFrame::INVALID: // Color format not set.
414 case media::VideoFrame::NATIVE_TEXTURE:
415 // These types will never work.
scherkus (not reviewing) 2013/02/05 22:40:44 if possible, my preference would be to CHECK()sinc
ncarter (slow) 2013/02/06 23:54:44 CHECK() isn't as much fun for the user when it hap
416 break;
417 case media::VideoFrame::I420:
418 case media::VideoFrame::YV12: {
419 DCHECK(!chopped_width_ && !chopped_height_);
420 media::CopyYPlane(frame->data(kYPlane),
421 frame->stride(kYPlane),
422 frame->rows(kYPlane),
423 target_as_frame);
424 media::CopyUPlane(frame->data(kUPlane),
425 frame->stride(kUPlane),
426 frame->rows(kUPlane),
427 target_as_frame);
428 media::CopyVPlane(frame->data(kVPlane),
429 frame->stride(kVPlane),
430 frame->rows(kVPlane),
431 target_as_frame);
432 break;
433 }
434 case media::VideoFrame::RGB32: {
435 media::ConvertRGB32ToYUV(frame->data(kRGBPlane),
436 target_as_frame->data(kYPlane),
437 target_as_frame->data(kUPlane),
438 target_as_frame->data(kVPlane),
439 target_size.width(),
440 target_size.height(),
441 frame->stride(kRGBPlane),
442 target_as_frame->stride(kYPlane),
443 target_as_frame->stride(kUPlane));
444 break;
445 }
446 default:
scherkus (not reviewing) 2013/02/05 22:40:44 I like having the compiler break when enums are ad
ncarter (slow) 2013/02/06 23:54:44 See above.
447 NOTREACHED();
448 }
449
450 BrowserThread::PostTask(BrowserThread::IO,
451 FROM_HERE,
452 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
453 this, buffer_id, timestamp));
454 }
455
362 void VideoCaptureController::OnError() { 456 void VideoCaptureController::OnError() {
363 BrowserThread::PostTask(BrowserThread::IO, 457 BrowserThread::PostTask(BrowserThread::IO,
364 FROM_HERE, 458 FROM_HERE,
365 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); 459 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this));
366 } 460 }
367 461
368 void VideoCaptureController::OnFrameInfo( 462 void VideoCaptureController::OnFrameInfo(
369 const media::VideoCaptureCapability& info) { 463 const media::VideoCaptureCapability& info) {
370 frame_info_= info; 464 frame_info_= info;
371 // Handle cases when |info| has odd numbers for width/height. 465 // Handle cases when |info| has odd numbers for width/height.
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 base::AutoLock lock(lock_); 687 base::AutoLock lock(lock_);
594 for (DIBMap::iterator dib_it = owned_dibs_.begin(); 688 for (DIBMap::iterator dib_it = owned_dibs_.begin();
595 dib_it != owned_dibs_.end(); dib_it++) { 689 dib_it != owned_dibs_.end(); dib_it++) {
596 if (dib_it->second->references > 0) 690 if (dib_it->second->references > 0)
597 return true; 691 return true;
598 } 692 }
599 return false; 693 return false;
600 } 694 }
601 695
602 } // namespace content 696 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698