summaryrefslogtreecommitdiffstats
path: root/libmpdemux/tvi_v4l.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmpdemux/tvi_v4l.c')
-rw-r--r--libmpdemux/tvi_v4l.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/libmpdemux/tvi_v4l.c b/libmpdemux/tvi_v4l.c
new file mode 100644
index 0000000000..43fb8713f4
--- /dev/null
+++ b/libmpdemux/tvi_v4l.c
@@ -0,0 +1,267 @@
+#include "config.h"
+
+#ifdef USE_TV
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/videodev.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "tv.h"
+
+static tvi_info_t info = {
+ "Video for Linux TV Input",
+ "v4l",
+ "alex",
+ "non-completed"
+};
+
+typedef struct {
+ char *video_device;
+ int fd;
+ struct video_capability capability;
+ struct video_channel *channels;
+ struct video_tuner tuner;
+ struct video_audio audio;
+ struct video_picture picture;
+
+ int buffered;
+ struct video_mbuf mbuf;
+ unsigned int *mmap;
+ struct video_mmap *buf;
+
+ int width;
+ int height;
+} priv_t;
+
+#include "tvi_def.h"
+
+static const char *device_cap[] = {
+ "capture", "tuner", "teletext", "overlay", "chromakey", "clipping",
+ "frameram", "scales", "monochrome", NULL
+};
+
+tvi_handle_t *tvi_init_v4l(char *device)
+{
+ tvi_handle_t *h;
+ priv_t *priv;
+
+ h = new_handle();
+ if (!h)
+ return(NULL);
+
+ priv = h->priv;
+
+ if (!device)
+ {
+ priv->video_device = malloc(strlen("/dev/video0"));
+ strcpy(priv->video_device, &"/dev/video0");
+ }
+ else
+ {
+ priv->video_device = malloc(strlen(device));
+ strcpy(priv->video_device, device);
+ }
+
+ return(h);
+}
+
+static int init(priv_t *priv)
+{
+ int i;
+
+ priv->fd = open(priv->video_device, O_RDONLY);
+ if (priv->fd == -1)
+ {
+ printf("v4l: open %s: %s\n", priv->video_device, strerror(errno));
+ goto err;
+ }
+
+ printf("fd: %d\n", priv->fd);
+
+ /* get capabilities */
+ if (ioctl(priv->fd, VIDIOCGCAP, &priv->capability) == -1)
+ {
+ printf("v4l: ioctl error: %s\n", strerror(errno));
+ goto err;
+ }
+
+ fcntl(priv->fd, F_SETFD, FD_CLOEXEC);
+
+ printf("capabilites: ");
+ for (i = 0; device_cap[i] != NULL; i++)
+ if (priv->capability.type & (1 << i))
+ printf(" %s", device_cap[i]);
+ printf("\n");
+ printf(" type: %d\n", priv->capability.type);
+ printf(" size: %dx%d => %dx%d\n",
+ priv->capability.minwidth, priv->capability.minheight,
+ priv->capability.maxwidth, priv->capability.maxheight);
+ priv->width = priv->capability.minwidth;
+ priv->height = priv->capability.minheight;
+ printf(" channels: %d\n", priv->capability.channels);
+
+ priv->channels = malloc(sizeof(struct video_channel)*priv->capability.channels);
+ memset(priv->channels, 0, sizeof(struct video_channel)*priv->capability.channels);
+ for (i = 0; i < priv->capability.channels; i++)
+ {
+ priv->channels[i].channel = i;
+ ioctl(priv->fd, VIDIOCGCHAN, &priv->channels[i]);
+ printf(" %s: tuners:%d %s%s %s%s\n",
+ priv->channels[i].name,
+ priv->channels[i].tuners,
+ (priv->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "",
+ (priv->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "",
+ (priv->channels[i].flags & VIDEO_TYPE_TV) ? "tv " : "",
+ (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "");
+ }
+
+ if (priv->capability.type & VID_TYPE_CAPTURE)
+ {
+ if (ioctl(priv->fd, VIDIOCGMBUF, &priv->mbuf) == 0)
+ {
+ printf("mbuf: size=%d, frames=%d (first offset: %p)\n",
+ priv->mbuf.size, priv->mbuf.frames, priv->mbuf.offsets[0]);
+ priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, priv->fd, 0);
+ if (priv->mmap == -1)
+ perror("mmap");
+ }
+ else
+ priv->mmap = -1;
+
+ if (priv->mmap != -1)
+ {
+ priv->buf = malloc(priv->mbuf.frames * sizeof(struct video_mmap));
+ memset(priv->buf, 0, priv->mbuf.frames * sizeof(struct video_mmap));
+ priv->buffered = 1;
+ }
+ else
+ priv->buffered = 0;
+ }
+
+ printf("buffered: %d\n", priv->buffered);
+
+ return(1);
+
+err:
+ if (priv->fd != -1)
+ close(priv->fd);
+ return(0);
+}
+
+static int exit(priv_t *priv)
+{
+}
+
+static int tune(priv_t *priv, int freq, int chan, int norm)
+{
+ if (freq)
+ {
+ ioctl(priv->fd, VIDIOCSFREQ, &freq);
+ return(1);
+ }
+
+ if (chan && norm)
+ {
+ /* set channel & norm ! */
+ }
+
+ return(0);
+}
+
+static int control(priv_t *priv, int cmd, void *arg)
+{
+ switch(cmd)
+ {
+ case TVI_CONTROL_VID_GET_FORMAT:
+ (int)*(void **)arg = 0x0;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_GET_PLANES:
+ (int)*(void **)arg = 1;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_GET_BITS:
+ (int)*(void **)arg = 12;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_GET_WIDTH:
+ (int)*(void **)arg = priv->width;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_CHK_WIDTH:
+ {
+ int req_width = (int)*(void **)arg;
+
+ printf("req_width: %d\n", req_width);
+ if ((req_width > priv->capability.minwidth) &&
+ (req_width < priv->capability.maxwidth))
+ return(TVI_CONTROL_TRUE);
+ return(TVI_CONTROL_FALSE);
+ }
+ case TVI_CONTROL_VID_SET_WIDTH:
+ priv->width = (int)*(void **)arg;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_GET_HEIGHT:
+ (int)*(void **)arg = priv->height;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_CHK_HEIGHT:
+ {
+ int req_height = (int)*(void **)arg;
+
+ printf("req_height: %d\n", req_height);
+ if ((req_height > priv->capability.minheight) &&
+ (req_height < priv->capability.maxheight))
+ return(TVI_CONTROL_TRUE);
+ return(TVI_CONTROL_FALSE);
+ }
+ case TVI_CONTROL_VID_SET_HEIGHT:
+ priv->height = (int)*(void **)arg;
+ return(TVI_CONTROL_TRUE);
+
+ case TVI_CONTROL_TUN_SET_FREQ:
+ {
+ long freq = (long)*(void **)arg; /* shit: long -> freq */
+
+ printf("requested frequency: %f\n", freq);
+ if (ioctl(priv->fd, VIDIOCSFREQ, &freq) != -1)
+ return(TVI_CONTROL_TRUE);
+ return(TVI_CONTROL_FALSE);
+ }
+ }
+
+ return(TVI_CONTROL_UNKNOWN);
+}
+
+static int grab_video_frame(priv_t *priv, char *buffer, int len)
+{
+ priv->buf[0].frame = 0;
+ priv->buf[0].width = 320;
+ priv->buf[0].height = 240;
+ priv->buf[0].format = VIDEO_PALETTE_YUV422;
+
+ if (ioctl(priv->fd, VIDIOCMCAPTURE, priv->buf) == -1)
+ {
+ printf("grab_video_frame failed: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int get_video_framesize(priv_t *priv)
+{
+ return 65536;
+}
+
+static int grab_audio_frame(priv_t *priv, char *buffer, int len)
+{
+}
+
+static int get_audio_framesize(priv_t *priv)
+{
+ return 65536;
+}
+
+#endif /* USE_TV */