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
This commit is contained in:
mikhal@webrtc.org
2012-07-10 20:48:48 +00:00
parent 475c26634e
commit 0bb817dab0
2 changed files with 88 additions and 181 deletions

View File

@@ -65,19 +65,6 @@ enum VideoRotationMode {
// video frame or -1 in case of an error . // video frame or -1 in case of an error .
int CalcBufferSize(VideoType type, int width, int height); 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 // Convert To I420
// Input: // Input:
// - src_video_type : Type of input video. // - src_video_type : Type of input video.
@@ -169,21 +156,6 @@ int MirrorI420UpDown(const uint8_t* src_frame,
uint8_t* dst_frame, uint8_t* dst_frame,
int width, int height); 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). // Compute PSNR for an I420 frame (all planes).
double I420PSNR(const uint8_t* ref_frame, double I420PSNR(const uint8_t* ref_frame,
const uint8_t* test_frame, const uint8_t* test_frame,

View File

@@ -54,111 +54,54 @@ VideoType RawVideoTypeToCommonVideoVideoType(RawVideoType type) {
} }
int CalcBufferSize(VideoType type, int width, int height) { int CalcBufferSize(VideoType type, int width, int height) {
int bits_per_pixel = 32; int buffer_size = 0;
switch (type) { switch (type) {
case kI420: case kI420:
case kNV12: case kNV12:
case kNV21: case kNV21:
case kIYUV: case kIYUV:
case kYV12: case kYV12: {
bits_per_pixel = 12; int half_width = (width + 1) >> 1;
int half_height = (height + 1) >> 1;
buffer_size = width * height + half_width * half_height * 2;
break; break;
}
case kARGB4444: case kARGB4444:
case kRGB565: case kRGB565:
case kARGB1555: case kARGB1555:
case kYUY2: case kYUY2:
case kUYVY: case kUYVY:
bits_per_pixel = 16; buffer_size = width * height * 2;
break; break;
case kRGB24: case kRGB24:
bits_per_pixel = 24; buffer_size = width * height * 3;
break; break;
case kBGRA: case kBGRA:
case kARGB: case kARGB:
bits_per_pixel = 32; buffer_size = width * height * 4;
break; break;
default: default:
assert(false); assert(false);
return -1; return -1;
} }
return (width * height * bits_per_pixel) / 8; // bytes return buffer_size;
}
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;
} }
int ConvertI420ToARGB8888(const uint8_t* src_frame, int ConvertI420ToARGB8888(const uint8_t* src_frame,
uint8_t* dst_frame, uint8_t* dst_frame,
int width, int height) { 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_y = src_frame;
const uint8_t* src_u = src_y + width * height; const uint8_t* src_u = src_y + width * abs_height;
const uint8_t* src_v = src_u + (width * height / 4); const uint8_t* src_v = src_u + half_width * half_height;
int src_stride_y = width; 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, return libyuv::I420ToARGB(src_y, src_stride_y,
src_u, src_stride_u, src_u, half_width,
src_v, src_stride_v, src_v, half_width,
dst_frame, dst_stride_argb, dst_frame, width * 4,
width, height); width, height);
} }
@@ -168,13 +111,16 @@ int ConvertI420ToARGB4444(const uint8_t* src_frame,
int dst_stride) { int dst_stride) {
if (dst_stride == 0 || dst_stride == width) if (dst_stride == 0 || dst_stride == width)
dst_stride = 2 * 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* yplane = src_frame;
const uint8_t* uplane = src_frame + width * height; const uint8_t* uplane = src_frame + width * abs_height;
const uint8_t* vplane = uplane + (width * height / 4); const uint8_t* vplane = uplane + half_width * half_height;
return libyuv::I420ToARGB4444(yplane, width, return libyuv::I420ToARGB4444(yplane, width,
uplane, width / 2, uplane, half_width,
vplane, width / 2, vplane, half_width,
dst_frame, dst_stride, dst_frame, dst_stride,
width, height); width, height);
} }
@@ -183,13 +129,15 @@ int ConvertI420ToRGB565(const uint8_t* src_frame,
uint8_t* dst_frame, uint8_t* dst_frame,
int width, int height) { int width, int height) {
int abs_height = (height < 0) ? -height : 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* yplane = src_frame;
const uint8_t* uplane = yplane + width * abs_height; 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, return libyuv::I420ToRGB565(yplane, width,
uplane, (width + 1) / 2, uplane, half_width,
vplane, (width + 1) / 2, vplane, half_width,
dst_frame, width * 2, dst_frame, width * 2,
width, height); width, height);
} }
@@ -202,14 +150,16 @@ int ConvertI420ToARGB1555(const uint8_t* src_frame,
dst_stride = 2 * width; dst_stride = 2 * width;
else if (dst_stride < 2 * width) else if (dst_stride < 2 * width)
return -1; 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* yplane = src_frame;
const uint8_t* uplane = src_frame + width * height; const uint8_t* uplane = src_frame + width * abs_height;
const uint8_t* vplane = uplane + (width * height / 4); const uint8_t* vplane = uplane + half_width * half_height;
return libyuv::I420ToARGB1555(yplane, width, return libyuv::I420ToARGB1555(yplane, width,
uplane, width / 2, uplane, half_width,
vplane, width / 2, vplane, half_width,
dst_frame, dst_stride, dst_frame, dst_stride,
width, height); width, height);
} }
@@ -217,20 +167,20 @@ int ConvertI420ToARGB1555(const uint8_t* src_frame,
int ConvertNV12ToRGB565(const uint8_t* src_frame, int ConvertNV12ToRGB565(const uint8_t* src_frame,
uint8_t* dst_frame, uint8_t* dst_frame,
int width, int height) { int width, int height) {
int abs_height = (height < 0) ? -height : height;
const uint8_t* yplane = src_frame; 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, return libyuv::NV12ToRGB565(yplane, width,
uvInterlaced, width / 2, uvInterlaced, (width + 1) >> 1,
dst_frame, width, dst_frame, width,
width, height); width, height);
} }
int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame, int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame,
int width, int height, int dst_stride) { int width, int height, int dst_stride) {
if (dst_stride == 0 || dst_stride == width) if (dst_stride == 0)
dst_stride = width; dst_stride = width;
// Stride - currently webrtc style
return libyuv::RGB24ToARGB(src_frame, width, return libyuv::RGB24ToARGB(src_frame, width,
dst_frame, dst_stride, dst_frame, dst_stride,
width, height); width, height);
@@ -300,9 +250,11 @@ int ConvertToI420(VideoType src_video_type,
uint8_t* dst_frame) { uint8_t* dst_frame) {
// All sanity tests are conducted within LibYuv. // All sanity tests are conducted within LibYuv.
int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height; 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_yplane = dst_frame;
uint8_t* dst_uplane = dst_yplane + dst_width * abs_dst_height; 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, return libyuv::ConvertToI420(src_frame, sample_size,
dst_yplane, dst_stride, dst_yplane, dst_stride,
dst_uplane, (dst_stride + 1) / 2, 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, VideoType dst_video_type, int dst_sample_size,
int width, int height, int width, int height,
uint8_t* dst_frame) { 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_yplane = src_frame;
const uint8_t* src_uplane = src_yplane + width * height; const uint8_t* src_uplane = src_yplane + width * abs_height;
const uint8_t* src_vplane = src_uplane + (width * height / 4); const uint8_t* src_vplane = src_uplane + half_width * half_height;
return libyuv::ConvertFromI420(src_yplane, src_stride, return libyuv::ConvertFromI420(src_yplane, src_stride,
src_uplane, (src_stride + 1) / 2, src_uplane, (src_stride + 1) / 2,
src_vplane, (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, VideoType dst_video_type, int dst_sample_size,
int width, int height, int width, int height,
uint8_t* dst_frame) { 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_yplane = src_frame;
const uint8_t* src_uplane = src_yplane + width * height; const uint8_t* src_uplane = src_yplane + width * abs_height;
const uint8_t* src_vplane = src_uplane + (width * height / 4); const uint8_t* src_vplane = src_uplane + half_src_stride * half_height;
// YV12 = Y, V, U // YV12 = Y, V, U
return libyuv::ConvertFromI420(src_yplane, src_stride, return libyuv::ConvertFromI420(src_yplane, src_stride,
src_vplane, (src_stride + 1) / 2, src_vplane, half_src_stride,
src_uplane, (src_stride + 1) / 2, src_uplane, half_src_stride,
dst_frame, dst_sample_size, dst_frame, dst_sample_size,
width, height, width, height,
ConvertVideoType(dst_video_type)); 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, int MirrorI420LeftRight(const uint8_t* src_frame,
uint8_t* dst_frame, uint8_t* dst_frame,
int width, int height) { 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_yplane = src_frame;
const uint8_t* src_uplane = src_yplane + width * height; 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_yplane = dst_frame;
uint8_t* dst_uplane = dst_yplane + width * height; 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, return libyuv::I420Mirror(src_yplane, width,
src_uplane, width / 2, src_uplane, half_width,
src_vplane, width / 2, src_vplane, half_width,
dst_yplane, width, dst_yplane, width,
dst_uplane, width / 2, dst_uplane, half_width,
dst_vplane, width / 2, dst_vplane, half_width,
width, height); width, height);
} }
int MirrorI420UpDown(const uint8_t* src_frame, uint8_t* dst_frame, int MirrorI420UpDown(const uint8_t* src_frame, uint8_t* dst_frame,
int width, int height) { 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_yplane = src_frame;
const uint8_t* src_uplane = src_frame + width * height; 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_yplane = dst_frame;
uint8_t* dst_uplane = dst_frame + width * height; 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. // Inserting negative height flips the frame.
return libyuv::I420Copy(src_yplane, width, return libyuv::I420Copy(src_yplane, width,
src_uplane, width / 2, src_uplane, half_width,
src_vplane, width / 2, src_vplane, half_width,
dst_yplane, width, dst_yplane, width,
dst_uplane, width / 2, dst_uplane, half_width,
dst_vplane, width / 2, dst_vplane, half_width,
width, -height); 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) // Compute PSNR for an I420 frame (all planes)
double I420PSNR(const uint8_t* ref_frame, double I420PSNR(const uint8_t* ref_frame,
const uint8_t* test_frame, const uint8_t* test_frame,
@@ -420,20 +352,21 @@ double I420PSNR(const uint8_t* ref_frame,
return -1; return -1;
else if (height < 0 || width < 0) else if (height < 0 || width < 0)
return -1; 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_y_a = ref_frame;
const uint8_t* src_u_a = src_y_a + width * height; 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_y_b = test_frame;
const uint8_t* src_u_b = src_y_b + width * height; 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; // In the following: stride is determined by width.
int stride_uv = (width + 1) / 2; double psnr = libyuv::I420Psnr(src_y_a, width,
double psnr = libyuv::I420Psnr(src_y_a, stride_y, src_u_a, half_width,
src_u_a, stride_uv, src_v_a, half_width,
src_v_a, stride_uv, src_y_b, width,
src_y_b, stride_y, src_u_b, half_width,
src_u_b, stride_uv, src_v_b, half_width,
src_v_b, stride_uv,
width, height); width, height);
// LibYuv sets the max psnr value to 128, we restrict it to 48. // 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. // 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; return -1;
else if (height < 0 || width < 0) else if (height < 0 || width < 0)
return -1; 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_y_a = ref_frame;
const uint8_t* src_u_a = src_y_a + width * height; 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_y_b = test_frame;
const uint8_t* src_u_b = src_y_b + width * height; 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_y = width;
int stride_uv = (width + 1) / 2; int stride_uv = half_width;
return libyuv::I420Ssim(src_y_a, stride_y, return libyuv::I420Ssim(src_y_a, stride_y,
src_u_a, stride_uv, src_u_a, stride_uv,
src_v_a, stride_uv, src_v_a, stride_uv,