- Reestructuración de ficheros y directorios general
- merge v0.01 --> Añadido fileselector - Añadidas fuentes de Gem y Pure Data - pix2jpg incluído en Gem. Archivos de construcción de Gem modificados. - Añadido fichero ompiling.txt con instrucciones de compilación
This commit is contained in:
parent
c9adfd020b
commit
e85d191b46
3100 changed files with 775434 additions and 3073 deletions
480
Gem/plugins/recordV4L/recordV4L.cpp
Normal file
480
Gem/plugins/recordV4L/recordV4L.cpp
Normal file
|
@ -0,0 +1,480 @@
|
|||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// GEM - Graphics Environment for Multimedia
|
||||
//
|
||||
// zmoelnig@iem.kug.ac.at
|
||||
//
|
||||
// Implementation file
|
||||
//
|
||||
// Copyright (c) 1997-1999 Mark Danks.
|
||||
// Copyright (c) Günther Geiger.
|
||||
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
|
||||
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "recordV4L.h"
|
||||
|
||||
#ifdef HAVE_VIDEO4LINUX
|
||||
|
||||
#include "Gem/Manager.h"
|
||||
#include "plugins/PluginFactory.h"
|
||||
|
||||
using namespace gem::plugins;
|
||||
|
||||
#include "Gem/Exception.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
REGISTER_RECORDFACTORY("V4L", recordV4L);
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
// recordV4L
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
recordV4L :: recordV4L(void):
|
||||
m_fd(-1),
|
||||
m_init(false),
|
||||
m_palette(0)
|
||||
{
|
||||
m_image.xsize=720;
|
||||
m_image.xsize=576;
|
||||
m_image.setCsizeByFormat(GL_YUV422_GEM);
|
||||
m_image.setCsizeByFormat(GL_RGBA);
|
||||
m_image.reallocate();
|
||||
|
||||
switch(m_image.format) {
|
||||
case GL_YUV422_GEM: m_palette = VIDEO_PALETTE_YUV422; break;
|
||||
case GL_LUMINANCE: m_palette = VIDEO_PALETTE_GREY; break;
|
||||
case GL_RGBA: m_palette = VIDEO_PALETTE_RGB32; break;
|
||||
default: throw(GemException("invalid colorspace"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// Destructor
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
recordV4L :: ~recordV4L(void)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void recordV4L :: stop(void)
|
||||
{
|
||||
if(m_fd>=0)
|
||||
::close(m_fd);
|
||||
m_fd=-1;
|
||||
|
||||
}
|
||||
|
||||
bool recordV4L :: start(const std::string filename, gem::Properties&props)
|
||||
{
|
||||
stop();
|
||||
|
||||
m_fd=::open(filename.c_str(), O_RDWR);
|
||||
if(m_fd<0)return false;
|
||||
|
||||
struct video_picture vid_pic;
|
||||
if (ioctl(m_fd, VIDIOCGPICT, &vid_pic) == -1) {
|
||||
perror("VIDIOCGPICT");
|
||||
stop(); return false;
|
||||
}
|
||||
vid_pic.palette = m_palette;
|
||||
if (ioctl(m_fd, VIDIOCSPICT, &vid_pic) == -1) {
|
||||
perror("VIDIOCSPICT");
|
||||
stop(); return false;
|
||||
}
|
||||
|
||||
struct video_window vid_win;
|
||||
if (ioctl(m_fd, VIDIOCGWIN, &vid_win) == -1) {
|
||||
perror("(VIDIOCGWIN)");
|
||||
stop(); return false;
|
||||
}
|
||||
|
||||
m_init=false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool recordV4L::init(const imageStruct* dummyImage, const int framedur) {
|
||||
if(m_init)return true;
|
||||
if(m_fd<0)return false;
|
||||
|
||||
unsigned int w=dummyImage->xsize;
|
||||
unsigned int h=dummyImage->ysize;
|
||||
|
||||
struct video_picture vid_pic;
|
||||
struct video_window vid_win;
|
||||
|
||||
if (ioctl(m_fd, VIDIOCGPICT, &vid_pic) == -1) {
|
||||
perror("VIDIOCGPICT");
|
||||
stop(); return false;
|
||||
}
|
||||
|
||||
vid_pic.palette = m_palette;
|
||||
|
||||
if (ioctl(m_fd, VIDIOCSPICT, &vid_pic) == -1) {
|
||||
perror("VIDIOCSPICT");
|
||||
stop(); return false;
|
||||
}
|
||||
|
||||
if (ioctl(m_fd, VIDIOCGWIN, &vid_win) == -1) {
|
||||
perror("ioctl (VIDIOCGWIN)");
|
||||
stop(); return false;
|
||||
}
|
||||
|
||||
vid_win.width = w;
|
||||
vid_win.height = h;
|
||||
if (ioctl(m_fd, VIDIOCSWIN, &vid_win) == -1) {
|
||||
perror("ioctl (VIDIOCSWIN)");
|
||||
stop(); return false;
|
||||
}
|
||||
|
||||
m_image.xsize=w;
|
||||
m_image.ysize=h;
|
||||
m_image.reallocate();
|
||||
|
||||
m_init=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// do the actual encoding and writing to file
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
bool recordV4L :: write(imageStruct*img)
|
||||
{
|
||||
if(!m_init){
|
||||
if(!init(img, 0))
|
||||
return false;
|
||||
}
|
||||
m_image.convertFrom(img);
|
||||
|
||||
// m_image.upsidedown=!m_image.upsidedown;
|
||||
m_image.fixUpDown();
|
||||
|
||||
int size=m_image.xsize*m_image.ysize*m_image.csize;
|
||||
|
||||
::write(m_fd, m_image.data, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// get number of codecs
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
static const std::string s_codec_name=std::string("v4l");
|
||||
static const std::string s_codec_desc=std::string("v4l(1) loopback device");
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// set codec by name
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
bool recordV4L :: setCodec(const std::string name)
|
||||
{
|
||||
if(name==s_codec_name)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// get codecs
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
std::vector<std::string>recordV4L::getCodecs(void) {
|
||||
std::vector<std::string>result;
|
||||
result.push_back(s_codec_name);
|
||||
return result;
|
||||
}
|
||||
const std::string recordV4L::getCodecDescription(const std::string codec) {
|
||||
std::string result;
|
||||
if(codec==s_codec_name)
|
||||
result=s_codec_desc;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool recordV4L::enumProperties(gem::Properties&props) {
|
||||
props.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* V4L */
|
||||
|
||||
#if 0
|
||||
/* handler for ioctls from the client */
|
||||
static int v4l_ioctlhandler(unsigned long int cmd, void *arg)
|
||||
{
|
||||
switch(cmd) {
|
||||
|
||||
/* capabilities */
|
||||
case VIDIOCGCAP: {
|
||||
struct video_capability *vidcap = arg;
|
||||
|
||||
snprintf(vidcap->name, 32, "Gem vloopback output");
|
||||
vidcap->type = VID_TYPE_CAPTURE;
|
||||
vidcap->channels = 1;
|
||||
vidcap->audios = 0;
|
||||
vidcap->maxwidth = MAX_WIDTH;
|
||||
vidcap->maxheight = MAX_HEIGHT;
|
||||
vidcap->minwidth = MIN_WIDTH;
|
||||
vidcap->minheight = MIN_HEIGHT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* channel info (rather limited */
|
||||
case VIDIOCGCHAN: {
|
||||
struct video_channel *vidchan = arg;
|
||||
|
||||
if(vidchan->channel != 0)
|
||||
return EINVAL;
|
||||
vidchan->flags = 0;
|
||||
vidchan->tuners = 0;
|
||||
vidchan->type = VIDEO_TYPE_CAMERA;
|
||||
strncpy(vidchan->name, "Gem", 32);
|
||||
return 0;
|
||||
}
|
||||
/* setting channel (we only have one) */
|
||||
case VIDIOCSCHAN: {
|
||||
int *v = arg;
|
||||
if(v[0] != 0)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getting picture properties */
|
||||
case VIDIOCGPICT: {
|
||||
struct video_picture *vidpic = arg;
|
||||
|
||||
vidpic->colour = 0xffff;
|
||||
vidpic->hue = 0xffff;
|
||||
vidpic->brightness = 0xffff;
|
||||
vidpic->contrast = 0xffff;
|
||||
vidpic->whiteness = 0xffff;
|
||||
vidpic->depth = pixel_depth;
|
||||
vidpic->palette = pixel_format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* setting picture properties: we just ignore this */
|
||||
/* LATER: don't we have to set the vidpic to the "real" values? */
|
||||
case VIDIOCSPICT: {
|
||||
struct video_picture *vidpic = arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VIDIOCGWIN: {
|
||||
struct video_window *vidwin = arg;
|
||||
|
||||
vidwin->x = 0;
|
||||
vidwin->y = 0;
|
||||
vidwin->width = vloopback_width;
|
||||
vidwin->height = vloopback_height;
|
||||
vidwin->chromakey = 0;
|
||||
vidwin->flags = 0;
|
||||
vidwin->clipcount = 0;
|
||||
}
|
||||
|
||||
case VIDIOCSWIN: {
|
||||
struct video_window *vidwin = arg;
|
||||
|
||||
if(vidwin->width > MAX_WIDTH || vidwin->height > MAX_HEIGHT)
|
||||
return EINVAL;
|
||||
if(vidwin->width < MIN_WIDTH || vidwin->height < MIN_HEIGHT)
|
||||
return EINVAL;
|
||||
if(vidwin->flags)
|
||||
return EINVAL;
|
||||
vloopback_width = vidwin->width;
|
||||
vloopback_height = vidwin->height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VIDIOCSYNC: {
|
||||
int frame = *(int *)arg;
|
||||
int ret = 0;
|
||||
|
||||
if(frame < 0 || frame > 1)
|
||||
return EINVAL;
|
||||
gbuf_lock();
|
||||
switch(gbufstat[frame]) {
|
||||
case GBUFFER_UNUSED:
|
||||
ret = 0;
|
||||
break;
|
||||
case GBUFFER_GRABBING:
|
||||
while(gbufstat[frame] == GBUFFER_GRABBING) {
|
||||
pthread_cond_wait(&gbufcond, &gbufmutex);
|
||||
}
|
||||
if(gbufstat[frame] == GBUFFER_DONE) {
|
||||
gbufstat[frame] = GBUFFER_UNUSED;
|
||||
ret = 0;
|
||||
} else {
|
||||
gbufstat[frame] = GBUFFER_UNUSED;
|
||||
ret = EIO;
|
||||
}
|
||||
break;
|
||||
case GBUFFER_DONE:
|
||||
gbufstat[frame] = GBUFFER_UNUSED;
|
||||
ret = 0;
|
||||
break;
|
||||
case GBUFFER_ERROR:
|
||||
default:
|
||||
gbufstat[frame] = GBUFFER_UNUSED;
|
||||
ret = EIO;
|
||||
break;
|
||||
}
|
||||
gbuf_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
case VIDIOCMCAPTURE: {
|
||||
struct video_mmap *vidmmap = arg;
|
||||
|
||||
if(vidmmap->width > MAX_WIDTH || vidmmap->height > MAX_HEIGHT) {
|
||||
fprintf(stderr, "vloopback: requested capture size is too big(%dx%d).\n",vidmmap->width, vidmmap->height);
|
||||
return EINVAL;
|
||||
}
|
||||
if(vidmmap->width < MIN_WIDTH || vidmmap->height < MIN_HEIGHT) {
|
||||
fprintf(stderr, "vloopback: requested capture size is to small(%dx%d).\n",vidmmap->width, vidmmap->height);
|
||||
return EINVAL;
|
||||
}
|
||||
if(vidmmap->format != pixel_format) {
|
||||
converter = palette_get_supported_converter_fromRGB32(vidmmap->format);
|
||||
if(converter == NULL) {
|
||||
fprintf(stderr, "vloopback: unsupported pixel format(%d) is requested.\n",vidmmap->format);
|
||||
return EINVAL;
|
||||
}
|
||||
pixel_format = vidmmap->format;
|
||||
}
|
||||
if(vidmmap->frame > 1 || vidmmap->frame < 0)
|
||||
return EINVAL;
|
||||
vloopback_width = vidmmap->width;
|
||||
vloopback_height = vidmmap->height;
|
||||
|
||||
if(gbufstat[vidmmap->frame] != GBUFFER_UNUSED) {
|
||||
if(gbufqueue[0] == vidmmap->frame || gbufqueue[1] == vidmmap->frame) {
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
gbuf_lock();
|
||||
gbufstat[vidmmap->frame] = GBUFFER_GRABBING;
|
||||
if(gbufqueue[0] < 0) {
|
||||
gbufqueue[0] = vidmmap->frame;
|
||||
} else {
|
||||
gbufqueue[1] = vidmmap->frame;
|
||||
}
|
||||
gbuf_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VIDIOCGMBUF: {
|
||||
struct video_mbuf *vidmbuf = arg;
|
||||
|
||||
vidmbuf->size = max_gbufsize;
|
||||
vidmbuf->frames = 2;
|
||||
vidmbuf->offsets[0] = 0;
|
||||
vidmbuf->offsets[1] = max_framesize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return EPERM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int signal_loop_init(void)
|
||||
{
|
||||
outputfd = open(output_devname, O_RDWR);
|
||||
if(outputfd < 0) {
|
||||
fprintf(stderr, "vloopback: couldn't open output device file %s\n",output_devname);
|
||||
return -1;
|
||||
}
|
||||
pixel_format = VIDEO_PALETTE_RGB32;
|
||||
pixel_depth = 4;
|
||||
converter = palette_get_supported_converter_fromRGB32(pixel_format);
|
||||
vloopback_width = screen_width;
|
||||
vloopback_height = screen_height;
|
||||
max_framesize = vloopback_width * vloopback_height * sizeof(RGB32);
|
||||
max_gbufsize = max_framesize * 2;
|
||||
gbuf = vloopback_mmap(outputfd, max_gbufsize);
|
||||
gbuf_clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *signal_loop(void *arg)
|
||||
{
|
||||
int signo;
|
||||
int size, ret;
|
||||
struct pollfd ufds;
|
||||
sigset_t sigset;
|
||||
unsigned long int cmd;
|
||||
|
||||
if(signal_loop_init()) {
|
||||
signal_loop_initialized = -1;
|
||||
return NULL;
|
||||
}
|
||||
signal_loop_initialized = 1;
|
||||
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGIO);
|
||||
while(signal_loop_thread_flag) {
|
||||
sigwait(&sigset, &signo);
|
||||
if(signo != SIGIO)
|
||||
continue;
|
||||
ufds.fd = outputfd;
|
||||
ufds.events = POLLIN;
|
||||
ufds.revents = 0;
|
||||
poll(&ufds, 1, 1000);
|
||||
if(!ufds.revents & POLLIN) {
|
||||
fprintf(stderr, "vloopback: received signal but got negative on poll.\n");
|
||||
continue;
|
||||
}
|
||||
size = read(outputfd, ioctlbuf, MAXIOCTL);
|
||||
if(size >= sizeof(unsigned long int)) {
|
||||
memcpy(&cmd, ioctlbuf, sizeof(unsigned long int));
|
||||
if(cmd == 0) {
|
||||
fprintf(stderr, "vloopback: client closed device.\n");
|
||||
gbuf_lock();
|
||||
gbuf_clear();
|
||||
gbuf_unlock();
|
||||
continue;
|
||||
}
|
||||
ret = v4l_ioctlhandler(cmd, ioctlbuf+sizeof(unsigned long int));
|
||||
if(ret) {
|
||||
/* new vloopback patch supports a way to return EINVAL to
|
||||
* a client. */
|
||||
memset(ioctlbuf+sizeof(unsigned long int), 0xff, MAXIOCTL-sizeof(unsigned long int));
|
||||
fprintf(stderr, "vloopback: ioctl %lx unsuccessfully handled.\n", cmd);
|
||||
ioctl(outputfd, VIDIOCSINVALID);
|
||||
}
|
||||
if(ioctl(outputfd, cmd, ioctlbuf+sizeof(unsigned long int))) {
|
||||
fprintf(stderr, "vloopback: ioctl %lx unsuccessfull.\n", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue