Used the command for 1080p h264 clip as follow: a). ffmpeg -i input -vf lutyuv="u=128:v=128" -f null /dev/null b). ffmpeg -i input -vf lutrgb="g=0:b=0" -f null /dev/null after enabled the slice threading, the fps change from: a). 144fps to 258fps (lutyuv) b). 94fps to 153fps (lutrgb) in Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
Unified · Split
| @@ -337,13 +337,194 @@ static int config_props(AVFilterLink *inlink) · 336 unmodified lines | ||
| 337 | 337 | return 0; |
| 338 | 338 | } |
| 339 | 339 | |
| 340 | +struct thread_data { | |
| 341 | + AVFrame *in; | |
| 342 | + AVFrame *out; | |
| 343 | + | |
| 344 | + int w; | |
| 345 | + int h; | |
| 346 | +}; | |
| 347 | + | |
| 348 | +#define LOAD_PACKED_COMMON\ | |
| 349 | + LutContext *s = ctx->priv;\ | |
| 350 | + const struct thread_data *td = arg;\ | |
| 351 | +\ | |
| 352 | + int i, j;\ | |
| 353 | + const int w = td->w;\ | |
| 354 | + const int h = td->h;\ | |
| 355 | + AVFrame *in = td->in;\ | |
| 356 | + AVFrame *out = td->out;\ | |
| 357 | + const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut;\ | |
| 358 | + const int step = s->step;\ | |
| 359 | +\ | |
| 360 | + const int slice_start = (h * jobnr ) / nb_jobs;\ | |
| 361 | + const int slice_end = (h * (jobnr+1)) / nb_jobs;\ | |
| 362 | + | |
| 363 | +/* packed, 16-bit */ | |
| 364 | +static int lut_packed_16bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 365 | +{ | |
| 366 | + LOAD_PACKED_COMMON | |
| 367 | + | |
| 368 | + uint16_t *inrow, *outrow, *inrow0, *outrow0; | |
| 369 | + const int in_linesize = in->linesize[0] / 2; | |
| 370 | + const int out_linesize = out->linesize[0] / 2; | |
| 371 | + inrow0 = (uint16_t *)in ->data[0]; | |
| 372 | + outrow0 = (uint16_t *)out->data[0]; | |
| 373 | + | |
| 374 | + for (i = slice_start; i < slice_end; i++) { | |
| 375 | + inrow = inrow0 + i * in_linesize; | |
| 376 | + outrow = outrow0 + i * out_linesize; | |
| 377 | + for (j = 0; j < w; j++) { | |
| 378 | + | |
| 379 | + switch (step) { | |
| 380 | +#if HAVE_BIGENDIAN | |
| 381 | + case 4: outrow[3] = av_bswap16(tab[3][av_bswap16(inrow[3])]); // Fall-through | |
| 382 | + case 3: outrow[2] = av_bswap16(tab[2][av_bswap16(inrow[2])]); // Fall-through | |
| 383 | + case 2: outrow[1] = av_bswap16(tab[1][av_bswap16(inrow[1])]); // Fall-through | |
| 384 | + default: outrow[0] = av_bswap16(tab[0][av_bswap16(inrow[0])]); | |
| 385 | +#else | |
| 386 | + case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through | |
| 387 | + case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through | |
| 388 | + case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through | |
| 389 | + default: outrow[0] = tab[0][inrow[0]]; | |
| 390 | +#endif | |
| 391 | + } | |
| 392 | + outrow += step; | |
| 393 | + inrow += step; | |
| 394 | + } | |
| 395 | + } | |
| 396 | + | |
| 397 | + return 0; | |
| 398 | +} | |
| 399 | + | |
| 400 | +/* packed, 8-bit */ | |
| 401 | +static int lut_packed_8bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 402 | +{ | |
| 403 | + LOAD_PACKED_COMMON | |
| 404 | + | |
| 405 | + uint8_t *inrow, *outrow, *inrow0, *outrow0; | |
| 406 | + const int in_linesize = in->linesize[0]; | |
| 407 | + const int out_linesize = out->linesize[0]; | |
| 408 | + inrow0 = in ->data[0]; | |
| 409 | + outrow0 = out->data[0]; | |
| 410 | + | |
| 411 | + for (i = slice_start; i < slice_end; i++) { | |
| 412 | + inrow = inrow0 + i * in_linesize; | |
| 413 | + outrow = outrow0 + i * out_linesize; | |
| 414 | + for (j = 0; j < w; j++) { | |
| 415 | + switch (step) { | |
| 416 | + case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through | |
| 417 | + case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through | |
| 418 | + case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through | |
| 419 | + default: outrow[0] = tab[0][inrow[0]]; | |
| 420 | + } | |
| 421 | + outrow += step; | |
| 422 | + inrow += step; | |
| 423 | + } | |
| 424 | + } | |
| 425 | + | |
| 426 | + return 0; | |
| 427 | +} | |
| 428 | + | |
| 429 | +#define LOAD_PLANAR_COMMON\ | |
| 430 | + LutContext *s = ctx->priv;\ | |
| 431 | + const struct thread_data *td = arg;\ | |
| 432 | + int i, j, plane;\ | |
| 433 | + AVFrame *in = td->in;\ | |
| 434 | + AVFrame *out = td->out;\ | |
| 435 | + | |
| 436 | +#define PLANAR_COMMON\ | |
| 437 | + int vsub = plane == 1 || plane == 2 ? s->vsub : 0;\ | |
| 438 | + int hsub = plane == 1 || plane == 2 ? s->hsub : 0;\ | |
| 439 | + int h = AV_CEIL_RSHIFT(td->h, vsub);\ | |
| 440 | + int w = AV_CEIL_RSHIFT(td->w, hsub);\ | |
| 441 | + const uint16_t *tab = s->lut[plane];\ | |
| 442 | +\ | |
| 443 | + const int slice_start = (h * jobnr ) / nb_jobs;\ | |
| 444 | + const int slice_end = (h * (jobnr+1)) / nb_jobs;\ | |
| 445 | + | |
| 446 | +/* planar >8 bit depth */ | |
| 447 | +static int lut_planar_16bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 448 | +{ | |
| 449 | + LOAD_PLANAR_COMMON | |
| 450 | + | |
| 451 | + uint16_t *inrow, *outrow; | |
| 452 | + | |
| 453 | + for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { | |
| 454 | + PLANAR_COMMON | |
| 455 | + | |
| 456 | + const int in_linesize = in->linesize[plane] / 2; | |
| 457 | + const int out_linesize = out->linesize[plane] / 2; | |
| 458 | + | |
| 459 | + inrow = (uint16_t *)(in ->data[plane] + slice_start * in_linesize); | |
| 460 | + outrow = (uint16_t *)(out->data[plane] + slice_start * out_linesize); | |
| 461 | + | |
| 462 | + for (i = slice_start; i < slice_end; i++) { | |
| 463 | + for (j = 0; j < w; j++) { | |
| 464 | +#if HAVE_BIGENDIAN | |
| 465 | + outrow[j] = av_bswap16(tab[av_bswap16(inrow[j])]); | |
| 466 | +#else | |
| 467 | + outrow[j] = tab[inrow[j]]; | |
| 468 | +#endif | |
| 469 | + } | |
| 470 | + inrow += in_linesize; | |
| 471 | + outrow += out_linesize; | |
| 472 | + } | |
| 473 | + } | |
| 474 | + | |
| 475 | + return 0; | |
| 476 | +} | |
| 477 | + | |
| 478 | +/* planar 8bit depth */ | |
| 479 | +static int lut_planar_8bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
| 480 | +{ | |
| 481 | + LOAD_PLANAR_COMMON | |
| 482 | + | |
| 483 | + uint8_t *inrow, *outrow; | |
| 484 | + | |
| 485 | + for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { | |
| 486 | + PLANAR_COMMON | |
| 487 | + | |
| 488 | + const int in_linesize = in->linesize[plane]; | |
| 489 | + const int out_linesize = out->linesize[plane]; | |
| 490 | + | |
| 491 | + inrow = in ->data[plane] + slice_start * in_linesize; | |
| 492 | + outrow = out->data[plane] + slice_start * out_linesize; | |
| 493 | + | |
| 494 | + for (i = slice_start; i < slice_end; i++) { | |
| 495 | + for (j = 0; j < w; j++) | |
| 496 | + outrow[j] = tab[inrow[j]]; | |
| 497 | + inrow += in_linesize; | |
| 498 | + outrow += out_linesize; | |
| 499 | + } | |
| 500 | + } | |
| 501 | + | |
| 502 | + return 0; | |
| 503 | +} | |
| 504 | + | |
| 505 | +#define PACKED_THREAD_DATA\ | |
| 506 | + struct thread_data td = {\ | |
| 507 | + .in = in,\ | |
| 508 | + .out = out,\ | |
| 509 | + .w = inlink->w,\ | |
| 510 | + .h = in->height,\ | |
| 511 | + };\ | |
| 512 | + | |
| 513 | +#define PLANAR_THREAD_DATA\ | |
| 514 | + struct thread_data td = {\ | |
| 515 | + .in = in,\ | |
| 516 | + .out = out,\ | |
| 517 | + .w = inlink->w,\ | |
| 518 | + .h = inlink->h,\ | |
| 519 | + };\ | |
| 520 | + | |
| 340 | 521 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
| 341 | 522 | { |
| 342 | 523 | AVFilterContext *ctx = inlink->dst; |
| 343 | 524 | LutContext *s = ctx->priv; |
| 344 | 525 | AVFilterLink *outlink = ctx->outputs[0]; |
| 345 | 526 | AVFrame *out; |
| 346 | − int i, j, plane, direct = 0; | |
| 527 | + int direct = 0; | |
| 347 | 528 | |
| 348 | 529 | if (av_frame_is_writable(in)) { |
| 349 | 530 | direct = 1; |
| @@ -359,121 +540,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) · 9 unmodified lines | ||
| 359 | 540 | |
| 360 | 541 | if (s->is_rgb && s->is_16bit && !s->is_planar) { |
| 361 | 542 | /* packed, 16-bit */ |
| 362 | − uint16_t *inrow, *outrow, *inrow0, *outrow0; | |
| 363 | − const int w = inlink->w; | |
| 364 | − const int h = in->height; | |
| 365 | − const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut; | |
| 366 | − const int in_linesize = in->linesize[0] / 2; | |
| 367 | − const int out_linesize = out->linesize[0] / 2; | |
| 368 | − const int step = s->step; | |
| 369 | − | |
| 370 | − inrow0 = (uint16_t*) in ->data[0]; | |
| 371 | − outrow0 = (uint16_t*) out->data[0]; | |
| 372 | − | |
| 373 | − for (i = 0; i < h; i ++) { | |
| 374 | − inrow = inrow0; | |
| 375 | − outrow = outrow0; | |
| 376 | − for (j = 0; j < w; j++) { | |
| 377 | − | |
| 378 | − switch (step) { | |
| 379 | −#if HAVE_BIGENDIAN | |
| 380 | − case 4: outrow[3] = av_bswap16(tab[3][av_bswap16(inrow[3])]); // Fall-through | |
| 381 | − case 3: outrow[2] = av_bswap16(tab[2][av_bswap16(inrow[2])]); // Fall-through | |
| 382 | − case 2: outrow[1] = av_bswap16(tab[1][av_bswap16(inrow[1])]); // Fall-through | |
| 383 | − default: outrow[0] = av_bswap16(tab[0][av_bswap16(inrow[0])]); | |
| 384 | −#else | |
| 385 | − case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through | |
| 386 | − case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through | |
| 387 | − case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through | |
| 388 | − default: outrow[0] = tab[0][inrow[0]]; | |
| 389 | −#endif | |
| 390 | − } | |
| 391 | − outrow += step; | |
| 392 | − inrow += step; | |
| 393 | − } | |
| 394 | − inrow0 += in_linesize; | |
| 395 | − outrow0 += out_linesize; | |
| 396 | − } | |
| 543 | + PACKED_THREAD_DATA | |
| 544 | + ctx->internal->execute(ctx, lut_packed_16bits, &td, NULL, | |
| 545 | + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); | |
| 397 | 546 | } else if (s->is_rgb && !s->is_planar) { |
| 398 | − /* packed */ | |
| 399 | − uint8_t *inrow, *outrow, *inrow0, *outrow0; | |
| 400 | − const int w = inlink->w; | |
| 401 | − const int h = in->height; | |
| 402 | − const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut; | |
| 403 | − const int in_linesize = in->linesize[0]; | |
| 404 | − const int out_linesize = out->linesize[0]; | |
| 405 | − const int step = s->step; | |
| 406 | − | |
| 407 | − inrow0 = in ->data[0]; | |
| 408 | − outrow0 = out->data[0]; | |
| 409 | − | |
| 410 | − for (i = 0; i < h; i ++) { | |
| 411 | − inrow = inrow0; | |
| 412 | − outrow = outrow0; | |
| 413 | − for (j = 0; j < w; j++) { | |
| 414 | − switch (step) { | |
| 415 | − case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through | |
| 416 | − case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through | |
| 417 | − case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through | |
| 418 | − default: outrow[0] = tab[0][inrow[0]]; | |
| 419 | − } | |
| 420 | − outrow += step; | |
| 421 | − inrow += step; | |
| 422 | − } | |
| 423 | − inrow0 += in_linesize; | |
| 424 | − outrow0 += out_linesize; | |
| 425 | − } | |
| 547 | + /* packed 8 bits */ | |
| 548 | + PACKED_THREAD_DATA | |
| 549 | + ctx->internal->execute(ctx, lut_packed_8bits, &td, NULL, | |
| 550 | + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); | |
| 426 | 551 | } else if (s->is_16bit) { |
| 427 | − // planar >8 bit depth | |
| 428 | − uint16_t *inrow, *outrow; | |
| 429 | − | |
| 430 | − for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { | |
| 431 | − int vsub = plane == 1 || plane == 2 ? s->vsub : 0; | |
| 432 | − int hsub = plane == 1 || plane == 2 ? s->hsub : 0; | |
| 433 | − int h = AV_CEIL_RSHIFT(inlink->h, vsub); | |
| 434 | − int w = AV_CEIL_RSHIFT(inlink->w, hsub); | |
| 435 | − const uint16_t *tab = s->lut[plane]; | |
| 436 | − const int in_linesize = in->linesize[plane] / 2; | |
| 437 | − const int out_linesize = out->linesize[plane] / 2; | |
| 438 | − | |
| 439 | − inrow = (uint16_t *)in ->data[plane]; | |
| 440 | − outrow = (uint16_t *)out->data[plane]; | |
| 441 | − | |
| 442 | − for (i = 0; i < h; i++) { | |
| 443 | − for (j = 0; j < w; j++) { | |
| 444 | −#if HAVE_BIGENDIAN | |
| 445 | − outrow[j] = av_bswap16(tab[av_bswap16(inrow[j])]); | |
| 446 | −#else | |
| 447 | − outrow[j] = tab[inrow[j]]; | |
| 448 | −#endif | |
| 449 | − } | |
| 450 | − inrow += in_linesize; | |
| 451 | − outrow += out_linesize; | |
| 452 | − } | |
| 453 | − } | |
| 552 | + /* planar >8 bit depth */ | |
| 553 | + PLANAR_THREAD_DATA | |
| 554 | + ctx->internal->execute(ctx, lut_planar_16bits, &td, NULL, | |
| 555 | + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); | |
| 454 | 556 | } else { |
| 455 | 557 | /* planar 8bit depth */ |
| 456 | − uint8_t *inrow, *outrow; | |
| 457 | − | |
| 458 | − for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { | |
| 459 | − int vsub = plane == 1 || plane == 2 ? s->vsub : 0; | |
| 460 | − int hsub = plane == 1 || plane == 2 ? s->hsub : 0; | |
| 461 | − int h = AV_CEIL_RSHIFT(inlink->h, vsub); | |
| 462 | − int w = AV_CEIL_RSHIFT(inlink->w, hsub); | |
| 463 | − const uint16_t *tab = s->lut[plane]; | |
| 464 | − const int in_linesize = in->linesize[plane]; | |
| 465 | − const int out_linesize = out->linesize[plane]; | |
| 466 | − | |
| 467 | − inrow = in ->data[plane]; | |
| 468 | − outrow = out->data[plane]; | |
| 469 | − | |
| 470 | − for (i = 0; i < h; i++) { | |
| 471 | − for (j = 0; j < w; j++) | |
| 472 | − outrow[j] = tab[inrow[j]]; | |
| 473 | − inrow += in_linesize; | |
| 474 | − outrow += out_linesize; | |
| 475 | − } | |
| 476 | − } | |
| 558 | + PLANAR_THREAD_DATA | |
| 559 | + ctx->internal->execute(ctx, lut_planar_8bits, &td, NULL, | |
| 560 | + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); | |
| 477 | 561 | } |
| 478 | 562 | |
| 479 | 563 | if (!direct) |
| @@ -508,7 +592,7 @@ static const AVFilterPad outputs[] = { · 28 unmodified lines | ||
| 508 | 592 | .query_formats = query_formats, \ |
| 509 | 593 | .inputs = inputs, \ |
| 510 | 594 | .outputs = outputs, \ |
| 511 | − .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, \ | |
| 595 | + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, \ | |
| 512 | 596 | } |
| 513 | 597 | |
| 514 | 598 | #if CONFIG_LUT_FILTER |