From: Thomas Vander Stichele Date: Mon, 17 Dec 2001 19:03:14 +0000 (+0000) Subject: first batch X-Git-Tag: 1.19.3~511^2~16418 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=37c4906a747054113b7183e2791f6b1af2bb3e90;p=platform%2Fupstream%2Fgstreamer.git first batch Original commit message from CVS: first batch --- diff --git a/sys/Makefile.am b/sys/Makefile.am new file mode 100644 index 0000000..101ea5a --- /dev/null +++ b/sys/Makefile.am @@ -0,0 +1,5 @@ +### use HAVE_ stuff to decide on dirs +DIRS=qcam v4l vcdsrc vgasink xvideosink + +DIST_SUBDIRS=qcam v4l vcdsrc vgasink xvideosink + diff --git a/sys/v4l/Makefile.am b/sys/v4l/Makefile.am new file mode 100644 index 0000000..b99e2d4 --- /dev/null +++ b/sys/v4l/Makefile.am @@ -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 diff --git a/sys/v4l/grab-v4l.c b/sys/v4l/grab-v4l.c new file mode 100644 index 0000000..6c05950 --- /dev/null +++ b/sys/v4l/grab-v4l.c @@ -0,0 +1,973 @@ +/* + * interface to the v4l driver + * + * (c) 1997-99 Gerd Knorr + * + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include /* XXX glibc */ +#include + +#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<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; +} + diff --git a/sys/v4l/grab.h b/sys/v4l/grab.h new file mode 100644 index 0000000..0eafe76 --- /dev/null +++ b/sys/v4l/grab.h @@ -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(); diff --git a/sys/v4l/gstv4lsrc.c b/sys/v4l/gstv4lsrc.c new file mode 100644 index 0000000..fc847c8 --- /dev/null +++ b/sys/v4l/gstv4lsrc.c @@ -0,0 +1,629 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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 +#include +#include +#include +#include +#include + +//#define DEBUG_ENABLED +#include + +#include + +static GstElementDetails gst_v4lsrc_details = { + "Video (v4l) Source", + "Source/Video", + "Read from a Video for Linux capture device", + VERSION, + "Wim Taymans ", + "(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 +}; + diff --git a/sys/v4l/gstv4lsrc.h b/sys/v4l/gstv4lsrc.h new file mode 100644 index 0000000..8411e9d --- /dev/null +++ b/sys/v4l/gstv4lsrc.h @@ -0,0 +1,97 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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 +#include + +#include + +#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__ */