diff -Naur -x CVS -x .* main/DOCS/DXR3 main-dxr3/DOCS/DXR3 --- main/DOCS/DXR3 Sat Nov 3 03:43:37 2001 +++ main-dxr3/DOCS/DXR3 Tue Nov 6 23:22:40 2001 @@ -36,7 +36,9 @@ * First of all you will need the DXR3/H+ drivers properly installed, including the dev-api. - These can be downloaded from dxr3.sourceforge.net + These can be downloaded from dxr3.sourceforge.net (I suggest using + the CVS version since most of the time I use the latest features + which are only available through cvs) * /libavcodec from ffmpeg (only required if you intend to play formats other than mpeg-(1/2), highly recommended!) there are @@ -57,13 +59,15 @@ problems. - + 3. Usage After installation you will have two new outdevices in mplayer: -vo dxr3 For video output - -ao dxr3 For audio output + -ao dxr3 For audio output (due to an unresolved bug + this is not recommended/useful!) +MPEG-1, MPEG-2, VCD and DVD Notes There are some notes to take into account here for optimum playback. When playing any mpeg-(1/2) file, this including usage of the "-dvd" and "-vcd" options you must either add the "-vc mpegpes" or edit @@ -72,38 +76,34 @@ spoils most of the useful features of this card except for tv-out ;). Remember that if you edit the codecs.conf file and move the mpegpes section will have to specify "-vc mpeg12" if you want to playback -any of these video types without "-vo dxr3"! +any of these video types _without_ "-vo dxr3"! +DIVX Notes +When playing divx's add "-vc odivx", if you get any other divx codec +to run faster tell me which one because I'll be interested in how it +could possibly be any faster than OpenDivX4Linux... + +Unsupported Codecs: If you ever get a codec unsupported message, lookup the codec in the codecs.conf file (search for "videocodec "), copy the entire codec section and send it to me and I'll make sure it works with the next patch (or the next after that if I have a thousand things to take care of first ;) my e-mail is at the bottom of this page. - - 4. Todo - * Make the osd use the subpic feature of the dxr3 (High) - * Overlay output (Medium) - * Driver options (Medium) - * Add an onscreen menu for "live" performance tuning (Low) - -(yuv2rgb (24bpp) asm optimizations, not my job though... but - this will improve playback of anything not mpeg-(1/2) for us - all) + * Scale video played using windows codecs (High) + * Make the osd use the subpic feature of the dxr3 (almost done)(High) + * Driver options (probably not until libvo2) (Medium) 5. Contacting me -You can contact me either by e-mailing me, dholm@iname.com or by using +You can contact me either by e-mailing me, or by using icq: 798427 -Feedback, bugreports and general suggestions are appreciated -(preferably by e-mail) -My name is David Holm for those of you who are incapable of reading -a heading. ;) - - +Feedback, bugreports and general suggestions are appreciated (preferably +by e-mail). My name is David Holm for those of you who are incapable of +reading a heading. ;) diff -Naur -x CVS -x .* main/libao2/ao_dxr3.c main-dxr3/libao2/ao_dxr3.c --- main/libao2/ao_dxr3.c Sat Nov 3 03:37:53 2001 +++ main-dxr3/libao2/ao_dxr3.c Tue Nov 6 23:22:40 2001 @@ -1,10 +1,12 @@ #include #include -#include + +#include #include +#include #include -#include - +#include +#include #include #include "../config.h" @@ -14,12 +16,7 @@ #include "audio_out.h" #include "audio_out_internal.h" -struct -{ - int ao_format; - int ao_rate; - int ao_channels; -} ao_device; +extern int verbose; static ao_info_t info = { @@ -39,86 +36,129 @@ // ao_outburst // ao_buffersize +static char *em8300_ma="/dev/em8300_ma"; +static audio_buf_info dxr3_buf_info; + // to set/get/query special features/parameters static int control(int cmd,int arg) { switch(cmd) { - case AOCONTROL_SET_DEVICE: - return CONTROL_OK; case AOCONTROL_QUERY_FORMAT: return CONTROL_TRUE; case AOCONTROL_GET_VOLUME: case AOCONTROL_SET_VOLUME: - { - return CONTROL_OK; - } + return CONTROL_OK; + return CONTROL_ERROR; } - return CONTROL_TRUE; + return CONTROL_UNKNOWN; } // open & setup audio device // return: 1=success 0=fail static int init(int rate,int channels,int format,int flags) { - ao_device.ao_format = format; - ao_device.ao_rate = rate; - ao_device.ao_channels = channels; - - if( dxr3_get_status() == DXR3_STATUS_CLOSED ) + if( dxr3_get_status() == DXR3_STATUS_CLOSED ) + if( dxr3_open( "/dev/em8300" ) < 0 ) { - if( dxr3_open( "/dev/em8300", "/etc/dxr3.ux" ) != 0 ) printf( "Error loading /dev/em8300 with /etc/dxr3.ux microcode\n" ); - printf( "DXR3 status: &s\n", dxr3_get_status() ? "opened":"closed" ); + printf( "Failed to initialize the DXR3\n" ); + return 0; } - else - printf( "DXR3 already open\n" ); - - if( dxr3_set_playmode( DXR3_PLAYMODE_PLAY ) != 0 ) printf( "Error setting playmode of DXR3\n" ); - - if( format == AFMT_AC3 ) - { - if( dxr3_audio_set_mode( DXR3_AUDIOMODE_DIGITALAC3 ) != 0 ) - { - printf( "Cannot set DXR3 to AC3 playback!\n" ); - return -1; - } + + if( dxr3_audio_get_filedescriptor( ) < 0 ) + { + printf("Can't open audio device %s -> nosound\n",em8300_ma); + return 0; + } + + ao_format = format; + ioctl (dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_SETFMT, &ao_format); + if(format == AFMT_AC3 && ao_format != AFMT_AC3) + { + printf("Can't set audio device %s to AC3 output\n", em8300_ma); + return 0; + } + printf("audio_setup: sample format: %s (requested: %s)\n", + audio_out_format_name(ao_format), audio_out_format_name(format)); + + if(format != AFMT_AC3) + { + ao_channels=channels-1; + ioctl (dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_STEREO, &ao_channels); + + // set rate + ao_samplerate=rate; + ioctl (dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_SPEED, &ao_samplerate); + printf("audio_setup: using %d Hz samplerate (requested: %d)\n",ao_samplerate,rate); + } + + if(ioctl(dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_GETOSPACE, &dxr3_buf_info)==-1){ + int r=0; + printf("audio_setup: driver doesn't support SNDCTL_DSP_GETOSPACE :-(\n"); + if(ioctl(dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_GETBLKSIZE, &r)==-1){ + printf("audio_setup: %d bytes/frag (config.h)\n",ao_outburst); + } else { + ao_outburst=r; + printf("audio_setup: %d bytes/frag (GETBLKSIZE)\n",ao_outburst); + } + } else { + printf("audio_setup: frags: %3d/%d (%d bytes/frag) free: %6d\n", + dxr3_buf_info.fragments, dxr3_buf_info.fragstotal, dxr3_buf_info.fragsize, dxr3_buf_info.bytes); + if(ao_buffersize==-1) ao_buffersize=dxr3_buf_info.bytes; + ao_outburst=dxr3_buf_info.fragsize; + } + + if(ao_buffersize==-1){ + // Measuring buffer size: + void* data; + ao_buffersize=0; +#ifdef HAVE_AUDIO_SELECT + data=malloc(ao_outburst); memset(data,0,ao_outburst); + while(ao_buffersize<0x40000){ + fd_set rfds; + struct timeval tv; + FD_ZERO(&rfds); FD_SET(dxr3_audio_get_filedescriptor( ),&rfds); + tv.tv_sec=0; tv.tv_usec = 0; + if(!select(dxr3_audio_get_filedescriptor( )+1, NULL, &rfds, NULL, &tv)) break; + write(dxr3_audio_get_filedescriptor( ),data,ao_outburst); + ao_buffersize+=ao_outburst; } - else - { - if( dxr3_audio_set_mode( DXR3_AUDIOMODE_ANALOG ) != 0 ) - { - printf( "Cannot set DXR3 to analog playback!\n" ); - return -1; - } - if( format == AFMT_U8 ) - dxr3_audio_set_samplesize( 8 ); - else if( format == AFMT_S16_LE ) - dxr3_audio_set_samplesize( 16 ); - else - { - printf( "Unsupported audio format\n" ); - return -1; - } - } - - dxr3_audio_set_stereo( (channels > 1) ? "true":"false" ); - dxr3_audio_set_rate( rate ); + free(data); + if(ao_buffersize==0){ + printf("\n *** Your audio driver DOES NOT support select() ***\n"); + printf("Recompile mplayer with #undef HAVE_AUDIO_SELECT in config.h !\n\n"); + return 0; + } +#endif + } - return 1; + + return 1; } // close audio device static void uninit() { - dxr3_close(); + ioctl(dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_RESET, NULL); + dxr3_close( ); } // stop playing and empty buffers (for seeking/pause) static void reset() { uninit(); - if( !init( ao_device.ao_rate, ao_device.ao_channels, ao_device.ao_format, 0 ) ) + if(dxr3_audio_get_filedescriptor( )<0) + { printf("\nFatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n"); + return; + } + + ioctl (dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_SETFMT, &ao_format); + if(ao_format != AFMT_AC3) + { + ioctl (dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_STEREO, &ao_channels); + ioctl (dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_SPEED, &ao_samplerate); + } } // stop playing, keep buffers (for pause) @@ -137,7 +177,30 @@ // return: how many bytes can be played without blocking static int get_space() { - return dxr3_audio_get_buffersize()-dxr3_audio_get_bytesleft(); + int playsize=ao_outburst; + +#ifdef SNDCTL_DSP_GETOSPACE + if(ioctl(dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_GETOSPACE, &dxr3_buf_info)!=-1){ + // calculate exact buffer space: + return dxr3_buf_info.fragments*dxr3_buf_info.fragsize; + } +#endif + + // check buffer +#ifdef HAVE_AUDIO_SELECT + { fd_set rfds; + struct timeval tv; + FD_ZERO(&rfds); + FD_SET(dxr3_audio_get_filedescriptor( ), &rfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + if(!select(dxr3_audio_get_filedescriptor( )+1, NULL, &rfds, NULL, &tv)) return 0; // not block! + } +#endif + + return ao_outburst; + +// return (dxr3_audio_get_buffersize()-dxr3_audio_get_bytesinbuffer()); } // plays 'len' bytes of 'data' @@ -145,19 +208,14 @@ // return: number of bytes played static int play(void* data,int len,int flags) { - if(len) - if( ao_device.ao_format == AFMT_AC3 ) - return dxr3_audio_write_ac3( data, len ); - else - return dxr3_audio_write_ac3( data, len ); - - printf( "Invalid audio data\n" ); - return 0; + return write(dxr3_audio_get_filedescriptor( ),data,len); } // return: how many unplayed bytes are in the buffer static int get_delay() { - return dxr3_audio_get_bytesleft(); + int r=0; + if(ioctl(dxr3_audio_get_filedescriptor( ), SNDCTL_DSP_GETODELAY, &r)!=-1) + return r; } diff -Naur -x CVS -x .* main/libvo/vo_dxr3.c main-dxr3/libvo/vo_dxr3.c --- main/libvo/vo_dxr3.c Tue Nov 6 12:21:08 2001 +++ main-dxr3/libvo/vo_dxr3.c Tue Nov 6 23:32:23 2001 @@ -24,7 +24,7 @@ #include "video_out.h" #include "video_out_internal.h" -#include "../postproc/rgb2rgb.h" +#include "../opendivx/yuv2rgb.h" #ifdef HAVE_MMX #include "mmx.h" #endif @@ -46,11 +46,14 @@ static unsigned char *picture_buf=NULL; static unsigned char *outbuf=NULL; -static int outbuf_size = 100000; +static unsigned char *spubuf=NULL; +static int outbuf_size = 0; +static int v_width,v_height; static int s_pos_x,s_pos_y; static int d_pos_x,d_pos_y; static int osd_w,osd_h; -static uint32_t img_format = 0; +static int img_format = 0; +static int palette[] = { 0x0000, 0x4949, 0xb5b5, 0xffff }; static vo_info_t vo_info = { @@ -65,16 +68,23 @@ { if( dxr3_get_status() == DXR3_STATUS_CLOSED ) { - if( dxr3_open( "/dev/em8300", "/etc/dxr3.ux" ) != 0 ) printf( "Error loading /dev/em8300 with /etc/dxr3.ux microcode file\n" ); + if( dxr3_open( "/dev/em8300" ) != 0 ) { printf( "Error opening /dev/em8300\n" ); return -1; } printf( "DXR3 status: %s\n", dxr3_get_status() ? "opened":"closed" ); } - else - printf( "DXR3 already open\n" ); + /* Subpic code isn't working yet, don't set to ON + unless you are really sure what you are doing */ + dxr3_subpic_set_mode( DXR3_SPU_MODE_OFF ); + dxr3_subpic_set_palette( (char*)palette ); + spubuf = malloc(width*height); + if( dxr3_set_playmode( DXR3_PLAYMODE_PLAY ) !=0 ) printf( "Error setting playmode of DXR3\n" ); img_format = format; + v_width = width; + v_height = height; picture_buf=NULL; + if( format == IMGFMT_YV12 ) { #ifdef USE_LIBAVCODEC @@ -98,11 +108,11 @@ memset(&codec_context,0,sizeof(codec_context)); codec_context.bit_rate=100000; // not used - codec_context.frame_rate=25*FRAME_RATE_BASE; // !!!!! - codec_context.gop_size=0; // I frames only + codec_context.frame_rate=25*FRAME_RATE_BASE; + codec_context.gop_size=0; codec_context.flags=CODEC_FLAG_QSCALE; - codec_context.quality=1; // quality! 1..31 (1=best,slowest) - codec_context.pix_fmt = PIX_FMT_RGB24; + codec_context.quality=1; + codec_context.pix_fmt = PIX_FMT_YUV420P; if(width<=352 && height<=288){ codec_context.width=352; codec_context.height=288; @@ -145,11 +155,11 @@ return -1; } - outbuf_size=10000+width*height; // must be enough! + outbuf_size=10000+width*height*4; outbuf = malloc(outbuf_size); size = codec_context.width*codec_context.height; - picture_buf = malloc((size * 3) / 2); /* size for YUV 420 */ + picture_buf = malloc((size * 3)/2); /* size for YUV 420 */ picture.data[0] = picture_buf; picture.data[1] = picture.data[0] + size; @@ -157,10 +167,81 @@ picture.linesize[0] = codec_context.width; picture.linesize[1] = codec_context.width / 2; picture.linesize[2] = codec_context.width / 2; + return 0; #endif return -1; } + else if(format==IMGFMT_BGR24) + { +#ifdef USE_LIBAVCODEC + int size = 0; + printf("Format: BGR24\n"); + + if(!avcodec_inited) + { + avcodec_init(); + avcodec_register_all(); + avcodec_inited=1; + } + + /* find the mpeg1 video encoder */ + codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO); + if (!codec) + { + fprintf(stderr, "mpeg1 codec not found\n"); + return -1; + } + + outbuf_size=10000+width*height*4; + outbuf = malloc(outbuf_size); + + memset(&codec_context,0,sizeof(codec_context)); + codec_context.bit_rate=100000; + codec_context.frame_rate=25*FRAME_RATE_BASE; + codec_context.gop_size=0; + codec_context.flags=CODEC_FLAG_QSCALE; + codec_context.quality=1; + codec_context.pix_fmt = PIX_FMT_YUV420P; + + codec_context.width=width; + codec_context.height=height; + + osd_w=s_width; + d_pos_x=(codec_context.width-(int)s_width)/2; + if(d_pos_x<0){ + s_pos_x=-d_pos_x;d_pos_x=0; + osd_w=codec_context.width; + } else s_pos_x=0; + + osd_h=s_height; + d_pos_y=(codec_context.height-(int)s_height)/2; + if(d_pos_y<0){ + s_pos_y=-d_pos_y;d_pos_y=0; + osd_h=codec_context.height; + } else s_pos_y=0; + + printf("[vo] position mapping: %d;%d => %d;%d\n",s_pos_x,s_pos_y,d_pos_x,d_pos_y); + + /* open it */ + if (avcodec_open(&codec_context, codec) < 0) { + fprintf(stderr, "could not open codec\n"); + return -1; + } + + size = codec_context.width*codec_context.height; + picture_buf = malloc((size * 3)/2); + + picture.data[0] = picture_buf; + picture.data[1] = picture.data[0] + size; + picture.data[2] = picture.data[1] + size / 4; + picture.linesize[0] = codec_context.width; + picture.linesize[1] = codec_context.width / 2; + picture.linesize[2] = codec_context.width / 2; + return 0; +#endif + return -1; + } else if(format==IMGFMT_MPEGPES) { printf( "Format: MPEG-PES\n" ); @@ -177,30 +258,29 @@ return &vo_info; } -#ifdef USE_LIBAVCODEC -static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride) +static void draw_alpha(int x, int y, int w, int h, unsigned char* src, unsigned char *srca, int srcstride) { - int x,y; - if( img_format == IMGFMT_YV12 ) - vo_draw_alpha_yv12(w,h,src,srca,stride,picture.data[0]+(x0+d_pos_x)+(y0+d_pos_y)*picture.linesize[0],picture.linesize[0]); + int i,skip=0,index=0; + unsigned char *dst = spubuf; + for( i = (y*w)+x; i < w*h; i++ ) + { + if(srca[i]) {*dst=skip;skip=0;dst++;*dst=3;dst++;index+=2;} + else skip++; + } + + dxr3_subpic_write(spubuf,index); } -#endif static void draw_osd(void) { - if( img_format == IMGFMT_YV12 ) - { -#ifdef USE_LIBAVCODEC vo_draw_text(osd_w,osd_h,draw_alpha); -#endif - } } static uint32_t draw_frame(uint8_t * src[]) { - int data_left; if( img_format == IMGFMT_MPEGPES ) { + int data_left; vo_mpegpes_t *p=(vo_mpegpes_t *)src[0]; data_left = p->size; @@ -214,24 +294,91 @@ { printf("ERROR: Uninplemented\n"); } + else if( img_format == IMGFMT_BGR24 ) + { + int tmp_size, out_size; + int wrap, wrap3, x, y; + int r, g, b, R, G, B, h = v_height, w = v_width; + unsigned char *s, *Y, *U, *V; + + if(d_pos_x+w>picture.linesize[0]) w=picture.linesize[0]-d_pos_x; + if(d_pos_y+h>codec_context.height) h=codec_context.height-d_pos_y; + + Y = picture.data[0]+d_pos_x+d_pos_y*picture.linesize[0]; + U = picture.data[1]+(d_pos_x/2)+(d_pos_y/2)*picture.linesize[1]; + V = picture.data[2]+(d_pos_x/2)+(d_pos_y/2)*picture.linesize[2]; + + //BGR24->YUV420P from ffmpeg, see ffmpeg.sourceforge.net for terms of license +#define SCALEBITS 8 +#define ONE_HALF (1 << (SCALEBITS - 1)) +#define FIX(x) ((int) ((x) * (1L<> SCALEBITS; + b = s[3]; + g = s[4]; + r = s[5]; + R += r; + G += g; + B += b; + Y[1] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; + s += wrap3; + Y += wrap; + + b = s[0]; + g = s[1]; + r = s[2]; + R += r; + G += g; + B += b; + Y[0] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; + b = s[3]; + g = s[4]; + r = s[5]; + R += r; + G += g; + B += b; + Y[1] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; + U[0] = ((- FIX(0.16874) * R - FIX(0.33126) * G - FIX(0.50000) * B + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128; + V[0] = ((FIX(0.50000) * R - FIX(0.41869) * G - FIX(0.08131) * B + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128; + + U++; + V++; + s -= (wrap3-6); + Y -= (wrap-2); + } + s += wrap3; + Y += wrap; + } +#undef SCALEBITS +#undef ONE_HALF +#undef FIX(x) + //End of ffmpeg code, see ffmpeg.sourceforge.net for terms of license + tmp_size = out_size = avcodec_encode_video(&codec_context, outbuf, outbuf_size, &picture); + while( out_size ) + out_size -= dxr3_video_write( &outbuf[tmp_size-out_size], out_size ); + + return 0; + } #endif - printf( "Error in draw_frame(...)" ); + printf( "Error in draw_frame(...)\n" ); return -1; } static void flip_page (void) { -#ifdef USE_LIBAVCODEC - if( img_format == IMGFMT_YV12 ) - { - int out_size, tmp_size; - /* encode the image */ - tmp_size = out_size = avcodec_encode_video(&codec_context, outbuf, outbuf_size, &picture); - while( out_size ) - out_size -= dxr3_video_write( &outbuf[tmp_size-out_size], out_size ); - } -#endif } static uint32_t draw_slice( uint8_t *srcimg[], int stride[], int w, int h, int x0, int y0 ) @@ -245,6 +392,7 @@ if( img_format == IMGFMT_YV12 ) { #ifdef USE_LIBAVCODEC + int out_size, tmp_size; x0+=d_pos_x; y0+=d_pos_y; if(x0+w>picture.linesize[0]) w=picture.linesize[0]-x0; // !! @@ -281,12 +429,17 @@ s+=stride[2]; d+=picture.linesize[2]; } + + tmp_size = out_size = avcodec_encode_video(&codec_context, outbuf, outbuf_size, &picture); + while( out_size ) + out_size -= dxr3_video_write( &outbuf[tmp_size-out_size], out_size ); - yuv2rgb_init( 24, MODE_RGB ); - yuv2rgb( outbuf, srcimg[0], srcimg[1], srcimg[2], w, h, h*3, stride[0], stride[1] ); return 0; #endif - printf( "You will need libavcodec of ffmpeg.so yo play this video\n" ); + return -1; + } + else if( img_format == IMGFMT_BGR24 ) + { return -1; } else if( img_format == IMGFMT_MPEGPES ) @@ -304,23 +457,23 @@ static uint32_t query_format(uint32_t format) { - if(format==IMGFMT_MPEGPES) return 1; + if(format==IMGFMT_MPEGPES) return 0x2|0x4; #ifdef USE_LIBAVCODEC - if(format==IMGFMT_YV12) return 1; -#endif + if(format==IMGFMT_YV12) return 0x1|0x4; + if(format==IMGFMT_BGR24) return 0x1|0x4; +#else + if(format==IMGFMT_YV12) {printf("You need to compile with libavcodec or ffmpeg.so to play this file!\n" ); return 0;} + if(format==IMGFMT_BGR24) {printf("You need to compile with libavcodec or ffmpeg.so to play this file!\n" ); return 0;} +#endif return 0; } static void uninit(void) { -#ifdef USE_LIBAVCODEC - if( img_format == IMGFMT_YV12 ) - { - free(outbuf); - free(picture_buf); - } -#endif + free(outbuf); + free(picture_buf); + free(spubuf); dxr3_close( ); }