view libvo/vo_aa.c @ 4613:8497da33a0d2

updated :noprebuf to emulate the playback used in mplayer 0.60 (with dxr3 patch), this solves alot of issues for ppl who had problems with the new prebuffering code
author mswitch
date Sat, 09 Feb 2002 17:40:33 +0000
parents c35d7ce151b3
children 5a7eb882bb19
line wrap: on
line source

/*
 * MPlayer
 * 
 * Video driver for AAlib - 1.0
 * 
 * by Folke Ashberg <folke@ashberg.de>
 * 
 * Code started: Sun Aug 12 2001
 * Version 1.0 : Thu Aug 16 2001
 *
 */

#include <stdio.h>
#include <stdlib.h>

#include <sys/stat.h>
#include <unistd.h>

#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <time.h>
#include <string.h>

#include "config.h"
#include "video_out.h"
#include "video_out_internal.h"
#include "../postproc/rgb2rgb.h"
#include "sub.h"

#include "linux/keycodes.h"
#include <aalib.h>
#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 <folke@ashberg.de>",
	    ""
	};

/* 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<aa_scrwidth(c);i++){
	if (i==where) posbar[i]='#';
	else posbar[i]='-';
    }
    if (where!=0) posbar[0]='|';
    if (where!=(aa_scrwidth(c)-1) ) posbar[aa_scrwidth(c)-1]='|';
    /* snipp */
    posbar[aa_scrwidth(c)]='\0';
    showosdmessage=1;
    stoposd = time(NULL) + duration;
    osdx=(aa_scrwidth(c) / 2) - (strlen(osdmessagetext) / 2 ) ;
}

void
printosdtext()
{
    /* 
     * places the mplayer status osd
     */
    if (vo_osd_text)
	aa_printf(c, 0, 0 , aaopt_osdcolor, "%s %s ", __sub_osd_names_short[vo_osd_text[0]], vo_osd_text+1);
}

void
printosdprogbar(){
    /* print mplayer osd-progbar */
    if (vo_osd_progbar_type!=-1){
	osdpercent(1,1,0,255,vo_osd_progbar_value, __sub_osd_names[vo_osd_progbar_type], "");	
    }
}
static uint32_t
config(uint32_t width, uint32_t height, uint32_t d_width,
	    uint32_t d_height, uint32_t fullscreen, char *title, 
	    uint32_t format,const vo_tune_info_t *info) {
    /*
     * main init
     * called by mplayer
     */
    FILE * fp;
    char fname[12];
    int fd, vt, major, minor;
    struct stat sbuf;
    char * hidis = NULL;
    int i;
    extern aa_linkedlist *aa_displayrecommended;

    switch(format) {
	case IMGFMT_BGR24:
	    bpp = 24;
	    break;     
	case IMGFMT_RGB24:
	    bpp = 24;
	    break;     
	case IMGFMT_YV12:
	    bpp = 24;
	    /* YUV ? then initialize what we will need */
	    convertbuf=malloc(width*height*3);
	    yuv2rgb_init(24,MODE_BGR);
	    break;
	default:
	    return 1;     
    }
    bppmul=bpp/8;
    

    /* initializing of aalib */
    
    hidis=aa_getfirst(&aa_displayrecommended); 
    if ( hidis==NULL ){
	/* check /dev/vcsa<vt> */
	/* 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;i<aa_scrwidth(c)*aa_scrheight(c);i++){
	if (osdbuffer[i]){
	    c->textbuffer[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[4];
    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"
                    "      <PROJECT><PROJECT>\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;
		
}

void
vo_aa_revertoption(config_t* opt,char* param) {
  if (!strcasecmp(opt, "aaosdcolor"))
    aaopt_osdcolor= AA_SPECIAL;
  else if (!strcasecmp(opt, "aasubcolor"))
    aaopt_subcolor= AA_SPECIAL;
}

static uint32_t preinit(const char *arg)
{
  return 0;
}

static uint32_t control(uint32_t request, void *data, ...)
{
  switch (request) {
  case VOCTRL_QUERY_FORMAT:
    return query_format(*((uint32_t*)data));
  }
  return VO_NOTIMPL;
}