diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 0c20a71f71..190a7b98f4 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -791,6 +791,62 @@ static int check_image_pointers(const uint8_t * const data[4], enum AVPixelForma return 1; } +static void xyz12Torgb48(struct SwsContext *c, uint16_t *dst, + const uint16_t *src, int stride, int h) +{ + int xp,yp; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat); + + for (yp=0; ypflags & PIX_FMT_BE) { + x = AV_RB16(src + xp + 0); + y = AV_RB16(src + xp + 1); + z = AV_RB16(src + xp + 2); + } else { + x = AV_RL16(src + xp + 0); + y = AV_RL16(src + xp + 1); + z = AV_RL16(src + xp + 2); + } + + x = c->xyzgamma[x>>4]; + y = c->xyzgamma[y>>4]; + z = c->xyzgamma[z>>4]; + + // convert from XYZlinear to sRGBlinear + r = c->xyz2rgb_matrix[0][0] * x + + c->xyz2rgb_matrix[0][1] * y + + c->xyz2rgb_matrix[0][2] * z >> 12; + g = c->xyz2rgb_matrix[1][0] * x + + c->xyz2rgb_matrix[1][1] * y + + c->xyz2rgb_matrix[1][2] * z >> 12; + b = c->xyz2rgb_matrix[2][0] * x + + c->xyz2rgb_matrix[1][2] * y + + c->xyz2rgb_matrix[2][2] * z >> 12; + + // limit values to 12-bit depth + r = av_clip_c(r,0,4095); + g = av_clip_c(g,0,4095); + b = av_clip_c(b,0,4095); + + // convert from sRGBlinear to RGB and scale from 12bit to 16bit + if (desc->flags & PIX_FMT_BE) { + AV_WB16(dst + xp + 0, c->rgbgamma[r] << 4); + AV_WB16(dst + xp + 1, c->rgbgamma[g] << 4); + AV_WB16(dst + xp + 2, c->rgbgamma[b] << 4); + } else { + AV_WL16(dst + xp + 0, c->rgbgamma[r] << 4); + AV_WL16(dst + xp + 1, c->rgbgamma[g] << 4); + AV_WL16(dst + xp + 2, c->rgbgamma[b] << 4); + } + } + src += stride; + dst += stride; + } +} + /** * swscale wrapper, so we don't need to export the SwsContext. * Assumes planar YUV to be in YUV order instead of YVU. @@ -922,6 +978,15 @@ int attribute_align_arg sws_scale(struct SwsContext *c, src2[0] = base; } + if (c->srcXYZ && !(c->dstXYZ && c->srcW==c->dstW && c->srcH==c->dstH)) { + uint8_t *base; + rgb0_tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32); + base = srcStride[0] < 0 ? rgb0_tmp - srcStride[0] * (srcSliceH-1) : rgb0_tmp; + + xyz12Torgb48(c, base, src2[0], srcStride[0]/2, srcSliceH); + src2[0] = base; + } + if (!srcSliceY && (c->flags & SWS_BITEXACT) && (c->flags & SWS_ERROR_DIFFUSION) && c->dither_error[0]) for (i = 0; i < 4; i++) memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (c->dstW+2)); diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index be5a80e73b..36ce1ea661 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -380,6 +380,8 @@ typedef struct SwsContext { int dstRange; ///< 0 = MPG YUV range, 1 = JPG YUV range (destination image). int src0Alpha; int dst0Alpha; + int srcXYZ; + int dstXYZ; int yuv2rgb_y_offset; int yuv2rgb_y_coeff; int yuv2rgb_v2r_coeff; @@ -473,6 +475,13 @@ typedef struct SwsContext { #endif int use_mmx_vfilter; +/* pre defined color-spaces gamma */ +#define XYZ_GAMMA (2.6f) +#define RGB_GAMMA (2.2f) + int16_t xyzgamma[4096]; + int16_t rgbgamma[4096]; + int16_t xyz2rgb_matrix[3][4]; + /* function pointers for swScale() */ yuv2planar1_fn yuv2plane1; yuv2planarX_fn yuv2planeX; diff --git a/libswscale/utils.c b/libswscale/utils.c index ca7c2c4a28..f13fec8977 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -196,6 +196,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_GBRP14BE] = { 1, 1 }, [AV_PIX_FMT_GBRP16LE] = { 1, 0 }, [AV_PIX_FMT_GBRP16BE] = { 1, 0 }, + [AV_PIX_FMT_XYZ12BE] = { 1, 0 }, + [AV_PIX_FMT_XYZ12LE] = { 1, 0 }, }; int sws_isSupportedInput(enum AVPixelFormat pix_fmt) @@ -893,6 +895,24 @@ static void fill_rgb2yuv_table(SwsContext *c, const int table[4], int dstRange) AV_WL16(p + 16*4 + 2*i, map[i] >= 0 ? c->input_rgb2yuv_table[map[i]] : 0); } +static void fill_xyztables(struct SwsContext *c) +{ + int i; + double xyzgamma = XYZ_GAMMA; + double rgbgamma = 1.0 / RGB_GAMMA; + static const int16_t xyz2rgb_matrix[3][4] = { + {13270, -6295, -2041}, + {-3969, 7682, 170}, + { 228, -835, 4329} }; + + /* set gamma vectors */ + for (i = 0; i < 4096; i++) { + c->xyzgamma[i] = lrint(pow(i / 4095.0, xyzgamma) * 4095.0); + c->rgbgamma[i] = lrint(pow(i / 4095.0, rgbgamma) * 4095.0); + } + memcpy(c->xyz2rgb_matrix, xyz2rgb_matrix, sizeof(c->xyz2rgb_matrix)); +} + int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], int srcRange, const int table[4], int dstRange, int brightness, int contrast, int saturation) @@ -913,6 +933,8 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], c->srcRange = srcRange; c->dstRange = dstRange; + fill_xyztables(c); + if ((isYUV(c->dstFormat) || isGray(c->dstFormat)) && (isYUV(c->srcFormat) || isGray(c->srcFormat))) return -1; @@ -983,6 +1005,15 @@ static int handle_0alpha(enum AVPixelFormat *format) } } +static int handle_xyz(enum AVPixelFormat *format) +{ + switch (*format) { + case AV_PIX_FMT_XYZ12BE : *format = AV_PIX_FMT_RGB48BE; return 1; + case AV_PIX_FMT_XYZ12LE : *format = AV_PIX_FMT_RGB48LE; return 1; + default: return 0; + } +} + SwsContext *sws_alloc_context(void) { SwsContext *c = av_mallocz(sizeof(SwsContext)); @@ -1025,6 +1056,8 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, handle_jpeg(&dstFormat); handle_0alpha(&srcFormat); handle_0alpha(&dstFormat); + handle_xyz(&srcFormat); + handle_xyz(&dstFormat); if(srcFormat!=c->srcFormat || dstFormat!=c->dstFormat){ av_log(c, AV_LOG_WARNING, "deprecated pixel format used, make sure you did set range correctly\n"); @@ -1518,6 +1551,8 @@ SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, c->dstRange = handle_jpeg(&dstFormat); c->src0Alpha = handle_0alpha(&srcFormat); c->dst0Alpha = handle_0alpha(&dstFormat); + c->srcXYZ = handle_xyz(&srcFormat); + c->dstXYZ = handle_xyz(&dstFormat); c->srcFormat = srcFormat; c->dstFormat = dstFormat; @@ -1959,11 +1994,13 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW, context->srcH = srcH; context->srcRange = handle_jpeg(&srcFormat); context->src0Alpha = handle_0alpha(&srcFormat); + context->srcXYZ = handle_xyz(&srcFormat); context->srcFormat = srcFormat; context->dstW = dstW; context->dstH = dstH; context->dstRange = handle_jpeg(&dstFormat); context->dst0Alpha = handle_0alpha(&dstFormat); + context->dstXYZ = handle_xyz(&dstFormat); context->dstFormat = dstFormat; context->flags = flags; context->param[0] = param[0];