/* * MPlayer * * Video driver for AAlib - 1.0 * * by Folke Ashberg * * Code started: Sun Aug 12 2001 * Version 1.0 : Thu Aug 16 2001 * */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "video_out.h" #include "video_out_internal.h" #include "../postproc/rgb2rgb.h" #include "sub.h" #include "linux/keycodes.h" #include #include "cfgparser.h" #define RGB 0 #define BGR 1 #define DO_INC(val,max,step) if (val + step <=max) val+=step; else val=max; #define DO_DEC(val,min,step) if (val - step >=min) val-=step; else val=min; #define MESSAGE_DURATION 3 #define MESSAGE_SIZE 512 #define MESSAGE_DEKO " +++ %s +++ " LIBVO_EXTERN(aa) static vo_info_t vo_info = { "AAlib", "aa", "Folke Ashberg ", "" }; /* aa's main context we use */ aa_context *c; aa_renderparams *p; static int fast =0; /* used for YV12 streams for the converted RGB image */ uint8_t * convertbuf=NULL; /* image infos */ static int image_format, bpp=24; static int image_width; static int image_height; static int bppmul; /* osd stuff */ time_t stoposd = 0; static int showosdmessage = 0; char osdmessagetext[MESSAGE_SIZE]; char posbar[MESSAGE_SIZE]; static int osdx, osdy; int aaconfigmode=1; /* for resizing/scaling */ static int *stx; static int *sty; double accum; #ifdef USE_OSD char * osdbuffer=NULL; #endif /* our version of the playmodes :) */ extern void mplayer_put_key(int code); /* to disable stdout outputs when curses/linux mode */ extern int quiet; /* configuration */ int aaopt_osdcolor = AA_SPECIAL; int aaopt_subcolor = AA_SPECIAL; extern struct aa_hardware_params aa_defparams; extern struct aa_renderparams aa_defrenderparams; void resize(void){ /* * this function is called by aa lib if windows resizes * further during init, because here we have to calculate * a little bit */ int i; aa_resize(c); showosdmessage=0; osdy=aa_scrheight(c) - ( aa_scrheight(c)/10 ); /* now calculating the needed values for resizing */ /* We only need to use floating point to determine the correct stretch vector for one line's worth. */ stx = (int *) malloc(sizeof(int) * image_width); sty = (int *) malloc(sizeof(int) * image_height); accum = 0; for (i=0; (i < image_width); i++) { int got; accum += (double)aa_imgwidth(c)/(double)image_width; got = (int) floor(accum); stx[i] = got; accum -= got; } accum = 0; for (i=0; (i < image_height); i++) { int got; accum += (double)aa_imgheight(c)/(double)image_height; got = (int) floor(accum); sty[i] = got; accum -= got; } #ifdef USE_OSD if (osdbuffer!=NULL) free(osdbuffer); osdbuffer=malloc(aa_scrwidth(c) * aa_scrheight(c)); #endif } void osdmessage(int duration, int deko, char *fmt, ...) { /* * for outputting a centered string at the bottom * of our window for a while */ va_list ar; char m[MESSAGE_SIZE]; va_start(ar, fmt); vsprintf(m, fmt, ar); va_end(ar); if (deko==1) sprintf(osdmessagetext, MESSAGE_DEKO , m); else strcpy(osdmessagetext, m); showosdmessage=1; stoposd = time(NULL) + duration; osdx=(aa_scrwidth(c) / 2) - (strlen(osdmessagetext) / 2 ) ; posbar[0]='\0'; } void osdpercent(int duration, int deko, int min, int max, int val, char * desc, char * unit) { /* * prints a bar for setting values */ float step; int where; char m[MESSAGE_SIZE]; int i; step=(float)aa_scrwidth(c) /(float)(max-min); where=(val-min)*step; sprintf(m,"%s: %i%s",desc, val, unit); if (deko==1) sprintf(osdmessagetext, MESSAGE_DEKO , m); else strcpy(osdmessagetext, m); posbar[0]='|'; posbar[aa_scrwidth(c)-1]='|'; for (i=0;i */ /* check only, if no driver is explicit set */ fd = dup (fileno (stderr)); fstat (fd, &sbuf); major = sbuf.st_rdev >> 8; vt = minor = sbuf.st_rdev & 0xff; close (fd); sprintf (fname, "/dev/vcsa%i", vt); fp = fopen (fname, "w+"); if (fp==NULL){ fprintf(stderr,"VO: [aa] cannot open %s for writing," "so we'll not use linux driver\n", fname); aa_recommendlowdisplay("linux"); aa_recommendhidisplay("curses"); aa_recommendhidisplay("X11"); }else fclose(fp); } else aa_recommendhidisplay(hidis); c = aa_autoinit(&aa_defparams); aa_resizehandler(c, (void *)resize); if (c == NULL) { printf("Can not intialize aalib\n"); return 0; } if (!aa_autoinitkbd(c,0)) { printf("Can not intialize keyboard\n"); aa_close(c); return 0; } /* if (!aa_autoinitmouse(c,0)) { printf("Can not intialize mouse\n"); aa_close(c); return 0; } */ aa_hidecursor(c); p = aa_getrenderparams(); if ((strstr(c->driver->name,"Curses")) || (strstr(c->driver->name,"Linux"))){ freopen("/dev/null", "w", stderr); quiet=1; /* disable mplayer outputs */ /* disable console blanking */ printf("\033[9;0]"); } image_height = height; image_width = width; image_format = format; /* needed by prepare_image */ stx = (int *) malloc(sizeof(int) * image_width); sty = (int *) malloc(sizeof(int) * image_height); /* nothing will change its size, be we need some values initialized */ resize(); #ifdef USE_OSD /* now init out own 'font' (to use vo_draw_text_sub without edit them) */ vo_font=malloc(sizeof(font_desc_t));//if(!desc) return NULL; memset(vo_font,0,sizeof(font_desc_t)); vo_font->pic_a[0]=malloc(sizeof(raw_file)); vo_font->pic_b[0]=malloc(sizeof(raw_file)); vo_font->spacewidth=1; vo_font->charspace=0; vo_font->height=1; vo_font->pic_a[0]->bmp=malloc(255); vo_font->pic_b[0]->bmp=malloc(255); vo_font->pic_a[0]->w=1; vo_font->pic_a[0]->h=1; for (i=1; i<256; i++){ vo_font->width[i]=1; vo_font->font[i]=0; vo_font->start[i]=i; vo_font->pic_a[0]->bmp[i]=i; vo_font->pic_b[0]->bmp[i]=i; }; #endif /* say hello */ osdmessage(5, 1, "Welcome to ASCII ARTS MPlayer"); printf("VO: [aa] screendriver: %s\n", c->driver->name); printf("VO: [aa] keyboarddriver: %s\n", c->kbddriver->name); //printf("VO: mousedriver: %s\n", c->mousedriver->name); printf( "\n" "Important Options\n" "\t-aaextended use use all 256 characters\n" "\t-aaeight use eight bit ascii\n" "\t-aadriver set recommended aalib driver (X11,curses,linux)\n" "\t-aahelp to see all options provided by aalib\n" "\n" "AA-MPlayer Keys\n" "\t1 : contrast -\n" "\t2 : contrast +\n" "\t3 : brightness -\n" "\t4 : brightness +\n" "\t5 : fast rendering\n" "\t6 : dithering\n" "\t7 : invert image\n" "\ta : toggles between aa and mplayer control\n" "\n" "All other keys are MPlayer defaults.\n" ); return 0; } static uint32_t query_format(uint32_t format) { /* * ...are we able to... ? * called by mplayer */ switch(format){ case IMGFMT_YV12: case IMGFMT_RGB|24: case IMGFMT_BGR|24: return 1; } return 0; } static const vo_info_t* get_info(void) { /* who i am? */ return (&vo_info); } int prepare_image(uint8_t *data, int inx, int iny, int outx, int outy){ /* * copies an RGB-Image to the aalib imagebuffer * also scaling an grayscaling is done here * show_image calls us */ int value; int x, y; int tox, toy; int ydest; int i; int pos; toy = 0; for (y=0; (y < (0 + iny)); y++) { for (ydest=0; (ydest < sty[y-0]); ydest++) { tox = 0; for (x=0; (x < (0 + inx)); x++) { if (!stx[x - 0]) { continue; } pos=3*(inx*y)+(3*x); value=(data[pos]+data[pos+1]+data[pos+2])/3; for (i=0; (i < stx[x - 0]); i++) { //printf("ToX: %i, ToY %i, i=%i, stx=%i, x=%i\n", tox, toy, i, stx[x], x); c->imagebuffer[(toy*outx) +tox]=value; tox++; } } toy++; } } return 0; } void show_image(uint8_t * src){ /* * every frame (flip_page/draw_frame) we will be called */ #ifdef USE_OSD int i; #endif /* events? */ check_events(); /* RGB->gray , scaling/resizing, stores data in aalib imgbuf */ prepare_image( src, image_width, image_height, aa_imgwidth(c), aa_imgheight(c) ); /* Now 'ASCIInate' the image */ if (fast) aa_fastrender(c, 0, 0, aa_scrwidth(c), aa_scrheight(c) ); else aa_render(c, p, 0, 0, aa_scrwidth(c), aa_scrheight(c)); /* do we have to put *our* (messages, progbar) osd to aa's txtbuf ? */ if (showosdmessage) { if (time(NULL)>=stoposd ) showosdmessage=0; /* update osd */ aa_puts(c, osdx, osdy, AA_SPECIAL, osdmessagetext); /* posbar? */ if (posbar[0]!='\0') aa_puts(c, 0, osdy + 1, AA_SPECIAL, posbar); } /* OSD time & playmode , subtitles */ #ifdef USE_OSD printosdtext(); /* now write the subtitle osd buffer */ for (i=0;itextbuffer[i]=osdbuffer[i]; c->attrbuffer[i]=aaopt_subcolor; } } #endif /* print out */ aa_flush(c); } static uint32_t draw_frame(uint8_t *src[]) { /* * RGB-Video's Only * src[0] is handled by prepare_image */ show_image(src[0]); return 0; } static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y) { /* * for MPGEGS YV12 * draw a rectangle converted to RGB to a * temporary RGB Buffer */ uint8_t *dst; dst = convertbuf+(image_width * y + x) * 3; yuv2rgb(dst,src[0],src[1],src[2],w,h,image_width*3,stride[0],stride[1]); return 0; } static void flip_page(void) { /* * wow! another ready Image, so draw it ! */ if(image_format == IMGFMT_YV12) show_image(convertbuf); } static void check_events(void) { /* * any events? * called by show_image and mplayer */ int key; while ((key=aa_getevent(c,0))!=AA_NONE ){ if (key>255){ /* some conversations */ switch (key) { case AA_UP: mplayer_put_key(KEY_UP); break; case AA_DOWN: mplayer_put_key(KEY_DOWN); break; case AA_LEFT: mplayer_put_key(KEY_LEFT); break; case AA_RIGHT: mplayer_put_key(KEY_RIGHT); break; case AA_ESC: mplayer_put_key(KEY_ESC); break; case 65765: mplayer_put_key(KEY_PAGE_UP); break; case 65766: mplayer_put_key(KEY_PAGE_DOWN); break; default: continue; /* aa lib special key */ break; } } if (key=='a' || key=='A'){ aaconfigmode=!aaconfigmode; osdmessage(MESSAGE_DURATION, 1, "aa config mode is now %s", aaconfigmode==1 ? "on. use keys 1-7" : "off"); } if (aaconfigmode==1) { switch (key) { /* AA image controls */ case '1': /* contrast */ DO_DEC(p->contrast,0,1); osdpercent(MESSAGE_DURATION, 1, 0, 255, p->contrast, "AA-Contrast", ""); break; case '2': /* contrast */ DO_INC(p->contrast,255,1); osdpercent(MESSAGE_DURATION, 1, 0, 255, p->contrast, "AA-Contrast", ""); break; case '3': /* brightness */ DO_DEC(p->bright,0,1); osdpercent(MESSAGE_DURATION, 1, 0, 255, p->bright, "AA-Brightnes", ""); break; case '4': /* brightness */ DO_INC(p->bright,255,1); osdpercent(MESSAGE_DURATION, 1, 0, 255, p->bright, "AA-Brightnes", ""); break; case '5': fast=!fast; osdmessage(MESSAGE_DURATION, 1, "Fast mode is now %s", fast==1 ? "on" : "off"); break; case '6': if (p->dither==AA_FLOYD_S){ p->dither=AA_NONE; osdmessage(MESSAGE_DURATION, 1, "Dithering: Off"); }else if (p->dither==AA_NONE){ p->dither=AA_ERRORDISTRIB; osdmessage(MESSAGE_DURATION, 1, "Dithering: Error Distribution"); }else if (p->dither==AA_ERRORDISTRIB){ p->dither=AA_FLOYD_S; osdmessage(MESSAGE_DURATION, 1, "Dithering: Floyd Steinberg"); } break; case '7': p->inversion=!p->inversion; osdmessage(MESSAGE_DURATION, 1, "Invert mode is now %s", p->inversion==1 ? "on" : "off"); break; default : /* nothing if we're interested in? * the mplayer should handle it! */ mplayer_put_key(key); break; } }// aaconfigmode else mplayer_put_key(key); } } static void uninit(void) { /* * THE END */ if (strstr(c->driver->name,"Curses") || strstr(c->driver->name,"Linux")){ freopen("/dev/tty", "w", stderr); quiet=0; /* enable mplayer outputs */ } #ifdef USE_OSD if (osdbuffer!=NULL) free(osdbuffer); #endif aa_close(c); free(stx); free(sty); if (convertbuf!=NULL) free(convertbuf); } #ifdef USE_OSD static void draw_alpha(int x,int y, int w,int h, unsigned char* src, unsigned char *srca, int stride){ /* alpha, hm, grr, only the char into our osdbuffer */ int pos; pos=(x)+(y)*(aa_scrwidth(c)); osdbuffer[pos]=src[0]; } #endif static void draw_osd(void){ #ifdef USE_OSD /* * the subtiles are written into a own osdbuffer * because draw_osd is called after show_image/flip_page * the osdbuffer is written the next show_image/flip_page * into aatextbuf */ char * vo_osd_text_save; int vo_osd_progbar_type_save; memset(osdbuffer,0,aa_scrwidth(c)*aa_scrheight(c)); printosdprogbar(); /* let vo_draw_text only write subtitle */ vo_osd_text_save=vo_osd_text; /* we have to save the osd_text */ vo_osd_text=NULL; vo_osd_progbar_type_save=vo_osd_progbar_type; vo_osd_progbar_type=-1; vo_draw_text(aa_scrwidth(c), aa_scrheight(c), draw_alpha); vo_osd_text=vo_osd_text_save; vo_osd_progbar_type=vo_osd_progbar_type_save; #endif } int getcolor(char * s){ int i; char * rest; if (s==NULL) return -1; i=strtol(s, &rest, 10); if ((rest==NULL || strlen(rest)==0) && i>=0 && i<=5) return i; if (!strcasecmp(s, "normal")) return AA_NORMAL; else if (!strcasecmp(s, "dim")) return AA_DIM; else if (!strcasecmp(s, "bold")) return AA_BOLD; else if (!strcasecmp(s, "boldfont")) return AA_BOLDFONT; else if (!strcasecmp(s, "special")) return AA_SPECIAL; else return -1; } int vo_aa_parseoption(struct config * conf, char *opt, char *param){ /* got an option starting with aa */ char *pseudoargv[3]; int pseudoargc; char * x, *help; int i; /* do WE need it ? */ if (!strcasecmp(opt, "aaosdcolor")){ if (param==NULL) return ERR_MISSING_PARAM; if ((i=getcolor(param))==-1) return ERR_OUT_OF_RANGE; aaopt_osdcolor=i; return 1; }else if (!strcasecmp(opt, "aasubcolor")){ if ((i=getcolor(param))==-1) return ERR_OUT_OF_RANGE; aaopt_subcolor=i; return 1; }else if (!strcasecmp(opt, "aahelp")){ printf("Here are the aalib options:\n"); help=strdup(aa_help); /* aa_help is const :( */ x=strtok(help,"-"); printf(x); while ((x=strtok(NULL, "-"))){ if (*(x-2)==' ') printf("-aa"); else printf("-"); printf("%s", x); } printf( "\n" "\n" "Additional options vo_aa provides:\n" " -aaosdcolor set osd color\n" " -aasubcolor set subtitle color\n" " the color params are:\n" " 0 : normal\n" " 1 : dark\n" " 2 : bold\n" " 3 : boldfont\n" " 4 : reverse\n" " 6 : special\n" "\n\n" " dT8 8Tb\n" " dT 8 8 Tb\n" " dT 8 8 Tb\n" " \n" " dT 8 8 Tb\n" " dT 8 8 Tb\n" "\n" ); exit(0); }else{ /* parse param to aalib */ pseudoargv[1]=malloc(strlen(opt)); pseudoargv[3]=NULL; sprintf(pseudoargv[1], "-%s", opt+2); if (param!=NULL){ pseudoargv[2]=param; pseudoargc=3; }else{ pseudoargv[2]=NULL; pseudoargc=2; } fprintf(stderr,"VO: [aa] "); i=aa_parseoptions(&aa_defparams, &aa_defrenderparams, &pseudoargc, pseudoargv); if (i!=1){ return ERR_MISSING_PARAM; } if (pseudoargv[1]!=NULL){ /* aalib has given param back */ fprintf(stderr," Parameter -%s accepted\n", opt); return 0; /* param could be the filename */ } fprintf(stderr," Parameter -%s %s accepted\n", opt, ((param==NULL) ? "" : param) ); return 1; /* all opt & params accepted */ } return ERR_NOT_AN_OPTION; }