mpv/libmpdemux/tvi_v4l.c

268 lines
6.1 KiB
C

#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 */