]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_lut.c
Merge commit '6b15874fc2c3f565732201f7907ae1112727d6ae'
[ffmpeg] / libavfilter / vf_lut.c
index 93b18a82cb04028b3b93dafb0943c1c5c773d2d2..3f0524daaf472efa91208af91dc8fb5fc800274a 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "libavutil/attributes.h"
+#include "libavutil/bswap.h"
 #include "libavutil/common.h"
 #include "libavutil/eval.h"
 #include "libavutil/opt.h"
@@ -59,12 +60,13 @@ enum var_name {
 
 typedef struct LutContext {
     const AVClass *class;
-    uint8_t lut[4][256];  ///< lookup table for each component
+    uint16_t lut[4][256 * 256];  ///< lookup table for each component
     char   *comp_expr_str[4];
     AVExpr *comp_expr[4];
     int hsub, vsub;
     double var_values[VAR_VARS_NB];
     int is_rgb, is_yuv;
+    int is_16bit;
     int step;
     int negate_alpha; /* only used by negate */
 } LutContext;
@@ -112,7 +114,13 @@ static av_cold void uninit(AVFilterContext *ctx)
     AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUV440P,    \
     AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,   \
     AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,   \
-    AV_PIX_FMT_YUVJ440P
+    AV_PIX_FMT_YUVJ440P,                                             \
+    AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUV422P9LE, AV_PIX_FMT_YUV420P9LE, \
+    AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV440P10LE, \
+    AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUV422P12LE, AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV440P12LE, \
+    AV_PIX_FMT_YUV444P14LE, AV_PIX_FMT_YUV422P14LE, AV_PIX_FMT_YUV420P14LE, \
+    AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUV420P16LE, \
+    AV_PIX_FMT_YUVA444P16LE, AV_PIX_FMT_YUVA422P16LE, AV_PIX_FMT_YUVA420P16LE
 
 #define RGB_FORMATS                             \
     AV_PIX_FMT_ARGB,         AV_PIX_FMT_RGBA,         \
@@ -205,6 +213,7 @@ static int config_props(AVFilterLink *inlink)
 
     s->var_values[VAR_W] = inlink->w;
     s->var_values[VAR_H] = inlink->h;
+    s->is_16bit = desc->comp[0].depth_minus1 > 7;
 
     switch (inlink->format) {
     case AV_PIX_FMT_YUV410P:
@@ -216,10 +225,40 @@ static int config_props(AVFilterLink *inlink)
     case AV_PIX_FMT_YUVA420P:
     case AV_PIX_FMT_YUVA422P:
     case AV_PIX_FMT_YUVA444P:
-        min[Y] = min[U] = min[V] = 16;
-        max[Y] = 235;
-        max[U] = max[V] = 240;
-        min[A] = 0; max[A] = 255;
+    case AV_PIX_FMT_YUV420P9LE:
+    case AV_PIX_FMT_YUV422P9LE:
+    case AV_PIX_FMT_YUV444P9LE:
+    case AV_PIX_FMT_YUVA420P9LE:
+    case AV_PIX_FMT_YUVA422P9LE:
+    case AV_PIX_FMT_YUVA444P9LE:
+    case AV_PIX_FMT_YUV420P10LE:
+    case AV_PIX_FMT_YUV422P10LE:
+    case AV_PIX_FMT_YUV440P10LE:
+    case AV_PIX_FMT_YUV444P10LE:
+    case AV_PIX_FMT_YUVA420P10LE:
+    case AV_PIX_FMT_YUVA422P10LE:
+    case AV_PIX_FMT_YUVA444P10LE:
+    case AV_PIX_FMT_YUV420P12LE:
+    case AV_PIX_FMT_YUV422P12LE:
+    case AV_PIX_FMT_YUV440P12LE:
+    case AV_PIX_FMT_YUV444P12LE:
+    case AV_PIX_FMT_YUV420P14LE:
+    case AV_PIX_FMT_YUV422P14LE:
+    case AV_PIX_FMT_YUV444P14LE:
+    case AV_PIX_FMT_YUV420P16LE:
+    case AV_PIX_FMT_YUV422P16LE:
+    case AV_PIX_FMT_YUV444P16LE:
+    case AV_PIX_FMT_YUVA420P16LE:
+    case AV_PIX_FMT_YUVA422P16LE:
+    case AV_PIX_FMT_YUVA444P16LE:
+        min[Y] = 16 * (1 << (desc->comp[0].depth_minus1 - 7));
+        min[U] = 16 * (1 << (desc->comp[1].depth_minus1 - 7));
+        min[V] = 16 * (1 << (desc->comp[2].depth_minus1 - 7));
+        min[A] = 0;
+        max[Y] = 235 * (1 << (desc->comp[0].depth_minus1 - 7));
+        max[U] = 240 * (1 << (desc->comp[1].depth_minus1 - 7));
+        max[V] = 240 * (1 << (desc->comp[2].depth_minus1 - 7));
+        max[A] = (1 << (desc->comp[3].depth_minus1 + 1)) - 1;
         break;
     default:
         min[0] = min[1] = min[2] = min[3] = 0;
@@ -255,7 +294,7 @@ static int config_props(AVFilterLink *inlink)
         s->var_values[VAR_MAXVAL] = max[color];
         s->var_values[VAR_MINVAL] = min[color];
 
-        for (val = 0; val < 256; val++) {
+        for (val = 0; val < (1 << (desc->comp[0].depth_minus1 + 1)); val++) {
             s->var_values[VAR_VAL] = val;
             s->var_values[VAR_CLIPVAL] = av_clip(val, min[color], max[color]);
             s->var_values[VAR_NEGVAL] =
@@ -283,7 +322,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     LutContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
     AVFrame *out;
-    uint8_t *inrow, *outrow, *inrow0, *outrow0;
     int i, j, plane, direct = 0;
 
     if (av_frame_is_writable(in)) {
@@ -300,9 +338,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     if (s->is_rgb) {
         /* packed */
+        uint8_t *inrow, *outrow, *inrow0, *outrow0;
         const int w = inlink->w;
         const int h = in->height;
-        const uint8_t (*tab)[256] = (const uint8_t (*)[256])s->lut;
+        const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut;
         const int in_linesize  =  in->linesize[0];
         const int out_linesize = out->linesize[0];
         const int step = s->step;
@@ -326,14 +365,44 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             inrow0  += in_linesize;
             outrow0 += out_linesize;
         }
+    } else if (s->is_16bit) {
+        // planar yuv >8 bit depth
+        uint16_t *inrow, *outrow;
+
+        for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) {
+            int vsub = plane == 1 || plane == 2 ? s->vsub : 0;
+            int hsub = plane == 1 || plane == 2 ? s->hsub : 0;
+            int h = FF_CEIL_RSHIFT(inlink->h, vsub);
+            int w = FF_CEIL_RSHIFT(inlink->w, hsub);
+            const uint16_t *tab = s->lut[plane];
+            const int in_linesize  =  in->linesize[plane] / 2;
+            const int out_linesize = out->linesize[plane] / 2;
+
+            inrow  = (uint16_t *)in ->data[plane];
+            outrow = (uint16_t *)out->data[plane];
+
+            for (i = 0; i < h; i++) {
+                for (j = 0; j < w; j++) {
+#if HAVE_BIGENDIAN
+                    outrow[j] = av_bswap16(tab[av_bswap16(inrow[j])]);
+#else
+                    outrow[j] = tab[inrow[j]];
+#endif
+                }
+                inrow  += in_linesize;
+                outrow += out_linesize;
+            }
+        }
     } else {
-        /* planar */
+        /* planar 8bit depth */
+        uint8_t *inrow, *outrow;
+
         for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) {
             int vsub = plane == 1 || plane == 2 ? s->vsub : 0;
             int hsub = plane == 1 || plane == 2 ? s->hsub : 0;
             int h = FF_CEIL_RSHIFT(inlink->h, vsub);
             int w = FF_CEIL_RSHIFT(inlink->w, hsub);
-            const uint8_t *tab = s->lut[plane];
+            const uint16_t *tab = s->lut[plane];
             const int in_linesize  =  in->linesize[plane];
             const int out_linesize = out->linesize[plane];