Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]
Return to module

File Contents

Contents of /v4l2-0.1/_v4l2.cmod:

/* Video 4 Linux v2 module for Pike
   Copyright Ian Carr-de Avelon 2004-2006 
   GPL applies
 */

#define VIDEOMAX 1000000
#include "util.h"
#include "math.h"



//Includes for Pike
#include "global.h"
#include "image.h"

#include "interpret.h"
#include "svalue.h"
#include "module.h"
#include "stralloc.h"
#include "array.h"
#include "pike_macros.h"
#include "program.h"
#include "object.h"
#include "interpret.h"
#include "pike_error.h"
#include "pike_types.h"
#include "threads.h"
#include "dynamic_buffer.h"
#include "builtin_functions.h"

//Includes for v4l2
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <asm/types.h>          /* for videodev2.h */
#include "videodev2.h"

#include <fcntl.h>              /* low-level i/o */
#include <errno.h>              /* for errno surprise! */

//#define HAVE_STDINT_H

#define CLEAR(x) memset (&(x), 0, sizeof (x))


struct buffer {
        void *                  start;
        size_t                  length;
};

struct v4l2_state {
	struct buffer * buffers;
	struct v4l2_buffer buf;
	int n_buffers;
};

static int xioctl(int fd, int request, void * arg){
int r;
do r = ioctl (fd, request, arg);
	while (-1 == r && EINTR == errno);
return r;
}


