From 2338131274df77004c180dd883db2bfea2ecc6a0 Mon Sep 17 00:00:00 2001 From: "mikhal@webrtc.org" Date: Thu, 27 Sep 2012 15:36:15 +0000 Subject: [PATCH] Switching Mirror functions to VideoFrame Review URL: https://webrtc-codereview.appspot.com/834005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2834 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../libyuv/include/webrtc_libyuv.h | 13 +- src/common_video/libyuv/libyuv_unittest.cc | 130 +++++++++++------- src/common_video/libyuv/webrtc_libyuv.cc | 33 +++-- .../main/source/incoming_video_stream.cc | 10 +- 4 files changed, 112 insertions(+), 74 deletions(-) diff --git a/src/common_video/libyuv/include/webrtc_libyuv.h b/src/common_video/libyuv/include/webrtc_libyuv.h index c09da043c1..a39ea32b20 100644 --- a/src/common_video/libyuv/include/webrtc_libyuv.h +++ b/src/common_video/libyuv/include/webrtc_libyuv.h @@ -130,17 +130,14 @@ int ConvertNV12ToRGB565(const uint8_t* src_frame, // The following 2 functions perform mirroring on a given image // (LeftRight/UpDown). // Input: -// - width : Image width in pixels. -// - height : Image height in pixels. // - src_frame : Pointer to a source frame. // - dst_frame : Pointer to a destination frame. // Return value: 0 if OK, < 0 otherwise. -int MirrorI420LeftRight(const uint8_t* src_frame, - uint8_t* dst_frame, - int width, int height); -int MirrorI420UpDown(const uint8_t* src_frame, - uint8_t* dst_frame, - int width, int height); +// It is assumed that src and dst frames have equal dimensions. +int MirrorI420LeftRight(const VideoFrame* src_frame, + VideoFrame* dst_frame); +int MirrorI420UpDown(const VideoFrame* src_frame, + VideoFrame* dst_frame); // Compute PSNR for an I420 frame (all planes). double I420PSNR(const uint8_t* ref_frame, diff --git a/src/common_video/libyuv/libyuv_unittest.cc b/src/common_video/libyuv/libyuv_unittest.cc index 2fb8fd2446..4af5aa572c 100644 --- a/src/common_video/libyuv/libyuv_unittest.cc +++ b/src/common_video/libyuv/libyuv_unittest.cc @@ -19,13 +19,13 @@ namespace webrtc { -int PrintFrame(const uint8_t* frame, int width, int height) { - if (frame == NULL) +int PrintBuffer(const uint8_t* buffer, int width, int height) { + if (buffer == NULL) return -1; int k = 0; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - printf("%d ", frame[k++]); + printf("%d ", buffer[k++]); } printf(" \n"); } @@ -33,34 +33,55 @@ int PrintFrame(const uint8_t* frame, int width, int height) { return 0; } -int PrintFrame(const uint8_t* frame, int width, - int height, const char* str) { + +int PrintFrame(const VideoFrame* frame, const char* str) { if (frame == NULL) return -1; - printf("%s %dx%d \n", str, width, height); - - const uint8_t* frame_y = frame; - const uint8_t* frame_u = frame_y + width * height; - const uint8_t* frame_v = frame_u + width * height / 4; + printf("%s %dx%d \n", str, frame->Width(), frame->Height()); int ret = 0; - ret += PrintFrame(frame_y, width, height); - ret += PrintFrame(frame_u, width / 2, height / 2); - ret += PrintFrame(frame_v, width / 2, height / 2); - + int width = frame->Width(); + int height = frame->Height(); + ret += PrintBuffer(frame->Buffer(), width, height); + int half_width = (frame->Width() + 1) / 2; + int half_height = (frame->Height() + 1) / 2; + ret += PrintBuffer(frame->Buffer() + width * height, half_width, half_height); + ret += PrintBuffer(frame->Buffer() + width * height + + half_width * half_height, half_width, half_height); return ret; } -void CreateImage(int width, int height, - uint8_t* frame, int offset, - int height_factor, int width_factor) { + +// Create an image from on a YUV frame. Every plane value starts with a start +// value, and will be set to increasing values. +// plane_offset - prep for PlaneType. +void CreateImage(VideoFrame* frame, int plane_offset[3]) { if (frame == NULL) return; + int width = frame->Width(); + int height = frame->Height(); + int half_width = (frame->Width() + 1) / 2; + int half_height = (frame->Height() + 1) / 2; + uint8_t *data = frame->Buffer(); + // Y plane. for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - *frame = static_cast((i + offset) * height_factor - + j * width_factor); - frame++; + *data = static_cast((i + plane_offset[0]) + j); + data++; + } + } + // U plane. + for (int i = 0; i < half_height; i++) { + for (int j = 0; j < half_width; j++) { + *data = static_cast((i + plane_offset[1]) + j); + data++; + } + } + // V Plane. + for (int i = 0; i < half_height; i++) { + for (int j = 0; j < half_width; j++) { + *data = static_cast((i + plane_offset[2]) + j); + data++; } } } @@ -251,52 +272,63 @@ TEST_F(TestLibYuv, ConvertTest) { // See http://code.google.com/p/webrtc/issues/detail?id=335 for more info. TEST_F(TestLibYuv, DISABLED_MirrorTest) { // TODO (mikhal): Add an automated test to confirm output. + // TODO(mikhal): Update to new I420VideoFrame and align values. Until then, + // this test is disabled, only insuring build. std::string str; int width = 16; int height = 8; - int factor_y = 1; - int factor_u = 1; - int factor_v = 1; - int start_buffer_offset = 10; int length = webrtc::CalcBufferSize(kI420, width, height); - uint8_t* test_frame = new uint8_t[length]; - memset(test_frame, 255, length); + VideoFrame test_frame; + test_frame.VerifyAndAllocate(length); + test_frame.SetWidth(width); + test_frame.SetHeight(height); + memset(test_frame.Buffer(), 255, length); - // Create input frame - uint8_t* in_frame = test_frame; - uint8_t* in_frame_cb = in_frame + width * height; - uint8_t* in_frame_cr = in_frame_cb + (width * height) / 4; - CreateImage(width, height, in_frame, 10, factor_y, 1); // Y - CreateImage(width / 2, height / 2, in_frame_cb, 100, factor_u, 1); // Cb - CreateImage(width / 2, height / 2, in_frame_cr, 200, factor_v, 1); // Cr - EXPECT_EQ(0, PrintFrame(test_frame, width, height, "InputFrame")); + // Create input frame. + VideoFrame in_frame, test_in_frame; + in_frame.VerifyAndAllocate(length); + in_frame.SetWidth(width); + in_frame.SetHeight(height); + in_frame.SetLength(length); + int plane_offset[3]; // prep for kNumPlanes. + plane_offset[0] = 10; + plane_offset[1] = 100; + plane_offset[2] = 200; + CreateImage(&in_frame, plane_offset); + test_in_frame.CopyFrame(in_frame); + EXPECT_EQ(0, PrintFrame(&in_frame, "InputFrame")); - uint8_t* test_frame2 = new uint8_t[length + start_buffer_offset * 2]; - memset(test_frame2, 255, length + start_buffer_offset * 2); - uint8_t* out_frame = test_frame2; + VideoFrame out_frame, test_out_frame; + out_frame.VerifyAndAllocate(length); + out_frame.SetWidth(width); + out_frame.SetHeight(height); + out_frame.SetLength(length); + CreateImage(&out_frame, plane_offset); + test_out_frame.CopyFrame(out_frame); - // LeftRight + // Left-Right. std::cout << "Test Mirror function: LeftRight" << std::endl; - EXPECT_EQ(0, MirrorI420LeftRight(in_frame, out_frame, width, height)); - EXPECT_EQ(0, PrintFrame(test_frame2, width, height, "OutputFrame")); - EXPECT_EQ(0, MirrorI420LeftRight(out_frame, test_frame, width, height)); + EXPECT_EQ(0, MirrorI420LeftRight(&in_frame, &out_frame)); + EXPECT_EQ(0, PrintFrame(&out_frame, "OutputFrame")); + EXPECT_EQ(0, MirrorI420LeftRight(&out_frame, &in_frame)); - EXPECT_EQ(0, memcmp(in_frame, test_frame, length)); + EXPECT_EQ(0, memcmp(in_frame.Buffer(), test_in_frame.Buffer(), length)); // UpDown std::cout << "Test Mirror function: UpDown" << std::endl; - EXPECT_EQ(0, MirrorI420UpDown(in_frame, out_frame, width, height)); - EXPECT_EQ(0, PrintFrame(test_frame2, width, height, "OutputFrame")); - EXPECT_EQ(0, MirrorI420UpDown(out_frame, test_frame, width, height)); - - EXPECT_EQ(0, memcmp(in_frame, test_frame, length)); + EXPECT_EQ(0, MirrorI420UpDown(&in_frame, &out_frame)); + EXPECT_EQ(0, PrintFrame(&test_out_frame, "OutputFrame")); + EXPECT_EQ(0, MirrorI420UpDown(&out_frame, &test_frame)); + EXPECT_EQ(0, memcmp(in_frame.Buffer(), test_frame.Buffer(), length)); // TODO(mikhal): Write to a file, and ask to look at the file. std::cout << "Do the mirrored frames look correct?" << std::endl; - delete [] test_frame; - delete [] test_frame2; + in_frame.Free(); + test_in_frame.Free(); + out_frame.Free(); + test_out_frame.Free(); } TEST_F(TestLibYuv, alignment) { diff --git a/src/common_video/libyuv/webrtc_libyuv.cc b/src/common_video/libyuv/webrtc_libyuv.cc index f7226f2adb..b39b242ba8 100644 --- a/src/common_video/libyuv/webrtc_libyuv.cc +++ b/src/common_video/libyuv/webrtc_libyuv.cc @@ -230,15 +230,20 @@ int ConvertFromYV12(const uint8_t* src_frame, int src_stride, ConvertVideoType(dst_video_type)); } -int MirrorI420LeftRight(const uint8_t* src_frame, - uint8_t* dst_frame, - int width, int height) { +int MirrorI420LeftRight(const VideoFrame* src_frame, + VideoFrame* dst_frame) { + // Source and destination frames should have equal resolution. + if (src_frame->Width() != dst_frame->Width() || + src_frame->Height() != dst_frame->Height()) + return -1; + int width = src_frame->Width(); + int height = src_frame->Height(); int half_width = (width + 1) >> 1; int half_height = (height + 1) >> 1; - const uint8_t* src_yplane = src_frame; + const uint8_t* src_yplane = src_frame->Buffer(); const uint8_t* src_uplane = src_yplane + width * height; const uint8_t* src_vplane = src_uplane + half_width * half_height; - uint8_t* dst_yplane = dst_frame; + uint8_t* dst_yplane = dst_frame->Buffer(); uint8_t* dst_uplane = dst_yplane + width * height; uint8_t* dst_vplane = dst_uplane + half_width * half_height; return libyuv::I420Mirror(src_yplane, width, @@ -250,15 +255,21 @@ int MirrorI420LeftRight(const uint8_t* src_frame, width, height); } -int MirrorI420UpDown(const uint8_t* src_frame, uint8_t* dst_frame, - int width, int height) { +int MirrorI420UpDown(const VideoFrame* src_frame, + VideoFrame* dst_frame) { + // Source and destination frames should have equal resolution + if (src_frame->Width() != dst_frame->Width() || + src_frame->Height() != dst_frame->Height()) + return -1; + int width = src_frame->Width(); + int height = src_frame->Height(); int half_width = (width + 1) >> 1; int half_height = (height + 1) >> 1; - const uint8_t* src_yplane = src_frame; - const uint8_t* src_uplane = src_frame + width * height; + const uint8_t* src_yplane = src_frame->Buffer(); + const uint8_t* src_uplane = src_yplane + width * height; const uint8_t* src_vplane = src_uplane + half_width * half_height; - uint8_t* dst_yplane = dst_frame; - uint8_t* dst_uplane = dst_frame + width * height; + uint8_t* dst_yplane = dst_frame->Buffer(); + uint8_t* dst_uplane = dst_yplane + width * height; uint8_t* dst_vplane = dst_uplane + half_width * half_height; // Inserting negative height flips the frame. diff --git a/src/modules/video_render/main/source/incoming_video_stream.cc b/src/modules/video_render/main/source/incoming_video_stream.cc index e44862a3d5..2c98060141 100644 --- a/src/modules/video_render/main/source/incoming_video_stream.cc +++ b/src/modules/video_render/main/source/incoming_video_stream.cc @@ -104,21 +104,19 @@ WebRtc_Word32 IncomingVideoStream::RenderFrame(const WebRtc_UWord32 stream_id, if (true == mirror_frames_enabled_) { transformed_video_frame_.VerifyAndAllocate(video_frame.Length()); if (mirroring_.mirror_x_axis) { - MirrorI420UpDown(video_frame.Buffer(), - transformed_video_frame_.Buffer(), - video_frame.Width(), video_frame.Height()); transformed_video_frame_.SetLength(video_frame.Length()); transformed_video_frame_.SetWidth(video_frame.Width()); transformed_video_frame_.SetHeight(video_frame.Height()); + MirrorI420UpDown(&video_frame, + &transformed_video_frame_); video_frame.SwapFrame(transformed_video_frame_); } if (mirroring_.mirror_y_axis) { - MirrorI420LeftRight(video_frame.Buffer(), - transformed_video_frame_.Buffer(), - video_frame.Width(), video_frame.Height()); transformed_video_frame_.SetLength(video_frame.Length()); transformed_video_frame_.SetWidth(video_frame.Width()); transformed_video_frame_.SetHeight(video_frame.Height()); + MirrorI420LeftRight(&video_frame, + &transformed_video_frame_); video_frame.SwapFrame(transformed_video_frame_); } }