Browse code

vf_overlay: enable RGB path

Add option rgb which forces the RGB path.

Stefano Sabatini authored on 2011/10/29 07:10:43
Showing 2 changed files
... ...
@@ -1631,10 +1631,10 @@ Overlay one video on top of another.
1631 1631
 It takes two inputs and one output, the first input is the "main"
1632 1632
 video on which the second input is overlayed.
1633 1633
 
1634
-It accepts the parameters: @var{x}:@var{y}.
1634
+It accepts the parameters: @var{x}:@var{y}[:@var{options}].
1635 1635
 
1636 1636
 @var{x} is the x coordinate of the overlayed video on the main video,
1637
-@var{y} is the y coordinate. The parameters are expressions containing
1637
+@var{y} is the y coordinate. @var{x} and @var{y} are expressions containing
1638 1638
 the following parameters:
1639 1639
 
1640 1640
 @table @option
... ...
@@ -1651,6 +1651,17 @@ overlay input width and height
1651 1651
 same as @var{overlay_w} and @var{overlay_h}
1652 1652
 @end table
1653 1653
 
1654
+@var{options} is an optional list of @var{key}=@var{value} pairs,
1655
+separated by ":".
1656
+
1657
+The description of the accepted options follows.
1658
+
1659
+@table @option
1660
+@item rgb
1661
+If set to 1, force the filter to accept inputs in the RGB
1662
+colorspace. Default value is 0.
1663
+@end table
1664
+
1654 1665
 Be aware that frames are taken from each input video in timestamp
1655 1666
 order, hence, if their initial timestamps differ, it is a a good idea
1656 1667
 to pass the two inputs through a @var{setpts=PTS-STARTPTS} filter to
... ...
@@ -33,6 +33,7 @@
33 33
 #include "libavutil/imgutils.h"
34 34
 #include "libavutil/mathematics.h"
35 35
 #include "internal.h"
36
+#include "drawutils.h"
36 37
 
