00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "framehook.h"
00049 #include "swscale.h"
00050
00051 #include <stdio.h>
00052 #include <stdlib.h>
00053 #include <fcntl.h>
00054 #include <stdarg.h>
00055 #include <string.h>
00056 #include <unistd.h>
00057 #undef time
00058 #include <sys/time.h>
00059 #include <time.h>
00060 #include <Imlib2.h>
00061 #include "eval.h"
00062
00063 const char *const_names[]={
00064 "PI",
00065 "E",
00066 "N",
00067 "H",
00068 "W",
00069 "h",
00070 "w",
00071 "X",
00072 "Y",
00073 NULL
00074 };
00075
00076 static int sws_flags = SWS_BICUBIC;
00077
00078 typedef struct {
00079 int dummy;
00080 Imlib_Font fn;
00081 char *text;
00082 char *file;
00083 int r, g, b, a;
00084 AVEvalExpr *eval_r, *eval_g, *eval_b, *eval_a;
00085 char *expr_R, *expr_G, *expr_B, *expr_A;
00086 int eval_colors;
00087 double x, y;
00088 char *fileImage;
00089 struct CachedImage *cache;
00090 Imlib_Image imageOverlaid;
00091 AVEvalExpr *eval_x, *eval_y;
00092 char *expr_x, *expr_y;
00093 int frame_number;
00094 int imageOverlaid_width, imageOverlaid_height;
00095
00096
00097 struct SwsContext *toRGB_convert_ctx;
00098
00099 struct SwsContext *fromRGB_convert_ctx;
00100 } ContextInfo;
00101
00102 typedef struct CachedImage {
00103 struct CachedImage *next;
00104 Imlib_Image image;
00105 int width;
00106 int height;
00107 } CachedImage;
00108
00109 void Release(void *ctx)
00110 {
00111 ContextInfo *ci;
00112 ci = (ContextInfo *) ctx;
00113
00114 if (ci->cache) {
00115 imlib_context_set_image(ci->cache->image);
00116 imlib_free_image();
00117 av_free(ci->cache);
00118 }
00119 if (ctx) {
00120 if (ci->imageOverlaid) {
00121 imlib_context_set_image(ci->imageOverlaid);
00122 imlib_free_image();
00123 }
00124 ff_eval_free(ci->eval_x);
00125 ff_eval_free(ci->eval_y);
00126 ff_eval_free(ci->eval_r);
00127 ff_eval_free(ci->eval_g);
00128 ff_eval_free(ci->eval_b);
00129 ff_eval_free(ci->eval_a);
00130
00131 av_free(ci->expr_x);
00132 av_free(ci->expr_y);
00133 av_free(ci->expr_R);
00134 av_free(ci->expr_G);
00135 av_free(ci->expr_B);
00136 av_free(ci->expr_A);
00137 sws_freeContext(ci->toRGB_convert_ctx);
00138 sws_freeContext(ci->fromRGB_convert_ctx);
00139 av_free(ctx);
00140 }
00141 }
00142
00143 int Configure(void **ctxp, int argc, char *argv[])
00144 {
00145 int c;
00146 ContextInfo *ci;
00147 char *rgbtxt = 0;
00148 char *font = "LucidaSansDemiBold/16";
00149 char *fp = getenv("FONTPATH");
00150 char *color = 0;
00151 FILE *f;
00152 char *p;
00153 char *error;
00154
00155 *ctxp = av_mallocz(sizeof(ContextInfo));
00156 ci = (ContextInfo *) *ctxp;
00157
00158 ci->x = 0.0;
00159 ci->y = 0.0;
00160 ci->expr_x = "0.0";
00161 ci->expr_y = "0.0";
00162
00163 optind = 1;
00164
00165
00166 if (fp)
00167 while (p = strchr(fp, ':')) {
00168 *p = 0;
00169 imlib_add_path_to_font_path(fp);
00170 fp = p + 1;
00171 }
00172 if ((fp) && (*fp))
00173 imlib_add_path_to_font_path(fp);
00174
00175
00176 while ((c = getopt(argc, argv, "R:G:B:A:C:c:f:F:t:x:y:i:")) > 0) {
00177 switch (c) {
00178 case 'R':
00179 ci->expr_R = av_strdup(optarg);
00180 ci->eval_colors = 1;
00181 break;
00182 case 'G':
00183 ci->expr_G = av_strdup(optarg);
00184 ci->eval_colors = 1;
00185 break;
00186 case 'B':
00187 ci->expr_B = av_strdup(optarg);
00188 ci->eval_colors = 1;
00189 break;
00190 case 'A':
00191 ci->expr_A = av_strdup(optarg);
00192 break;
00193 case 'C':
00194 rgbtxt = optarg;
00195 break;
00196 case 'c':
00197 color = optarg;
00198 break;
00199 case 'F':
00200 font = optarg;
00201 break;
00202 case 't':
00203 ci->text = av_strdup(optarg);
00204 break;
00205 case 'f':
00206 ci->file = av_strdup(optarg);
00207 break;
00208 case 'x':
00209 ci->expr_x = av_strdup(optarg);
00210 break;
00211 case 'y':
00212 ci->expr_y = av_strdup(optarg);
00213 break;
00214 case 'i':
00215 ci->fileImage = av_strdup(optarg);
00216 break;
00217 case '?':
00218 fprintf(stderr, "Unrecognized argument '%s'\n", argv[optind]);
00219 return -1;
00220 }
00221 }
00222
00223 if (ci->eval_colors && !(ci->expr_R && ci->expr_G && ci->expr_B))
00224 {
00225 fprintf(stderr, "You must specify expressions for all or no colors.\n");
00226 return -1;
00227 }
00228
00229 if (ci->text || ci->file) {
00230 ci->fn = imlib_load_font(font);
00231 if (!ci->fn) {
00232 fprintf(stderr, "Failed to load font '%s'\n", font);
00233 return -1;
00234 }
00235 imlib_context_set_font(ci->fn);
00236 imlib_context_set_direction(IMLIB_TEXT_TO_RIGHT);
00237 }
00238
00239 if (color) {
00240 char buff[256];
00241 int done = 0;
00242
00243 if (ci->eval_colors)
00244 {
00245 fprintf(stderr, "You must not specify both a color name and expressions for the colors.\n");
00246 return -1;
00247 }
00248
00249 if (rgbtxt)
00250 f = fopen(rgbtxt, "r");
00251 else
00252 {
00253 f = fopen("/usr/share/X11/rgb.txt", "r");
00254 if (!f)
00255 f = fopen("/usr/lib/X11/rgb.txt", "r");
00256 }
00257 if (!f) {
00258 fprintf(stderr, "Failed to find RGB color names file\n");
00259 return -1;
00260 }
00261 while (fgets(buff, sizeof(buff), f)) {
00262 int r, g, b;
00263 char colname[80];
00264
00265 if (sscanf(buff, "%d %d %d %64s", &r, &g, &b, colname) == 4 &&
00266 strcasecmp(colname, color) == 0) {
00267 ci->r = r;
00268 ci->g = g;
00269 ci->b = b;
00270
00271 done = 1;
00272 break;
00273 }
00274 }
00275 fclose(f);
00276 if (!done) {
00277 fprintf(stderr, "Unable to find color '%s' in rgb.txt\n", color);
00278 return -1;
00279 }
00280 } else if (ci->eval_colors) {
00281 if (!(ci->eval_r = ff_parse(ci->expr_R, const_names, NULL, NULL, NULL, NULL, &error))){
00282 av_log(NULL, AV_LOG_ERROR, "Couldn't parse R expression '%s': %s\n", ci->expr_R, error);
00283 return -1;
00284 }
00285 if (!(ci->eval_g = ff_parse(ci->expr_G, const_names, NULL, NULL, NULL, NULL, &error))){
00286 av_log(NULL, AV_LOG_ERROR, "Couldn't parse G expression '%s': %s\n", ci->expr_G, error);
00287 return -1;
00288 }
00289 if (!(ci->eval_b = ff_parse(ci->expr_B, const_names, NULL, NULL, NULL, NULL, &error))){
00290 av_log(NULL, AV_LOG_ERROR, "Couldn't parse B expression '%s': %s\n", ci->expr_B, error);
00291 return -1;
00292 }
00293 }
00294
00295 if (ci->expr_A) {
00296 if (!(ci->eval_a = ff_parse(ci->expr_A, const_names, NULL, NULL, NULL, NULL, &error))){
00297 av_log(NULL, AV_LOG_ERROR, "Couldn't parse A expression '%s': %s\n", ci->expr_A, error);
00298 return -1;
00299 }
00300 } else {
00301 ci->a = 255;
00302 }
00303
00304 if (!(ci->eval_colors || ci->eval_a))
00305 imlib_context_set_color(ci->r, ci->g, ci->b, ci->a);
00306
00307
00308 if (ci->fileImage) {
00309 ci->imageOverlaid = imlib_load_image_immediately(ci->fileImage);
00310 if (!(ci->imageOverlaid)){
00311 av_log(NULL, AV_LOG_ERROR, "Couldn't load image '%s'\n", ci->fileImage);
00312 return -1;
00313 }
00314 imlib_context_set_image(ci->imageOverlaid);
00315 ci->imageOverlaid_width = imlib_image_get_width();
00316 ci->imageOverlaid_height = imlib_image_get_height();
00317 }
00318
00319 if (!(ci->eval_x = ff_parse(ci->expr_x, const_names, NULL, NULL, NULL, NULL, &error))){
00320 av_log(NULL, AV_LOG_ERROR, "Couldn't parse x expression '%s': %s\n", ci->expr_x, error);
00321 return -1;
00322 }
00323
00324 if (!(ci->eval_y = ff_parse(ci->expr_y, const_names, NULL, NULL, NULL, NULL, &error))){
00325 av_log(NULL, AV_LOG_ERROR, "Couldn't parse y expression '%s': %s\n", ci->expr_y, error);
00326 return -1;
00327 }
00328
00329 return 0;
00330 }
00331
00332 static Imlib_Image get_cached_image(ContextInfo *ci, int width, int height)
00333 {
00334 CachedImage *cache;
00335
00336 for (cache = ci->cache; cache; cache = cache->next) {
00337 if (width == cache->width && height == cache->height)
00338 return cache->image;
00339 }
00340
00341 return NULL;
00342 }
00343
00344 static void put_cached_image(ContextInfo *ci, Imlib_Image image, int width, int height)
00345 {
00346 CachedImage *cache = av_mallocz(sizeof(*cache));
00347
00348 cache->image = image;
00349 cache->width = width;
00350 cache->height = height;
00351 cache->next = ci->cache;
00352 ci->cache = cache;
00353 }
00354
00355 void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
00356 {
00357 ContextInfo *ci = (ContextInfo *) ctx;
00358 AVPicture picture1;
00359 Imlib_Image image;
00360 DATA32 *data;
00361
00362 image = get_cached_image(ci, width, height);
00363
00364 if (!image) {
00365 image = imlib_create_image(width, height);
00366 put_cached_image(ci, image, width, height);
00367 }
00368
00369 imlib_context_set_image(image);
00370 data = imlib_image_get_data();
00371
00372 avpicture_fill(&picture1, (uint8_t *) data, PIX_FMT_RGB32, width, height);
00373
00374
00375 ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
00376 width, height, pix_fmt,
00377 width, height, PIX_FMT_RGB32,
00378 sws_flags, NULL, NULL, NULL);
00379 if (ci->toRGB_convert_ctx == NULL) {
00380 av_log(NULL, AV_LOG_ERROR,
00381 "Cannot initialize the toRGB conversion context\n");
00382 return;
00383 }
00384
00385
00386
00387 sws_scale(ci->toRGB_convert_ctx,
00388 picture->data, picture->linesize, 0, height,
00389 picture1.data, picture1.linesize);
00390
00391 imlib_image_set_has_alpha(0);
00392
00393 {
00394 int wid, hig, h_a, v_a;
00395 char buff[1000];
00396 char tbuff[1000];
00397 char *tbp = ci->text;
00398 time_t now = time(0);
00399 char *p, *q;
00400 int y;
00401
00402 double const_values[]={
00403 M_PI,
00404 M_E,
00405 ci->frame_number,
00406 height,
00407 width,
00408 ci->imageOverlaid_height,
00409 ci->imageOverlaid_width,
00410 ci->x,
00411 ci->y,
00412 0
00413 };
00414
00415 if (ci->file) {
00416 int fd = open(ci->file, O_RDONLY);
00417
00418 if (fd < 0) {
00419 tbp = "[File not found]";
00420 } else {
00421 int l = read(fd, tbuff, sizeof(tbuff) - 1);
00422
00423 if (l >= 0) {
00424 tbuff[l] = 0;
00425 tbp = tbuff;
00426 } else {
00427 tbp = "[I/O Error]";
00428 }
00429 close(fd);
00430 }
00431 }
00432
00433 if (tbp)
00434 strftime(buff, sizeof(buff), tbp, localtime(&now));
00435 else if (!(ci->imageOverlaid))
00436 strftime(buff, sizeof(buff), "[No data]", localtime(&now));
00437
00438 ci->x = ff_parse_eval(ci->eval_x, const_values, ci);
00439 ci->y = ff_parse_eval(ci->eval_y, const_values, ci);
00440 y = ci->y;
00441
00442 if (ci->eval_a) {
00443 ci->a = ff_parse_eval(ci->eval_a, const_values, ci);
00444 }
00445
00446 if (ci->eval_colors) {
00447 ci->r = ff_parse_eval(ci->eval_r, const_values, ci);
00448 ci->g = ff_parse_eval(ci->eval_g, const_values, ci);
00449 ci->b = ff_parse_eval(ci->eval_b, const_values, ci);
00450 }
00451
00452 if (ci->eval_colors || ci->eval_a) {
00453 imlib_context_set_color(ci->r, ci->g, ci->b, ci->a);
00454 }
00455
00456 if (!(ci->imageOverlaid))
00457 for (p = buff; p; p = q) {
00458 q = strchr(p, '\n');
00459 if (q)
00460 *q++ = 0;
00461
00462 imlib_text_draw_with_return_metrics(ci->x, y, p, &wid, &hig, &h_a, &v_a);
00463 y += v_a;
00464 }
00465
00466 if (ci->imageOverlaid) {
00467 imlib_context_set_image(image);
00468 imlib_blend_image_onto_image(ci->imageOverlaid, 0,
00469 0, 0, ci->imageOverlaid_width, ci->imageOverlaid_height,
00470 ci->x, ci->y, ci->imageOverlaid_width, ci->imageOverlaid_height);
00471 }
00472
00473 }
00474
00475 ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
00476 width, height, PIX_FMT_RGB32,
00477 width, height, pix_fmt,
00478 sws_flags, NULL, NULL, NULL);
00479 if (ci->fromRGB_convert_ctx == NULL) {
00480 av_log(NULL, AV_LOG_ERROR,
00481 "Cannot initialize the fromRGB conversion context\n");
00482 return;
00483 }
00484
00485
00486 sws_scale(ci->fromRGB_convert_ctx,
00487 picture1.data, picture1.linesize, 0, height,
00488 picture->data, picture->linesize);
00489
00490 ci->frame_number++;
00491 }
00492