summaryrefslogtreecommitdiffstats
path: root/libmpdemux/tvi_v4l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmpdemux/tvi_v4l2.c')
-rw-r--r--libmpdemux/tvi_v4l2.c1746
1 files changed, 0 insertions, 1746 deletions
diff --git a/libmpdemux/tvi_v4l2.c b/libmpdemux/tvi_v4l2.c
deleted file mode 100644
index 049d34e37c..0000000000
--- a/libmpdemux/tvi_v4l2.c
+++ /dev/null
@@ -1,1746 +0,0 @@
-/*
-** Video 4 Linux 2 input
-**
-** This file is part of MPlayer, see http://mplayerhq.hu/ for info.
-**
-** (c) 2003 Martin Olschewski <olschewski@zpr.uni-koeln.de>
-** (c) 2003 Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz>
-**
-** File licensed under the GPL, see http://www.fsf.org/ for more info.
-**
-** Some ideas are based on works from
-** Alex Beregszaszi <alex@fsn.hu>
-** Gerd Knorr <kraxel@bytesex.org>
-**
-** CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE!
-*/
-
-/*
-
-known issues:
-- norm setting isn't consistent with tvi_v4l
-- the same for volume/bass/treble/balance
-
-*/
-
-#include "config.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#ifdef HAVE_SYS_SYSINFO_H
-#include <sys/sysinfo.h>
-#endif
-#include <linux/types.h>
-#include <linux/videodev2.h>
-#include "mp_msg.h"
-#include "libvo/img_format.h"
-#include "libaf/af_format.h"
-#include "tv.h"
-#include "audio_in.h"
-
-/* information about this file */
-static tvi_info_t info = {
- "Video 4 Linux 2 input",
- "v4l2",
- "Martin Olschewski <olschewski@zpr.uni-koeln.de>",
- "first try, more to come ;-)"
-};
-
-struct map {
- struct v4l2_buffer buf;
- void *addr;
- size_t len;
-};
-
-#define BUFFER_COUNT 6
-
-/* private data */
-typedef struct {
- /* video */
- char *video_dev;
- int video_fd;
- int mp_format;
- struct v4l2_capability capability;
- struct v4l2_input input;
- struct v4l2_format format;
- struct v4l2_standard standard;
- struct v4l2_tuner tuner;
- struct map *map;
- int mapcount;
- int frames;
- volatile long long first_frame;
- long long curr_frame;
- /* audio video interleaving ;-) */
- volatile int streamon;
- pthread_t audio_grabber_thread;
- pthread_mutex_t skew_mutex;
-
- /* 2nd level video buffers */
- int first;
- int immediate_mode;
-
- int video_buffer_size_max;
- volatile int video_buffer_size_current;
- unsigned char **video_ringbuffer;
- long long *video_timebuffer;
- volatile int video_head;
- volatile int video_tail;
- volatile int video_cnt;
- pthread_t video_grabber_thread;
- pthread_mutex_t video_buffer_mutex;
-
- /* audio */
- char *audio_dev;
- audio_in_t audio_in;
-
- long long audio_start_time;
- int audio_buffer_size;
- int aud_skew_cnt;
- unsigned char *audio_ringbuffer;
- long long *audio_skew_buffer;
- long long *audio_skew_delta_buffer;
- volatile int audio_head;
- volatile int audio_tail;
- volatile int audio_cnt;
- volatile long long audio_skew;
- volatile double audio_skew_factor;
- volatile long long audio_skew_measure_time;
- volatile int audio_drop;
- volatile int shutdown;
-
- int audio_inited;
- double audio_secs_per_block;
- long long audio_usecs_per_block;
- long long audio_skew_total;
- long long audio_skew_delta_total;
- long audio_recv_blocks_total;
- long audio_sent_blocks_total;
- pthread_mutex_t audio_mutex;
- int audio_insert_null_samples;
- volatile long audio_null_blocks_inserted;
- volatile long long dropped_frames_timeshift;
- long long dropped_frames_compensated;
-} priv_t;
-
-#include "tvi_def.h"
-
-static void *audio_grabber(void *data);
-static void *video_grabber(void *data);
-
-/**********************************************************************\
-
- Only few of the fourccs are the same in v4l2 and mplayer:
-
- IMGFMT_YVU9 == V4L2_PIX_FMT_YVU410
- IMGFMT_YV12 == V4L2_PIX_FMT_YVU420
- IMGFMT_NV12 == V4L2_PIX_FMT_NV12
- IMGFMT_422P == V4L2_PIX_FMT_YUV422P
- IMGFMT_411P == V4L2_PIX_FMT_YUV411P
- IMGFMT_UYVY == V4L2_PIX_FMT_UYVY
- IMGFMT_Y41P == V4L2_PIX_FMT_Y41P
-
- This may be an useful translation table for some others:
-
- IMGFMT_RGB8 == V4L2_PIX_FMT_RGB332
- IMGFMT_BGR15 == V4L2_PIX_FMT_RGB555
- IMGFMT_BGR16 == V4L2_PIX_FMT_RGB565
- IMGFMT_RGB24 == V4L2_PIX_FMT_RGB24
- IMGFMT_RGB32 == V4L2_PIX_FMT_RGB32
- IMGFMT_BGR24 == V4L2_PIX_FMT_BGR24
- IMGFMT_BGR32 == V4L2_PIX_FMT_BGR32
- IMGFMT_Y800 == V4L2_PIX_FMT_GREY
- IMGFMT_IF09 == V4L2_PIX_FMT_YUV410
- IMGFMT_I420 == V4L2_PIX_FMT_YUV420
- IMGFMT_YUY2 == V4L2_PIX_FMT_YUYV
-
-\**********************************************************************/
-
-/*
-** Translate a mplayer fourcc to a video4linux2 pixel format.
-*/
-static int fcc_mp2vl(int fcc)
-{
- switch (fcc) {
- case IMGFMT_RGB8: return V4L2_PIX_FMT_RGB332;
- case IMGFMT_BGR15: return V4L2_PIX_FMT_RGB555;
- case IMGFMT_BGR16: return V4L2_PIX_FMT_RGB565;
- case IMGFMT_RGB24: return V4L2_PIX_FMT_RGB24;
- case IMGFMT_RGB32: return V4L2_PIX_FMT_RGB32;
- case IMGFMT_BGR24: return V4L2_PIX_FMT_BGR24;
- case IMGFMT_BGR32: return V4L2_PIX_FMT_BGR32;
- case IMGFMT_Y800: return V4L2_PIX_FMT_GREY;
- case IMGFMT_IF09: return V4L2_PIX_FMT_YUV410;
- case IMGFMT_I420: return V4L2_PIX_FMT_YUV420;
- case IMGFMT_YUY2: return V4L2_PIX_FMT_YUYV;
- case IMGFMT_YV12: return V4L2_PIX_FMT_YVU420;
- case IMGFMT_UYVY: return V4L2_PIX_FMT_UYVY;
- }
- return fcc;
-}
-
-/*
-** Translate a video4linux2 fourcc aka pixel format to mplayer.
-*/
-static int fcc_vl2mp(int fcc)
-{
- switch (fcc) {
- case V4L2_PIX_FMT_RGB332: return IMGFMT_RGB8;
- case V4L2_PIX_FMT_RGB555: return IMGFMT_BGR15;
- case V4L2_PIX_FMT_RGB565: return IMGFMT_BGR16;
- case V4L2_PIX_FMT_RGB24: return IMGFMT_RGB24;
- case V4L2_PIX_FMT_RGB32: return IMGFMT_RGB32;
- case V4L2_PIX_FMT_BGR24: return IMGFMT_BGR24;
- case V4L2_PIX_FMT_BGR32: return IMGFMT_BGR32;
- case V4L2_PIX_FMT_GREY: return IMGFMT_Y800;
- case V4L2_PIX_FMT_YUV410: return IMGFMT_IF09;
- case V4L2_PIX_FMT_YUV420: return IMGFMT_I420;
- case V4L2_PIX_FMT_YVU420: return IMGFMT_YV12;
- case V4L2_PIX_FMT_YUYV: return IMGFMT_YUY2;
- case V4L2_PIX_FMT_UYVY: return IMGFMT_UYVY;
- }
- return fcc;
-}
-
-/*
-** Translate a video4linux2 fourcc aka pixel format
-** to a human readable string.
-*/
-static const char *pixfmt2name(int pixfmt)
-{
- static char unknown[24];
-
- switch (pixfmt) {
- case V4L2_PIX_FMT_RGB332: return "RGB332";
- case V4L2_PIX_FMT_RGB555: return "RGB555";
- case V4L2_PIX_FMT_RGB565: return "RGB565";
- case V4L2_PIX_FMT_RGB555X: return "RGB555X";
- case V4L2_PIX_FMT_RGB565X: return "RGB565X";
- case V4L2_PIX_FMT_BGR24: return "BGR24";
- case V4L2_PIX_FMT_RGB24: return "RGB24";
- case V4L2_PIX_FMT_BGR32: return "BGR32";
- case V4L2_PIX_FMT_RGB32: return "RGB32";
- case V4L2_PIX_FMT_GREY: return "GREY";
- case V4L2_PIX_FMT_YVU410: return "YVU410";
- case V4L2_PIX_FMT_YVU420: return "YVU420";
- case V4L2_PIX_FMT_YUYV: return "YUYV";
- case V4L2_PIX_FMT_UYVY: return "UYVY";
-/* case V4L2_PIX_FMT_YVU422P: return "YVU422P"; */
-/* case V4L2_PIX_FMT_YVU411P: return "YVU411P"; */
- case V4L2_PIX_FMT_YUV422P: return "YUV422P";
- case V4L2_PIX_FMT_YUV411P: return "YUV411P";
- case V4L2_PIX_FMT_Y41P: return "Y41P";
- case V4L2_PIX_FMT_NV12: return "NV12";
- case V4L2_PIX_FMT_NV21: return "NV21";
- case V4L2_PIX_FMT_YUV410: return "YUV410";
- case V4L2_PIX_FMT_YUV420: return "YUV420";
- case V4L2_PIX_FMT_YYUV: return "YYUV";
- case V4L2_PIX_FMT_HI240: return "HI240";
- case V4L2_PIX_FMT_WNVA: return "WNVA";
- }
- sprintf(unknown, "unknown (0x%x)", pixfmt);
- return unknown;
-}
-
-
-/*
-** Gives the depth of a video4linux2 fourcc aka pixel format in bits.
-*/
-static int pixfmt2depth(int pixfmt)
-{
- switch (pixfmt) {
- case V4L2_PIX_FMT_RGB332:
- return 8;
- case V4L2_PIX_FMT_RGB555:
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB555X:
- case V4L2_PIX_FMT_RGB565X:
- return 16;
- case V4L2_PIX_FMT_BGR24:
- case V4L2_PIX_FMT_RGB24:
- return 24;
- case V4L2_PIX_FMT_BGR32:
- case V4L2_PIX_FMT_RGB32:
- return 32;
- case V4L2_PIX_FMT_GREY:
- return 8;
- case V4L2_PIX_FMT_YVU410:
- return 9;
- case V4L2_PIX_FMT_YVU420:
- return 12;
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUV422P:
- case V4L2_PIX_FMT_YUV411P:
- return 16;
- case V4L2_PIX_FMT_Y41P:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- return 12;
- case V4L2_PIX_FMT_YUV410:
- return 9;
- case V4L2_PIX_FMT_YUV420:
- return 12;
- case V4L2_PIX_FMT_YYUV:
- return 16;
- case V4L2_PIX_FMT_HI240:
- return 8;
-
- }
- return 0;
-}
-
-static int amode2v4l(int amode)
-{
- switch (amode) {
- case 0:
- return V4L2_TUNER_MODE_MONO;
- case 1:
- return V4L2_TUNER_MODE_STEREO;
- case 2:
- return V4L2_TUNER_MODE_LANG1;
- case 3:
- return V4L2_TUNER_MODE_LANG2;
- default:
- return -1;
- }
-}
-
-
-// sets and sanitizes audio buffer/block sizes
-static void setup_audio_buffer_sizes(priv_t *priv)
-{
- int bytes_per_sample = priv->audio_in.bytes_per_sample;
- double fps = (double)priv->standard.frameperiod.denominator /
- priv->standard.frameperiod.numerator;
- int seconds = priv->video_buffer_size_max/fps;
-
- if (seconds < 5) seconds = 5;
- if (seconds > 500) seconds = 500;
-
- // make the audio buffer at least as the video buffer capacity (or 5 seconds) long
- priv->audio_buffer_size = 1 + seconds*priv->audio_in.samplerate
- *priv->audio_in.channels
- *bytes_per_sample/priv->audio_in.blocksize;
- if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256;
-
- // make the skew buffer at least 1 second long
- priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate
- *priv->audio_in.channels
- *bytes_per_sample/priv->audio_in.blocksize;
- if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16;
-
- mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n",
- priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt);
-}
-
-static void init_audio(priv_t *priv)
-{
- if (priv->audio_inited) return;
-
- if (!tv_param_noaudio) {
-#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
- if (tv_param_alsa)
- audio_in_init(&priv->audio_in, AUDIO_IN_ALSA);
- else
- audio_in_init(&priv->audio_in, AUDIO_IN_OSS);
-#else
- audio_in_init(&priv->audio_in, AUDIO_IN_OSS);
-#endif
-
- if (priv->audio_dev) {
- audio_in_set_device(&priv->audio_in, priv->audio_dev);
- }
-
- audio_in_set_samplerate(&priv->audio_in, 44100);
- if (priv->capability.capabilities & V4L2_CAP_TUNER) {
- if (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) {
- audio_in_set_channels(&priv->audio_in, 2);
- } else {
- audio_in_set_channels(&priv->audio_in, 1);
- }
- } else {
- if (tv_param_forcechan >= 0) {
- audio_in_set_channels(&priv->audio_in, tv_param_forcechan);
- } else {
- audio_in_set_channels(&priv->audio_in, 2);
- }
- }
-
- if (audio_in_setup(&priv->audio_in) < 0) return;
-
- priv->audio_inited = 1;
- }
-}
-
-#if 0
-/*
-** the number of milliseconds elapsed between time0 and time1
-*/
-static size_t difftv(struct timeval time1, struct timeval time0)
-{
- return (time1.tv_sec - time0.tv_sec) * 1000 +
- (time1.tv_usec - time0.tv_usec) / 1000;
-}
-#endif
-
-/*
-** Get current video capture format.
-*/
-static int getfmt(priv_t *priv)
-{
- int i;
-
- priv->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if ((i = ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get format failed: %s\n",
- info.short_name, strerror(errno));
- }
- return i;
-}
-
-
-/*
-** Get current video capture standard.
-*/
-static int getstd(priv_t *priv)
-{
- v4l2_std_id id;
- int i=0;
-
- if (ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get standard failed: %s\n",
- info.short_name, strerror(errno));
- return -1;
- }
- do {
- priv->standard.index = i++;
- if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) {
- return -1;
- }
- } while (priv->standard.id != id);
- return 0;
-}
-
-/***********************************************************************\
- * *
- * *
- * Interface to mplayer *
- * *
- * *
-\***********************************************************************/
-
-static int set_mute(priv_t *priv, int value)
-{
- struct v4l2_control control;
- control.id = V4L2_CID_AUDIO_MUTE;
- control.value = value;
- if (ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) {
- mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set mute failed: %s\n",
- info.short_name, strerror(errno));
- return 0;
- }
- return 1;
-}
-
-/*
-** MPlayer uses values from -100 up to 100 for controls.
-** Here they are scaled to what the tv card needs and applied.
-*/
-static int set_control(priv_t *priv, struct v4l2_control *control, int val_signed) {
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = control->id;
- if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
-
- if (val_signed) {
- if (control->value < 0) {
- control->value = qctrl.default_value + control->value *
- (qctrl.default_value - qctrl.minimum) / 100;
- } else {
- control->value = qctrl.default_value + control->value *
- (qctrl.maximum - qctrl.default_value) / 100;
- }
- } else {
- if (control->value < 50) {
- control->value = qctrl.default_value + (control->value-50) *
- (qctrl.default_value - qctrl.minimum) / 50;
- } else {
- control->value = qctrl.default_value + (control->value-50) *
- (qctrl.maximum - qctrl.default_value) / 50;
- }
- }
-
-
- if (ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl set %s %d failed: %s\n",
- info.short_name, qctrl.name, control->value, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- mp_msg(MSGT_TV, MSGL_V, "%s: set %s: %d [%d, %d]\n", info.short_name,
- qctrl.name, control->value, qctrl.minimum, qctrl.maximum);
-
- return TVI_CONTROL_TRUE;
-}
-
-
-/*
-** Scale the control values back to what mplayer needs.
-*/
-static int get_control(priv_t *priv, struct v4l2_control *control, int val_signed) {
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = control->id;
- if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
-
- if (ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl get %s failed: %s\n",
- info.short_name, qctrl.name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- mp_msg(MSGT_TV, MSGL_V, "%s: get %s: %d [%d, %d]\n", info.short_name,
- qctrl.name, control->value, qctrl.minimum, qctrl.maximum);
-
- if (val_signed) {
- if (control->value < qctrl.default_value) {
- control->value = (control->value - qctrl.default_value) * 100 /
- (qctrl.default_value - qctrl.minimum);
- } else {
- control->value = (control->value - qctrl.default_value) * 100 /
- (qctrl.maximum - qctrl.default_value);
- }
- } else {
- if (control->value < qctrl.default_value) {
- control->value = (control->value - qctrl.default_value) * 50 /
- (qctrl.default_value - qctrl.minimum) + 50;
- } else {
- control->value = (control->value - qctrl.default_value) * 50 /
- (qctrl.maximum - qctrl.default_value) + 50;
- }
- }
-
- return TVI_CONTROL_TRUE;
-}
-
-static int control(priv_t *priv, int cmd, void *arg)
-{
- struct v4l2_control control;
- struct v4l2_frequency frequency;
-
- switch(cmd) {
- case TVI_CONTROL_IS_VIDEO:
- return priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE?
- TVI_CONTROL_TRUE: TVI_CONTROL_FALSE;
- case TVI_CONTROL_IS_AUDIO:
- if (tv_param_force_audio) return TVI_CONTROL_TRUE;
- case TVI_CONTROL_IS_TUNER:
- return priv->capability.capabilities & V4L2_CAP_TUNER?
- TVI_CONTROL_TRUE: TVI_CONTROL_FALSE;
- case TVI_CONTROL_IMMEDIATE:
- priv->immediate_mode = 1;
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_GET_FPS:
- *(float *)arg = (float)priv->standard.frameperiod.denominator /
- priv->standard.frameperiod.numerator;
- mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name,
- *(float *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_GET_BITS:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- *(int *)arg = pixfmt2depth(priv->format.fmt.pix.pixelformat);
- mp_msg(MSGT_TV, MSGL_V, "%s: get depth: %d\n", info.short_name,
- *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_GET_FORMAT:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- *(int *)arg = fcc_vl2mp(priv->format.fmt.pix.pixelformat);
- mp_msg(MSGT_TV, MSGL_V, "%s: get format: %s\n", info.short_name,
- pixfmt2name(priv->format.fmt.pix.pixelformat));
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_SET_FORMAT:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- priv->format.fmt.pix.pixelformat = fcc_mp2vl(*(int *)arg);
- priv->format.fmt.pix.field = V4L2_FIELD_ANY;
-
- priv->mp_format = *(int *)arg;
- mp_msg(MSGT_TV, MSGL_V, "%s: set format: %s\n", info.short_name,
- pixfmt2name(priv->format.fmt.pix.pixelformat));
- if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- /* according to the v4l2 specs VIDIOC_S_FMT should not fail, inflexible drivers
- might even always return the default parameters -> update the format here*/
- priv->mp_format = fcc_vl2mp(priv->format.fmt.pix.pixelformat);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_GET_WIDTH:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->format.fmt.pix.width;
- mp_msg(MSGT_TV, MSGL_V, "%s: get width: %d\n", info.short_name,
- *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_CHK_WIDTH:
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_SET_WIDTH:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- priv->format.fmt.pix.width = *(int *)arg;
- mp_msg(MSGT_TV, MSGL_V, "%s: set width: %d\n", info.short_name,
- *(int *)arg);
- if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set width failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_GET_HEIGHT:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->format.fmt.pix.height;
- mp_msg(MSGT_TV, MSGL_V, "%s: get height: %d\n", info.short_name,
- *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_CHK_HEIGHT:
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_SET_HEIGHT:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- priv->format.fmt.pix.height = *(int *)arg;
- priv->format.fmt.pix.field = V4L2_FIELD_ANY;
- mp_msg(MSGT_TV, MSGL_V, "%s: set height: %d\n", info.short_name,
- *(int *)arg);
- if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set height failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_GET_BRIGHTNESS:
- control.id = V4L2_CID_BRIGHTNESS;
- if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) {
- *(int *)arg = control.value;
- return TVI_CONTROL_TRUE;
- }
- return TVI_CONTROL_FALSE;
- case TVI_CONTROL_VID_SET_BRIGHTNESS:
- control.id = V4L2_CID_BRIGHTNESS;
- control.value = *(int *)arg;
- return set_control(priv, &control, 1);
- case TVI_CONTROL_VID_GET_HUE:
- control.id = V4L2_CID_HUE;
- if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) {
- *(int *)arg = control.value;
- return TVI_CONTROL_TRUE;
- }
- return TVI_CONTROL_FALSE;
- case TVI_CONTROL_VID_SET_HUE:
- control.id = V4L2_CID_HUE;
- control.value = *(int *)arg;
- return set_control(priv, &control, 1);
- case TVI_CONTROL_VID_GET_SATURATION:
- control.id = V4L2_CID_SATURATION;
- if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) {
- *(int *)arg = control.value;
- return TVI_CONTROL_TRUE;
- }
- return TVI_CONTROL_FALSE;
- case TVI_CONTROL_VID_SET_SATURATION:
- control.id = V4L2_CID_SATURATION;
- control.value = *(int *)arg;
- return set_control(priv, &control, 1);
- case TVI_CONTROL_VID_GET_CONTRAST:
- control.id = V4L2_CID_CONTRAST;
- if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) {
- *(int *)arg = control.value;
- return TVI_CONTROL_TRUE;
- }
- return TVI_CONTROL_FALSE;
- case TVI_CONTROL_VID_SET_CONTRAST:
- control.id = V4L2_CID_CONTRAST;
- control.value = *(int *)arg;
- return set_control(priv, &control, 1);
- case TVI_CONTROL_TUN_GET_FREQ:
- frequency.tuner = 0;
- frequency.type = V4L2_TUNER_ANALOG_TV;
- if (ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) {
- mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl get frequency failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- *(int *)arg = frequency.frequency;
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_SET_FREQ:
-#if 0
- set_mute(priv, 1);
- usleep(100000); // wait to suppress noise during switching
-#endif
- frequency.tuner = 0;
- frequency.type = V4L2_TUNER_ANALOG_TV;
- frequency.frequency = *(int *)arg;
- if (ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) {
- mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set frequency failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
-#if 0
- usleep(100000); // wait to suppress noise during switching
- set_mute(priv, 0);
-#endif
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_GET_TUNER:
- mp_msg(MSGT_TV, MSGL_V, "%s: get tuner\n",info.short_name);
- if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_SET_TUNER:
- mp_msg(MSGT_TV, MSGL_V, "%s: set tuner\n",info.short_name);
- if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_GET_NORM:
- *(int *)arg = priv->standard.index;
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_SET_NORM:
- priv->standard.index = *(int *)arg;
- if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum norm failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- mp_msg(MSGT_TV, MSGL_V, "%s: set norm: %s\n", info.short_name, priv->standard.name);
- if (ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set norm failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_SPC_GET_NORMID:
- {
- int i;
- for (i = 0;; i++) {
- struct v4l2_standard standard;
- memset(&standard, 0, sizeof(standard));
- standard.index = i;
- if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard))
- return TVI_CONTROL_FALSE;
- if (!strcasecmp(standard.name, (char *)arg)) {
- *(int *)arg = i;
- return TVI_CONTROL_TRUE;
- }
- }
- return TVI_CONTROL_FALSE;
- }
- case TVI_CONTROL_SPC_GET_INPUT:
- if (ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_SPC_SET_INPUT:
- mp_msg(MSGT_TV, MSGL_V, "%s: set input: %d\n", info.short_name, *(int *)arg);
- priv->input.index = *(int *)arg;
- if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum input failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- if (ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set input failed: %s\n",
- info.short_name, strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_FORMAT:
- init_audio(priv);
- if (!priv->audio_inited) return TVI_CONTROL_FALSE;
- *(int *)arg = AF_FORMAT_S16_LE;
- mp_msg(MSGT_TV, MSGL_V, "%s: get audio format: %d\n",
- info.short_name, *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_SAMPLERATE:
- init_audio(priv);
- if (!priv->audio_inited) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->audio_in.samplerate;
- mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplerate: %d\n",
- info.short_name, *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_SAMPLESIZE:
- init_audio(priv);
- if (!priv->audio_inited) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->audio_in.bytes_per_sample;
- mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplesize: %d\n",
- info.short_name, *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_CHANNELS:
- init_audio(priv);
- if (!priv->audio_inited) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->audio_in.channels;
- mp_msg(MSGT_TV, MSGL_V, "%s: get audio channels: %d\n",
- info.short_name, *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_SET_SAMPLERATE:
- init_audio(priv);
- mp_msg(MSGT_TV, MSGL_V, "%s: set audio samplerate: %d\n",
- info.short_name, *(int *)arg);
- if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE;
-// setup_audio_buffer_sizes(priv);
- return TVI_CONTROL_TRUE;
- }
- mp_msg(MSGT_TV, MSGL_V, "%s: unknown control: %d\n", info.short_name, cmd);
- return(TVI_CONTROL_UNKNOWN);
-}
-
-
-#define PRIV ((priv_t *) (tvi_handle->priv))
-
-/* handler creator - entry point ! */
-tvi_handle_t *tvi_init_v4l2(char *video_dev, char *audio_dev)
-{
- tvi_handle_t *tvi_handle;
-
- /* new_handle initializes priv with memset 0 */
- tvi_handle = new_handle();
- if (!tvi_handle) {
- return NULL;
- }
- PRIV->video_fd = -1;
-
- PRIV->video_dev = strdup(video_dev? video_dev: "/dev/video0");
- if (!PRIV->video_dev) {
- free_handle(tvi_handle);
- return NULL;
- }
-
- if (audio_dev) {
- PRIV->audio_dev = strdup(audio_dev);
- if (!PRIV->audio_dev) {
- free(PRIV->video_dev);
- free_handle(tvi_handle);
- return NULL;
- }
- }
-
- return tvi_handle;
-}
-
-#undef PRIV
-
-
-static int uninit(priv_t *priv)
-{
- int i, frames, dropped = 0;
-
- priv->shutdown = 1;
- if(priv->video_grabber_thread)
- pthread_join(priv->video_grabber_thread, NULL);
- pthread_mutex_destroy(&priv->video_buffer_mutex);
-
- if (priv->streamon) {
- struct v4l2_buffer buf;
-
- /* get performance */
- frames = 1 + (priv->curr_frame - priv->first_frame +
- priv->standard.frameperiod.numerator * 500000 /
- priv->standard.frameperiod.denominator) *
- priv->standard.frameperiod.denominator /
- priv->standard.frameperiod.numerator / 1000000;
- dropped = frames - priv->frames;
-
- /* turn off streaming */
- if (ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamoff failed: %s\n",
- info.short_name, strerror(errno));
- }
- priv->streamon = 0;
-
- /* unqueue all remaining buffers */
- memset(&buf,0,sizeof(buf));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- while (!ioctl(priv->video_fd, VIDIOC_DQBUF, &buf));
- }
-
- /* unmap all buffers */
- for (i = 0; i < priv->mapcount; i++) {
- if (munmap(priv->map[i].addr, priv->map[i].len) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: munmap capture buffer failed: %s\n",
- info.short_name, strerror(errno));
- }
- }
-
- /* stop audio thread */
- if (!tv_param_noaudio && priv->audio_grabber_thread) {
- pthread_join(priv->audio_grabber_thread, NULL);
- pthread_mutex_destroy(&priv->skew_mutex);
- pthread_mutex_destroy(&priv->audio_mutex);
- }
-
- set_mute(priv, 1);
-
- /* free memory and close device */
- free(priv->map); priv->map = NULL;
- priv->mapcount = 0;
- if(priv->video_fd!=-1)close(priv->video_fd); priv->video_fd = -1;
- free(priv->video_dev); priv->video_dev = NULL;
-
- if (priv->video_ringbuffer) {
- int i;
- for (i = 0; i < priv->video_buffer_size_current; i++) {
- free(priv->video_ringbuffer[i]);
- }
- free(priv->video_ringbuffer);
- }
- if (priv->video_timebuffer)
- free(priv->video_timebuffer);
- if (!tv_param_noaudio) {
- if (priv->audio_ringbuffer)
- free(priv->audio_ringbuffer);
- if (priv->audio_skew_buffer)
- free(priv->audio_skew_buffer);
- if (priv->audio_skew_delta_buffer)
- free(priv->audio_skew_delta_buffer);
- }
-
- /* show some nice statistics ;-) */
- mp_msg(MSGT_TV, MSGL_INFO,
- "%s: %d frames successfully processed, %d frames dropped.\n",
- info.short_name, priv->frames, dropped);
- mp_msg(MSGT_TV, MSGL_V, "%s: up to %u video frames buffered.\n",
- info.short_name, priv->video_buffer_size_current);
- return 1;
-}
-
-
-/* initialisation */
-static int init(priv_t *priv)
-{
- int i;
-
- priv->audio_ringbuffer = NULL;
- priv->audio_skew_buffer = NULL;
- priv->audio_skew_delta_buffer = NULL;
-
- priv->audio_inited = 0;
-
- /* Open the video device. */
- priv->video_fd = open(priv->video_dev, O_RDWR);
- if (priv->video_fd < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: unable to open '%s': %s\n",
- info.short_name, priv->video_dev, strerror(errno));
- uninit(priv);
- return 0;
- }
- mp_msg(MSGT_TV, MSGL_DBG2, "%s: video fd: %s: %d\n",
- info.short_name, priv->video_dev, priv->video_fd);
-
- /*
- ** Query the video capabilities and current settings
- ** for further control calls.
- */
- if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query capabilities failed: %s\n",
- info.short_name, strerror(errno));
- uninit(priv);
- return 0;
- }
-
- if (!(priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE))
- {
- mp_msg(MSGT_TV, MSGL_ERR, "Device %s is not a video capture device.\n",
- priv->video_dev);
- return 0;
- }
-
- if (getfmt(priv) < 0) {
- uninit(priv);
- return 0;
- }
- getstd(priv);
- /*
- ** if this device has got a tuner query it's settings
- ** otherwise set some nice defaults
- */
- if (priv->capability.capabilities & V4L2_CAP_TUNER) {
- if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) {
- mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n",
- info.short_name, strerror(errno));
- uninit(priv);
- return 0;
- }
- }
- mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.card);
- if (priv->capability.capabilities & V4L2_CAP_TUNER) {
- mp_msg(MSGT_TV, MSGL_INFO, " Tuner cap:%s%s%s\n",
- (priv->tuner.capability & V4L2_TUNER_CAP_STEREO) ? " STEREO" : "",
- (priv->tuner.capability & V4L2_TUNER_CAP_LANG1) ? " LANG1" : "",
- (priv->tuner.capability & V4L2_TUNER_CAP_LANG2) ? " LANG2" : "");
- mp_msg(MSGT_TV, MSGL_INFO, " Tuner rxs:%s%s%s%s\n",
- (priv->tuner.rxsubchans & V4L2_TUNER_SUB_MONO) ? " MONO" : "",
- (priv->tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) ? " STEREO" : "",
- (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG1) ? " LANG1" : "",
- (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG2) ? " LANG2" : "");
- }
- mp_msg(MSGT_TV, MSGL_INFO, " Capabilites:%s%s%s%s%s%s%s%s%s%s%s\n",
- priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE?
- " video capture": "",
- priv->capability.capabilities & V4L2_CAP_VIDEO_OUTPUT?
- " video output": "",
- priv->capability.capabilities & V4L2_CAP_VIDEO_OVERLAY?
- " video overlay": "",
- priv->capability.capabilities & V4L2_CAP_VBI_CAPTURE?
- " VBI capture device": "",
- priv->capability.capabilities & V4L2_CAP_VBI_OUTPUT?
- " VBI output": "",
- priv->capability.capabilities & V4L2_CAP_RDS_CAPTURE?
- " RDS data capture": "",
- priv->capability.capabilities & V4L2_CAP_TUNER?
- " tuner": "",
- priv->capability.capabilities & V4L2_CAP_AUDIO?
- " audio": "",
- priv->capability.capabilities & V4L2_CAP_READWRITE?
- " read/write": "",
- priv->capability.capabilities & V4L2_CAP_ASYNCIO?
- " async i/o": "",
- priv->capability.capabilities & V4L2_CAP_STREAMING?
- " streaming": "");
- mp_msg(MSGT_TV, MSGL_INFO, " supported norms:");
- for (i = 0;; i++) {
- struct v4l2_standard standard;
- memset(&standard, 0, sizeof(standard));
- standard.index = i;
- if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard))
- break;
- mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, standard.name);
- }
- mp_msg(MSGT_TV, MSGL_INFO, "\n inputs:");
- for (i = 0; 1; i++) {
- struct v4l2_input input;
-
- input.index = i;
- if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {