From ef1ee362b36893cd1cc1e9c7de378e9cb239b0e8 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Wed, 29 Jun 2011 09:39:43 -0700 Subject: swscale: implement >8bit scaling support. This means that precision is retained when scaling between sample formats with >8 bits per component (48bit RGB, 16bit grayscale, 9/10/16bit YUV). --- libswscale/ppc/swscale_altivec.c | 4 +- libswscale/swscale.c | 694 +++++++++++++++++++++++++------------- libswscale/swscale_internal.h | 10 + libswscale/utils.c | 9 +- libswscale/x86/swscale_template.c | 73 +--- 5 files changed, 481 insertions(+), 309 deletions(-) (limited to 'libswscale') diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c index 396b00ccc6..6fb3de0ee7 100644 --- a/libswscale/ppc/swscale_altivec.c +++ b/libswscale/ppc/swscale_altivec.c @@ -406,7 +406,9 @@ void ff_sws_init_swScale_altivec(SwsContext *c) if (!(av_get_cpu_flags() & AV_CPU_FLAG_ALTIVEC)) return; - c->hScale = hScale_altivec_real; + if (c->scalingBpp == 8) { + c->hScale = hScale_altivec_real; + } if (!is16BPS(dstFormat) && !is9_OR_10BPS(dstFormat) && dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21 && !c->alpPixBuf) { diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 64ba97e7d4..987afff2d2 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -195,18 +195,18 @@ DECLARE_ALIGNED(8, const uint8_t, dither_8x8_220)[8][8]={ #endif static av_always_inline void -yuv2yuvX16_c_template(const int16_t *lumFilter, const int16_t **lumSrc, +yuv2yuvX16_c_template(const int16_t *lumFilter, const int32_t **lumSrc, int lumFilterSize, const int16_t *chrFilter, - const int16_t **chrUSrc, const int16_t **chrVSrc, - int chrFilterSize, const int16_t **alpSrc, + const int32_t **chrUSrc, const int32_t **chrVSrc, + int chrFilterSize, const int32_t **alpSrc, uint16_t *dest[4], int dstW, int chrDstW, int big_endian, int output_bits) { //FIXME Optimize (just quickly written not optimized..) int i; - int shift = 11 + 16 - output_bits; uint16_t *yDest = dest[0], *uDest = dest[1], *vDest = dest[2], *aDest = CONFIG_SWSCALE_ALPHA ? dest[3] : NULL; + int shift = 15 + 16 - output_bits; #define output_pixel(pos, val) \ if (big_endian) { \ @@ -223,7 +223,7 @@ yuv2yuvX16_c_template(const int16_t *lumFilter, const int16_t **lumSrc, } \ } for (i = 0; i < dstW; i++) { - int val = 1 << (26-output_bits); + int val = 1 << (30-output_bits); int j; for (j = 0; j < lumFilterSize; j++) @@ -234,8 +234,8 @@ yuv2yuvX16_c_template(const int16_t *lumFilter, const int16_t **lumSrc, if (uDest) { for (i = 0; i < chrDstW; i++) { - int u = 1 << (26-output_bits); - int v = 1 << (26-output_bits); + int u = 1 << (30-output_bits); + int v = 1 << (30-output_bits); int j; for (j = 0; j < chrFilterSize; j++) { @@ -250,7 +250,7 @@ yuv2yuvX16_c_template(const int16_t *lumFilter, const int16_t **lumSrc, if (CONFIG_SWSCALE_ALPHA && aDest) { for (i = 0; i < dstW; i++) { - int val = 1 << (26-output_bits); + int val = 1 << (30-output_bits); int j; for (j = 0; j < lumFilterSize; j++) @@ -264,12 +264,16 @@ yuv2yuvX16_c_template(const int16_t *lumFilter, const int16_t **lumSrc, #define yuv2NBPS(bits, BE_LE, is_be) \ static void yuv2yuvX ## bits ## BE_LE ## _c(SwsContext *c, const int16_t *lumFilter, \ - const int16_t **lumSrc, int lumFilterSize, \ - const int16_t *chrFilter, const int16_t **chrUSrc, \ - const int16_t **chrVSrc, \ - int chrFilterSize, const int16_t **alpSrc, \ + const int16_t **_lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **_chrUSrc, \ + const int16_t **_chrVSrc, \ + int chrFilterSize, const int16_t **_alpSrc, \ uint8_t *_dest[4], int dstW, int chrDstW) \ { \ + const int32_t **lumSrc = (const int32_t **) _lumSrc, \ + **chrUSrc = (const int32_t **) _chrUSrc, \ + **chrVSrc = (const int32_t **) _chrVSrc, \ + **alpSrc = (const int32_t **) _alpSrc; \ yuv2yuvX16_c_template(lumFilter, lumSrc, lumFilterSize, \ chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ alpSrc, (uint16_t **) _dest, \ @@ -418,109 +422,121 @@ static void yuv2nv12X_c(SwsContext *c, const int16_t *lumFilter, static av_always_inline void yuv2gray16_X_c_template(SwsContext *c, const int16_t *lumFilter, - const int16_t **lumSrc, int lumFilterSize, - const int16_t *chrFilter, const int16_t **chrUSrc, - const int16_t **chrVSrc, int chrFilterSize, - const int16_t **alpSrc, uint8_t *dest, int dstW, + const int32_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int32_t **chrUSrc, + const int32_t **chrVSrc, int chrFilterSize, + const int32_t **alpSrc, uint16_t *dest, int dstW, int y, enum PixelFormat target) { int i; for (i = 0; i < (dstW >> 1); i++) { int j; - int Y1 = 1 << 18; - int Y2 = 1 << 18; - const int i2 = 2 * i; + int Y1 = 1 << 14; + int Y2 = 1 << 14; for (j = 0; j < lumFilterSize; j++) { - Y1 += lumSrc[j][i2] * lumFilter[j]; - Y2 += lumSrc[j][i2+1] * lumFilter[j]; + Y1 += lumSrc[j][i * 2] * lumFilter[j]; + Y2 += lumSrc[j][i * 2 + 1] * lumFilter[j]; } - Y1 >>= 11; - Y2 >>= 11; + Y1 >>= 15; + Y2 >>= 15; if ((Y1 | Y2) & 0x10000) { Y1 = av_clip_uint16(Y1); Y2 = av_clip_uint16(Y2); } - output_pixel(&dest[2 * i2 + 0], Y1); - output_pixel(&dest[2 * i2 + 2], Y2); + output_pixel(&dest[i * 2 + 0], Y1); + output_pixel(&dest[i * 2 + 1], Y2); } } static av_always_inline void -yuv2gray16_2_c_template(SwsContext *c, const int16_t *buf[2], - const int16_t *ubuf[2], const int16_t *vbuf[2], - const int16_t *abuf[2], uint8_t *dest, int dstW, +yuv2gray16_2_c_template(SwsContext *c, const int32_t *buf[2], + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf[2], uint16_t *dest, int dstW, int yalpha, int uvalpha, int y, enum PixelFormat target) { int yalpha1 = 4095 - yalpha; int i; - const int16_t *buf0 = buf[0], *buf1 = buf[1]; + const int32_t *buf0 = buf[0], *buf1 = buf[1]; for (i = 0; i < (dstW >> 1); i++) { - const int i2 = 2 * i; - int Y1 = (buf0[i2 ] * yalpha1 + buf1[i2 ] * yalpha) >> 11; - int Y2 = (buf0[i2+1] * yalpha1 + buf1[i2+1] * yalpha) >> 11; + int Y1 = (buf0[i * 2 ] * yalpha1 + buf1[i * 2 ] * yalpha) >> 15; + int Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 15; - output_pixel(&dest[2 * i2 + 0], Y1); - output_pixel(&dest[2 * i2 + 2], Y2); + output_pixel(&dest[i * 2 + 0], Y1); + output_pixel(&dest[i * 2 + 1], Y2); } } static av_always_inline void -yuv2gray16_1_c_template(SwsContext *c, const int16_t *buf0, - const int16_t *ubuf[2], const int16_t *vbuf[2], - const int16_t *abuf0, uint8_t *dest, int dstW, +yuv2gray16_1_c_template(SwsContext *c, const int32_t *buf0, + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf0, uint16_t *dest, int dstW, int uvalpha, int y, enum PixelFormat target) { int i; for (i = 0; i < (dstW >> 1); i++) { - const int i2 = 2 * i; - int Y1 = buf0[i2 ] << 1; - int Y2 = buf0[i2+1] << 1; + int Y1 = buf0[i * 2 ] << 1; + int Y2 = buf0[i * 2 + 1] << 1; - output_pixel(&dest[2 * i2 + 0], Y1); - output_pixel(&dest[2 * i2 + 2], Y2); + output_pixel(&dest[i * 2 + 0], Y1); + output_pixel(&dest[i * 2 + 1], Y2); } } #undef output_pixel -#define YUV2PACKEDWRAPPER(name, base, ext, fmt) \ +#define YUV2PACKED16WRAPPER(name, base, ext, fmt) \ static void name ## ext ## _X_c(SwsContext *c, const int16_t *lumFilter, \ - const int16_t **lumSrc, int lumFilterSize, \ - const int16_t *chrFilter, const int16_t **chrUSrc, \ - const int16_t **chrVSrc, int chrFilterSize, \ - const int16_t **alpSrc, uint8_t *dest, int dstW, \ + const int16_t **_lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **_chrUSrc, \ + const int16_t **_chrVSrc, int chrFilterSize, \ + const int16_t **_alpSrc, uint8_t *_dest, int dstW, \ int y) \ { \ + const int32_t **lumSrc = (const int32_t **) _lumSrc, \ + **chrUSrc = (const int32_t **) _chrUSrc, \ + **chrVSrc = (const int32_t **) _chrVSrc, \ + **alpSrc = (const int32_t **) _alpSrc; \ + uint16_t *dest = (uint16_t *) _dest; \ name ## base ## _X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ alpSrc, dest, dstW, y, fmt); \ } \ \ -static void name ## ext ## _2_c(SwsContext *c, const int16_t *buf[2], \ - const int16_t *ubuf[2], const int16_t *vbuf[2], \ - const int16_t *abuf[2], uint8_t *dest, int dstW, \ +static void name ## ext ## _2_c(SwsContext *c, const int16_t *_buf[2], \ + const int16_t *_ubuf[2], const int16_t *_vbuf[2], \ + const int16_t *_abuf[2], uint8_t *_dest, int dstW, \ int yalpha, int uvalpha, int y) \ { \ + const int32_t **buf = (const int32_t **) _buf, \ + **ubuf = (const int32_t **) _ubuf, \ + **vbuf = (const int32_t **) _vbuf, \ + **abuf = (const int32_t **) _abuf; \ + uint16_t *dest = (uint16_t *) _dest; \ name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \ dest, dstW, yalpha, uvalpha, y, fmt); \ } \ \ -static void name ## ext ## _1_c(SwsContext *c, const int16_t *buf0, \ - const int16_t *ubuf[2], const int16_t *vbuf[2], \ - const int16_t *abuf0, uint8_t *dest, int dstW, \ +static void name ## ext ## _1_c(SwsContext *c, const int16_t *_buf0, \ + const int16_t *_ubuf[2], const int16_t *_vbuf[2], \ + const int16_t *_abuf0, uint8_t *_dest, int dstW, \ int uvalpha, int y) \ { \ + const int32_t *buf0 = (const int32_t *) _buf0, \ + **ubuf = (const int32_t **) _ubuf, \ + **vbuf = (const int32_t **) _vbuf, \ + *abuf0 = (const int32_t *) _abuf0; \ + uint16_t *dest = (uint16_t *) _dest; \ name ## base ## _1_c_template(c, buf0, ubuf, vbuf, abuf0, dest, \ dstW, uvalpha, y, fmt); \ } -YUV2PACKEDWRAPPER(yuv2gray16,, LE, PIX_FMT_GRAY16LE); -YUV2PACKEDWRAPPER(yuv2gray16,, BE, PIX_FMT_GRAY16BE); +YUV2PACKED16WRAPPER(yuv2gray16,, LE, PIX_FMT_GRAY16LE); +YUV2PACKED16WRAPPER(yuv2gray16,, BE, PIX_FMT_GRAY16BE); #define output_pixel(pos, acc) \ if (target == PIX_FMT_MONOBLACK) { \ @@ -616,6 +632,38 @@ yuv2mono_1_c_template(SwsContext *c, const int16_t *buf0, #undef output_pixel +#define YUV2PACKEDWRAPPER(name, base, ext, fmt) \ +static void name ## ext ## _X_c(SwsContext *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + name ## base ## _X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt); \ +} \ + \ +static void name ## ext ## _2_c(SwsContext *c, const int16_t *buf[2], \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf[2], uint8_t *dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt); \ +} \ + \ +static void name ## ext ## _1_c(SwsContext *c, const int16_t *buf0, \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf0, uint8_t *dest, int dstW, \ + int uvalpha, int y) \ +{ \ + name ## base ## _1_c_template(c, buf0, ubuf, vbuf, \ + abuf0, dest, dstW, uvalpha, \ + y, fmt); \ +} + YUV2PACKEDWRAPPER(yuv2mono,, white, PIX_FMT_MONOWHITE); YUV2PACKEDWRAPPER(yuv2mono,, black, PIX_FMT_MONOBLACK); @@ -731,26 +779,32 @@ yuv2422_1_c_template(SwsContext *c, const int16_t *buf0, YUV2PACKEDWRAPPER(yuv2, 422, yuyv422, PIX_FMT_YUYV422); YUV2PACKEDWRAPPER(yuv2, 422, uyvy422, PIX_FMT_UYVY422); -#define r_b ((target == PIX_FMT_RGB48LE || target == PIX_FMT_RGB48BE) ? r : b) -#define b_r ((target == PIX_FMT_RGB48LE || target == PIX_FMT_RGB48BE) ? b : r) +#define R_B ((target == PIX_FMT_RGB48LE || target == PIX_FMT_RGB48BE) ? R : B) +#define B_R ((target == PIX_FMT_RGB48LE || target == PIX_FMT_RGB48BE) ? B : R) +#define output_pixel(pos, val) \ + if (isBE(target)) { \ + AV_WB16(pos, val); \ + } else { \ + AV_WL16(pos, val); \ + } static av_always_inline void yuv2rgb48_X_c_template(SwsContext *c, const int16_t *lumFilter, - const int16_t **lumSrc, int lumFilterSize, - const int16_t *chrFilter, const int16_t **chrUSrc, - const int16_t **chrVSrc, int chrFilterSize, - const int16_t **alpSrc, uint8_t *dest, int dstW, + const int32_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int32_t **chrUSrc, + const int32_t **chrVSrc, int chrFilterSize, + const int32_t **alpSrc, uint16_t *dest, int dstW, int y, enum PixelFormat target) { int i; for (i = 0; i < (dstW >> 1); i++) { int j; - int Y1 = 1 << 18; - int Y2 = 1 << 18; - int U = 1 << 18; - int V = 1 << 18; - const uint8_t *r, *g, *b; + int Y1 = 0; + int Y2 = 0; + int U = -128 << 23; // 19 + int V = -128 << 23; + int R, G, B; for (j = 0; j < lumFilterSize; j++) { Y1 += lumSrc[j][i * 2] * lumFilter[j]; @@ -760,40 +814,45 @@ yuv2rgb48_X_c_template(SwsContext *c, const int16_t *lumFilter, U += chrUSrc[j][i] * chrFilter[j]; V += chrVSrc[j][i] * chrFilter[j]; } - Y1 >>= 19; - Y2 >>= 19; - U >>= 19; - V >>= 19; - if ((Y1 | Y2 | U | V) & 0x100) { - Y1 = av_clip_uint8(Y1); - Y2 = av_clip_uint8(Y2); - U = av_clip_uint8(U); - V = av_clip_uint8(V); - } - /* FIXME fix tables so that clipping is not needed and then use _NOCLIP*/ - r = (const uint8_t *) c->table_rV[V]; - g = (const uint8_t *)(c->table_gU[U] + c->table_gV[V]); - b = (const uint8_t *) c->table_bU[U]; + // 8bit: 12+15=27; 16-bit: 12+19=31 + Y1 >>= 14; // 10 + Y2 >>= 14; + U >>= 14; + V >>= 14; + + // 8bit: 27 -> 17bit, 16bit: 31 - 14 = 17bit + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += 1 << 13; // 21 + Y2 += 1 << 13; + // 8bit: 17 + 13bit = 30bit, 16bit: 17 + 13bit = 30bit + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; - dest[ 0] = dest[ 1] = r_b[Y1]; - dest[ 2] = dest[ 3] = g[Y1]; - dest[ 4] = dest[ 5] = b_r[Y1]; - dest[ 6] = dest[ 7] = r_b[Y2]; - dest[ 8] = dest[ 9] = g[Y2]; - dest[10] = dest[11] = b_r[Y2]; - dest += 12; + // 8bit: 30 - 22 = 8bit, 16bit: 30bit - 14 = 16bit + output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14); + output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14); + output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14); + output_pixel(&dest[3], av_clip_uintp2(R_B + Y2, 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2( G + Y2, 30) >> 14); + output_pixel(&dest[5], av_clip_uintp2(B_R + Y2, 30) >> 14); + dest += 6; } } static av_always_inline void -yuv2rgb48_2_c_template(SwsContext *c, const int16_t *buf[2], - const int16_t *ubuf[2], const int16_t *vbuf[2], - const int16_t *abuf[2], uint8_t *dest, int dstW, +yuv2rgb48_2_c_template(SwsContext *c, const int32_t *buf[2], + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf[2], uint16_t *dest, int dstW, int yalpha, int uvalpha, int y, enum PixelFormat target) { - const int16_t *buf0 = buf[0], *buf1 = buf[1], + const int32_t *buf0 = buf[0], *buf1 = buf[1], *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], *vbuf0 = vbuf[0], *vbuf1 = vbuf[1]; int yalpha1 = 4095 - yalpha; @@ -801,80 +860,108 @@ yuv2rgb48_2_c_template(SwsContext *c, const int16_t *buf[2], int i; for (i = 0; i < (dstW >> 1); i++) { - int Y1 = (buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 19; - int Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 19; - int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19; - int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19; - const uint8_t *r = (const uint8_t *) c->table_rV[V], - *g = (const uint8_t *)(c->table_gU[U] + c->table_gV[V]), - *b = (const uint8_t *) c->table_bU[U]; + int Y1 = (buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 14; + int Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 14; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha + (-128 << 23)) >> 14; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha + (-128 << 23)) >> 14; + int R, G, B; - dest[ 0] = dest[ 1] = r_b[Y1]; - dest[ 2] = dest[ 3] = g[Y1]; - dest[ 4] = dest[ 5] = b_r[Y1]; - dest[ 6] = dest[ 7] = r_b[Y2]; - dest[ 8] = dest[ 9] = g[Y2]; - dest[10] = dest[11] = b_r[Y2]; - dest += 12; + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += 1 << 13; + Y2 += 1 << 13; + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14); + output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14); + output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14); + output_pixel(&dest[3], av_clip_uintp2(R_B + Y2, 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2( G + Y2, 30) >> 14); + output_pixel(&dest[5], av_clip_uintp2(B_R + Y2, 30) >> 14); + dest += 6; } } static av_always_inline void -yuv2rgb48_1_c_template(SwsContext *c, const int16_t *buf0, - const int16_t *ubuf[2], const int16_t *vbuf[2], - const int16_t *abuf0, uint8_t *dest, int dstW, +yuv2rgb48_1_c_template(SwsContext *c, const int32_t *buf0, + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf0, uint16_t *dest, int dstW, int uvalpha, int y, enum PixelFormat target) { - const int16_t *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + const int32_t *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], *vbuf0 = vbuf[0], *vbuf1 = vbuf[1]; int i; if (uvalpha < 2048) { for (i = 0; i < (dstW >> 1); i++) { - int Y1 = buf0[i * 2] >> 7; - int Y2 = buf0[i * 2 + 1] >> 7; - int U = ubuf1[i] >> 7; - int V = vbuf1[i] >> 7; - const uint8_t *r = (const uint8_t *) c->table_rV[V], - *g = (const uint8_t *)(c->table_gU[U] + c->table_gV[V]), - *b = (const uint8_t *) c->table_bU[U]; - - dest[ 0] = dest[ 1] = r_b[Y1]; - dest[ 2] = dest[ 3] = g[Y1]; - dest[ 4] = dest[ 5] = b_r[Y1]; - dest[ 6] = dest[ 7] = r_b[Y2]; - dest[ 8] = dest[ 9] = g[Y2]; - dest[10] = dest[11] = b_r[Y2]; - dest += 12; + int Y1 = (buf0[i * 2] ) >> 2; + int Y2 = (buf0[i * 2 + 1]) >> 2; + int U = (ubuf0[i] + (-128 << 11)) >> 2; + int V = (vbuf0[i] + (-128 << 11)) >> 2; + int R, G, B; + + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += 1 << 13; + Y2 += 1 << 13; + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14); + output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14); + output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14); + output_pixel(&dest[3], av_clip_uintp2(R_B + Y2, 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2( G + Y2, 30) >> 14); + output_pixel(&dest[5], av_clip_uintp2(B_R + Y2, 30) >> 14); + dest += 6; } } else { for (i = 0; i < (dstW >> 1); i++) { - int Y1 = buf0[i * 2] >> 7; - int Y2 = buf0[i * 2 + 1] >> 7; - int U = (ubuf0[i] + ubuf1[i]) >> 8; - int V = (vbuf0[i] + vbuf1[i]) >> 8; - const uint8_t *r = (const uint8_t *) c->table_rV[V], - *g = (const uint8_t *)(c->table_gU[U] + c->table_gV[V]), - *b = (const uint8_t *) c->table_bU[U]; - - dest[ 0] = dest[ 1] = r_b[Y1]; - dest[ 2] = dest[ 3] = g[Y1]; - dest[ 4] = dest[ 5] = b_r[Y1]; - dest[ 6] = dest[ 7] = r_b[Y2]; - dest[ 8] = dest[ 9] = g[Y2]; - dest[10] = dest[11] = b_r[Y2]; - dest += 12; + int Y1 = (buf0[i * 2] ) >> 2; + int Y2 = (buf0[i * 2 + 1]) >> 2; + int U = (ubuf0[i] + ubuf1[i] + (-128 << 11)) >> 3; + int V = (vbuf0[i] + vbuf1[i] + (-128 << 11)) >> 3; + int R, G, B; + + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += 1 << 13; + Y2 += 1 << 13; + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14); + output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14); + output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14); + output_pixel(&dest[3], av_clip_uintp2(R_B + Y2, 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2( G + Y2, 30) >> 14); + output_pixel(&dest[5], av_clip_uintp2(B_R + Y2, 30) >> 14); + dest += 6; } } } +#undef output_pixel #undef r_b #undef b_r -YUV2PACKEDWRAPPER(yuv2, rgb48, rgb48be, PIX_FMT_RGB48BE); -//YUV2PACKEDWRAPPER(yuv2, rgb48, rgb48le, PIX_FMT_RGB48LE); -YUV2PACKEDWRAPPER(yuv2, rgb48, bgr48be, PIX_FMT_BGR48BE); -//YUV2PACKEDWRAPPER(yuv2, rgb48, bgr48le, PIX_FMT_BGR48LE); +YUV2PACKED16WRAPPER(yuv2, rgb48, rgb48be, PIX_FMT_RGB48BE); +YUV2PACKED16WRAPPER(yuv2, rgb48, rgb48le, PIX_FMT_RGB48LE); +YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48be, PIX_FMT_BGR48BE); +YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48le, PIX_FMT_BGR48LE); static av_always_inline void yuv2rgb_write(uint8_t *_dest, int i, int Y1, int Y2, @@ -1025,7 +1112,7 @@ yuv2rgb_X_c_template(SwsContext *c, const int16_t *lumFilter, U = av_clip_uint8(U); V = av_clip_uint8(V); } - if (hasAlpha) {\ + if (hasAlpha) { A1 = 1 << 18; A2 = 1 << 18; for (j = 0; j < lumFilterSize; j++) { @@ -1318,50 +1405,50 @@ static av_always_inline void fillPlane(uint8_t* plane, int stride, #define b ((origin == PIX_FMT_BGR48BE || origin == PIX_FMT_BGR48LE) ? r_b : b_r) static av_always_inline void -rgb48ToY_c_template(uint8_t *dst, const uint8_t *src, int width, +rgb48ToY_c_template(uint16_t *dst, const uint16_t *src, int width, enum PixelFormat origin) { int i; for (i = 0; i < width; i++) { - int r_b = input_pixel(&src[i*6+0]) >> 8; - int g = input_pixel(&src[i*6+2]) >> 8; - int b_r = input_pixel(&src[i*6+4]) >> 8; + unsigned int r_b = input_pixel(&src[i*3+0]); + unsigned int g = input_pixel(&src[i*3+1]); + unsigned int b_r = input_pixel(&src[i*3+2]); - dst[i] = (RY*r + GY*g + BY*b + (33<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dst[i] = (RY*r + GY*g + BY*b + (0x2001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; } } static av_always_inline void -rgb48ToUV_c_template(uint8_t *dstU, uint8_t *dstV, - const uint8_t *src1, const uint8_t *src2, +rgb48ToUV_c_template(uint16_t *dstU, uint16_t *dstV, + const uint16_t *src1, const uint16_t *src2, int width, enum PixelFormat origin) { int i; assert(src1==src2); for (i = 0; i < width; i++) { - int r_b = input_pixel(&src1[i*6+0]) >> 8; - int g = input_pixel(&src1[i*6+2]) >> 8; - int b_r = input_pixel(&src1[i*6+4]) >> 8; + int r_b = input_pixel(&src1[i*3+0]); + int g = input_pixel(&src1[i*3+1]); + int b_r = input_pixel(&src1[i*3+2]); - dstU[i] = (RU*r + GU*g + BU*b + (257<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; - dstV[i] = (RV*r + GV*g + BV*b + (257<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstU[i] = (RU*r + GU*g + BU*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i] = (RV*r + GV*g + BV*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; } } static av_always_inline void -rgb48ToUV_half_c_template(uint8_t *dstU, uint8_t *dstV, - const uint8_t *src1, const uint8_t *src2, +rgb48ToUV_half_c_template(uint16_t *dstU, uint16_t *dstV, + const uint16_t *src1, const uint16_t *src2, int width, enum PixelFormat origin) { int i; assert(src1==src2); for (i = 0; i < width; i++) { - int r_b = (input_pixel(&src1[12*i + 0]) >> 8) + (input_pixel(&src1[12*i + 6]) >> 8); - int g = (input_pixel(&src1[12*i + 2]) >> 8) + (input_pixel(&src1[12*i + 8]) >> 8); - int b_r = (input_pixel(&src1[12*i + 4]) >> 8) + (input_pixel(&src1[12*i + 10]) >> 8); + int r_b = (input_pixel(&src1[6 * i + 0]) + input_pixel(&src1[6 * i + 3]) + 1) >> 1; + int g = (input_pixel(&src1[6 * i + 1]) + input_pixel(&src1[6 * i + 4]) + 1) >> 1; + int b_r = (input_pixel(&src1[6 * i + 2]) + input_pixel(&src1[6 * i + 5]) + 1) >> 1; - dstU[i]= (RU*r + GU*g + BU*b + (257<> (RGB2YUV_SHIFT+1); - dstV[i]= (RV*r + GV*g + BV*b + (257<> (RGB2YUV_SHIFT+1); + dstU[i]= (RU*r + GU*g + BU*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i]= (RV*r + GV*g + BV*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; } } @@ -1370,23 +1457,31 @@ rgb48ToUV_half_c_template(uint8_t *dstU, uint8_t *dstV, #undef input_pixel #define rgb48funcs(pattern, BE_LE, origin) \ -static void pattern ## 48 ## BE_LE ## ToY_c(uint8_t *dst, const uint8_t *src, \ +static void pattern ## 48 ## BE_LE ## ToY_c(uint8_t *_dst, const uint8_t *_src, \ int width, uint32_t *unused) \ { \ + const uint16_t *src = (const uint16_t *) _src; \ + uint16_t *dst = (uint16_t *) _dst; \ rgb48ToY_c_template(dst, src, width, origin); \ } \ \ -static void pattern ## 48 ## BE_LE ## ToUV_c(uint8_t *dstU, uint8_t *dstV, \ - const uint8_t *src1, const uint8_t *src2, \ +static void pattern ## 48 ## BE_LE ## ToUV_c(uint8_t *_dstU, uint8_t *_dstV, \ + const uint8_t *_src1, const uint8_t *_src2, \ int width, uint32_t *unused) \ { \ + const uint16_t *src1 = (const uint16_t *) _src1, \ + *src2 = (const uint16_t *) _src2; \ + uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \ rgb48ToUV_c_template(dstU, dstV, src1, src2, width, origin); \ } \ \ -static void pattern ## 48 ## BE_LE ## ToUV_half_c(uint8_t *dstU, uint8_t *dstV, \ - const uint8_t *src1, const uint8_t *src2, \ +static void pattern ## 48 ## BE_LE ## ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, \ + const uint8_t *_src1, const uint8_t *_src2, \ int width, uint32_t *unused) \ { \ + const uint16_t *src1 = (const uint16_t *) _src1, \ + *src2 = (const uint16_t *) _src2; \ + uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \ rgb48ToUV_half_c_template(dstU, dstV, src1, src2, width, origin); \ } @@ -1601,13 +1696,26 @@ static void yuy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, assert(src1 == src2); } -static void LEToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, - const uint8_t *src2, int width, uint32_t *unused) +static void bswap16Y_c(uint8_t *_dst, const uint8_t *_src, int width, uint32_t *unused) { int i; + const uint16_t *src = (const uint16_t *) _src; + uint16_t *dst = (uint16_t *) _dst; for (i=0; i> (depth - 8); - dstV[i] = input_pixel(&srcV[i]) >> (depth - 8); + int upx = input_pixel(&srcU[i]); + int vpx = input_pixel(&srcV[i]); + dstU[i] = (upx << (16 - depth)) | (upx >> (2 * depth - 16)); + dstV[i] = (vpx << (16 - depth)) | (vpx >> (2 * depth - 16)); } } static av_always_inline void -yuv9_or_10ToY_c_template(uint8_t *dstY, const uint8_t *_srcY, +yuv9_or_10ToY_c_template(uint16_t *dstY, const uint16_t *srcY, int width, enum PixelFormat origin, int depth) { int i; - const uint16_t *srcY = (const uint16_t*)_srcY; - for (i = 0; i < width; i++) - dstY[i] = input_pixel(&srcY[i]) >> (depth - 8); + for (i = 0; i < width; i++) { + int px = input_pixel(&srcY[i]); + dstY[i] = (px << (16 - depth)) | (px >> (2 * depth - 16)); + } } #undef input_pixel #define YUV_NBPS(depth, BE_LE, origin) \ -static void BE_LE ## depth ## ToUV_c(uint8_t *dstU, uint8_t *dstV, \ - const uint8_t *srcU, const uint8_t *srcV, \ +static void BE_LE ## depth ## ToUV_c(uint8_t *_dstU, uint8_t *_dstV, \ + const uint8_t *_srcU, const uint8_t *_srcV, \ int width, uint32_t *unused) \ { \ + uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \ + const uint16_t *srcU = (const uint16_t *) _srcU, \ + *srcV = (const uint16_t *) _srcV; \ yuv9_OR_10ToUV_c_template(dstU, dstV, srcU, srcV, width, origin, depth); \ } \ -static void BE_LE ## depth ## ToY_c(uint8_t *dstY, const uint8_t *srcY, \ +static void BE_LE ## depth ## ToY_c(uint8_t *_dstY, const uint8_t *_srcY, \ int width, uint32_t *unused) \ { \ + uint16_t *dstY = (uint16_t *) _dstY; \ + const uint16_t *srcY = (const uint16_t *) _srcY; \ yuv9_or_10ToY_c_template(dstY, srcY, width, origin, depth); \ } @@ -1801,6 +1905,27 @@ static void rgb24ToUV_half_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, } } +static void hScale16_c(int16_t *_dst, int dstW, const uint8_t *_src, + const int16_t *filter, + const int16_t *filterPos, int filterSize) +{ + int i; + int32_t *dst = (int32_t *) _dst; + const uint16_t *src = (const uint16_t *) _src; + + for (i = 0; i < dstW; i++) { + int j; + int srcPos = filterPos[i]; + unsigned int val = 0; + + for (j = 0; j < filterSize; j++) { + val += src[srcPos + j] * filter[filterSize * i + j]; + } + // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit + dst[i] = FFMIN(val >> 11, (1 << 19) - 1); + } +} + // bilinear / bicubic scaling static void hScale_c(int16_t *dst, int dstW, const uint8_t *src, const int16_t *filter, const int16_t *filterPos, @@ -1851,6 +1976,41 @@ static void lumRangeFromJpeg_c(int16_t *dst, int width) dst[i] = (dst[i]*14071 + 33561947)>>14; } +static void chrRangeToJpeg16_c(int16_t *_dstU, int16_t *_dstV, int width) +{ + int i; + int32_t *dstU = (int32_t *) _dstU; + int32_t *dstV = (int32_t *) _dstV; + for (i = 0; i < width; i++) { + dstU[i] = (FFMIN(dstU[i],30775)*4663 - 9289992)>>12; //-264 + dstV[i] = (FFMIN(dstV[i],30775)*4663 - 9289992)>>12; //-264 + } +} +static void chrRangeFromJpeg16_c(int16_t *_dstU, int16_t *_dstV, int width) +{ + int i; + int32_t *dstU = (int32_t *) _dstU; + int32_t *dstV = (int32_t *) _dstV; + for (i = 0; i < width; i++) { + dstU[i] = (dstU[i]*1799 + 4081085)>>11; //1469 + dstV[i] = (dstV[i]*1799 + 4081085)>>11; //1469 + } +} +static void lumRangeToJpeg16_c(int16_t *_dst, int width) +{ + int i; + int32_t *dst = (int32_t *) _dst; + for (i = 0; i < width; i++) + dst[i] = (FFMIN(dst[i],30189)*19077 - 39057361)>>14; +} +static void lumRangeFromJpeg16_c(int16_t *_dst, int width) +{ + int i; + int32_t *dst = (int32_t *) _dst; + for (i = 0; i < width; i++) + dst[i] = (dst[i]*14071 + 33561947)>>14; +} + static void hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth, const uint8_t *src, int srcW, int xInc) { @@ -1864,8 +2024,25 @@ static void hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth, } } +static void scale8To16Rv_c(uint16_t *_dst, const uint8_t *src, int len) +{ + int i; + uint8_t *dst = (uint8_t *) _dst; + for (i = len - 1; i >= 0; i--) { + dst[i * 2] = dst[i * 2 + 1] = src[i]; + } +} + +static void scale19To15Fw_c(int16_t *dst, const int32_t *src, int len) +{ + int i; + for (i = 0; i < len; i++) { + dst[i] = src[i] >> 4; + } +} + // *** horizontal scale Y line to temp buffer -static av_always_inline void hyscale(SwsContext *c, uint16_t *dst, int dstWidth, +static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth, const uint8_t *src, int srcW, int xInc, const int16_t *hLumFilter, const int16_t *hLumFilterPos, int hLumFilterSize, @@ -1880,6 +2057,11 @@ static av_always_inline void hyscale(SwsContext *c, uint16_t *dst, int dstWidth, src= formatConvBuffer; } + if (av_pix_fmt_descriptors[c->srcFormat].comp[0].depth_minus1 < 8 && c->scalingBpp == 16) { + c->scale8To16Rv((uint16_t *) formatConvBuffer, src, srcW); + src = formatConvBuffer; + } + if (!c->hyscale_fast) { c->hScale(dst, dstWidth, src, hLumFilter, hLumFilterPos, hLumFilterSize); } else { // fast bilinear upscale / crap downscale @@ -1888,6 +2070,10 @@ static av_always_inline void hyscale(SwsContext *c, uint16_t *dst, int dstWidth, if (convertRange) convertRange(dst, dstWidth); + + if (av_pix_fmt_descriptors[c->dstFormat].comp[0].depth_minus1 < 8 && c->scalingBpp == 16) { + c->scale19To15Fw(dst, (int32_t *) dst, dstWidth); + } } static void hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2, @@ -1905,19 +2091,27 @@ static void hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2, } } -static av_always_inline void hcscale(SwsContext *c, uint16_t *dst1, uint16_t *dst2, int dstWidth, +static av_always_inline void hcscale(SwsContext *c, int16_t *dst1, int16_t *dst2, int dstWidth, const uint8_t *src1, const uint8_t *src2, int srcW, int xInc, const int16_t *hChrFilter, const int16_t *hChrFilterPos, int hChrFilterSize, uint8_t *formatConvBuffer, uint32_t *pal) { if (c->chrToYV12) { - uint8_t *buf2 = formatConvBuffer + FFALIGN(srcW, 16); + uint8_t *buf2 = formatConvBuffer + FFALIGN(srcW * c->scalingBpp >> 3, 16); c->chrToYV12(formatConvBuffer, buf2, src1, src2, srcW, pal); src1= formatConvBuffer; src2= buf2; } + if (av_pix_fmt_descriptors[c->srcFormat].comp[0].depth_minus1 < 8 && c->scalingBpp == 16) { + uint8_t *buf2 = (formatConvBuffer + FFALIGN(srcW * 2, 16)); + c->scale8To16Rv((uint16_t *) formatConvBuffer, src1, srcW); + c->scale8To16Rv((uint16_t *) buf2, src2, srcW); + src1 = formatConvBuffer; + src2 = buf2; + } + if (!c->hcscale_fast) { c->hScale(dst1, dstWidth, src1, hChrFilter, hChrFilterPos, hChrFilterSize); c->hScale(dst2, dstWidth, src2, hChrFilter, hChrFilterPos, hChrFilterSize); @@ -1927,6 +2121,11 @@ static av_always_inline void hcscale(SwsContext *c, uint16_t *dst1, uint16_t *ds if (c->chrConvertRange) c->chrConvertRange(dst1, dst2, dstWidth); + + if (av_pix_fmt_descriptors[c->dstFormat].comp[0].depth_minus1 < 8 && c->scalingBpp == 16) { + c->scale19To15Fw(dst1, (int32_t *) dst1, dstWidth); + c->scale19To15Fw(dst2, (int32_t *) dst2, dstWidth); + } } static av_always_inline void @@ -2049,20 +2248,20 @@ find_c_packed_planar_out_funcs(SwsContext *c, *yuv2packedX = yuv2uyvy422_X_c; break; case PIX_FMT_RGB48LE: - //*yuv2packed1 = yuv2rgb48le_1_c; - //*yuv2packed2 = yuv2rgb48le_2_c; - //*yuv2packedX = yuv2rgb48le_X_c; - //break; + *yuv2packed1 = yuv2rgb48le_1_c; + *yuv2packed2 = yuv2rgb48le_2_c; + *yuv2packedX = yuv2rgb48le_X_c; + break; case PIX_FMT_RGB48BE: *yuv2packed1 = yuv2rgb48be_1_c; *yuv2packed2 = yuv2rgb48be_2_c; *yuv2packedX = yuv2rgb48be_X_c; break; case PIX_FMT_BGR48LE: - //*yuv2packed1 = yuv2bgr48le_1_c; - //*yuv2packed2 = yuv2bgr48le_2_c; - //*yuv2packedX = yuv2bgr48le_X_c; - //break; + *yuv2packed1 = yuv2bgr48le_1_c; + *yuv2packed2 = yuv2bgr48le_2_c; + *yuv2packedX = yuv2bgr48le_X_c; + break; case PIX_FMT_BGR48BE: *yuv2packed1 = yuv2bgr48be_1_c; *yuv2packed2 = yuv2bgr48be_2_c; @@ -2435,13 +2634,6 @@ static av_cold void sws_init_swScale_c(SwsContext *c) &c->yuv2packed1, &c->yuv2packed2, &c->yuv2packedX); - c->hScale = hScale_c; - - if (c->flags & SWS_FAST_BILINEAR) { - c->hyscale_fast = hyscale_fast_c; - c->hcscale_fast = hcscale_fast_c; - } - c->chrToYV12 = NULL; switch(srcFormat) { case PIX_FMT_YUYV422 : c->chrToYV12 = yuy2ToUV_c; break; @@ -2453,22 +2645,25 @@ static av_cold void sws_init_swScale_c(SwsContext *c) case PIX_FMT_PAL8 : case PIX_FMT_BGR4_BYTE: case PIX_FMT_RGB4_BYTE: c->chrToYV12 = palToUV_c; break; - case PIX_FMT_YUV444P9BE: - case PIX_FMT_YUV420P9BE: c->chrToYV12 = BE9ToUV_c; break; case PIX_FMT_YUV444P9LE: - case PIX_FMT_YUV420P9LE: c->chrToYV12 = LE9ToUV_c; break; - case PIX_FMT_YUV444P10BE: - case PIX_FMT_YUV422P10BE: - case PIX_FMT_YUV420P10BE: c->chrToYV12 = BE10ToUV_c; break; + case PIX_FMT_YUV420P9LE: c->chrToYV12 = LE9ToUV_c; break; case PIX_FMT_YUV422P10LE: case PIX_FMT_YUV444P10LE: case PIX_FMT_YUV420P10LE: c->chrToYV12 = LE10ToUV_c; break; - case PIX_FMT_YUV420P16BE: - case PIX_FMT_YUV422P16BE: - case PIX_FMT_YUV444P16BE: c->chrToYV12 = BEToUV_c; break; + case PIX_FMT_YUV444P9BE: + case PIX_FMT_YUV420P9BE: c->chrToYV12 = BE9ToUV_c; break; + case PIX_FMT_YUV444P10BE: + case PIX_FMT_YUV422P10BE: + case PIX_FMT_YUV420P10BE: c->chrToYV12 = BE10ToUV_c; break; +#if HAVE_BIGENDIAN case PIX_FMT_YUV420P16LE: case PIX_FMT_YUV422P16LE: - case PIX_FMT_YUV444P16LE: c->chrToYV12 = LEToUV_c; break; + case PIX_FMT_YUV444P16LE: c->chrToYV12 = bswap16UV_c; break; +#else + case PIX_FMT_YUV420P16BE: + case PIX_FMT_YUV422P16BE: + case PIX_FMT_YUV444P16BE: c->chrToYV12 = bswap16UV_c; break; +#endif } if (c->chrSrcHSubSample) { switch(srcFormat) { @@ -2517,27 +2712,30 @@ static av_cold void sws_init_swScale_c(SwsContext *c) c->lumToYV12 = NULL; c->alpToYV12 = NULL; switch (srcFormat) { - case PIX_FMT_YUV444P9BE: - case PIX_FMT_YUV420P9BE: c->lumToYV12 = BE9ToY_c; break; case PIX_FMT_YUV444P9LE: - case PIX_FMT_YUV420P9LE: c->lumToYV12 = LE9ToY_c; break; - case PIX_FMT_YUV444P10BE: - case PIX_FMT_YUV422P10BE: - case PIX_FMT_YUV420P10BE: c->lumToYV12 = BE10ToY_c; break; + case PIX_FMT_YUV420P9LE: c->lumToYV12 = LE9ToY_c; break; case PIX_FMT_YUV444P10LE: case PIX_FMT_YUV422P10LE: case PIX_FMT_YUV420P10LE: c->lumToYV12 = LE10ToY_c; break; - case PIX_FMT_YUYV422 : - case PIX_FMT_YUV420P16BE: - case PIX_FMT_YUV422P16BE: - case PIX_FMT_YUV444P16BE: - case PIX_FMT_Y400A : - case PIX_FMT_GRAY16BE : c->lumToYV12 = yuy2ToY_c; break; - case PIX_FMT_UYVY422 : + case PIX_FMT_YUV444P9BE: + case PIX_FMT_YUV420P9BE: c->lumToYV12 = BE9ToY_c; break; + case PIX_FMT_YUV444P10BE: + case PIX_FMT_YUV422P10BE: + case PIX_FMT_YUV420P10BE: c->lumToYV12 = BE10ToY_c; break; +#if HAVE_BIGENDIAN case PIX_FMT_YUV420P16LE: case PIX_FMT_YUV422P16LE: case PIX_FMT_YUV444P16LE: - case PIX_FMT_GRAY16LE : c->lumToYV12 = uyvyToY_c; break; + case PIX_FMT_GRAY16LE: c->lumToYV12 = bswap16Y_c; break; +#else + case PIX_FMT_YUV420P16BE: + case PIX_FMT_YUV422P16BE: + case PIX_FMT_YUV444P16BE: + case PIX_FMT_GRAY16BE: c->lumToYV12 = bswap16Y_c; break; +#endif + case PIX_FMT_YUYV422 : + case PIX_FMT_Y400A : c->lumToYV12 = yuy2ToY_c; break; + case PIX_FMT_UYVY422 : c->lumToYV12 = uyvyToY_c; break; case PIX_FMT_BGR24 : c->lumToYV12 = bgr24ToY_c; break; case PIX_FMT_BGR565LE : c->lumToYV12 = bgr16leToY_c; break; case PIX_FMT_BGR565BE : c->lumToYV12 = bgr16beToY_c; break; @@ -2574,6 +2772,13 @@ static av_cold void sws_init_swScale_c(SwsContext *c) } } + if (c->scalingBpp == 8) { + c->hScale = hScale_c; + if (c->flags & SWS_FAST_BILINEAR) { + c->hyscale_fast = hyscale_fast_c; + c->hcscale_fast = hcscale_fast_c; + } + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) { if (c->srcRange) { c->lumConvertRange = lumRangeFromJpeg_c; @@ -2583,6 +2788,21 @@ static av_cold void sws_init_swScale_c(SwsContext *c) c->chrConvertRange = chrRangeToJpeg_c; } } + } else { + c->hScale = hScale16_c; + c->scale19To15Fw = scale19To15Fw_c; + c->scale8To16Rv = scale8To16Rv_c; + + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) { + if (c->srcRange) { + c->lumConvertRange = lumRangeFromJpeg16_c; + c->chrConvertRange = chrRangeFromJpeg16_c; + } else { + c->lumConvertRange = lumRangeToJpeg16_c; + c->chrConvertRange = chrRangeToJpeg16_c; + } + } + } if (!(isGray(srcFormat) || isGray(c->dstFormat) || srcFormat == PIX_FMT_MONOBLACK || srcFormat == PIX_FMT_MONOWHITE)) diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index c1eed8ac96..cfb19d9c13 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -205,6 +205,7 @@ typedef struct SwsContext { enum PixelFormat srcFormat; ///< Source pixel format. int dstFormatBpp; ///< Number of bits per pixel of the destination pixel format. int srcFormatBpp; ///< Number of bits per pixel of the source pixel format. + int scalingBpp; int chrSrcHSubSample; ///< Binary logarithm of horizontal subsampling factor between luma/alpha and chroma planes in source image. int chrSrcVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in source image. int chrDstHSubSample; ///< Binary logarithm of horizontal subsampling factor between luma/alpha and chroma planes in destination image. @@ -446,6 +447,15 @@ typedef struct SwsContext { void (*lumConvertRange)(int16_t *dst, int width); ///< Color range conversion function for luma plane if needed. void (*chrConvertRange)(int16_t *dst1, int16_t *dst2, int width); ///< Color range conversion function for chroma planes if needed. + /** + * dst[..] = (src[..] << 8) | src[..]; + */ + void (*scale8To16Rv)(uint16_t *dst, const uint8_t *src, int len); + /** + * dst[..] = src[..] >> 4; + */ + void (*scale19To15Fw)(int16_t *dst, const int32_t *src, int len); + int needs_hcscale; ///< Set if there are chroma planes to be converted. } SwsContext; diff --git a/libswscale/utils.c b/libswscale/utils.c index 69714183d0..b7ccac94ba 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -877,8 +877,13 @@ int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter) } } - FF_ALLOC_OR_GOTO(c, c->formatConvBuffer, FFALIGN(srcW, 16) * 2, fail); - if (HAVE_MMX2 && cpu_flags & AV_CPU_FLAG_MMX2) { + // FIXME it's even nicer if bpp isn't 16, but max({src,dst}formatbpp) + c->scalingBpp = FFMAX(av_pix_fmt_descriptors[srcFormat].comp[0].depth_minus1, + av_pix_fmt_descriptors[dstFormat].comp[0].depth_minus1) >= 8 ? 16 : 8; + if (c->scalingBpp == 16) + dst_stride <<= 1; + FF_ALLOC_OR_GOTO(c, c->formatConvBuffer, FFALIGN(srcW, 16) * 2 * c->scalingBpp >> 3, fail); + if (HAVE_MMX2 && cpu_flags & AV_CPU_FLAG_MMX2 && c->scalingBpp == 8) { c->canMMX2BeUsed= (dstW >=srcW && (dstW&31)==0 && (srcW&15)==0) ? 1 : 0; if (!c->canMMX2BeUsed && dstW >=srcW && (srcW&15)==0 && (flags&SWS_FAST_BILINEAR)) { if (flags&SWS_PRINT_INFO) diff --git a/libswscale/x86/swscale_template.c b/libswscale/x86/swscale_template.c index de0e4abfe0..54c7edc25e 100644 --- a/libswscale/x86/swscale_template.c +++ b/libswscale/x86/swscale_template.c @@ -1625,32 +1625,6 @@ static void RENAME(yuy2ToUV)(uint8_t *dstU, uint8_t *dstV, assert(src1 == src2); } -static void RENAME(LEToUV)(uint8_t *dstU, uint8_t *dstV, - const uint8_t *src1, const uint8_t *src2, - int width, uint32_t *unused) -{ - __asm__ volatile( - "mov %0, %%"REG_a" \n\t" - "1: \n\t" - "movq (%1, %%"REG_a",2), %%mm0 \n\t" - "movq 8(%1, %%"REG_a",2), %%mm1 \n\t" - "movq (%2, %%"REG_a",2), %%mm2 \n\t" - "movq 8(%2, %%"REG_a",2), %%mm3 \n\t" - "psrlw $8, %%mm0 \n\t" - "psrlw $8, %%mm1 \n\t" - "psrlw $8, %%mm2 \n\t" - "psrlw $8, %%mm3 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "packuswb %%mm3, %%mm2 \n\t" - "movq %%mm0, (%3, %%"REG_a") \n\t" - "movq %%mm2, (%4, %%"REG_a") \n\t" - "add $8, %%"REG_a" \n\t" - " js 1b \n\t" - : : "g" ((x86_reg)-width), "r" (src1+width*2), "r" (src2+width*2), "r" (dstU+width), "r" (dstV+width) - : "%"REG_a - ); -} - /* This is almost identical to the previous, end exists only because * yuy2ToY/UV)(dst, src+1, ...) would have 100% unaligned accesses. */ static void RENAME(uyvyToY)(uint8_t *dst, const uint8_t *src, @@ -1700,33 +1674,6 @@ static void RENAME(uyvyToUV)(uint8_t *dstU, uint8_t *dstV, assert(src1 == src2); } -static void RENAME(BEToUV)(uint8_t *dstU, uint8_t *dstV, - const uint8_t *src1, const uint8_t *src2, - int width, uint32_t *unused) -{ - __asm__ volatile( - "movq "MANGLE(bm01010101)", %%mm4 \n\t" - "mov %0, %%"REG_a" \n\t" - "1: \n\t" - "movq (%1, %%"REG_a",2), %%mm0 \n\t" - "movq 8(%1, %%"REG_a",2), %%mm1 \n\t" - "movq (%2, %%"REG_a",2), %%mm2 \n\t" - "movq 8(%2, %%"REG_a",2), %%mm3 \n\t" - "pand %%mm4, %%mm0 \n\t" - "pand %%mm4, %%mm1 \n\t" - "pand %%mm4, %%mm2 \n\t" - "pand %%mm4, %%mm3 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "packuswb %%mm3, %%mm2 \n\t" - "movq %%mm0, (%3, %%"REG_a") \n\t" - "movq %%mm2, (%4, %%"REG_a") \n\t" - "add $8, %%"REG_a" \n\t" - " js 1b \n\t" - : : "g" ((x86_reg)-width), "r" (src1+width*2), "r" (src2+width*2), "r" (dstU+width), "r" (dstV+width) - : "%"REG_a - ); -} - static av_always_inline void RENAME(nvXXtoUV)(uint8_t *dst1, uint8_t *dst2, const uint8_t *src, int width) { @@ -2268,6 +2215,7 @@ static av_cold void RENAME(sws_init_swScale)(SwsContext *c) } } + if (c->scalingBpp == 8) { #if !COMPILE_TEMPLATE_MMX2 c->hScale = RENAME(hScale ); #endif /* !COMPILE_TEMPLATE_MMX2 */ @@ -2285,6 +2233,7 @@ static av_cold void RENAME(sws_init_swScale)(SwsContext *c) #if COMPILE_TEMPLATE_MMX2 } #endif /* COMPILE_TEMPLATE_MMX2 */ + } #if !COMPILE_TEMPLATE_MMX2 switch(srcFormat) { @@ -2292,12 +2241,6 @@ static av_cold void RENAME(sws_init_swScale)(SwsContext *c) case PIX_FMT_UYVY422 : c->chrToYV12 = RENAME(uyvyToUV); break; case PIX_FMT_NV12 : c->chrToYV12 = RENAME(nv12ToUV); break; case PIX_FMT_NV21 : c->chrToYV12 = RENAME(nv21ToUV); break; - case PIX_FMT_YUV420P16BE: - case PIX_FMT_YUV422P16BE: - case PIX_FMT_YUV444P16BE: c->chrToYV12 = RENAME(BEToUV); break; - case PIX_FMT_YUV420P16LE: - case PIX_FMT_YUV422P16LE: - case PIX_FMT_YUV444P16LE: c->chrToYV12 = RENAME(LEToUV); break; default: break; } #endif /* !COMPILE_TEMPLATE_MMX2 */ @@ -2312,16 +2255,8 @@ static av_cold void RENAME(sws_init_swScale)(SwsContext *c) switch (srcFormat) { #if !COMPILE_TEMPLATE_MMX2 case PIX_FMT_YUYV422 : - case PIX_FMT_YUV420P16BE: - case PIX_FMT_YUV422P16BE: - case PIX_FMT_YUV444P16BE: - case PIX_FMT_Y400A : - case PIX_FMT_GRAY16BE : c->lumToYV12 = RENAME(yuy2ToY); break; - case PIX_FMT_UYVY422 : - case PIX_FMT_YUV420P16LE: - case PIX_FMT_YUV422P16LE: - case PIX_FMT_YUV444P16LE: - case PIX_FMT_GRAY16LE : c->lumToYV12 = RENAME(uyvyToY); break; + case PIX_FMT_Y400A : c->lumToYV12 = RENAME(yuy2ToY); break; + case PIX_FMT_UYVY422 : c->lumToYV12 = RENAME(uyvyToY); break; #endif /* !COMPILE_TEMPLATE_MMX2 */ case PIX_FMT_BGR24 : c->lumToYV12 = RENAME(bgr24ToY); break; case PIX_FMT_RGB24 : c->lumToYV12 = RENAME(rgb24ToY); break; -- cgit v1.2.3