📄 v4lxif.cc
字号:
/* video4linux interface wrapper for kwintv Copyright (C) 1998,1999 Moritz Wenk (wenk@mathematik.uni-kl.de) This program 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 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <endian.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/mman.h>#include <asm/types.h>#include "v4lxif.h"//#include <kapp.h>#ifndef GUILESS#include <qapp.h>#include <X11/Xlib.h>#include <X11/Xmd.h>#include "qt_visual.h"#endif#include <stdarg.h>#ifndef GUILESS#ifdef HAVE_LIBXXF86DGA#include <X11/Xproto.h>#include <X11/extensions/xf86dga.h>#include <X11/extensions/xf86dgastr.h>// Support deprecated XFree86 symbol names#ifndef XDGA_MINOR_VERSION#define XDGA_MINOR_VERSION XF86DGA_MINOR_VERSION#endif#ifndef XDGA_MAJOR_VERSION#define XDGA_MAJOR_VERSION XF86DGA_MAJOR_VERSION#endif#endif /* HAVE_LIBXXF86DGA */#endif /* GUILESS *//* PAL NTSC SECAM */static int maxwidth[] = { 768, 640, 768 };static int maxheight[] = { 576, 480, 576 };extern int errno;const int one = 1;const int zero = 0;//#define VIF_FATAL(a) {warning(a);_state=0;}#define VIF_FATAL(a) (warning(a))#define VIF_WARN(a) (warning(a))#define VIF_FATAL_STR(a,b) (warning(a,(b)))//#define VIF_FATAL(a) (fatal(a,(b)))#define VIF_WARN_STR(a,b) (warning(a,(b)))#if 0static unsigned short format2palette[] = { 0, /* unused */ VIDEO_PALETTE_HI240, /* RGB8 */ VIDEO_PALETTE_GREY, /* GRAY8 */#if __BYTE_ORDER == __BIG_ENDIAN 0, 0, VIDEO_PALETTE_RGB555, /* RGB15_BE */ VIDEO_PALETTE_RGB565, /* RGB16_BE */ 0, 0, VIDEO_PALETTE_RGB24, /* RGB24 */ VIDEO_PALETTE_RGB32, /* RGB32 */#else // little endian (intel) VIDEO_PALETTE_RGB555, /* RGB15_LE */ VIDEO_PALETTE_RGB565, /* RGB16_LE */ 0, 0, VIDEO_PALETTE_RGB24, /* BGR24 */ VIDEO_PALETTE_RGB32, /* BGR32 */ 0, 0,#endif};#endif#define VIDEO_RGB08 1 /* bt848 dithered */#define VIDEO_GRAY 2#define VIDEO_RGB15_LE 3 /* 15 bpp little endian */#define VIDEO_RGB16_LE 4 /* 16 bpp little endian */#define VIDEO_RGB15_BE 5 /* 15 bpp big endian */#define VIDEO_RGB16_BE 6 /* 16 bpp big endian */#define VIDEO_BGR24 7 /* bgrbgrbgrbgr (LE) */#define VIDEO_BGR32 8 /* bgr-bgr-bgr- (LE) */#define VIDEO_RGB24 9 /* rgbrgbrgbrgb (BE)*/#define VIDEO_RGB32 10 /* -rgb-rgb-rgb (BE)*/#define VIDEO_LUT2 11 /* lookup-table 2 byte depth */#define VIDEO_LUT4 12 /* lookup-table 4 byte depth */#define VIDEO_YUYV 13 /* YUV 4:2:2 */#define VIDEO_YUV420 14 /* YUV 4:2:0 */unsigned int format2depth[] = { 0, /* unused */ 8, /* RGB8 */ 8, /* GRAY8 */ 16, /* RGB15 LE */ 16, /* RGB16 LE */ 16, /* RGB15 BE */ 16, /* RGB16 BE */ 24, /* BGR24 */ 32, /* BGR32 */ 24, /* RGB24 */ 32, /* RGB32 */ 16, /* LUT2 */ 32, /* LUT4 */ 16, /* YUV422 */ 12, /* YUV420 */};char* format_desc[] = { "", "8 bit PseudoColor (dithering)", "8 bit StaticGray", "15 bit TrueColor (LE)", "16 bit TrueColor (LE)", "15 bit TrueColor (BE)", "16 bit TrueColor (BE)", "24 bit TrueColor (LE: bgr)", "32 bit TrueColor (LE: bgr-)", "24 bit TrueColor (BE: rgb)", "32 bit TrueColor (BE: -rgb)", "16 bit TrueColor (lut)", "32 bit TrueColor (lut)", "16 bit YUV 4:2:2", "12 bit YUV 4:2:0", "12 bit YUV 4:1:1"};int con_printf(const char* fmt, ...){ va_list va; va_start(va, fmt); vprintf(fmt, va); printf("\n"); return 0;}//==============================================================================v4lxif::v4lxif(const char * _device, v4lxif_version _ifv ) : ifv(_ifv), device(_device){#ifdef v4lDEBUG debug("v4l1: Using interface %s in ::v4lxif",ifname[ifv].str);#endif // open v4l device if ( -1 == (devv4l=::open(device,O_RDWR)) ) { fatal("v4lx: Error opening v4lx device %s: %s in ::v4lxif",device,strerror(errno)); }}v4lxif::~v4lxif(){#ifdef v4lDEBUG debug("v4lx: Close device in ::~v4lxif");#endif if ( -1 == ::close(devv4l) ) warning("v4l1: Error closing the v4lx device %s: %s in ::v4lxif",device,strerror(errno));}//==============================================================================v4l1if::v4l1if( int fd ){ devv4l=fd;}v4l1if::v4l1if( const char* mem, const char * _device, int _bpp, int _palette ) : v4lxif( _device, v4lxif::v4l1 ), _state(1){#ifndef GUILESS int visual_class; Visual *myvisual; Display *disp= qt_xdisplay();#endif ushort i; setupok=true;// // capture off if ( -1 == ioctl(devv4l, VIDIOCCAPTURE, &zero) ) VIF_FATAL("v4l1: VIDIOCCAPTURE in ::v4l1if"); // get capabilities if( -1 == ioctl(devv4l,VIDIOCGCAP,&vcap) ) VIF_FATAL("v4l1: VIDIOC_G_CAP in ::v4l1if"); // get input sources (channels) vchan = (struct video_channel*)malloc(sizeof(struct video_channel)*vcap.channels); memset(vchan,0,sizeof(struct video_channel)*vcap.channels); // get audios vaudio = (struct video_audio*)malloc(sizeof(struct video_audio)*vcap.audios); memset(vaudio,0,sizeof(struct video_audio)*vcap.audios);// return;#ifdef v4lDEBUG debug("v4l1: Grabber name: %s",vcap.name); for (i = 0; device_cap[i].str != NULL; i++) if (vcap.type & (1 << i)) debug("\t %s: %s",device_cap[i].str,device_cap[i].description); debug("v4l1: range of tv size : %dx%d => %dx%d", vcap.minwidth,vcap.minheight, vcap.maxwidth,vcap.maxheight); debug("v4l1: input channels: %d",vcap.channels);#endif // get information about each channel for (i = 0; i < vcap.channels; i++) { vchan[i].channel = i; if ( -1 == ioctl(devv4l,VIDIOCGCHAN,&vchan[i]) ) VIF_FATAL("v4l1: VIDIOC_G_CHAN in ::v4l1if"); } achan= 0;#ifdef v4lDEBUG for (i = 0; i < vcap.channels; i++) { debug("\t [%d] %s: %s [%d], %s%s%s%s",i+1, vchan[i].name, (vchan[i].flags & VIDEO_VC_TUNER) ? "has tuner" : "no tuner", vchan[i].tuners, (vchan[i].flags & VIDEO_VC_AUDIO) ? "audio, " : "", "",//(vchan[i].flags & VIDEO_VC_NORM) ? "norm, " : "", (vchan[i].type & VIDEO_TYPE_TV) ? "tv" : "", (vchan[i].type & VIDEO_TYPE_CAMERA) ? "camera" : ""); }#endif // set v4l to the first aviable input source, also set first norm vchan[0].norm= 0; if ( -1 == ioctl(devv4l, VIDIOCSCHAN, &vchan[0]) ) VIF_WARN("v4l1: you need a newer bttv version (>= 0.5.14)"); // get information for each audio for (i = 0; i < vcap.audios; i++) { vaudio[i].audio = i; if ( -1 == ioctl(devv4l,VIDIOCGAUDIO,&vaudio[i]) ) VIF_FATAL("v4l1: VIDIOC_G_AUDIO in ::v4l1if"); } aaudio= 0; // mute them all for (i = 0; i < vcap.audios; i++) if (vaudio[i].flags & VIDEO_AUDIO_MUTABLE) { vaudio[i].flags |= VIDEO_AUDIO_MUTE; if ( -1 == ioctl(devv4l,VIDIOCSAUDIO,&vaudio[i]) ) VIF_FATAL("v4l1: VIDIOC_S_AUDIO in ::v4l1if"); } smute= true;#ifdef v4lDEBUG debug("v4l1: input audios: %d",vcap.audios); for (i = 0; i < vcap.audios; i++) { debug("\t [%d] %s: %s%s vol=%d, bass=%d, ter=%d",i+1,vaudio[i].name, (vaudio[i].flags & VIDEO_AUDIO_MUTABLE)?"mutable":"not mutable", (vaudio[i].flags & VIDEO_AUDIO_MUTE)?"[unmuted]":"[muted]", (vaudio[i].flags & VIDEO_AUDIO_VOLUME)?vaudio[i].volume:-1, (vaudio[i].flags & VIDEO_AUDIO_BASS)?vaudio[i].bass:-1, (vaudio[i].flags & VIDEO_AUDIO_TREBLE)?vaudio[i].treble:-1); }#endif // check tuner ( are there any tv cards with more than one ??? ) for (i = 0; i < vcap.channels; i++) { if ( vchan[i].tuners > 1 ) { warning("v4l1: Found more than one [%d] tuner for source channel %s.",vchan[i].tuners,vchan[i].name); warning("v4l1: Only the first tuner of channel %s will be supported!",vchan[i].name); warning("v4l1: This warning can be ignored..."); } } atuner= 0; memset(&vtuner,0,sizeof(struct video_tuner)); // vtuner.tuner=atuner; if ( vcap.type & VID_TYPE_TUNER) { if ( -1 == ioctl(devv4l, VIDIOCGTUNER, &vtuner) ) VIF_FATAL("v4l1: VIDIOC_G_TUNER in ::v4l1if");#ifdef v4lDEBUG debug("v4l1: tuner: %s %lu-%lu",vtuner.name,vtuner.rangelow,vtuner.rangehigh); debug("v4l1: tuner sees stereo: %s",vtuner.flags & VIDEO_TUNER_STEREO_ON?"yes":"no"); //if ( vtuner.flags & VIDEO_TUNER_NORM ) { debug("v4l1: tuner supports modes (active: %s): ",norms[vtuner.mode].str); for (i = 0; norms[i].str != NULL; i++) { if (vtuner.flags & (1<<i)) { debug("\t %s",norms[i].str); } } //} else debug("v4l1: tuner supports no modes (fixed: %s)",norms[vtuner.mode].str);#endif } // get window parameters if ( -1 == ioctl(devv4l, VIDIOCGWIN, &(vwin)) ) VIF_FATAL("v4l1: VIDIOC_G_WIN in ::v4l1if"); if ( -1 == ioctl(devv4l, VIDIOCGPICT, &vpic) ) VIF_FATAL("v4l1: VIDIOC_G_PICT in ::v4l1if"); #ifdef v4lDEBUG debug("v4l1: picture: brightness=%d hue=%d colour=%d contrast=%d", vpic.brightness, vpic.hue, vpic.colour, vpic.contrast); debug("v4l1: picture : whiteness=%d depth=%d palette=%d[%s]", vpic.whiteness, vpic.depth, vpic.palette, PALETTE(vpic.palette));#endif // get frame buffer parameters if ( -1 == ioctl(devv4l, VIDIOCGFBUF, &(vbuf)) ) VIF_FATAL("v4l1: ioctl VIDIOC_G_FBUF in ::v4l1if");#ifndef GUILESS#ifdef v4lDEBUG List_visuals(disp);#endif#endif#ifndef GUILESS // get the visual int display_bits= find_visual(disp,NULL,&myvisual,&visual_class); // do some checks for color depth, size and buffer pos // first, guess the color depth of the screen int n,pixmap_bytes; XPixmapFormatValues *pf = XListPixmapFormats(disp,&n); for (i = 0; i < n; i++) { if (pf[i].depth == QColor::numBitPlanes()) pixmap_bytes = pf[i].bits_per_pixel/8; } /* guess physical screen format */ if (ImageByteOrder(disp) == MSBFirst) { switch (pixmap_bytes) { case 1: x11_format = VIDEO_RGB08; break; case 2: x11_format = (display_bits==15) ? VIDEO_RGB15_BE : VIDEO_RGB16_BE; break; case 3: x11_format = VIDEO_RGB24; break; case 4: x11_format = VIDEO_RGB32; break; default: VIF_WARN_STR("v4l1: Unknown color depth found: %d",pixmap_bytes); } } else { // little endian (intel) switch (pixmap_bytes) { case 1: x11_format = VIDEO_RGB08; break; case 2: x11_format = (display_bits==15) ? VIDEO_RGB15_LE : VIDEO_RGB16_LE; break; case 3: x11_format = VIDEO_BGR24; break; case 4: x11_format = VIDEO_BGR32; break; default: VIF_WARN_STR("v4l1: Unknown color depth found: %d",pixmap_bytes); } }#ifdef v4lDEBUG debug("v4l1: hope physical screen format is <%s>",format_desc[x11_format]);#endif if ( _palette > 0 && _palette < 11 ) { x11_format = _palette; } vpic.palette = (x11_format < sizeof(format2palette)/sizeof(unsigned short)) ? format2palette[x11_format] : 0; if ( vpic.palette == 0 ) { warning("v4l1: unsupported overlay video format <%d-%s> in ::v4l1if", x11_format,format_desc[x11_format]); vpic.palette = VIDEO_RGB08; }#else /* GUILESS */ vpic.palette = VIDEO_RGB15_LE;#endif#ifdef v4lDEBUG debug("v4l1: set palette to %d",format2palette[x11_format]);#endif if ( -1 == ioctl(devv4l, VIDIOCSPICT, &vpic) ) VIF_FATAL("v4l1: VIDIOC_S_PICT in ::v4l1if");#ifdef v4lDEBUG // reread palette if ( -1 == ioctl(devv4l, VIDIOCGPICT, &vpic) ) VIF_FATAL("v4l1: VIDIOC_G_PICT in ::v4l1if"); debug("v4l1: palette is %d",vpic.palette);#endif#ifndef GUILESS#ifdef HAVE_LIBXXF86DGA // do some strange things with dga int major, minor, width, bank, ram; int flags; void *base = NULL; bool have_dga= false;#ifndef XDGA_MAJOR_VERSION#define XDGA_MAJOR_VERSION XF86DGA_MAJOR_VERSION#endif#ifndef XDGA_MINOR_VERSION#define XDGA_MINOR_VERSION XF86DGA_MINOR_VERSION#endif if (XF86DGAQueryExtension(disp, &major, &minor)) { XF86DGAQueryDirectVideo(disp,XDefaultScreen(disp),&flags); if (flags & XF86DGADirectPresent) { have_dga= true; XF86DGAQueryVersion(disp,&major,&minor); if ((major != XDGA_MAJOR_VERSION) || (minor != XDGA_MINOR_VERSION)) { warning("v4l1: X-Server DGA extension version mismatch, disabled"); warning("v4l1: server version %d.%d != included version %d.%d",major,minor, XDGA_MAJOR_VERSION,XDGA_MINOR_VERSION); have_dga= false; } else { XF86DGAGetVideoLL(disp, DefaultScreen(disp), (int *)&base, &width, &bank, &ram ); if (!base) fatal("v4l1: can not allocate frame buffer base: 0x%x",(int)base); } } } if (have_dga) { // check framebuffer if ( (void*)((unsigned long)vbuf.base & 0xfffff000) != (void*)((unsigned long)base & 0xfffff000) ) { warning("v4l1: Video4Linux and DGA disagree about the framebuffer base"); warning("v4l1: Video4Linux: 0x%x, dga: 0x%x!", (unsigned int)vbuf.base ,(unsigned int)base); warning("v4l1: you probably want to insmod the bttv module with " "\"vidmem=0x%03lx\"\n",(unsigned long)base >> 20); setupok=false; } if ( _bpp == 0 && _palette == 0 ) { // check color depth if ( (unsigned int)((vbuf.depth+7)&0xf8) != format2depth[x11_format] ) { warning("v4l1: Video4Linux and DGA disagree about the color depth"); warning("v4l1: Video4Linux: %d, DGA: %d.", (vbuf.depth+7)&0xf8,format2depth[x11_format]); warning("v4l1: Is kv4lsetup installed correctly?"); setupok=false; } } #ifdef v4lDEBUG else debug("v4l1: forced bpp %d, palette %d",_bpp,_palette);#endif } // have_dga#endif /* HAVE_LIBXXF86DGA */#endif /* GUILESS */ // get infos about snapshot buffer memory size if ( -1 == ioctl(devv4l, VIDIOCGMBUF, &(vmbuf)) ) VIF_FATAL("v4l1: VIDIOC_G_MBUF in ::v4l1if"); msize = vmbuf.size; // Alloc memory for snapshot grabbermem=(char *)mmap(0,msize,PROT_READ|PROT_WRITE,MAP_SHARED,devv4l,0); if ((char*)-1 == grabbermem) { warning("v4l1: unable to allocate memory for snap shots and video clips!"); }#ifdef v4lDEBUG debug("v4l1: bpp %d, bpl %d, width %d, height %d",vbuf.depth,vbuf.bytesperline,vwin.width,vwin.height); debug("v4l1: video buffer: size %d, frames %d",vmbuf.size,vmbuf.frames); debug("v4l1: memory for snap shots: 0x%08x", (long) grabbermem);#endif gsync=ggrab=0; geven=true; if ( !setupok ) exit(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -