[MPlayer-dev-eng] New vo_v4lw video output module
Tilmann Bitterberg
tilmann at bitterberg.de
Wed Nov 28 01:42:43 CET 2001
Hi,
I hacked together a new libvo module called vo_v4lw.c. It
provides write support for the video4linux api. This means that
mplayer can act as a video4linux device providing (uncompressed)
YUV/RGB data to other v4l applications like xawtv, mp1e etc.
This is a generic way to use other recompressors over a well
known API.
The main work is done by a linux kernel module called vloopback
which provides a v4l loopback device. vloopback provides at
least 2 v4l devices, one is the input pipe and the other one the
output. Read more on <http://motion.technolust.cx/vloopback/index.html>.
I did not wrote vloopback but hacked on it too and you probably
want my version which is at <http://tibit.org/video/>
A (very) quick Howto follows (more on the mentioned site):
- patch mplayer
- get vloopback from http://tibit.org/video/vloopback-0.90-tibit.tar.gz
- compile and load module vloopback
- compile mplayer (./configure will detect v4lw)
- run mplayer (it will tell you the output device)
./mplayer -vo v4lw movie.avi
- run xawtv
xawtv -c /dev/v4l/video1 -geometry 800x600
Limitations:
- No scaling possible, so you have to tell grabbing applications
the *exact* size.
- RGB is not tested (draw_frame too).
- No sound.
- Only tested with Linux 2.4.X and devfs
If you find that code useful you're welcome to include it into
your amazing project.
Tilmann
please CC: me, since I'm not yet on the list.
--
If something can go wrong, it w
fortune: segmentation fault. core dumped
-------------- next part --------------
diff -Nur MPlayer-0.50/configure MPlayer-0.50-tibit/configure
--- MPlayer-0.50/configure Tue Nov 20 18:06:03 2001
+++ MPlayer-0.50-tibit/configure Tue Nov 20 16:22:12 2001
@@ -144,6 +144,7 @@
--enable-sdl build with SDL render support [autodetect]
--enable-aa build with AAlib render support [autodetect]
--enable-ggi build with GGI render support [autodetect]
+ --enable-v4l build with video4linux write support [autodetect]
--enable-mga build with mga_vid support [autodetect, if /dev/mga_vid
is available]
--enable-xmga build with mga_vid X Window support [autodetect,
@@ -511,6 +512,7 @@
_xmga=autodetect
_dga=no
_dga2=no
+_v4l=no
_svga=no
_fbdev=no
[ "$system_name" = Linux ] && _fbdev=yes
@@ -589,6 +591,11 @@
fi
+if [ -d /proc/video/vloopback ]; then
+ _v4l=yes
+fi
+
+
if [ -c /dev/mga_vid ]; then
_mga=yes
_syncfb=yes
@@ -1176,6 +1183,9 @@
--enable-ggi)
_ggi=yes
;;
+ --enable-v4l)
+ _v4l=yes
+ ;;
--enable-mga)
_mga=yes
;;
@@ -1289,6 +1299,9 @@
--disable-ggi)
_ggi=no
;;
+ --disable-v4l)
+ _v4l=no
+ ;;
--disable-mga)
_mga=no
;;
@@ -1550,6 +1563,7 @@
echo "Screen size ... ${_x}x${_y}"
echo "Checking for X11 libs ... $_x11libdir"
echo "Checking for X11 headers ... $_x11incdir"
+echo "Checking v4l loopback ... $_v4l"
echo "Checking mga_vid device ... $_mga"
echo "Checking for xmga ... $_xmga"
echo "Checking for SDL ... $_sdl"
@@ -2059,6 +2073,12 @@
fi
# ---
+if [ $_v4l = yes ]; then
+ _v4l='#define HAVE_V4L'
+ _vosrc=$_vosrc' vo_v4l.c'
+else
+ _v4l='#undef HAVE_V4L'
+fi
if [ $_mga = yes ]; then
_mga='#define HAVE_MGA'
@@ -2408,6 +2428,7 @@
$_ggi
$_3dfx
$_tdfxfb
+$_v4l
$_mga
$_xmga
$_syncfb
diff -Nur MPlayer-0.50/libvo/video_out.c MPlayer-0.50-tibit/libvo/video_out.c
--- MPlayer-0.50/libvo/video_out.c Tue Nov 20 18:06:03 2001
+++ MPlayer-0.50-tibit/libvo/video_out.c Tue Nov 20 16:23:43 2001
@@ -70,6 +70,7 @@
extern vo_functions_t video_out_ggi;
extern vo_functions_t video_out_aa;
extern vo_functions_t video_out_mpegpes;
+extern vo_functions_t video_out_v4l;
vo_functions_t* video_out_drivers[] =
{
@@ -116,6 +117,9 @@
#endif
#ifdef HAVE_AA
&video_out_aa,
+#endif
+#ifdef HAVE_V4L
+ &video_out_v4l,
#endif
#ifdef HAVE_PNG
diff -Nur MPlayer-0.50/libvo/vo_v4l.c MPlayer-0.50-tibit/libvo/vo_v4l.c
--- MPlayer-0.50/libvo/vo_v4l.c Thu Jan 1 00:00:00 1970
+++ MPlayer-0.50-tibit/libvo/vo_v4l.c Sat Nov 24 19:00:54 2001
@@ -0,0 +1,399 @@
+/*
+ * vo_v4l.c
+ *
+ * Copyright (C) Aaron Holtzman - June 2000
+ *
+ * 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.
+ *
+ */
+
+/*
+ Quick v4l loopback howto:
+
+ - get the vloopback kernel module from
+ <http://motion.technolust.cx/vloopback/index.html>
+
+ - 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-v4l
+ to be sure
+
+ - start mplayer
+ mplayer -vo v4l movie.avi
+
+ - start xawtv
+ xawtv -c /dev/v4l/video5 -geometry 800x600
+
+ - done
+ easy, isn't it.
+
+ NOTES:
+ - avicap and mp1e don't work yet, they want mmap'ed buffers
+ and I can't provide them (right now). Thats not fully correct,
+ I got mp1e to work with a hacked vloopback.o
+ - 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 v4l 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <linux/videodev.h>
+
+#include "config.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+
+LIBVO_EXTERN(v4l)
+
+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;
+
+static vo_info_t vo_info =
+{
+ "v4l video output",
+ "v4l",
+ "Tilmann Bitterberg <god at tibit.org>",
+ "experimental"
+};
+
+/* stolen from:
+ * vloopback/example/dummy.c
+ * returns 0 on successfull opening, !0 otherwise
+ */
+int check_vidpipe(void)
+{
+ FILE *vloopbacks;
+ char pipepath[255];
+ char buffer[255];
+ char *loop; /* internal loop nr */
+ char *input; /* our output dev */
+ char *istatus;
+ char *output; /* user should read from */
+ char *ostatus;
+
+ vloopbacks=fopen("/proc/video/vloopback/vloopbacks", "r");
+ if (!vloopbacks) {
+ perror ("V4L: Failed to open '/proc/video/vloopback/vloopbacks'");
+ printf ("V4L: You need to load the vlooback kernel module\n");
+ return -1;
+ }
+ /* Read vloopback version */
+ fgets(buffer, 255, vloopbacks);
+ /* Read explaination line */
+ fgets(buffer, 255, vloopbacks);
+ while (fgets(buffer, 255, vloopbacks)) {
+ if (strlen(buffer)>1) {
+ buffer[strlen(buffer)-1]=0;
+ loop = strtok(buffer, "\t");
+ input = strtok(NULL, "\t");
+ istatus = strtok(NULL, "\t");
+ output = strtok(NULL, "\t");
+ ostatus = strtok(NULL, "\t");
+ if (istatus[0] == '-') {
+ sprintf(pipepath, "/dev/%s", input);
+ devout = open (pipepath, O_RDWR);
+ if (devout >= 0) {
+ printf("V4L: I am writing to: /dev/%s\n", input);
+ printf("V4L: You should read from: /dev/%s\n", output);
+ /* Ok, found one */
+ return 0;
+ } else {
+ printf ("V4L: Error opening /dev/%s\n", input);
+ perror ("V4L: Failed to open output video device");
+ /* scan ahead */
+ }
+ }
+ }
+ }
+ printf("V4L: Unable to find a available vloopback device\n");
+ printf("V4L: Maybe insmod with a greater pipes= value helps\n");
+ return -1;
+}
+/* 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;
+
+ if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) {
+ perror ("ioctl (VIDIOCGCAP)");
+ return (1);
+ }
+ if (ioctl (dev, VIDIOCGPICT, &vid_pic)== -1) {
+ perror ("ioctl VIDIOCGPICT");
+ return (1);
+ }
+ /* this is probably brain dead */
+ /* vid_pic.palette=VIDEO_PALETTE_RGB24; */
+ /* vid_pic.palette=VIDEO_PALETTE_YUV420P; */
+ vid_pic.palette = fmt;
+
+ if (ioctl (dev, VIDIOCSPICT, &vid_pic)== -1) {
+ perror ("ioctl VIDIOCSPICT");
+ return (1);
+ }
+ if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) {
+ perror ("ioctl VIDIOCGWIN");
+ return (1);
+ }
+ vid_win.width = width;
+ vid_win.height = height;
+ if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) {
+ perror ("ioctl VIDIOCSWIN");
+ return (1);
+ }
+ return 0;
+}
+
+/* stolen from
+ vo_odivx.c
+ */
+/* orig size -- working */
+static uint32_t 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<h;i++){
+ memcpy(d,s,w);
+ s+=stride[0];
+ d+=dstride;
+ }
+
+ w/=2;h/=2;x/=2;y/=2; dstride/=2;
+
+ // copy U
+ d=image + size + dstride*y+x;
+ s=src[1];
+ for(i=0;i<h;i++){
+ memcpy(d,s,w);
+ s+=stride[1];
+ d+=dstride;
+ }
+
+ // copy V
+ d=image + size + size/4 + dstride*y+x;
+ s=src[2];
+ for(i=0;i<h;i++){
+ memcpy(d,s,w);
+ s+=stride[2];
+ d+=dstride;
+ }
+
+ return 0;
+}
+/*
+ printf("%d, %d, %d, %d, %d, %d, %d\n", stride[0], stride[1], stride[2], w, h, x, y);
+ 720, 360, 360, 720, 16, 0, 0
+ 720, 360, 360, 720, 16, 0, 16
+ ...
+ 720, 360, 360, 720, 16, 0, 544
+ 720, 360, 360, 720, 16, 0, 560
+*/
+#if 0
+static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
+{
+ uint8_t *s;
+ uint8_t *d;
+ int i;
+ int j;
+ int dstride = image_width;
+ int size = image_width*image_height;
+
+ stride[0]<<=1;
+ stride[1]<<=1;
+ stride[2]<<=1;
+
+ // copy Y
+ d=image+dstride/2*y+x;
+ s=src[0];
+ for(i=0;i<h;i+=2){
+ for (j=0; j<w; j+=2)
+ d[j>>1]=s[j];
+ s+=stride[0];
+ d+=dstride;
+ }
+
+ w/=2;h/=2;x/=2;y/=2; dstride/=2;
+
+ // copy U
+ d=image + size + dstride/2*y+x;
+ s=src[1];
+ for(i=0;i<h;i+=2){
+ for (j=0; j<w; j+=2)
+ d[j>>1]=s[j];
+ s+=stride[1];
+ d+=dstride;
+ }
+
+ // copy V
+ d=image + size + size/4 + dstride/2*y+x;
+ s=src[2];
+ for(i=0;i<h;i+=2){
+ for (j=0; j<w; j+=2)
+ d[j>>1]=s[j];
+ s+=stride[2];
+ d+=dstride;
+ }
+
+ return 0;
+}
+#endif
+static void draw_osd(void)
+{
+}
+
+static void put_image(void)
+{
+ int size = image_width*image_height*3;
+ if (write(devout, image, size) != size) {
+ perror("V4L: Error writing image to pipe!");
+ }
+}
+
+static void flip_page(void)
+{
+ put_image();
+}
+
+static uint32_t draw_frame(uint8_t *src[])
+{
+ memcpy (image, src, image_width * image_height * 3);
+ return 0;
+}
+
+static uint32_t query_format(uint32_t format)
+{
+ switch(format){
+ case IMGFMT_YV12:
+ case IMGFMT_YUY2:
+ case IMGFMT_RGB24:
+ case IMGFMT_BGR24:
+ 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)
+{
+
+ image_width = width;
+ image_height = height;
+ image_format = format;
+
+ switch (image_format) {
+ case IMGFMT_YV12:
+ case IMGFMT_I420:
+ fmt = VIDEO_PALETTE_YUV420P;
+ break;
+ case IMGFMT_RGB24:
+ case IMGFMT_BGR24:
+ fmt = VIDEO_PALETTE_RGB24;
+ break;
+ }
+
+ if (check_vidpipe() != 0) {
+ return (1);
+ }
+
+
+ if (start_pipe(devout, width, height) != 0) {
+ return (1);
+ }
+
+ /* printf("V4L: width: %d; height: %d; format: %d\n", width, height, format); */
+
+ image = (uint8_t *) malloc(width*height*3);
+
+ if (!image) {
+ close (devout);
+ return (1);
+ }
+ /* clear the buffer, grey */
+ memset(image,0x80,width*height*3);
+
+ return 0;
+}
+
+static const vo_info_t*
+get_info(void)
+{
+ return &vo_info;
+}
+
+static void
+uninit(void)
+{
+ if (image)
+ free(image);
+ close (devout);
+}
+
+
+static void check_events(void)
+{
+}
More information about the MPlayer-dev-eng
mailing list