[MPlayer-dev-eng] VO_V4lw With MPlayer 1.0rc1

Federico Lorenzi florenzi at gmail.com
Mon Jun 4 07:43:56 CEST 2007


Hello list!

After browsing around for a bit about how I could get V4L loopback output,
I came across the vo_v4lw module for mplayer. Being really outdated from
2001, I searched some more and came across a much more recent revision
located at:
http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/2006-April/042586.html

However, this version is for MPlayer0.9pre7try2, which doesn't compile
cleanly on
my current system. Not only that but it uses the old version of vloopback, which
doesn't work on 2.6 kernels. Having absolutely no C knowledge at this stage, I
decided to do some hacking up of the module, and I can get it to compile, and
mplayer runs cleanly with it. The problem arises when i try and get
something to
listen to /dev/video1. This just crashes both running MPlayers into some unknown
state in which killall -KILL fails to kill them.

I have attached my vo_v4lw.c source file, and please remember I know NOTHING
about C, if someone with knowledge could take a look at it and help
fix it out, I
would be most grateful. Most of the source code in here comes from the vloopback
example files, so they would be a good place to look at.


Thanks in advance,
Federico


--  vo_v4lw.c --
#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 <errno.h>
#include <sys/poll.h>
#include <dirent.h>
#include <sys/utsname.h>

#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; i<width-10; i++) {
		image_out[10*width*3+i*3]=colour++;
		image_out[10*width*3+i*3+1]=0;
		image_out[10*width*3+i*3+2]=-colour;
	}
	for (i=10; i<width-10; i++) {
		image_out[(height-10)*width*3+i*3]=colour;
		image_out[(height-10)*width*3+i*3+1]=0;
		image_out[(height-10)*width*3+i*3+2]=-colour++;
	}
	/*
	*/
	usleep(500); /* BIG XXX */
	return 0;
}
	

int v4l_ioctl(unsigned long int cmd, void *arg)
{
        int i;
        switch (cmd) {
                case VIDIOCGCAP:
                {
                        struct video_capability *vidcap=arg;

                        sprintf(vidcap->name, "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; i<vidmbuf->frames; 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;
}

#define VIDIOCSINVALID	_IO('v',BASE_VIDIOCPRIVATE+1)

static vo_info_t info =
{
	"video4linux write output",
	"v4lw",
	"Tilmann Bitterberg <god at tibit.org>",
	"update 4/27/06 sfanzyshen <sfranzyshen at hotmail.com>"
};

LIBVO_EXTERN(v4lw)

int open_vidpipe(void)
{
	int pipe_fd = -1;
	devout = open("/dev/video0", O_RDWR);
        pipe_fd = devout;
        if (pipe_fd >= 0)
                printf("INFO: Opened input of %i\n", 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;

	if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) {
		printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno));
		return (1);
	}
	if (ioctl (dev, VIDIOCGPICT, &vid_pic)== -1) {
		printf ("ioctl VIDIOCGPICT\nError[%s]\n",strerror(errno));
		return (1);
	}
	vid_pic.palette=fmt;
	if (ioctl (dev, VIDIOCSPICT, &vid_pic)== -1) {
		printf ("ioctl VIDIOCSPICT\nError[%s]\n",strerror(errno));
		return (1);
	}
	if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) {
		printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno));
		return (1);
	}
	vid_win.width=width;
	vid_win.height=height;
	if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) {
		printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno));
		return (1);
	}
	return 0;
}

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<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;
}



static void draw_osd(void)
{
}

static void put_image(void)
{
	int size = image_width*image_height*3;
	printf("writing...");
	if (write(devout, image_out, size) != size) {
		perror("ERROR: Error writing image to pipe!\n");
	}
}


static void flip_page(void)
{
	put_image();
}

static int draw_frame(uint8_t *src[])
{
	printf("INFO: Started drawframe\n");
	memcpy (image, src, image_width * image_height * 3);
	return 0;
}

static int query_format(uint32_t format)
{
	switch(format){
		case IMGFMT_YV12:
		case IMGFMT_I420:
		case IMGFMT_YUY2:
		case IMGFMT_RGB24:
		case IMGFMT_BGR24:
			return 1;
	}
	return 0;
}

static int config (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;
	}

	open_vidpipe();


	if (start_pipe(devout, width, height) != 0) {
		printf("ERROR: Could not start pipe\n");
		return 1;
	}

	printf("INFO: width: %d; height: %d; format: %d\n", width, height, format);

	image = (int8_t *) malloc(width*height*3);
	printf("INFO: Image Created %d\n",image);
	if (!image) {
		printf("ERROR: Image could not be created properly!\n");
		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 &info;
}

static void
uninit(void)
{
	if (image)
		free(image);
	printf("INFO: Device closed in exit\n");
	close (devout);
}


static void check_events(void)
{
}
static int preinit(const char *arg)
{
  return 0;
}

static int control(uint32_t request, void *data, ...)
{
  switch (request) {
  case VOCTRL_QUERY_FORMAT:
    return query_format(*((uint32_t*)data));
  }
  return VO_NOTIMPL;
}
-- end --



More information about the MPlayer-dev-eng mailing list