37 38
 static const char *var_names[] = {
38 39
     "main_w",    "W", ///< width  of the main    video
... ...
@@ -53,13 +54,31 @@ enum var_name {
53 53
 #define MAIN    0
54 54
 #define OVERLAY 1
55 55
 
56
+#define R 0
57
+#define G 1
58
+#define B 2
59
+#define A 3
60
+
61
+#define Y 0
62
+#define U 1
63
+#define V 2
64
+
56 65
 typedef struct {
57 66
     const AVClass *class;
58 67
     int x, y;                   ///< position of overlayed picture
59 68
 
69
+    int allow_packed_rgb;
70
+    uint8_t main_is_packed_rgb;
71
+    uint8_t main_rgba_map[4];
72
+    uint8_t main_has_alpha;
73
+    uint8_t overlay_is_packed_rgb;
74
+    uint8_t overlay_rgba_map[4];
75
+    uint8_t overlay_has_alpha;
76
+
60 77
     AVFilterBufferRef *overpicref;
61 78
 
62
-    int max_plane_step[4];      ///< steps per pixel for each plane
79
+    int main_pix_step[4];       ///< steps per pixel for each plane of the main output
80
+    int overlay_pix_step[4];    ///< steps per pixel for each plane of the overlay
63 81
     int hsub, vsub;             ///< chroma subsampling values
64 82
 
65 83
     char *x_expr, *y_expr;
... ...
@@ -70,6 +89,7 @@ typedef struct {
70 70
 static const AVOption overlay_options[] = {
71 71
     { "x", "set the x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX },
72 72
     { "y", "set the y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX },
73
+    {"rgb", "force packed RGB in input and output", OFFSET(allow_packed_rgb), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
73 74
     {NULL},
74 75
 };
75 76
 
... ...
@@ -128,27 +148,59 @@ static av_cold void uninit(AVFilterContext *ctx)
128 128
 
129 129
 static int query_formats(AVFilterContext *ctx)
130 130
 {
131
-    const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_YUV420P,  PIX_FMT_NONE };
132
-    const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_YUVA420P, PIX_FMT_NONE };
133
-    AVFilterFormats *inout_formats = avfilter_make_format_list(inout_pix_fmts);
134
-    AVFilterFormats *blend_formats = avfilter_make_format_list(blend_pix_fmts);
131
+    OverlayContext *over = ctx->priv;
135 132
 
136
-    avfilter_formats_ref(inout_formats, &ctx->inputs [MAIN   ]->out_formats);
137
-    avfilter_formats_ref(blend_formats, &ctx->inputs [OVERLAY]->out_formats);
138
-    avfilter_formats_ref(inout_formats, &ctx->outputs[MAIN   ]->in_formats );
133
+    /* overlay formats contains alpha, for avoiding conversion with alpha information loss */
134
+    const enum PixelFormat main_pix_fmts_yuv[] = { PIX_FMT_YUV420P,  PIX_FMT_NONE };
135
+    const enum PixelFormat overlay_pix_fmts_yuv[] = { PIX_FMT_YUVA420P, PIX_FMT_NONE };
136
+    const enum PixelFormat main_pix_fmts_rgb[] = {
137
+        PIX_FMT_ARGB,  PIX_FMT_RGBA,
138
+        PIX_FMT_ABGR,  PIX_FMT_BGRA,
139
+        PIX_FMT_RGB24, PIX_FMT_BGR24,
140
+        PIX_FMT_NONE
141
+    };
142
+    const enum PixelFormat overlay_pix_fmts_rgb[] = {
143
+        PIX_FMT_ARGB,  PIX_FMT_RGBA,
144
+        PIX_FMT_ABGR,  PIX_FMT_BGRA,
145
+        PIX_FMT_NONE
146
+    };
147
+
148
+    AVFilterFormats *main_formats;
149
+    AVFilterFormats *overlay_formats;
150
+
151
+    if (over->allow_packed_rgb) {
152
+        main_formats    = avfilter_make_format_list(main_pix_fmts_rgb);
153
+        overlay_formats = avfilter_make_format_list(overlay_pix_fmts_rgb);
154
+    } else {
155
+        main_formats    = avfilter_make_format_list(main_pix_fmts_yuv);
156
+        overlay_formats = avfilter_make_format_list(overlay_pix_fmts_yuv);
157
+    }
158
+
159
+    avfilter_formats_ref(main_formats,    &ctx->inputs [MAIN   ]->out_formats);
160
+    avfilter_formats_ref(overlay_formats, &ctx->inputs [OVERLAY]->out_formats);
161
+    avfilter_formats_ref(main_formats,    &ctx->outputs[MAIN   ]->in_formats );
139 162
 
140 163
     return 0;
141 164
 }
142 165
 
166
+static enum PixelFormat alpha_pix_fmts[] = {
167
+    PIX_FMT_YUVA420P, PIX_FMT_ARGB, PIX_FMT_ABGR, PIX_FMT_RGBA,
168
+    PIX_FMT_BGRA, PIX_FMT_NONE
169
+};
170
+
143 171
 static int config_input_main(AVFilterLink *inlink)
144 172
 {
145 173
     OverlayContext *over = inlink->dst->priv;
146 174
     const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format];
147 175
 
148
-    av_image_fill_max_pixsteps(over->max_plane_step, NULL, pix_desc);
176
+    av_image_fill_max_pixsteps(over->main_pix_step,    NULL, pix_desc);
177
+
149 178
     over->hsub = pix_desc->log2_chroma_w;
150 179
     over->vsub = pix_desc->log2_chroma_h;
151 180
 
181
+    over->main_is_packed_rgb =
182
+        ff_fill_rgba_map(over->main_rgba_map, inlink->format) >= 0;
183
+    over->main_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
152 184
     return 0;
153 185
 }
154 186
 
... ...
@@ -159,6 +211,9 @@ static int config_input_overlay(AVFilterLink *inlink)
159 159
     char *expr;
160 160
     double var_values[VAR_VARS_NB], res;
161 161
     int ret;
162
+    const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format];
163
+
164
+    av_image_fill_max_pixsteps(over->overlay_pix_step, NULL, pix_desc);
162 165
 
163 166
     /* Finish the configuration by evaluating the expressions
164 167
        now when both inputs are configured. */
... ...
@@ -181,6 +236,10 @@ static int config_input_overlay(AVFilterLink *inlink)
181 181
         goto fail;
182 182
     over->x = res;
183 183
 
184
+    over->overlay_is_packed_rgb =
185
+        ff_fill_rgba_map(over->overlay_rgba_map, inlink->format) >= 0;
186
+    over->overlay_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
187
+
184 188
     av_log(ctx, AV_LOG_INFO,
185 189
            "main w:%d h:%d fmt:%s overlay x:%d y:%d w:%d h:%d fmt:%s\n",
186 190
            ctx->inputs[MAIN]->w, ctx->inputs[MAIN]->h,
... ...
@@ -272,6 +331,10 @@ static void start_frame_overlay(AVFilterLink *inlink, AVFilterBufferRef *inpicre
272 272
                                          ctx->outputs[0]->time_base);
273 273
 }
274 274
 
275
+// divide by 255 and round to nearest
276
+// apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
277
+#define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
278
+
275 279
 static void blend_slice(AVFilterContext *ctx,
276 280
                         AVFilterBufferRef *dst, AVFilterBufferRef *src,
277 281
                         int x, int y, int w, int h,
... ...
@@ -289,21 +352,43 @@ static void blend_slice(AVFilterContext *ctx,
289 289
     start_y = FFMAX(y, slice_y);
290 290
     height = end_y - start_y;
291 291
 
292
-    if (dst->format == PIX_FMT_BGR24 || dst->format == PIX_FMT_RGB24) {
293
-        uint8_t *dp = dst->data[0] + x * 3 + start_y * dst->linesize[0];
292
+    if (over->main_is_packed_rgb) {
293
+        uint8_t *dp = dst->data[0] + x * over->main_pix_step[0] +
294
+                      start_y * dst->linesize[0];
294 295
         uint8_t *sp = src->data[0];
295
-        int b = dst->format == PIX_FMT_BGR24 ? 2 : 0;
296
-        int r = dst->format == PIX_FMT_BGR24 ? 0 : 2;
296
+        uint8_t alpha;          ///< the amount of overlay to blend on to main
297
+        const int dr = over->main_rgba_map[R];
298
+        const int dg = over->main_rgba_map[G];
299
+        const int db = over->main_rgba_map[B];
300
+        const int dstep = over->main_pix_step[0];
301
+        const int sr = over->overlay_rgba_map[R];
302
+        const int sg = over->overlay_rgba_map[G];
303
+        const int sb = over->overlay_rgba_map[B];
304
+        const int sa = over->overlay_rgba_map[A];
305
+        const int sstep = over->overlay_pix_step[0];
297 306
         if (slice_y > y)
298 307
             sp += (slice_y - y) * src->linesize[0];
299 308
         for (i = 0; i < height; i++) {
300 309
             uint8_t *d = dp, *s = sp;
301 310
             for (j = 0; j < width; j++) {
302
-                d[r] = (d[r] * (0xff - s[3]) + s[0] * s[3] + 128) >> 8;
303
-                d[1] = (d[1] * (0xff - s[3]) + s[1] * s[3] + 128) >> 8;
304
-                d[b] = (d[b] * (0xff - s[3]) + s[2] * s[3] + 128) >> 8;
305
-                d += 3;
306
-                s += 4;
311
+                alpha = s[sa];
312
+                switch (alpha) {
313
+                case 0:
314
+                    break;
315
+                case 255:
316
+                    d[dr] = s[sr];
317
+                    d[dg] = s[sg];
318
+                    d[db] = s[sb];
319
+                    break;
320
+                default:
321
+                    // main_value = main_value * (1 - alpha) + overlay_value * alpha
322
+                    // since alpha is in the range 0-255, the result must divided by 255
323
+                    d[dr] = FAST_DIV255(d[dr] * (255 - alpha) + s[sr] * alpha);
324
+                    d[dg] = FAST_DIV255(d[dg] * (255 - alpha) + s[sg] * alpha);
325
+                    d[db] = FAST_DIV255(d[db] * (255 - alpha) + s[sb] * alpha);
326
+                }
327
+                d += dstep;
328
+                s += sstep;
307 329
             }
308 330
             dp += dst->linesize[0];
309 331
             sp += src->linesize[0];