From 1fa37522cade3c1bbd5a523f4aafc884348f8262 Mon Sep 17 00:00:00 2001 From: "wjia@chromium.org" Date: Thu, 28 Feb 2013 22:01:04 +0000 Subject: Remove one video frame copying in video capture. On Android, the captured frame might need to be rotated. By moving the rotation code into VideoCaptureController, one video frame copying is reduced. On Nexus 4, the frame copying from intermedia buffer to shared memory takes about 0.1 ms per frame for VGA YV12. Review URL: https://codereview.chromium.org/12378007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185339 0039d316-1c4b-4281-b951-d872f2087c98 --- .../media/video_capture_controller.cc | 92 ++++++++++++++++------ 1 file changed, 69 insertions(+), 23 deletions(-) (limited to 'content/browser/renderer_host/media/video_capture_controller.cc') diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc index b503293..fc18af4 100644 --- a/content/browser/renderer_host/media/video_capture_controller.cc +++ b/content/browser/renderer_host/media/video_capture_controller.cc @@ -20,6 +20,39 @@ #include "third_party/libyuv/include/libyuv.h" #endif +namespace { + +void ResetBufferYV12(uint8* buffer, int width, int height) { + int y_size = width * height; + memset(buffer, 0, y_size); + buffer += y_size; + memset(buffer, 128, y_size / 2); +} + +// TODO(wjia): Support stride. +void RotatePackedYV12Frame( + const uint8* src, + uint8* dest_yplane, + uint8* dest_uplane, + uint8* dest_vplane, + int width, + int height, + int rotation, + bool flip_vert, + bool flip_horiz) { + media::RotatePlaneByPixels( + src, dest_yplane, width, height, rotation, flip_vert, flip_horiz); + int y_size = width * height; + src += y_size; + media::RotatePlaneByPixels( + src, dest_uplane, width/2, height/2, rotation, flip_vert, flip_horiz); + src += y_size/4; + media::RotatePlaneByPixels( + src, dest_vplane, width/2, height/2, rotation, flip_vert, flip_horiz); +} + +} // namespace + namespace content { // The number of DIBs VideoCaptureController allocate. @@ -58,6 +91,7 @@ struct VideoCaptureController::ControllerClient { struct VideoCaptureController::SharedDIB { SharedDIB(base::SharedMemory* ptr) : shared_memory(ptr), + rotation(0), references(0) { } @@ -66,6 +100,8 @@ struct VideoCaptureController::SharedDIB { // The memory created to be shared with renderer processes. scoped_ptr shared_memory; + int rotation; + // Number of renderer processes which hold this shared memory. // renderer process is represented by VidoeCaptureHost. int references; @@ -250,7 +286,8 @@ void VideoCaptureController::ReturnBuffer( bool VideoCaptureController::ReserveSharedMemory(int* buffer_id_out, uint8** yplane, uint8** uplane, - uint8** vplane) { + uint8** vplane, + int rotation) { int buffer_id = 0; base::SharedMemory* dib = NULL; { @@ -263,6 +300,11 @@ bool VideoCaptureController::ReserveSharedMemory(int* buffer_id_out, // renderer side. dib_it->second->references = -1; dib = dib_it->second->shared_memory.get(); + if (rotation != dib_it->second->rotation) { + ResetBufferYV12(static_cast(dib->memory()), + frame_info_.width, frame_info_.height); + dib_it->second->rotation = rotation; + } break; } } @@ -284,42 +326,46 @@ bool VideoCaptureController::ReserveSharedMemory(int* buffer_id_out, // Implements VideoCaptureDevice::EventHandler. // OnIncomingCapturedFrame is called the thread running the capture device. // I.e.- DirectShow thread on windows and v4l2_thread on Linux. -void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, - int length, - base::Time timestamp) { +void VideoCaptureController::OnIncomingCapturedFrame( + const uint8* data, + int length, + base::Time timestamp, + int rotation, + bool flip_vert, + bool flip_horiz) { + DCHECK (frame_info_.color == media::VideoCaptureCapability::kI420 || + frame_info_.color == media::VideoCaptureCapability::kYV12 || + (rotation == 0 && !flip_vert && !flip_horiz)); + int buffer_id = 0; uint8* yplane = NULL; uint8* uplane = NULL; uint8* vplane = NULL; - if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) + if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane, rotation)) return; // Do color conversion from the camera format to I420. switch (frame_info_.color) { case media::VideoCaptureCapability::kColorUnknown: // Color format not set. break; - case media::VideoCaptureCapability::kI420: { + case media::VideoCaptureCapability::kI420: DCHECK(!chopped_width_ && !chopped_height_); - memcpy(yplane, data, (frame_info_.width * frame_info_.height * 3) / 2); + RotatePackedYV12Frame( + data, yplane, uplane, vplane, frame_info_.width, frame_info_.height, + rotation, flip_vert, flip_horiz); break; - } - case media::VideoCaptureCapability::kYV12: { + case media::VideoCaptureCapability::kYV12: DCHECK(!chopped_width_ && !chopped_height_); - const uint8* ptr = data; - memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); - ptr += frame_info_.width * frame_info_.height; - memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); - ptr += (frame_info_.width * frame_info_.height) >> 2; - memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); + RotatePackedYV12Frame( + data, yplane, vplane, uplane, frame_info_.width, frame_info_.height, + rotation, flip_vert, flip_horiz); break; - } - case media::VideoCaptureCapability::kNV21: { + case media::VideoCaptureCapability::kNV21: DCHECK(!chopped_width_ && !chopped_height_); media::ConvertNV21ToYUV(data, yplane, uplane, vplane, frame_info_.width, frame_info_.height); break; - } - case media::VideoCaptureCapability::kYUY2: { + case media::VideoCaptureCapability::kYUY2: DCHECK(!chopped_width_ && !chopped_height_); if (frame_info_.width * frame_info_.height * 2 != length) { // If |length| of |data| does not match the expected width and height @@ -330,7 +376,6 @@ void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, frame_info_.height); break; - } case media::VideoCaptureCapability::kRGB24: { int ystride = frame_info_.width; int uvstride = frame_info_.width / 2; @@ -347,13 +392,12 @@ void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, rgb_stride, ystride, uvstride); break; } - case media::VideoCaptureCapability::kARGB: { + case media::VideoCaptureCapability::kARGB: media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, frame_info_.height, (frame_info_.width + chopped_width_) * 4, frame_info_.width, frame_info_.width / 2); break; - } #if !defined(OS_IOS) && !defined(OS_ANDROID) case media::VideoCaptureCapability::kMJPEG: { int yplane_stride = frame_info_.width; @@ -398,7 +442,7 @@ void VideoCaptureController::OnIncomingCapturedVideoFrame( uint8* yplane = NULL; uint8* uplane = NULL; uint8* vplane = NULL; - if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) + if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane, 0)) return; scoped_refptr target_as_frame( @@ -553,6 +597,8 @@ void VideoCaptureController::DoFrameInfoOnIOThread() { frames_created = false; break; } + ResetBufferYV12(static_cast(shared_memory->memory()), + frame_info_.width, frame_info_.height); SharedDIB* dib = new SharedDIB(shared_memory.release()); owned_dibs_.insert(std::make_pair(i, dib)); } -- cgit v1.1