From 23e1afb44a1a1b19908fe6646334068780fafbf7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 10 Jan 2018 09:16:59 +0100 Subject: [PATCH] Added new and optimized YUV primitives. * RGBToAVC444YUVv2: Split a RGB frame in luma and/or chroma v2 YUV420 frames * RGBX specific versions of RGBToAVC444YUV and RGBToYUV420_8u_P3AC4R --- include/freerdp/primitives.h | 6 + libfreerdp/primitives/prim_YUV.c | 327 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 333 insertions(+) diff --git a/include/freerdp/primitives.h b/include/freerdp/primitives.h index 022da27..e17598d 100644 --- a/include/freerdp/primitives.h +++ b/include/freerdp/primitives.h @@ -203,6 +203,11 @@ typedef pstatus_t (*__RGBToAVC444YUV_t)( BYTE* pMainDst[3], const UINT32 dstMainStep[3], BYTE* pAuxDst[3], const UINT32 dstAuxStep[3], const prim_size_t* roi); +typedef pstatus_t (*__RGBToAVC444YUVv2_t)( + const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, + BYTE* pMainDst[3], const UINT32 dstMainStep[3], + BYTE* pAuxDst[3], const UINT32 dstAuxStep[3], + const prim_size_t* roi); typedef pstatus_t (*__andC_32u_t)( const UINT32* pSrc, UINT32 val, @@ -254,6 +259,7 @@ typedef struct __YUV444SplitToYUV420_t YUV444SplitToYUV420; __YUV444ToRGB_8u_P3AC4R_t YUV444ToRGB_8u_P3AC4R; __RGBToAVC444YUV_t RGBToAVC444YUV; + __RGBToAVC444YUVv2_t RGBToAVC444YUVv2; } primitives_t; #ifdef __cplusplus diff --git a/libfreerdp/primitives/prim_YUV.c b/libfreerdp/primitives/prim_YUV.c index 1adb18c..28c3d92 100644 --- a/libfreerdp/primitives/prim_YUV.c +++ b/libfreerdp/primitives/prim_YUV.c @@ -726,6 +726,73 @@ static INLINE pstatus_t general_RGBToYUV420_BGRX( return PRIMITIVES_SUCCESS; } +static INLINE pstatus_t general_RGBToYUV420_RGBX( + const BYTE* pSrc, UINT32 srcStep, + BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi) +{ + UINT32 x, y, i; + size_t x1 = 0, x2 = 4, x3 = srcStep, x4 = srcStep + 4; + size_t y1 = 0, y2 = 1, y3 = dstStep[0], y4 = dstStep[0] + 1; + UINT32 max_x = roi->width - 1; + UINT32 max_y = roi->height - 1; + + for (y = i = 0; y < roi->height; y += 2, i++) + { + const BYTE* src = pSrc + y * srcStep; + BYTE* ydst = pDst[0] + y * dstStep[0]; + BYTE* udst = pDst[1] + i * dstStep[1]; + BYTE* vdst = pDst[2] + i * dstStep[2]; + + for (x = 0; x < roi->width; x += 2) + { + BYTE R, G, B; + INT32 Ra, Ga, Ba; + /* row 1, pixel 1 */ + Ra = R = *(src + x1 + 0); + Ga = G = *(src + x1 + 1); + Ba = B = *(src + x1 + 2); + ydst[y1] = RGB2Y(R, G, B); + + if (x < max_x) + { + /* row 1, pixel 2 */ + Ra += R = *(src + x2 + 0); + Ga += G = *(src + x2 + 1); + Ba += B = *(src + x2 + 2); + ydst[y2] = RGB2Y(R, G, B); + } + + if (y < max_y) + { + /* row 2, pixel 1 */ + Ra += R = *(src + x3 + 0); + Ga += G = *(src + x3 + 1); + Ba += B = *(src + x3 + 2); + ydst[y3] = RGB2Y(R, G, B); + + if (x < max_x) + { + /* row 2, pixel 2 */ + Ra += R = *(src + x4 + 0); + Ga += G = *(src + x4 + 1); + Ba += B = *(src + x4 + 2); + ydst[y4] = RGB2Y(R, G, B); + } + } + + Ba >>= 2; + Ga >>= 2; + Ra >>= 2; + *udst++ = RGB2U(Ra, Ga, Ba); + *vdst++ = RGB2V(Ra, Ga, Ba); + ydst += 2; + src += 8; + } + } + + return PRIMITIVES_SUCCESS; +} + static INLINE pstatus_t general_RGBToYUV420_ANY( const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi) @@ -813,6 +880,10 @@ static pstatus_t general_RGBToYUV420_8u_P3AC4R( case PIXEL_FORMAT_BGRX32: return general_RGBToYUV420_BGRX(pSrc, srcStep, pDst, dstStep, roi); + case PIXEL_FORMAT_RGBA32: + case PIXEL_FORMAT_RGBX32: + return general_RGBToYUV420_RGBX(pSrc, srcStep, pDst, dstStep, roi); + default: return general_RGBToYUV420_ANY(pSrc, srcFormat, srcStep, pDst, dstStep, roi); } @@ -906,6 +977,94 @@ static INLINE pstatus_t general_RGBToAVC444YUV_BGRX( return PRIMITIVES_SUCCESS; } +static INLINE pstatus_t general_RGBToAVC444YUV_RGBX( + const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, + BYTE* pDst1[3], const UINT32 dst1Step[3], + BYTE* pDst2[3], const UINT32 dst2Step[3], + const prim_size_t* roi) +{ + /** + * Note: + * Read information in function general_RGBToAVC444YUV_ANY below ! + */ + UINT32 x, y, n, numRows, numCols; + BOOL evenRow = TRUE; + BYTE* b1 = NULL; + BYTE* b2 = NULL; + BYTE* b3 = NULL; + BYTE* b4 = NULL; + BYTE* b5 = NULL; + BYTE* b6 = NULL; + BYTE* b7 = NULL; + const BYTE* pMaxSrc = pSrc + (roi->height - 1) * srcStep; + numRows = (roi->height + 1) & ~1; + numCols = (roi->width + 1) & ~1; + + for (y = 0; y < numRows; y++, evenRow = !evenRow) + { + const BYTE* src = y < roi->height ? pSrc + y * srcStep : pMaxSrc; + UINT32 i = y >> 1; + b1 = pDst1[0] + y * dst1Step[0]; + + if (evenRow) + { + b2 = pDst1[1] + i * dst1Step[1]; + b3 = pDst1[2] + i * dst1Step[2]; + b6 = pDst2[1] + i * dst2Step[1]; + b7 = pDst2[2] + i * dst2Step[2]; + } + else + { + n = (i & ~7) + i; + b4 = pDst2[0] + dst2Step[0] * n; + b5 = b4 + 8 * dst2Step[0]; + } + + for (x = 0; x < numCols; x += 2) + { + BYTE R, G, B, Y1, Y2, U1, U2, V1, V2; + R = src[0]; + G = src[1]; + B = src[2]; + Y1 = Y2 = RGB2Y(R, G, B); + U1 = U2 = RGB2U(R, G, B); + V1 = V2 = RGB2V(R, G, B); + + if (x + 1 < roi->width) + { + R = src[4]; + G = src[5]; + B = src[6]; + Y2 = RGB2Y(R, G, B); + U2 = RGB2U(R, G, B); + V2 = RGB2V(R, G, B); + } + + *b1++ = Y1; + *b1++ = Y2; + + if (evenRow) + { + *b2++ = U1; + *b3++ = V1; + *b6++ = U2; + *b7++ = V2; + } + else + { + *b4++ = U1; + *b4++ = U2; + *b5++ = V1; + *b5++ = V2; + } + + src += 8; + } + } + + return PRIMITIVES_SUCCESS; +} + static INLINE pstatus_t general_RGBToAVC444YUV_ANY( const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, BYTE* pDst1[3], const UINT32 dst1Step[3], @@ -1058,6 +1217,10 @@ static INLINE pstatus_t general_RGBToAVC444YUV( case PIXEL_FORMAT_BGRX32: return general_RGBToAVC444YUV_BGRX(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2, dst2Step, roi); + case PIXEL_FORMAT_RGBA32: + case PIXEL_FORMAT_RGBX32: + return general_RGBToAVC444YUV_RGBX(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2, dst2Step, roi); + default: return general_RGBToAVC444YUV_ANY(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2, dst2Step, roi); } @@ -1065,6 +1228,169 @@ static INLINE pstatus_t general_RGBToAVC444YUV( return !PRIMITIVES_SUCCESS; } +static INLINE pstatus_t general_RGBToAVC444YUVv2_ANY( + const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, + BYTE* pDst1[3], const UINT32 dst1Step[3], + BYTE* pDst2[3], const UINT32 dst2Step[3], + const prim_size_t* roi) +{ + /** + * Note: According to [MS-RDPEGFX 2.2.4.4 RFX_AVC420_BITMAP_STREAM] the + * width and height of the MPEG-4 AVC/H.264 codec bitstream MUST be aligned + * to a multiple of 16. + * Hence the passed destination YUV420/CHROMA420 buffers must have been + * allocated accordingly !! + */ + /** + * [MS-RDPEGFX 3.3.8.3.3 YUV420p Stream Combination for YUV444v2 mode] defines the following "Bx areas": + * + * YUV420 frame (main view): + * B1: From Y444 all pixels + * B2: From U444 all pixels in even rows with even rows and columns + * B3: From V444 all pixels in even rows with even rows and columns + * + * Chroma420 frame (auxillary view): + * B45: From U444 and V444 all pixels from all odd columns + * B67: From U444 and V444 every 4th pixel in odd rows + * B89: From U444 and V444 every 4th pixel (initial offset of 2) in odd rows + * + * Chroma Bxy areas correspond to the left and right half of the YUV420 plane. + * for (y = 0; y < fullHeight; y++) + * { + * for (x = 0; x < fullWidth; x++) + * { + * B1[x,y] = Y444[x,y]; + * } + * + * for (x = 0; x < halfWidth; x++) + * { + * B4[x,y] = U444[2 * x, 2 * y]; + * B5[x,y] = V444[2 * x, 2 * y]; + * } + * } + * + * for (y = 0; y < halfHeight; y++) + * { + * for (x = 0; x < halfWidth; x++) + * { + * B2[x,y] = U444[2 * x, 2 * y]; + * B3[x,y] = V444[2 * x, 2 * y]; + * B6[x,y] = U444[4 * x, 2 * y + 1]; + * B7[x,y] = V444[4 * x, 2 * y + 1]; + * B8[x,y] = V444[4 * x + 2, 2 * y + 1]; + * B9[x,y] = V444[4 * x + 2, 2 * y] + 1; + * } + * } + * + */ + UINT32 x, y; + + for (y = 0; y < roi->height; y++) + { + const BYTE* src = pSrc + y * srcStep; + BYTE* b1 = pDst1 ? (pDst1[0] + y * dst1Step[0]) : NULL; + BYTE* b4 = pDst2 ? (pDst2[0] + y * dst2Step[0]) : NULL; + BYTE* b5 = pDst2 ? (pDst2[0] + y * dst2Step[0] + dst2Step[0] / 2) : NULL; + + for (x = 0; x < roi->width; x++) + { + const UINT32 color = ReadColor(src, srcFormat); + BYTE r, g, b; + SplitColor(color, srcFormat, &r, &g, &b, NULL, NULL); + src += 4; + + if (b1) + { + const BYTE y = RGB2Y(r, g, b); + *b1++ = y; + } + + if (b4 && b5 && ((x & 1) == 1)) + { + const BYTE u = RGB2U(r, g, b); + const BYTE v = RGB2V(r, g, b); + *b4++ = u; + *b5++ = v; + } + } + } + + if (pDst1) + { + for (y = 0; y < roi->height / 2; y++) + { + const BYTE* src = pSrc + (2 * y) * srcStep; + BYTE* b2 = pDst1[1] + 2 * y * dst1Step[1]; + BYTE* b3 = pDst1[2] + 2 * y * dst1Step[2]; + + for (x = 0; x < roi->width / 2; x++) + { + const UINT32 color = ReadColor(src, srcFormat); + BYTE r, g, b; + SplitColor(color, srcFormat, &r, &g, &b, NULL, NULL); + src += 8; + { + const BYTE u = RGB2U(r, g, b); + const BYTE v = RGB2V(r, g, b); + *b2++ = u; + *b3++ = v; + } + } + } + } + + if (pDst2) + { + for (y = 0; y < roi->height / 2; y++) + { + const BYTE* src = pSrc + (2 * y + 1) * srcStep; + BYTE* b6 = pDst2[1] + y * dst2Step[1]; + BYTE* b7 = pDst2[1] + y * dst2Step[1] + dst2Step[1] / 2; + BYTE* b8 = pDst2[2] + y * dst2Step[2]; + BYTE* b9 = pDst2[2] + y * dst2Step[2] + dst2Step[2] / 2; + + for (x = 0; x < roi->width / 2; x++) + { + const UINT32 color = ReadColor(src, srcFormat); + BYTE r, g, b, u, v; + SplitColor(color, srcFormat, &r, &g, &b, NULL, NULL); + src += 8; + u = RGB2U(r, g, b); + v = RGB2V(r, g, b); + + if (x & 1) + { + *b8++ = u; + *b9++ = v; + } + else + { + *b6++ = u; + *b7++ = v; + } + } + } + } + + return PRIMITIVES_SUCCESS; +} + +static INLINE pstatus_t general_RGBToAVC444YUVv2( + const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, + BYTE* pDst1[3], const UINT32 dst1Step[3], + BYTE* pDst2[3], const UINT32 dst2Step[3], + const prim_size_t* roi) +{ + switch (srcFormat) + { + default: + return general_RGBToAVC444YUVv2_ANY(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2, dst2Step, + roi); + } + + return !PRIMITIVES_SUCCESS; +} + void primitives_init_YUV(primitives_t* prims) { prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R; @@ -1074,5 +1400,6 @@ void primitives_init_YUV(primitives_t* prims) prims->YUV420CombineToYUV444 = general_YUV420CombineToYUV444; prims->YUV444SplitToYUV420 = general_YUV444SplitToYUV420; prims->RGBToAVC444YUV = general_RGBToAVC444YUV; + prims->RGBToAVC444YUVv2 = general_RGBToAVC444YUVv2; } -- 2.7.4