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