1 /*
2 * filter_pv.c
3 *
4 * Copyright (C) Thomas Oestreich - October 2002
5 *
6 * This file is part of transcode, a video stream processing tool
7 *
8 * transcode is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * transcode is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Make; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24 #define MOD_NAME "filter_pv.so"
25 #define MOD_VERSION "v0.2.3 (2004-06-01)"
26 #define MOD_CAP "xv only preview plugin"
27 #define MOD_AUTHOR "Thomas Oestreich, Tilmann Bitterberg"
28
29 #include "transcode.h"
30 #include "filter.h"
31 #include "libtc/optstr.h"
32 #include "libtcvideo/tcvideo.h"
33
34 #include "video_trans.h"
35
36 #ifdef HAVE_DLFCN_H
37 #include <dlfcn.h>
38 #else
39 # ifdef OS_DARWIN
40 # include "libdldarwin/dlfcn.h"
41 # endif
42 #endif
43
44 #include "pv.h"
45 #include "font_xpm.h"
46
47
48 static int cache_num=0;
49 static int cache_ptr=0;
50 static int cache_enabled=0;
51
52 //cache navigation
53 int cache_long_skip = 25;
54 int cache_short_skip = 1;
55
56 static char *vid_buf_mem=NULL;
57 static char **vid_buf=NULL;
58
59 static int w, h;
60
61 static int cols=20;
62 static int rows=20;
63
64 static char buffer[128];
65 static int size=0;
66 static int use_secondary_buffer=0;
67 static ImageFormat srcfmt = IMG_NONE, destfmt = IMG_NONE;
68
69 static int xv_init_ok=0;
70
71 static int preview_delay=0;
72 static int preview_skip=0, preview_skip_num=25;
73 static int preview_xv_port=0;
74 static char *undo_buffer = NULL;
75 static char *run_buffer[2] = {NULL, NULL};
76 static char *process_buffer[3] = {NULL, NULL, NULL};
77
78 static int process_ctr_cur=0;
79
80 static TCVHandle tcvhandle;
81
82
83 /* global variables */
84
85 static xv_player_t *xv_player = NULL;
86
87
88 #define ONE_SECOND 1000000 // in units of usec
89
inc_preview_delay(void)90 void inc_preview_delay(void)
91 {
92 preview_delay+=ONE_SECOND/10;
93 if(preview_delay>ONE_SECOND) preview_delay=ONE_SECOND;
94 }
95
dec_preview_delay(void)96 void dec_preview_delay(void)
97 {
98 preview_delay-=ONE_SECOND/10;
99 if(preview_delay<0) preview_delay=0;
100 }
101
preview_toggle_skip(void)102 void preview_toggle_skip(void)
103 {
104 preview_skip = (preview_skip>0) ? 0: preview_skip_num;
105 }
106
107 /*-------------------------------------------------
108 *
109 * single function interface
110 *
111 *-------------------------------------------------*/
112
tc_filter(frame_list_t * ptr_,char * options)113 int tc_filter(frame_list_t *ptr_, char *options)
114 {
115 vframe_list_t *ptr = (vframe_list_t *)ptr_;
116 vob_t *vob=NULL;
117
118 int pre=0, vid=0;
119
120 if(ptr->tag & TC_FILTER_GET_CONFIG) {
121 optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VY4O", "1");
122 optstr_param (options, "cache", "Number of raw frames to cache for seeking", "%d", "15", "15", "255");
123 optstr_param (options, "skip", "display only every Nth frame", "%d", "0", "0", "255");
124 optstr_param (options, "fullscreen", "Display in fullscreen mode","", "0");
125 optstr_param (options, "port", "force Xv port","%d", "0", "0", "255");
126 }
127
128 //----------------------------------
129 //
130 // filter init
131 //
132 //----------------------------------
133
134 if(ptr->tag & TC_FILTER_INIT) {
135
136 if((vob = tc_get_vob())==NULL) return(-1);
137
138 // filter init ok.
139
140 if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
141
142 if (options != NULL) {
143
144 if(verbose) tc_log_info(MOD_NAME, "options=%s", options);
145
146 optstr_get (options, "cache", "%d", &cache_num);
147
148 //adjust for small buffers
149 if(cache_num && cache_num<15) {
150 cache_num=15;
151 cache_long_skip=5;
152 }
153
154 optstr_get (options, "skip", "%d", &preview_skip_num);
155 if (optstr_lookup(options, "help")) return -1;
156
157 }
158
159 if(cache_num<0) tc_log_warn(MOD_NAME, "invalid cache number - exit");
160 if(preview_skip_num<0) tc_log_warn(MOD_NAME, "invalid number of frames to skip - exit");
161
162 tc_snprintf(buffer, sizeof(buffer), "%s-%s", PACKAGE, VERSION);
163
164 if(xv_player != NULL) return(-1);
165 if(!(xv_player = xv_player_new())) return(-1);
166
167
168 if (options != NULL) {
169 if(optstr_lookup(options, "fullscreen") != NULL)
170 xv_player->display->full_screen = 1;
171 optstr_get (options, "port", "%d", &preview_xv_port);
172 if(preview_xv_port != 0) {
173 tc_log_info(MOD_NAME, "forced Xv port: %d", preview_xv_port);
174 xv_player->display->arg_xv_port = preview_xv_port;
175 }
176 }
177
178
179 //init filter
180
181 w = vob->ex_v_width;
182 h = vob->ex_v_height;
183
184 size = w*h* 3/2;
185
186 if(verbose) tc_log_info(MOD_NAME, "preview window %dx%d", w, h);
187
188 tcvhandle = tcv_init();
189 if (!tcvhandle) {
190 tc_log_error(MOD_NAME, "tcv_init() failed");
191 return -1;
192 }
193
194 switch(vob->im_v_codec) {
195
196 case CODEC_YUV422:
197
198 if(xv_display_init(xv_player->display, 0, NULL,
199 w, h, buffer, buffer, 1)<0) return(-1);
200 size = w*h*2;
201 srcfmt = IMG_YUV422P;
202 destfmt = IMG_YUY2;
203
204 break;
205
206 case CODEC_YUV:
207
208 if(xv_display_init(xv_player->display, 0, NULL,
209 w, h, buffer, buffer, 0)<0) return(-1);
210
211 break;
212
213 case CODEC_RAW_YUV:
214
215 if(xv_display_init(xv_player->display, 0, NULL,
216 w, h, buffer, buffer, 0)<0) return(-1);
217 use_secondary_buffer=1;
218 break;
219
220 default:
221 tc_log_error(MOD_NAME, "non-YUV codecs not supported for this preview plug-in");
222 return(-1);
223 }
224
225 //cache
226
227 if (cache_num) {
228 if(preview_cache_init()<0) return(-1);
229
230 /* FIXME: these are never freed! */
231 if ((undo_buffer = tc_bufalloc(SIZE_RGB_FRAME)) == NULL)
232 return (-1);
233 if ((run_buffer[0] = tc_bufalloc (SIZE_RGB_FRAME)) == NULL)
234 return (-1);
235 if ((run_buffer[1] = tc_bufalloc (SIZE_RGB_FRAME)) == NULL)
236 return (-1);
237 if ((process_buffer[0] = tc_bufalloc (SIZE_RGB_FRAME)) == NULL)
238 return (-1);
239 if ((process_buffer[1] = tc_bufalloc (SIZE_RGB_FRAME)) == NULL)
240 return (-1);
241 if ((process_buffer[2] = tc_bufalloc (SIZE_RGB_FRAME)) == NULL)
242 return (-1);
243
244 }
245
246 xv_init_ok=1;
247
248 return(0);
249 }
250
251 //----------------------------------
252 //
253 // filter close
254 //
255 //----------------------------------
256
257 if(ptr->tag & TC_FILTER_CLOSE) {
258
259 if(!xv_init_ok) return(0);
260
261 if(size) xv_display_exit(xv_player->display);
262
263 tcv_free(tcvhandle);
264 tcvhandle = 0;
265
266 return(0);
267 }
268
269 //----------------------------------
270 //
271 // filter frame routine
272 //
273 //----------------------------------
274
275 // tag variable indicates, if we are called before
276 // transcodes internal video/audo frame processing routines
277 // or after and determines video/audio context
278
279 if(verbose & TC_STATS) tc_log_info(MOD_NAME, "%s/%s %s %s", vob->mod_path, MOD_NAME, MOD_VERSION, MOD_CAP);
280
281 //we do nothing if not properly initialized
282 if(!xv_init_ok) return(0);
283
284 // tag variable indicates, if we are called before
285 // transcodes internal video/audo frame processing routines
286 // or after and determines video/audio context
287
288 pre = (ptr->tag & TC_PREVIEW)? 1:0;
289 vid = (ptr->tag & TC_VIDEO)? 1:0;
290
291 if( (ptr->tag & TC_PRE_M_PROCESS) && vid && cache_enabled) {
292 process_ctr_cur = (process_ctr_cur+1)%3;
293 ac_memcpy (process_buffer[process_ctr_cur], ptr->video_buf, ptr->video_size);
294 return 0;
295 }
296 if(pre && vid) {
297
298 if(preview_skip && (ptr->id % preview_skip_num)) return(0);
299
300 if(!xv_player->display->dontdraw) {
301
302 //0.6.2 (secondaray buffer for pass-through mode)
303 if (use_secondary_buffer) {
304 ac_memcpy(xv_player->display->pixels[0], ptr->video_buf2, size);
305 } else if (srcfmt != IMG_NONE && destfmt != IMG_NONE) {
306 tcv_convert(tcvhandle, ptr->video_buf,
307 (uint8_t *)xv_player->display->pixels,
308 w, h, srcfmt, destfmt);
309 } else {
310 ac_memcpy(xv_player->display->pixels[0], ptr->video_buf, size);
311 }
312
313 //display video frame
314 xv_display_show(xv_player->display);
315
316 if(cache_enabled) preview_cache_submit(xv_player->display->pixels[0], ptr->id, ptr->attributes);
317
318 if(preview_delay) usleep(preview_delay);
319
320 } else {
321
322 //check only for X11-events
323 xv_display_event(xv_player->display);
324
325 }//dontdraw=1?
326
327 }//correct slot?
328
329 return(0);
330 }
331
preview_cache_init(void)332 int preview_cache_init(void) {
333
334 //size must be know!
335
336 int n;
337
338 if((vid_buf_mem = (char *) calloc(cache_num, size))==NULL) {
339 tc_log_perror(MOD_NAME, "out of memory");
340 return(-1);
341 }
342
343 if((vid_buf = (char **) calloc(cache_num, sizeof(char *)))==NULL) {
344 tc_log_perror(MOD_NAME, "out of memory");
345 return(-1);
346 }
347
348 for (n=0; n<cache_num; ++n) vid_buf[n] = (char *) (vid_buf_mem + n * size);
349
350 cache_enabled=1;
351
352 return(0);
353
354 }
355
preview_cache_submit(char * buf,int id,int flag)356 void preview_cache_submit(char *buf, int id, int flag) {
357
358 char string[255];
359 memset (string, 0, 255);
360
361 if(!cache_enabled) return;
362
363 cache_ptr = (cache_ptr+1)%cache_num;
364
365 ac_memcpy((char*) vid_buf[cache_ptr], buf, size);
366
367 (flag & TC_FRAME_IS_KEYFRAME) ? tc_snprintf(string, sizeof(string), "%u *", id) : tc_snprintf(string, sizeof(string), "%u", id);
368
369 str2img (vid_buf[cache_ptr], string, w, h, cols, rows, 0, 0, CODEC_YUV);
370 }
371
preview_filter_buffer(int frames_needed)372 int preview_filter_buffer(int frames_needed)
373 {
374 int current,i;
375
376 static int this_filter = 0;
377 static vframe_list_t *ptr = NULL;
378 vob_t *vob = tc_get_vob();
379
380 if (ptr == NULL)
381 ptr = malloc (sizeof (vframe_list_t));
382 memset (ptr, 0, sizeof (vframe_list_t));
383
384 if (!cache_enabled) return 0;
385
386 if (this_filter == 0)
387 this_filter = tc_filter_find("pv");
388
389 for (current = frames_needed, i = 1; current > 0; current--, i++){
390
391 #undef NO_PROCESS
392 #ifdef NO_PROCESS
393 ac_memcpy (run_buffer[0], (char *)vid_buf[cache_ptr-(current-1)], size);
394 ac_memcpy (run_buffer[1], (char *)vid_buf[cache_ptr-(current-1)], size);
395 #else
396 ac_memcpy (run_buffer[0], process_buffer[(process_ctr_cur+1)%3], SIZE_RGB_FRAME);
397 ac_memcpy (run_buffer[1], process_buffer[(process_ctr_cur+1)%3], SIZE_RGB_FRAME);
398 #endif
399
400 if (i == 1) {
401 ac_memcpy (undo_buffer, (char *)vid_buf[cache_ptr], size);
402 }
403
404 ptr->bufid = 1;
405 ptr->next = ptr;
406
407 ptr->filter_id = 0;
408 ptr->v_codec = CODEC_YUV;
409 ptr->id = i; // frame
410 #ifdef STATBUFFER
411 ptr->internal_video_buf_0 = run_buffer[0];
412 ptr->internal_video_buf_1 = run_buffer[1];
413 #endif /* STATBUFFER */
414
415 // RGB
416 ptr->video_buf_RGB[0]=run_buffer[0];
417 ptr->video_buf_RGB[1]=run_buffer[1];
418
419 //YUV
420 ptr->video_buf_Y[0] = run_buffer[0];
421 ptr->video_buf_Y[1] = run_buffer[1];
422
423 ptr->video_buf_U[0] = ptr->video_buf_Y[0]
424 + TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT;
425 ptr->video_buf_U[1] = ptr->video_buf_Y[1]
426 + TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT;
427
428 ptr->video_buf_V[0] = ptr->video_buf_U[0]
429 + (TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT)/4;
430 ptr->video_buf_V[1] = ptr->video_buf_U[1]
431 + (TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT)/4;
432
433 //default pointer
434 ptr->video_buf = run_buffer[0];
435 ptr->video_buf2 = run_buffer[1];
436 ptr->free = 1;
437
438 #ifdef NO_PROCESS
439 ptr->video_size = size;
440 ptr->v_width = w;
441 ptr->v_height = h;
442 #else
443 ptr->v_width = vob->im_v_width;
444 ptr->v_height = vob->im_v_height;
445 ptr->video_size = vob->im_v_width*vob->im_v_height*3/2;
446 #endif
447
448 // we disable this filter (filter_pv), because it does not make sense
449 // to be run in the preview loop
450 tc_filter_disable(this_filter);
451
452 // PRE
453 ptr->tag= TC_VIDEO | TC_PRE_S_PROCESS | TC_PRE_M_PROCESS;
454 tc_filter_process((frame_list_t *)ptr);
455
456 // CORE
457 process_vid_frame(vob, ptr);
458
459 // POST
460 ptr->tag= TC_VIDEO | TC_POST_S_PROCESS | TC_POST_M_PROCESS;
461 tc_filter_process((frame_list_t *)ptr);
462
463 tc_filter_enable(this_filter);
464
465 ac_memcpy (vid_buf[cache_ptr-current+1], ptr->video_buf, size);
466 preview_cache_draw(0);
467
468 ac_memcpy ((char *)vid_buf[cache_ptr], undo_buffer, size);
469 }
470 return 0;
471 }
472 #if 0
473 void preview_filter(void)
474 {
475 FILE *f;
476 FILE *g;
477 char tmpfile[] = "/tmp/filter-select";
478 char infile[] = "/tmp/filter-in";
479 char buf[1024];
480 char filter_name[255];
481 char *config, *c;
482 int filter_handle, this_filter=-1, disable = 0;
483 int frames_needed = 1;
484 int current=0;
485 int i;
486
487 if (!cache_enabled) return;
488
489 // build commandline
490 tc_snprintf (buf, 1024,
491 "xterm -title \"Transcode Filter select\" -e %s/filter_list.awk %s %s && cat %s && rm -f %s",
492 vob->mod_path, vob->mod_path, tmpfile, tmpfile, tmpfile);
493 if ((f = popen (buf, "r")) == NULL) {
494 perror ("popen filter select");
495 return;
496 }
497 // recycle
498 memset (buf, 0, 1024);
499
500 // block until data is available
501 // filter Name
502 fgets(buf, 1024, f);
503 // delete newline
504 buf[strlen(buf)-1] = '\0';
505 strlcpy (filter_name, buf, sizeof(filter_name));
506
507 // (c)onfig or (d)isable
508 memset (buf, 0, 1024);
509 fgets(buf, 1024, f);
510 buf[strlen(buf)-1] = '\0';
511 if ( strcmp (buf, "(d)") == 0) { disable = 1; }
512
513 pclose (f);
514
515 if (disable) {
516 filter_handle = tc_filter_find(filter_name);
517 if (filter_handle == -1) {
518 // not loaded
519 return;
520 } else {
521 tc_filter_disable(filter_handle);
522 goto redisplay_frame;
523 }
524 }
525 filter_handle = tc_filter_add(filter_name, NULL);
526
527 this_filter = tc_filter_find("pv");
528 tc_log_msg(MOD_NAME, "this_filter (%d)", this_filter);
529
530 // we now have a valid ID
531 if ( (config = tc_filter_get_conf(filter_handle, NULL)) == NULL) {
532 tc_log_warn(MOD_NAME, "Filter \"%s\" can not be configured.", filter_name);
533 }
534
535 if ((g = fopen(tmpfile, "w")) != NULL) {
536 fputs (config, g);
537 fclose (g);
538 } else {
539 tc_log_warn(MOD_NAME, "unable to write to %s.\n", tmpfile);
540 return;
541 }
542
543 if ((c = strchr (config, '\n'))) {
544 *c = '\0';
545 optstr_frames_needed (config, &frames_needed);
546 } else
547 frames_needed = 1;
548
549 tc_log_msg(MOD_NAME, "XXX optstr_frames_needed:(%d)", frames_needed);
550
551
552 free (config);
553
554 // recycle
555 memset (buf, 0, 1024);
556
557 tc_snprintf (buf, 1024,
558 "xterm -title \"Transcode parameters\" -e %s/parse_csv.awk %s %s %s && cat %s && rm -f %s %s",
559 vob->mod_path, tmpfile, filter_name, infile, infile, tmpfile, infile);
560
561 if ((f = popen (buf, "r")) == NULL) {
562 perror ("popen filter param");
563 return;
564 }
565
566 // recycle
567 memset (buf, 0, 1024);
568
569 // block until data is available
570 fgets(buf, 1024, f);
571 pclose (f);
572
573
574 buf[strlen(buf)-1] = '\0';
575
576 //tc_log_msg(MOD_NAME, "XX buf (%s)", buf);
577 // XXX
578 if (buf && *buf) {
579 char *s = strchr(buf, '=');
580 tc_filter_configure(filter_handle, s ? s+1 : NULL);
581 }
582
583 redisplay_frame:
584 // logoaway pos=210x136:size=257x175:mode=2
585 for (current = frames_needed, i = 1; current > 0; current--, i++){
586
587 vframe_list_t ptr;
588
589 if (!disable)
590 ac_memcpy (undo_buffer, (char *)vid_buf[cache_ptr], size);
591
592 ac_memcpy (run_buffer[0], (char *)vid_buf[cache_ptr-(current-1)], size);
593 ac_memcpy (run_buffer[1], (char *)vid_buf[cache_ptr-(current-1)], size);
594
595 ptr.bufid = 1;
596 ptr.next = &ptr;
597 ptr.tag= TC_VIDEO | TC_POST_M_PROCESS | TC_PRE_M_PROCESS |
598 TC_POST_S_PROCESS | TC_PRE_S_PROCESS;
599
600 ptr.filter_id = 0;
601 ptr.v_codec = CODEC_YUV;
602 ptr.id = i; // frame
603 #ifdef STATBUFFER
604 ptr.internal_video_buf_0 = run_buffer[0];
605 ptr.internal_video_buf_1 = run_buffer[1];
606 #endif /* STATBUFFER */
607
608 // RGB
609 ptr.video_buf_RGB[0]=run_buffer[0];
610 ptr.video_buf_RGB[1]=run_buffer[1];
611
612 //YUV
613 ptr.video_buf_Y[0] = run_buffer[0];
614 ptr.video_buf_Y[1] = run_buffer[1];
615
616 ptr.video_buf_U[0] = ptr.video_buf_Y[0]
617 + TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT;
618 ptr.video_buf_U[1] = ptr.video_buf_Y[1]
619 + TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT;
620
621 ptr.video_buf_V[0] = ptr.video_buf_U[0]
622 + (TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT)/4;
623 ptr.video_buf_V[1] = ptr.video_buf_U[1]
624 + (TC_MAX_V_FRAME_WIDTH * TC_MAX_V_FRAME_HEIGHT)/4;
625
626 //default pointer
627 ptr.video_buf = run_buffer[0];
628 ptr.video_buf2 = run_buffer[1];
629 ptr.free = 1;
630
631 ptr.video_size = size;
632 ptr.v_width = w;
633 ptr.v_height = h;
634
635
636 // we disable this filter (filter_pv), because it does not make sense
637 // to be run in the preview loop
638 tc_filter_disable(this_filter);
639 tc_filter_process((frame_list_t *)&ptr);
640 tc_filter_enable(this_filter);
641
642 ac_memcpy (vid_buf[cache_ptr-current+1], ptr.video_buf, size);
643 preview_cache_draw(0);
644 }
645 return;
646
647 }
648 #endif
649
preview_cache_undo(void)650 void preview_cache_undo(void)
651 {
652 if (!cache_enabled) return;
653
654 ac_memcpy((char *)vid_buf[cache_ptr], undo_buffer, size);
655 preview_cache_draw(0);
656 }
657
preview_cache_draw(int next)658 void preview_cache_draw(int next) {
659
660 if(!cache_enabled) return;
661
662 cache_ptr+=next;
663
664 if(next < 0) cache_ptr+=cache_num;
665 while (cache_ptr<0)
666 cache_ptr+=cache_num;
667
668 cache_ptr%=cache_num;
669
670 ac_memcpy(xv_player->display->pixels[0], (char*) vid_buf[cache_ptr], size);
671
672 //display video frame
673 xv_display_show(xv_player->display);
674
675 return;
676
677 }
678
str2img(char * img,char * c,int width,int height,int char_width,int char_height,int posx,int posy,int codec)679 void str2img(char *img, char *c, int width, int height, int char_width, int char_height, int posx, int posy, int codec)
680 {
681 char **cur;
682 int posxorig=posx;
683
684 while (*c != '\0' && *c && c) {
685 if (*c == '\n') {
686 posy+=char_height;
687 posx=posxorig;
688 }
689 if (posx+char_width >= width || posy >= height)
690 break;
691
692 cur = char2bmp(*c);
693 if (cur) {
694 bmp2img (img, cur, width, height, char_width, char_height, posx, posy, codec);
695 posx+=char_width;
696 }
697
698 c++;
699 }
700 }
701
bmp2img(char * img,char ** c,int width,int height,int char_width,int char_height,int posx,int posy,int codec)702 void bmp2img(char *img, char **c, int width, int height, int char_width, int char_height, int posx, int posy, int codec)
703 {
704 int h, w;
705
706 if (codec == CODEC_YUV) {
707 for (h=0; h<char_height; h++) {
708 for (w=0; w<char_width; w++) {
709 img[(posy+h)*width+posx+w] = (c[h][w] == '+')?230:img[(posy+h)*width+posx+w];
710 }
711
712 }
713 } else {
714 for (h=0; h<char_height; h++) {
715 for (w=0; w<char_width; w++) {
716 char *col=&img[3*((height-(posy+h))*width+posx+w)];
717 *(col-0) = (c[h][w] == '+')?255:*(col-0);
718 *(col-1) = (c[h][w] == '+')?255:*(col-1);
719 *(col-2) = (c[h][w] == '+')?255:*(col-2);
720 }
721 }
722 }
723 /*
724 for (h=char_height-1; h>=0; h--) {
725 for (w=char_width-1; w>=0; w--) {
726 */
727 }
728
char2bmp(char c)729 char **char2bmp(char c) {
730 switch (c) {
731 case '0': return &null_xpm[4];
732 case '1': return &one_xpm[4];
733 case '2': return &two_xpm[4];
734 case '3': return &three_xpm[4];
735 case '4': return &four_xpm[4];
736 case '5': return &five_xpm[4];
737 case '6': return &six_xpm[4];
738 case '7': return &seven_xpm[4];
739 case '8': return &eight_xpm[4];
740 case '9': return &nine_xpm[4];
741 case '-': return &minus_xpm[4];
742 case ':': return &colon_xpm[4];
743 case ' ': return &space_xpm[4];
744 case '!': return &exklam_xpm[4];
745 case '?': return &quest_xpm[4];
746 case '.': return &dot_xpm[4];
747 case ',': return &comma_xpm[4];
748 case ';': return &semicomma_xpm[4];
749 case 'A': return &A_xpm[4];
750 case 'a': return &a_xpm[4];
751 case 'B': return &B_xpm[4];
752 case 'b': return &b_xpm[4];
753 case 'C': return &C_xpm[4];
754 case 'c': return &c_xpm[4];
755 case 'D': return &D_xpm[4];
756 case 'd': return &d_xpm[4];
757 case 'E': return &E_xpm[4];
758 case 'e': return &e_xpm[4];
759 case 'F': return &F_xpm[4];
760 case 'f': return &f_xpm[4];
761 case 'G': return &G_xpm[4];
762 case 'g': return &g_xpm[4];
763 case 'H': return &H_xpm[4];
764 case 'h': return &h_xpm[4];
765 case 'I': return &I_xpm[4];
766 case 'i': return &i_xpm[4];
767 case 'J': return &J_xpm[4];
768 case 'j': return &j_xpm[4];
769 case 'K': return &K_xpm[4];
770 case 'k': return &k_xpm[4];
771 case 'L': return &L_xpm[4];
772 case 'l': return &l_xpm[4];
773 case 'M': return &M_xpm[4];
774 case 'm': return &m_xpm[4];
775 case 'N': return &N_xpm[4];
776 case 'n': return &n_xpm[4];
777 case 'O': return &O_xpm[4];
778 case 'o': return &o_xpm[4];
779 case 'P': return &P_xpm[4];
780 case 'p': return &p_xpm[4];
781 case 'Q': return &Q_xpm[4];
782 case 'q': return &q_xpm[4];
783 case 'R': return &R_xpm[4];
784 case 'r': return &r_xpm[4];
785 case 'S': return &S_xpm[4];
786 case 's': return &s_xpm[4];
787 case 'T': return &T_xpm[4];
788 case 't': return &t_xpm[4];
789 case 'U': return &U_xpm[4];
790 case 'u': return &u_xpm[4];
791 case 'V': return &V_xpm[4];
792 case 'v': return &v_xpm[4];
793 case 'W': return &W_xpm[4];
794 case 'w': return &w_xpm[4];
795 case 'X': return &X_xpm[4];
796 case 'x': return &x_xpm[4];
797 case 'Y': return &Y_xpm[4];
798 case 'y': return &y_xpm[4];
799 case 'Z': return &Z_xpm[4];
800 case 'z': return &z_xpm[4];
801 case '*': return &ast_xpm[4];
802 default: return NULL;
803 }
804 return NULL;
805 }
806
preview_grab_jpeg(void)807 int preview_grab_jpeg(void)
808 {
809 const char *error;
810 char *prefix = "preview_grab-";
811 vob_t *vob = tc_get_vob();
812 static vob_t *mvob;
813 static void *jpeg_vhandle = NULL;
814 static int (*JPEG_export)(int opt, void *para1, void *para2);
815 static int counter = 0;
816
817 char module[TC_BUF_MAX];
818 transfer_t export_para;
819 int ret = 0;
820
821 if(!cache_enabled) return 1;
822
823 if (jpeg_vhandle == NULL) {
824 tc_snprintf(module, sizeof(module), "%s/export_%s.so", MOD_PATH, "jpg");
825 jpeg_vhandle = dlopen(module, RTLD_GLOBAL| RTLD_LAZY);
826 if (!jpeg_vhandle) {
827 tc_log_error(MOD_NAME, "%s", dlerror());
828 tc_log_error(MOD_NAME, "loading \"%s\" failed", module);
829 return(1);
830 }
831 JPEG_export = dlsym(jpeg_vhandle, "tc_export");
832 if ((error = dlerror()) != NULL) {
833 tc_log_error(MOD_NAME, "%s", error);
834 return(1);
835 }
836 export_para.flag = TC_DEBUG;
837 ret = JPEG_export(TC_EXPORT_NAME, &export_para, NULL);
838
839 mvob = malloc(sizeof(vob_t));
840 ac_memcpy (mvob, vob, sizeof(vob_t));
841 mvob->video_out_file = prefix;
842
843 export_para.flag = TC_VIDEO;
844 if((ret=JPEG_export(TC_EXPORT_INIT, &export_para, mvob))==TC_EXPORT_ERROR) {
845 tc_log_error(MOD_NAME, "video jpg export module error: init failed");
846 return(1);
847 }
848
849 export_para.flag = TC_VIDEO;
850 if((ret=JPEG_export(TC_EXPORT_OPEN, &export_para, mvob))==TC_EXPORT_ERROR) {
851 tc_log_error(MOD_NAME, "video export module error: open failed");
852 return(1);
853 }
854 }
855
856 // encode and export video frame
857 export_para.buffer = (char *)vid_buf[cache_ptr];
858 export_para.size = size;
859 export_para.attributes = TC_FRAME_IS_KEYFRAME;
860 export_para.flag = TC_VIDEO;
861
862 if(JPEG_export(TC_EXPORT_ENCODE, &export_para, mvob)<0) {
863 tc_log_warn(MOD_NAME, "error encoding jpg frame");
864 return 1;
865 }
866 tc_log_info(MOD_NAME, "Saved JPEG to %s%06d.jpg", prefix, counter++);
867
868
869 return 0;
870 }
871
872 /* vim:sw=4
873 */
874