PIKECLASS  lowlevel {
/* Global variables */
CVAR struct v4l2_state  state;



PIKEFUN mapping init(int fd){
int out;
struct v4l2_capability cap;

        out=ioctl (fd, VIDIOC_QUERYCAP, &cap);
	if(out==-1)
		RETURN(0);
//FIXME add checking
pop_n_elems(1);
      push_text("driver");
      push_string(make_shared_string(cap.driver));
      push_text("card");
      push_string(make_shared_string(cap.card));
      push_text("bus_info");
      push_string(make_shared_string(cap.bus_info));
      push_text("version");
      push_int(cap.version);
      push_text("capabilities");
      push_int(cap.capabilities);

  f_aggregate_mapping(10);
}

PIKEFUN mapping enumerate_inputs(int fd, int index){
int out;
struct v4l2_input in;
in.index=index;
pop_n_elems(2);
out=ioctl (fd, VIDIOC_ENUMINPUT, &in);
if(out==-1)
	RETURN(0);
//FIXME add checking
      push_text("index");
      push_int(in.index);
      push_text("name");
      push_string(make_shared_string(in.name));
      push_text("type");
      push_int(in.type);
      push_text("audioset");
      push_int(in.audioset);
      push_text("tuner");
      push_int(in.tuner);
//      push_text("v4l2_std_id");
//      push_int(in.v4l2_std_id);
      push_text("status");
      push_int(in.status);
  f_aggregate_mapping(12);
}

PIKEFUN int current_input(int fd){
int out,*in;

pop_n_elems(1);
        out=ioctl (fd, VIDIOC_G_INPUT, in);
        if(out==-1)
                RETURN(0);
//FIXME add checking
RETURN(*in);
}

PIKEFUN int select_input(int fd){
int out,*in;

pop_n_elems(1);
        out=ioctl (fd, VIDIOC_S_INPUT, in);
        if(out==-1)
                RETURN(0);
//FIXME add checking
RETURN(1);
}

PIKEFUN mapping enumerate_audio(int fd, int index){
int out;
struct v4l2_audio audio;
audio.reserved[0]=0;
audio.reserved[1]=0;
audio.index=index;
out=ioctl (fd, VIDIOC_ENUMAUDIO, &audio);
pop_n_elems(2);
if(out==-1)
        RETURN(0);
//FIXME add checking
      push_text("index");
      push_int(audio.index);
      push_text("name");
      push_string(make_shared_string(audio.name));
      push_text("capability");
      push_int(audio.capability);
      push_text("mode");
      push_int(audio.mode);
  f_aggregate_mapping(8);
}

PIKEFUN mapping current_audio(int fd){
int out;
struct v4l2_audio audio;
audio.reserved[0]=0;
audio.reserved[1]=0;
out=ioctl (fd, VIDIOC_G_AUDIO, &audio);
if(out==-1)
        RETURN(0);
//FIXME add checking
pop_n_elems(1);
      push_text("index");
      push_int(audio.index);
      push_text("name");
      push_string(make_shared_string(audio.name));
      push_text("capability");
      push_int(audio.capability);
      push_text("mode");
      push_int(audio.mode);
  f_aggregate_mapping(8);
}
 

PIKEFUN int set_audio(int fd, int index, int mode){
int out;
struct v4l2_audio audio;
audio.reserved[0]=0;
audio.reserved[1]=0;
audio.index=index;
audio.mode=mode;
pop_n_elems(3);
out=ioctl (fd, VIDIOC_S_AUDIO, &audio);
if(out==-1)
        RETURN(0);
RETURN(1);	
}

PIKEFUN mapping query_tuner(int fd, int index){
int out;
struct v4l2_tuner tuner;
tuner.index=index;
out=ioctl (fd, VIDIOC_G_TUNER, &tuner);
if(out==-1)
        RETURN(0);
pop_n_elems(2);
      push_text("index");
      push_int(tuner.index);
      push_text("name");
      push_string(make_shared_string(tuner.name));
      push_text("type");
      push_int((int)tuner.type);
      push_text("capability");
      push_int(tuner.capability);
      push_text("rangelow");
      push_int(tuner.rangelow);
      push_text("rangehigh");
      push_int(tuner.rangehigh);
      push_text("rxsubchans");
      push_int(tuner.rxsubchans);
  f_aggregate_mapping(14);
}

PIKEFUN int set_tuner_mode(int fd, int index, int mode){
int out;
struct v4l2_audio audio;
audio.index=index;
audio.mode=mode;
out=ioctl (fd, VIDIOC_S_TUNER, &audio);
pop_n_elems(3);
if(out==-1)
        RETURN(0);
RETURN(1);
}
//FIXME and the frequency

PIKEFUN string current_standard(int fd){
int out;
v4l2_std_id standard;

pop_n_elems(1);
out=ioctl (fd, VIDIOC_G_STD, &standard);
if(out==-1)
        RETURN(0);
      push_string(make_shared_binary_string((char*)&standard,8));
}

PIKEFUN string set_standard(int fd, string newstd){
int out;
//IAN check string is 8 characters
out=ioctl (fd, VIDIOC_G_STD, &newstd->str);
pop_n_elems(2);
if(out==-1)
        RETURN(0);
      push_string(make_shared_binary_string((char*)newstd->str,8));
}

PIKEFUN string query_controls(int fd, int id){
int out;
struct v4l2_queryctrl query;
query.id=id;
out=ioctl (fd, VIDIOC_QUERYCTRL, &query);
pop_n_elems(2);
if(out==-1)
        RETURN(0);
      push_text("id");
      push_int(query.id);
      push_text("type");
      push_int((int)query.type);
      push_text("name");
      push_string(make_shared_string(query.name));
      push_text("minimum");
      push_int(query.minimum);
      push_text("maximum");
      push_int(query.maximum);
      push_text("step");
      push_int(query.step);
      push_text("default_value");
      push_int(query.default_value);
      push_text("flags");
      push_int(query.flags);
  f_aggregate_mapping(16);
}

PIKEFUN string query_menu(int fd, int id, int index){
int out;
struct v4l2_querymenu query;
query.id=id;
query.index=index;
out=ioctl (fd, VIDIOC_QUERYMENU, &query);
pop_n_elems(3);
if(out==-1)
        RETURN(0);
      push_text("id");
      push_int(query.id);
      push_text("index");
      push_int(query.index);
      push_text("name");
      push_string(make_shared_string(query.name));
  f_aggregate_mapping(6);
}

PIKEFUN int set_control(int fd, int id, int value){
int out;
struct v4l2_control set;
set.id=id;
set.value=value;
out=ioctl (fd, VIDIOC_S_CTRL, &set);
pop_n_elems(3);
if(out==-1)
        RETURN(0);
RETURN(1);
}

PIKEFUN string enumerate_formats(int fd, int index, int type){
int out;
struct v4l2_fmtdesc query;
query.index=index;
query.type=(enum v4l2_buf_type)type;
out=ioctl (fd, VIDIOC_ENUM_FMT, &query);
pop_n_elems(3);
if(out==-1)
        RETURN(0);
      push_text("index");
      push_int(query.index);
      push_text("type");
      push_int((int)query.type);
      push_text("flags");
      push_int(query.flags);
      push_text("description");
      push_string(make_shared_string(query.description));
      push_text("pixelformat");
      push_int(query.pixelformat);
  f_aggregate_mapping(10);
}

PIKEFUN mapping get_format(int fd){
int out;
struct v4l2_format query;
out=ioctl (fd, VIDIOC_G_FMT, &query);
//if(out==-1)
//        RETURN(0);
pop_n_elems(1);
      push_text("type");
      push_int((int)query.type);
/* FIXME check which type and add information in the union
//v4l2_pix_format
      push_text("width");
      push_int(query.pix.width);
      push_text("height");
      push_int(query.pix.height);
      push_text("pixelformat");
      push_int(query.pix.pixelformat);
      push_text("field");
      push_int((int *)query.pix.field);
      push_text("bytesperline");
      push_int(query.pix.bytesperline);
      push_text("sizeimage");
      push_int(query.pix.sizeimage);
      push_text("colorspace");
      push_int((int *)query.pix.colorspace);
//v4l2_window
//v4l2_rect
      push_text("left");
      push_int(query.win.w.left);
      push_text("top");
      push_int(query.win.w.top);
      push_text("width");
      push_int(query.win.w.width);
      push_text("height");
      push_int(query.win.w.height);
      push_text("field");
      push_int((int *)query.win.field);
      push_text("chromakey");
      push_int(query.win.chromakey);
//FIXME there can be multiple cliping frames
//v4l2_clip
//v4l2_rect
      push_text("clip left");
      push_int(query.win.clips.c.left);
      push_text("clip top");
      push_int(query.win.clips.c.top);
      push_text("clip width");
      push_int(query.win.clips.c.width);
      push_text("clip height");
      push_int(query.win.clips.c.height);
      push_text("clipcount");
      push_int(query.win.clipcount); 
  f_aggregate_mapping(38);
 */
  f_aggregate_mapping(2);
}


PIKEFUN int device_init(int fd, int width, int height){
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
unsigned int min;

pop_n_elems(3);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
		crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		crop.c = cropcap.defrect; /* reset to default */
		if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
			switch (errno) {
				case EINVAL:
                                /* Cropping not supported. */
                                break;
                        default:
                                /* Errors ignored. */
                                break;
                        	}
                	}
        } else {
                /* Errors ignored. */
        }

        CLEAR (fmt);
        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmt.fmt.pix.width       = width;
        fmt.fmt.pix.height      = height;
