diff --git a/README.chromium b/README.chromium index d6f51ab00..7f777c63c 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 179 +Version: 180 License: BSD License File: LICENSE diff --git a/include/libyuv/convert.h b/include/libyuv/convert.h index 1912cdd77..a0d1cc032 100644 --- a/include/libyuv/convert.h +++ b/include/libyuv/convert.h @@ -49,6 +49,15 @@ int I444ToI420(const uint8* src_y, int src_stride_y, uint8* dst_v, int dst_stride_v, int width, int height); +// Convert I411 to I420. +int I411ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + // Convert I400 (grey) to I420. int I400ToI420(const uint8* src_y, int src_stride_y, uint8* dst_y, int dst_stride_y, diff --git a/include/libyuv/convert_from.h b/include/libyuv/convert_from.h index 26047eea6..a50c931ed 100644 --- a/include/libyuv/convert_from.h +++ b/include/libyuv/convert_from.h @@ -39,6 +39,14 @@ int I420ToI444(const uint8* src_y, int src_stride_y, uint8* dst_v, int dst_stride_v, int width, int height); +int I420ToI411(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + // Copy to I400. Source can be I420,422,444,400,NV12,NV21 int I400Copy(const uint8* src_y, int src_stride_y, uint8* dst_y, int dst_stride_y, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index ca0952fa3..44082ed29 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,7 +11,7 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 179 +#define LIBYUV_VERSION 180 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/include/libyuv/video_common.h b/include/libyuv/video_common.h index cb8237314..636545646 100644 --- a/include/libyuv/video_common.h +++ b/include/libyuv/video_common.h @@ -42,6 +42,7 @@ enum FourCC { FOURCC_I420 = FOURCC('I', '4', '2', '0'), FOURCC_I422 = FOURCC('I', '4', '2', '2'), FOURCC_I444 = FOURCC('I', '4', '4', '4'), + FOURCC_I411 = FOURCC('I', '4', '1', '1'), FOURCC_I400 = FOURCC('I', '4', '0', '0'), FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), diff --git a/source/convert.cc b/source/convert.cc index 7d682083d..20f84ca23 100644 --- a/source/convert.cc +++ b/source/convert.cc @@ -258,6 +258,57 @@ int I444ToI420(const uint8* src_y, int src_stride_y, return 0; } +// use Bilinear for upsampling chroma +void ScalePlaneBilinear(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_ptr, uint8* dst_ptr); + +// 411 chroma is 1/4 width, 1x height +// 420 chroma is 1/2 width, 1/2 height +int I411ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height) { + // Negative height means invert the image. + if (height < 0) { + height = -height; + dst_y = dst_y + (height - 1) * dst_stride_y; + dst_u = dst_u + (height - 1) * dst_stride_u; + dst_v = dst_v + (height - 1) * dst_stride_v; + dst_stride_y = -dst_stride_y; + dst_stride_u = -dst_stride_u; + dst_stride_v = -dst_stride_v; + } + + // Copy Y plane + if (dst_y) { + CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + } + + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + int quarterwidth = (width + 3) >> 2; + + // Resample U plane. + ScalePlaneBilinear(quarterwidth, height, // from 1/4 width, 1x height + halfwidth, halfheight, // to 1/2 width, 1/2 height + src_stride_u, + dst_stride_u, + src_u, dst_u); + + // Resample V plane. + ScalePlaneBilinear(quarterwidth, height, // from 1/4 width, 1x height + halfwidth, halfheight, // to 1/2 width, 1/2 height + src_stride_v, + dst_stride_v, + src_v, dst_v); + return 0; +} + // I400 is greyscale typically used in MJPG int I400ToI420(const uint8* src_y, int src_stride_y, uint8* dst_y, int dst_stride_y, @@ -1607,6 +1658,23 @@ int ConvertToI420(const uint8* sample, size_t sample_size, dst_width, inv_dst_height); break; } + case FOURCC_I411: { + int quarterwidth = (src_width + 3) / 4; + const uint8* src_y = sample + src_width * crop_y + crop_x; + const uint8* src_u = sample + src_width * abs_src_height + + quarterwidth * crop_y + crop_x / 4; + const uint8* src_v = sample + src_width * abs_src_height + + quarterwidth * (abs_src_height + crop_y) + crop_x / 4; + I411ToI420(src_y, src_width, + src_u, quarterwidth, + src_v, quarterwidth, + y, y_stride, + u, u_stride, + v, v_stride, + dst_width, inv_dst_height); + break; + } + // Formats not supported case FOURCC_MJPG: default: diff --git a/source/convert_from.cc b/source/convert_from.cc index cb436a1e4..8102a2d37 100644 --- a/source/convert_from.cc +++ b/source/convert_from.cc @@ -140,6 +140,51 @@ int I420ToI444(const uint8* src_y, int src_stride_y, return 0; } +// 420 chroma is 1/2 width, 1/2 height +// 411 chroma is 1/4 width, 1x height +int I420ToI411(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height) { + // Negative height means invert the image. + if (height < 0) { + height = -height; + dst_y = dst_y + (height - 1) * dst_stride_y; + dst_u = dst_u + (height - 1) * dst_stride_u; + dst_v = dst_v + (height - 1) * dst_stride_v; + dst_stride_y = -dst_stride_y; + dst_stride_u = -dst_stride_u; + dst_stride_v = -dst_stride_v; + } + + // Copy Y plane + if (dst_y) { + CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + } + + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + int quarterwidth = (width + 3) >> 2; + + // Resample U plane. + ScalePlaneBilinear(halfwidth, halfheight, // from 1/2 width, 1/2 height + quarterwidth, height, // to 1/4 width, 1x height + src_stride_u, + dst_stride_u, + src_u, dst_u); + + // Resample V plane. + ScalePlaneBilinear(halfwidth, halfheight, // from 1/2 width, 1/2 height + quarterwidth, height, // to 1/4 width, 1x height + src_stride_v, + dst_stride_v, + src_v, dst_v); + return 0; +} + // Copy to I400. Source can be I420,422,444,400,NV12,NV21 int I400Copy(const uint8* src_y, int src_stride_y, uint8* dst_y, int dst_stride_y, @@ -1231,6 +1276,19 @@ int ConvertFromI420(const uint8* y, int y_stride, width, height); break; } + case FOURCC_I411: { + int quarterwidth = (width + 3) / 4; + uint8* dst_u = dst_sample + width * height; + uint8* dst_v = dst_u + quarterwidth * height; + I420ToI411(y, y_stride, + u, u_stride, + v, v_stride, + dst_sample, width, + dst_u, quarterwidth, + dst_v, quarterwidth, + width, height); + break; + } // Formats not supported - MJPG, biplanar, some rgb formats. default: diff --git a/source/rotate_neon.cc b/source/rotate_neon.cc index 449476364..264e81e7e 100644 --- a/source/rotate_neon.cc +++ b/source/rotate_neon.cc @@ -107,7 +107,7 @@ void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { ); } -static const uint8 vtbl_4x4_transpose[16] __attribute__((vector_size(16))) = +static const uvec8 vtbl_4x4_transpose = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 }; void TransposeWx8_NEON(const uint8* src, int src_stride, @@ -346,7 +346,7 @@ void MirrorRowUV_NEON(const uint8* src, ); } -static const uint8 vtbl_4x4_transpose_di[16] __attribute__((vector_size(16))) = +static const uvec8 vtbl_4x4_transpose_di = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 }; void TransposeUVWx8_NEON(const uint8* src, int src_stride, diff --git a/source/row_neon.cc b/source/row_neon.cc index 00bbf729d..e21b4c054 100644 --- a/source/row_neon.cc +++ b/source/row_neon.cc @@ -61,8 +61,10 @@ extern "C" { #if defined(HAS_I420TOARGBROW_NEON) || \ defined(HAS_I420TOBGRAROW_NEON) || \ defined(HAS_I420TOABGRROW_NEON) -static const vec8 kUVToRB[8] = { 127, 127, 127, 127, 102, 102, 102, 102 }; -static const vec8 kUVToG[8] = { -25, -25, -25, -25, -52, -52, -52, -52 }; +static const vec8 kUVToRB = { 127, 127, 127, 127, 102, 102, 102, 102, + 0, 0, 0, 0, 0, 0, 0, 0 }; +static const vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52, + 0, 0, 0, 0, 0, 0, 0, 0 }; #endif #if defined(HAS_I420TOARGBROW_NEON) @@ -84,13 +86,13 @@ YUVTORGB "vst4.u8 {d20, d21, d22, d23}, [%3]! \n" "subs %4, %4, #8 \n" "bhi 1b \n" - : "+r"(y_buf), // %0 - "+r"(u_buf), // %1 - "+r"(v_buf), // %2 - "+r"(rgb_buf), // %3 - "+r"(width) // %4 - : "r"(kUVToRB), - "r"(kUVToG) + : "+r"(y_buf), // %0 + "+r"(u_buf), // %1 + "+r"(v_buf), // %2 + "+r"(rgb_buf), // %3 + "+r"(width) // %4 + : "r"(kUVToRB), // %5 + "r"(kUVToG) // %6 : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); @@ -117,13 +119,13 @@ YUVTORGB "vst4.u8 {d19, d20, d21, d22}, [%3]! \n" "subs %4, %4, #8 \n" "bhi 1b \n" - : "+r"(y_buf), // %0 - "+r"(u_buf), // %1 - "+r"(v_buf), // %2 - "+r"(rgb_buf), // %3 - "+r"(width) // %4 - : "r"(kUVToRB), - "r"(kUVToG) + : "+r"(y_buf), // %0 + "+r"(u_buf), // %1 + "+r"(v_buf), // %2 + "+r"(rgb_buf), // %3 + "+r"(width) // %4 + : "r"(kUVToRB), // %5 + "r"(kUVToG) // %6 : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); @@ -150,13 +152,13 @@ YUVTORGB "vst4.u8 {d20, d21, d22, d23}, [%3]! \n" "subs %4, %4, #8 \n" "bhi 1b \n" - : "+r"(y_buf), // %0 - "+r"(u_buf), // %1 - "+r"(v_buf), // %2 - "+r"(rgb_buf), // %3 - "+r"(width) // %4 - : "r"(kUVToRB), - "r"(kUVToG) + : "+r"(y_buf), // %0 + "+r"(u_buf), // %1 + "+r"(v_buf), // %2 + "+r"(rgb_buf), // %3 + "+r"(width) // %4 + : "r"(kUVToRB), // %5 + "r"(kUVToG) // %6 : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); @@ -174,10 +176,10 @@ void SplitUV_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) { "vst1.u8 {q0}, [%1]! \n" // store U "vst1.u8 {q1}, [%2]! \n" // Store V "bhi 1b \n" - : "+r"(src_uv), - "+r"(dst_u), - "+r"(dst_v), - "+r"(pix) // Output registers + : "+r"(src_uv), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(pix) // %3 // Output registers : // Input registers : "memory", "cc", "q0", "q1" // Clobber List ); @@ -195,10 +197,10 @@ void CopyRow_NEON(const uint8* src, uint8* dst, int count) { "subs %2, %2, #64 \n" // 64 processed per loop "vst1.u8 {q0,q1,q2,q3}, [%1]! \n" // store 64 "bhi 1b \n" - : "+r"(src), - "+r"(dst), - "+r"(count) // Output registers - : // Input registers + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(count) // %2 // Output registers + : // Input registers : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List ); }