nvidia_vid.c
来自「linux下的MPEG1」· C语言 代码 · 共 977 行 · 第 1/3 页
C
977 行
struct rivatv_info { unsigned int use_colorkey; unsigned int colorkey; /* saved xv colorkey*/ unsigned int vidixcolorkey; /*currently used colorkey*/ unsigned int depth; unsigned int format; unsigned int pitch; unsigned int width,height; unsigned int d_width,d_height; /*scaled width && height*/ unsigned int wx,wy; /*window x && y*/ unsigned int screen_x; /*screen width*/ unsigned int screen_y; /*screen height*/ unsigned long buffer_size; /* size of the image buffer */ struct rivatv_chip chip; /* NV architecture structure */ void* video_base; /* virtual address of control region */ void* control_base; /* virtual address of fb region */ unsigned long picture_base; /* direct pointer to video picture */ unsigned long picture_offset; /* offset of video picture in frame buffer */// struct rivatv_dma dma; /* DMA structure */ unsigned int cur_frame; unsigned int num_frames; /* number of buffers */ int bps; /* bytes per line */};typedef struct rivatv_info rivatv_info;//framebuffer size funcsstatic unsigned long rivatv_fbsize_nv03 (struct rivatv_chip *chip){ if (VID_RD32 (chip->PFB, 0) & 0x00000020) { if (((VID_RD32 (chip->PMC, 0) & 0xF0) == 0x20) && ((VID_RD32 (chip->PMC, 0) & 0x0F) >= 0x02)) { /* SDRAM 128 ZX. */ return ((1 << (VID_RD32 (chip->PFB, 0) & 0x03)) * 1024 * 1024); } else { return 1024 * 1024 * 8; } } else { /* SGRAM 128. */ switch (chip->PFB[0x00000000] & 0x00000003) { case 0: return 1024 * 1024 * 8; break; case 2: return 1024 * 1024 * 4; break; default: return 1024 * 1024 * 2; break; } }}static unsigned long rivatv_fbsize_nv04 (struct rivatv_chip *chip){ if (VID_RD32 (chip->PFB, 0) & 0x00000100) { return ((VID_RD32 (chip->PFB, 0) >> 12) & 0x0F) * 1024 * 1024 * 2 + 1024 * 1024 * 2; } else { switch (VID_RD32 (chip->PFB, 0) & 0x00000003) { case 0: return 1024 * 1024 * 32; break; case 1: return 1024 * 1024 * 4; break; case 2: return 1024 * 1024 * 8; break; case 3: default: return 1024 * 1024 * 16; break; } }}static unsigned long rivatv_fbsize_nv10 (struct rivatv_chip *chip){ return ((VID_RD32 (chip->PFB, 0x20C) >> 20) & 0x000000FF) * 1024 * 1024;}//lock funcsstatic void rivatv_lock_nv03 (struct rivatv_chip *chip, int LockUnlock){ VID_WR08 (chip->PVIO, 0x3C4, 0x06); VID_WR08 (chip->PVIO, 0x3C5, LockUnlock ? 0x99 : 0x57);}static void rivatv_lock_nv04 (struct rivatv_chip *chip, int LockUnlock){ VID_WR08 (chip->PCIO, 0x3C4, 0x06); VID_WR08 (chip->PCIO, 0x3C5, LockUnlock ? 0x99 : 0x57); VID_WR08 (chip->PCIO, 0x3D4, 0x1F); VID_WR08 (chip->PCIO, 0x3D5, LockUnlock ? 0x99 : 0x57);}/* Enable PFB (Framebuffer), PVIDEO (Overlay unit) and PME (Mediaport) if neccessary. */static void rivatv_enable_PMEDIA (struct rivatv_info *info){ uint32_t reg; /* switch off interrupts once for a while */// VID_WR32 (info->chip.PME, 0x200140, 0x00);// VID_WR32 (info->chip.PMC, 0x000140, 0x00); reg = VID_RD32 (info->chip.PMC, 0x000200); /* NV3 (0x10100010): NV03_PMC_ENABLE_PMEDIA, NV03_PMC_ENABLE_PFB, NV03_PMC_ENABLE_PVIDEO */ if ((reg & 0x10100010) != 0x10100010) { printf("PVIDEO and PFB disabled, enabling...\n"); VID_OR32 (info->chip.PMC, 0x000200, 0x10100010); } /* save the current colorkey */ switch (info->chip.arch ) { case NV_ARCH_10: case NV_ARCH_20: case NV_ARCH_30: /* NV_PVIDEO_COLOR_KEY */ info->colorkey = VID_RD32 (info->chip.PVIDEO, 0xB00); break; case NV_ARCH_03: case NV_ARCH_04: /* NV_PVIDEO_KEY */ info->colorkey = VID_RD32 (info->chip.PVIDEO, 0x240); break; } /* re-enable interrupts again */// VID_WR32 (info->chip.PMC, 0x000140, 0x01);// VID_WR32 (info->chip.PME, 0x200140, 0x01);}/* Stop overlay video. */static void rivatv_overlay_stop (struct rivatv_info *info) { switch (info->chip.arch ) { case NV_ARCH_10: case NV_ARCH_20: case NV_ARCH_30: /* NV_PVIDEO_COLOR_KEY */ /* Xv-Extension-Hack: Restore previously saved value. */ VID_WR32 (info->chip.PVIDEO, 0xB00, info->colorkey); /* NV_PVIDEO_STOP */ VID_OR32 (info->chip.PVIDEO, 0x704, 0x11); /* NV_PVIDEO_BUFFER */ VID_AND32 (info->chip.PVIDEO, 0x700, ~0x11); /* NV_PVIDEO_INTR_EN_BUFFER */// VID_AND32 (info->chip.PVIDEO, 0x140, ~0x11); break; case NV_ARCH_03: case NV_ARCH_04: /* NV_PVIDEO_KEY */ VID_WR32 (info->chip.PVIDEO, 0x240, info->colorkey); /* NV_PVIDEO_OVERLAY_VIDEO_OFF */ VID_AND32 (info->chip.PVIDEO, 0x244, ~0x01); /* NV_PVIDEO_INTR_EN_0_NOTIFY */// VID_AND32 (info->chip.PVIDEO, 0x140, ~0x01); /* NV_PVIDEO_OE_STATE */ VID_WR32 (info->chip.PVIDEO, 0x224, 0); /* NV_PVIDEO_SU_STATE */ VID_WR32 (info->chip.PVIDEO, 0x228, 0); /* NV_PVIDEO_RM_STATE */ VID_WR32 (info->chip.PVIDEO, 0x22C, 0); break; }}/* Get pan offset of the physical screen. */static uint32_t rivatv_overlay_pan (struct rivatv_info *info){ uint32_t pan; info->chip.lock (&info->chip, 0); VID_WR08 (info->chip.PCIO, 0x3D4, 0x0D); pan = VID_RD08 (info->chip.PCIO, 0x3D5); VID_WR08 (info->chip.PCIO, 0x3D4, 0x0C); pan |= VID_RD08 (info->chip.PCIO, 0x3D5) << 8; VID_WR08 (info->chip.PCIO, 0x3D4, 0x19); pan |= (VID_RD08 (info->chip.PCIO, 0x3D5) & 0x1F) << 16; VID_WR08 (info->chip.PCIO, 0x3D4, 0x2D); pan |= (VID_RD08 (info->chip.PCIO, 0x3D5) & 0x60) << 16; return pan << 2;}/* Compute and set colorkey depending on the colour depth. */static void rivatv_overlay_colorkey (rivatv_info* info, unsigned int chromakey){ uint32_t r, g, b, key = 0; r = (chromakey & 0x00FF0000) >> 16; g = (chromakey & 0x0000FF00) >> 8; b = chromakey & 0x000000FF; switch (info->depth) { case 15: key = ((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3));#ifndef WIN32 key = key | 0x00008000;#endif break; case 16: // XXX unchecked key = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3));#ifndef WIN32 key = key | 0x00008000;#endif break; case 24: // XXX unchecked, maybe swap order of masking - FIXME Can the card be in 24 bit mode anyway? key = (chromakey & 0x00FFFFFF) | 0x00800000; break; case 32: key = chromakey;#ifndef WIN32 key = key | 0x80000000;#endif break; } //printf("[nvidia_vid] depth=%d %08X \n", info->depth, chromakey); switch (info->chip.arch) { case NV_ARCH_10: case NV_ARCH_20: case NV_ARCH_30: VID_WR32 (info->chip.PVIDEO, 0xB00, key); break; case NV_ARCH_03: case NV_ARCH_04: VID_WR32 (info->chip.PVIDEO, 0x240, key); break; }}static void nv_getscreenproperties(struct rivatv_info *info){ uint32_t bpp=0; info->chip.lock(&info->chip, 0); /*get screen depth*/ VID_WR08(info->chip.PCIO, 0x03D4,0x28); bpp = VID_RD08(info->chip.PCIO,0x03D5)&0x3; if(bpp==3)bpp=4; if((bpp == 2) && (info->chip.PVIDEO[0x00000600/4] & 0x00001000) == 0x0)info->depth=15; else info->depth = bpp*8; /*get screen width*/ VID_WR08(info->chip.PCIO, 0x03D4, 0x1); info->screen_x = (1 + VID_RD08(info->chip.PCIO, 0x3D5)) * 8; /*get screen height*/ /* get first 8 bits in VT_DISPLAY_END*/ VID_WR08(info->chip.PCIO, 0x03D4, 0x12); info->screen_y = VID_RD08(info->chip.PCIO,0x03D5); VID_WR08(info->chip.PCIO,0x03D4,0x07); /* get 9th bit in CRTC_OVERFLOW*/ info->screen_y |= (VID_RD08(info->chip.PCIO,0x03D5) &0x02)<<7; /* and the 10th in CRTC_OVERFLOW*/ info->screen_y |=(VID_RD08(info->chip.PCIO,0x03D5) &0x40)<<3; ++info->screen_y;}/* Start overlay video. */static void rivatv_overlay_start (struct rivatv_info *info,int bufno){ uint32_t base, size, offset, xscale, yscale, pan; uint32_t value; int x=info->wx?info->wx:8, y=info->wy?info->wy:8; int lwidth=info->d_width, lheight=info->d_height; int bps; int i; size = info->buffer_size; base = info->picture_offset; offset = bufno*size; /*update depth & dimensions here because it may change with vo vesa or vo fbdev*/ nv_getscreenproperties(info); if(info->depth){// bps = info->screen_x * ((info->depth+1)/8); /* get pan offset of the physical screen */ pan = rivatv_overlay_pan (info); /* adjust window position depending on the pan offset */ bps = 0; info->chip.lock (&info->chip, 0); for (i = 0; (i < 1024) && (bps == 0); i++) { if (info->chip.arch != NV_ARCH_03) bps = info->chip.PGRAPH[0x00000670/4]; else bps = info->chip.PGRAPH[0x00000650/4]; } if (bps == 0) { fprintf(stderr, "[nvidia_vid] reading bps returned 0!!!\n"); if (info->bps != 0) bps = info->bps; } else { info->bps = bps; } if (bps != 0) { x = info->wx - (pan % bps) * 8 / info->depth; y = info->wy - (pan / bps); } } /* adjust negative output window variables */ if (x < 0) { lwidth = info->d_width + x; offset += (-x * info->width / info->d_width) << 1;// offset += (-window->x * port->vld_width / window->width) << 1; x = 0; } if (y < 0) { lheight = info->d_height + y; offset += (-y * info->height / info->d_height * info->width) << 1;// offset += (-window->y * port->vld_height / window->height * port->org_width) << 1; y = 0; } switch (info->chip.arch) { case NV_ARCH_10: case NV_ARCH_20: case NV_ARCH_30: /* NV_PVIDEO_BASE */ VID_WR32 (info->chip.PVIDEO, 0x900 + 0, base + offset); //VID_WR32 (info->chip.PVIDEO, 0x900 + 4, base); /* NV_PVIDEO_LIMIT */ VID_WR32 (info->chip.PVIDEO, 0x908 + 0, base + offset + size - 1); //VID_WR32 (info->chip.PVIDEO, 0x908 + 4, base + size - 1);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?