/* * vo_v4lw.c * * Copyright (C) Tilmann Bitterberg - Nov 2001 * * This 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. * * This 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. * * Updated 4/27/2006 - sfranzyshen * compiled against MPlayer-1.0pre7try2 */ /* Quick v4lw loopback howto: - get the vloopback kernel module from or (alternative) my hacked version from - if using my version, you don't need to specify dev_offset. - untar and compile it tar xzf vloopback-VERSION.tar.gz && cd vloopback-VERSION make - load the vloopback module insmod vloopback.o dev_offset=2 pipes=1 - Make the devices accessible chmod og+rw /dev/v4l/video2 chmod og+rw /dev/v4l/video3 - eventually you have to recompile mplayer to let it see that it can talk v4l. ./configure --enable-v4lw to be sure - start mplayer mplayer -vo v4lw movie.avi - start xawtv xawtv -c /dev/v4l/video3 -geometry 800x600 - done easy, isn't it. NOTES: - avicap doesn't work yet. I got mp1e to work with a my hacked vloopback.o, you need to specify the exact size. - no scaling of video output is possible right now. - be sure to insmod vloopback with a dev_offset appropriate for your system. If you have a real grabber card (eg. a bttv which is at /dev/v4l/video0) you _HAVE_ to use at least a dev_offset=1 or you'll crash your kernel. - I am on devfs, if you're not you have to use /dev/video2 instead of /dev/v4l/video2 and may have to create the devices manually. Eg. for video2: mknod c 81 2 /dev/video2 - mplayer will tell you the v4lw output device from which you have to read. Performance: System: 2 * 1GHz Intel PIII (Coppermine) #SMP MPEG1 at 768x576 mplayer CPU Usage ca. 35%, xawtv 11% Divx at 512x384 mplayer CPU Usage ca. 20%, xawtv 10% */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "video_out.h" #include "video_out_internal.h" #include "fastmemcpy.h" #include "sub.h" #include "aspect.h" #include "mp_msg.h" static uint32_t image_width, image_height; static int devout; static uint8_t *image; static unsigned int image_format=0; static int bpp = 24; static int fmt; #define MAXIOCTL 1024 #define MAXWIDTH 1280 #define MAXHEIGHT 1024 int width; int height; char ioctlbuf[MAXIOCTL]; int v4ldev; char *image_out; int get_frame(void) { int i; char colour = 0; memset(image_out, 0x128, width*height*3); for (i=10; iname, "Jeroen's dummy v4l driver"); vidcap->type= VID_TYPE_CAPTURE; vidcap->channels=1; vidcap->audios=0; vidcap->maxwidth=MAXWIDTH; vidcap->maxheight=MAXHEIGHT; vidcap->minwidth=20; vidcap->minheight=20; return 0; } case VIDIOCGCHAN: { struct video_channel *vidchan= (struct video_channel *)arg; printf("VIDIOCGCHAN called\n"); if (vidchan->channel!=0) ;//return 1; vidchan->channel=0; vidchan->flags=0; vidchan->tuners=0; vidchan->norm=0; vidchan->type=VIDEO_TYPE_CAMERA; strcpy(vidchan->name, "Loopback"); return 0; } case VIDIOCSCHAN: { int *v=arg; if (v[0]!=0) return 1; return 0; } case VIDIOCGTUNER: { struct video_tuner *v = arg; if(v->tuner) { printf("VIDIOCGTUNER: Invalid Tuner, was %d\n", v->tuner); //return -EINVAL; } v->tuner=0; strcpy(v->name, "Format"); v->rangelow=0; v->rangehigh=0; v->flags=0; v->mode=VIDEO_MODE_AUTO; return 1; } case VIDIOCGPICT: { struct video_picture *vidpic=arg; vidpic->colour=0x8000; vidpic->hue=0x8000; vidpic->brightness=0x8000; vidpic->contrast=0x8000; vidpic->whiteness=0x8000; vidpic->depth=0x8000; vidpic->palette=fmt; return 0; } case VIDIOCSPICT: { struct video_picture *vidpic=arg; if (vidpic->palette!=fmt) return 1; return 0; } case VIDIOCGWIN: { struct video_window *vidwin=arg; vidwin->x=0; vidwin->y=0; vidwin->width=width; vidwin->height=height; vidwin->chromakey=0; vidwin->flags=0; vidwin->clipcount=0; return 0; } case VIDIOCSWIN: { struct video_window *vidwin=arg; if (vidwin->width > MAXWIDTH || vidwin->height > MAXHEIGHT ) return 1; if (vidwin->flags) return 1; width=vidwin->width; height=vidwin->height; printf("new size: %dx%d\n", width, height); return 0; } case VIDIOCGMBUF: { struct video_mbuf *vidmbuf=arg; vidmbuf->size=width*height*3; vidmbuf->frames=1; for (i=0; iframes; i++) vidmbuf->offsets[i]=i*vidmbuf->size; return 0; } case VIDIOCMCAPTURE: { struct video_mmap *vidmmap=arg; //return 0; if (vidmmap->height>MAXHEIGHT || vidmmap->width>MAXWIDTH || vidmmap->format!=fmt ) return 1; if (vidmmap->height!=height || vidmmap->width!=width) { height=vidmmap->height; width=vidmmap->width; printf("new size: %dx%d\n", width, height); } // check if 'vidmmap->frame' is valid // initiate capture for 'vidmmap->frame' frames return 0; } case VIDIOCSYNC: { //struct video_mmap *vidmmap=arg; // check if frames are ready. // wait until ready. get_frame(); return 0; } default: { printf("unknown ioctl: %ld\n", cmd & 0xff); return 1; } } return 0; } static vo_info_t info = { "video4linux write output", "v4lw", "Tilmann Bitterberg ", "update 4/27/06 sfanzyshen " }; LIBVO_EXTERN(v4lw) /* stolen from: * vloopback/example/dummy.c * returns 0 on successfull opening, !0 otherwise */ int check_vidpipe(void) { int pipe_fd = -1; FILE *vloopbacks; char pipepath[255]; char buffer[255]; char *loop; char *input; char *istatus; char *output; char *ostatus; char *major; char *minor; struct utsname uts; if (uname(&uts) < 0) { printf("Unable to execute uname\nError[%s]\n",strerror(errno)); return -1; } major = strtok(uts.release, "."); minor = strtok(NULL, "."); if ((major == NULL) || (minor == NULL) || (strcmp(major, "2"))) { printf("Unable to decipher OS version\n"); return -1; } DIR *dir; struct dirent *dirp; const char prefix[]="/sys/class/video4linux/"; char *ptr, *io; int fd; int low=9999; int tfd; int tnum; if ((dir=opendir(prefix))== NULL) { printf( "Failed to open '%s'", prefix); return -1; } while ((dirp=readdir(dir)) != NULL) { if (!strncmp(dirp->d_name, "video", 5)) { strcpy(buffer, prefix); strcat(buffer, dirp->d_name); strcat(buffer, "/name"); if ((fd=open(buffer, O_RDONLY)) >= 0) { if ((read(fd, buffer, sizeof(buffer)-1))<0) { close(fd); continue; } ptr = strtok(buffer, " "); if (strcmp(ptr,"Video")) { close(fd); continue; } major = strtok(NULL, " "); minor = strtok(NULL, " "); io = strtok(NULL, " \n"); if (strcmp(major, "loopback") || strcmp(io, "input")) { close(fd); continue; } if ((ptr=strtok(buffer, " "))==NULL) { close(fd); continue; } tnum = atoi(minor); if (tnum < low) { strcpy(buffer, "/dev/"); strcat(buffer, dirp->d_name); if ((tfd=open(buffer, O_RDWR))>=0) { strcpy(pipepath, buffer); if (pipe_fd>=0) { close(pipe_fd); } pipe_fd = tfd; low = tnum; } } close(fd); } } } closedir(dir); if (pipe_fd >= 0) printf("Opened input of %i", pipe_fd); return 0; } /* copied from * vloopback-0.90/example/invert.c */ int start_pipe (int dev, int width, int height) { struct video_capability vid_caps; struct video_window vid_win; struct video_picture vid_pic; printf("Started startpipe"); if (v4l_ioctl (VIDIOCGCAP, &vid_caps) == -1) { printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); return (1); } if (v4l_ioctl (VIDIOCGPICT, &vid_pic)== -1) { printf ("ioctl VIDIOCGPICT\nError[%s]\n",strerror(errno)); return (1); } /* this is probably brain dead */ /* vid_pic.palette=VIDEO_PALETTE_RGB24; */ /* vid_pic.palette=VIDEO_PALETTE_YUV420P; */ vid_pic.palette = fmt; if (v4l_ioctl (VIDIOCSPICT, &vid_pic)== -1) { printf ("ioctl VIDIOCSPICT\nError[%s]\n",strerror(errno)); return (1); } if (v4l_ioctl (VIDIOCGWIN, &vid_win)== -1) { printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno)); return (1); } vid_win.width = width; vid_win.height = height; if (v4l_ioctl (VIDIOCSWIN, &vid_win)== -1) { printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno)); return (1); } return 0; } /* stolen from vo_odivx.c */ /* orig size -- working */ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) { uint8_t *s; uint8_t *d; int i; int dstride=image_width; int size = image_width*image_height; // copy Y d=image+dstride*y+x; s=src[0]; for(i=0;i