Browse code

avfilter: add unpremultiply filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2017/08/01 18:32:22
Showing 6 changed files
... ...
@@ -29,6 +29,7 @@ version <next>:
29 29
 - limiter video filter
30 30
 - libvmaf video filter
31 31
 - Dolby E decoder and SMPTE 337M demuxer
32
+- unpremultiply video filter
32 33
 
33 34
 version 3.3:
34 35
 - CrystalHD decoder moved to new decode API
... ...
@@ -14532,6 +14532,25 @@ ffmpeg -i INPUT -vf trim=duration=1
14532 14532
 
14533 14533
 @end itemize
14534 14534
 
14535
+@section unpremultiply
14536
+Apply alpha unpremultiply effect to input video stream using first plane
14537
+of second stream as alpha.
14538
+
14539
+Both streams must have same dimensions and same pixel format.
14540
+
14541
+The filter accepts the following option:
14542
+
14543
+@table @option
14544
+@item planes
14545
+Set which planes will be processed, unprocessed planes will be copied.
14546
+By default value 0xf, all planes will be processed.
14547
+
14548
+If the format has 1 or 2 components, then luma is bit 0.
14549
+If the format has 3 or 4 components:
14550
+for RGB formats bit 0 is green, bit 1 is blue and bit 2 is red;
14551
+for YUV formats bit 0 is luma, bit 1 is chroma-U and bit 2 is chroma-V.
14552
+If present, the alpha channel is always the last bit.
14553
+@end table
14535 14554
 
14536 14555
 @anchor{unsharp}
14537 14556
 @section unsharp
... ...
@@ -314,6 +314,7 @@ OBJS-$(CONFIG_TILE_FILTER)                   += vf_tile.o
314 314
 OBJS-$(CONFIG_TINTERLACE_FILTER)             += vf_tinterlace.o
315 315
 OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
316 316
 OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
317
+OBJS-$(CONFIG_UNPREMULTIPLY_FILTER)          += vf_premultiply.o framesync2.o
317 318
 OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
318 319
 OBJS-$(CONFIG_USPP_FILTER)                   += vf_uspp.o
319 320
 OBJS-$(CONFIG_VAGUEDENOISER_FILTER)          += vf_vaguedenoiser.o
... ...
@@ -325,6 +325,7 @@ static void register_all(void)
325 325
     REGISTER_FILTER(TINTERLACE,     tinterlace,     vf);
326 326
     REGISTER_FILTER(TRANSPOSE,      transpose,      vf);
327 327
     REGISTER_FILTER(TRIM,           trim,           vf);
328
+    REGISTER_FILTER(UNPREMULTIPLY,  unpremultiply,  vf);
328 329
     REGISTER_FILTER(UNSHARP,        unsharp,        vf);
329 330
     REGISTER_FILTER(USPP,           uspp,           vf);
330 331
     REGISTER_FILTER(VAGUEDENOISER,  vaguedenoiser,  vf);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   6
33
-#define LIBAVFILTER_VERSION_MINOR  95
33
+#define LIBAVFILTER_VERSION_MINOR  96
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
... ...
@@ -33,7 +33,8 @@ typedef struct PreMultiplyContext {
33 33
     int linesize[4];
34 34
     int nb_planes;
35 35
     int planes;
36
-    int half, depth, offset;
36
+    int inverse;
37
+    int half, depth, offset, max;
37 38
     FFFrameSync fs;
38 39
 
39 40
     void (*premultiply[4])(const uint8_t *msrc, const uint8_t *asrc,
... ...
@@ -47,11 +48,12 @@ typedef struct PreMultiplyContext {
47 47
 #define OFFSET(x) offsetof(PreMultiplyContext, x)
48 48
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
49 49
 
50
-static const AVOption premultiply_options[] = {
50
+static const AVOption options[] = {
51 51
     { "planes", "set planes", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=0xF}, 0, 0xF, FLAGS },
52 52
     { NULL }
53 53
 };
54 54
 
55
+#define premultiply_options options
55 56
 AVFILTER_DEFINE_CLASS(premultiply);
56 57
 
57 58
 static int query_formats(AVFilterContext *ctx)
... ...
@@ -199,6 +201,153 @@ static void premultiply16offset(const uint8_t *mmsrc, const uint8_t *aasrc,
199 199
     }
200 200
 }
201 201
 
202
+static void unpremultiply8(const uint8_t *msrc, const uint8_t *asrc,
203
+                           uint8_t *dst,
204
+                           ptrdiff_t mlinesize, ptrdiff_t alinesize,
205
+                           ptrdiff_t dlinesize,
206
+                           int w, int h,
207
+                           int half, int max, int offset)
208
+{
209
+    int x, y;
210
+
211
+    for (y = 0; y < h; y++) {
212
+        for (x = 0; x < w; x++) {
213
+            if (asrc[x] > 0 && asrc[x] < 255)
214
+                dst[x] = FFMIN(msrc[x] * 255 / asrc[x], 255);
215
+            else
216
+                dst[x] = msrc[x];
217
+        }
218
+
219
+        dst  += dlinesize;
220
+        msrc += mlinesize;
221
+        asrc += alinesize;
222
+    }
223
+}
224
+
225
+static void unpremultiply8yuv(const uint8_t *msrc, const uint8_t *asrc,
226
+                              uint8_t *dst,
227
+                              ptrdiff_t mlinesize, ptrdiff_t alinesize,
228
+                              ptrdiff_t dlinesize,
229
+                              int w, int h,
230
+                              int half, int max, int offset)
231
+{
232
+    int x, y;
233
+
234
+    for (y = 0; y < h; y++) {
235
+        for (x = 0; x < w; x++) {
236
+            if (asrc[x] > 0 && asrc[x] < 255)
237
+                dst[x] = FFMIN((msrc[x] - 128) * 255 / asrc[x] + 128, 255);
238
+            else
239
+                dst[x] = msrc[x];
240
+        }
241
+
242
+        dst  += dlinesize;
243
+        msrc += mlinesize;
244
+        asrc += alinesize;
245
+    }
246
+}
247
+
248
+static void unpremultiply8offset(const uint8_t *msrc, const uint8_t *asrc,
249
+                                 uint8_t *dst,
250
+                                 ptrdiff_t mlinesize, ptrdiff_t alinesize,
251
+                                 ptrdiff_t dlinesize,
252
+                                 int w, int h,
253
+                                 int half, int max, int offset)
254
+{
255
+    int x, y;
256
+
257
+    for (y = 0; y < h; y++) {
258
+        for (x = 0; x < w; x++) {
259
+            if (asrc[x] > 0 && asrc[x] < 255)
260
+                dst[x] = FFMIN((msrc[x] - offset) * 255 / asrc[x] + offset, 255);
261
+            else
262
+                dst[x] = msrc[x];
263
+        }
264
+
265
+        dst  += dlinesize;
266
+        msrc += mlinesize;
267
+        asrc += alinesize;
268
+    }
269
+}
270
+
271
+static void unpremultiply16(const uint8_t *mmsrc, const uint8_t *aasrc,
272
+                            uint8_t *ddst,
273
+                            ptrdiff_t mlinesize, ptrdiff_t alinesize,
274
+                            ptrdiff_t dlinesize,
275
+                            int w, int h,
276
+                            int half, int max, int offset)
277
+{
278
+    const uint16_t *msrc = (const uint16_t *)mmsrc;
279
+    const uint16_t *asrc = (const uint16_t *)aasrc;
280
+    uint16_t *dst = (uint16_t *)ddst;
281
+    int x, y;
282
+
283
+    for (y = 0; y < h; y++) {
284
+        for (x = 0; x < w; x++) {
285
+            if (asrc[x] > 0 && asrc[x] < max)
286
+                dst[x] = FFMIN(msrc[x] * (unsigned)max / asrc[x], max);
287
+            else
288
+                dst[x] = msrc[x];
289
+        }
290
+
291
+        dst  += dlinesize / 2;
292
+        msrc += mlinesize / 2;
293
+        asrc += alinesize / 2;
294
+    }
295
+}
296
+
297
+static void unpremultiply16yuv(const uint8_t *mmsrc, const uint8_t *aasrc,
298
+                               uint8_t *ddst,
299
+                               ptrdiff_t mlinesize, ptrdiff_t alinesize,
300
+                               ptrdiff_t dlinesize,
301
+                               int w, int h,
302
+                               int half, int max, int offset)
303
+{
304
+    const uint16_t *msrc = (const uint16_t *)mmsrc;
305
+    const uint16_t *asrc = (const uint16_t *)aasrc;
306
+    uint16_t *dst = (uint16_t *)ddst;
307
+    int x, y;
308
+
309
+    for (y = 0; y < h; y++) {
310
+        for (x = 0; x < w; x++) {
311
+            if (asrc[x] > 0 && asrc[x] < max)
312
+                dst[x] = FFMAX(FFMIN((msrc[x] - half) * max / asrc[x], half - 1), -half) + half;
313
+            else
314
+                dst[x] = msrc[x];
315
+        }
316
+
317
+        dst  += dlinesize / 2;
318
+        msrc += mlinesize / 2;
319
+        asrc += alinesize / 2;
320
+    }
321
+}
322
+
323
+static void unpremultiply16offset(const uint8_t *mmsrc, const uint8_t *aasrc,
324
+                                  uint8_t *ddst,
325
+                                  ptrdiff_t mlinesize, ptrdiff_t alinesize,
326
+                                  ptrdiff_t dlinesize,
327
+                                  int w, int h,
328
+                                  int half, int max, int offset)
329
+{
330
+    const uint16_t *msrc = (const uint16_t *)mmsrc;
331
+    const uint16_t *asrc = (const uint16_t *)aasrc;
332
+    uint16_t *dst = (uint16_t *)ddst;
333
+    int x, y;
334
+
335
+    for (y = 0; y < h; y++) {
336
+        for (x = 0; x < w; x++) {
337
+            if (asrc[x] > 0 && asrc[x] < max)
338
+                dst[x] = FFMAX(FFMIN((msrc[x] - offset) * (unsigned)max / asrc[x] + offset, max), 0);
339
+            else
340
+                dst[x] = msrc[x];
341
+        }
342
+
343
+        dst  += dlinesize / 2;
344
+        msrc += mlinesize / 2;
345
+        asrc += alinesize / 2;
346
+    }
347
+}
348
+
202 349
 static int process_frame(FFFrameSync *fs)
203 350
 {
204 351
     AVFilterContext *ctx = fs->parent;
... ...
@@ -226,48 +375,80 @@ static int process_frame(FFFrameSync *fs)
226 226
         full = base->color_range == AVCOL_RANGE_JPEG;
227 227
         limited = base->color_range == AVCOL_RANGE_MPEG;
228 228
 
229
-        switch (outlink->format) {
230
-        case AV_PIX_FMT_YUV444P:
231
-            s->premultiply[0] = full ? premultiply8 : premultiply8offset;
232
-            s->premultiply[1] = premultiply8yuv;
233
-            s->premultiply[2] = premultiply8yuv;
234
-            break;
235
-        case AV_PIX_FMT_YUVJ444P:
236
-            s->premultiply[0] = premultiply8;
237
-            s->premultiply[1] = premultiply8yuv;
238
-            s->premultiply[2] = premultiply8yuv;
239
-            break;
240
-        case AV_PIX_FMT_GBRP:
241
-            s->premultiply[0] = limited ? premultiply8offset : premultiply8;
242
-            s->premultiply[1] = limited ? premultiply8offset : premultiply8;
243
-            s->premultiply[2] = limited ? premultiply8offset : premultiply8;
244
-            break;
245
-        case AV_PIX_FMT_YUV444P9:
246
-        case AV_PIX_FMT_YUV444P10:
247
-        case AV_PIX_FMT_YUV444P12:
248
-        case AV_PIX_FMT_YUV444P14:
249
-        case AV_PIX_FMT_YUV444P16:
250
-            s->premultiply[0] = full ? premultiply16 : premultiply16offset;
251
-            s->premultiply[1] = premultiply16yuv;
252
-            s->premultiply[2] = premultiply16yuv;
253
-            break;
254
-        case AV_PIX_FMT_GBRP9:
255
-        case AV_PIX_FMT_GBRP10:
256
-        case AV_PIX_FMT_GBRP12:
257
-        case AV_PIX_FMT_GBRP14:
258
-        case AV_PIX_FMT_GBRP16:
259
-            s->premultiply[0] = limited ? premultiply16offset : premultiply16;
260
-            s->premultiply[1] = limited ? premultiply16offset : premultiply16;
261
-            s->premultiply[2] = limited ? premultiply16offset : premultiply16;
262
-            break;
263
-        case AV_PIX_FMT_GRAY8:
264
-            s->premultiply[0] = limited ? premultiply8offset : premultiply8;
265
-            break;
266
-        case AV_PIX_FMT_GRAY10:
267
-        case AV_PIX_FMT_GRAY12:
268
-        case AV_PIX_FMT_GRAY16:
269
-            s->premultiply[0] = limited ? premultiply16offset : premultiply16;
270
-            break;
229
+        if (s->inverse) {
230
+            switch (outlink->format) {
231
+            case AV_PIX_FMT_YUV444P:
232
+                s->premultiply[0] = full ? unpremultiply8 : unpremultiply8offset;
233
+                s->premultiply[1] = s->premultiply[2] = unpremultiply8yuv;
234
+                break;
235
+            case AV_PIX_FMT_YUVJ444P:
236
+                s->premultiply[0] = unpremultiply8;
237
+                s->premultiply[1] = s->premultiply[2] = unpremultiply8yuv;
238
+                break;
239
+            case AV_PIX_FMT_GBRP:
240
+                s->premultiply[0] = s->premultiply[1] = s->premultiply[2] = limited ? unpremultiply8offset : unpremultiply8;
241
+                break;
242
+            case AV_PIX_FMT_YUV444P9:
243
+            case AV_PIX_FMT_YUV444P10:
244
+            case AV_PIX_FMT_YUV444P12:
245
+            case AV_PIX_FMT_YUV444P14:
246
+            case AV_PIX_FMT_YUV444P16:
247
+                s->premultiply[0] = full ? unpremultiply16 : unpremultiply16offset;
248
+                s->premultiply[1] = s->premultiply[2] = unpremultiply16yuv;
249
+                break;
250
+            case AV_PIX_FMT_GBRP9:
251
+            case AV_PIX_FMT_GBRP10:
252
+            case AV_PIX_FMT_GBRP12:
253
+            case AV_PIX_FMT_GBRP14:
254
+            case AV_PIX_FMT_GBRP16:
255
+                s->premultiply[0] = s->premultiply[1] = s->premultiply[2] = limited ? unpremultiply16offset : unpremultiply16;
256
+                break;
257
+            case AV_PIX_FMT_GRAY8:
258
+                s->premultiply[0] = limited ? unpremultiply8offset : unpremultiply8;
259
+                break;
260
+            case AV_PIX_FMT_GRAY10:
261
+            case AV_PIX_FMT_GRAY12:
262
+            case AV_PIX_FMT_GRAY16:
263
+                s->premultiply[0] = limited ? unpremultiply16offset : unpremultiply16;
264
+                break;
265
+            }
266
+        } else {
267
+            switch (outlink->format) {
268
+            case AV_PIX_FMT_YUV444P:
269
+                s->premultiply[0] = full ? premultiply8 : premultiply8offset;
270
+                s->premultiply[1] = s->premultiply[2] = premultiply8yuv;
271
+                break;
272
+            case AV_PIX_FMT_YUVJ444P:
273
+                s->premultiply[0] = premultiply8;
274
+                s->premultiply[1] = s->premultiply[2] = premultiply8yuv;
275
+                break;
276
+            case AV_PIX_FMT_GBRP:
277
+                s->premultiply[0] = s->premultiply[1] = s->premultiply[2] = limited ? premultiply8offset : premultiply8;
278
+                break;
279
+            case AV_PIX_FMT_YUV444P9:
280
+            case AV_PIX_FMT_YUV444P10:
281
+            case AV_PIX_FMT_YUV444P12:
282
+            case AV_PIX_FMT_YUV444P14:
283
+            case AV_PIX_FMT_YUV444P16:
284
+                s->premultiply[0] = full ? premultiply16 : premultiply16offset;
285
+                s->premultiply[1] = s->premultiply[2] = premultiply16yuv;
286
+                break;
287
+            case AV_PIX_FMT_GBRP9:
288
+            case AV_PIX_FMT_GBRP10:
289
+            case AV_PIX_FMT_GBRP12:
290
+            case AV_PIX_FMT_GBRP14:
291
+            case AV_PIX_FMT_GBRP16:
292
+                s->premultiply[0] = s->premultiply[1] = s->premultiply[2] = limited ? premultiply16offset : premultiply16;
293
+                break;
294
+            case AV_PIX_FMT_GRAY8:
295
+                s->premultiply[0] = limited ? premultiply8offset : premultiply8;
296
+                break;
297
+            case AV_PIX_FMT_GRAY10:
298
+            case AV_PIX_FMT_GRAY12:
299
+            case AV_PIX_FMT_GRAY16:
300
+                s->premultiply[0] = limited ? premultiply16offset : premultiply16;
301
+                break;
302
+            }
271 303
         }
272 304
 
273 305
         for (p = 0; p < s->nb_planes; p++) {
... ...
@@ -282,7 +463,7 @@ static int process_frame(FFFrameSync *fs)
282 282
                               base->linesize[p], alpha->linesize[0],
283 283
                               out->linesize[p],
284 284
                               s->width[p], s->height[p],
285
-                              s->half, s->depth, s->offset);
285
+                              s->half, s->inverse ? s->max : s->depth, s->offset);
286 286
         }
287 287
     }
288 288
     out->pts = av_rescale_q(base->pts, s->fs.time_base, outlink->time_base);
... ...
@@ -310,6 +491,7 @@ static int config_input(AVFilterLink *inlink)
310 310
     s->width[0]  = s->width[3]  = inlink->w;
311 311
 
312 312
     s->depth = desc->comp[0].depth;
313
+    s->max = (1 << s->depth) - 1;
313 314
     s->half = (1 << s->depth) / 2;
314 315
     s->offset = 16 << (s->depth - 8);
315 316
 
... ...
@@ -369,6 +551,16 @@ static int activate(AVFilterContext *ctx)
369 369
     return ff_framesync2_activate(&s->fs);
370 370
 }
