From: Michael Niedermayer <[email protected]> The implementation is heavily based on Matthias Buercher's and Nicolas Bertrand's vf_xyz2rgb
Signed-off-by: Anton Khirnov <[email protected]> --- libswscale/swscale_internal.h | 9 +++++ libswscale/swscale_unscaled.c | 82 ++++++++++++++++++++++++++++++++++++++--- libswscale/utils.c | 42 +++++++++++++++++++++ 3 files changed, 128 insertions(+), 5 deletions(-) diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index f9f023f..d7979ea 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -362,6 +362,8 @@ typedef struct SwsContext { int dstColorspaceTable[4]; int srcRange; ///< 0 = MPG YUV range, 1 = JPG YUV range (source image). int dstRange; ///< 0 = MPG YUV range, 1 = JPG YUV range (destination image). + int src_xyz; + int dst_xyz; int yuv2rgb_y_offset; int yuv2rgb_y_coeff; int yuv2rgb_v2r_coeff; @@ -454,6 +456,13 @@ typedef struct SwsContext { DECLARE_ALIGNED(8, uint64_t, sparc_coeffs)[10]; #endif +/* 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/swscale_unscaled.c b/libswscale/swscale_unscaled.c index a994d6f..a4f5a34 100644 --- a/libswscale/swscale_unscaled.c +++ b/libswscale/swscale_unscaled.c @@ -1122,6 +1122,62 @@ static int check_image_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, return 1; } +static void xyz12_to_rgb48(struct SwsContext *c, uint16_t *dst, + const uint16_t *src, int stride, int h) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat); + int xp, yp; + + for (yp = 0; yp < h; yp++) { + for (xp = 0; xp + 2 < stride; xp += 3) { + int x, y, z, r, g, b; + + if (desc->flags & 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. @@ -1132,9 +1188,10 @@ int attribute_align_arg sws_scale(struct SwsContext *c, int srcSliceH, uint8_t *const dst[], const int dstStride[]) { - int i; + int i, ret; const uint8_t *src2[4] = { srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3] }; uint8_t *dst2[4] = { dst[0], dst[1], dst[2], dst[3] }; + uint8_t *tmp = NULL; // do not mess up sliceDir if we have a "trailing" 0-size slice if (srcSliceH == 0) @@ -1220,6 +1277,18 @@ int attribute_align_arg sws_scale(struct SwsContext *c, } } + if (c->src_xyz && !(c->dst_xyz && c->srcW == c->dstW && c->srcH == c->dstH)) { + uint8_t *base; + tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32); + if (!tmp) + return 0; + + base = srcStride[0] < 0 ? tmp - srcStride[0] * (srcSliceH - 1) : tmp; + + xyz12_to_rgb48(c, base, src2[0], srcStride[0]/2, srcSliceH); + src2[0] = base; + } + // copy strides, so they can safely be modified if (c->sliceDir == 1) { // slices go from top to bottom @@ -1235,8 +1304,8 @@ int attribute_align_arg sws_scale(struct SwsContext *c, if (srcSliceY + srcSliceH == c->srcH) c->sliceDir = 0; - return c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2, - dstStride2); + ret = c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2, + dstStride2); } else { // slices go from bottom to top => we flip the image internally int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2], @@ -1261,9 +1330,12 @@ int attribute_align_arg sws_scale(struct SwsContext *c, if (!srcSliceY) c->sliceDir = 0; - return c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH, - srcSliceH, dst2, dstStride2); + ret = c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH, + srcSliceH, dst2, dstStride2); } + + av_freep(&tmp); + return ret; } /* Convert the palette to the same packed 32-bit format as the palette */ diff --git a/libswscale/utils.c b/libswscale/utils.c index 6bbdb64..8b9adbd 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -170,6 +170,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_GBRP10BE] = { 1, 1 }, [AV_PIX_FMT_GBRP16LE] = { 1, 0 }, [AV_PIX_FMT_GBRP16BE] = { 1, 0 }, + [AV_PIX_FMT_XYZ12LE] = { 1, 0 }, + [AV_PIX_FMT_XYZ12BE] = { 1, 0 }, }; int sws_isSupportedInput(enum AVPixelFormat pix_fmt) @@ -772,6 +774,26 @@ static void getSubSampleFactors(int *h, int *v, enum AVPixelFormat format) *v = desc->log2_chroma_h; } + +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) @@ -786,6 +808,9 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], c->saturation = saturation; c->srcRange = srcRange; c->dstRange = dstRange; + + fill_xyztables(c); + if (isYUV(c->dstFormat) || isGray(c->dstFormat)) return -1; @@ -852,6 +877,16 @@ SwsContext *sws_alloc_context(void) return c; } + +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; + } +} + av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter) { @@ -879,6 +914,9 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, unscaled = (srcW == dstW && srcH == dstH); + handle_xyz(&srcFormat); + handle_xyz(&dstFormat); + if (!sws_isSupportedInput(srcFormat)) { av_log(c, AV_LOG_ERROR, "%s is not supported as input pixel format\n", sws_format_name(srcFormat)); @@ -1310,6 +1348,8 @@ SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, c->dstH = dstH; c->srcRange = handle_jpeg(&srcFormat); c->dstRange = handle_jpeg(&dstFormat); + c->src_xyz = handle_xyz(&srcFormat); + c->dst_xyz = handle_xyz(&dstFormat); c->srcFormat = srcFormat; c->dstFormat = dstFormat; @@ -1737,10 +1777,12 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW, context->srcW = srcW; context->srcH = srcH; context->srcRange = handle_jpeg(&srcFormat); + context->src_xyz = handle_xyz(&srcFormat); context->srcFormat = srcFormat; context->dstW = dstW; context->dstH = dstH; context->dstRange = handle_jpeg(&dstFormat); + context->dst_xyz = handle_xyz(&dstFormat); context->dstFormat = dstFormat; context->flags = flags; context->param[0] = param[0]; -- 1.7.10.4 _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
