00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025
00026
00027 #include <dlfcn.h>
00028 #include <frei0r.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include "config.h"
00033 #include "libavutil/avstring.h"
00034 #include "libavutil/imgutils.h"
00035 #include "libavutil/internal.h"
00036 #include "libavutil/mathematics.h"
00037 #include "libavutil/mem.h"
00038 #include "libavutil/parseutils.h"
00039 #include "avfilter.h"
00040 #include "formats.h"
00041 #include "internal.h"
00042 #include "video.h"
00043
00044 typedef f0r_instance_t (*f0r_construct_f)(unsigned int width, unsigned int height);
00045 typedef void (*f0r_destruct_f)(f0r_instance_t instance);
00046 typedef void (*f0r_deinit_f)(void);
00047 typedef int (*f0r_init_f)(void);
00048 typedef void (*f0r_get_plugin_info_f)(f0r_plugin_info_t *info);
00049 typedef void (*f0r_get_param_info_f)(f0r_param_info_t *info, int param_index);
00050 typedef void (*f0r_update_f)(f0r_instance_t instance, double time, const uint32_t *inframe, uint32_t *outframe);
00051 typedef void (*f0r_update2_f)(f0r_instance_t instance, double time, const uint32_t *inframe1, const uint32_t *inframe2, const uint32_t *inframe3, uint32_t *outframe);
00052 typedef void (*f0r_set_param_value_f)(f0r_instance_t instance, f0r_param_t param, int param_index);
00053 typedef void (*f0r_get_param_value_f)(f0r_instance_t instance, f0r_param_t param, int param_index);
00054
00055 typedef struct Frei0rContext {
00056 f0r_update_f update;
00057 void *dl_handle;
00058 f0r_instance_t instance;
00059 f0r_plugin_info_t plugin_info;
00060
00061 f0r_get_param_info_f get_param_info;
00062 f0r_get_param_value_f get_param_value;
00063 f0r_set_param_value_f set_param_value;
00064 f0r_construct_f construct;
00065 f0r_destruct_f destruct;
00066 f0r_deinit_f deinit;
00067 char params[256];
00068
00069
00070 int w, h;
00071 AVRational time_base;
00072 uint64_t pts;
00073 } Frei0rContext;
00074
00075 static void *load_sym(AVFilterContext *ctx, const char *sym_name)
00076 {
00077 Frei0rContext *frei0r = ctx->priv;
00078 void *sym = dlsym(frei0r->dl_handle, sym_name);
00079 if (!sym)
00080 av_log(ctx, AV_LOG_ERROR, "Could not find symbol '%s' in loaded module\n", sym_name);
00081 return sym;
00082 }
00083
00084 static int set_param(AVFilterContext *ctx, f0r_param_info_t info, int index, char *param)
00085 {
00086 Frei0rContext *frei0r = ctx->priv;
00087 union {
00088 double d;
00089 f0r_param_color_t col;
00090 f0r_param_position_t pos;
00091 } val;
00092 char *tail;
00093 uint8_t rgba[4];
00094
00095 switch (info.type) {
00096 case F0R_PARAM_BOOL:
00097 if (!strcmp(param, "y")) val.d = 1.0;
00098 else if (!strcmp(param, "n")) val.d = 0.0;
00099 else goto fail;
00100 break;
00101
00102 case F0R_PARAM_DOUBLE:
00103 val.d = strtod(param, &tail);
00104 if (*tail || val.d == HUGE_VAL)
00105 goto fail;
00106 break;
00107
00108 case F0R_PARAM_COLOR:
00109 if (sscanf(param, "%f/%f/%f", &val.col.r, &val.col.g, &val.col.b) != 3) {
00110 if (av_parse_color(rgba, param, -1, ctx) < 0)
00111 goto fail;
00112 val.col.r = rgba[0] / 255.0;
00113 val.col.g = rgba[1] / 255.0;
00114 val.col.b = rgba[2] / 255.0;
00115 }
00116 break;
00117
00118 case F0R_PARAM_POSITION:
00119 if (sscanf(param, "%lf/%lf", &val.pos.x, &val.pos.y) != 2)
00120 goto fail;
00121 break;
00122 }
00123
00124 frei0r->set_param_value(frei0r->instance, &val, index);
00125 return 0;
00126
00127 fail:
00128 av_log(ctx, AV_LOG_ERROR, "Invalid value '%s' for parameter '%s'\n",
00129 param, info.name);
00130 return AVERROR(EINVAL);
00131 }
00132
00133 static int set_params(AVFilterContext *ctx, const char *params)
00134 {
00135 Frei0rContext *frei0r = ctx->priv;
00136 int i;
00137
00138 for (i = 0; i < frei0r->plugin_info.num_params; i++) {
00139 f0r_param_info_t info;
00140 char *param;
00141 int ret;
00142
00143 frei0r->get_param_info(&info, i);
00144
00145 if (*params) {
00146 if (!(param = av_get_token(¶ms, ":")))
00147 return AVERROR(ENOMEM);
00148 params++;
00149 ret = set_param(ctx, info, i, param);
00150 av_free(param);
00151 if (ret < 0)
00152 return ret;
00153 }
00154
00155 av_log(ctx, AV_LOG_VERBOSE,
00156 "idx:%d name:'%s' type:%s explanation:'%s' ",
00157 i, info.name,
00158 info.type == F0R_PARAM_BOOL ? "bool" :
00159 info.type == F0R_PARAM_DOUBLE ? "double" :
00160 info.type == F0R_PARAM_COLOR ? "color" :
00161 info.type == F0R_PARAM_POSITION ? "position" :
00162 info.type == F0R_PARAM_STRING ? "string" : "unknown",
00163 info.explanation);
00164
00165 #ifdef DEBUG
00166 av_log(ctx, AV_LOG_DEBUG, "value:");
00167 switch (info.type) {
00168 void *v;
00169 double d;
00170 char s[128];
00171 f0r_param_color_t col;
00172 f0r_param_position_t pos;
00173
00174 case F0R_PARAM_BOOL:
00175 v = &d;
00176 frei0r->get_param_value(frei0r->instance, v, i);
00177 av_log(ctx, AV_LOG_DEBUG, "%s", d >= 0.5 && d <= 1.0 ? "y" : "n");
00178 break;
00179 case F0R_PARAM_DOUBLE:
00180 v = &d;
00181 frei0r->get_param_value(frei0r->instance, v, i);
00182 av_log(ctx, AV_LOG_DEBUG, "%f", d);
00183 break;
00184 case F0R_PARAM_COLOR:
00185 v = &col;
00186 frei0r->get_param_value(frei0r->instance, v, i);
00187 av_log(ctx, AV_LOG_DEBUG, "%f/%f/%f", col.r, col.g, col.b);
00188 break;
00189 case F0R_PARAM_POSITION:
00190 v = &pos;
00191 frei0r->get_param_value(frei0r->instance, v, i);
00192 av_log(ctx, AV_LOG_DEBUG, "%lf/%lf", pos.x, pos.y);
00193 break;
00194 default:
00195 v = s;
00196 frei0r->get_param_value(frei0r->instance, v, i);
00197 av_log(ctx, AV_LOG_DEBUG, "'%s'\n", s);
00198 break;
00199 }
00200 #endif
00201 av_log(ctx, AV_LOG_VERBOSE, "\n");
00202 }
00203
00204 return 0;
00205 }
00206
00207 static void *load_path(AVFilterContext *ctx, const char *prefix, const char *name)
00208 {
00209 char path[1024];
00210
00211 snprintf(path, sizeof(path), "%s%s%s", prefix, name, SLIBSUF);
00212 av_log(ctx, AV_LOG_DEBUG, "Looking for frei0r effect in '%s'\n", path);
00213 return dlopen(path, RTLD_NOW|RTLD_LOCAL);
00214 }
00215
00216 static av_cold int frei0r_init(AVFilterContext *ctx,
00217 const char *dl_name, int type)
00218 {
00219 Frei0rContext *frei0r = ctx->priv;
00220 f0r_init_f f0r_init;
00221 f0r_get_plugin_info_f f0r_get_plugin_info;
00222 f0r_plugin_info_t *pi;
00223 char *path;
00224
00225
00226 if ((path = av_strdup(getenv("FREI0R_PATH")))) {
00227 char *p, *ptr = NULL;
00228 for (p = path; p = av_strtok(p, ":", &ptr); p = NULL)
00229 if (frei0r->dl_handle = load_path(ctx, p, dl_name))
00230 break;
00231 av_free(path);
00232 }
00233 if (!frei0r->dl_handle && (path = getenv("HOME"))) {
00234 char prefix[1024];
00235 snprintf(prefix, sizeof(prefix), "%s/.frei0r-1/lib/", path);
00236 frei0r->dl_handle = load_path(ctx, prefix, dl_name);
00237 }
00238 if (!frei0r->dl_handle)
00239 frei0r->dl_handle = load_path(ctx, "/usr/local/lib/frei0r-1/", dl_name);
00240 if (!frei0r->dl_handle)
00241 frei0r->dl_handle = load_path(ctx, "/usr/lib/frei0r-1/", dl_name);
00242 if (!frei0r->dl_handle) {
00243 av_log(ctx, AV_LOG_ERROR, "Could not find module '%s'\n", dl_name);
00244 return AVERROR(EINVAL);
00245 }
00246
00247 if (!(f0r_init = load_sym(ctx, "f0r_init" )) ||
00248 !(f0r_get_plugin_info = load_sym(ctx, "f0r_get_plugin_info")) ||
00249 !(frei0r->get_param_info = load_sym(ctx, "f0r_get_param_info" )) ||
00250 !(frei0r->get_param_value = load_sym(ctx, "f0r_get_param_value")) ||
00251 !(frei0r->set_param_value = load_sym(ctx, "f0r_set_param_value")) ||
00252 !(frei0r->update = load_sym(ctx, "f0r_update" )) ||
00253 !(frei0r->construct = load_sym(ctx, "f0r_construct" )) ||
00254 !(frei0r->destruct = load_sym(ctx, "f0r_destruct" )) ||
00255 !(frei0r->deinit = load_sym(ctx, "f0r_deinit" )))
00256 return AVERROR(EINVAL);
00257
00258 if (f0r_init() < 0) {
00259 av_log(ctx, AV_LOG_ERROR, "Could not init the frei0r module\n");
00260 return AVERROR(EINVAL);
00261 }
00262
00263 f0r_get_plugin_info(&frei0r->plugin_info);
00264 pi = &frei0r->plugin_info;
00265 if (pi->plugin_type != type) {
00266 av_log(ctx, AV_LOG_ERROR,
00267 "Invalid type '%s' for the plugin\n",
00268 pi->plugin_type == F0R_PLUGIN_TYPE_FILTER ? "filter" :
00269 pi->plugin_type == F0R_PLUGIN_TYPE_SOURCE ? "source" :
00270 pi->plugin_type == F0R_PLUGIN_TYPE_MIXER2 ? "mixer2" :
00271 pi->plugin_type == F0R_PLUGIN_TYPE_MIXER3 ? "mixer3" : "unknown");
00272 return AVERROR(EINVAL);
00273 }
00274
00275 av_log(ctx, AV_LOG_VERBOSE,
00276 "name:%s author:'%s' explanation:'%s' color_model:%s "
00277 "frei0r_version:%d version:%d.%d num_params:%d\n",
00278 pi->name, pi->author, pi->explanation,
00279 pi->color_model == F0R_COLOR_MODEL_BGRA8888 ? "bgra8888" :
00280 pi->color_model == F0R_COLOR_MODEL_RGBA8888 ? "rgba8888" :
00281 pi->color_model == F0R_COLOR_MODEL_PACKED32 ? "packed32" : "unknown",
00282 pi->frei0r_version, pi->major_version, pi->minor_version, pi->num_params);
00283
00284 return 0;
00285 }
00286
00287 static av_cold int filter_init(AVFilterContext *ctx, const char *args)
00288 {
00289 Frei0rContext *frei0r = ctx->priv;
00290 char dl_name[1024], c;
00291 *frei0r->params = 0;
00292
00293 if (args)
00294 sscanf(args, "%1023[^:=]%c%255c", dl_name, &c, frei0r->params);
00295
00296 return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_FILTER);
00297 }
00298
00299 static av_cold void uninit(AVFilterContext *ctx)
00300 {
00301 Frei0rContext *frei0r = ctx->priv;
00302
00303 if (frei0r->destruct && frei0r->instance)
00304 frei0r->destruct(frei0r->instance);
00305 if (frei0r->deinit)
00306 frei0r->deinit();
00307 if (frei0r->dl_handle)
00308 dlclose(frei0r->dl_handle);
00309
00310 memset(frei0r, 0, sizeof(*frei0r));
00311 }
00312
00313 static int config_input_props(AVFilterLink *inlink)
00314 {
00315 AVFilterContext *ctx = inlink->dst;
00316 Frei0rContext *frei0r = ctx->priv;
00317
00318 if (!(frei0r->instance = frei0r->construct(inlink->w, inlink->h))) {
00319 av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance\n");
00320 return AVERROR(EINVAL);
00321 }
00322
00323 return set_params(ctx, frei0r->params);
00324 }
00325
00326 static int query_formats(AVFilterContext *ctx)
00327 {
00328 Frei0rContext *frei0r = ctx->priv;
00329 AVFilterFormats *formats = NULL;
00330
00331 if (frei0r->plugin_info.color_model == F0R_COLOR_MODEL_BGRA8888) {
00332 ff_add_format(&formats, PIX_FMT_BGRA);
00333 } else if (frei0r->plugin_info.color_model == F0R_COLOR_MODEL_RGBA8888) {
00334 ff_add_format(&formats, PIX_FMT_RGBA);
00335 } else {
00336 static const enum PixelFormat pix_fmts[] = {
00337 PIX_FMT_BGRA, PIX_FMT_ARGB, PIX_FMT_ABGR, PIX_FMT_ARGB, PIX_FMT_NONE
00338 };
00339 formats = ff_make_format_list(pix_fmts);
00340 }
00341
00342 if (!formats)
00343 return AVERROR(ENOMEM);
00344
00345 ff_set_common_formats(ctx, formats);
00346 return 0;
00347 }
00348
00349 static int null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00350 {
00351 return 0;
00352 }
00353
00354 static int end_frame(AVFilterLink *inlink)
00355 {
00356 Frei0rContext *frei0r = inlink->dst->priv;
00357 AVFilterLink *outlink = inlink->dst->outputs[0];
00358 AVFilterBufferRef *inpicref = inlink->cur_buf;
00359 AVFilterBufferRef *outpicref = outlink->out_buf;
00360 int ret;
00361
00362 frei0r->update(frei0r->instance, inpicref->pts * av_q2d(inlink->time_base) * 1000,
00363 (const uint32_t *)inpicref->data[0],
00364 (uint32_t *)outpicref->data[0]);
00365 if ((ret = ff_draw_slice(outlink, 0, outlink->h, 1)) ||
00366 (ret = ff_end_frame(outlink)) < 0)
00367 return ret;
00368 return 0;
00369 }
00370
00371 AVFilter avfilter_vf_frei0r = {
00372 .name = "frei0r",
00373 .description = NULL_IF_CONFIG_SMALL("Apply a frei0r effect."),
00374
00375 .query_formats = query_formats,
00376 .init = filter_init,
00377 .uninit = uninit,
00378
00379 .priv_size = sizeof(Frei0rContext),
00380
00381 .inputs = (const AVFilterPad[]) {{ .name = "default",
00382 .type = AVMEDIA_TYPE_VIDEO,
00383 .draw_slice = null_draw_slice,
00384 .config_props = config_input_props,
00385 .end_frame = end_frame,
00386 .min_perms = AV_PERM_READ },
00387 { .name = NULL}},
00388
00389 .outputs = (const AVFilterPad[]) {{ .name = "default",
00390 .type = AVMEDIA_TYPE_VIDEO, },
00391 { .name = NULL}},
00392 };
00393
00394 static av_cold int source_init(AVFilterContext *ctx, const char *args)
00395 {
00396 Frei0rContext *frei0r = ctx->priv;
00397 char dl_name[1024], c;
00398 char frame_size[128] = "";
00399 char frame_rate[128] = "";
00400 AVRational frame_rate_q;
00401
00402 memset(frei0r->params, 0, sizeof(frei0r->params));
00403
00404 if (args)
00405 sscanf(args, "%127[^:]:%127[^:]:%1023[^:=]%c%255c",
00406 frame_size, frame_rate, dl_name, &c, frei0r->params);
00407
00408 if (av_parse_video_size(&frei0r->w, &frei0r->h, frame_size) < 0) {
00409 av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'\n", frame_size);
00410 return AVERROR(EINVAL);
00411 }
00412
00413 if (av_parse_video_rate(&frame_rate_q, frame_rate) < 0) {
00414 av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", frame_rate);
00415 return AVERROR(EINVAL);
00416 }
00417 frei0r->time_base.num = frame_rate_q.den;
00418 frei0r->time_base.den = frame_rate_q.num;
00419
00420 return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_SOURCE);
00421 }
00422
00423 static int source_config_props(AVFilterLink *outlink)
00424 {
00425 AVFilterContext *ctx = outlink->src;
00426 Frei0rContext *frei0r = ctx->priv;
00427
00428 if (av_image_check_size(frei0r->w, frei0r->h, 0, ctx) < 0)
00429 return AVERROR(EINVAL);
00430 outlink->w = frei0r->w;
00431 outlink->h = frei0r->h;
00432 outlink->time_base = frei0r->time_base;
00433 outlink->sample_aspect_ratio = (AVRational){1,1};
00434
00435 if (!(frei0r->instance = frei0r->construct(outlink->w, outlink->h))) {
00436 av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance\n");
00437 return AVERROR(EINVAL);
00438 }
00439
00440 return set_params(ctx, frei0r->params);
00441 }
00442
00443 static int source_request_frame(AVFilterLink *outlink)
00444 {
00445 Frei0rContext *frei0r = outlink->src->priv;
00446 AVFilterBufferRef *picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00447 AVFilterBufferRef *buf_out;
00448 int ret;
00449
00450 if (!picref)
00451 return AVERROR(ENOMEM);
00452
00453 picref->video->sample_aspect_ratio = (AVRational) {1, 1};
00454 picref->pts = frei0r->pts++;
00455 picref->pos = -1;
00456
00457 buf_out = avfilter_ref_buffer(picref, ~0);
00458 if (!buf_out) {
00459 ret = AVERROR(ENOMEM);
00460 goto fail;
00461 }
00462
00463 ret = ff_start_frame(outlink, buf_out);
00464 if (ret < 0)
00465 goto fail;
00466
00467 frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}),
00468 NULL, (uint32_t *)picref->data[0]);
00469 ret = ff_draw_slice(outlink, 0, outlink->h, 1);
00470 if (ret < 0)
00471 goto fail;
00472
00473 ret = ff_end_frame(outlink);
00474
00475 fail:
00476 avfilter_unref_buffer(picref);
00477
00478 return ret;
00479 }
00480
00481 AVFilter avfilter_vsrc_frei0r_src = {
00482 .name = "frei0r_src",
00483 .description = NULL_IF_CONFIG_SMALL("Generate a frei0r source."),
00484
00485 .priv_size = sizeof(Frei0rContext),
00486 .init = source_init,
00487 .uninit = uninit,
00488
00489 .query_formats = query_formats,
00490
00491 .inputs = NULL,
00492
00493 .outputs = (const AVFilterPad[]) {{ .name = "default",
00494 .type = AVMEDIA_TYPE_VIDEO,
00495 .request_frame = source_request_frame,
00496 .config_props = source_config_props },
00497 { .name = NULL}},
00498 };