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"
41 #define MESSAGE_DURATION 3
42 #define MESSAGE_SIZE 512
43 #define MESSAGE_DEKO " +++ %s +++ "
45 static vo_info_t info
= {
48 "Alban Bedel <albeu@free.fr> and Folke Ashberg <folke@ashberg.de>",
54 /* aa's main context we use */
58 /* used for the sws */
59 static uint8_t * image
[3];
60 static int image_stride
[3];
63 static int image_format
;
64 static int image_width
;
65 static int image_height
;
66 static int image_x
, image_y
;
67 static int screen_x
, screen_y
;
68 static int screen_w
, screen_h
;
70 static int src_height
;
74 static int showosdmessage
= 0;
75 char osdmessagetext
[MESSAGE_SIZE
];
76 char posbar
[MESSAGE_SIZE
];
77 static int osdx
, osdy
;
78 static int osd_text_length
= 0;
81 font_desc_t
* vo_font_save
= NULL
;
83 static struct SwsContext
*sws
=NULL
;
85 /* our version of the playmodes :) */
87 extern void mplayer_put_key(int code
);
89 /* to disable stdout outputs when curses/linux mode */
93 int aaopt_osdcolor
= AA_SPECIAL
;
94 int aaopt_subcolor
= AA_SPECIAL
;
96 extern struct aa_hardware_params aa_defparams
;
97 extern struct aa_renderparams aa_defrenderparams
;
102 * this function is called by aa lib if windows resizes
103 * further during init, because here we have to calculate
109 aspect_save_screenres(aa_imgwidth(c
),aa_imgheight(c
));
110 image_height
= aa_imgheight(c
); //src_height;
111 image_width
= aa_imgwidth(c
); //src_width;
113 aspect(&image_width
,&image_height
,A_ZOOM
);
115 image_x
= (aa_imgwidth(c
) - image_width
) / 2;
116 image_y
= (aa_imgheight(c
) - image_height
) / 2;
117 screen_w
= image_width
* aa_scrwidth(c
) / aa_imgwidth(c
);
118 screen_h
= image_height
* aa_scrheight(c
) / aa_imgheight(c
);
119 screen_x
= (aa_scrwidth(c
) - screen_w
) / 2;
120 screen_y
= (aa_scrheight(c
) - screen_h
) / 2;
122 if(sws
) sws_freeContext(sws
);
123 sws
= sws_getContextFromCmdLine(src_width
,src_height
,image_format
,
124 image_width
,image_height
,IMGFMT_Y8
);
126 image
[0] = aa_image(c
) + image_y
* aa_imgwidth(c
) + image_x
;
130 image_stride
[0] = aa_imgwidth(c
);
139 osdmessage(int duration
, int deko
, char *fmt
, ...)
142 * for outputting a centered string at the bottom
143 * of our window for a while
146 char m
[MESSAGE_SIZE
];
147 unsigned int old_len
= strlen(osdmessagetext
);
150 vsprintf(m
, fmt
, ar
);
152 if (deko
==1) sprintf(osdmessagetext
, MESSAGE_DEKO
, m
);
153 else strcpy(osdmessagetext
, m
);
155 if(old_len
> strlen(osdmessagetext
)) {
156 memset(c
->textbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,' ',old_len
);
157 memset(c
->attrbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,0,old_len
);
160 stoposd
= time(NULL
) + duration
;
161 osdx
=(aa_scrwidth(c
) / 2) - (strlen(osdmessagetext
) / 2 ) ;
166 osdpercent(int duration
, int deko
, int min
, int max
, int val
, char * desc
, char * unit
)
169 * prints a bar for setting values
176 step
=(float)aa_scrwidth(c
) /(float)(max
-min
);
177 where
=(val
-min
)*step
;
178 osdmessage(duration
,deko
,"%s: %i%s",desc
, val
, unit
);
180 posbar
[aa_scrwidth(c
)-1]='|';
181 for (i
=0;i
<aa_scrwidth(c
);i
++){
182 if (i
==where
) posbar
[i
]='#';
185 if (where
!=0) posbar
[0]='|';
186 if (where
!=(aa_scrwidth(c
)-1) ) posbar
[aa_scrwidth(c
)-1]='|';
188 posbar
[aa_scrwidth(c
)]='\0';
195 if(osd_text_length
> 0 && !vo_osd_text
) {
196 memset(c
->textbuffer
,' ',osd_text_length
);
197 memset(c
->attrbuffer
,0,osd_text_length
);
201 * places the mplayer status osd
203 if (vo_osd_text
&& vo_osd_text
[0] != 0) {
205 if(vo_osd_text
[0] < 32) {
206 len
= strlen(__sub_osd_names_short
[vo_osd_text
[0]]) + strlen(vo_osd_text
+1) + 2;
207 aa_printf(c
, 0, 0 , aaopt_osdcolor
, "%s %s ", __sub_osd_names_short
[vo_osd_text
[0]], vo_osd_text
+1);
209 len
= strlen(vo_osd_text
) + 1;
210 aa_printf(c
, 0, 0 , aaopt_osdcolor
, "%s ",vo_osd_text
);
213 if(len
< osd_text_length
) {
214 memset(c
->textbuffer
+ len
,' ',osd_text_length
- len
);
215 memset(c
->attrbuffer
+ len
,0,osd_text_length
- len
);
217 osd_text_length
= len
;
224 /* print mplayer osd-progbar */
225 if (vo_osd_progbar_type
!=-1){
226 osdpercent(1,1,0,255,vo_osd_progbar_value
, __sub_osd_names
[vo_osd_progbar_type
], "");
230 config(uint32_t width
, uint32_t height
, uint32_t d_width
,
231 uint32_t d_height
, uint32_t fullscreen
, char *title
,
240 aspect_save_orig(width
,height
);
241 aspect_save_prescale(d_width
,d_height
);
245 image_format
= format
;
247 /* nothing will change its size, be we need some values initialized */
251 /* now init out own 'font' (to use vo_draw_text_sub without edit them) */
252 if(!vo_font_save
) vo_font_save
= vo_font
;
253 if(vo_font
== vo_font_save
) {
254 vo_font
=malloc(sizeof(font_desc_t
));//if(!desc) return NULL;
255 memset(vo_font
,0,sizeof(font_desc_t
));
256 vo_font
->pic_a
[0]=malloc(sizeof(raw_file
));
257 memset(vo_font
->pic_a
[0],0,sizeof(raw_file
));
258 vo_font
->pic_b
[0]=malloc(sizeof(raw_file
));
259 memset(vo_font
->pic_b
[0],0,sizeof(raw_file
));
262 vo_font
->dynamic
= 0;
265 vo_font
->spacewidth
=1;
266 vo_font
->charspace
=0;
268 vo_font
->pic_a
[0]->bmp
=malloc(255);
269 vo_font
->pic_a
[0]->pal
=NULL
;
270 vo_font
->pic_b
[0]->bmp
=malloc(255);
271 vo_font
->pic_b
[0]->pal
=NULL
;
272 vo_font
->pic_a
[0]->w
=1;
273 vo_font
->pic_a
[0]->h
=1;
274 for (i
=0; i
<255; i
++){
278 vo_font
->pic_a
[0]->bmp
[i
]=i
;
279 vo_font
->pic_b
[0]->bmp
[i
]=i
;
284 osdmessage(5, 1, "Welcome to ASCII ART MPlayer");
286 mp_msg(MSGT_VO
,MSGL_V
,"VO: [aa] screendriver: %s\n", c
->driver
->name
);
287 mp_msg(MSGT_VO
,MSGL_V
,"VO: [aa] keyboarddriver: %s\n", c
->kbddriver
->name
);
289 mp_msg(MSGT_VO
,MSGL_INFO
,
291 "Important Options\n"
292 "\t-aaextended use use all 256 characters\n"
293 "\t-aaeight use eight bit ascii\n"
294 "\t-aadriver set recommended aalib driver (X11,curses,linux)\n"
295 "\t-aahelp to see all options provided by aalib\n"
300 "\t3 : brightness -\n"
301 "\t4 : brightness +\n"
302 "\t5 : fast rendering\n"
304 "\t7 : invert image\n"
305 "\ta : toggles between aa and mplayer control\n"
308 "All other keys are MPlayer defaults.\n"
317 query_format(uint32_t format
) {
319 * ...are we able to... ?
321 * All input format supported by the sws
336 return VFCAP_CSP_SUPPORTED
|VFCAP_SWSCALE
346 draw_frame(uint8_t *src
[]) {
347 int stride
[3] = { 0 , 0 , 0 };
349 switch(image_format
) {
352 stride
[0] = src_width
*2;
356 stride
[0] = src_width
*3;
359 stride
[0] = src_width
*4;
363 sws_scale_ordered(sws
,src
,stride
,0,src_height
,image
,image_stride
);
365 /* Now 'ASCIInate' the image */
367 aa_fastrender(c
, screen_x
, screen_y
, screen_w
+ screen_x
, screen_h
+ screen_y
);
369 aa_render(c
, p
,screen_x
, screen_y
, screen_w
+ screen_x
, screen_h
+ screen_y
);
375 draw_slice(uint8_t *src
[], int stride
[],
376 int w
, int h
, int x
, int y
) {
378 int dx1
= screen_x
+ (x
* screen_w
/ src_width
);
379 int dy1
= screen_y
+ (y
* screen_h
/ src_height
);
380 int dx2
= screen_x
+ ((x
+w
) * screen_w
/ src_width
);
381 int dy2
= screen_y
+ ((y
+h
) * screen_h
/ src_height
);
383 sws_scale_ordered(sws
,src
,stride
,y
,h
,image
,image_stride
);
385 /* Now 'ASCIInate' the image */
387 aa_fastrender(c
, dx1
, dy1
, dx2
, dy2
);
389 aa_render(c
, p
,dx1
, dy1
, dx2
, dy2
);
398 /* do we have to put *our* (messages, progbar) osd to aa's txtbuf ? */
401 if (time(NULL
)>=stoposd
) {
404 memset(c
->textbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,' ',strlen(osdmessagetext
));
405 memset(c
->attrbuffer
+ osdy
* aa_scrwidth(c
) + osdx
,0,strlen(osdmessagetext
));
406 osdmessagetext
[0] = '\0';
409 memset(c
->textbuffer
+ (osdy
+1) * aa_scrwidth(c
),' ',strlen(posbar
));
410 memset(c
->attrbuffer
+ (osdy
+1) * aa_scrwidth(c
),0,strlen(posbar
));
414 aa_puts(c
, osdx
, osdy
, AA_SPECIAL
, osdmessagetext
);
417 aa_puts(c
, 0, osdy
+ 1, AA_SPECIAL
, posbar
);
420 /* OSD time & playmode , subtitles */
434 * called by show_image and mplayer
437 while ((key
=aa_getevent(c
,0))!=AA_NONE
){
439 /* some conversations */
442 mplayer_put_key(KEY_UP
);
445 mplayer_put_key(KEY_DOWN
);
448 mplayer_put_key(KEY_LEFT
);
451 mplayer_put_key(KEY_RIGHT
);
454 mplayer_put_key(KEY_ESC
);
457 mplayer_put_key(KEY_PAGE_UP
);
460 mplayer_put_key(KEY_PAGE_DOWN
);
463 continue; /* aa lib special key */
467 if (key
=='a' || key
=='A'){
468 aaconfigmode
=!aaconfigmode
;
469 osdmessage(MESSAGE_DURATION
, 1, "aa config mode is now %s",
470 aaconfigmode
==1 ? "on. use keys 5-7" : "off");
472 if (aaconfigmode
==1) {
474 /* AA image controls */
477 osdmessage(MESSAGE_DURATION
, 1, "Fast mode is now %s", fast
==1 ? "on" : "off");
480 if (p
->dither
==AA_FLOYD_S
){
482 osdmessage(MESSAGE_DURATION
, 1, "Dithering: Off");
483 }else if (p
->dither
==AA_NONE
){
484 p
->dither
=AA_ERRORDISTRIB
;
485 osdmessage(MESSAGE_DURATION
, 1, "Dithering: Error Distribution");
486 }else if (p
->dither
==AA_ERRORDISTRIB
){
487 p
->dither
=AA_FLOYD_S
;
488 osdmessage(MESSAGE_DURATION
, 1, "Dithering: Floyd Steinberg");
492 p
->inversion
=!p
->inversion
;
493 osdmessage(MESSAGE_DURATION
, 1, "Invert mode is now %s",
494 p
->inversion
==1 ? "on" : "off");
498 /* nothing if we're interested in?
499 * the mplayer should handle it!
501 mplayer_put_key(key
);
505 else mplayer_put_key(key
);
515 if (strstr(c
->driver
->name
,"Curses") || strstr(c
->driver
->name
,"Linux")){
516 freopen("/dev/tty", "w", stderr
);
520 free(vo_font
->pic_a
[0]->bmp
);
521 free(vo_font
->pic_a
[0]);
522 free(vo_font
->pic_b
[0]->bmp
);
523 free(vo_font
->pic_b
[0]);
525 vo_font
= vo_font_save
;
533 static void draw_alpha(int x
,int y
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
535 for (i
= 0; i
< h
; i
++) {
536 for (j
= 0; j
< w
; j
++) {
537 if (src
[i
*stride
+j
] > 0) {
538 c
->textbuffer
[x
+ j
+ (y
+i
)*aa_scrwidth(c
)] = src
[i
*stride
+j
];
539 c
->attrbuffer
[x
+ j
+ (y
+i
)*aa_scrwidth(c
)] = aaopt_subcolor
;
545 static void clear_alpha(int x0
,int y0
, int w
,int h
) {
548 for(l
= 0 ; l
< h
; l
++) {
549 memset(c
->textbuffer
+ (y0
+ l
) * aa_scrwidth(c
) + x0
,' ',w
);
550 memset(c
->attrbuffer
+ (y0
+ l
) * aa_scrwidth(c
) + x0
,0,w
);
560 char * vo_osd_text_save
;
561 int vo_osd_progbar_type_save
;
564 /* let vo_draw_text only write subtitle */
565 vo_osd_text_save
=vo_osd_text
; /* we have to save the osd_text */
567 vo_osd_progbar_type_save
=vo_osd_progbar_type
;
568 vo_osd_progbar_type
=-1;
569 vo_remove_text(aa_scrwidth(c
), aa_scrheight(c
),clear_alpha
);
570 vo_draw_text(aa_scrwidth(c
), aa_scrheight(c
), draw_alpha
);
571 vo_osd_text
=vo_osd_text_save
;
572 vo_osd_progbar_type
=vo_osd_progbar_type_save
;
580 if (s
==NULL
) return -1;
581 i
=strtol(s
, &rest
, 10);
582 if ((rest
==NULL
|| strlen(rest
)==0) && i
>=0 && i
<=5) return i
;
583 if (!strcasecmp(s
, "normal")) return AA_NORMAL
;
584 else if (!strcasecmp(s
, "dim")) return AA_DIM
;
585 else if (!strcasecmp(s
, "bold")) return AA_BOLD
;
586 else if (!strcasecmp(s
, "boldfont")) return AA_BOLDFONT
;
587 else if (!strcasecmp(s
, "special")) return AA_SPECIAL
;
592 vo_aa_parseoption(m_option_t
* conf
, char *opt
, char *param
){
593 /* got an option starting with aa */
598 /* do WE need it ? */
599 if (!strcasecmp(opt
, "aaosdcolor")){
600 if (param
==NULL
) return M_OPT_MISSING_PARAM
;
601 if ((i
=getcolor(param
))==-1) return M_OPT_OUT_OF_RANGE
;
604 }else if (!strcasecmp(opt
, "aasubcolor")){
605 if ((i
=getcolor(param
))==-1) return M_OPT_OUT_OF_RANGE
;
608 }else if (!strcasecmp(opt
, "aahelp")){
609 printf("Here are the aalib options:\n");
610 help
=strdup(aa_help
); /* aa_help is const :( */
613 while ((x
=strtok(NULL
, "-"))){
614 if (*(x
-2)==' ') printf("-aa");
621 "Additional options vo_aa provides:\n"
622 " -aaosdcolor set osd color\n"
623 " -aasubcolor set subtitle color\n"
624 " the color parameters are:\n"
635 " <PROJECT><PROJECT>\n"
644 /* parse param to aalib */
645 pseudoargv
[1]=malloc(strlen(opt
));
647 sprintf(pseudoargv
[1], "-%s", opt
+2);
655 fprintf(stderr
,"VO: [aa] ");
656 i
=aa_parseoptions(&aa_defparams
, &aa_defrenderparams
, &pseudoargc
, pseudoargv
);
658 return M_OPT_MISSING_PARAM
;
660 if (pseudoargv
[1]!=NULL
){
661 /* aalib has given param back */
662 fprintf(stderr
," Parameter -%s accepted\n", opt
);
663 return 0; /* param could be the filename */
665 fprintf(stderr
," Parameter -%s %s accepted\n", opt
, ((param
==NULL
) ? "" : param
) );
666 return 1; /* all opt & params accepted */
669 return M_OPT_UNKNOWN
;
674 vo_aa_revertoption(m_option_t
* opt
,char* param
) {
675 if (!strcasecmp(param
, "aaosdcolor"))
676 aaopt_osdcolor
= AA_SPECIAL
;
677 else if (!strcasecmp(param
, "aasubcolor"))
678 aaopt_subcolor
= AA_SPECIAL
;
681 static uint32_t preinit(const char *arg
)
685 int fd
, vt
, major
, minor
;
688 extern aa_linkedlist
*aa_displayrecommended
;
692 mp_msg(MSGT_VO
,MSGL_ERR
,"vo_aa: Unknown subdevice: %s\n",arg
);
696 /* initializing of aalib */
698 hidis
=aa_getfirst(&aa_displayrecommended
);
700 /* check /dev/vcsa<vt> */
701 /* check only, if no driver is explicit set */
702 fd
= dup (fileno (stderr
));
704 major
= sbuf
.st_rdev
>> 8;
705 vt
= minor
= sbuf
.st_rdev
& 0xff;
707 sprintf (fname
, "/dev/vcsa%2.2i", vt
);
708 fp
= fopen (fname
, "w+");
710 fprintf(stderr
,"VO: [aa] cannot open %s for writing,"
711 "so we'll not use linux driver\n", fname
);
712 aa_recommendlowdisplay("linux");
713 aa_recommendhidisplay("curses");
714 aa_recommendhidisplay("X11");
716 } else aa_recommendhidisplay(hidis
);
717 c
= aa_autoinit(&aa_defparams
);
720 mp_msg(MSGT_VO
,MSGL_ERR
,"Cannot initialize aalib\n");
723 if (!aa_autoinitkbd(c
,0)) {
724 mp_msg(MSGT_VO
,MSGL_ERR
,"Cannot initialize keyboard\n");
729 aa_resizehandler(c
, (void *)resize
);
731 p
= aa_getrenderparams();
733 if ((strstr(c
->driver
->name
,"Curses")) || (strstr(c
->driver
->name
,"Linux"))){
734 freopen("/dev/null", "w", stderr
);
735 /* disable console blanking */
739 memset(image
,0,3*sizeof(uint8_t));
740 osdmessagetext
[0] = '\0';
746 static uint32_t control(uint32_t request
, void *data
, ...)
749 case VOCTRL_QUERY_FORMAT
:
750 return query_format(*((uint32_t*)data
));
751 case VOCTRL_SET_EQUALIZER
: {
756 val
= va_arg(ap
, int);
759 if(strcmp((char*)data
,"contrast") == 0)
760 p
->contrast
= ( val
+ 100 ) * 64 / 100;
761 else if(strcmp((char*)data
,"brightness") == 0)
762 p
->bright
= ( val
+ 100) * 128 / 100;
765 case VOCTRL_GET_EQUALIZER
: {
770 val
= va_arg(ap
, int*);
773 if(strcmp((char*)data
,"contrast") == 0)
774 *val
= (p
->contrast
- 64) * 100 / 64;
775 else if(strcmp((char*)data
,"brightness") == 0)
776 *val
= (p
->bright
- 128) * 100 / 128;