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

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

Issue 23870002: Video Capture: Use libyuv for color conversion in VideoCaptureController. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Special RGB treatment for Windows platforms Created 7 years, 3 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "content/browser/renderer_host/media/media_stream_manager.h" 13 #include "content/browser/renderer_host/media/media_stream_manager.h"
14 #include "content/browser/renderer_host/media/video_capture_manager.h" 14 #include "content/browser/renderer_host/media/video_capture_manager.h"
15 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
16 #include "media/base/video_frame.h" 16 #include "media/base/video_frame.h"
17 #include "media/base/video_util.h" 17 #include "media/base/video_util.h"
18 #include "media/base/yuv_convert.h" 18 #include "media/base/yuv_convert.h"
19 19
20 #if !defined(OS_IOS) && !defined(OS_ANDROID) 20 #if !defined(OS_IOS) && !defined(OS_ANDROID)
21 #include "third_party/libyuv/include/libyuv.h" 21 #include "third_party/libyuv/include/libyuv.h"
22 #endif 22 #endif
23 23
24 namespace { 24 namespace {
25 25
26 #if defined(OS_IOS) || defined(OS_ANDROID)
26 // TODO(wjia): Support stride. 27 // TODO(wjia): Support stride.
27 void RotatePackedYV12Frame( 28 void RotatePackedYV12Frame(
28 const uint8* src, 29 const uint8* src,
29 uint8* dest_yplane, 30 uint8* dest_yplane,
30 uint8* dest_uplane, 31 uint8* dest_uplane,
31 uint8* dest_vplane, 32 uint8* dest_vplane,
32 int width, 33 int width,
33 int height, 34 int height,
34 int rotation, 35 int rotation,
35 bool flip_vert, 36 bool flip_vert,
36 bool flip_horiz) { 37 bool flip_horiz) {
37 media::RotatePlaneByPixels( 38 media::RotatePlaneByPixels(
38 src, dest_yplane, width, height, rotation, flip_vert, flip_horiz); 39 src, dest_yplane, width, height, rotation, flip_vert, flip_horiz);
39 int y_size = width * height; 40 int y_size = width * height;
40 src += y_size; 41 src += y_size;
41 media::RotatePlaneByPixels( 42 media::RotatePlaneByPixels(
42 src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz); 43 src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz);
43 src += y_size/4; 44 src += y_size/4;
44 media::RotatePlaneByPixels( 45 media::RotatePlaneByPixels(
45 src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz); 46 src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz);
46 } 47 }
48 #endif // #if defined(OS_IOS) || defined(OS_ANDROID)
47 49
48 } // namespace 50 } // namespace
49 51
50 namespace content { 52 namespace content {
51 53
52 // The number of buffers that VideoCaptureBufferPool should allocate. 54 // The number of buffers that VideoCaptureBufferPool should allocate.
53 static const int kNoOfBuffers = 3; 55 static const int kNoOfBuffers = 3;
54 56
55 struct VideoCaptureController::ControllerClient { 57 struct VideoCaptureController::ControllerClient {
56 ControllerClient( 58 ControllerClient(
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 if (!buffer_pool_.get()) 253 if (!buffer_pool_.get())
252 return NULL; 254 return NULL;
253 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width, 255 return buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
254 frame_info_.height), 256 frame_info_.height),
255 0); 257 0);
256 } 258 }
257 259
258 // Implements VideoCaptureDevice::EventHandler. 260 // Implements VideoCaptureDevice::EventHandler.
259 // OnIncomingCapturedFrame is called the thread running the capture device. 261 // OnIncomingCapturedFrame is called the thread running the capture device.
260 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. 262 // I.e.- DirectShow thread on windows and v4l2_thread on Linux.
263 #if !defined(OS_IOS) && !defined(OS_ANDROID)
wjia(left Chromium) 2013/09/02 17:11:35 Is it possible to add color conversion for Android
mcasas 2013/09/03 08:10:41 That'll be cool indeed, I can follow through with
261 void VideoCaptureController::OnIncomingCapturedFrame( 264 void VideoCaptureController::OnIncomingCapturedFrame(
262 const uint8* data, 265 const uint8* data,
263 int length, 266 int length,
267 base::Time timestamp,
268 int rotation,
269 bool flip_vert,
270 bool flip_horiz) {
wjia(left Chromium) 2013/09/02 17:11:35 Do we need to support rotation for desktop platfor
mcasas 2013/09/03 08:10:41 I don't know. But why would we change this generic
271 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 ||
272 frame_info_.color == media::VideoCaptureCapability::kYV12 ||
273 (rotation == 0 && !flip_vert && !flip_horiz));
274
275 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame");
276
277 scoped_refptr<media::VideoFrame> dst;
278 {
279 base::AutoLock lock(buffer_pool_lock_);
280 if (!buffer_pool_.get())
281 return;
282 dst = buffer_pool_->ReserveI420VideoFrame(gfx::Size(frame_info_.width,
283 frame_info_.height),
wjia(left Chromium) 2013/09/02 17:11:35 It's more readable to drop "gfx::Size" to a new li
mcasas 2013/09/03 08:10:41 Indeed. Done.
284 rotation);
285 }
286
287 if (!dst.get())
288 return;
289
290 uint8* yplane = dst->data(media::VideoFrame::kYPlane);
291 uint8* uplane = dst->data(media::VideoFrame::kUPlane);
292 uint8* vplane = dst->data(media::VideoFrame::kVPlane);
293 int yplane_stride = frame_info_.width;
294 int uv_plane_stride = (frame_info_.width + 1) / 2;
295 int crop_x = 0;
296 int crop_y = 0;
297 libyuv::FourCC destination_colorspace = libyuv::FOURCC_ANY;
mcasas 2013/09/03 08:10:41 Actually I made a mistake here, this variable shou
298 libyuv::RotationMode rotation_mode = libyuv::kRotate0;
299
300 if (rotation == 90)
301 rotation_mode = libyuv::kRotate90;
302 else if (rotation == 180)
303 rotation_mode = libyuv::kRotate180;
304 else if (rotation == 270)
305 rotation_mode = libyuv::kRotate270;
wjia(left Chromium) 2013/09/02 17:11:35 Is this mapping correct? How do you test it? flip
mcasas 2013/09/03 08:10:41 I missed two things indeed: 1) using horizontal fl
306
307 switch (frame_info_.color) {
308 case media::VideoCaptureCapability::kColorUnknown: // Color format not set.
309 break;
310 case media::VideoCaptureCapability::kI420:
311 DCHECK(!chopped_width_ && !chopped_height_);
312 destination_colorspace = libyuv::FOURCC_I420;
313 break;
314 case media::VideoCaptureCapability::kYV12:
315 DCHECK(!chopped_width_ && !chopped_height_);
316 destination_colorspace = libyuv::FOURCC_YV12;
317 break;
318 case media::VideoCaptureCapability::kNV21:
319 DCHECK(!chopped_width_ && !chopped_height_);
320 destination_colorspace = libyuv::FOURCC_NV12;
321 break;
322 case media::VideoCaptureCapability::kYUY2:
323 DCHECK(!chopped_width_ && !chopped_height_);
324 destination_colorspace = libyuv::FOURCC_YUY2;
325 break;
326 case media::VideoCaptureCapability::kRGB24:
327 #if defined(OS_WIN)
328 // RGB on Windows start at the bottom line and has a negative stride. This
329 // is not supported by libyuv, so the media API is used instead.
330 {
331 int rgb_stride = -3 * (frame_info_.width + chopped_width_);
332 const uint8* rgb_src =
333 data + 3 * (frame_info_.width + chopped_width_) *
334 (frame_info_.height - 1 + chopped_height_);
335 media::ConvertRGB24ToYUV(rgb_src,
336 yplane,
337 uplane,
338 vplane,
339 frame_info_.width,
340 frame_info_.height,
341 rgb_stride,
342 yplane_stride,
343 uv_plane_stride);
344 }
345 destination_colorspace = libyuv::FOURCC_ANY;
346 #else
347 destination_colorspace = libyuv::FOURCC_RAW;
348 #endif
349 break;
350 case media::VideoCaptureCapability::kARGB:
351 destination_colorspace = libyuv::FOURCC_ARGB;
352 break;
353 case media::VideoCaptureCapability::kMJPEG:
354 destination_colorspace = libyuv::FOURCC_MJPG;
355 break;
356 default:
357 NOTREACHED();
358 }
359 // Destination colorspace is always YUV I420. If destination_colorspace is
360 // libyuv::FOURCC_ANY, then ConvertToI420 just returns -1.
361 libyuv::ConvertToI420(data,
wjia(left Chromium) 2013/09/02 17:11:35 Do you need to call this for kRGB24 on WIN (it has
mcasas 2013/09/03 08:10:41 It would be called with a destination_colorspace =
362 length,
363 yplane,
364 yplane_stride,
365 uplane,
366 uv_plane_stride,
367 vplane,
368 uv_plane_stride,
369 crop_x,
370 crop_y,
371 frame_info_.width,
372 frame_info_.height,
373 frame_info_.width,
374 frame_info_.height,
375 rotation_mode,
376 destination_colorspace);
377
378 BrowserThread::PostTask(
379 BrowserThread::IO,
380 FROM_HERE,
381 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
382 this,
383 dst,
384 timestamp));
385 }
386 #else
387 void VideoCaptureController::OnIncomingCapturedFrame(
388 const uint8* data,
389 int length,
264 base::Time timestamp, 390 base::Time timestamp,
265 int rotation, 391 int rotation,
266 bool flip_vert, 392 bool flip_vert,
267 bool flip_horiz) { 393 bool flip_horiz) {
268 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || 394 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 ||
269 frame_info_.color == media::VideoCaptureCapability::kYV12 || 395 frame_info_.color == media::VideoCaptureCapability::kYV12 ||
270 (rotation == 0 && !flip_vert && !flip_horiz)); 396 (rotation == 0 && !flip_vert && !flip_horiz));
271 397
272 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame"); 398 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedFrame");
273 399
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, 435 media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width,
310 frame_info_.height); 436 frame_info_.height);
311 break; 437 break;
312 case media::VideoCaptureCapability::kYUY2: 438 case media::VideoCaptureCapability::kYUY2:
313 DCHECK(!chopped_width_ && !chopped_height_); 439 DCHECK(!chopped_width_ && !chopped_height_);
314 if (frame_info_.width * frame_info_.height * 2 != length) { 440 if (frame_info_.width * frame_info_.height * 2 != length) {
315 // If |length| of |data| does not match the expected width and height 441 // If |length| of |data| does not match the expected width and height
316 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel. 442 // we can't convert the frame to I420. YUY2 is 2 bytes per pixel.
317 break; 443 break;
318 } 444 }
319
320 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, 445 media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width,
321 frame_info_.height); 446 frame_info_.height);
322 break; 447 break;
323 case media::VideoCaptureCapability::kRGB24: { 448 case media::VideoCaptureCapability::kRGB24: {
324 int ystride = frame_info_.width; 449 int ystride = frame_info_.width;
325 int uvstride = frame_info_.width / 2; 450 int uvstride = frame_info_.width / 2;
326 #if defined(OS_WIN) // RGB on Windows start at the bottom line.
327 int rgb_stride = -3 * (frame_info_.width + chopped_width_);
328 const uint8* rgb_src = data + 3 * (frame_info_.width + chopped_width_) *
329 (frame_info_.height -1 + chopped_height_);
330 #else
331 int rgb_stride = 3 * (frame_info_.width + chopped_width_); 451 int rgb_stride = 3 * (frame_info_.width + chopped_width_);
332 const uint8* rgb_src = data; 452 const uint8* rgb_src = data;
333 #endif
334 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane, 453 media::ConvertRGB24ToYUV(rgb_src, yplane, uplane, vplane,
335 frame_info_.width, frame_info_.height, 454 frame_info_.width, frame_info_.height,
336 rgb_stride, ystride, uvstride); 455 rgb_stride, ystride, uvstride);
337 break; 456 break;
338 } 457 }
339 case media::VideoCaptureCapability::kARGB: 458 case media::VideoCaptureCapability::kARGB:
340 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, 459 media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width,
341 frame_info_.height, 460 frame_info_.height,
342 (frame_info_.width + chopped_width_) * 4, 461 (frame_info_.width + chopped_width_) * 4,
343 frame_info_.width, frame_info_.width / 2); 462 frame_info_.width, frame_info_.width / 2);
344 break; 463 break;
345 #if !defined(OS_IOS) && !defined(OS_ANDROID)
346 case media::VideoCaptureCapability::kMJPEG: {
347 int yplane_stride = frame_info_.width;
348 int uv_plane_stride = (frame_info_.width + 1) / 2;
349 int crop_x = 0;
350 int crop_y = 0;
351 libyuv::ConvertToI420(data, length, yplane, yplane_stride, uplane,
352 uv_plane_stride, vplane, uv_plane_stride, crop_x,
353 crop_y, frame_info_.width, frame_info_.height,
354 frame_info_.width, frame_info_.height,
355 libyuv::kRotate0, libyuv::FOURCC_MJPG);
356 break;
357 }
358 #endif
359 default: 464 default:
360 NOTREACHED(); 465 NOTREACHED();
361 } 466 }
362 467
363 BrowserThread::PostTask(BrowserThread::IO, 468 BrowserThread::PostTask(BrowserThread::IO,
364 FROM_HERE, 469 FROM_HERE,
365 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, 470 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread,
366 this, dst, timestamp)); 471 this, dst, timestamp));
367 } 472 }
473 #endif // #if !defined(OS_IOS) && !defined(OS_ANDROID)
368 474
369 // OnIncomingCapturedVideoFrame is called the thread running the capture device. 475 // OnIncomingCapturedVideoFrame is called the thread running the capture device.
370 void VideoCaptureController::OnIncomingCapturedVideoFrame( 476 void VideoCaptureController::OnIncomingCapturedVideoFrame(
371 const scoped_refptr<media::VideoFrame>& frame, 477 const scoped_refptr<media::VideoFrame>& frame,
372 base::Time timestamp) { 478 base::Time timestamp) {
373 479
374 scoped_refptr<media::VideoFrame> target; 480 scoped_refptr<media::VideoFrame> target;
375 { 481 {
376 base::AutoLock lock(buffer_pool_lock_); 482 base::AutoLock lock(buffer_pool_lock_);
377 483
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 controller_clients_.push_back((*client_it)); 835 controller_clients_.push_back((*client_it));
730 pending_clients_.erase(client_it++); 836 pending_clients_.erase(client_it++);
731 } 837 }
732 // Request the manager to start the actual capture. 838 // Request the manager to start the actual capture.
733 video_capture_manager_->Start(current_params_, this); 839 video_capture_manager_->Start(current_params_, this);
734 state_ = VIDEO_CAPTURE_STATE_STARTED; 840 state_ = VIDEO_CAPTURE_STATE_STARTED;
735 device_in_use_ = true; 841 device_in_use_ = true;
736 } 842 }
737 843
738 } // namespace content 844 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698