From 582bc5a348f5cd12b6ad3be4ecbee71bc082ea32 Mon Sep 17 00:00:00 2001 From: Sergey Lavrushkin Date: Fri, 3 Aug 2018 18:06:50 +0300 Subject: libswscale: Adds conversions from/to float gray format. Signed-off-by: Michael Niedermayer --- libswscale/input.c | 38 ++++++++++++++ libswscale/output.c | 105 ++++++++++++++++++++++++++++++++++++++ libswscale/ppc/swscale_altivec.c | 1 + libswscale/swscale_internal.h | 9 ++++ libswscale/swscale_unscaled.c | 54 +++++++++++++++++++- libswscale/utils.c | 20 +++++++- libswscale/x86/swscale_template.c | 3 +- 7 files changed, 226 insertions(+), 4 deletions(-) (limited to 'libswscale') diff --git a/libswscale/input.c b/libswscale/input.c index 3fd3a5d81e..4099c19c2b 100644 --- a/libswscale/input.c +++ b/libswscale/input.c @@ -942,6 +942,30 @@ static av_always_inline void planar_rgb16_to_uv(uint8_t *_dstU, uint8_t *_dstV, } #undef rdpx +static av_always_inline void grayf32ToY16_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i){ + dst[i] = av_clip_uint16(lrintf(65535.0f * src[i])); + } +} + +static av_always_inline void grayf32ToY16_bswap_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused) +{ + int i; + const uint32_t *src = (const uint32_t *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i){ + dst[i] = av_clip_uint16(lrintf(65535.0f * av_int2float(av_bswap32(src[i])))); + } +} + #define rgb9plus_planar_funcs_endian(nbits, endian_name, endian) \ static void planar_rgb##nbits##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \ int w, int32_t *rgb2yuv) \ @@ -1538,6 +1562,20 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_P010BE: c->lumToYV12 = p010BEToY_c; break; + case AV_PIX_FMT_GRAYF32LE: +#if HAVE_BIGENDIAN + c->lumToYV12 = grayf32ToY16_bswap_c; +#else + c->lumToYV12 = grayf32ToY16_c; +#endif + break; + case AV_PIX_FMT_GRAYF32BE: +#if HAVE_BIGENDIAN + c->lumToYV12 = grayf32ToY16_c; +#else + c->lumToYV12 = grayf32ToY16_bswap_c; +#endif + break; } if (c->needAlpha) { if (is16BPS(srcFormat) || isNBPS(srcFormat)) { diff --git a/libswscale/output.c b/libswscale/output.c index 0af2fffea4..de8637aa3b 100644 --- a/libswscale/output.c +++ b/libswscale/output.c @@ -208,6 +208,105 @@ static void yuv2p016cX_c(SwsContext *c, const int16_t *chrFilter, int chrFilterS } } +static av_always_inline void +yuv2plane1_float_c_template(const int32_t *src, float *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = float_mult * (float)val_uint; + } +} + +static av_always_inline void +yuv2plane1_float_bswap_c_template(const int32_t *src, uint32_t *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +static av_always_inline void +yuv2planeX_float_c_template(const int16_t *filter, int filterSize, const int32_t **src, + float *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 15; + static const float float_mult = 1.0f / 65535.0f; + int i, j, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = (1 << (shift - 1)) - 0x40000000; + for (j = 0; j < filterSize; ++j){ + val += src[j][i] * (unsigned)filter[j]; + } + output_pixel(&val_uint, val, 0x8000, int); + dest[i] = float_mult * (float)val_uint; + } +} + +static av_always_inline void +yuv2planeX_float_bswap_c_template(const int16_t *filter, int filterSize, const int32_t **src, + uint32_t *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 15; + static const float float_mult = 1.0f / 65535.0f; + int i, j, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = (1 << (shift - 1)) - 0x40000000; + for (j = 0; j < filterSize; ++j){ + val += src[j][i] * (unsigned)filter[j]; + } + output_pixel(&val_uint, val, 0x8000, int); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +#define yuv2plane1_float(template, dest_type, BE_LE) \ +static void yuv2plane1_float ## BE_LE ## _c(const int16_t *src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template((const int32_t *)src, (dest_type *)dest, dstW); \ +} + +#define yuv2planeX_float(template, dest_type, BE_LE) \ +static void yuv2planeX_float ## BE_LE ## _c(const int16_t *filter, int filterSize, \ + const int16_t **src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template(filter, filterSize, (const int32_t **)src, (dest_type *)dest, dstW); \ +} + +#if HAVE_BIGENDIAN +yuv2plane1_float(yuv2plane1_float_c_template, float, BE) +yuv2plane1_float(yuv2plane1_float_bswap_c_template, uint32_t, LE) +yuv2planeX_float(yuv2planeX_float_c_template, float, BE) +yuv2planeX_float(yuv2planeX_float_bswap_c_template, uint32_t, LE) +#else +yuv2plane1_float(yuv2plane1_float_c_template, float, LE) +yuv2plane1_float(yuv2plane1_float_bswap_c_template, uint32_t, BE) +yuv2planeX_float(yuv2planeX_float_c_template, float, LE) +yuv2planeX_float(yuv2planeX_float_bswap_c_template, uint32_t, BE) +#endif + #undef output_pixel #define output_pixel(pos, val) \ @@ -2303,6 +2402,12 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c, *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_14BE_c : yuv2plane1_14LE_c; } else av_assert0(0); + } else if (dstFormat == AV_PIX_FMT_GRAYF32BE) { + *yuv2planeX = yuv2planeX_floatBE_c; + *yuv2plane1 = yuv2plane1_floatBE_c; + } else if (dstFormat == AV_PIX_FMT_GRAYF32LE) { + *yuv2planeX = yuv2planeX_floatLE_c; + *yuv2plane1 = yuv2plane1_floatLE_c; } else { *yuv2plane1 = yuv2plane1_8_c; *yuv2planeX = yuv2planeX_8_c; diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c index 9438a63ff2..2fb2337769 100644 --- a/libswscale/ppc/swscale_altivec.c +++ b/libswscale/ppc/swscale_altivec.c @@ -339,6 +339,7 @@ av_cold void ff_sws_init_swscale_ppc(SwsContext *c) } if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && dstFormat != AV_PIX_FMT_NV12 && dstFormat != AV_PIX_FMT_NV21 && + dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != AV_PIX_FMT_GRAYF32LE && !c->needAlpha) { c->yuv2planeX = yuv2planeX_altivec; } diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index 1703856ab2..4fa59386a6 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -336,6 +336,8 @@ typedef struct SwsContext { uint32_t pal_yuv[256]; uint32_t pal_rgb[256]; + float uint2float_lut[256]; + /** * @name Scaled horizontal lines ring buffer. * The horizontal scaler keeps just enough scaled lines in a ring buffer @@ -764,6 +766,13 @@ static av_always_inline int isAnyRGB(enum AVPixelFormat pix_fmt) pix_fmt == AV_PIX_FMT_MONOBLACK || pix_fmt == AV_PIX_FMT_MONOWHITE; } +static av_always_inline int isFloat(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->flags & AV_PIX_FMT_FLAG_FLOAT; +} + static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c index 6480070cbf..973fa4875f 100644 --- a/libswscale/swscale_unscaled.c +++ b/libswscale/swscale_unscaled.c @@ -1467,6 +1467,46 @@ static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[], return srcSliceH; } +static int uint_y_to_float_y_wrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *dst[], int dstStride[]) +{ + int y, x; + ptrdiff_t dstStrideFloat = dstStride[0] >> 2; + const uint8_t *srcPtr = src[0]; + float *dstPtr = (float *)(dst[0] + dstStride[0] * srcSliceY); + + for (y = 0; y < srcSliceH; ++y){ + for (x = 0; x < c->srcW; ++x){ + dstPtr[x] = c->uint2float_lut[srcPtr[x]]; + } + srcPtr += srcStride[0]; + dstPtr += dstStrideFloat; + } + + return srcSliceH; +} + +static int float_y_to_uint_y_wrapper(SwsContext *c, const uint8_t* src[], + int srcStride[], int srcSliceY, + int srcSliceH, uint8_t* dst[], int dstStride[]) +{ + int y, x; + ptrdiff_t srcStrideFloat = srcStride[0] >> 2; + const float *srcPtr = (const float *)src[0]; + uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY; + + for (y = 0; y < srcSliceH; ++y){ + for (x = 0; x < c->srcW; ++x){ + dstPtr[x] = av_clip_uint8(lrintf(255.0f * srcPtr[x])); + } + srcPtr += srcStrideFloat; + dstPtr += dstStride[0]; + } + + return srcSliceH; +} + /* unscaled copy like stuff (assumes nearly identical formats) */ static int packedCopyWrapper(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, @@ -1899,6 +1939,16 @@ void ff_get_unscaled_swscale(SwsContext *c) c->swscale = yuv422pToUyvyWrapper; } + /* uint Y to float Y */ + if (srcFormat == AV_PIX_FMT_GRAY8 && dstFormat == AV_PIX_FMT_GRAYF32){ + c->swscale = uint_y_to_float_y_wrapper; + } + + /* float Y to uint Y */ + if (srcFormat == AV_PIX_FMT_GRAYF32 && dstFormat == AV_PIX_FMT_GRAY8){ + c->swscale = float_y_to_uint_y_wrapper; + } + /* LQ converters if -sws 0 or -sws 4*/ if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) { /* yv12_to_yuy2 */ @@ -1925,13 +1975,13 @@ void ff_get_unscaled_swscale(SwsContext *c) if ( srcFormat == dstFormat || (srcFormat == AV_PIX_FMT_YUVA420P && dstFormat == AV_PIX_FMT_YUV420P) || (srcFormat == AV_PIX_FMT_YUV420P && dstFormat == AV_PIX_FMT_YUVA420P) || - (isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) || + (isFloat(srcFormat) == isFloat(dstFormat)) && ((isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) || (isPlanarYUV(dstFormat) && isPlanarGray(srcFormat)) || (isPlanarGray(dstFormat) && isPlanarGray(srcFormat)) || (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) && c->chrDstHSubSample == c->chrSrcHSubSample && c->chrDstVSubSample == c->chrSrcVSubSample && - !isSemiPlanarYUV(srcFormat) && !isSemiPlanarYUV(dstFormat))) + !isSemiPlanarYUV(srcFormat) && !isSemiPlanarYUV(dstFormat)))) { if (isPacked(c->srcFormat)) c->swscale = packedCopyWrapper; diff --git a/libswscale/utils.c b/libswscale/utils.c index 61b47182f8..5e56371180 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -258,6 +258,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_P010BE] = { 1, 1 }, [AV_PIX_FMT_P016LE] = { 1, 1 }, [AV_PIX_FMT_P016BE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF32LE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF32BE] = { 1, 1 }, }; int sws_isSupportedInput(enum AVPixelFormat pix_fmt) @@ -1173,6 +1175,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, const AVPixFmtDescriptor *desc_dst; int ret = 0; enum AVPixelFormat tmpFmt; + static const float float_mult = 1.0f / 255.0f; cpu_flags = av_get_cpu_flags(); flags = c->flags; @@ -1537,6 +1540,19 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, } } + if (unscaled && c->srcBpc == 8 && dstFormat == AV_PIX_FMT_GRAYF32){ + for (i = 0; i < 256; ++i){ + c->uint2float_lut[i] = (float)i * float_mult; + } + } + + // float will be converted to uint16_t + if ((srcFormat == AV_PIX_FMT_GRAYF32BE || srcFormat == AV_PIX_FMT_GRAYF32LE) && + (!unscaled || unscaled && dstFormat != srcFormat && (srcFormat != AV_PIX_FMT_GRAYF32 || + dstFormat != AV_PIX_FMT_GRAY8))){ + c->srcBpc = 16; + } + if (CONFIG_SWSCALE_ALPHA && isALPHA(srcFormat) && !isALPHA(dstFormat)) { enum AVPixelFormat tmpFormat = alphaless_fmt(srcFormat); @@ -1793,7 +1809,9 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, /* unscaled special cases */ if (unscaled && !usesHFilter && !usesVFilter && - (c->srcRange == c->dstRange || isAnyRGB(dstFormat))) { + (c->srcRange == c->dstRange || isAnyRGB(dstFormat) || + srcFormat == AV_PIX_FMT_GRAYF32 && dstFormat == AV_PIX_FMT_GRAY8 || + srcFormat == AV_PIX_FMT_GRAY8 && dstFormat == AV_PIX_FMT_GRAYF32)) { ff_get_unscaled_swscale(c); if (c->swscale) { diff --git a/libswscale/x86/swscale_template.c b/libswscale/x86/swscale_template.c index b8bdcd4d03..7c30470679 100644 --- a/libswscale/x86/swscale_template.c +++ b/libswscale/x86/swscale_template.c @@ -1500,7 +1500,8 @@ static av_cold void RENAME(sws_init_swscale)(SwsContext *c) c->use_mmx_vfilter= 0; if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && dstFormat != AV_PIX_FMT_NV12 - && dstFormat != AV_PIX_FMT_NV21 && !(c->flags & SWS_BITEXACT)) { + && dstFormat != AV_PIX_FMT_NV21 && dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != AV_PIX_FMT_GRAYF32LE + && !(c->flags & SWS_BITEXACT)) { if (c->flags & SWS_ACCURATE_RND) { if (!(c->flags & SWS_FULL_CHR_H_INT)) { switch (c->dstFormat) { -- cgit v1.2.3