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