From e2642494e416917637f8d68c439219515eb1bba4 Mon Sep 17 00:00:00 2001 From: "mikhal@webrtc.org" Date: Wed, 28 Dec 2011 21:21:40 +0000 Subject: [PATCH] libyuv: Updating API to use latest ConvertFrom/To functionality Review URL: http://webrtc-codereview.appspot.com/333020 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1302 4adac7df-926f-26a2-2b94-8c16560cd09d --- src/common_video/libyuv/include/libyuv.h | 56 ++++++++- src/common_video/libyuv/libyuv.cc | 135 ++++++++++++++++++++- src/common_video/libyuv/libyuv_unittest.cc | 55 ++++----- 3 files changed, 211 insertions(+), 35 deletions(-) diff --git a/src/common_video/libyuv/include/libyuv.h b/src/common_video/libyuv/include/libyuv.h index 468706377..f016a3f9d 100644 --- a/src/common_video/libyuv/include/libyuv.h +++ b/src/common_video/libyuv/include/libyuv.h @@ -29,6 +29,7 @@ enum VideoType { kI420, kIYUV, kRGB24, + kABGR, kARGB, kARGB4444, kRGB565, @@ -39,9 +40,9 @@ enum VideoType { kMJPG, kNV21, kNV12, - kARGBMac, - kRGBAMac, - kNumberOfVideoTypes + kBGRA, + kARGBMac, // TODO (mikhal): remove + kRGBAMac, // TODO (mikhal): remove }; // Conversion between the RawVideoType and the LibYuv videoType. @@ -105,6 +106,32 @@ int ConvertToI420(VideoType src_video_type, bool interlaced, VideoRotationMode rotate); +// The previous function will soon be removed. +// TODO(mikhal): Remove legacy function after integration. + +// Convert From/To I420 +// Input: +// - src_video_type : Type of input video. +// - src_frame : Pointer to a source frame. +// - crop_x/crop_y : Starting positions for cropping (0 for no crop). +// - src/dst_width : src/dst width in pixels. +// - src/dst_height : src/dst height in pixels. +// - sample_size : Required only for the parsing of MJPG (set to 0 else). +// - dst_stride : Number of bytes in a row of the dst Y plane. +// - rotate : Rotation mode of output image. +// Output: +// - dst_frame : Pointer to a destination frame. +// Return value: 0 if OK, < 0 otherwise. + +int ConvertToI420(VideoType src_video_type, + const uint8_t* src_frame, + int crop_x, int crop_y, + int src_width, int src_height, + int sample_size, + int dst_width, int dst_height, int dst_stride, + VideoRotationMode rotation, + uint8_t* dst_frame); + // TODO(andrew): return to the int width and height types. This was swapped // temporarily to satisfy a linking error with the libjingle revision we and // Chrome pull, due to the removed vplib. @@ -117,6 +144,29 @@ int ConvertFromI420(VideoType dst_video_type, uint8_t* dst_frame, bool interlaced, VideoRotationMode rotate); +// The previous function will soon be removed. +// TODO(mikhal): Remove legacy function after integration. +// Input: +// - src_frame : Pointer to a source frame. +// - src_stride : Number of bytes in a row of the src Y plane. +// - dst_video_type : Type of output video. +// - dst_sample_size : Required only for the parsing of MJPG. +// - width : Width in pixels. +// - height : Height in pixels. +// - dst_frame : Pointer to a source frame. + +// - dst_frame : Pointer to a destination frame. +// Return value: 0 if OK, < 0 otherwise. +int ConvertFromI420(const uint8_t* src_frame, int src_stride, + VideoType dst_video_type, int dst_sample_size, + int width, int height, + uint8_t* dst_frame); +// ConvertFrom YV12. +// Interface - same as above. +int ConvertFromYV12(const uint8_t* src_frame, int src_stride, + VideoType dst_video_type, int dst_sample_size, + int width, int height, + uint8_t* dst_frame); // The following list describes the designated conversion function which // are called by the two prior general conversion function. diff --git a/src/common_video/libyuv/libyuv.cc b/src/common_video/libyuv/libyuv.cc index 178dad343..251a52dd1 100644 --- a/src/common_video/libyuv/libyuv.cc +++ b/src/common_video/libyuv/libyuv.cc @@ -208,9 +208,10 @@ int ConvertI420ToARGB4444(const uint8_t* src_frame, int ConvertI420ToRGB565(const uint8_t* src_frame, uint8_t* dst_frame, int width, int height) { + int abs_height = (height < 0) ? -height : height; const uint8_t* yplane = src_frame; - const uint8_t* uplane = src_frame + width * height; - const uint8_t* vplane = uplane + (width * height / 4); + const uint8_t* uplane = src_frame + width * abs_height; + const uint8_t* vplane = uplane + (width * abs_height / 4); return libyuv::I420ToRGB565(yplane, width, uplane, width / 2, @@ -221,6 +222,7 @@ int ConvertI420ToRGB565(const uint8_t* src_frame, // Same as ConvertI420ToRGB565 with a vertical flip. +// TODO (mikhal): Deprecate int ConvertI420ToRGB565Android(const uint8_t* src_frame, uint8_t* dst_frame, int width, int height) { @@ -571,12 +573,11 @@ int ConvertRGB24ToI420(int width, int height, uint8_t* yplane = dst_frame; uint8_t* uplane = yplane + width * height; uint8_t* vplane = uplane + (width * height / 4); - // WebRtc expects a vertical flipped image. return libyuv::RGB24ToI420(src_frame, width * 3, yplane, width, uplane, width / 2, vplane, width / 2, - width, -height); + width, height); } int ConvertI420ToARGBMac(const uint8_t* src_frame, uint8_t* dst_frame, @@ -612,6 +613,131 @@ int ConvertARGBMacToI420(int width, int height, width, height); } +libyuv::RotationMode ConvertRotationMode(VideoRotationMode rotation) { + switch(rotation) { + case kRotateNone: + return libyuv::kRotate0; + break; + case kRotate90: + return libyuv::kRotate90; + break; + case kRotate180: + return libyuv::kRotate180; + break; + case kRotate270: + return libyuv::kRotate270; + break; + } + assert(false); +} + +int ConvertVideoType(VideoType video_type) { + switch(video_type) { + case kUnknown: + return libyuv::FOURCC_ANY; + break; + case kI420: + return libyuv::FOURCC_I420; + break; + case kIYUV: // same as KYV12 + case kYV12: + return libyuv::FOURCC_YV12; + break; + case kRGB24: + return libyuv::FOURCC_24BG; + break; + case kABGR: + return libyuv::FOURCC_ABGR; + break; + case kARGB4444: + case kRGB565: + case kARGB1555: + case kARGBMac: + case kRGBAMac: + // TODO(mikhal): Not supported; + assert(false); + return libyuv::FOURCC_ANY; + break; + case kYUY2: + return libyuv::FOURCC_YUY2; + break; + case kUYVY: + return libyuv::FOURCC_UYVY; + break; + case kMJPG: + return libyuv::FOURCC_MJPG; + break; + case kNV21: + return libyuv::FOURCC_NV21; + break; + case kNV12: + return libyuv::FOURCC_NV12; + break; + case kARGB: + return libyuv::FOURCC_ARGB; + break; + case kBGRA: + return libyuv::FOURCC_BGRA; + break; + } + // default value + return libyuv::FOURCC_ANY; +} + +int ConvertToI420(VideoType src_video_type, + const uint8_t* src_frame, + int crop_x, int crop_y, + int src_width, int src_height, + int sample_size, + int dst_width, int dst_height, int dst_stride, + VideoRotationMode rotation, + uint8_t* dst_frame) { + // All sanity tests are conducted within LibYuv. + uint8_t* dst_yplane = dst_frame; + uint8_t* dst_uplane = dst_yplane + dst_width * dst_height; + uint8_t* dst_vplane = dst_uplane + (dst_width * dst_height / 4); + return libyuv::ConvertToI420(src_frame, sample_size, + dst_yplane, dst_stride, + dst_uplane, (dst_stride + 1) / 2, + dst_vplane, (dst_stride + 1) / 2, + crop_x, crop_y, + src_width, src_height, + dst_width, dst_height, + ConvertRotationMode(rotation), + ConvertVideoType(src_video_type)); +} + +int ConvertFromI420(const uint8_t* src_frame, int src_stride, + VideoType dst_video_type, int dst_sample_size, + int width, int height, + uint8_t* dst_frame) { + const uint8_t* src_yplane = src_frame; + const uint8_t* src_uplane = src_yplane + width * height; + const uint8_t* src_vplane = src_uplane + (width * height / 4); + return libyuv::ConvertFromI420(src_yplane, src_stride, + src_uplane, (src_stride + 1) / 2, + src_vplane, (src_stride + 1) / 2, + dst_frame, dst_sample_size, + width, height, + ConvertVideoType(dst_video_type)); +} + +int ConvertFromYV12(const uint8_t* src_frame, int src_stride, + VideoType dst_video_type, int dst_sample_size, + int width, int height, + uint8_t* dst_frame) { + const uint8_t* src_yplane = src_frame; + const uint8_t* src_uplane = src_yplane + width * height; + const uint8_t* src_vplane = src_uplane + (width * height / 4); + // YV12 = Y, V, U + return libyuv::ConvertFromI420(src_yplane, src_stride, + src_vplane, (src_stride + 1) / 2, + src_uplane, (src_stride + 1) / 2, + dst_frame, dst_sample_size, + width, height, + ConvertVideoType(dst_video_type)); +} + int ConvertToI420(VideoType src_video_type, const uint8_t* src_frame, int width, @@ -974,7 +1100,6 @@ double I420SSIM(const uint8_t* ref_frame, src_u_b, stride_uv, src_v_b, stride_uv, width, height); - } } // namespace webrtc diff --git a/src/common_video/libyuv/libyuv_unittest.cc b/src/common_video/libyuv/libyuv_unittest.cc index f6859f389..9f1645b16 100644 --- a/src/common_video/libyuv/libyuv_unittest.cc +++ b/src/common_video/libyuv/libyuv_unittest.cc @@ -119,27 +119,27 @@ TEST_F(TestLibYuv, ConvertTest) { // printf("\nConvert #%d I420 <-> RGB24\n", j); uint8_t* res_rgb_buffer2 = new uint8_t[width_ * height_ * 3]; uint8_t* res_i420_buffer = new uint8_t[frame_length_]; - EXPECT_EQ(0, ConvertFromI420(kRGB24, orig_buffer, width_, height_, - res_rgb_buffer2, false, kRotateNone)); - EXPECT_EQ(0, ConvertToI420(kRGB24, res_rgb_buffer2, width_, height_, - res_i420_buffer, false, kRotateNone)); + + EXPECT_EQ(0, ConvertFromI420(orig_buffer, width_, kRGB24, 0, + width_, height_, res_rgb_buffer2)); + + EXPECT_EQ(0, ConvertToI420(kRGB24, res_rgb_buffer2, 0, 0, width_, height_, + 0, width_, height_, width_, kRotateNone, + res_i420_buffer)); fwrite(res_i420_buffer, frame_length_, 1, output_file); - //ImagePSNRfromBuffer(orig_buffer, res_i420_buffer, width_, height_, &psnr); psnr = I420PSNR(orig_buffer, res_i420_buffer, width_, height_); - // Optimization Speed- quality trade-off => 45 dB only. + // Optimization Speed- quality trade-off => 45 dB only (platform dependant). EXPECT_GT(ceil(psnr), 45); j++; delete [] res_rgb_buffer2; // printf("\nConvert #%d I420 <-> UYVY\n", j); uint8_t* out_uyvy_buffer = new uint8_t[width_ * height_ * 2]; - EXPECT_EQ(0, ConvertFromI420(kUYVY, orig_buffer, width_, - height_, out_uyvy_buffer, false, kRotateNone)); - - EXPECT_EQ(0, ConvertToI420(kUYVY, out_uyvy_buffer, width_, height_, - res_i420_buffer, false, kRotateNone)); - //ImagePSNRfromBuffer(orig_buffer, res_i420_buffer, width_, height_, &psnr); + EXPECT_EQ(0, ConvertFromI420(orig_buffer, width_, + kUYVY, 0, width_, height_, out_uyvy_buffer)); + EXPECT_EQ(0, ConvertToI420(kUYVY, out_uyvy_buffer, 0, 0, width_, height_, + 0, width_, height_, width_,kRotateNone, res_i420_buffer)); psnr = I420PSNR(orig_buffer, res_i420_buffer, width_, height_); EXPECT_EQ(48.0, psnr); fwrite(res_i420_buffer, frame_length_, 1, output_file); @@ -149,12 +149,12 @@ TEST_F(TestLibYuv, ConvertTest) { // printf("\nConvert #%d I420 <-> I420 \n", j); uint8_t* out_i420_buffer = new uint8_t[width_ * height_ * 3 / 2 ]; - EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer, width_, height_, - out_i420_buffer, false, kRotateNone)); - EXPECT_EQ(0, ConvertFromI420(kI420 , out_i420_buffer, width_, height_, - res_i420_buffer, false, kRotateNone)); + EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer, 0, 0, width_, height_, + 0, width_, height_, width_, + kRotateNone, out_i420_buffer)); + EXPECT_EQ(0, ConvertFromI420(out_i420_buffer, width_, kI420, 0, + width_, height_, res_i420_buffer)); fwrite(res_i420_buffer, frame_length_, 1, output_file); - //ImagePSNRfromBuffer(orig_buffer, res_i420_buffer, width_, height_, &psnr); psnr = I420PSNR(orig_buffer, res_i420_buffer, width_, height_); EXPECT_EQ(48.0, psnr); j++; @@ -163,13 +163,14 @@ TEST_F(TestLibYuv, ConvertTest) { // printf("\nConvert #%d I420 <-> YV12\n", j); uint8_t* outYV120Buffer = new uint8_t[frame_length_]; - EXPECT_EQ(0, ConvertFromI420(kYV12, orig_buffer, width_, height_, - outYV120Buffer, false, kRotateNone)); - EXPECT_EQ(0, ConvertYV12ToI420(outYV120Buffer, width_, height_, - res_i420_buffer)); + EXPECT_EQ(0, ConvertFromI420(orig_buffer, width_, kYV12, 0, + width_, height_, outYV120Buffer)); + EXPECT_EQ(0, ConvertFromYV12(outYV120Buffer, width_, + kI420, 0, + width_, height_, + res_i420_buffer)); fwrite(res_i420_buffer, frame_length_, 1, output_file); - //ImagePSNRfromBuffer(orig_buffer, res_i420_buffer, width_, height_, &psnr); psnr = I420PSNR(orig_buffer, res_i420_buffer, width_, height_); EXPECT_EQ(48.0, psnr); j++; @@ -177,14 +178,14 @@ TEST_F(TestLibYuv, ConvertTest) { // printf("\nConvert #%d I420 <-> YUY2\n", j); uint8_t* out_yuy2_buffer = new uint8_t[width_ * height_ * 2]; + EXPECT_EQ(0, ConvertFromI420(orig_buffer, width_, + kYUY2, 0, width_, height_, out_yuy2_buffer)); - EXPECT_EQ(0, ConvertFromI420(kYUY2, orig_buffer, width_, height_, - out_yuy2_buffer, false, kRotateNone)); - EXPECT_EQ(0, ConvertToI420(kYUY2, out_yuy2_buffer, width_, height_, - res_i420_buffer, false, kRotateNone)); + EXPECT_EQ(0, ConvertToI420(kYUY2, out_yuy2_buffer, 0, 0, width_, height_, + 0, width_, height_, width_, + kRotateNone, res_i420_buffer)); fwrite(res_i420_buffer, frame_length_, 1, output_file); - //ImagePSNRfromBuffer(orig_buffer, res_i420_buffer, width_, height_, &psnr); psnr = I420PSNR(orig_buffer, res_i420_buffer, width_, height_); EXPECT_EQ(48.0, psnr); delete [] out_yuy2_buffer;