// How many MegaBytes of RAM is on your G200/G400 card? #define RAM_SIZE 16 /* * video_out_syncfb.c * * Copyright (C) Aaron Holtzman - Aug 1999 * * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. * * mpeg2dec is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * mpeg2dec is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include "config.h" #include "video_out.h" #include "video_out_internal.h" LIBVO_EXTERN(syncfb) #include #include #include #include #include #include "drivers/syncfb/syncfb.h" static vo_info_t vo_info = { "Matrox G200/G400 Synchronous framebuffer (/dev/syncfb)", "syncfb", "Matthias Oelmann ", "" }; /* deinterlacing on? looks only good in 50 Hz(PAL) or 60 Hz(NTSC) modes */ static int vo_conf_deinterlace = 0; /* 72/75 Hz Monitor frequency for progressive output */ static int vo_conf_cinemode = 0; static syncfb_config_t config; static syncfb_capability_t sfb_caps; static syncfb_buffer_info_t bufinfo; static uint_8 *vid_data; static uint_8 *frame_mem; static int debug_skip_first = 250; static int dbg_singleframe = 0; static int conf_palette; static int f; /* it seems that mpeg2dec never calls draw_frame, so i could not test it.... */ static void write_frame_YUV422(uint_8 *y,uint_8 *cr, uint_8 *cb) { uint_8 *crp, *cbp; uint_32 *dest32; uint_32 bespitch,h,w; bespitch = config.src_pitch; dest32 = (uint_32 *)vid_data; for(h=0; h < config.src_height/2; h++) { cbp = cb; crp = cr; for(w=0; w < config.src_width/2; w++) { *dest32++ = (*y) + ((*cr)<<8) + ((*(y+1))<<16) + ((*cb)<<24); y++; y++; cb++; cr++; } dest32 += (bespitch - config.src_width) / 2; for(w=0; w < config.src_width/2; w++) { *dest32++ = (*y) + ((*crp)<<8) + ((*(y+1))<<16) + ((*cbp)<<24); y++; y++; cbp++; crp++; } dest32 += (bespitch - config.src_width) / 2; } } static void write_frame_YUV420P2(uint_8 *y,uint_8 *cr, uint_8 *cb) { uint_8 *dest, *tmp; uint_32 bespitch,h,w; bespitch = config.src_pitch; dest = frame_mem + bufinfo.offset; for(h=0; h < config.src_height; h++) { memcpy(dest, y, config.src_width); y += config.src_width; dest += bespitch; } dest = frame_mem + bufinfo.offset_p2; for(h=0; h < config.src_height/2; h++) { tmp = dest; for(w=0; w < config.src_width/2; w++) { *tmp++ = *cr++; *tmp++ = *cb++; } dest += bespitch; } } static void write_frame_YUV420P3(uint_8 *y,uint_8 *cr, uint_8 *cb) { } static void write_slice_YUV420P2(uint_8 *y,uint_8 *cr, uint_8 *cb,uint_32 slice_num) { uint_8 *dest, *tmp; uint_32 bespitch,h,w; bespitch = config.src_pitch; dest = frame_mem + bufinfo.offset + (bespitch * 16 * slice_num); for(h=0; h < 16; h++) { memcpy(dest, y, config.src_width); y += config.src_width; dest += bespitch; } dest = frame_mem + bufinfo.offset_p2 + (bespitch * 16 * slice_num) /2; for(h=0; h < 8; h++) { tmp = dest; for(w=0; w < config.src_width/2; w++) { *tmp++ = *cr++; *tmp++ = *cb++; } dest += bespitch; } } static void write_slice_YUV420P3(uint_8 *y,uint_8 *cr, uint_8 *cb,int stride[],uint_32 ypos,uint_32 xsize,uint_32 ysize) { uint_8 *dest; uint_32 bespitch,h; bespitch = config.src_pitch; dest = frame_mem + bufinfo.offset + (bespitch * ypos); for(h=0; h < ysize; h++) { memcpy(dest, y, xsize); y += stride[0]; dest += bespitch; } xsize/=2; ysize/=2; dest = frame_mem + bufinfo.offset_p2 + (bespitch * ypos)/4; for(h=0; h < ysize; h++) { memcpy(dest, cr, xsize); cr += stride[1]; dest += bespitch/2; } dest = frame_mem + bufinfo.offset_p3 + (bespitch * ypos)/4; for(h=0; h < ysize; h++) { memcpy(dest, cb, xsize); cb += stride[2]; dest += bespitch/2; } } static void write_slice_YUV422(uint_8 *y,uint_8 *cr, uint_8 *cb,uint_32 slice_num) { uint_8 *crp, *cbp; uint_32 *dest32; uint_32 bespitch,h,w; bespitch = config.src_pitch; dest32 = (uint_32 *)(vid_data + (bespitch * 16 * slice_num) * 2); for(h=0; h < 8; h++) { cbp = cb; crp = cr; for(w=0; w < config.src_width/2; w++) { *dest32++ = (*y) + ((*cr)<<8) + ((*(y+1))<<16) + ((*cb)<<24); y++; y++; cb++; cr++; } dest32 += (bespitch - config.src_width) / 2; for(w=0; w < config.src_width/2; w++) { *dest32++ = (*y) + ((*crp)<<8) + ((*(y+1))<<16) + ((*cbp)<<24); y++; y++; cbp++; crp++; } dest32 += (bespitch - config.src_width) / 2; } } //static uint32_t draw_slice(uint8_t *src[], uint32_t slice_num) static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) { if ( vid_data == NULL ) return 0; write_slice_YUV420P3(src[0],src[1], src[2],stride,y,w,h); //printf("sorry, not syncfb/draw_slice() implemented yet...\n"); #if 0 if ( conf_palette == VIDEO_PALETTE_YUV422 ) { write_slice_YUV422(src[0],src[1], src[2],slice_num); } else if ( conf_palette == VIDEO_PALETTE_YUV420P2 ) { write_slice_YUV420P2(src[0],src[1], src[2],slice_num); } else if ( conf_palette == VIDEO_PALETTE_YUV420P3 ) { write_slice_YUV420P3(src[0],src[1], src[2],slice_num); } #endif return 0; } static void flip_page(void) { // memset(frame_mem + bufinfo.offset_p2, 0x80, config.src_width*config.src_height); ioctl(f,SYNCFB_COMMIT_BUFFER,&bufinfo); if ( dbg_singleframe ) { if ( debug_skip_first == 0 ) { printf( "Press 'anykey' for field 1\n" ); getchar(); ioctl(f,SYNCFB_VBI,0); } if ( debug_skip_first > 0 ) { debug_skip_first--; // debug_skip_first = 0; if ( debug_skip_first == 0 ) { ioctl(f,SYNCFB_VBI,0); ioctl(f,SYNCFB_VBI,0); ioctl(f,SYNCFB_VBI,0); } } if ( debug_skip_first == 0 ) { printf( "Press 'anykey' for field 2\n" ); getchar(); ioctl(f,SYNCFB_VBI,0); } } ioctl(f,SYNCFB_REQUEST_BUFFER,&bufinfo); if ( bufinfo.id == -1 ) printf( "Got buffer #%d\n", bufinfo.id ); vid_data = (uint_8 *)(frame_mem + bufinfo.offset); if ( bufinfo.id == -1 ) { //vid_data = frame_mem; vid_data = NULL; } // printf("Flip %d\n", bufinfo.offset); } static uint32_t draw_frame(uint8_t *src[]) { printf("DRAW FRAME!!!\n"); if ( conf_palette == VIDEO_PALETTE_YUV422 ) { write_frame_YUV422(src[0],src[1], src[2]); } else if ( conf_palette == VIDEO_PALETTE_YUV420P2 ) { write_frame_YUV420P2(src[0],src[1], src[2]); } else if ( conf_palette == VIDEO_PALETTE_YUV420P3 ) { write_frame_YUV420P3(src[0],src[1], src[2]); } flip_page(); return 0; } static uint32_t query_format(uint32_t format) { switch(format){ case IMGFMT_YV12: // case IMGFMT_RGB|24: // case IMGFMT_BGR|24: return 1; } return 0; } static uint32_t init(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format) { uint_32 frame_size; f = open("/dev/syncfb",O_RDWR); if(f == -1) { f = open("/dev/mga_vid",O_RDWR); if(f == -1) { fprintf(stderr,"Couldn't open /dev/syncfb or /dev/mga_vid\n"); return(-1); } } if (ioctl(f,SYNCFB_GET_CAPS,&sfb_caps)) perror("Error in mga_vid_config ioctl"); if (ioctl(f,SYNCFB_GET_CONFIG,&config)) perror("Error in mga_vid_config ioctl"); if (sfb_caps.palettes & (1<