//saa7134 V4L2_PIX_FMT_RGB24 snafu
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
        if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)){
		push_int(-1);
		return;
		}
        /* Note VIDIOC_S_FMT may change width and height. */
        /* Buggy driver paranoia. */
        min = fmt.fmt.pix.width * 2;
        if (fmt.fmt.pix.bytesperline < min)
                fmt.fmt.pix.bytesperline = min;
        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
        if (fmt.fmt.pix.sizeimage < min)
                fmt.fmt.pix.sizeimage = min;
push_int(1);
return;
}

//start grabbing frames using user pointers. 
//"no" is the number of buffers to setup and queue
PIKEFUN int start(int fd, int no){
int i;
enum v4l2_buf_type type;
struct v4l2_requestbuffers reqbuf;
pop_n_elems(2);
memset (&reqbuf, 0, sizeof (reqbuf));
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = no;

if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
        if (errno == EINVAL){
		push_int(-1);
		return;
		}
	}

THIS->state.buffers = calloc (reqbuf.count, sizeof (*THIS->state.buffers));
//assert (THIS->state.buffers != NULL);
if(THIS->state.buffers == NULL){
	push_int(-10);
	return;
	}

for (i = 0; i < reqbuf.count; i++) {
        struct v4l2_buffer buffer;
        memset (&buffer, 0, sizeof (buffer));
        buffer.type = reqbuf.type;
        buffer.memory = V4L2_MEMORY_MMAP;
        buffer.index = i;
        if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
		push_int(-2);
		return;
		}
        THIS->state.buffers[i].length = buffer.length; /* remember for munmap() */
        THIS->state.buffers[i].start = mmap (NULL, buffer.length,
                                 PROT_READ | PROT_WRITE, /* required */
/*                                 MAP_SHARED,             / * recommended */
/*				MAP_PRIVATE|MAP_ANONYMOUS, / * other Pike uses */
				MAP_SHARED,
                                 fd, buffer.m.offset);
        if (THIS->state.buffers[i].start == MAP_FAILED) {
                /* You may need to unmap and free the so far
                   mapped buffers here. */
		push_int(errno);
//		push_int(-9);
		return;
		}
        }
