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

Reply via email to