History

avfilter/vf_colorkey: add >8 depth support

Paul B Mahol committed 4 years ago

Commit c3f5f1b1 parent 9d20f641 file · +107 −85Browse files

Showing the changes to libavfilter (1 of 1 file). Show all

Unified · Split

libavfilter/vf_colorkey.c+107−85
@@ -23,6 +23,7 @@ · 22 unmodified lines
23#include "libavutil/opt.h"23#include "libavutil/opt.h"
24#include "libavutil/imgutils.h"24#include "libavutil/imgutils.h"
25#include "avfilter.h"25#include "avfilter.h"
26#include "drawutils.h"
26#include "formats.h"27#include "formats.h"
27#include "internal.h"28#include "internal.h"
28#include "video.h"29#include "video.h"
@@ -31,105 +32,120 @@ typedef struct ColorkeyContext { · 2 unmodified lines
31 const AVClass *class;32 const AVClass *class;
32 33
33 /* color offsets rgba */34 /* color offsets rgba */
34 int co[4];35 uint8_t co[4];
35 36
36 uint8_t colorkey_rgba[4];37 uint8_t colorkey_rgba[4];
37 float similarity;38 float similarity;
38 float blend;39 float blend;
40 double scale;
41 int depth;
42 int max;
39 43
40 int (*do_slice)(AVFilterContext *ctx, void *arg,44 int (*do_slice)(AVFilterContext *ctx, void *arg,
41 int jobnr, int nb_jobs);45 int jobnr, int nb_jobs);
42} ColorkeyContext;46} ColorkeyContext;
43 47
44static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b)48static int do_colorkey_pixel(const uint8_t *colorkey_rgba, int r, int g, int b,
49 float similarity, float blend, int max, double scale)
45{50{
46 int dr = (int)r - ctx->colorkey_rgba[0];51 double dr, dg, db, diff;
47 int dg = (int)g - ctx->colorkey_rgba[1];
48 int db = (int)b - ctx->colorkey_rgba[2];
49 52
50 double diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0 * 3.0));53 dr = r * scale - colorkey_rgba[0];
54 dg = g * scale - colorkey_rgba[1];
55 db = b * scale - colorkey_rgba[2];
51 56
52 if (ctx->blend > 0.0001) {57 diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0 * 3.0));
53 return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;58
59 if (blend > 0.0001) {
60 return av_clipd((diff - similarity) / blend, 0.0, 1.0) * max;
54 } else {61 } else {
55 return (diff > ctx->similarity) ? 255 : 0;62 return (diff > similarity) ? max : 0;
56 }63 }
57}64}
58 65
59static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)66#define COLORKEY_SLICE(name, type) \
60{67static int do_colorkey_slice##name(AVFilterContext *avctx, \
61 AVFrame *frame = arg;68 void *arg, \
62 69 int jobnr, int nb_jobs) \
63 const int slice_start = (frame->height * jobnr) / nb_jobs;70{ \
64 const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;71 AVFrame *frame = arg; \
65 72 const int slice_start = (frame->height * jobnr) / nb_jobs; \
66 ColorkeyContext *ctx = avctx->priv;73 const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs; \
67 74 ColorkeyContext *ctx = avctx->priv; \
68 int o, x, y;75 const float similarity = ctx->similarity; \
69 76 const float blend = ctx->blend; \
70 for (y = slice_start; y < slice_end; ++y) {77 const uint8_t *colorkey_rgba = ctx->colorkey_rgba; \
71 for (x = 0; x < frame->width; ++x) {78 const uint8_t *co = ctx->co; \
72 o = frame->linesize[0] * y + x * 4;79 const double scale = ctx->scale; \
73 80 const int max = ctx->max; \
74 frame->data[0][o + ctx->co[3]] =81 \
75 do_colorkey_pixel(ctx,82 for (int y = slice_start; y < slice_end; y++) { \
76 frame->data[0][o + ctx->co[0]],83 type *dst = (type *)(frame->data[0] + y * frame->linesize[0]);\
77 frame->data[0][o + ctx->co[1]],84 \
78 frame->data[0][o + ctx->co[2]]);85 for (int x = 0; x < frame->width; x++) { \
79 }86 const int o = x * 4; \
80 }87 \
81 88 dst[o + co[3]] = do_colorkey_pixel(colorkey_rgba, \
82 return 0;89 dst[o + co[0]], \
90 dst[o + co[1]], \
91 dst[o + co[2]], \
92 similarity, blend, max, scale); \
93 } \
94 } \
95 \
96 return 0; \
83}97}
84 98
85static int do_colorhold_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)99COLORKEY_SLICE(8, uint8_t)
86{100COLORKEY_SLICE(16, uint16_t)
87 AVFrame *frame = arg;101
88 102#define COLORHOLD_SLICE(name, type, htype) \
89 const int slice_start = (frame->height * jobnr) / nb_jobs;103static int do_colorhold_slice##name(AVFilterContext *avctx, void *arg, \
90 const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;104 int jobnr, int nb_jobs) \
91 105{ \
92 ColorkeyContext *ctx = avctx->priv;106 AVFrame *frame = arg; \
93 107 const int slice_start = (frame->height * jobnr) / nb_jobs; \
94 int x, y;108 const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs; \
95 109 ColorkeyContext *ctx = avctx->priv; \
96 for (y = slice_start; y < slice_end; ++y) {110 const int depth = ctx->depth; \
97 for (x = 0; x < frame->width; ++x) {111 const int max = ctx->max; \
98 int o, t, r, g, b;112 const int half = max / 2; \
99 113 const uint8_t *co = ctx->co; \
100 o = frame->linesize[0] * y + x * 4;114 const uint8_t *colorkey_rgba = ctx->colorkey_rgba; \
101 r = frame->data[0][o + ctx->co[0]];115 const float similarity = ctx->similarity; \
102 g = frame->data[0][o + ctx->co[1]];116 const float blend = ctx->blend; \
103 b = frame->data[0][o + ctx->co[2]];117 const double scale = ctx->scale; \
104 118 \
105 t = do_colorkey_pixel(ctx, r, g, b);119 for (int y = slice_start; y < slice_end; ++y) { \
106 120 type *dst = (type *)(frame->data[0] + y * frame->linesize[0]); \
107 if (t > 0) {121 \
108 int a = (r + g + b) / 3;122 for (int x = 0; x < frame->width; ++x) { \
109 int rt = 255 - t;123 int o, t, r, g, b; \
110 124 \
111 frame->data[0][o + ctx->co[0]] = (a * t + r * rt + 127) >> 8;125 o = x * 4; \
112 frame->data[0][o + ctx->co[1]] = (a * t + g * rt + 127) >> 8;126 r = dst[o + co[0]]; \
113 frame->data[0][o + ctx->co[2]] = (a * t + b * rt + 127) >> 8;127 g = dst[o + co[1]]; \
114 }128 b = dst[o + co[2]]; \
115 }129 \
116 }130 t = do_colorkey_pixel(colorkey_rgba, r, g, b, \
117 131 similarity, blend, max, scale); \
118 return 0;132 \
133 if (t > 0) { \
134 htype a = (r + g + b) / 3; \
135 htype rt = max - t; \
136 \
137 dst[o + co[0]] = (a * t + r * rt + half) >> depth; \
138 dst[o + co[1]] = (a * t + g * rt + half) >> depth; \
139 dst[o + co[2]] = (a * t + b * rt + half) >> depth; \
140 } \
141 } \
142 } \
143 \
144 return 0; \
119}145}
120 146
121static av_cold int init_filter(AVFilterContext *avctx)147COLORHOLD_SLICE(8, uint8_t, int)
122{148COLORHOLD_SLICE(16, uint16_t, int64_t)
123 ColorkeyContext *ctx = avctx->priv;
124
125 if (!strcmp(avctx->filter->name, "colorkey")) {
126 ctx->do_slice = do_colorkey_slice;
127 } else {
128 ctx->do_slice = do_colorhold_slice;
129 }
130
131 return 0;
132}
133 149
134static int filter_frame(AVFilterLink *link, AVFrame *frame)150static int filter_frame(AVFilterLink *link, AVFrame *frame)
135{151{
@@ -148,15 +164,21 @@ static av_cold int config_output(AVFilterLink *outlink) · 12 unmodified lines
148{164{
149 AVFilterContext *avctx = outlink->src;165 AVFilterContext *avctx = outlink->src;
150 ColorkeyContext *ctx = avctx->priv;166 ColorkeyContext *ctx = avctx->priv;
151 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);167 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->inputs[0]->format);
152 int i;
153 168
169 ctx->depth = desc->comp[0].depth;
170 ctx->max = (1 << ctx->depth) - 1;
171 ctx->scale = 255.0 / ctx->max;
154 outlink->w = avctx->inputs[0]->w;172 outlink->w = avctx->inputs[0]->w;
155 outlink->h = avctx->inputs[0]->h;173 outlink->h = avctx->inputs[0]->h;
156 outlink->time_base = avctx->inputs[0]->time_base;174 outlink->time_base = avctx->inputs[0]->time_base;
175 ff_fill_rgba_map(ctx->co, outlink->format);
157 176
158 for (i = 0; i < 4; ++i)177 if (!strcmp(avctx->filter->name, "colorkey")) {
159 ctx->co[i] = desc->comp[i].offset;178 ctx->do_slice = ctx->max == 255 ? do_colorkey_slice8 : do_colorkey_slice16;
179 } else {
180 ctx->do_slice = ctx->max == 255 ? do_colorhold_slice8 : do_colorhold_slice16;
181 }
160 182
161 return 0;183 return 0;
162}184}
@@ -166,6 +188,8 @@ static const enum AVPixelFormat pixel_fmts[] = { · 3 unmodified lines
166 AV_PIX_FMT_RGBA,188 AV_PIX_FMT_RGBA,
167 AV_PIX_FMT_ABGR,189 AV_PIX_FMT_ABGR,
168 AV_PIX_FMT_BGRA,190 AV_PIX_FMT_BGRA,
191 AV_PIX_FMT_RGBA64,
192 AV_PIX_FMT_BGRA64,
169 AV_PIX_FMT_NONE193 AV_PIX_FMT_NONE
170};194};
171 195
@@ -205,7 +229,6 @@ const AVFilter ff_vf_colorkey = { · 33 unmodified lines
205 .description = NULL_IF_CONFIG_SMALL("Turns a certain color into transparency. Operates on RGB colors."),229 .description = NULL_IF_CONFIG_SMALL("Turns a certain color into transparency. Operates on RGB colors."),
206 .priv_size = sizeof(ColorkeyContext),230 .priv_size = sizeof(ColorkeyContext),
207 .priv_class = &colorkey_class,231 .priv_class = &colorkey_class,
208 .init = init_filter,
209 FILTER_INPUTS(colorkey_inputs),232 FILTER_INPUTS(colorkey_inputs),
210 FILTER_OUTPUTS(colorkey_outputs),233 FILTER_OUTPUTS(colorkey_outputs),
211 FILTER_PIXFMTS_ARRAY(pixel_fmts),234 FILTER_PIXFMTS_ARRAY(pixel_fmts),
@@ -230,7 +253,6 @@ const AVFilter ff_vf_colorhold = { · 18 unmodified lines
230 .description = NULL_IF_CONFIG_SMALL("Turns a certain color range into gray. Operates on RGB colors."),253 .description = NULL_IF_CONFIG_SMALL("Turns a certain color range into gray. Operates on RGB colors."),
231 .priv_size = sizeof(ColorkeyContext),254 .priv_size = sizeof(ColorkeyContext),
232 .priv_class = &colorhold_class,255 .priv_class = &colorhold_class,
233 .init = init_filter,
234 FILTER_INPUTS(colorkey_inputs),256 FILTER_INPUTS(colorkey_inputs),
235 FILTER_OUTPUTS(colorkey_outputs),257 FILTER_OUTPUTS(colorkey_outputs),
236 FILTER_PIXFMTS_ARRAY(pixel_fmts),258 FILTER_PIXFMTS_ARRAY(pixel_fmts),

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t