371 371
 
372
+static av_cold int init(AVFilterContext *ctx)
373
+{
374
+    PreMultiplyContext *s = ctx->priv;
375
+
376
+    if (!strcmp(ctx->filter->name, "unpremultiply"))
377
+        s->inverse = 1;
378
+
379
+    return 0;
380
+}
381
+
372 382
 static av_cold void uninit(AVFilterContext *ctx)
373 383
 {
374 384
     PreMultiplyContext *s = ctx->priv;
... ...
@@ -398,6 +590,8 @@ static const AVFilterPad premultiply_outputs[] = {
398 398
     { NULL }
399 399
 };
400 400
 
401
+#if CONFIG_PREMULTIPLY_FILTER
402
+
401 403
 AVFilter ff_vf_premultiply = {
402 404
     .name          = "premultiply",
403 405
     .description   = NULL_IF_CONFIG_SMALL("PreMultiply first stream with first plane of second stream."),
... ...
@@ -410,3 +604,26 @@ AVFilter ff_vf_premultiply = {
410 410
     .priv_class    = &premultiply_class,
411 411
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
412 412
 };
413
+
414
+#endif /* CONFIG_PREMULTIPLY_FILTER */
415
+
416
+#if CONFIG_UNPREMULTIPLY_FILTER
417
+
418
+#define unpremultiply_options options
419
+AVFILTER_DEFINE_CLASS(unpremultiply);
420
+
421
+AVFilter ff_vf_unpremultiply = {
422
+    .name          = "unpremultiply",
423
+    .description   = NULL_IF_CONFIG_SMALL("UnPreMultiply first stream with first plane of second stream."),
424
+    .priv_size     = sizeof(PreMultiplyContext),
425
+    .init          = init,
426
+    .uninit        = uninit,
427
+    .query_formats = query_formats,
428
+    .activate      = activate,
429
+    .inputs        = premultiply_inputs,
430
+    .outputs       = premultiply_outputs,
431
+    .priv_class    = &unpremultiply_class,
432
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
433
+};
434
+
435
+#endif /* CONFIG_UNPREMULTIPLY_FILTER */