| @@ -26,8 +26,6 @@ | |||
| * | |||
| * @see http://www.libretro.com/forums/viewtopic.php?f=6&t=134 | |||
| * @see https://github.com/yoyofr/iFBA/blob/master/fba_src/src/intf/video/scalers/xbr.cpp | |||
| * | |||
| * @todo add threading | |||
| */ | |||
| #include "libavutil/opt.h" | |||
| @@ -40,7 +38,7 @@ | |||
| #define RED_BLUE_MASK 0x00FF00FF | |||
| #define GREEN_MASK 0x0000FF00 | |||
| typedef void (*xbrfunc_t)(AVFrame *input, AVFrame *output, const uint32_t *r2y); | |||
| typedef int (*xbrfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); | |||
| typedef struct { | |||
| const AVClass *class; | |||
| @@ -49,6 +47,11 @@ typedef struct { | |||
| uint32_t rgbtoyuv[1<<24]; | |||
| } XBRContext; | |||
| typedef struct ThreadData { | |||
| AVFrame *in, *out; | |||
| const uint32_t *rgbtoyuv; | |||
| } ThreadData; | |||
| #define OFFSET(x) offsetof(XBRContext, x) | |||
| #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | |||
| static const AVOption xbr_options[] = { | |||
| @@ -182,12 +185,18 @@ static uint32_t pixel_diff(uint32_t x, uint32_t y, const uint32_t *r2y) | |||
| } \ | |||
| } while (0) | |||
| static void xbr2x(AVFrame * input, AVFrame * output, const uint32_t * r2y) | |||
| static int xbr2x(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |||
| { | |||
| int x, y; | |||
| const ThreadData *td = arg; | |||
| const AVFrame *input = td->in; | |||
| AVFrame *output = td->out; | |||
| const uint32_t *r2y = td->rgbtoyuv; | |||
| const int slice_start = (input->height * jobnr ) / nb_jobs; | |||
| const int slice_end = (input->height * (jobnr+1)) / nb_jobs; | |||
| const int nl = output->linesize[0] >> 2; | |||
| for (y = 0; y < input->height; y++) { | |||
| for (y = slice_start; y < slice_end; y++) { | |||
| INIT_SRC_DST_POINTERS(2) | |||
| for (x = 0; x < input->width; x++) { | |||
| @@ -209,6 +218,7 @@ static void xbr2x(AVFrame * input, AVFrame * output, const uint32_t * r2y) | |||
| E += 2; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| #define FILT3(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, \ | |||
| @@ -251,13 +261,19 @@ static void xbr2x(AVFrame * input, AVFrame * output, const uint32_t * r2y) | |||
| } \ | |||
| } while (0) | |||
| static void xbr3x(AVFrame *input, AVFrame *output, const uint32_t *r2y) | |||
| static int xbr3x(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |||
| { | |||
| int x, y; | |||
| const ThreadData *td = arg; | |||
| const AVFrame *input = td->in; | |||
| AVFrame *output = td->out; | |||
| const uint32_t *r2y = td->rgbtoyuv; | |||
| const int slice_start = (input->height * jobnr ) / nb_jobs; | |||
| const int slice_end = (input->height * (jobnr+1)) / nb_jobs; | |||
| const int nl = output->linesize[0] >> 2; | |||
| const int nl1 = nl + nl; | |||
| for (y = 0; y < input->height; y++) { | |||
| for (y = slice_start; y < slice_end; y++) { | |||
| INIT_SRC_DST_POINTERS(3) | |||
| for (x = 0; x < input->width; x++) { | |||
| @@ -281,6 +297,7 @@ static void xbr3x(AVFrame *input, AVFrame *output, const uint32_t *r2y) | |||
| E += 3; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| #define FILT4(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, \ | |||
| @@ -327,14 +344,20 @@ static void xbr3x(AVFrame *input, AVFrame *output, const uint32_t *r2y) | |||
| } \ | |||
| } while (0) | |||
| static void xbr4x(AVFrame *input, AVFrame *output, const uint32_t *r2y) | |||
| static int xbr4x(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |||
| { | |||
| int x, y; | |||
| const ThreadData *td = arg; | |||
| const AVFrame *input = td->in; | |||
| AVFrame *output = td->out; | |||
| const uint32_t *r2y = td->rgbtoyuv; | |||
| const int slice_start = (input->height * jobnr ) / nb_jobs; | |||
| const int slice_end = (input->height * (jobnr+1)) / nb_jobs; | |||
| const int nl = output->linesize[0] >> 2; | |||
| const int nl1 = nl + nl; | |||
| const int nl2 = nl1 + nl; | |||
| for (y = 0; y < input->height; y++) { | |||
| for (y = slice_start; y < slice_end; y++) { | |||
| INIT_SRC_DST_POINTERS(4) | |||
| for (x = 0; x < input->width; x++) { | |||
| @@ -359,6 +382,7 @@ static void xbr4x(AVFrame *input, AVFrame *output, const uint32_t *r2y) | |||
| E += 4; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| static int config_output(AVFilterLink *outlink) | |||
| @@ -387,7 +411,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||
| AVFilterContext *ctx = inlink->dst; | |||
| AVFilterLink *outlink = ctx->outputs[0]; | |||
| XBRContext *xbr = ctx->priv; | |||
| const uint32_t *r2y = xbr->rgbtoyuv; | |||
| ThreadData td; | |||
| AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |||
| if (!out) { | |||
| @@ -396,7 +420,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||
| } | |||
| av_frame_copy_props(out, in); | |||
| xbr->func(in, out, r2y); | |||
| td.in = in; | |||
| td.out = out; | |||
| td.rgbtoyuv = xbr->rgbtoyuv; | |||
| ctx->internal->execute(ctx, xbr->func, &td, NULL, FFMIN(inlink->h, ctx->graph->nb_threads)); | |||
| out->width = outlink->w; | |||
| out->height = outlink->h; | |||
| @@ -459,4 +487,5 @@ AVFilter ff_vf_xbr = { | |||
| .priv_size = sizeof(XBRContext), | |||
| .priv_class = &xbr_class, | |||
| .init = init, | |||
| .flags = AVFILTER_FLAG_SLICE_THREADS, | |||
| }; | |||