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