4 * Video driver for AAlib - 1.0
6 * by Folke Ashberg <folke@ashberg.de>
8 * Code started: Sun Aug 12 2001
9 * Version 1.0 : Thu Aug 16 2001
27 #include "video_out.h"
28 #include "video_out_internal.h"
30 #include "postproc/swscale.h"
31 #include "libmpcodecs/vf_scale.h"
32 #include "font_load.h"
35 #include "osdep/keycodes.h"
37 #include "subopt-helper.h"
42 #define MESSAGE_DURATION 3
43 #define MESSAGE_SIZE 512
44 #define MESSAGE_DEKO " +++ %s +++ "
46 static vo_info_t info
= {
49 "Alban Bedel <albeu@free.fr> and Folke Ashberg <folke@ashberg.de>",
55 /* aa's main context we use */
59 /* used for the sws */
60 static uint8_t * image
[3];
61 static int image_stride
[3];
64 static int image_format
;
65 static int image_width
;
66 static int image_height
;
67 static int image_x
, image_y
;
68 static int screen_x
, screen_y
;
69 static int screen_w
, screen_h
;
71 static int src_height
;
75 static int showosdmessage
= 0;
76 char osdmessagetext
[MESSAGE_SIZE
];
77 char posbar
[MESSAGE_SIZE
];
78 static int osdx
, osdy
;
79 static int osd_text_length
= 0;
82 font_desc_t
* vo_font_save
= NULL
;
84 static struct SwsContext
*sws
=NULL
;
86 /* our version of the playmodes :) */
88 extern void mplayer_put_key(int code
);
90 /* to disable stdout outputs when curses/linux mode */
94 int aaopt_osdcolor
= AA_SPECIAL
;
95 int aaopt_subcolor
= AA_SPECIAL
;
97 extern struct aa_hardware_params aa_defparams
;
98 extern struct aa_renderparams aa_defrenderparams
;
103 * this function is called by aa lib if windows resizes
104 * further during init, because here we have to calculate
110 aspect_save_screenres(aa_imgwidth(c
),aa_imgheight(c
));
111 image_height
= aa_imgheight(c
); //src_height;
112 image_width
= aa_imgwidth(c
); //src_width;
114 aspect(&image_width
,&image_height
,A_ZOOM
);
116 image_x
= (aa_imgwidth(c
) - image_width
) / 2;
117 image_y
= (aa_imgheight(c
) - image_height
) / 2;
118 screen_w
= image_width
* aa_scrwidth(c
) / aa_imgwidth(c
);
119 screen_h
= image_height
* aa_scrheight(c
) / aa_imgheight(c
);
120 screen_x
= (aa_scrwidth(c
) - screen_w
) / 2;
121 screen_y
= (aa_scrheight(c
) - screen_h
) / 2;
123 if(sws
) sws_freeContext(sws
);
124 sws
= sws_getContextFromCmdLine(src_width
,src_height
,image_format
,
125 image_width
,image_height
,IMGFMT_Y8
);
127 image
[0] = aa_image(c
) + image_y
* aa_imgwidth(c
) + image_x
;
131 image_stride
[0] = aa_imgwidth(c
);
140 osdmessage(int duration
, int deko
, char *fmt
, ...)
143 * for outputting a centered string at the bottom
144 * of our window for a while
147 char m
[MESSAGE_SIZE
];
148 unsigned int old_len
= strlen(osdmessagetext
);
151 vsprintf(m
, fmt
, ar
);
153 if (deko
==1) sprintf(osdmessagetext
, MESSAGE_DEKO
, m
);
154 else strcpy(osdmessagetext
, m
);
156 if(old_len
> strlen(osdmessagetext
)) {
157 memset(c
->textbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,' ',old_len
);
158 memset(c
->attrbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,0,old_len
);
161 stoposd
= time(NULL
) + duration
;
162 osdx
=(aa_scrwidth(c
) / 2) - (strlen(osdmessagetext
) / 2 ) ;
167 osdpercent(int duration
, int deko
, int min
, int max
, int val
, char * desc
, char * unit
)
170 * prints a bar for setting values
177 step
=(float)aa_scrwidth(c
) /(float)(max
-min
);
178 where
=(val
-min
)*step
;
179 osdmessage(duration
,deko
,"%s: %i%s",desc
, val
, unit
);
181 posbar
[aa_scrwidth(c
)-1]='|';
182 for (i
=0;i
<aa_scrwidth(c
);i
++){
183 if (i
==where
) posbar
[i
]='#';
186 if (where
!=0) posbar
[0]='|';
187 if (where
!=(aa_scrwidth(c
)-1) ) posbar
[aa_scrwidth(c
)-1]='|';
189 posbar
[aa_scrwidth(c
)]='\0';
196 if(osd_text_length
> 0 && !vo_osd_text
) {
197 memset(c
->textbuffer
,' ',osd_text_length
);
198 memset(c
->attrbuffer
,0,osd_text_length
);
202 * places the mplayer status osd
204 if (vo_osd_text
&& vo_osd_text
[0] != 0) {
206 if(vo_osd_text
[0] < 32) {
207 len
= strlen(__sub_osd_names_short
[vo_osd_text
[0]]) + strlen(vo_osd_text
+1) + 2;
208 aa_printf(c
, 0, 0 , aaopt_osdcolor
, "%s %s ", __sub_osd_names_short
[vo_osd_text
[0]], vo_osd_text
+1);
210 len
= strlen(vo_osd_text
) + 1;
211 aa_printf(c
, 0, 0 , aaopt_osdcolor
, "%s ",vo_osd_text
);
214 if(len
< osd_text_length
) {
215 memset(c
->textbuffer
+ len
,' ',osd_text_length
- len
);
216 memset(c
->attrbuffer
+ len
,0,osd_text_length
- len
);
218 osd_text_length
= len
;
224 printosdprogbar(void){
225 /* print mplayer osd-progbar */
226 if (vo_osd_progbar_type
!=-1){
227 osdpercent(1,1,0,255,vo_osd_progbar_value
, __sub_osd_names
[vo_osd_progbar_type
], "");
231 config(uint32_t width
, uint32_t height
, uint32_t d_width
,
232 uint32_t d_height
, uint32_t flags
, char *title
,
241 aspect_save_orig(width
,height
);
242 aspect_save_prescale(d_width
,d_height
);
246 image_format
= format
;
248 /* nothing will change its size, be we need some values initialized */
252 /* now init out own 'font' (to use vo_draw_text_sub without edit them) */
253 if(!vo_font_save
) vo_font_save
= vo_font
;
254 if(vo_font
== vo_font_save
) {
255 vo_font
=malloc(sizeof(font_desc_t
));//if(!desc) return NULL;
256 memset(vo_font
,0,sizeof(font_desc_t
));
257 vo_font
->pic_a
[0]=malloc(sizeof(raw_file
));
258 memset(vo_font
->pic_a
[0],0,sizeof(raw_file
));
259 vo_font
->pic_b
[0]=malloc(sizeof(raw_file
));
260 memset(vo_font
->pic_b
[0],0,sizeof(raw_file
));
263 vo_font
->dynamic
= 0;
266 vo_font
->spacewidth
=1;
267 vo_font
->charspace
=0;
269 vo_font
->pic_a
[0]->bmp
=malloc(255);
270 vo_font
->pic_a
[0]->pal
=NULL
;
271 vo_font
->pic_b
[0]->bmp
=malloc(255);
272 vo_font
->pic_b
[0]->pal
=NULL
;
273 vo_font
->pic_a
[0]->w
=1;
274 vo_font
->pic_a
[0]->h
=1;
275 for (i
=0; i
<255; i
++){
279 vo_font
->pic_a
[0]->bmp
[i
]=i
;
280 vo_font
->pic_b
[0]->bmp
[i
]=i
;
285 osdmessage(5, 1, "Welcome to ASCII ART MPlayer");
287 mp_msg(MSGT_VO
,MSGL_V
,"VO: [aa] screendriver: %s\n", c
->driver
->name
);
288 mp_msg(MSGT_VO
,MSGL_V
,"VO: [aa] keyboarddriver: %s\n", c
->kbddriver
->name
);
290 mp_msg(MSGT_VO
,MSGL_INFO
,
292 "Important suboptions\n"
293 "\textended use use all 256 characters\n"
294 "\teight use eight bit ascii\n"
295 "\tdriver set recommended aalib driver (X11,curses,linux)\n"
296 "\thelp to see all options provided by aalib\n"
301 "\t3 : brightness -\n"
302 "\t4 : brightness +\n"
303 "\t5 : fast rendering\n"
305 "\t7 : invert image\n"
306 "\ta : toggles between aa and mplayer control\n"
309 "All other keys are MPlayer defaults.\n"
318 query_format(uint32_t format
) {
320 * ...are we able to... ?
322 * All input format supported by the sws
337 return VFCAP_CSP_SUPPORTED
|VFCAP_SWSCALE
347 draw_frame(uint8_t *src
[]) {
348 int stride
[3] = { 0 , 0 , 0 };
350 switch(image_format
) {
353 stride
[0] = src_width
*2;
357 stride
[0] = src_width
*3;
360 stride
[0] = src_width
*4;
364 sws_scale_ordered(sws
,src
,stride
,0,src_height
,image
,image_stride
);
366 /* Now 'ASCIInate' the image */
368 aa_fastrender(c
, screen_x
, screen_y
, screen_w
+ screen_x
, screen_h
+ screen_y
);
370 aa_render(c
, p
,screen_x
, screen_y
, screen_w
+ screen_x
, screen_h
+ screen_y
);
376 draw_slice(uint8_t *src
[], int stride
[],
377 int w
, int h
, int x
, int y
) {
379 int dx1
= screen_x
+ (x
* screen_w
/ src_width
);
380 int dy1
= screen_y
+ (y
* screen_h
/ src_height
);
381 int dx2
= screen_x
+ ((x
+w
) * screen_w
/ src_width
);
382 int dy2
= screen_y
+ ((y
+h
) * screen_h
/ src_height
);
384 sws_scale_ordered(sws
,src
,stride
,y
,h
,image
,image_stride
);
386 /* Now 'ASCIInate' the image */
388 aa_fastrender(c
, dx1
, dy1
, dx2
, dy2
);
390 aa_render(c
, p
,dx1
, dy1
, dx2
, dy2
);
399 /* do we have to put *our* (messages, progbar) osd to aa's txtbuf ? */
402 if (time(NULL
)>=stoposd
) {
405 memset(c
->textbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,' ',strlen(osdmessagetext
));
406 memset(c
->attrbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,0,strlen(osdmessagetext
));
407 osdmessagetext
[0] = '\0';
410 memset(c
->textbuffer
+ (osdy
+1) * aa_scrwidth(c
),' ',strlen(posbar
));
411 memset(c
->attrbuffer
+ (osdy
+1) * aa_scrwidth(c
),0,strlen(posbar
));
415 aa_puts(c
, osdx
, osdy
, AA_SPECIAL
, osdmessagetext
);
418 aa_puts(c
, 0, osdy
+ 1, AA_SPECIAL
, posbar
);
421 /* OSD time & playmode , subtitles */
435 * called by show_image and mplayer
438 while ((key
=aa_getevent(c
,0))!=AA_NONE
){
440 /* some conversations */
443 mplayer_put_key(KEY_UP
);
446 mplayer_put_key(KEY_DOWN
);
449 mplayer_put_key(KEY_LEFT
);
452 mplayer_put_key(KEY_RIGHT
);
455 mplayer_put_key(KEY_ESC
);
458 mplayer_put_key(KEY_PAGE_UP
);
461 mplayer_put_key(KEY_PAGE_DOWN
);
464 continue; /* aa lib special key */
468 if (key
=='a' || key
=='A'){
469 aaconfigmode
=!aaconfigmode
;
470 osdmessage(MESSAGE_DURATION
, 1, "aa config mode is now %s",
471 aaconfigmode
==1 ? "on. use keys 5-7" : "off");
473 if (aaconfigmode
==1) {
475 /* AA image controls */
478 osdmessage(MESSAGE_DURATION
, 1, "Fast mode is now %s", fast
==1 ? "on" : "off");
481 if (p
->dither
==AA_FLOYD_S
){
483 osdmessage(MESSAGE_DURATION
, 1, "Dithering: Off");
484 }else if (p
->dither
==AA_NONE
){
485 p
->dither
=AA_ERRORDISTRIB
;
486 osdmessage(MESSAGE_DURATION
, 1, "Dithering: Error Distribution");
487 }else if (p
->dither
==AA_ERRORDISTRIB
){
488 p
->dither
=AA_FLOYD_S
;
489 osdmessage(MESSAGE_DURATION
, 1, "Dithering: Floyd Steinberg");
493 p
->inversion
=!p
->inversion
;
494 osdmessage(MESSAGE_DURATION
, 1, "Invert mode is now %s",
495 p
->inversion
==1 ? "on" : "off");
499 /* nothing if we're interested in?
500 * the mplayer should handle it!
502 mplayer_put_key(key
);
506 else mplayer_put_key(key
);
516 if (strstr(c
->driver
->name
,"Curses") || strstr(c
->driver
->name
,"Linux")){
517 freopen("/dev/tty", "w", stderr
);
521 free(vo_font
->pic_a
[0]->bmp
);
522 free(vo_font
->pic_a
[0]);
523 free(vo_font
->pic_b
[0]->bmp
);
524 free(vo_font
->pic_b
[0]);
526 vo_font
= vo_font_save
;
534 static void draw_alpha(int x
,int y
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
536 for (i
= 0; i
< h
; i
++) {
537 for (j
= 0; j
< w
; j
++) {
538 if (src
[i
*stride
+j
] > 0) {
539 c
->textbuffer
[x
+ j
+ (y
+i
)*aa_scrwidth(c
)] = src
[i
*stride
+j
];
540 c
->attrbuffer
[x
+ j
+ (y
+i
)*aa_scrwidth(c
)] = aaopt_subcolor
;
546 static void clear_alpha(int x0
,int y0
, int w
,int h
) {
549 for(l
= 0 ; l
< h
; l
++) {
550 memset(c
->textbuffer
+ (y0
+ l
) * aa_scrwidth(c
) + x0
,' ',w
);
551 memset(c
->attrbuffer
+ (y0
+ l
) * aa_scrwidth(c
) + x0
,0,w
);
561 char * vo_osd_text_save
;
562 int vo_osd_progbar_type_save
;
565 /* let vo_draw_text only write subtitle */
566 vo_osd_text_save
=vo_osd_text
; /* we have to save the osd_text */
568 vo_osd_progbar_type_save
=vo_osd_progbar_type
;
569 vo_osd_progbar_type
=-1;
570 vo_remove_text(aa_scrwidth(c
), aa_scrheight(c
),clear_alpha
);
571 vo_draw_text(aa_scrwidth(c
), aa_scrheight(c
), draw_alpha
);
572 vo_osd_text
=vo_osd_text_save
;
573 vo_osd_progbar_type
=vo_osd_progbar_type_save
;
581 if (s
==NULL
) return -1;
582 i
=strtol(s
, &rest
, 10);
583 if ((rest
==NULL
|| strlen(rest
)==0) && i
>=0 && i
<=5) return i
;
584 if (!strcasecmp(s
, "normal")) return AA_NORMAL
;
585 else if (!strcasecmp(s
, "dim")) return AA_DIM
;
586 else if (!strcasecmp(s
, "bold")) return AA_BOLD
;
587 else if (!strcasecmp(s
, "boldfont")) return AA_BOLDFONT
;
588 else if (!strcasecmp(s
, "special")) return AA_SPECIAL
;
592 static int parse_suboptions(const char *arg
) {
593 char *pseudoargv
[4], *osdcolor
= NULL
, *subcolor
= NULL
, **strings
,
595 int pseudoargc
, displayhelp
= 0, *booleans
;
596 opt_t extra_opts
[] = {
597 {"osdcolor", OPT_ARG_MSTRZ
, &osdcolor
, NULL
, 0},
598 {"subcolor", OPT_ARG_MSTRZ
, &subcolor
, NULL
, 0},
599 {"help", OPT_ARG_BOOL
, &displayhelp
, NULL
, 0} };
600 opt_t
*subopts
= NULL
, *p
;
601 char *strings_list
[] = {"-driver", "-kbddriver", "-mousedriver", "-font",
602 "-width", "-height", "-minwidth", "-minheight", "-maxwidth",
603 "-maxheight", "-recwidth", "-recheight", "-bright", "-contrast",
604 "-gamma", "-dimmul", "-boldmul", "-random" };
605 char *booleans_list
[] = {"-dim", "-bold", "-reverse", "-normal",
606 "-boldfont", "-inverse", "-extended", "-eight", "-dither",
607 "-floyd_steinberg", "-error_distribution"};
608 char *nobooleans_list
[] = {"-nodim", "-nobold", "-noreverse", "-nonormal",
609 "-noboldfont", "-noinverse", "-noextended", "-noeight", "-nodither",
610 "-nofloyd_steinberg", "-noerror_distribution"};
611 const int nstrings
= sizeof(strings_list
) / sizeof(char*);
612 const int nbooleans
= sizeof(booleans_list
) / sizeof(int);
613 const int nextra_opts
= sizeof(extra_opts
) / sizeof(opt_t
);
614 const int nsubopts
= nstrings
+ nbooleans
+ nextra_opts
;
617 subopts
= calloc(nsubopts
+ 1, sizeof(opt_t
));
618 strings
= calloc(nstrings
, sizeof(char*));
619 booleans
= calloc(nbooleans
, sizeof(int));
622 for (i
=0; i
<nstrings
; i
++, p
++) {
623 p
->name
= strings_list
[i
] + 1; // skip '-'
624 p
->type
= OPT_ARG_MSTRZ
;
625 p
->valp
= &strings
[i
];
627 for (i
=0; i
<nbooleans
; i
++, p
++) {
628 p
->name
= booleans_list
[i
] + 1;
629 p
->type
= OPT_ARG_BOOL
;
630 p
->valp
= &booleans
[i
];
632 memcpy(p
, extra_opts
, sizeof(extra_opts
));
634 retval
= subopt_parse(arg
, subopts
);
636 if (retval
== 0 && displayhelp
) {
637 helpmsg
= strdup(aa_help
);
638 for (i
=0; i
<(signed)strlen(helpmsg
); i
++)
639 if (helpmsg
[i
] == '-') helpmsg
[i
] = ' ';
640 mp_msg(MSGT_VO
, MSGL_INFO
, MSGTR_VO_AA_HelpHeader
);
641 mp_msg(MSGT_VO
, MSGL_INFO
, "%s\n\n", helpmsg
);
642 mp_msg(MSGT_VO
, MSGL_INFO
, MSGTR_VO_AA_AdditionalOptions
);
646 pseudoargv
[3] = NULL
;
647 for (i
=0; i
<nstrings
; i
++) {
648 pseudoargc
= 3; // inside loop because aalib changes it
649 if (strings
[i
] != NULL
) {
650 pseudoargv
[1] = strings_list
[i
];
651 pseudoargv
[2] = strings
[i
];
652 aa_parseoptions(&aa_defparams
, &aa_defrenderparams
,
653 &pseudoargc
, pseudoargv
) != 1;
656 pseudoargv
[2] = NULL
;
657 for (i
=0; i
<nbooleans
; i
++) {
659 if (booleans
[i
]) pseudoargv
[1] = booleans_list
[i
];
660 else pseudoargv
[1] = nobooleans_list
[i
];
661 aa_parseoptions(&aa_defparams
, &aa_defrenderparams
,
662 &pseudoargc
, pseudoargv
) != 1;
664 if (osdcolor
) aaopt_osdcolor
= getcolor(osdcolor
);
665 if (subcolor
) aaopt_subcolor
= getcolor(subcolor
);
668 if (subopts
) free(subopts
);
669 if (booleans
) free(booleans
);
671 for (i
=0; i
<nstrings
; i
++)
676 if (osdcolor
) free(osdcolor
);
677 if (subcolor
) free(subcolor
);
678 if (helpmsg
) free(helpmsg
);
682 static int preinit(const char *arg
)
686 int fd
, vt
, major
, minor
;
689 extern aa_linkedlist
*aa_displayrecommended
;
693 if (parse_suboptions(arg
) != 0)
697 /* initializing of aalib */
699 hidis
=aa_getfirst(&aa_displayrecommended
);
701 /* check /dev/vcsa<vt> */
702 /* check only, if no driver is explicit set */
703 fd
= dup (fileno (stderr
));
705 major
= sbuf
.st_rdev
>> 8;
706 vt
= minor
= sbuf
.st_rdev
& 0xff;
708 sprintf (fname
, "/dev/vcsa%2.2i", vt
);
709 fp
= fopen (fname
, "w+");
711 fprintf(stderr
,"VO: [aa] cannot open %s for writing,"
712 "so we'll not use linux driver\n", fname
);
713 aa_recommendlowdisplay("linux");
714 aa_recommendhidisplay("curses");
715 aa_recommendhidisplay("X11");
717 } else aa_recommendhidisplay(hidis
);
718 c
= aa_autoinit(&aa_defparams
);
721 mp_msg(MSGT_VO
,MSGL_ERR
,"Cannot initialize aalib\n");
724 if (!aa_autoinitkbd(c
,0)) {
725 mp_msg(MSGT_VO
,MSGL_ERR
,"Cannot initialize keyboard\n");
730 aa_resizehandler(c
, (void *)resize
);
732 p
= aa_getrenderparams();
734 if ((strstr(c
->driver
->name
,"Curses")) || (strstr(c
->driver
->name
,"Linux"))){
735 freopen("/dev/null", "w", stderr
);
736 /* disable console blanking */
740 memset(image
,0,3*sizeof(uint8_t));
741 osdmessagetext
[0] = '\0';
747 static int control(uint32_t request
, void *data
, ...)
750 case VOCTRL_QUERY_FORMAT
:
751 return query_format(*((uint32_t*)data
));
752 case VOCTRL_SET_EQUALIZER
: {
757 val
= va_arg(ap
, int);
760 if(strcmp((char*)data
,"contrast") == 0)
761 p
->contrast
= ( val
+ 100 ) * 64 / 100;
762 else if(strcmp((char*)data
,"brightness") == 0)
763 p
->bright
= ( val
+ 100) * 128 / 100;
766 case VOCTRL_GET_EQUALIZER
: {
771 val
= va_arg(ap
, int*);
774 if(strcmp((char*)data
,"contrast") == 0)
775 *val
= (p
->contrast
- 64) * 100 / 64;
776 else if(strcmp((char*)data
,"brightness") == 0)
777 *val
= (p
->bright
- 128) * 100 / 128;