for (i = 0; i < reqbuf.count; ++i) {
     struct v4l2_buffer buf;
     CLEAR (buf);
     buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     buf.memory      = V4L2_MEMORY_MMAP;
     buf.index       = i;
     if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)){
//		push_int(-2*i);
		push_int(errno);
		return;
		}
	}
THIS->state.n_buffers=reqbuf.count;

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)){
	push_int(-4);
	return;
	}

push_int(reqbuf.count);
return;
}

PIKEFUN int stop(int fd){
enum v4l2_buf_type type;
int i;

pop_n_elems(1);
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)){
	push_int(0);
	return;
	}
for (i = 0; i < THIS->state.n_buffers; ++i) {
        munmap (THIS->state.buffers[i].start, THIS->state.buffers[i].length);
        }
RETURN(1);
}

PIKEFUN string get_data(int fd){
int i;
struct v4l2_buffer buf;
pop_n_elems(1);
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
      push_string(make_shared_string((char *)strerror(errno)));
	return;
	}

if(buf.index >= THIS->state.n_buffers){
	push_int(-2);
	return;
	}
	
//process_image ((void *) buf.m.userptr);
push_string(make_shared_binary_string((char *)THIS->state.buffers[buf.index].start,THIS->state.buffers[buf.index].length));
if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)){
	push_int(-3);
	return;
	}
return;
}

PIKEFUN object get_image(object rgb, int fd){
struct image *img = NULL;
img=(struct image *)rgb->storage;
rgb_group *pixels;
pixels=img->img;
int i;
char save;
COLORTYPE *data; 
struct v4l2_buffer buf;

pop_n_elems(2);
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
      push_string(make_shared_string((char *)strerror(errno)));
	return;
	}

if(buf.index >= THIS->state.n_buffers){
	push_int(-2);
	return;
	}
	
//memcpy(img->img,(rgb_group *)THIS->state.buffers[buf.index].start,(size_t)THIS->state.buffers[buf.index].length);
//The kernel module gives us RGB, and could give us BGR, but Pike seems to
//use GRB
data=(__u8*)THIS->state.buffers[buf.index].start;
// 3green shown blue, 2red shown green, 
for(i=0;i<img->xsize*img->ysize;i++){
	pixels->b=*data++;
	pixels->r=*data++;
	pixels->g=*data++;
	pixels++;
	data++;
	}
if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)){
	push_int(-3);
	return;
	}
ref_push_object(rgb);
return;
}


}//end class

gotpike.org | Copyright © 2004 - 2011 | Pike is a trademark of Department of Computer and Information Science, Linköping University