Unified · Split
| @@ -44,6 +44,9 @@ typedef struct ColorLevelsContext { · 43 unmodified lines | ||
| 44 | 44 | int preserve_color; |
| 45 | 45 | |
| 46 | 46 | int nb_comp; |
| 47 | + int depth; | |
| 48 | + int max; | |
| 49 | + int planar; | |
| 47 | 50 | int bpp; |
| 48 | 51 | int step; |
| 49 | 52 | uint8_t rgba_map[4]; |
| @@ -85,8 +88,8 @@ static const AVOption colorlevels_options[] = { · 35 unmodified lines | ||
| 85 | 88 | AVFILTER_DEFINE_CLASS(colorlevels); |
| 86 | 89 | |
| 87 | 90 | typedef struct ThreadData { |
| 88 | − const uint8_t *srcrow; | |
| 89 | − uint8_t *dstrow; | |
| 91 | + const uint8_t *srcrow[4]; | |
| 92 | + uint8_t *dstrow[4]; | |
| 90 | 93 | int dst_linesize; |
| 91 | 94 | int src_linesize; |
| 92 | 95 | |
| @@ -98,8 +101,7 @@ typedef struct ThreadData { · 5 unmodified lines | ||
| 98 | 101 | int omin[4]; |
| 99 | 102 | } ThreadData; |
| 100 | 103 | |
| 101 | −#define DO_COMMON(type, clip, preserve) \ | |
| 102 | − ColorLevelsContext *s = ctx->priv; \ | |
| 104 | +#define DO_COMMON(type, clip, preserve, planar) \ | |
| 103 | 105 | const ThreadData *td = arg; \ |
| 104 | 106 | const int linesize = s->linesize; \ |
| 105 | 107 | const int step = s->step; \ |
| @@ -108,12 +110,14 @@ typedef struct ThreadData { · 2 unmodified lines | ||
| 108 | 110 | const int slice_end = (process_h * (jobnr+1)) / nb_jobs; \ |
| 109 | 111 | const int src_linesize = td->src_linesize / sizeof(type); \ |
| 110 | 112 | const int dst_linesize = td->dst_linesize / sizeof(type); \ |
| 111 | − const type *srcrow = (const type *)td->srcrow + src_linesize * slice_start; \ | |
| 112 | − type *dstrow = (type *)td->dstrow + dst_linesize * slice_start; \ | |
| 113 | − const uint8_t offset_r = s->rgba_map[R]; \ | |
| 114 | − const uint8_t offset_g = s->rgba_map[G]; \ | |
| 115 | − const uint8_t offset_b = s->rgba_map[B]; \ | |
| 116 | − const uint8_t offset_a = s->rgba_map[A]; \ | |
| 113 | + const type *src_r = (const type *)(td->srcrow[R]) + src_linesize * slice_start; \ | |
| 114 | + const type *src_g = (const type *)(td->srcrow[G]) + src_linesize * slice_start; \ | |
| 115 | + const type *src_b = (const type *)(td->srcrow[B]) + src_linesize * slice_start; \ | |
| 116 | + const type *src_a = (const type *)(td->srcrow[A]) + src_linesize * slice_start; \ | |
| 117 | + type *dst_r = (type *)(td->dstrow[R]) + src_linesize * slice_start; \ | |
| 118 | + type *dst_g = (type *)(td->dstrow[G]) + src_linesize * slice_start; \ | |
| 119 | + type *dst_b = (type *)(td->dstrow[B]) + src_linesize * slice_start; \ | |
| 120 | + type *dst_a = (type *)(td->dstrow[A]) + src_linesize * slice_start; \ | |
| 117 | 121 | const int imin_r = td->imin[R]; \ |
| 118 | 122 | const int imin_g = td->imin[G]; \ |
| 119 | 123 | const int imin_b = td->imin[B]; \ |
| @@ -126,14 +130,6 @@ typedef struct ThreadData { · 6 unmodified lines | ||
| 126 | 130 | const float coeff_g = td->coeff[G]; \ |
| 127 | 131 | const float coeff_b = td->coeff[B]; \ |
| 128 | 132 | const float coeff_a = td->coeff[A]; \ |
| 129 | − const type *src_r = srcrow + offset_r; \ | |
| 130 | − const type *src_g = srcrow + offset_g; \ | |
| 131 | − const type *src_b = srcrow + offset_b; \ | |
| 132 | − const type *src_a = srcrow + offset_a; \ | |
| 133 | − type *dst_r = dstrow + offset_r; \ | |
| 134 | − type *dst_g = dstrow + offset_g; \ | |
| 135 | − type *dst_b = dstrow + offset_b; \ | |
| 136 | − type *dst_a = dstrow + offset_a; \ | |
| 137 | 133 | \ |
| 138 | 134 | for (int y = slice_start; y < slice_end; y++) { \ |
| 139 | 135 | for (int x = 0; x < linesize; x += step) { \ |
| @@ -142,7 +138,7 @@ typedef struct ThreadData { · 2 unmodified lines | ||
| 142 | 138 | ig = src_g[x]; \ |
| 143 | 139 | ib = src_b[x]; \ |
| 144 | 140 | if (preserve) { \ |
| 145 | − float ratio, icolor, ocolor, max = (1<<(8*sizeof(type)))-1; \ | |
| 141 | + float ratio, icolor, ocolor, max = s->max; \ | |
| 146 | 142 | \ |
| 147 | 143 | or = (ir - imin_r) * coeff_r + omin_r; \ |
| 148 | 144 | og = (ig - imin_g) * coeff_g + omin_g; \ |
| @@ -158,18 +154,18 @@ typedef struct ThreadData { · 9 unmodified lines | ||
| 158 | 154 | ob *= ratio; \ |
| 159 | 155 | } \ |
| 160 | 156 | \ |
| 161 | − dst_r[x] = clip(or); \ | |
| 162 | − dst_g[x] = clip(og); \ | |
| 163 | − dst_b[x] = clip(ob); \ | |
| 157 | + dst_r[x] = clip(or, depth); \ | |
| 158 | + dst_g[x] = clip(og, depth); \ | |
| 159 | + dst_b[x] = clip(ob, depth); \ | |
| 164 | 160 | } else { \ |
| 165 | − dst_r[x] = clip((ir - imin_r) * coeff_r + omin_r); \ | |
| 166 | − dst_g[x] = clip((ig - imin_g) * coeff_g + omin_g); \ | |
| 167 | − dst_b[x] = clip((ib - imin_b) * coeff_b + omin_b); \ | |
| 161 | + dst_r[x] = clip((ir - imin_r) * coeff_r + omin_r, depth); \ | |
| 162 | + dst_g[x] = clip((ig - imin_g) * coeff_g + omin_g, depth); \ | |
| 163 | + dst_b[x] = clip((ib - imin_b) * coeff_b + omin_b, depth); \ | |
| 168 | 164 | } \ |
| 169 | 165 | } \ |
| 170 | 166 | \ |
| 171 | 167 | for (int x = 0; x < linesize && s->nb_comp == 4; x += step) \ |
| 172 | − dst_a[x] = clip((src_a[x] - imin_a) * coeff_a + omin_a); \ | |
| 168 | + dst_a[x] = clip((src_a[x] - imin_a) * coeff_a + omin_a, depth); \ | |
| 173 | 169 | \ |
| 174 | 170 | src_r += src_linesize; \ |
| 175 | 171 | src_g += src_linesize; \ |
| @@ -182,31 +178,126 @@ typedef struct ThreadData { · 6 unmodified lines | ||
| 182 | 178 | dst_a += dst_linesize; \ |
| 183 | 179 | } |
| 184 | 180 | |
| 181 | +#define CLIP8(x, depth) av_clip_uint8(x) | |
| 182 | +#define CLIP16(x, depth) av_clip_uint16(x) | |
| 183 | + | |
| 185 | 184 | static int colorlevels_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
| 186 | 185 | { |
| 187 | − DO_COMMON(uint8_t, av_clip_uint8, 0) | |
| 188 | − | |
| 186 | + ColorLevelsContext *s = ctx->priv; | |
| 187 | + DO_COMMON(uint8_t, CLIP8, 0, 0) | |
| 189 | 188 | return 0; |
| 190 | 189 | } |
| 191 | 190 | |
| 192 | 191 | static int colorlevels_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
| 193 | 192 | { |
| 194 | − DO_COMMON(uint16_t, av_clip_uint16, 0) | |
| 195 | − | |
| 193 | + ColorLevelsContext *s = ctx->priv;\ | |
| 194 | + DO_COMMON(uint16_t, CLIP16, 0, 0) | |
| 196 | 195 | return 0; |
| 197 | 196 | } |
| 198 | 197 | |
| 199 | 198 | static int colorlevels_preserve_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
| 200 | 199 | { |
| 201 | − DO_COMMON(uint8_t, av_clip_uint8, 1) | |
| 202 | − | |
| 200 | + ColorLevelsContext *s = ctx->priv; | |
| 201 | + DO_COMMON(uint8_t, CLIP8, 1, 0) | |
| 203 | 202 | return 0; |
| 204 | 203 | } |
| 205 | 204 | |
| 206 | 205 | static int colorlevels_preserve_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
| 207 | 206 | { |
| 208 | − DO_COMMON(uint16_t, av_clip_uint16, 1) | |
| 207 | + ColorLevelsContext *s = ctx->priv; | |
| 208 | + DO_COMMON(uint16_t, CLIP16, 1, 0) | |
| 209 | + return 0; | |
| 210 | +} | |
| 211 | + | |
| 212 | +static int colorlevels_slice_8_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 213 | +{ | |
| 214 | + ColorLevelsContext *s = ctx->priv; | |
| 215 | + DO_COMMON(uint8_t, CLIP8, 0, 1) | |
| 216 | + return 0; | |
| 217 | +} | |
| 218 | + | |
| 219 | +static int colorlevels_slice_9_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 220 | +{ | |
| 221 | + ColorLevelsContext *s = ctx->priv; | |
| 222 | + const int depth = s->depth; | |
| 223 | + DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) | |
| 224 | + return 0; | |
| 225 | +} | |
| 226 | + | |
| 227 | +static int colorlevels_slice_10_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 228 | +{ | |
| 229 | + ColorLevelsContext *s = ctx->priv; | |
| 230 | + const int depth = s->depth; | |
| 231 | + DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) | |
| 232 | + return 0; | |
| 233 | +} | |
| 234 | + | |
| 235 | +static int colorlevels_slice_12_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 236 | +{ | |
| 237 | + ColorLevelsContext *s = ctx->priv; | |
| 238 | + const int depth = s->depth; | |
| 239 | + DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) | |
| 240 | + return 0; | |
| 241 | +} | |
| 242 | + | |
| 243 | +static int colorlevels_slice_14_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 244 | +{ | |
| 245 | + ColorLevelsContext *s = ctx->priv; | |
| 246 | + const int depth = s->depth; | |
| 247 | + DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) | |
| 248 | + return 0; | |
| 249 | +} | |
| 209 | 250 | |
| 251 | +static int colorlevels_slice_16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 252 | +{ | |
| 253 | + ColorLevelsContext *s = ctx->priv; | |
| 254 | + DO_COMMON(uint16_t, CLIP16, 0, 1) | |
| 255 | + return 0; | |
| 256 | +} | |
| 257 | + | |
| 258 | +static int colorlevels_preserve_slice_8_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 259 | +{ | |
| 260 | + ColorLevelsContext *s = ctx->priv; | |
| 261 | + DO_COMMON(uint8_t, CLIP8, 1, 1) | |
| 262 | + return 0; | |
| 263 | +} | |
| 264 | + | |
| 265 | +static int colorlevels_preserve_slice_9_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 266 | +{ | |
| 267 | + ColorLevelsContext *s = ctx->priv; | |
| 268 | + const int depth = s->depth; | |
| 269 | + DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) | |
| 270 | + return 0; | |
| 271 | +} | |
| 272 | + | |
| 273 | +static int colorlevels_preserve_slice_10_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 274 | +{ | |
| 275 | + ColorLevelsContext *s = ctx->priv; | |
| 276 | + const int depth = s->depth; | |
| 277 | + DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) | |
| 278 | + return 0; | |
| 279 | +} | |
| 280 | + | |
| 281 | +static int colorlevels_preserve_slice_12_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 282 | +{ | |
| 283 | + ColorLevelsContext *s = ctx->priv; | |
| 284 | + const int depth = s->depth; | |
| 285 | + DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) | |
| 286 | + return 0; | |
| 287 | +} | |
| 288 | + | |
| 289 | +static int colorlevels_preserve_slice_14_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 290 | +{ | |
| 291 | + ColorLevelsContext *s = ctx->priv; | |
| 292 | + const int depth = s->depth; | |
| 293 | + DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) | |
| 294 | + return 0; | |
| 295 | +} | |
| 296 | + | |
| 297 | +static int colorlevels_preserve_slice_16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 298 | +{ | |
| 299 | + ColorLevelsContext *s = ctx->priv; | |
| 300 | + DO_COMMON(uint16_t, CLIP16, 1, 1) | |
| 210 | 301 | return 0; |
| 211 | 302 | } |
| 212 | 303 | |
| @@ -217,16 +308,48 @@ static int config_input(AVFilterLink *inlink) · 4 unmodified lines | ||
| 217 | 308 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
| 218 | 309 | |
| 219 | 310 | s->nb_comp = desc->nb_components; |
| 220 | − s->bpp = desc->comp[0].depth >> 3; | |
| 221 | − s->step = av_get_padded_bits_per_pixel(desc) >> (3 + (s->bpp == 2)); | |
| 311 | + s->planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR; | |
| 312 | + s->depth = desc->comp[0].depth; | |
| 313 | + s->max = (1 << s->depth) - 1; | |
| 314 | + s->bpp = (desc->comp[0].depth + 7) >> 3; | |
| 315 | + s->step = s->planar ? 1 : av_get_padded_bits_per_pixel(desc) >> (3 + (s->bpp == 2)); | |
| 222 | 316 | s->linesize = inlink->w * s->step; |
| 223 | 317 | ff_fill_rgba_map(s->rgba_map, inlink->format); |
| 224 | 318 | |
| 225 | − s->colorlevels_slice[0] = colorlevels_slice_8; | |
| 226 | − s->colorlevels_slice[1] = colorlevels_preserve_slice_8; | |
| 227 | − if (s->bpp == 2) { | |
| 228 | − s->colorlevels_slice[0] = colorlevels_slice_16; | |
| 229 | − s->colorlevels_slice[1] = colorlevels_preserve_slice_16; | |
| 319 | + if (!s->planar) { | |
| 320 | + s->colorlevels_slice[0] = colorlevels_slice_8; | |
| 321 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_8; | |
| 322 | + if (s->bpp == 2) { | |
| 323 | + s->colorlevels_slice[0] = colorlevels_slice_16; | |
| 324 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_16; | |
| 325 | + } | |
| 326 | + } else { | |
| 327 | + switch (s->depth) { | |
| 328 | + case 8: | |
| 329 | + s->colorlevels_slice[0] = colorlevels_slice_8_planar; | |
| 330 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_8_planar; | |
| 331 | + break; | |
| 332 | + case 9: | |
| 333 | + s->colorlevels_slice[0] = colorlevels_slice_9_planar; | |
| 334 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_9_planar; | |
| 335 | + break; | |
| 336 | + case 10: | |
| 337 | + s->colorlevels_slice[0] = colorlevels_slice_10_planar; | |
| 338 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_10_planar; | |
| 339 | + break; | |
| 340 | + case 12: | |
| 341 | + s->colorlevels_slice[0] = colorlevels_slice_12_planar; | |
| 342 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_12_planar; | |
| 343 | + break; | |
| 344 | + case 14: | |
| 345 | + s->colorlevels_slice[0] = colorlevels_slice_14_planar; | |
| 346 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_14_planar; | |
| 347 | + break; | |
| 348 | + case 16: | |
| 349 | + s->colorlevels_slice[0] = colorlevels_slice_16_planar; | |
| 350 | + s->colorlevels_slice[1] = colorlevels_preserve_slice_16_planar; | |
| 351 | + break; | |
| 352 | + } | |
| 230 | 353 | } |
| 231 | 354 | |
| 232 | 355 | return 0; |
| @@ -255,8 +378,25 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) · 22 unmodified lines | ||
| 255 | 378 | td.h = inlink->h; |
| 256 | 379 | td.dst_linesize = out->linesize[0]; |
| 257 | 380 | td.src_linesize = in->linesize[0]; |
| 258 | − td.srcrow = in->data[0]; | |
| 259 | − td.dstrow = out->data[0]; | |
| 381 | + if (s->planar) { | |
| 382 | + td.srcrow[R] = in->data[2]; | |
| 383 | + td.dstrow[R] = out->data[2]; | |
| 384 | + td.srcrow[G] = in->data[0]; | |
| 385 | + td.dstrow[G] = out->data[0]; | |
| 386 | + td.srcrow[B] = in->data[1]; | |
| 387 | + td.dstrow[B] = out->data[1]; | |
| 388 | + td.srcrow[A] = in->data[3]; | |
| 389 | + td.dstrow[A] = out->data[3]; | |
| 390 | + } else { | |
| 391 | + td.srcrow[R] = in->data[0] + s->rgba_map[R] * s->bpp; | |
| 392 | + td.dstrow[R] = out->data[0] + s->rgba_map[R] * s->bpp; | |
| 393 | + td.srcrow[G] = in->data[0] + s->rgba_map[G] * s->bpp; | |
| 394 | + td.dstrow[G] = out->data[0] + s->rgba_map[G] * s->bpp; | |
| 395 | + td.srcrow[B] = in->data[0] + s->rgba_map[B] * s->bpp; | |
| 396 | + td.dstrow[B] = out->data[0] + s->rgba_map[B] * s->bpp; | |
| 397 | + td.srcrow[A] = in->data[0] + s->rgba_map[A] * s->bpp; | |
| 398 | + td.dstrow[A] = out->data[0] + s->rgba_map[A] * s->bpp; | |
| 399 | + } | |
| 260 | 400 | |
| 261 | 401 | switch (s->bpp) { |
| 262 | 402 | case 1: |
| @@ -378,7 +518,13 @@ const AVFilter ff_vf_colorlevels = { · 115 unmodified lines | ||
| 378 | 518 | AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, |
| 379 | 519 | AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, |
| 380 | 520 | AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, |
| 381 | − AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA), | |
| 521 | + AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, | |
| 522 | + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, | |
| 523 | + AV_PIX_FMT_GBRP9, | |
| 524 | + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, | |
| 525 | + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, | |
| 526 | + AV_PIX_FMT_GBRP14, | |
| 527 | + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16), | |
| 382 | 528 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, |
| 383 | 529 | .process_command = ff_filter_process_command, |
| 384 | 530 | }; |