From 0bb817dab0b8969d228f187239c30c35c0e010af Mon Sep 17 00:00:00 2001 From: "mikhal@webrtc.org" Date: Tue, 10 Jul 2012 20:48:48 +0000 Subject: [PATCH] 1. Adding odd size support to LibYuv wrapper. 2. Removing unused functionality. 3. Adding support for negative height (flips the image). BUG= TEST= Review URL: https://webrtc-codereview.appspot.com/673008 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2503 4adac7df-926f-26a2-2b94-8c16560cd09d --- src/common_video/libyuv/include/libyuv.h | 28 --- src/common_video/libyuv/libyuv.cc | 241 +++++++++-------------- 2 files changed, 88 insertions(+), 181 deletions(-) diff --git a/src/common_video/libyuv/include/libyuv.h b/src/common_video/libyuv/include/libyuv.h index 6da862ff4..f14ac2d66 100644 --- a/src/common_video/libyuv/include/libyuv.h +++ b/src/common_video/libyuv/include/libyuv.h @@ -65,19 +65,6 @@ enum VideoRotationMode { // video frame or -1 in case of an error . int CalcBufferSize(VideoType type, int width, int height); -// Compute required buffer size when converting from one type to another. -// Input: -// - src_video_type - Type of the existing video frame. -// - dst_video_type - Type of the designated video frame. -// - length - length in bytes of the data. -// Return value: The required size in bytes to accommodate the specified -// converted video frame or -1 in case of an error. -int CalcBufferSize(VideoType src_video_type, - VideoType dst_video_type, - int length); -// TODO (mikhal): Merge the two functions above. - - // Convert To I420 // Input: // - src_video_type : Type of input video. @@ -169,21 +156,6 @@ int MirrorI420UpDown(const uint8_t* src_frame, uint8_t* dst_frame, int width, int height); -// Mirror functions + conversion -// Input: -// - src_frame : Pointer to source frame. -// - dst_frame : Pointer to destination frame. -// - src_width : Width of input buffer. -// - src_height : Height of input buffer. -// - src_color_space : Color space to convert from, I420 if no -// conversion should be done. -// Return value: 0 if OK, < 0 otherwise. -int ConvertToI420AndMirrorUpDown(const uint8_t* src_frame, - uint8_t* dst_frame, - int src_width, - int src_height, - VideoType src_video_type); - // Compute PSNR for an I420 frame (all planes). double I420PSNR(const uint8_t* ref_frame, const uint8_t* test_frame, diff --git a/src/common_video/libyuv/libyuv.cc b/src/common_video/libyuv/libyuv.cc index d4006c22e..41d37e33b 100644 --- a/src/common_video/libyuv/libyuv.cc +++ b/src/common_video/libyuv/libyuv.cc @@ -54,111 +54,54 @@ VideoType RawVideoTypeToCommonVideoVideoType(RawVideoType type) { } int CalcBufferSize(VideoType type, int width, int height) { - int bits_per_pixel = 32; + int buffer_size = 0; switch (type) { case kI420: case kNV12: case kNV21: case kIYUV: - case kYV12: - bits_per_pixel = 12; + case kYV12: { + int half_width = (width + 1) >> 1; + int half_height = (height + 1) >> 1; + buffer_size = width * height + half_width * half_height * 2; break; + } case kARGB4444: case kRGB565: case kARGB1555: case kYUY2: case kUYVY: - bits_per_pixel = 16; + buffer_size = width * height * 2; break; case kRGB24: - bits_per_pixel = 24; + buffer_size = width * height * 3; break; case kBGRA: case kARGB: - bits_per_pixel = 32; + buffer_size = width * height * 4; break; default: assert(false); return -1; } - return (width * height * bits_per_pixel) / 8; // bytes -} - -int CalcBufferSize(VideoType src_video_type, - VideoType dst_video_type, - int length) { - int src_bits_per_pixel = 32; - switch (src_video_type) { - case kI420: - case kNV12: - case kNV21: - case kIYUV: - case kYV12: - src_bits_per_pixel = 12; - break; - case kARGB4444: - case kRGB565: - case kARGB1555: - case kYUY2: - case kUYVY: - src_bits_per_pixel = 16; - break; - case kRGB24: - src_bits_per_pixel = 24; - break; - case kBGRA: - case kARGB: - src_bits_per_pixel = 32; - break; - default: - assert(false); - return -1; - } - - int dst_bits_per_pixel = 32; - switch (dst_video_type) { - case kI420: - case kIYUV: - case kYV12: - dst_bits_per_pixel = 12; - break; - case kARGB4444: - case kRGB565: - case kARGB1555: - case kYUY2: - case kUYVY: - dst_bits_per_pixel = 16; - break; - case kRGB24: - dst_bits_per_pixel = 24; - break; - case kBGRA: - case kARGB: - dst_bits_per_pixel = 32; - break; - default: - assert(false); - return -1; - } - return (length * dst_bits_per_pixel) / src_bits_per_pixel; + return buffer_size; } int ConvertI420ToARGB8888(const uint8_t* src_frame, uint8_t* dst_frame, int width, int height) { - + int abs_height = (height < 0) ? -height : height; + int half_width = (width + 1) >> 1; + int half_height = (abs_height + 1) >> 1; const uint8_t* src_y = src_frame; - const uint8_t* src_u = src_y + width * height; - const uint8_t* src_v = src_u + (width * height / 4); + const uint8_t* src_u = src_y + width * abs_height; + const uint8_t* src_v = src_u + half_width * half_height; int src_stride_y = width; - int src_stride_u = width / 2; - int src_stride_v = width / 2; - int dst_stride_argb = width * 4; return libyuv::I420ToARGB(src_y, src_stride_y, - src_u, src_stride_u, - src_v, src_stride_v, - dst_frame, dst_stride_argb, + src_u, half_width, + src_v, half_width, + dst_frame, width * 4, width, height); } @@ -168,13 +111,16 @@ int ConvertI420ToARGB4444(const uint8_t* src_frame, int dst_stride) { if (dst_stride == 0 || dst_stride == width) dst_stride = 2 * width; + int abs_height = (height < 0) ? -height : height; + int half_width = (width + 1) >> 1; + int half_height = (abs_height + 1) >> 1; 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 + half_width * half_height; return libyuv::I420ToARGB4444(yplane, width, - uplane, width / 2, - vplane, width / 2, + uplane, half_width, + vplane, half_width, dst_frame, dst_stride, width, height); } @@ -183,13 +129,15 @@ int ConvertI420ToRGB565(const uint8_t* src_frame, uint8_t* dst_frame, int width, int height) { int abs_height = (height < 0) ? -height : height; + int half_width = (width + 1) >> 1; + int half_height = (abs_height + 1) >> 1; const uint8_t* yplane = src_frame; const uint8_t* uplane = yplane + width * abs_height; - const uint8_t* vplane = uplane + (width + 1) / 2 * (abs_height + 1) / 2; + const uint8_t* vplane = uplane + half_width * half_height; return libyuv::I420ToRGB565(yplane, width, - uplane, (width + 1) / 2, - vplane, (width + 1) / 2, + uplane, half_width, + vplane, half_width, dst_frame, width * 2, width, height); } @@ -202,14 +150,16 @@ int ConvertI420ToARGB1555(const uint8_t* src_frame, dst_stride = 2 * width; else if (dst_stride < 2 * width) return -1; - + int abs_height = (height < 0) ? -height : height; + int half_width = (width + 1) >> 1; + int half_height = (abs_height + 1) >> 1; 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 + half_width * half_height; return libyuv::I420ToARGB1555(yplane, width, - uplane, width / 2, - vplane, width / 2, + uplane, half_width, + vplane, half_width, dst_frame, dst_stride, width, height); } @@ -217,20 +167,20 @@ int ConvertI420ToARGB1555(const uint8_t* src_frame, int ConvertNV12ToRGB565(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* uvInterlaced = src_frame + (width * height); + const uint8_t* uvInterlaced = src_frame + (width * abs_height); return libyuv::NV12ToRGB565(yplane, width, - uvInterlaced, width / 2, + uvInterlaced, (width + 1) >> 1, dst_frame, width, width, height); } int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame, int width, int height, int dst_stride) { - if (dst_stride == 0 || dst_stride == width) + if (dst_stride == 0) dst_stride = width; - // Stride - currently webrtc style return libyuv::RGB24ToARGB(src_frame, width, dst_frame, dst_stride, width, height); @@ -300,9 +250,11 @@ int ConvertToI420(VideoType src_video_type, uint8_t* dst_frame) { // All sanity tests are conducted within LibYuv. int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height; + int half_dst_width = (dst_width + 1) >> 1; + int half_dst_height = (abs_dst_height + 1) >> 1; uint8_t* dst_yplane = dst_frame; uint8_t* dst_uplane = dst_yplane + dst_width * abs_dst_height; - uint8_t* dst_vplane = dst_uplane + (dst_width * abs_dst_height / 4); + uint8_t* dst_vplane = dst_uplane + half_dst_width * half_dst_height; return libyuv::ConvertToI420(src_frame, sample_size, dst_yplane, dst_stride, dst_uplane, (dst_stride + 1) / 2, @@ -318,9 +270,12 @@ 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) { + int abs_height = (height < 0) ? -height : height; + int half_width = (width + 1) >> 1; + int half_height = (abs_height + 1) >> 1; 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); + const uint8_t* src_uplane = src_yplane + width * abs_height; + const uint8_t* src_vplane = src_uplane + half_width * half_height; return libyuv::ConvertFromI420(src_yplane, src_stride, src_uplane, (src_stride + 1) / 2, src_vplane, (src_stride + 1) / 2, @@ -333,13 +288,16 @@ 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) { + int half_src_stride = (src_stride + 1) >> 1; + int abs_height = (height < 0) ? -height : height; + int half_height = (abs_height + 1) >> 1; 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); + const uint8_t* src_uplane = src_yplane + width * abs_height; + const uint8_t* src_vplane = src_uplane + half_src_stride * half_height; // YV12 = Y, V, U return libyuv::ConvertFromI420(src_yplane, src_stride, - src_vplane, (src_stride + 1) / 2, - src_uplane, (src_stride + 1) / 2, + src_vplane, half_src_stride, + src_uplane, half_src_stride, dst_frame, dst_sample_size, width, height, ConvertVideoType(dst_video_type)); @@ -348,70 +306,44 @@ int ConvertFromYV12(const uint8_t* src_frame, int src_stride, int MirrorI420LeftRight(const uint8_t* src_frame, uint8_t* dst_frame, int width, int 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_yplane + width * height; - const uint8_t* src_vplane = src_uplane + (width * height / 4); + const uint8_t* src_vplane = src_uplane + half_width * half_height; uint8_t* dst_yplane = dst_frame; uint8_t* dst_uplane = dst_yplane + width * height; - uint8_t* dst_vplane = dst_uplane + (width * height / 4); + uint8_t* dst_vplane = dst_uplane + half_width * half_height; return libyuv::I420Mirror(src_yplane, width, - src_uplane, width / 2, - src_vplane, width / 2, + src_uplane, half_width, + src_vplane, half_width, dst_yplane, width, - dst_uplane, width / 2, - dst_vplane, width / 2, + dst_uplane, half_width, + dst_vplane, half_width, width, height); } int MirrorI420UpDown(const uint8_t* src_frame, uint8_t* dst_frame, int width, int 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_vplane = src_uplane + (width * height / 4); + 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_vplane = dst_uplane + (width * height / 4); + uint8_t* dst_vplane = dst_uplane + half_width * half_height; // Inserting negative height flips the frame. return libyuv::I420Copy(src_yplane, width, - src_uplane, width / 2, - src_vplane, width / 2, + src_uplane, half_width, + src_vplane, half_width, dst_yplane, width, - dst_uplane, width / 2, - dst_vplane, width / 2, + dst_uplane, half_width, + dst_vplane, half_width, width, -height); } -int ConvertToI420AndMirrorUpDown(const uint8_t* src_frame, - uint8_t* dst_frame, - int src_width, int src_height, - VideoType src_video_type) { - if (src_video_type != kI420 && src_video_type != kYV12) - return -1; - // TODO(mikhal): Use a more general convert function - with negative height - // Inserting negative height flips the frame. - // Using I420Copy with a negative height. - const uint8_t* src_yplane = src_frame; - const uint8_t* src_uplane = src_frame + src_width * src_height; - const uint8_t* src_vplane = src_uplane + (src_width * src_height / 4); - uint8_t* dst_yplane = dst_frame; - uint8_t* dst_uplane = dst_frame + src_width * src_height; - uint8_t* dst_vplane = dst_uplane + (src_width * src_height / 4); - if (src_video_type == kYV12) { - // Switch U and V - dst_vplane = dst_frame + src_width * src_height; - dst_uplane = dst_vplane + (src_width * src_height / 4); - } - // Inserting negative height flips the frame. - return libyuv::I420Copy(src_yplane, src_width, - src_uplane, src_width / 2, - src_vplane, src_width / 2, - dst_yplane, src_width, - dst_uplane, src_width / 2, - dst_vplane, src_width / 2, - src_width, -src_height); -} - // Compute PSNR for an I420 frame (all planes) double I420PSNR(const uint8_t* ref_frame, const uint8_t* test_frame, @@ -420,20 +352,21 @@ double I420PSNR(const uint8_t* ref_frame, return -1; else if (height < 0 || width < 0) return -1; + int half_width = (width + 1) >> 1; + int half_height = (height + 1) >> 1; const uint8_t* src_y_a = ref_frame; const uint8_t* src_u_a = src_y_a + width * height; - const uint8_t* src_v_a = src_u_a + (width * height / 4); + const uint8_t* src_v_a = src_u_a + half_width * half_height; const uint8_t* src_y_b = test_frame; const uint8_t* src_u_b = src_y_b + width * height; - const uint8_t* src_v_b = src_u_b + (width * height / 4); - int stride_y = width; - int stride_uv = (width + 1) / 2; - double psnr = libyuv::I420Psnr(src_y_a, stride_y, - src_u_a, stride_uv, - src_v_a, stride_uv, - src_y_b, stride_y, - src_u_b, stride_uv, - src_v_b, stride_uv, + const uint8_t* src_v_b = src_u_b + half_width * half_height; + // In the following: stride is determined by width. + double psnr = libyuv::I420Psnr(src_y_a, width, + src_u_a, half_width, + src_v_a, half_width, + src_y_b, width, + src_u_b, half_width, + src_v_b, half_width, width, height); // LibYuv sets the max psnr value to 128, we restrict it to 48. // In case of 0 mse in one frame, 128 can skew the results significantly. @@ -447,14 +380,16 @@ double I420SSIM(const uint8_t* ref_frame, return -1; else if (height < 0 || width < 0) return -1; + int half_width = (width + 1) >> 1; + int half_height = (height + 1) >> 1; const uint8_t* src_y_a = ref_frame; const uint8_t* src_u_a = src_y_a + width * height; - const uint8_t* src_v_a = src_u_a + (width * height / 4); + const uint8_t* src_v_a = src_u_a + half_width * half_height; const uint8_t* src_y_b = test_frame; const uint8_t* src_u_b = src_y_b + width * height; - const uint8_t* src_v_b = src_u_b + (width * height / 4); + const uint8_t* src_v_b = src_u_b + half_width * half_height; int stride_y = width; - int stride_uv = (width + 1) / 2; + int stride_uv = half_width; return libyuv::I420Ssim(src_y_a, stride_y, src_u_a, stride_uv, src_v_a, stride_uv,