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
Showing the changes to libavfilter (1 of 1 file). Show all
Unified · Split
| @@ -337,13 +337,194 @@ static int config_props(AVFilterLink *inlink) · 336 unmodified lines | |||
| 337 | return 0; | 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 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | 521 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
| 341 | { | 522 | { |
| 342 | AVFilterContext *ctx = inlink->dst; | 523 | AVFilterContext *ctx = inlink->dst; |
| 343 | LutContext *s = ctx->priv; | 524 | LutContext *s = ctx->priv; |
| 344 | AVFilterLink *outlink = ctx->outputs[0]; | 525 | AVFilterLink *outlink = ctx->outputs[0]; |
| 345 | AVFrame *out; | 526 | AVFrame *out; |
| 346 | int i, j, plane, direct = 0; | 527 | int direct = 0; |
| 347 | 528 | ||
| 348 | if (av_frame_is_writable(in)) { | 529 | if (av_frame_is_writable(in)) { |
| 349 | direct = 1; | 530 | direct = 1; |
| @@ -359,121 +540,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) · 9 unmodified lines | |||
| 359 | 540 | ||
| 360 | if (s->is_rgb && s->is_16bit && !s->is_planar) { | 541 | if (s->is_rgb && s->is_16bit && !s->is_planar) { |
| 361 | /* packed, 16-bit */ | 542 | /* packed, 16-bit */ |
| 362 | uint16_t *inrow, *outrow, *inrow0, *outrow0; | 543 | PACKED_THREAD_DATA |
| 363 | const int w = inlink->w; | 544 | ctx->internal->execute(ctx, lut_packed_16bits, &td, NULL, |
| 364 | const int h = in->height; | 545 | FFMIN(in->height, ff_filter_get_nb_threads(ctx))); |
| 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 | } | ||
| 397 | } else if (s->is_rgb && !s->is_planar) { | 546 | } else if (s->is_rgb && !s->is_planar) { |
| 398 | /* packed */ | 547 | /* packed 8 bits */ |
| 399 | uint8_t *inrow, *outrow, *inrow0, *outrow0; | 548 | PACKED_THREAD_DATA |
| 400 | const int w = inlink->w; | 549 | ctx->internal->execute(ctx, lut_packed_8bits, &td, NULL, |
| 401 | const int h = in->height; | 550 | FFMIN(in->height, ff_filter_get_nb_threads(ctx))); |
| 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 | } | ||
| 426 | } else if (s->is_16bit) { | 551 | } else if (s->is_16bit) { |
| 427 | // planar >8 bit depth | 552 | /* planar >8 bit depth */ |
| 428 | uint16_t *inrow, *outrow; | 553 | PLANAR_THREAD_DATA |
| 429 | 554 | ctx->internal->execute(ctx, lut_planar_16bits, &td, NULL, | |
| 430 | for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { | 555 | FFMIN(in->height, ff_filter_get_nb_threads(ctx))); |
| 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 | } | ||
| 454 | } else { | 556 | } else { |
| 455 | /* planar 8bit depth */ | 557 | /* planar 8bit depth */ |
| 456 | uint8_t *inrow, *outrow; | 558 | PLANAR_THREAD_DATA |
| 457 | 559 | ctx->internal->execute(ctx, lut_planar_8bits, &td, NULL, | |
| 458 | for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { | 560 | FFMIN(in->height, ff_filter_get_nb_threads(ctx))); |
| 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 | } | ||
| 477 | } | 561 | } |
| 478 | 562 | ||
| 479 | if (!direct) | 563 | if (!direct) |
| @@ -508,7 +592,7 @@ static const AVFilterPad outputs[] = { · 28 unmodified lines | |||
| 508 | .query_formats = query_formats, \ | 592 | .query_formats = query_formats, \ |
| 509 | .inputs = inputs, \ | 593 | .inputs = inputs, \ |
| 510 | .outputs = outputs, \ | 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 | #if CONFIG_LUT_FILTER | 598 | #if CONFIG_LUT_FILTER |