Mercurial > mplayer.hg
view libvo/vo_dxr2.c @ 16718:044260623695
makes demux_lavf (-demuxer 35) use the framerate specified in the container
if it's set and only fall back to the codec framerate if the former is not
set.
This solves the issue of some avi's playing at 30000/1 fps instead of the
correct framerate.
Patch by Ivo < ivop AH euronet POIS nl >
Original thread:
Date: Sep 25, 2005 12:34 AM
Subject: [MPlayer-dev-eng] [PATCH] make demux_lavf use container framerate
author | gpoirier |
---|---|
date | Mon, 10 Oct 2005 05:45:38 +0000 |
parents | fd51fd1ff231 |
children | e60c8c7399d2 |
line wrap: on
line source
#include "fastmemcpy.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <time.h> #include <errno.h> #include "config.h" #include "video_out.h" #include "video_out_internal.h" #include "mp_msg.h" #include "m_option.h" #include "sub.h" #ifdef X11_FULLSCREEN #include "x11_common.h" #endif #include <dxr2ioctl.h> extern char *get_path(char *filename); extern float monitor_aspect; extern float movie_aspect; int dxr2_fd = -1; static int movie_w,movie_h; static int playing = 0; static int last_freq_id = -1; // vo device used to blank the screen for the overlay init static vo_functions_t* sub_vo = NULL; static uint8_t* sub_img = NULL; static int sub_x,sub_y,sub_w,sub_h; static int sub_x_off,sub_y_off; static int sub_config_count; static int aspect; static int sub_vo_win = 0; static int use_ol = 1; static int ol_ratio = 1000; static char *norm = NULL; static char *ucode = NULL; static int ar_mode = DXR2_ASPECTRATIOMODE_LETTERBOX; static int mv_mode = DXR2_MACROVISION_OFF; static int _75ire_mode = DXR2_75IRE_OFF; static int bw_mode = DXR2_BLACKWHITE_OFF; static int interlaced_mode = DXR2_INTERLACED_ON; static int pixel_mode = DXR2_PIXEL_CCIR601; static int iec958_mode = DXR2_IEC958_DECODED; static int mute_mode = DXR2_AUDIO_MUTE_OFF; static int ignore_cache = 0; static int update_cache = 0; static int olw_cor = 0, olh_cor = 0,olx_cor = 0, oly_cor = 0; static int ol_osd = 0; static int ck_rmin = 0x40; static int ck_rmax = 0xFF; static int ck_r = 0xFF; static int ck_gmin = 0x00; static int ck_gmax = 0x20; static int ck_g = 0; static int ck_bmin = 0x40; static int ck_bmax = 0xFF; static int ck_b = 0xFF; static int cr_left = 0, cr_right = 0; static int cr_top = 55, cr_bot = 300; m_option_t dxr2_opts[] = { { "overlay", &use_ol, CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "nooverlay", &use_ol, CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "overlay-ratio", &ol_ratio, CONF_TYPE_INT, CONF_RANGE, 1, 2500, NULL }, { "ucode", &ucode, CONF_TYPE_STRING,0, 0, 0, NULL}, { "norm", &norm, CONF_TYPE_STRING,0, 0, 0, NULL}, { "ar-mode",&ar_mode, CONF_TYPE_INT, CONF_RANGE,0,2,NULL }, { "macrovision",&mv_mode,CONF_TYPE_INT,CONF_RANGE,0,3, NULL }, { "75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "no75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "bw",&bw_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "color",&bw_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "interlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "nointerlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "square-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "ccir601-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "iec958-encoded",&iec958_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "iec958-decoded",&iec958_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "mute", &mute_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "nomute",&mute_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "ignore-cache",&ignore_cache,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "update-cache",&update_cache,CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "olh-cor", &olh_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL}, { "olw-cor", &olw_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL}, { "olx-cor", &olx_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL}, { "oly-cor", &oly_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL}, { "ol-osd", &ol_osd, CONF_TYPE_FLAG, 0, 0, 1, NULL}, { "nool-osd", &ol_osd, CONF_TYPE_FLAG, 0, 1, 0, NULL}, { "ck-rmin", &ck_rmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-rmax", &ck_rmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-r", &ck_r, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-gmin", &ck_gmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-gmax", &ck_gmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-g", &ck_g, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-bmin", &ck_bmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-bmax", &ck_bmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "ck-b", &ck_b, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL}, { "cr-left", &cr_left, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL}, { "cr-right", &cr_right, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL}, { "cr-top", &cr_top, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL}, { "cr-bot", &cr_bot, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL}, { NULL,NULL, 0, 0, 0, 0, NULL} }; static vo_info_t info = { "DXR2 video out", "dxr2", "Alban Bedel <albeu@free.fr> and Tobias Diedrich <ranma@gmx.at>", "" }; LIBVO_EXTERN (dxr2) static char *ucodesearchpath[] = { "/usr/local/lib/dxr2/dvd12.ux", "/usr/lib/dxr2/dvd12.ux", "/usr/src/dvd12.ux", NULL, }; #define BUF_SIZE 2048 static unsigned char dxr2buf[BUF_SIZE]; static unsigned int dxr2bufpos = 0; static void write_dxr2(void *data, int len) { int w = 0; while (len>0) if ((dxr2bufpos+len) <= BUF_SIZE) { memcpy(dxr2buf+dxr2bufpos, data, len); dxr2bufpos+=len; len=0; } else { int copylen=BUF_SIZE-dxr2bufpos; if(copylen > 0) { memcpy(dxr2buf+dxr2bufpos, data, copylen); dxr2bufpos += copylen; data+=copylen; len-=copylen; } w = write(dxr2_fd, dxr2buf, BUF_SIZE); if(w < 0) { mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed : %s \n",strerror(errno)); dxr2bufpos = 0; break; } dxr2bufpos -= w; if(dxr2bufpos) memmove(dxr2buf,dxr2buf + w,dxr2bufpos); } } static void flush_dxr2() { int w; while (dxr2bufpos) { w = write(dxr2_fd, dxr2buf, dxr2bufpos); if(w < 0) { mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed %s \n",strerror(errno)); dxr2bufpos = 0; break; } dxr2bufpos -= w; } } #define PACK_MAX_SIZE 2048 static unsigned char pack[PACK_MAX_SIZE]; static unsigned char mpg_header[]={ 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, 0x01, 0x86, 0xa3, 0xf8 }; static unsigned char mpg_eof[]={ 0x00, 0x00, 0x01, 0xb9 }; static void dxr2_send_header(void) { write_dxr2(&mpg_header, sizeof(mpg_header)); } static void dxr2_send_eof(void) { write_dxr2(&mpg_eof, sizeof(mpg_eof)); } void dxr2_send_packet(unsigned char* data,int len,int id,int timestamp) { int ptslen=5; if(dxr2_fd < 0) { mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n"); return; } mp_msg(MSGT_VO,MSGL_DBG2,"DXR2 packet : 0x%x => %d \n",id,timestamp); dxr2_send_header(); // startcode: pack[0]=pack[1]=0;pack[2]=0x01; // stream id pack[3]=id; while(len>0){ int payload_size=len; // data + PTS if(9+ptslen+payload_size>PACK_MAX_SIZE) payload_size=PACK_MAX_SIZE-(6+ptslen); // construct PES header: (code from ffmpeg's libav) // packetsize: pack[4]=(3+ptslen+payload_size)>>8; pack[5]=(3+ptslen+payload_size)&255; pack[6]=0x81; if(ptslen){ int x; pack[7]=0x80; pack[8]=ptslen; // presentation time stamp: x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1; pack[9]=x; x=((((timestamp >> 15) & 0x7fff) << 1) | 1); pack[10]=x>>8; pack[11]=x&255; x=((((timestamp) & 0x7fff) << 1) | 1); pack[12]=x>>8; pack[13]=x&255; } else { pack[7]=0x00; pack[8]=0x00; } write_dxr2(pack, 9+ptslen); write_dxr2(data, payload_size); len-=payload_size; data+=payload_size; ptslen=0; // store PTS only once, at first packet! } } void dxr2_send_lpcm_packet(unsigned char* data,int len,int id,unsigned int timestamp,int freq_id) { int arg; int ptslen=5; if(dxr2_fd < 0) { mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n"); return; } if(last_freq_id != freq_id) { ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY, &freq_id); last_freq_id = freq_id; } if (((int) timestamp)<0) timestamp=0; mp_msg(MSGT_VO,MSGL_DBG2,"dxr2_send_lpcm_packet(timestamp=%d)\n", timestamp); // startcode: pack[0]=pack[1]=0;pack[2]=0x01; // stream id pack[3]=0xBD; while(len>=4){ int payload_size; payload_size=PACK_MAX_SIZE-6-3-ptslen-7; // max possible data len if(payload_size>len) payload_size=len; payload_size&=(~3); // align! // packetsize: pack[4]=(payload_size+3+ptslen+7)>>8; pack[5]=(payload_size+3+ptslen+7)&255; // stuffing: pack[6]=0x81; // pack[7]=0x00; //0x80 // hdrlen: pack[8]=ptslen; if(ptslen){ int x; pack[7]=0x80; // presentation time stamp: x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1; pack[9]=x; x=((((timestamp >> 15) & 0x7fff) << 1) | 1); pack[10]=x>>8; pack[11]=x&255; x=((((timestamp) & 0x7fff) << 1) | 1); pack[12]=x>>8; pack[13]=x&255; } else { pack[7]=0x00; } // ============ LPCM header: (7 bytes) ================= // Info by mocm@convergence.de // ID: pack[ptslen+9]=id; // number of frames: pack[ptslen+10]=0x07; // first acces unit pointer, i.e. start of audio frame: pack[ptslen+11]=0x00; pack[ptslen+12]=0x04; // audio emphasis on-off 1 bit // audio mute on-off 1 bit // reserved 1 bit // audio frame number 5 bit pack[ptslen+13]=0x0C; // quantization word length 2 bit // audio sampling frequency (48khz = 0, 96khz = 1) 2 bit // reserved 1 bit // number of audio channels - 1 (e.g. stereo = 1) 3 bit pack[ptslen+14]=1; // dynamic range control (0x80 if off) pack[ptslen+15]=0x80; write_dxr2(pack, 6+3+ptslen+7); write_dxr2(data, payload_size); len-=payload_size; data+=payload_size; timestamp+=90000/4*payload_size/48000; } } void dxr2_send_sub_packet(unsigned char* data,int len,int id,unsigned int timestamp) { int ptslen=5; if(dxr2_fd < 0) { mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n"); return; } if (((int) timestamp)<0) timestamp=0; mp_msg(MSGT_VO,MSGL_DBG2,"dxr2_send_sub_packet(timestamp=%d)\n", timestamp); // startcode: pack[0]=pack[1]=0;pack[2]=0x01; // stream id pack[3]=0xBD; while(len>=4){ int payload_size= PACK_MAX_SIZE-(7+ptslen+3); if(payload_size>len) payload_size= len; pack[4]=(3+ptslen+1+payload_size)>>8; pack[5]=(3+ptslen+1+payload_size)&255; pack[6]=0x81; if(ptslen){ int x; pack[7]=0x80; pack[8]=ptslen; // presentation time stamp: x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1; pack[9]=x; x=((((timestamp >> 15) & 0x7fff) << 1) | 1); pack[10]=x>>8; pack[11]=x&255; x=((((timestamp) & 0x7fff) << 1) | 1); pack[12]=x>>8; pack[13]=x&255; } else { pack[7]=0x00; pack[8]=0x00; } pack[ptslen+9] = id; write_dxr2(pack,7+ptslen+3); write_dxr2(data,payload_size); len -= payload_size; data += payload_size; ptslen = 0; } } static int dxr2_set_vga_params(dxr2_vgaParams_t* vga,int detect) { // Init the overlay, don't ask me how it work ;-) dxr2_sixArg_t oc; dxr2_oneArg_t om; dxr2_twoArg_t win; dxr2_fourArg_t crop; crop.arg1= cr_left; crop.arg2= cr_right; crop.arg3 = cr_top; crop.arg4 = cr_bot; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop); oc.arg1 = 0x40; oc.arg2 = 0xff; oc.arg3 = 0x40; oc.arg4 = 0xff; oc.arg5 = 0x40; oc.arg6 = 0xff; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc); om.arg = ol_ratio; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_RATIO,&om); win.arg1 = 100; win.arg2 = 3; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); win.arg1 = vo_screenwidth; win.arg2 = vo_screenheight; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION,&win); om.arg = 0; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_IN_DELAY,&om); if(detect) { // First we need a white screen uint8_t* img = malloc(vo_screenwidth*vo_screenheight*3); uint8_t* src[] = { img, NULL, NULL }; int stride[] = { vo_screenwidth * 3 , 0, 0 }; int cc = vo_config_count; memset(img,255,vo_screenwidth*vo_screenheight*3); vo_config_count = sub_config_count; if(sub_vo->config(vo_screenwidth,vo_screenheight,vo_screenwidth,vo_screenheight, VOFLAG_FULLSCREEN ,"DXR2 sub vo",IMGFMT_BGR24) != 0) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No overlay\n"); sub_vo->uninit(); sub_vo = NULL; use_ol = 0; vo_config_count = cc; return 0; } sub_vo->draw_slice(src,stride,vo_screenwidth,vo_screenheight,0,0); sub_vo->flip_page(); free(img); sub_config_count++; vo_config_count = cc; om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om); vga->xScreen = vo_screenwidth; vga->yScreen = vo_screenheight; vga->hOffWinKey = 100; vga->vOffWinKey = 3; ioctl(dxr2_fd, DXR2_IOC_CALCULATE_VGA_PARAMETERS, vga); } ioctl(dxr2_fd, DXR2_IOC_SET_VGA_PARAMETERS,vga); return 1; } static int dxr2_save_vga_params(dxr2_vgaParams_t* vga,char* name) { struct stat s; char* p = get_path("dxr2_cache"); int p_len = strlen(p), name_len = strlen(name); char cache_path[p_len + name_len + 2]; int ret; FILE* fd; if(stat(p,&s) !=0) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] No vga cache dir found (%s)\n",strerror(errno)); if(errno == EACCES) { free(p); return 0; } // Try to create the dir if(mkdir(p,S_IRWXU) != 0) { mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to create vga cache dir %s (%s)\n",p,strerror(errno)); free(p); return 0; } } sprintf(cache_path,"%s/%s",p,name); free(p); fd = fopen(cache_path,"w"); if(fd == NULL) { mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to open cache file %s for writing (%s)\n",cache_path,strerror(errno)); return 0; } ret = fprintf(fd,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", vga->hOffWinKey, vga->vOffWinKey, vga->xScreen, vga->yScreen, vga->hsyncPol, vga->vsyncPol, vga->blankStart, vga->blankWidth, vga->hOffset, vga->vOffset, vga->ratio, olx_cor, oly_cor, olw_cor, olh_cor); fclose(fd); return ret >= 11 ? 1 : 0; } static int dxr2_load_vga_params(dxr2_vgaParams_t* vga,char* name) { char* p = get_path("dxr2_cache"); int p_len = strlen(p), name_len = strlen(name); char cache_path[p_len + name_len + 2]; int ret; int xc,yc,wc,hc; FILE* fd; sprintf(cache_path,"%s/%s",p,name); free(p); fd = fopen(cache_path,"r"); if(fd == NULL) { mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to open cache file %s for reading (%s)\n",cache_path,strerror(errno)); return 0; } ret = fscanf(fd, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", &vga->hOffWinKey, &vga->vOffWinKey, &vga->xScreen, &vga->yScreen, &vga->hsyncPol, &vga->vsyncPol, &vga->blankStart, &vga->blankWidth, &vga->hOffset, &vga->vOffset, &vga->ratio, &xc, &yc, &wc, &hc); fclose(fd); if(ret > 11 && !olx_cor) olx_cor = xc; if(ret > 12 && !oly_cor) oly_cor = yc; if(ret > 13 && !olw_cor) olw_cor = wc; if(ret > 14 && !olh_cor) olh_cor = hc; return ret >= 11 ? 1 : 0; } static int dxr2_setup_vga_params(void) { const vo_info_t* vi = sub_vo->info; dxr2_vgaParams_t vga; int loaded = dxr2_load_vga_params(&vga,(char*)vi->short_name); if(!dxr2_set_vga_params(&vga,(update_cache || ignore_cache) ? 1 : !loaded )) return 0; if(!loaded || update_cache) dxr2_save_vga_params(&vga,(char*)vi->short_name); return 1; } static void dxr2_set_overlay_window(void) { uint8_t* src[] = { sub_img, NULL, NULL }; int stride[] = { movie_w * 3 , 0, 0 }; dxr2_twoArg_t win; int redisp = 0; int cc = vo_config_count; vo_config_count = sub_config_count; sub_vo->draw_slice(src,stride,movie_w,movie_h,0,0); sub_vo->flip_page(); vo_config_count = cc; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] setting overlay with correction x=%d y=%d w=%d h=%d\n",olx_cor,oly_cor, olw_cor,olh_cor); // Sub vo isn't a windowed one, fill in the needed stuff if(!sub_vo_win) { if(vo_fs) { vo_dwidth = vo_screenwidth; vo_dheight = vo_screenheight; vo_dx = vo_dy = 0; } else { vo_dwidth = movie_w; vo_dheight = movie_h; vo_dx = (vo_screenwidth - vo_dwidth) / 2; vo_dy = (vo_screenheight - vo_dheight) / 2; } } if(sub_w != vo_dwidth || sub_h != vo_dheight) { int new_aspect = ((1<<16)*vo_dwidth + vo_dheight/2)/vo_dheight; sub_w = vo_dwidth; sub_h = vo_dheight; if(new_aspect > aspect) sub_w = (sub_h*aspect + (1<<15))>>16; else sub_h = ((sub_w<<16) + (aspect>>1)) /aspect; sub_w += olw_cor; sub_h += olh_cor; sub_x_off = (vo_dwidth-sub_w) / 2; sub_y_off = (vo_dheight-sub_h) / 2; sub_x = -vo_dx; // Be sure to also replace the overlay win.arg1 = sub_w; win.arg2 = sub_h; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] set win size w=%d h=%d and offset x=%d y=%d \n",win.arg1,win.arg2,sub_x_off,sub_y_off); ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win); } if(vo_dx != sub_x || vo_dy != sub_y) { sub_x = vo_dx + olx_cor + sub_x_off; sub_y = vo_dy + oly_cor + sub_y_off; win.arg1 = (sub_x > 0 ? sub_x : 0); win.arg2 = (sub_y > 0 ? sub_y : 0); mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] set pos x=%d y=%d \n",win.arg1,win.arg2); ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); } } static int config(uint32_t s_width, uint32_t s_height, uint32_t width, uint32_t height, uint32_t flags, char *title, uint32_t format) { int arg; dxr2_threeArg_t arg3; if(dxr2_fd < 0) { mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n"); return VO_ERROR; } if(playing) { dxr2_send_eof(); flush_dxr2(); ioctl(dxr2_fd, DXR2_IOC_STOP, NULL); playing = 0; } last_freq_id = -1; // Video stream setup arg3.arg1 = DXR2_STREAM_VIDEO; arg3.arg2 = 0; ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3); if (vo_fps > 28) arg3.arg1 = DXR2_SRC_VIDEO_FREQ_30; else arg3.arg1 = DXR2_SRC_VIDEO_FREQ_25; arg3.arg2 = s_width; arg3.arg3 = s_height; ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_VIDEO_FORMAT, &arg3); arg = DXR2_BITSTREAM_TYPE_MPEG_VOB; ioctl(dxr2_fd, DXR2_IOC_SET_BITSTREAM_TYPE, &arg); // Aspect ratio if (1.76 <= movie_aspect && movie_aspect <= 1.80) { arg = DXR2_ASPECTRATIO_16_9; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 16:9\n"); } else { arg = DXR2_ASPECTRATIO_4_3; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 4:3\n"); } ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_ASPECT_RATIO, &arg); if (1.76 <= monitor_aspect && monitor_aspect <=1.80) { arg = DXR2_ASPECTRATIO_16_9; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 16:9\n"); } else { arg = DXR2_ASPECTRATIO_4_3; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 4:3\n"); } ioctl(dxr2_fd, DXR2_IOC_SET_OUTPUT_ASPECT_RATIO, &arg); arg = ar_mode; ioctl(dxr2_fd, DXR2_IOC_SET_ASPECT_RATIO_MODE, &arg); // TV setup arg = mv_mode; ioctl(dxr2_fd, DXR2_IOC_SET_TV_MACROVISION_MODE, &arg); arg = _75ire_mode; ioctl(dxr2_fd, DXR2_IOC_SET_TV_75IRE_MODE, &arg); arg = bw_mode; ioctl(dxr2_fd, DXR2_IOC_SET_TV_BLACKWHITE_MODE, &arg); arg = interlaced_mode; ioctl(dxr2_fd, DXR2_IOC_SET_TV_INTERLACED_MODE, &arg); arg = pixel_mode; ioctl(dxr2_fd, DXR2_IOC_SET_TV_PIXEL_MODE, &arg); if (norm) { if (strcmp(norm, "ntsc")==0) arg = DXR2_OUTPUTFORMAT_NTSC; else if (strcmp(norm, "pal")==0) { if (vo_fps > 28) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal, but we play at 30 fps, selecting pal60 instead\n"); arg = DXR2_OUTPUTFORMAT_PAL_60; norm="pal60"; } else arg = DXR2_OUTPUTFORMAT_PAL_BDGHI; } else if (strcmp(norm, "pal60")==0) { if (vo_fps > 28) arg = DXR2_OUTPUTFORMAT_PAL_60; else { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal60, but we play at 25 fps, selecting pal instead\n"); arg = DXR2_OUTPUTFORMAT_PAL_BDGHI; norm="pal"; } } else if (strcmp(norm, "palm")==0) arg = DXR2_OUTPUTFORMAT_PAL_M; else if (strcmp(norm, "paln")==0) arg = DXR2_OUTPUTFORMAT_PAL_N; else if (strcmp(norm, "palnc")==0) arg = DXR2_OUTPUTFORMAT_PAL_Nc; else { mp_msg(MSGT_VO,MSGL_WARN,"[dxr2] invalid norm %s\n", norm); mp_msg(MSGT_VO,MSGL_WARN,"Valid values are ntsc,pal,pal60,palm,paln,palnc\n"); mp_msg(MSGT_VO,MSGL_WARN,"Using ntsc\n"); norm="ntsc"; } } else { if (vo_fps > 28) { arg = DXR2_OUTPUTFORMAT_NTSC; norm="ntsc"; } else { arg = DXR2_OUTPUTFORMAT_PAL_BDGHI; norm="pal"; } } mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] output norm set to %s\n", norm); ioctl(dxr2_fd, DXR2_IOC_SET_TV_OUTPUT_FORMAT, &arg); // Subtitles arg = DXR2_SUBPICTURE_ON; ioctl(dxr2_fd,DXR2_IOC_ENABLE_SUBPICTURE,&arg); arg3.arg1 = DXR2_STREAM_SUBPICTURE; arg3.arg2 = 0; ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3); // Audio arg = iec958_mode; ioctl(dxr2_fd, DXR2_IOC_IEC958_OUTPUT_MODE, &arg); arg = DXR2_AUDIO_WIDTH_16; ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_DATA_WIDTH, &arg); arg = DXR2_AUDIO_FREQ_48; ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY, &arg); arg3.arg1 = DXR2_STREAM_AUDIO_LPCM; arg3.arg2 = 0; ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3); arg = 19; ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_VOLUME, &arg); arg = mute_mode; ioctl(dxr2_fd, DXR2_IOC_AUDIO_MUTE, &arg); movie_w = width; movie_h = height; //vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0; // Overlay while(use_ol) { dxr2_twoArg_t win; dxr2_oneArg_t om; int cc = vo_config_count; vo_config_count = sub_config_count; // Load or detect the overlay stuff if(!dxr2_setup_vga_params()) { sub_vo->uninit(); sub_vo = NULL; vo_config_count = cc; break; } // Does the sub vo support the x11 stuff // Fix me : test the other x11 vo's and enable them if(strcmp(sub_vo->info->short_name,"x11") == 0) sub_vo_win = 1; else sub_vo_win = 0; // No window and no osd => we don't need any subdriver if(!sub_vo_win && !ol_osd) { sub_vo->uninit(); sub_vo = NULL; } while(sub_vo) { dxr2_sixArg_t oc; int i,sub_flags = VOFLAG_SWSCALE | (flags & VOFLAG_FULLSCREEN); if(sub_vo->config(width,height,width,height,sub_flags, "MPlayer DXR2 render",IMGFMT_BGR24) != 0) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No X11 window\n"); sub_vo->uninit(); sub_vo = NULL; break; } sub_config_count++; // Feel free to try some other other color and report your results oc.arg1 = ck_rmin; oc.arg2 = ck_rmax; oc.arg3 = ck_gmin; oc.arg4 = ck_gmax; oc.arg5 = ck_bmin; oc.arg6 = ck_bmax; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc); om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om); sub_img = malloc(width*height*3); for(i = 0 ; i < width*height*3 ; i += 3) { sub_img[i] = ck_b; sub_img[i+1] = ck_g; sub_img[i+2] = ck_r; } aspect = ((1<<16)*width + height/2)/height; sub_w = sub_h = 0; dxr2_set_overlay_window(); break; } vo_config_count = cc; if(!sub_vo) { // Fallback on non windowed overlay vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0; om.arg = DXR2_OVERLAY_WINDOW_KEY; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om); win.arg1 = flags & VOFLAG_FULLSCREEN ? vo_screenwidth : width; win.arg2 = flags & VOFLAG_FULLSCREEN ? vo_screenheight : height; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win); win.arg1 = (vo_screenwidth - win.arg1) / 2; win.arg2 = (vo_screenheight - win.arg2) / 2; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); } break; } if (vo_ontop) vo_x11_setlayer(mDisplay, vo_window, vo_ontop); // start playing if(ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL) == 0) { playing = 1; return 0; } else return VO_ERROR; } static void clear_alpha(int x0,int y0, int w,int h) { uint8_t* src[] = { sub_img , NULL, NULL }; int stride[] = { movie_w * 3, 0, 0 }; sub_vo->draw_slice(src,stride,w,h,x0,y0); } static void draw_osd(void) { if(sub_vo && ol_osd) { vo_remove_text(movie_w,movie_h,clear_alpha); sub_vo->draw_osd(); } } static int draw_frame(uint8_t * src[]) { vo_mpegpes_t *p=(vo_mpegpes_t *)src[0]; if(p->id == 0x1E0) {// Video dxr2_send_packet(p->data, p->size, p->id, p->timestamp); } else if(p->id == 0x20) // Subtitles dxr2_send_sub_packet(p->data, p->size, p->id, p->timestamp); return 0; } static void flip_page (void) { if(sub_vo && ol_osd && vo_osd_changed_flag) sub_vo->flip_page(); } static int draw_slice( uint8_t *srcimg[], int stride[], int w, int h, int x0, int y0 ) { return 0; } static int query_format(uint32_t format) { if (format==IMGFMT_MPEGPES) return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_TIMER|VFCAP_SPU; return 0; } static void uninit(void) { mp_msg(MSGT_VO,MSGL_DBG2, "VO: [dxr2] Uninitializing\n" ); if (dxr2_fd > 0) { if(playing) { dxr2_send_eof(); flush_dxr2(); playing = 0; } close(dxr2_fd); dxr2_fd = -1; } if(sub_img) { free(sub_img); sub_img = NULL; } if(sub_vo) { int cc = vo_config_count; vo_config_count = sub_config_count; sub_vo->uninit(); sub_vo = NULL; vo_config_count = cc; } } static void check_events(void) { // I'd like to have this done in an x11 independent way // It's because of this that we are limited to vo_x11 for windowed overlay :-( #ifdef X11_FULLSCREEN if(sub_vo && sub_vo_win) { int e=vo_x11_check_events(mDisplay); if ( !(e&VO_EVENT_RESIZE) && !(e&VO_EVENT_EXPOSE) ) return; XSetBackground(mDisplay, vo_gc, 0); XClearWindow(mDisplay, vo_window); dxr2_set_overlay_window(); } #endif } static int preinit(const char *arg) { int uCodeFD = -1; int uCodeSize; dxr2_uCode_t* uCode; dxr2_fourArg_t crop; int n=0; sub_vo = NULL; sub_config_count = 0; if(use_ol) { if (arg) { for(n = 0 ; video_out_drivers[n] != NULL ; n++) { const vo_info_t* vi = video_out_drivers[n]->info; if(!vi) continue; if(strcasecmp(arg,vi->short_name) == 0) break; } sub_vo = video_out_drivers[n]; } else { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] We need a sub driver to initialize the overlay\n"); use_ol = 0; } } if(!sub_vo) { if(use_ol) mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub driver '%s' not found => no overlay\n",arg); use_ol = 0; } else { if(sub_vo->preinit(NULL) != 0) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s preinit failed => no overlay\n",arg); sub_vo = NULL; use_ol = 0; } else { uint32_t fmt = IMGFMT_BGR24; mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Sub vo %s inited\n",arg); if(sub_vo->control(VOCTRL_QUERY_FORMAT,&fmt) <= 0) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s doesn't support BGR24 => no overlay\n",arg); sub_vo->uninit(); sub_vo = NULL; use_ol = 0; } } } dxr2_fd = open( "/dev/dxr2", O_WRONLY); if( dxr2_fd < 0 ) { mp_msg(MSGT_VO,MSGL_V, "VO: [dxr2] Error opening /dev/dxr2 for writing!\n" ); return VO_ERROR; } if(ucode) uCodeFD = open(ucode, O_RDONLY); else for (n=0; ucodesearchpath[n] != NULL; n++) { mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Looking for microcode in %s... ", ucodesearchpath[n]); if ((uCodeFD = open(ucodesearchpath[n], O_RDONLY))>0) { mp_msg(MSGT_VO,MSGL_V,"ok\n"); break; } else { mp_msg(MSGT_VO,MSGL_V,"failed (%s)\n", strerror(errno)); } } if (uCodeFD < 0) { mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not open microcode\n"); return VO_ERROR; } uCodeSize = lseek(uCodeFD, 0, SEEK_END); if ((uCode = malloc(uCodeSize + 4)) == NULL) { mp_msg(MSGT_VO,MSGL_FATAL,"VO: [dxr2] Could not allocate memory for uCode: %s\n", strerror(errno)); return VO_ERROR; } lseek(uCodeFD, 0, SEEK_SET); if (read(uCodeFD, uCode+4, uCodeSize) != uCodeSize) { mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not read uCode uCode: %s\n", strerror(errno)); return VO_ERROR; } close(uCodeFD); uCode->uCodeLength = uCodeSize; // upload ucode ioctl(dxr2_fd, DXR2_IOC_INIT_ZIVADS, uCode); // reset card ioctl(dxr2_fd, DXR2_IOC_RESET, NULL); playing = 0; if(!use_ol) { crop.arg1=0; crop.arg2=0; crop.arg3=0; crop.arg4=0; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop); } return 0; } static int control(uint32_t request, void *data, ...) { switch (request) { case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t*)data)); case VOCTRL_PAUSE: ioctl(dxr2_fd,DXR2_IOC_PAUSE, NULL); return VO_TRUE; case VOCTRL_RESUME: ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL); return VO_TRUE; case VOCTRL_RESET: flush_dxr2(); ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL); return VO_TRUE; case VOCTRL_ONTOP: vo_x11_ontop(); return VO_TRUE; case VOCTRL_FULLSCREEN: if(!use_ol) return VO_NOTIMPL; else if(sub_vo) { int r = sub_vo->control(VOCTRL_FULLSCREEN,0); if(r == VO_TRUE && !sub_vo_win) dxr2_set_overlay_window(); return r; } else { dxr2_twoArg_t win; vo_fs = !vo_fs; win.arg1 = vo_fs ? vo_screenwidth : movie_w; win.arg2 = vo_fs ? vo_screenheight : movie_h; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win); win.arg1 = (vo_screenwidth - win.arg1) / 2; win.arg2 = (vo_screenheight - win.arg2) / 2; ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); return VO_TRUE; } case VOCTRL_SET_SPU_PALETTE: { if(ioctl(dxr2_fd,DXR2_IOC_SET_SUBPICTURE_PALETTE,data) < 0) { mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] SPU palette loading failed\n"); return VO_ERROR; } return VO_TRUE; } } return VO_NOTIMPL; }