On Fri, May 03, 2013 at 11:14:08AM +0200, Anton Khirnov wrote: > From: Michael Niedermayer <[email protected]> > > The implementation is heavily based on Matthias Buercher's and Nicolas > Bertrand's vf_xyz2rgb
s/implementation/very dirty hack/ > 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); looks wrong because it should use full range > + } > + } > + 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]; > -- I was too optimistic - it's not a dirty hack, it's so ugly that it makes overall SwScaler 3-5% uglier. _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
