mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
first batch
Original commit message from CVS: first batch
This commit is contained in:
parent
49d345d9ef
commit
37c4906a74
6 changed files with 1837 additions and 0 deletions
5
sys/Makefile.am
Normal file
5
sys/Makefile.am
Normal file
|
@ -0,0 +1,5 @@
|
|||
### use HAVE_ stuff to decide on dirs
|
||||
DIRS=qcam v4l vcdsrc vgasink xvideosink
|
||||
|
||||
DIST_SUBDIRS=qcam v4l vcdsrc vgasink xvideosink
|
||||
|
12
sys/v4l/Makefile.am
Normal file
12
sys/v4l/Makefile.am
Normal file
|
@ -0,0 +1,12 @@
|
|||
plugindir = $(libdir)/gst
|
||||
|
||||
plugin_LTLIBRARIES = libv4lsrc.la
|
||||
|
||||
libv4lsrc_la_SOURCES = \
|
||||
gstv4lsrc.c \
|
||||
grab-v4l.c
|
||||
|
||||
## FIXME : do we need -O2 ? libv4lsrc_la_CFLAGS = -O2 $(GST_CFLAGS)
|
||||
libv4lsrc_la_CFLAGS = $(GST_CFLAGS)
|
||||
|
||||
noinst_HEADERS = gstv4lsrc.h grab.h
|
973
sys/v4l/grab-v4l.c
Normal file
973
sys/v4l/grab-v4l.c
Normal file
|
@ -0,0 +1,973 @@
|
|||
/*
|
||||
* interface to the v4l driver
|
||||
*
|
||||
* (c) 1997-99 Gerd Knorr <kraxel@goldbach.in-berlin.de>
|
||||
*
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <endian.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <X11/Intrinsic.h>
|
||||
|
||||
#include <asm/types.h> /* XXX glibc */
|
||||
#include <linux/videodev.h>
|
||||
|
||||
#include "grab.h"
|
||||
|
||||
#define SYNC_TIMEOUT 1
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* experimental, interface might change */
|
||||
#ifndef VIDIOCSWIN2
|
||||
#define VIDIOCSWIN2 _IOW('v',28,struct video_window2)
|
||||
struct video_window2
|
||||
{
|
||||
__u16 palette; /* Palette (aka video format) in use */
|
||||
__u32 start; /* start address, relative to video_buffer.base */
|
||||
__u32 pitch;
|
||||
__u32 width;
|
||||
__u32 height;
|
||||
__u32 flags;
|
||||
|
||||
struct video_clip *clips;
|
||||
int clipcount;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* open+close */
|
||||
static int grab_open(struct GRABBER *grab_v4l, char *filename);
|
||||
static int grab_close(struct GRABBER *grab_v4l);
|
||||
|
||||
/* overlay */
|
||||
static int grab_setupfb(struct GRABBER *grab_v4l, int sw, int sh, int format, void *base, int width);
|
||||
static int grab_overlay(struct GRABBER *grab_v4l, int x, int y, int width, int height, int format,
|
||||
OverlayClip *oc, int count);
|
||||
static int grab_offscreen(struct GRABBER *grab_v4l, int start, int pitch, int width, int height,
|
||||
int format);
|
||||
|
||||
/* capture */
|
||||
static int grab_mm_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height,
|
||||
int *linelength);
|
||||
static void* grab_mm_capture(struct GRABBER *grab_v4l, int single);
|
||||
static void grab_mm_cleanup(struct GRABBER *grab_v4l);
|
||||
static int grab_read_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height,
|
||||
int *linelength);
|
||||
static void* grab_read_capture(struct GRABBER *grab_v4l, int single);
|
||||
static void grab_read_cleanup(struct GRABBER *grab_v4l);
|
||||
|
||||
/* control */
|
||||
static int grab_tune(struct GRABBER *grab_v4l, unsigned long freq);
|
||||
static int grab_tuned(struct GRABBER *grab_v4l);
|
||||
static int grab_input(struct GRABBER *grab_v4l, int input, int norm);
|
||||
static int grab_hasattr(struct GRABBER *grab_v4l, int id);
|
||||
static int grab_getattr(struct GRABBER *grab_v4l, int id);
|
||||
static int grab_setattr(struct GRABBER *grab_v4l, int id, int val);
|
||||
|
||||
/* internal helpers */
|
||||
static int grab_wait(struct GRABBER *grab_v4l, struct video_mmap *gb);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static const char *device_cap[] = {
|
||||
"capture", "tuner", "teletext", "overlay", "chromakey", "clipping",
|
||||
"frameram", "scales", "monochrome", NULL
|
||||
};
|
||||
|
||||
static const char *device_pal[] = {
|
||||
"-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15",
|
||||
"yuv422", "yuyv", "uyvy", "yuv420", "yuv411", "raw",
|
||||
"yuv422p", "yuv411p", "yuv420p", "yuv410p"
|
||||
};
|
||||
#define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN")
|
||||
|
||||
static const struct STRTAB stereo[] = {
|
||||
{ 0, "auto" },
|
||||
{ 1, "mono" },
|
||||
{ 2, "stereo" },
|
||||
{ 4, "lang1" },
|
||||
{ 8, "lang2" },
|
||||
{ -1, NULL, },
|
||||
};
|
||||
static struct STRTAB norms[] = {
|
||||
{ 0, "PAL" },
|
||||
{ 1, "NTSC" },
|
||||
{ 2, "SECAM" },
|
||||
{ 3, "AUTO" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
static const struct STRTAB norms_bttv[] = {
|
||||
{ 0, "PAL" },
|
||||
{ 1, "NTSC" },
|
||||
{ 2, "SECAM" },
|
||||
{ 3, "PAL-NC" },
|
||||
{ 4, "PAL-M" },
|
||||
{ 5, "PAL-N" },
|
||||
{ 6, "NTSC-JP" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
static int gb_pal[] = {
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const unsigned short format2palette[] = {
|
||||
0,/* unused */
|
||||
VIDEO_PALETTE_HI240,/* RGB8 */
|
||||
VIDEO_PALETTE_GREY,/* GRAY8 */
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
0,
|
||||
0,
|
||||
VIDEO_PALETTE_RGB555,/* RGB15_BE */
|
||||
VIDEO_PALETTE_RGB565,/* RGB16_BE */
|
||||
0,
|
||||
0,
|
||||
VIDEO_PALETTE_RGB24,/* RGB24 */
|
||||
VIDEO_PALETTE_RGB32,/* RGB32 */
|
||||
#else
|
||||
VIDEO_PALETTE_RGB555,/* RGB15_LE */
|
||||
VIDEO_PALETTE_RGB565,/* RGB16_LE */
|
||||
0,
|
||||
0,
|
||||
VIDEO_PALETTE_RGB24,/* BGR24 */
|
||||
VIDEO_PALETTE_RGB32,/* BGR32 */
|
||||
0,
|
||||
0,
|
||||
#endif
|
||||
0, /* LUT 2 */
|
||||
0, /* LUT 4 */
|
||||
VIDEO_PALETTE_YUV422, /* YUV422 */
|
||||
VIDEO_PALETTE_YUV422P, /* YUV422P */
|
||||
VIDEO_PALETTE_YUV420P, /* YUV420P */
|
||||
};
|
||||
|
||||
static const unsigned int format2depth[] = {
|
||||
0, /* unused */
|
||||
8, /* RGB8 */
|
||||
8, /* GRAY8 */
|
||||
16, /* RGB15 LE */
|
||||
16, /* RGB16 LE */
|
||||
16, /* RGB15 BE */
|
||||
16, /* RGB16 BE */
|
||||
24, /* BGR24 */
|
||||
32, /* BGR32 */
|
||||
24, /* RGB24 */
|
||||
32, /* RGB32 */
|
||||
16, /* LUT2 */
|
||||
32, /* LUT4 */
|
||||
16, /* YUV422 */
|
||||
16, /* YUV422P */
|
||||
12, /* YUV420P */
|
||||
0, /* MJPEG */
|
||||
};
|
||||
|
||||
static const unsigned char* format_desc[] = {
|
||||
"",
|
||||
"8 bit PseudoColor (dithering)",
|
||||
"8 bit StaticGray",
|
||||
"15 bit TrueColor (LE)",
|
||||
"16 bit TrueColor (LE)",
|
||||
"15 bit TrueColor (BE)",
|
||||
"16 bit TrueColor (BE)",
|
||||
"24 bit TrueColor (LE: bgr)",
|
||||
"32 bit TrueColor (LE: bgr-)",
|
||||
"24 bit TrueColor (BE: rgb)",
|
||||
"32 bit TrueColor (BE: -rgb)",
|
||||
"16 bit TrueColor (lut)",
|
||||
"32 bit TrueColor (lut)",
|
||||
"16 bit YUV 4:2:2",
|
||||
"16 bit YUV 4:2:2 (planar)",
|
||||
"12 bit YUV 4:2:0 (planar)",
|
||||
"MJPEG"
|
||||
};
|
||||
|
||||
|
||||
/* pass 0/1 by reference */
|
||||
static const int one = 1, zero = 0;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
static const struct GRAB_ATTR init_grab_attr[] =
|
||||
{
|
||||
{ GRAB_ATTR_VOLUME, 1, VIDIOCGAUDIO, VIDIOCSAUDIO, NULL },
|
||||
{ GRAB_ATTR_MUTE, 1, VIDIOCGAUDIO, VIDIOCSAUDIO, NULL },
|
||||
{ GRAB_ATTR_MODE, 1, VIDIOCGAUDIO, VIDIOCSAUDIO, NULL },
|
||||
|
||||
{ GRAB_ATTR_COLOR, 1, VIDIOCGPICT, VIDIOCSPICT, NULL },
|
||||
{ GRAB_ATTR_BRIGHT, 1, VIDIOCGPICT, VIDIOCSPICT, NULL },
|
||||
{ GRAB_ATTR_HUE, 1, VIDIOCGPICT, VIDIOCSPICT, NULL },
|
||||
{ GRAB_ATTR_CONTRAST, 1, VIDIOCGPICT, VIDIOCSPICT, NULL },
|
||||
};
|
||||
|
||||
struct GRABBER *grab_init()
|
||||
{
|
||||
struct GRABBER *new_grabber;
|
||||
|
||||
new_grabber = malloc(sizeof(struct GRABBER));
|
||||
|
||||
new_grabber->name = "v4l";
|
||||
new_grabber->flags = 0;
|
||||
new_grabber->norms = norms;
|
||||
new_grabber->inputs = NULL;
|
||||
new_grabber->opened = 0;
|
||||
new_grabber->fd = -1;
|
||||
new_grabber->overlay = 0;
|
||||
new_grabber->audio_modes = stereo;
|
||||
new_grabber->grab_open = grab_open;
|
||||
new_grabber->grab_close = grab_close;
|
||||
new_grabber->grab_setupfb = grab_setupfb;
|
||||
new_grabber->grab_overlay = NULL;
|
||||
new_grabber->grab_offscreen = NULL;
|
||||
new_grabber->grab_setparams = NULL;
|
||||
new_grabber->grab_capture = NULL;
|
||||
new_grabber->grab_cleanup = NULL;
|
||||
new_grabber->grab_tune = grab_tune;
|
||||
new_grabber->grab_tuned = grab_tuned;
|
||||
new_grabber->grab_input = grab_input;
|
||||
new_grabber->grab_hasattr = grab_hasattr;
|
||||
new_grabber->grab_getattr = grab_getattr;
|
||||
new_grabber->grab_setattr = grab_setattr;
|
||||
|
||||
memcpy(new_grabber->grab_attr, init_grab_attr, sizeof(init_grab_attr));
|
||||
|
||||
new_grabber->grab_attr[0].arg = &new_grabber->audio;
|
||||
new_grabber->grab_attr[1].arg = &new_grabber->audio;
|
||||
new_grabber->grab_attr[2].arg = &new_grabber->audio;
|
||||
new_grabber->grab_attr[3].arg = &new_grabber->pict;
|
||||
new_grabber->grab_attr[4].arg = &new_grabber->pict;
|
||||
new_grabber->grab_attr[5].arg = &new_grabber->pict;
|
||||
new_grabber->grab_attr[6].arg = &new_grabber->pict;
|
||||
|
||||
return new_grabber;
|
||||
}
|
||||
|
||||
/* FIXME this isn't used (yet?)
|
||||
static void grab_cleanup(struct GRABBER *grab_v4l)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
static int grab_open(struct GRABBER *grab_v4l, char *filename)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (-1 != grab_v4l->fd)
|
||||
goto err;
|
||||
|
||||
if (-1 == (grab_v4l->fd = open(filename ? filename : "/dev/video",O_RDWR))) {
|
||||
fprintf(stderr,"v4l: open %s: %s\n",
|
||||
filename ? filename : "/dev/video",strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability)) {
|
||||
perror("v4l: open\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
fprintf(stderr, "v4l: open\n");
|
||||
|
||||
fcntl(grab_v4l->fd,F_SETFD,FD_CLOEXEC);
|
||||
|
||||
fprintf(stderr,"v4l: device is %s\n",grab_v4l->capability.name);
|
||||
|
||||
sprintf(grab_v4l->name = malloc(strlen(grab_v4l->capability.name)+8),
|
||||
"v4l: %s",grab_v4l->capability.name);
|
||||
|
||||
fprintf(stderr,"v4l: capabilities: ");
|
||||
for (i = 0; device_cap[i] != NULL; i++)
|
||||
if (grab_v4l->capability.type & (1 << i))
|
||||
fprintf(stderr," %s",device_cap[i]);
|
||||
fprintf(stderr,"\n");
|
||||
|
||||
/* input sources */
|
||||
fprintf(stderr,"v4l: channels: %d\n",grab_v4l->capability.channels);
|
||||
|
||||
grab_v4l->channels = malloc(sizeof(struct video_channel)*grab_v4l->capability.channels);
|
||||
memset(grab_v4l->channels,0,sizeof(struct video_channel)*grab_v4l->capability.channels);
|
||||
|
||||
grab_v4l->inputs = malloc(sizeof(struct STRTAB)*(grab_v4l->capability.channels+1));
|
||||
memset(grab_v4l->inputs,0,sizeof(struct STRTAB)*(grab_v4l->capability.channels+1));
|
||||
|
||||
for (i = 0; i < grab_v4l->capability.channels; i++) {
|
||||
grab_v4l->channels[i].channel = i;
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGCHAN,&grab_v4l->channels[i]))
|
||||
perror("v4l: ioctl VIDIOCGCHAN"), exit(0);
|
||||
grab_v4l->inputs[i].nr = i;
|
||||
grab_v4l->inputs[i].str = grab_v4l->channels[i].name;
|
||||
fprintf(stderr,"v4l: %s: %d %s%s %s%s\n",
|
||||
grab_v4l->channels[i].name,
|
||||
grab_v4l->channels[i].tuners,
|
||||
(grab_v4l->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "",
|
||||
(grab_v4l->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "",
|
||||
(grab_v4l->channels[i].type & VIDEO_TYPE_TV) ? "tv " : "",
|
||||
(grab_v4l->channels[i].type & VIDEO_TYPE_CAMERA) ? "camera " : "");
|
||||
}
|
||||
grab_v4l->inputs[i].nr = -1;
|
||||
grab_v4l->inputs[i].str = NULL;
|
||||
|
||||
/* ioctl probe, switch to input 0 */
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSCHAN,&grab_v4l->channels[0])) {
|
||||
fprintf(stderr,"v4l: you need a newer bttv version (>= 0.5.14)\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* audios */
|
||||
fprintf(stderr,"v4l: audios : %d\n",grab_v4l->capability.audios);
|
||||
|
||||
if (grab_v4l->capability.audios) {
|
||||
grab_v4l->audio.audio = 0;
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGAUDIO,&grab_v4l->audio))
|
||||
perror("v4l: ioctl VIDIOCGCAUDIO") /* , exit(0) */ ;
|
||||
fprintf(stderr,"v4l: %d (%s): ",i,grab_v4l->audio.name);
|
||||
if (grab_v4l->audio.flags & VIDEO_AUDIO_MUTABLE)
|
||||
fprintf(stderr,"muted=%s ",
|
||||
(grab_v4l->audio.flags&VIDEO_AUDIO_MUTE) ? "yes":"no");
|
||||
if (grab_v4l->audio.flags & VIDEO_AUDIO_VOLUME)
|
||||
fprintf(stderr,"volume=%d ",grab_v4l->audio.volume);
|
||||
if (grab_v4l->audio.flags & VIDEO_AUDIO_BASS)
|
||||
fprintf(stderr,"bass=%d ",grab_v4l->audio.bass);
|
||||
if (grab_v4l->audio.flags & VIDEO_AUDIO_TREBLE)
|
||||
fprintf(stderr,"treble=%d ",grab_v4l->audio.treble);
|
||||
fprintf(stderr,"\n");
|
||||
|
||||
if (!(grab_v4l->audio.flags & VIDEO_AUDIO_VOLUME)) {
|
||||
grab_v4l->grab_attr[0].have = 0; /* volume */
|
||||
}
|
||||
} else {
|
||||
grab_v4l->grab_attr[0].have = 0; /* volume */
|
||||
grab_v4l->grab_attr[1].have = 0; /* mute */
|
||||
grab_v4l->grab_attr[2].have = 0; /* audio mode */
|
||||
}
|
||||
|
||||
fprintf(stderr,"v4l: size : %dx%d => %dx%d\n",
|
||||
grab_v4l->capability.minwidth,grab_v4l->capability.minheight,
|
||||
grab_v4l->capability.maxwidth,grab_v4l->capability.maxheight);
|
||||
|
||||
/* tuner (more than one???) */
|
||||
if (grab_v4l->capability.type & VID_TYPE_TUNER) {
|
||||
grab_v4l->tuner = malloc(sizeof(struct video_tuner));
|
||||
memset(grab_v4l->tuner,0,sizeof(struct video_tuner));
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGTUNER,grab_v4l->tuner))
|
||||
perror("v4l: ioctl VIDIOCGTUNER");
|
||||
fprintf(stderr,"v4l: tuner : %s %lu-%lu",
|
||||
grab_v4l->tuner->name,grab_v4l->tuner->rangelow,grab_v4l->tuner->rangehigh);
|
||||
for (i = 0; norms[i].str != NULL; i++) {
|
||||
if (grab_v4l->tuner->flags & (1<<i)) {
|
||||
fprintf(stderr," %s",norms[i].str);
|
||||
} else
|
||||
norms[i].nr = -1;
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
} else {
|
||||
struct video_channel vchan;
|
||||
|
||||
memcpy(&vchan, &grab_v4l->channels[0], sizeof(struct video_channel));
|
||||
for (i = 0; norms[i].str != NULL; i++) {
|
||||
vchan.norm = i;
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSCHAN,&vchan))
|
||||
norms[i].nr = -1;
|
||||
fprintf(stderr," %s",norms[i].str);
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSCHAN,&grab_v4l->channels[0])) {
|
||||
fprintf(stderr,"v4l: you need a newer bttv version (>= 0.5.14)\n");
|
||||
goto err;
|
||||
}
|
||||
grab_v4l->grab_tune = NULL;
|
||||
grab_v4l->grab_tuned = NULL;
|
||||
}
|
||||
#if 1
|
||||
#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
|
||||
/* dirty hack time / v4l design flaw -- works with bttv only
|
||||
* this adds support for a few less common PAL versions */
|
||||
if (-1 != ioctl(grab_v4l->fd,BTTV_VERSION,0)) {
|
||||
grab_v4l->norms = norms_bttv;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* frame buffer */
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGFBUF,&grab_v4l->ov_fbuf))
|
||||
perror("v4l: ioctl VIDIOCGFBUF");
|
||||
fprintf(stderr,"v4l: fbuffer : base=0x%p size=%dx%d depth=%d bpl=%d\n",
|
||||
grab_v4l->ov_fbuf.base, grab_v4l->ov_fbuf.width, grab_v4l->ov_fbuf.height,
|
||||
grab_v4l->ov_fbuf.depth, grab_v4l->ov_fbuf.bytesperline);
|
||||
|
||||
/* picture parameters */
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGPICT,&grab_v4l->pict))
|
||||
perror("v4l: ioctl VIDIOCGPICT");
|
||||
|
||||
fprintf(stderr,
|
||||
"v4l: picture : brightness=%d hue=%d colour=%d contrast=%d\n",
|
||||
grab_v4l->pict.brightness, grab_v4l->pict.hue, grab_v4l->pict.colour, grab_v4l->pict.contrast);
|
||||
fprintf(stderr,
|
||||
"v4l: picture : whiteness=%d depth=%d palette=%s\n",
|
||||
grab_v4l->pict.whiteness, grab_v4l->pict.depth, PALETTE(grab_v4l->pict.palette));
|
||||
|
||||
/* map grab buffer */
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGMBUF,&grab_v4l->gb_buffers)) {
|
||||
perror("v4l: ioctl VIDIOCGMBUF");
|
||||
}
|
||||
grab_v4l->map = mmap(0,grab_v4l->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,grab_v4l->fd,0);
|
||||
if ((char*)-1 != grab_v4l->map) {
|
||||
grab_v4l->grab_setparams = grab_mm_setparams;
|
||||
grab_v4l->grab_capture = grab_mm_capture;
|
||||
grab_v4l->grab_cleanup = grab_mm_cleanup;
|
||||
} else {
|
||||
perror("v4l: mmap");
|
||||
grab_v4l->grab_setparams = grab_read_setparams;
|
||||
grab_v4l->grab_capture = grab_read_capture;
|
||||
grab_v4l->grab_cleanup = grab_read_cleanup;
|
||||
}
|
||||
grab_v4l->opened = 1;
|
||||
|
||||
return grab_v4l->fd;
|
||||
|
||||
err:
|
||||
if (grab_v4l->fd != -1) {
|
||||
close(grab_v4l->fd);
|
||||
grab_v4l->fd = -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_close(struct GRABBER *grab_v4l)
|
||||
{
|
||||
if (-1 == grab_v4l->fd)
|
||||
return 0;
|
||||
|
||||
if (grab_v4l->gb_grab > grab_v4l->gb_sync)
|
||||
grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
|
||||
|
||||
if ((char*)-1 != grab_v4l->map)
|
||||
munmap(grab_v4l->map,grab_v4l->gb_buffers.size);
|
||||
|
||||
fprintf(stderr, "v4l: close\n");
|
||||
|
||||
close(grab_v4l->fd);
|
||||
grab_v4l->fd = -1;
|
||||
grab_v4l->opened = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* do overlay */
|
||||
|
||||
static int
|
||||
grab_setupfb(struct GRABBER *grab_v4l, int sw, int sh, int format, void *base, int bpl)
|
||||
{
|
||||
int settings_ok = 1;
|
||||
grab_v4l->swidth = sw;
|
||||
grab_v4l->sheight = sh;
|
||||
|
||||
/* double-check settings */
|
||||
fprintf(stderr,"v4l: %dx%d, %d bit/pixel, %d byte/scanline\n",
|
||||
grab_v4l->ov_fbuf.width,grab_v4l->ov_fbuf.height,
|
||||
grab_v4l->ov_fbuf.depth,grab_v4l->ov_fbuf.bytesperline);
|
||||
if ((bpl > 0 && grab_v4l->ov_fbuf.bytesperline != bpl) ||
|
||||
(grab_v4l->ov_fbuf.width != sw) ||
|
||||
(grab_v4l->ov_fbuf.height != sh)) {
|
||||
fprintf(stderr,"v4l: WARNING: v4l and dga disagree about the screen size\n");
|
||||
fprintf(stderr,"v4l: WARNING: Is v4l-conf installed correctly?\n");
|
||||
settings_ok = 0;
|
||||
}
|
||||
if (format2depth[format] != ((grab_v4l->ov_fbuf.depth+7)&0xf8)) {
|
||||
fprintf(stderr,"v4l: WARNING: v4l and dga disagree about the color depth\n");
|
||||
fprintf(stderr,"v4l: WARNING: Is v4l-conf installed correctly?\n");
|
||||
fprintf(stderr,"%d %d\n",format2depth[format],grab_v4l->ov_fbuf.depth);
|
||||
settings_ok = 0;
|
||||
}
|
||||
if (settings_ok) {
|
||||
grab_v4l->grab_overlay = grab_overlay;
|
||||
grab_v4l->grab_offscreen = grab_offscreen;
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr,"v4l: WARNING: overlay mode disabled\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
grab_overlay(struct GRABBER *grab_v4l, int x, int y, int width, int height, int format,
|
||||
OverlayClip *oc, int count)
|
||||
{
|
||||
int i,xadjust=0,yadjust=0;
|
||||
|
||||
//fprintf(stderr,"v4l: overlay %d %d\n", x, y);
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
//fprintf(stderr,"v4l: overlay off\n");
|
||||
ioctl(grab_v4l->fd, VIDIOCCAPTURE, &zero);
|
||||
grab_v4l->overlay = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
grab_v4l->ov_win.x = x;
|
||||
grab_v4l->ov_win.y = y;
|
||||
grab_v4l->ov_win.width = width;
|
||||
grab_v4l->ov_win.height = height;
|
||||
grab_v4l->ov_win.flags = 0;
|
||||
|
||||
/* check against max. size */
|
||||
ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability);
|
||||
if (grab_v4l->ov_win.width > grab_v4l->capability.maxwidth) {
|
||||
grab_v4l->ov_win.width = grab_v4l->capability.maxwidth;
|
||||
grab_v4l->ov_win.x += (width - grab_v4l->ov_win.width)/2;
|
||||
}
|
||||
if (grab_v4l->ov_win.height > grab_v4l->capability.maxheight) {
|
||||
grab_v4l->ov_win.height = grab_v4l->capability.maxheight;
|
||||
grab_v4l->ov_win.y += (height - grab_v4l->ov_win.height)/2;
|
||||
}
|
||||
|
||||
/* pass aligned values -- the driver does'nt get it right yet */
|
||||
grab_v4l->ov_win.width &= ~3;
|
||||
grab_v4l->ov_win.height &= ~3;
|
||||
grab_v4l->ov_win.x &= ~3;
|
||||
if (grab_v4l->ov_win.x < x) grab_v4l->ov_win.x += 4;
|
||||
if (grab_v4l->ov_win.x+grab_v4l->ov_win.width > x+width) grab_v4l->ov_win.width -= 4;
|
||||
|
||||
/* fixups */
|
||||
xadjust = grab_v4l->ov_win.x - x;
|
||||
yadjust = grab_v4l->ov_win.y - y;
|
||||
|
||||
if (grab_v4l->capability.type & VID_TYPE_CLIPPING) {
|
||||
grab_v4l->ov_win.clips = grab_v4l->ov_clips;
|
||||
grab_v4l->ov_win.clipcount = count;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
grab_v4l->ov_clips[i].x = oc[i].x1 - xadjust;
|
||||
grab_v4l->ov_clips[i].y = oc[i].y1 - yadjust;
|
||||
grab_v4l->ov_clips[i].width = oc[i].x2-oc[i].x1 /* XXX */;
|
||||
grab_v4l->ov_clips[i].height = oc[i].y2-oc[i].y1;
|
||||
//fprintf(stderr,"v4l: clip=%dx%d+%d+%d\n",
|
||||
//grab_v4l->ov_clips[i].width,grab_v4l->ov_clips[i].height,
|
||||
//grab_v4l->ov_clips[i].x,grab_v4l->ov_clips[i].y);
|
||||
}
|
||||
}
|
||||
if (grab_v4l->capability.type & VID_TYPE_CHROMAKEY) {
|
||||
grab_v4l->ov_win.chromakey = 0; /* XXX */
|
||||
}
|
||||
if (-1 == ioctl(grab_v4l->fd, VIDIOCSWIN, &grab_v4l->ov_win))
|
||||
perror("v4l: ioctl VIDIOCSWIN");
|
||||
|
||||
if (!grab_v4l->overlay) {
|
||||
grab_v4l->pict.palette =
|
||||
(format < sizeof(format2palette)/sizeof(unsigned short))?
|
||||
format2palette[format]: 0;
|
||||
if(grab_v4l->pict.palette == 0) {
|
||||
fprintf(stderr,"v4l: unsupported overlay video format: %s\n",
|
||||
format_desc[format]);
|
||||
return -1;
|
||||
}
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSPICT,&grab_v4l->pict))
|
||||
perror("v4l: ioctl VIDIOCSPICT");
|
||||
if (-1 == ioctl(grab_v4l->fd, VIDIOCCAPTURE, &one))
|
||||
perror("v4l: ioctl VIDIOCCAPTURE");
|
||||
grab_v4l->overlay = 1;
|
||||
}
|
||||
|
||||
//fprintf(stderr,"v4l: overlay win=%dx%d+%d+%d, %d clips\n",
|
||||
// width,height,x,y, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_offscreen(struct GRABBER *grab_v4l, int start, int pitch, int width, int height, int format)
|
||||
{
|
||||
struct video_window2 vo;
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
fprintf(stderr,"v4l: offscreen off\n");
|
||||
ioctl(grab_v4l->fd, VIDIOCCAPTURE, &zero);
|
||||
grab_v4l->overlay = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vo.palette = VIDEO_PALETTE_YUV422; /* FIXME */
|
||||
vo.start = start;
|
||||
vo.pitch = pitch;
|
||||
vo.width = width;
|
||||
vo.height = height;
|
||||
vo.flags = 0;
|
||||
vo.clips = NULL;
|
||||
vo.clipcount = 0;
|
||||
|
||||
if (-1 == ioctl(grab_v4l->fd_grab,VIDIOCSWIN2,&vo))
|
||||
perror("v4l: ioctl VIDIOCSOFFSCREEN");
|
||||
if (-1 == ioctl(grab_v4l->fd_grab,VIDIOCCAPTURE,&one))
|
||||
perror("v4l: ioctl VIDIOCCAPTURE");
|
||||
fprintf(stderr,"v4l: offscreen size=%dx%d\n",
|
||||
width,height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* capture using mmaped buffers (with double-buffering, ...) */
|
||||
|
||||
static int
|
||||
grab_queue(struct GRABBER *grab_v4l, struct video_mmap *gb, int probe)
|
||||
{
|
||||
//fprintf(stderr,"g%d",gb->frame);
|
||||
#if 0
|
||||
/* might be useful for debugging driver problems */
|
||||
memset(map + grab_v4l->gb_buffers.offsets[gb->frame],0,
|
||||
grab_v4l->gb_buffers.size/grab_v4l->gb_buffers.frames);
|
||||
#endif
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCMCAPTURE,gb)) {
|
||||
if (errno == EAGAIN)
|
||||
fprintf(stderr,"v4l: grabber chip can't sync (no station tuned in?)\n");
|
||||
else
|
||||
if (!probe)
|
||||
fprintf(stderr,"v4l: ioctl VIDIOCMCAPTURE(%d,%s,%dx%d): %s\n",
|
||||
gb->frame,PALETTE(gb->format),gb->width,gb->height,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
//fprintf(stderr,"* ");
|
||||
grab_v4l->gb_grab++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_wait(struct GRABBER *grab_v4l, struct video_mmap *gb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
//alarm(SYNC_TIMEOUT);
|
||||
//fprintf(stderr,"s%d",gb->frame);
|
||||
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSYNC,&(gb->frame))) {
|
||||
//perror("v4l: ioctl VIDIOCSYNC");
|
||||
ret = -1;
|
||||
}
|
||||
grab_v4l->gb_sync++;
|
||||
//fprintf(stderr,"* ");
|
||||
//alarm(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_probe(struct GRABBER *grab_v4l, int format)
|
||||
{
|
||||
struct video_mmap gb;
|
||||
|
||||
if (0 != gb_pal[format])
|
||||
goto done;
|
||||
|
||||
gb.frame = 0;
|
||||
gb.width = 64;
|
||||
gb.height = 48;
|
||||
|
||||
fprintf(stderr, "v4l: capture probe %s...\t", device_pal[format]);
|
||||
gb.format = format;
|
||||
if (-1 == grab_queue(grab_v4l, &gb,1)) {
|
||||
gb_pal[format] = 2;
|
||||
goto done;
|
||||
}
|
||||
if (-1 == grab_wait(grab_v4l, &gb)) {
|
||||
gb_pal[format] = 2;
|
||||
goto done;
|
||||
}
|
||||
gb_pal[format] = 1;
|
||||
fprintf(stderr, "ok\n");
|
||||
|
||||
done:
|
||||
return gb_pal[format] == 1;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_mm_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height, int *linelength)
|
||||
{
|
||||
//if (!grab_v4l->opened) return -1;
|
||||
|
||||
/* finish old stuff */
|
||||
if (grab_v4l->gb_grab > grab_v4l->gb_sync)
|
||||
grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
|
||||
|
||||
/* verify parameters */
|
||||
ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability);
|
||||
if (*width > grab_v4l->capability.maxwidth)
|
||||
*width = grab_v4l->capability.maxwidth;
|
||||
if (*height > grab_v4l->capability.maxheight)
|
||||
*height = grab_v4l->capability.maxheight;
|
||||
*linelength = *width * format2depth[format] / 8;
|
||||
|
||||
#if 1
|
||||
/* XXX bttv bug workaround - it returns a larger size than it can handle */
|
||||
if (*width > 768+76) {
|
||||
*width = 768+76;
|
||||
*linelength = *width * format2depth[format] / 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize everything */
|
||||
grab_v4l->gb_even.format = grab_v4l->gb_odd.format =
|
||||
(format < sizeof(format2palette)/sizeof(unsigned short)) ?
|
||||
format2palette[format] : 0;
|
||||
if (grab_v4l->gb_even.format == 0 || !grab_probe(grab_v4l, grab_v4l->gb_even.format)) {
|
||||
return -1;
|
||||
}
|
||||
grab_v4l->pixmap_bytes = format2depth[format] / 8;
|
||||
grab_v4l->gb_even.frame = 0;
|
||||
grab_v4l->gb_odd.frame = 1;
|
||||
grab_v4l->gb_even.width = *width;
|
||||
grab_v4l->gb_even.height = *height;
|
||||
grab_v4l->gb_odd.width = *width;
|
||||
grab_v4l->gb_odd.height = *height;
|
||||
grab_v4l->even = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void*
|
||||
grab_mm_capture(struct GRABBER *grab_v4l, int single)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
if (!single && grab_v4l->gb_grab == grab_v4l->gb_sync)
|
||||
/* streaming capture started */
|
||||
if (-1 == grab_queue(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd,0))
|
||||
return NULL;
|
||||
|
||||
if (single && grab_v4l->gb_grab > grab_v4l->gb_sync)
|
||||
/* clear streaming capture */
|
||||
grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
|
||||
|
||||
/* queue */
|
||||
if (-1 == grab_queue(grab_v4l, grab_v4l->even ? &grab_v4l->gb_odd : &grab_v4l->gb_even,0))
|
||||
return NULL;
|
||||
if (grab_v4l->gb_grab > grab_v4l->gb_sync+1) {
|
||||
/* wait -- streaming */
|
||||
//fprintf(stderr, "v4lsrc: 1 %d %d\n", grab_v4l->gb_grab, gb_sync);
|
||||
grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
|
||||
buf = grab_v4l->map + grab_v4l->gb_buffers.offsets[grab_v4l->even ? 0 : 1];
|
||||
} else {
|
||||
/* wait -- single */
|
||||
//fprintf(stderr, "v4lsrc: 2 %d %d %d\n", grab_v4l->gb_grab, gb_sync, even);
|
||||
grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_odd : &grab_v4l->gb_even);
|
||||
buf = grab_v4l->map + grab_v4l->gb_buffers.offsets[grab_v4l->even ? 1 : 0];
|
||||
}
|
||||
grab_v4l->even = !grab_v4l->even;
|
||||
//fprintf(stderr, "v4lsrc: even %d\n", even);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
grab_mm_cleanup(struct GRABBER *grab_v4l)
|
||||
{
|
||||
if (grab_v4l->gb_grab > grab_v4l->gb_sync)
|
||||
grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* capture using simple read() */
|
||||
|
||||
static int
|
||||
grab_read_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height, int *linelength)
|
||||
{
|
||||
struct video_window win;
|
||||
|
||||
grab_v4l->pict.depth = format2depth[format];
|
||||
grab_v4l->pict.palette = format2palette[format];
|
||||
|
||||
/* set format */
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSPICT,&grab_v4l->pict)) {
|
||||
perror("v4l: ioctl VIDIOCSPICT");
|
||||
return -1;
|
||||
}
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGPICT,&grab_v4l->pict)) {
|
||||
perror("v4l: ioctl VIDIOCGPICT");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set size */
|
||||
ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability);
|
||||
if (*width > grab_v4l->capability.maxwidth)
|
||||
*width = grab_v4l->capability.maxwidth;
|
||||
if (*height > grab_v4l->capability.maxheight)
|
||||
*height = grab_v4l->capability.maxheight;
|
||||
memset(&win,0,sizeof(struct video_window));
|
||||
win.width = *width;
|
||||
win.height = *height;
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCSWIN,&win)) {
|
||||
perror("v4l: ioctl VIDIOCSWIN");
|
||||
return -1;
|
||||
}
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGWIN,&win)) {
|
||||
perror("v4l: ioctl VIDIOCGWIN");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*width = win.width;
|
||||
*height = win.height;
|
||||
*linelength = *width * format2depth[format] / 8;
|
||||
|
||||
/* alloc buffer */
|
||||
grab_v4l->grab_read_size = *linelength * *height;
|
||||
if (grab_v4l->grab_read_buf)
|
||||
free(grab_v4l->grab_read_buf);
|
||||
grab_v4l->grab_read_buf = malloc(grab_v4l->grab_read_size);
|
||||
if (NULL == grab_v4l->grab_read_buf)
|
||||
return -1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void*
|
||||
grab_read_capture(struct GRABBER *grab_v4l, int single)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = read(grab_v4l->fd,grab_v4l->grab_read_buf,grab_v4l->grab_read_size);
|
||||
if (grab_v4l->grab_read_size != rc) {
|
||||
fprintf(stderr,"v4l: grabber read error (rc=%d)\n",rc);
|
||||
return NULL;
|
||||
}
|
||||
return grab_v4l->grab_read_buf;
|
||||
}
|
||||
|
||||
static void
|
||||
grab_read_cleanup(struct GRABBER *grab_v4l)
|
||||
{
|
||||
if (grab_v4l->grab_read_buf) {
|
||||
free(grab_v4l->grab_read_buf);
|
||||
grab_v4l->grab_read_buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
grab_tune(struct GRABBER *grab_v4l, unsigned long freq)
|
||||
{
|
||||
freq = freq*16/1000;
|
||||
fprintf(stderr,"v4l: freq: %.3f\n",(float)freq/16);
|
||||
if (-1 == ioctl(grab_v4l->fd, VIDIOCSFREQ, &freq))
|
||||
perror("v4l: ioctl VIDIOCSFREQ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_tuned(struct GRABBER *grab_v4l)
|
||||
{
|
||||
usleep(10000);
|
||||
if (-1 == ioctl(grab_v4l->fd,VIDIOCGTUNER,grab_v4l->tuner)) {
|
||||
perror("v4l: ioctl VIDIOCGTUNER");
|
||||
return 0;
|
||||
}
|
||||
return grab_v4l->tuner->signal ? 1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grab_input(struct GRABBER *grab_v4l, int input, int norm)
|
||||
{
|
||||
if (-1 != input) {
|
||||
fprintf(stderr,"v4l: input: %d\n",input);
|
||||
grab_v4l->cur_input = input;
|
||||
}
|
||||
if (-1 != norm) {
|
||||
fprintf(stderr,"v4l: norm : %d\n",norm);
|
||||
grab_v4l->cur_norm = norm;
|
||||
}
|
||||
|
||||
grab_v4l->channels[grab_v4l->cur_input].norm = grab_v4l->cur_norm;
|
||||
if (-1 == ioctl(grab_v4l->fd, VIDIOCSCHAN, &grab_v4l->channels[grab_v4l->cur_input]))
|
||||
perror("v4l: ioctl VIDIOCSCHAN");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
int grab_hasattr(struct GRABBER *grab_v4l, int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ATTR; i++)
|
||||
if (id == grab_v4l->grab_attr[i].id && grab_v4l->grab_attr[i].have)
|
||||
break;
|
||||
if (i == NUM_ATTR)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int grab_getattr(struct GRABBER *grab_v4l, int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ATTR; i++)
|
||||
if (id == grab_v4l->grab_attr[i].id && grab_v4l->grab_attr[i].have)
|
||||
break;
|
||||
if (i == NUM_ATTR)
|
||||
return -1;
|
||||
if (-1 == ioctl(grab_v4l->fd,grab_v4l->grab_attr[i].get,grab_v4l->grab_attr[i].arg))
|
||||
perror("v4l: ioctl get");
|
||||
|
||||
switch (id) {
|
||||
case GRAB_ATTR_VOLUME: return grab_v4l->audio.volume;
|
||||
case GRAB_ATTR_MUTE: return grab_v4l->audio.flags & VIDEO_AUDIO_MUTE;
|
||||
case GRAB_ATTR_MODE: return grab_v4l->audio.mode;
|
||||
case GRAB_ATTR_COLOR: return grab_v4l->pict.contrast;
|
||||
case GRAB_ATTR_BRIGHT: return grab_v4l->pict.contrast;
|
||||
case GRAB_ATTR_HUE: return grab_v4l->pict.contrast;
|
||||
case GRAB_ATTR_CONTRAST: return grab_v4l->pict.contrast;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int grab_setattr(struct GRABBER *grab_v4l, int id, int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* read ... */
|
||||
for (i = 0; i < NUM_ATTR; i++)
|
||||
if (id == grab_v4l->grab_attr[i].id && grab_v4l->grab_attr[i].have)
|
||||
break;
|
||||
if (i == NUM_ATTR)
|
||||
return -1;
|
||||
if (-1 == ioctl(grab_v4l->fd,grab_v4l->grab_attr[i].set,grab_v4l->grab_attr[i].arg))
|
||||
perror("v4l: ioctl get");
|
||||
|
||||
/* ... modify ... */
|
||||
switch (id) {
|
||||
case GRAB_ATTR_VOLUME: grab_v4l->audio.volume = val; break;
|
||||
case GRAB_ATTR_MUTE:
|
||||
if (val)
|
||||
grab_v4l->audio.flags |= VIDEO_AUDIO_MUTE;
|
||||
else
|
||||
grab_v4l->audio.flags &= ~VIDEO_AUDIO_MUTE;
|
||||
break;
|
||||
case GRAB_ATTR_MODE: grab_v4l->audio.mode = val; break;
|
||||
case GRAB_ATTR_COLOR: grab_v4l->pict.colour = val; break;
|
||||
case GRAB_ATTR_BRIGHT: grab_v4l->pict.brightness = val; break;
|
||||
case GRAB_ATTR_HUE: grab_v4l->pict.hue = val; break;
|
||||
case GRAB_ATTR_CONTRAST: grab_v4l->pict.contrast = val; break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
/* ... write */
|
||||
if (-1 == ioctl(grab_v4l->fd,grab_v4l->grab_attr[i].set,grab_v4l->grab_attr[i].arg))
|
||||
perror("v4l: ioctl set");
|
||||
return 0;
|
||||
}
|
||||
|
121
sys/v4l/grab.h
Normal file
121
sys/v4l/grab.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
#define VIDEO_RGB08 1 /* bt848 dithered */
|
||||
#define VIDEO_GRAY 2
|
||||
#define VIDEO_RGB15_LE 3 /* 15 bpp little endian */
|
||||
#define VIDEO_RGB16_LE 4 /* 16 bpp little endian */
|
||||
#define VIDEO_RGB15_BE 5 /* 15 bpp big endian */
|
||||
#define VIDEO_RGB16_BE 6 /* 16 bpp big endian */
|
||||
#define VIDEO_BGR24 7 /* bgrbgrbgrbgr (LE) */
|
||||
#define VIDEO_BGR32 8 /* bgr-bgr-bgr- (LE) */
|
||||
#define VIDEO_RGB24 9 /* rgbrgbrgbrgb (BE)*/
|
||||
#define VIDEO_RGB32 10 /* -rgb-rgb-rgb (BE)*/
|
||||
#define VIDEO_LUT2 11 /* lookup-table 2 byte depth */
|
||||
#define VIDEO_LUT4 12 /* lookup-table 4 byte depth */
|
||||
#define VIDEO_YUV422 13 /* YUV 4:2:2 */
|
||||
#define VIDEO_YUV422P 14 /* YUV 4:2:2 (planar) */
|
||||
#define VIDEO_YUV420P 15 /* YUV 4:2:0 (planar) */
|
||||
#define VIDEO_MJPEG 16 /* MJPEG */
|
||||
|
||||
#define CAN_AUDIO_VOLUME 1
|
||||
|
||||
#define GRAB_ATTR_VOLUME 1
|
||||
#define GRAB_ATTR_MUTE 2
|
||||
#define GRAB_ATTR_MODE 3
|
||||
|
||||
#define GRAB_ATTR_COLOR 11
|
||||
#define GRAB_ATTR_BRIGHT 12
|
||||
#define GRAB_ATTR_HUE 13
|
||||
#define GRAB_ATTR_CONTRAST 14
|
||||
|
||||
#define TRAP(txt) fprintf(stderr,"%s:%d:%s\n",__FILE__,__LINE__,txt);exit(1);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct STRTAB {
|
||||
long nr;
|
||||
char *str;
|
||||
};
|
||||
|
||||
typedef struct _OverlayClip OverlayClip;
|
||||
|
||||
struct _OverlayClip {
|
||||
int x1, x2, y1, y2;
|
||||
};
|
||||
|
||||
struct GRAB_ATTR {
|
||||
int id;
|
||||
int have;
|
||||
int get;
|
||||
int set;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct GRABBER {
|
||||
char *name;
|
||||
int flags;
|
||||
const struct STRTAB *norms;
|
||||
struct STRTAB *inputs;
|
||||
const struct STRTAB *audio_modes;
|
||||
int opened;
|
||||
char *map;
|
||||
int fd, fd_grab;
|
||||
|
||||
/* generic informations */
|
||||
struct video_capability capability;
|
||||
struct video_channel *channels;
|
||||
struct video_audio audio;
|
||||
struct video_tuner *tuner;
|
||||
struct video_picture pict;
|
||||
#define NUM_ATTR 7
|
||||
struct GRAB_ATTR grab_attr[NUM_ATTR];
|
||||
|
||||
int cur_input;
|
||||
int cur_norm;
|
||||
int grab_read_size;
|
||||
char *grab_read_buf;
|
||||
|
||||
/* overlay */
|
||||
struct video_window ov_win;
|
||||
struct video_clip ov_clips[32];
|
||||
struct video_buffer ov_fbuf;
|
||||
|
||||
/* screen grab */
|
||||
struct video_mmap gb_even;
|
||||
struct video_mmap gb_odd;
|
||||
int even,pixmap_bytes;
|
||||
int gb_grab,gb_sync;
|
||||
struct video_mbuf gb_buffers;
|
||||
|
||||
|
||||
/* state */
|
||||
int overlay, swidth, sheight;
|
||||
|
||||
int (*grab_open)(struct GRABBER *grab_v4l, char *opt);
|
||||
int (*grab_close)(struct GRABBER *grab_v4l);
|
||||
|
||||
int (*grab_setupfb)(struct GRABBER *grab_v4l, int sw, int sh, int format, void *base, int bpl);
|
||||
int (*grab_overlay)(struct GRABBER *grab_v4l, int x, int y, int width, int height, int format,
|
||||
OverlayClip *oc, int count);
|
||||
int (*grab_offscreen)(struct GRABBER *grab_v4l, int start, int pitch, int width, int height,
|
||||
int format);
|
||||
|
||||
int (*grab_setparams)(struct GRABBER *grab_v4l, int format, int *width, int *height, int *linelength);
|
||||
void* (*grab_capture)(struct GRABBER *grab_v4l, int single);
|
||||
void (*grab_cleanup)(struct GRABBER *grab_v4l);
|
||||
|
||||
int (*grab_tune)(struct GRABBER *grab_v4l, unsigned long freq);
|
||||
int (*grab_tuned)(struct GRABBER *grab_v4l);
|
||||
int (*grab_input)(struct GRABBER *grab_v4l, int input, int norm);
|
||||
|
||||
#if 0
|
||||
int (*grab_picture)(int color, int bright, int hue, int contrast);
|
||||
int (*grab_audio)(int mute, int volume, int *mode);
|
||||
#else
|
||||
int (*grab_hasattr)(struct GRABBER *grab_v4l, int id);
|
||||
int (*grab_getattr)(struct GRABBER *grab_v4l, int id);
|
||||
int (*grab_setattr)(struct GRABBER *grab_v4l, int id, int val);
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct GRABBER *grab_init();
|
629
sys/v4l/gstv4lsrc.c
Normal file
629
sys/v4l/gstv4lsrc.c
Normal file
|
@ -0,0 +1,629 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define DEBUG_ENABLED
|
||||
#include <gstv4lsrc.h>
|
||||
|
||||
#include <linux/videodev.h>
|
||||
|
||||
static GstElementDetails gst_v4lsrc_details = {
|
||||
"Video (v4l) Source",
|
||||
"Source/Video",
|
||||
"Read from a Video for Linux capture device",
|
||||
VERSION,
|
||||
"Wim Taymans <wim.taymans@tvd.be>",
|
||||
"(C) 2000",
|
||||
};
|
||||
|
||||
/* V4lSrc signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_WIDTH,
|
||||
ARG_HEIGHT,
|
||||
ARG_FORMAT,
|
||||
ARG_TUNE,
|
||||
ARG_TUNED,
|
||||
ARG_INPUT,
|
||||
ARG_NORM,
|
||||
ARG_VOLUME,
|
||||
ARG_MUTE,
|
||||
ARG_AUDIO_MODE,
|
||||
ARG_COLOR,
|
||||
ARG_BRIGHT,
|
||||
ARG_HUE,
|
||||
ARG_CONTRAST,
|
||||
ARG_DEVICE,
|
||||
};
|
||||
|
||||
|
||||
static void gst_v4lsrc_class_init (GstV4lSrcClass *klass);
|
||||
static void gst_v4lsrc_init (GstV4lSrc *v4lsrc);
|
||||
|
||||
static void gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
||||
static void gst_v4lsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
|
||||
|
||||
static GstElementStateReturn gst_v4lsrc_change_state (GstElement *element);
|
||||
static void gst_v4lsrc_close_v4l (GstV4lSrc *src);
|
||||
static gboolean gst_v4lsrc_open_v4l (GstV4lSrc *src);
|
||||
|
||||
static GstBuffer* gst_v4lsrc_get (GstPad *pad);
|
||||
static GstPadNegotiateReturn gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data);
|
||||
|
||||
static gboolean gst_v4lsrc_sync_parms (GstV4lSrc *v4lsrc);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
////static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
GType
|
||||
gst_v4lsrc_get_type (void)
|
||||
{
|
||||
static GType v4lsrc_type = 0;
|
||||
|
||||
if (!v4lsrc_type) {
|
||||
static const GTypeInfo v4lsrc_info = {
|
||||
sizeof(GstV4lSrcClass), NULL,
|
||||
NULL,
|
||||
(GClassInitFunc)gst_v4lsrc_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(GstV4lSrc),
|
||||
0,
|
||||
(GInstanceInitFunc)gst_v4lsrc_init,
|
||||
NULL
|
||||
};
|
||||
v4lsrc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
|
||||
}
|
||||
return v4lsrc_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4lsrc_class_init (GstV4lSrcClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass*)klass;
|
||||
gstelement_class = (GstElementClass*)klass;
|
||||
|
||||
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
|
||||
g_param_spec_int("width","width","width",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
|
||||
g_param_spec_int("height","height","height",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
|
||||
g_param_spec_int("format","format","format",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TUNE,
|
||||
g_param_spec_ulong("tune","tune","tune",
|
||||
0,G_MAXULONG,0,G_PARAM_WRITABLE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TUNED,
|
||||
g_param_spec_boolean("tuned","tuned","tuned",
|
||||
TRUE,G_PARAM_READABLE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_INPUT,
|
||||
g_param_spec_int("input","input","input",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM,
|
||||
g_param_spec_int("norm","norm","norm",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
|
||||
g_param_spec_int("volume","volume","volume",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
|
||||
g_param_spec_boolean("mute","mute","mute",
|
||||
TRUE,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_AUDIO_MODE,
|
||||
g_param_spec_int("mode","mode","mode",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_COLOR,
|
||||
g_param_spec_int("color","color","color",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHT,
|
||||
g_param_spec_int("bright","bright","bright",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HUE,
|
||||
g_param_spec_int("hue","hue","hue",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CONTRAST,
|
||||
g_param_spec_int("contrast","contrast","contrast",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
|
||||
g_param_spec_string("device","device","device",
|
||||
NULL, G_PARAM_READWRITE)); // CHECKME
|
||||
|
||||
gobject_class->set_property = gst_v4lsrc_set_property;
|
||||
gobject_class->get_property = gst_v4lsrc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_v4lsrc_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4lsrc_init (GstV4lSrc *v4lsrc)
|
||||
{
|
||||
v4lsrc->srcpad = gst_pad_new("src",GST_PAD_SRC);
|
||||
gst_element_add_pad(GST_ELEMENT(v4lsrc),v4lsrc->srcpad);
|
||||
|
||||
gst_pad_set_get_function (v4lsrc->srcpad,gst_v4lsrc_get);
|
||||
gst_pad_set_negotiate_function (v4lsrc->srcpad,gst_v4lsrc_negotiate);
|
||||
|
||||
/* if the destination cannot say what it wants, we give this */
|
||||
v4lsrc->width = 100;
|
||||
v4lsrc->height = 100;
|
||||
v4lsrc->format = 0;
|
||||
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 3;
|
||||
// make a grbber
|
||||
v4lsrc->grabber = grab_init();
|
||||
v4lsrc->device = NULL;
|
||||
v4lsrc->init = TRUE;
|
||||
}
|
||||
|
||||
static GstPadNegotiateReturn
|
||||
gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data)
|
||||
{
|
||||
GstV4lSrc *v4lsrc;
|
||||
|
||||
GST_DEBUG (0, "v4lsrc: negotiate %p\n", user_data);
|
||||
|
||||
v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
|
||||
|
||||
if (!*caps) {
|
||||
return GST_PAD_NEGOTIATE_FAIL;
|
||||
}
|
||||
else {
|
||||
gint width, height;
|
||||
gulong format;
|
||||
|
||||
GST_DEBUG (0, "%08lx\n", gst_caps_get_fourcc_int (*caps, "format"));
|
||||
|
||||
width = gst_caps_get_int (*caps, "width");
|
||||
height = gst_caps_get_int (*caps, "height");
|
||||
|
||||
format = gst_caps_get_fourcc_int (*caps, "format");
|
||||
|
||||
g_print ("v4lsrc: got format %08lx\n", format);
|
||||
|
||||
switch (format) {
|
||||
case GST_MAKE_FOURCC ('R','G','B',' '):
|
||||
{
|
||||
gint depth, endianness, bpp;
|
||||
|
||||
depth = gst_caps_get_int (*caps, "depth");
|
||||
bpp = gst_caps_get_int (*caps, "bpp");
|
||||
endianness = gst_caps_get_int (*caps, "endianness");
|
||||
|
||||
GST_DEBUG (0, "%d\n", depth);
|
||||
g_print ("v4lsrc: got depth %d, bpp %d, endianness %d\n", depth, bpp, endianness);
|
||||
switch (depth) {
|
||||
case 15:
|
||||
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
|
||||
VIDEO_RGB15_LE:
|
||||
VIDEO_RGB15_BE);
|
||||
v4lsrc->buffer_size = width * height * 2;
|
||||
break;
|
||||
case 16:
|
||||
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
|
||||
VIDEO_RGB16_LE:
|
||||
VIDEO_RGB16_BE);
|
||||
v4lsrc->buffer_size = width * height * 2;
|
||||
break;
|
||||
case 24:
|
||||
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
|
||||
VIDEO_BGR24:
|
||||
VIDEO_RGB24);
|
||||
v4lsrc->buffer_size = width * height * 3;
|
||||
break;
|
||||
case 32:
|
||||
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
|
||||
VIDEO_BGR32:
|
||||
VIDEO_RGB32);
|
||||
v4lsrc->buffer_size = width * height * 4;
|
||||
break;
|
||||
default:
|
||||
*caps = NULL;
|
||||
return GST_PAD_NEGOTIATE_TRY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_MAKE_FOURCC ('I','4','2','0'):
|
||||
v4lsrc->format = VIDEO_YUV420P;
|
||||
v4lsrc->buffer_size = width * height +
|
||||
width * height / 2;
|
||||
break;
|
||||
case GST_MAKE_FOURCC ('U','Y','V','Y'):
|
||||
if (G_BYTE_ORDER == G_BIG_ENDIAN) {
|
||||
v4lsrc->format = VIDEO_YUV422;
|
||||
v4lsrc->buffer_size = width * height * 2;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
*caps = NULL;
|
||||
return GST_PAD_NEGOTIATE_TRY;
|
||||
}
|
||||
case GST_MAKE_FOURCC ('Y','U','Y','2'):
|
||||
if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
|
||||
v4lsrc->format = VIDEO_YUV422;
|
||||
v4lsrc->buffer_size = width * height * 2;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
*caps = NULL;
|
||||
return GST_PAD_NEGOTIATE_TRY;
|
||||
}
|
||||
default:
|
||||
*caps = NULL;
|
||||
return GST_PAD_NEGOTIATE_TRY;
|
||||
}
|
||||
v4lsrc->width = width;
|
||||
v4lsrc->height = height;
|
||||
|
||||
if (gst_v4lsrc_sync_parms (v4lsrc)) {
|
||||
return GST_PAD_NEGOTIATE_AGREE;
|
||||
}
|
||||
else {
|
||||
*caps = NULL;
|
||||
return GST_PAD_NEGOTIATE_TRY;
|
||||
}
|
||||
}
|
||||
|
||||
return GST_PAD_NEGOTIATE_FAIL;
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
gst_v4lsrc_create_caps (GstV4lSrc *src)
|
||||
{
|
||||
GstCaps *caps;
|
||||
gulong fourcc = 0;
|
||||
gint width, height;
|
||||
|
||||
width = src->width;
|
||||
height = src->height;
|
||||
|
||||
switch (src->format) {
|
||||
case VIDEO_RGB08:
|
||||
case VIDEO_GRAY:
|
||||
case VIDEO_LUT2:
|
||||
case VIDEO_LUT4:
|
||||
caps = NULL;
|
||||
break;
|
||||
case VIDEO_RGB15_LE:
|
||||
case VIDEO_RGB16_LE:
|
||||
case VIDEO_RGB15_BE:
|
||||
case VIDEO_RGB16_BE:
|
||||
case VIDEO_BGR24:
|
||||
case VIDEO_BGR32:
|
||||
case VIDEO_RGB24:
|
||||
case VIDEO_RGB32:
|
||||
caps = NULL;
|
||||
break;
|
||||
case VIDEO_YUV422:
|
||||
case VIDEO_YUV422P:
|
||||
case VIDEO_YUV420P: {
|
||||
|
||||
if (src->format == VIDEO_YUV422) {
|
||||
fourcc = GST_STR_FOURCC ("YUY2");
|
||||
src->buffer_size = width * height * 2;
|
||||
}
|
||||
else if (src->format == VIDEO_YUV422P) {
|
||||
fourcc = GST_STR_FOURCC ("YV12");
|
||||
src->buffer_size = width * height * 2;
|
||||
}
|
||||
else if (src->format == VIDEO_YUV420P) {
|
||||
fourcc = GST_STR_FOURCC ("I420");
|
||||
src->buffer_size = width * height +
|
||||
width * height / 2;
|
||||
}
|
||||
|
||||
caps = GST_CAPS_NEW (
|
||||
"v4lsrc_caps",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (fourcc),
|
||||
"width", GST_PROPS_INT (src->width),
|
||||
"height", GST_PROPS_INT (src->height)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
caps = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstBuffer*
|
||||
gst_v4lsrc_get (GstPad *pad)
|
||||
{
|
||||
GstV4lSrc *v4lsrc;
|
||||
GstBuffer *buf = NULL;
|
||||
guint8 *grab_buf;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
|
||||
v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
|
||||
|
||||
if (v4lsrc->format && v4lsrc->init) {
|
||||
gst_pad_set_caps (v4lsrc->srcpad, gst_v4lsrc_create_caps (v4lsrc));
|
||||
v4lsrc->init = FALSE;
|
||||
}
|
||||
else {
|
||||
if (!gst_pad_get_caps (v4lsrc->srcpad) &&
|
||||
!gst_pad_renegotiate (v4lsrc->srcpad)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buf = gst_buffer_new();
|
||||
GST_BUFFER_DATA(buf) = g_malloc(v4lsrc->buffer_size);
|
||||
GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
|
||||
GST_DEBUG (0,"v4lsrc: making new buffer %p\n", GST_BUFFER_DATA(buf));
|
||||
|
||||
GST_DEBUG (0,"v4lsrc: request buffer\n");
|
||||
// request a buffer from the grabber
|
||||
grab_buf = v4lsrc->grabber->grab_capture(v4lsrc->grabber, 0);
|
||||
//meta_pull->overlay_info->did_overlay = FALSE;
|
||||
|
||||
g_assert(buf != NULL);
|
||||
|
||||
GST_DEBUG (0,"v4lsrc: sending %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
|
||||
// copy the buffer
|
||||
memcpy(GST_BUFFER_DATA(buf), grab_buf, GST_BUFFER_SIZE(buf));
|
||||
|
||||
GST_DEBUG (0,"v4lsrc: sent %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
GstV4lSrc *src;
|
||||
int ret = 0;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail(GST_IS_V4LSRC(object));
|
||||
src = GST_V4LSRC(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_WIDTH:
|
||||
src->width = g_value_get_int (value);
|
||||
gst_v4lsrc_sync_parms(src);
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
src->height = g_value_get_int (value);
|
||||
gst_v4lsrc_sync_parms(src);
|
||||
break;
|
||||
case ARG_FORMAT:
|
||||
src->format = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_TUNE:
|
||||
src->tune = g_value_get_ulong (value);
|
||||
ret = src->grabber->grab_tune(src->grabber, src->tune);
|
||||
break;
|
||||
case ARG_INPUT:
|
||||
src->input = g_value_get_int (value);
|
||||
ret = src->grabber->grab_input(src->grabber, src->input, -1);
|
||||
break;
|
||||
case ARG_NORM:
|
||||
src->norm = g_value_get_int (value);
|
||||
ret = src->grabber->grab_input(src->grabber, -1, src->norm);
|
||||
break;
|
||||
case ARG_VOLUME:
|
||||
src->volume = g_value_get_int (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_VOLUME, src->volume);
|
||||
break;
|
||||
case ARG_MUTE:
|
||||
src->mute = g_value_get_boolean (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_MUTE, src->mute);
|
||||
break;
|
||||
case ARG_AUDIO_MODE:
|
||||
src->audio_mode = g_value_get_int (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_MODE, src->audio_mode);
|
||||
break;
|
||||
case ARG_COLOR:
|
||||
src->color = g_value_get_int (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_COLOR, src->color);
|
||||
break;
|
||||
case ARG_BRIGHT:
|
||||
src->bright = g_value_get_int (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_BRIGHT, src->bright);
|
||||
break;
|
||||
case ARG_HUE:
|
||||
src->hue = g_value_get_int (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_HUE, src->hue);
|
||||
break;
|
||||
case ARG_CONTRAST:
|
||||
src->contrast = g_value_get_int (value);
|
||||
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_CONTRAST, src->contrast);
|
||||
break;
|
||||
case ARG_DEVICE:
|
||||
if (src->device)
|
||||
g_free (src->device);
|
||||
src->device = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "v4lsrc: error setting property\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4lsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
GstV4lSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail(GST_IS_V4LSRC(object));
|
||||
src = GST_V4LSRC(object);
|
||||
|
||||
g_print ("get arg\n");
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_WIDTH:
|
||||
g_value_set_int (value, src->width);
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
g_value_set_int (value, src->height);
|
||||
break;
|
||||
case ARG_TUNED:
|
||||
g_value_set_boolean (value, src->grabber->grab_tuned(src->grabber));
|
||||
break;
|
||||
case ARG_VOLUME:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_VOLUME));
|
||||
break;
|
||||
case ARG_MUTE:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_MUTE));
|
||||
break;
|
||||
case ARG_AUDIO_MODE:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_MODE));
|
||||
break;
|
||||
case ARG_COLOR:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_COLOR));
|
||||
break;
|
||||
case ARG_BRIGHT:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_BRIGHT));
|
||||
break;
|
||||
case ARG_HUE:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_HUE));
|
||||
break;
|
||||
case ARG_CONTRAST:
|
||||
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_CONTRAST));
|
||||
break;
|
||||
case ARG_DEVICE:
|
||||
g_value_set_string (value, src->device);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_v4lsrc_change_state (GstElement *element)
|
||||
{
|
||||
g_return_val_if_fail(GST_IS_V4LSRC(element), FALSE);
|
||||
|
||||
/* if going down into NULL state, close the file if it's open */
|
||||
if (GST_STATE_PENDING(element) == GST_STATE_NULL) {
|
||||
if (GST_FLAG_IS_SET(element,GST_V4LSRC_OPEN))
|
||||
gst_v4lsrc_close_v4l(GST_V4LSRC(element));
|
||||
/* otherwise (READY or higher) we need to open the sound card */
|
||||
} else {
|
||||
gst_info ("v4lsrc: opening\n");
|
||||
if (!GST_FLAG_IS_SET(element,GST_V4LSRC_OPEN)) {
|
||||
if (!gst_v4lsrc_open_v4l(GST_V4LSRC(element))) {
|
||||
gst_info ("v4lsrc: open failed\n");
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS(parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4lsrc_sync_parms (GstV4lSrc *src)
|
||||
{
|
||||
gint linelength;
|
||||
gboolean success;
|
||||
|
||||
g_return_val_if_fail(src != NULL, FALSE);
|
||||
g_return_val_if_fail(GST_IS_V4LSRC(src), FALSE);
|
||||
|
||||
GST_DEBUG (0,"v4lsrc: resync %d %d %d\n", src->width, src->height, src->format);
|
||||
|
||||
if (!src->grabber->opened)
|
||||
return FALSE;
|
||||
|
||||
if (src->grabber->grab_setparams(src->grabber, src->format, &src->width, &src->height, &linelength) != 0) {
|
||||
fprintf(stderr, "v4lsrc: error setting params\n");
|
||||
success = FALSE;
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (0,"v4lsrc: resynced to %d %d %d\n", src->width, src->height, src->buffer_size);
|
||||
success = TRUE;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4lsrc_open_v4l (GstV4lSrc *src)
|
||||
{
|
||||
g_return_val_if_fail(src->grabber != NULL, FALSE);
|
||||
g_return_val_if_fail(!src->grabber->opened, FALSE);
|
||||
|
||||
if (src->grabber->grab_open(src->grabber, src->device) != -1) {
|
||||
gst_v4lsrc_sync_parms(src);
|
||||
GST_FLAG_SET(src, GST_V4LSRC_OPEN);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4lsrc_close_v4l (GstV4lSrc *src)
|
||||
{
|
||||
g_return_if_fail(src->grabber != NULL);
|
||||
g_return_if_fail(src->grabber->opened);
|
||||
|
||||
src->grabber->grab_close(src->grabber);
|
||||
GST_FLAG_UNSET(src, GST_V4LSRC_OPEN);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_init (GModule *module, GstPlugin *plugin)
|
||||
{
|
||||
GstElementFactory *factory;
|
||||
|
||||
/* create an elementfactory for the v4lsrcparse element */
|
||||
factory = gst_elementfactory_new("v4lsrc",GST_TYPE_V4LSRC,
|
||||
&gst_v4lsrc_details);
|
||||
g_return_val_if_fail(factory != NULL, FALSE);
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstPluginDesc plugin_desc = {
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"v4lsrc",
|
||||
plugin_init
|
||||
};
|
||||
|
97
sys/v4l/gstv4lsrc.h
Normal file
97
sys/v4l/gstv4lsrc.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_V4LSRC_H__
|
||||
#define __GST_V4LSRC_H__
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <linux/videodev.h>
|
||||
|
||||
#include "grab.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#define GST_TYPE_V4LSRC \
|
||||
(gst_v4lsrc_get_type())
|
||||
#define GST_V4LSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LSRC,GstV4lSrc))
|
||||
#define GST_V4LSRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LSRC,GstV4lSrcClass))
|
||||
#define GST_IS_V4LSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LSRC))
|
||||
#define GST_IS_V4LSRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LSRC))
|
||||
|
||||
// NOTE: per-element flags start with 16 for now
|
||||
typedef enum {
|
||||
GST_V4LSRC_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_V4LSRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST+2,
|
||||
} GstV4lSrcFlags;
|
||||
|
||||
typedef struct _GstV4lSrc GstV4lSrc;
|
||||
typedef struct _GstV4lSrcClass GstV4lSrcClass;
|
||||
|
||||
struct _GstV4lSrc {
|
||||
GstElement element;
|
||||
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
/* video device */
|
||||
struct GRABBER *grabber;
|
||||
gboolean init;
|
||||
|
||||
gint width;
|
||||
gint height;
|
||||
guint16 format;
|
||||
guint32 buffer_size;
|
||||
gulong tune;
|
||||
gboolean tuned;
|
||||
gint input;
|
||||
gint norm;
|
||||
gint volume;
|
||||
gboolean mute;
|
||||
gint audio_mode;
|
||||
gint color;
|
||||
gint bright;
|
||||
gint hue;
|
||||
gint contrast;
|
||||
gchar *device;
|
||||
};
|
||||
|
||||
struct _GstV4lSrcClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_v4lsrc_get_type(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __GST_V4LSRC_H__ */
|
Loading…
Reference in a new issue