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 int load_path(AVFilterContext *ctx, void **handle_ptr, const char *prefix, const char *name)
00208 {
00209 char *path = av_asprintf("%s%s%s", prefix, name, SLIBSUF);
00210 if (!path)
00211 return AVERROR(ENOMEM);
00212 av_log(ctx, AV_LOG_DEBUG, "Looking for frei0r effect in '%s'\n", path);
00213 *handle_ptr = dlopen(path, RTLD_NOW|RTLD_LOCAL);
00214 av_free(path);
00215 return 0;
00216 }
00217
00218 static av_cold int frei0r_init(AVFilterContext *ctx,
00219 const char *dl_name, int type)
00220 {
00221 Frei0rContext *frei0r = ctx->priv;
00222 f0r_init_f f0r_init;
00223 f0r_get_plugin_info_f f0r_get_plugin_info;
00224 f0r_plugin_info_t *pi;
00225 char *path;
00226 int ret = 0;
00227
00228
00229 if ((path = av_strdup(getenv("FREI0R_PATH")))) {
00230 #ifdef _WIN32
00231 const char *separator = ";";
00232 #else
00233 const char *separator = ":";
00234 #endif
00235 char *p, *ptr = NULL;
00236 for (p = path; p = av_strtok(p, separator, &ptr); p = NULL) {
00237
00238 char *p1 = av_asprintf("%s/", p);
00239 if (!p1) {
00240 ret = AVERROR(ENOMEM);
00241 goto check_path_end;
00242 }
00243 ret = load_path(ctx, &frei0r->dl_handle, p1, dl_name);
00244 av_free(p1);
00245 if (ret < 0)
00246 goto check_path_end;
00247 if (frei0r->dl_handle)
00248 break;
00249 }
00250
00251 check_path_end:
00252 av_free(path);
00253 if (ret < 0)
00254 return ret;
00255 }
00256 if (!frei0r->dl_handle && (path = getenv("HOME"))) {
00257 char *prefix = av_asprintf("%s/.frei0r-1/lib/", path);
00258 if (!prefix)
00259 return AVERROR(ENOMEM);
00260 ret = load_path(ctx, &frei0r->dl_handle, prefix, dl_name);
00261 av_free(prefix);
00262 if (ret < 0)
00263 return ret;
00264 }
00265 if (!frei0r->dl_handle) {
00266 ret = load_path(ctx, &frei0r->dl_handle, "/usr/local/lib/frei0r-1/", dl_name);
00267 if (ret < 0)
00268 return ret;
00269 }
00270 if (!frei0r->dl_handle) {
00271 ret = load_path(ctx, &frei0r->dl_handle, "/usr/lib/frei0r-1/", dl_name);
00272 if (ret < 0)
00273 return ret;
00274 }
00275 if (!frei0r->dl_handle) {
00276 av_log(ctx, AV_LOG_ERROR, "Could not find module '%s'\n", dl_name);
00277 return AVERROR(EINVAL);
00278 }
00279
00280 if (!(f0r_init = load_sym(ctx, "f0r_init" )) ||
00281 !(f0r_get_plugin_info = load_sym(ctx, "f0r_get_plugin_info")) ||
00282 !(frei0r->get_param_info = load_sym(ctx, "f0r_get_param_info" )) ||
00283 !(frei0r->get_param_value = load_sym(ctx, "f0r_get_param_value")) ||
00284 !(frei0r->set_param_value = load_sym(ctx, "f0r_set_param_value")) ||
00285 !(frei0r->update = load_sym(ctx, "f0r_update" )) ||
00286 !(frei0r->construct = load_sym(ctx, "f0r_construct" )) ||
00287 !(frei0r->destruct = load_sym(ctx, "f0r_destruct" )) ||
00288 !(frei0r->deinit = load_sym(ctx, "f0r_deinit" )))
00289 return AVERROR(EINVAL);
00290
00291 if (f0r_init() < 0) {
00292 av_log(ctx, AV_LOG_ERROR, "Could not init the frei0r module\n");
00293 return AVERROR(EINVAL);
00294 }
00295
00296 f0r_get_plugin_info(&frei0r->plugin_info);
00297 pi = &frei0r->plugin_info;
00298 if (pi->plugin_type != type) {
00299 av_log(ctx, AV_LOG_ERROR,
00300 "Invalid type '%s' for the plugin\n",
00301 pi->plugin_type == F0R_PLUGIN_TYPE_FILTER ? "filter" :
00302 pi->plugin_type == F0R_PLUGIN_TYPE_SOURCE ? "source" :
00303 pi->plugin_type == F0R_PLUGIN_TYPE_MIXER2 ? "mixer2" :
00304 pi->plugin_type == F0R_PLUGIN_TYPE_MIXER3 ? "mixer3" : "unknown");
00305 return AVERROR(EINVAL);
00306 }
00307
00308 av_log(ctx, AV_LOG_VERBOSE,
00309 "name:%s author:'%s' explanation:'%s' color_model:%s "
00310 "frei0r_version:%d version:%d.%d num_params:%d\n",
00311 pi->name, pi->author, pi->explanation,
00312 pi->color_model == F0R_COLOR_MODEL_BGRA8888 ? "bgra8888" :
00313 pi->color_model == F0R_COLOR_MODEL_RGBA8888 ? "rgba8888" :
00314 pi->color_model == F0R_COLOR_MODEL_PACKED32 ? "packed32" : "unknown",
00315 pi->frei0r_version, pi->major_version, pi->minor_version, pi->num_params);
00316
00317 return 0;
00318 }
00319
00320 static av_cold int filter_init(AVFilterContext *ctx, const char *args)
00321 {
00322 Frei0rContext *frei0r = ctx->priv;
00323 char dl_name[1024], c;
00324 *frei0r->params = 0;
00325
00326 if (args)
00327 sscanf(args, "%1023[^:=]%c%255c", dl_name, &c, frei0r->params);
00328
00329 return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_FILTER);
00330 }
00331
00332 static av_cold void uninit(AVFilterContext *ctx)
00333 {
00334 Frei0rContext *frei0r = ctx->priv;
00335
00336 if (frei0r->destruct && frei0r->instance)
00337 frei0r->destruct(frei0r->instance);
00338 if (frei0r->deinit)
00339 frei0r->deinit();
00340 if (frei0r->dl_handle)
00341 dlclose(frei0r->dl_handle);
00342
00343 memset(frei0r, 0, sizeof(*frei0r));
00344 }
00345
00346 static int config_input_props(AVFilterLink *inlink)
00347 {
00348 AVFilterContext *ctx = inlink->dst;
00349 Frei0rContext *frei0r = ctx->priv;
00350
00351 if (!(frei0r->instance = frei0r->construct(inlink->w, inlink->h))) {
00352 av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance\n");
00353 return AVERROR(EINVAL);
00354 }
00355
00356 return set_params(ctx, frei0r->params);
00357 }
00358
00359 static int query_formats(AVFilterContext *ctx)
00360 {
00361 Frei0rContext *frei0r = ctx->priv;
00362 AVFilterFormats *formats = NULL;
00363
00364 if (frei0r->plugin_info.color_model == F0R_COLOR_MODEL_BGRA8888) {
00365 ff_add_format(&formats, AV_PIX_FMT_BGRA);
00366 } else if (frei0r->plugin_info.color_model == F0R_COLOR_MODEL_RGBA8888) {
00367 ff_add_format(&formats, AV_PIX_FMT_RGBA);
00368 } else {
00369 static const enum AVPixelFormat pix_fmts[] = {
00370 AV_PIX_FMT_BGRA, AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, AV_PIX_FMT_ARGB, AV_PIX_FMT_NONE
00371 };
00372 formats = ff_make_format_list(pix_fmts);
00373 }
00374
00375 if (!formats)
00376 return AVERROR(ENOMEM);
00377
00378 ff_set_common_formats(ctx, formats);
00379 return 0;
00380 }
00381
00382 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
00383 {
00384 Frei0rContext *frei0r = inlink->dst->priv;
00385 AVFilterLink *outlink = inlink->dst->outputs[0];
00386 AVFilterBufferRef *out;
00387
00388 out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00389 if (!out) {
00390 avfilter_unref_bufferp(&in);
00391 return AVERROR(ENOMEM);
00392 }
00393 avfilter_copy_buffer_ref_props(out, in);
00394
00395 frei0r->update(frei0r->instance, in->pts * av_q2d(inlink->time_base) * 1000,
00396 (const uint32_t *)in->data[0],
00397 (uint32_t *)out->data[0]);
00398
00399 avfilter_unref_bufferp(&in);
00400
00401 return ff_filter_frame(outlink, out);
00402 }
00403
00404 static const AVFilterPad avfilter_vf_frei0r_inputs[] = {
00405 {
00406 .name = "default",
00407 .type = AVMEDIA_TYPE_VIDEO,
00408 .config_props = config_input_props,
00409 .filter_frame = filter_frame,
00410 .min_perms = AV_PERM_READ
00411 },
00412 { NULL }
00413 };
00414
00415 static const AVFilterPad avfilter_vf_frei0r_outputs[] = {
00416 {
00417 .name = "default",
00418 .type = AVMEDIA_TYPE_VIDEO,
00419 },
00420 { NULL }
00421 };
00422
00423 AVFilter avfilter_vf_frei0r = {
00424 .name = "frei0r",
00425 .description = NULL_IF_CONFIG_SMALL("Apply a frei0r effect."),
00426
00427 .query_formats = query_formats,
00428 .init = filter_init,
00429 .uninit = uninit,
00430
00431 .priv_size = sizeof(Frei0rContext),
00432
00433 .inputs = avfilter_vf_frei0r_inputs,
00434
00435 .outputs = avfilter_vf_frei0r_outputs,
00436 };
00437
00438 static av_cold int source_init(AVFilterContext *ctx, const char *args)
00439 {
00440 Frei0rContext *frei0r = ctx->priv;
00441 char dl_name[1024], c;
00442 char frame_size[128] = "";
00443 char frame_rate[128] = "";
00444 AVRational frame_rate_q;
00445
00446 memset(frei0r->params, 0, sizeof(frei0r->params));
00447
00448 if (args)
00449 sscanf(args, "%127[^:]:%127[^:]:%1023[^:=]%c%255c",
00450 frame_size, frame_rate, dl_name, &c, frei0r->params);
00451
00452 if (av_parse_video_size(&frei0r->w, &frei0r->h, frame_size) < 0) {
00453 av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'\n", frame_size);
00454 return AVERROR(EINVAL);
00455 }
00456
00457 if (av_parse_video_rate(&frame_rate_q, frame_rate) < 0) {
00458 av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", frame_rate);
00459 return AVERROR(EINVAL);
00460 }
00461 frei0r->time_base.num = frame_rate_q.den;
00462 frei0r->time_base.den = frame_rate_q.num;
00463
00464 return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_SOURCE);
00465 }
00466
00467 static int source_config_props(AVFilterLink *outlink)
00468 {
00469 AVFilterContext *ctx = outlink->src;
00470 Frei0rContext *frei0r = ctx->priv;
00471
00472 if (av_image_check_size(frei0r->w, frei0r->h, 0, ctx) < 0)
00473 return AVERROR(EINVAL);
00474 outlink->w = frei0r->w;
00475 outlink->h = frei0r->h;
00476 outlink->time_base = frei0r->time_base;
00477 outlink->sample_aspect_ratio = (AVRational){1,1};
00478
00479 if (!(frei0r->instance = frei0r->construct(outlink->w, outlink->h))) {
00480 av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance\n");
00481 return AVERROR(EINVAL);
00482 }
00483
00484 return set_params(ctx, frei0r->params);
00485 }
00486
00487 static int source_request_frame(AVFilterLink *outlink)
00488 {
00489 Frei0rContext *frei0r = outlink->src->priv;
00490 AVFilterBufferRef *picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00491
00492 if (!picref)
00493 return AVERROR(ENOMEM);
00494
00495 picref->video->sample_aspect_ratio = (AVRational) {1, 1};
00496 picref->pts = frei0r->pts++;
00497 picref->pos = -1;
00498
00499 frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}),
00500 NULL, (uint32_t *)picref->data[0]);
00501
00502 return ff_filter_frame(outlink, picref);
00503 }
00504
00505 static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = {
00506 {
00507 .name = "default",
00508 .type = AVMEDIA_TYPE_VIDEO,
00509 .request_frame = source_request_frame,
00510 .config_props = source_config_props
00511 },
00512 { NULL }
00513 };
00514
00515 AVFilter avfilter_vsrc_frei0r_src = {
00516 .name = "frei0r_src",
00517 .description = NULL_IF_CONFIG_SMALL("Generate a frei0r source."),
00518
00519 .priv_size = sizeof(Frei0rContext),
00520 .init = source_init,
00521 .uninit = uninit,
00522
00523 .query_formats = query_formats,
00524
00525 .inputs = NULL,
00526
00527 .outputs = avfilter_vsrc_frei0r_src_outputs,
00528 };