summaryrefslogtreecommitdiffstats
path: root/stream/tvi_v4l2.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-09-13 17:16:18 +0200
committerwm4 <wm4@nowhere>2019-09-13 17:32:19 +0200
commitb30e85508a305d668db8419556d295a65ab08707 (patch)
treefa48444a183c97fd5081aa0206c5adece43eaf32 /stream/tvi_v4l2.c
parent162e0f5ad92116d1a4fb740d087da2a152686b73 (diff)
downloadmpv-b30e85508a305d668db8419556d295a65ab08707.tar.bz2
mpv-b30e85508a305d668db8419556d295a65ab08707.tar.xz
Remove classic Linux analog TV support, and DVB runtime controls
Linux analog TV support (via tv://) was excessively complex, and whenever I attempted to use it (cameras or loopback devices), it didn't work well, or would have required some major work to update it. It's very much stuck in the analog past (my favorite are the frequency tables in frequencies.c for analog TV channels which don't exist anymore). Especially cameras and such work fine with libavdevice and better than tv://, for example: mpv av://v4l2:/dev/video0 (adding --profile=low-latency --untimed even makes it mostly realtime) Adding a new input layer that targets such "modern" uses would be acceptable, if anyone is interested in it. The old TV code is just too focused on actual analog TV. DVB is rather obscure, but has an active maintainer, so don't remove it. However, the demux/stream ctrl layer must go, so remove controls for channel switching. Most of these could be reimplemented by using the normal method for option runtime changes.
Diffstat (limited to 'stream/tvi_v4l2.c')
-rw-r--r--stream/tvi_v4l2.c1786
1 files changed, 0 insertions, 1786 deletions
diff --git a/stream/tvi_v4l2.c b/stream/tvi_v4l2.c
deleted file mode 100644
index 70595c6034..0000000000
--- a/stream/tvi_v4l2.c
+++ /dev/null
@@ -1,1786 +0,0 @@
-/*
- * Video 4 Linux 2 input
- *
- * copyright (c) 2003 Martin Olschewski <olschewski@zpr.uni-koeln.de>
- * copyright (c) 2003 Jindrich Makovicka <makovick@gmail.com>
- *
- * Some ideas are based on works from
- * Alex Beregszaszi <alex@fsn.hu>
- * Gerd Knorr <kraxel@bytesex.org>
- *
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * mpv 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
-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 <strings.h>
-#include <time.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <math.h>
-#if HAVE_SYS_VIDEOIO_H
-#include <sys/videoio.h>
-#else
-#include <linux/videodev2.h>
-#endif
-#if HAVE_LIBV4L2
-#include <libv4l2.h>
-#endif
-#include "common/msg.h"
-#include "common/common.h"
-#include "audio/format.h"
-#include "tv.h"
-#include "audio_in.h"
-
-#if !HAVE_LIBV4L2
-#define v4l2_open open
-#define v4l2_close close
-#define v4l2_ioctl ioctl
-#define v4l2_mmap mmap
-#define v4l2_munmap munmap
-#endif
-
-// flag introduced in kernel 3.10
-#ifndef V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
-#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000
-#endif
-
-#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
-#define HAVE_CLOCK_GETTIME 1
-#else
-#define HAVE_CLOCK_GETTIME 0
-#endif
-
-#define info tvi_info_v4l2
-static tvi_handle_t *tvi_init_v4l2(struct mp_log *log, tv_param_t* tv_param);
-/* information about this file */
-const tvi_info_t tvi_info_v4l2 = {
- tvi_init_v4l2,
- "Video 4 Linux 2 input",
- "v4l2",
-};
-
-struct map {
- struct v4l2_buffer buf;
- void *addr;
- size_t len;
-};
-
-#define BUFFER_COUNT 6
-
-/** video ringbuffer entry */
-typedef struct {
- unsigned char *data; ///< frame contents
- long long timestamp; ///< frame timestamp
- int framesize; ///< actual frame size
-} video_buffer_entry;
-
-/* private data */
-typedef struct priv {
- /* video */
- struct mp_log *log;
- 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; ///< number of useconds
- long long curr_frame; ///< usec, using kernel timestamps
- int clk_id; /**< clk_id from clock_gettime
- used in frame timestamps */
- /* 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;
- video_buffer_entry *video_ringbuffer;
- 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_initialized;
- 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;
-
- tv_param_t *tv_param;
-} priv_t;
-
-typedef struct tt_stream_props_s{
- int sampling_rate;
- int samples_per_line;
- int offset;
- int count[2]; ///< number of lines in first and second fields
- int interlaced; ///< vbi data are interlaced
- int bufsize; ///< required buffer size
-} tt_stream_props;
-
-#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:
-
- MP_FOURCC_YVU9 == V4L2_PIX_FMT_YVU410
- MP_FOURCC_YV12 == V4L2_PIX_FMT_YVU420
- MP_FOURCC_NV12 == V4L2_PIX_FMT_NV12
- MP_FOURCC_422P == V4L2_PIX_FMT_YUV422P
- MP_FOURCC_411P == V4L2_PIX_FMT_YUV411P
- MP_FOURCC_UYVY == V4L2_PIX_FMT_UYVY
- MP_FOURCC_Y41P == V4L2_PIX_FMT_Y41P
-
- This may be an useful translation table for some others:
-
- MP_FOURCC_RGB8 == V4L2_PIX_FMT_RGB332
- MP_FOURCC_BGR15 == V4L2_PIX_FMT_RGB555
- MP_FOURCC_BGR16 == V4L2_PIX_FMT_RGB565
- MP_FOURCC_RGB24 == V4L2_PIX_FMT_RGB24
- MP_FOURCC_RGB32 == V4L2_PIX_FMT_RGB32
- MP_FOURCC_BGR24 == V4L2_PIX_FMT_BGR24
- MP_FOURCC_BGR32 == V4L2_PIX_FMT_BGR32
- MP_FOURCC_Y800 == V4L2_PIX_FMT_GREY
- MP_FOURCC_YUV9 == V4L2_PIX_FMT_YUV410
- MP_FOURCC_I420 == V4L2_PIX_FMT_YUV420
- MP_FOURCC_YUY2 == V4L2_PIX_FMT_YUYV
-
-\**********************************************************************/
-
-/*
-** Translate a mplayer fourcc to a video4linux2 pixel format.
-*/
-static int fcc_mp2vl(int fcc)
-{
- switch (fcc) {
- case MP_FOURCC_RGB8: return V4L2_PIX_FMT_RGB332;
- case MP_FOURCC_BGR15: return V4L2_PIX_FMT_RGB555;
- case MP_FOURCC_BGR16: return V4L2_PIX_FMT_RGB565;
- case MP_FOURCC_RGB24: return V4L2_PIX_FMT_RGB24;
- case MP_FOURCC_RGB32: return V4L2_PIX_FMT_RGB32;
- case MP_FOURCC_BGR24: return V4L2_PIX_FMT_BGR24;
- case MP_FOURCC_BGR32: return V4L2_PIX_FMT_BGR32;
- case MP_FOURCC_Y800: return V4L2_PIX_FMT_GREY;
- case MP_FOURCC_YUV9: return V4L2_PIX_FMT_YUV410;
- case MP_FOURCC_I420: return V4L2_PIX_FMT_YUV420;
- case MP_FOURCC_YUY2: return V4L2_PIX_FMT_YUYV;
- case MP_FOURCC_YV12: return V4L2_PIX_FMT_YVU420;
- case MP_FOURCC_UYVY: return V4L2_PIX_FMT_UYVY;
- case MP_FOURCC_MJPEG: return V4L2_PIX_FMT_MJPEG;
- case MP_FOURCC_JPEG: return V4L2_PIX_FMT_JPEG;
- }
- 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 MP_FOURCC_RGB8;
- case V4L2_PIX_FMT_RGB555: return MP_FOURCC_BGR15;
- case V4L2_PIX_FMT_RGB565: return MP_FOURCC_BGR16;
- case V4L2_PIX_FMT_RGB24: return MP_FOURCC_RGB24;
- case V4L2_PIX_FMT_RGB32: return MP_FOURCC_RGB32;
- case V4L2_PIX_FMT_BGR24: return MP_FOURCC_BGR24;
- case V4L2_PIX_FMT_BGR32: return MP_FOURCC_BGR32;
- case V4L2_PIX_FMT_GREY: return MP_FOURCC_Y800;
- case V4L2_PIX_FMT_YUV410: return MP_FOURCC_YUV9;
- case V4L2_PIX_FMT_YUV420: return MP_FOURCC_I420;
- case V4L2_PIX_FMT_YVU420: return MP_FOURCC_YV12;
- case V4L2_PIX_FMT_YUYV: return MP_FOURCC_YUY2;
- case V4L2_PIX_FMT_UYVY: return MP_FOURCC_UYVY;
- case V4L2_PIX_FMT_MJPEG: return MP_FOURCC_MJPEG;
- case V4L2_PIX_FMT_JPEG: return MP_FOURCC_JPEG;
- }
- return fcc;
-}
-
-/*
-** Translate a video4linux2 fourcc aka pixel format
-** to a human readable string.
-*/
-static const char *pixfmt2name(char *buf, int pixfmt)
-{
- 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";
- case V4L2_PIX_FMT_MJPEG: return "MJPEG";
- case V4L2_PIX_FMT_JPEG: return "JPEG";
- }
- sprintf(buf, "unknown (0x%x)", pixfmt);
- return buf;
-}
-
-
-/*
-** 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;
- }
-}
-
-
-/*
-** Get current FPS.
-*/
-static double getfps(priv_t *priv)
-{
- if (priv->tv_param->fps > 0)
- return priv->tv_param->fps;
- if (priv->standard.frameperiod.denominator && priv->standard.frameperiod.numerator)
- return (double)priv->standard.frameperiod.denominator / priv->standard.frameperiod.numerator;
- return 25.0;
-}
-
-// 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;
- int seconds = priv->video_buffer_size_max/getfps(priv);
-
- 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_VERBOSE(priv, "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_initialized) return;
-
- if (priv->tv_param->audio) {
-#if HAVE_ALSA
- if (priv->tv_param->alsa)
- audio_in_init(&priv->audio_in, priv->log, AUDIO_IN_ALSA);
- else
- audio_in_init(&priv->audio_in, priv->log, AUDIO_IN_OSS);
-#else
- audio_in_init(&priv->audio_in, priv->log, 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 (priv->tv_param->forcechan >= 0) {
- audio_in_set_channels(&priv->audio_in, priv->tv_param->forcechan);
- } else {
- audio_in_set_channels(&priv->audio_in, 2);
- }
- }
-
- if (audio_in_setup(&priv->audio_in) < 0) return;
-
- priv->audio_initialized = 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 = v4l2_ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) {
- MP_ERR(priv, "ioctl get format failed: %s\n",
- mp_strerror(errno));
- }
- return i;
-}
-
-
-/*
-** Get current video capture standard.
-*/
-static int getstd(priv_t *priv)
-{
- v4l2_std_id id;
- int i=0;
-
- if (v4l2_ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) {
- struct v4l2_streamparm parm;
-
- parm.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if(v4l2_ioctl(priv->video_fd, VIDIOC_G_PARM, &parm) >= 0) {
- MP_WARN(priv, "your device driver does not support VIDIOC_G_STD ioctl,"
- " VIDIOC_G_PARM was used instead.\n");
- priv->standard.index=0;
- priv->standard.id=0;
- priv->standard.frameperiod=parm.parm.capture.timeperframe;
- return 0;
- }
-
- MP_ERR(priv, "ioctl get standard failed: %s\n", mp_strerror(errno));
- return -1;
- }
- do {
- priv->standard.index = i++;
- if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) {
- return -1;
- }
- } while (priv->standard.id != id);
- return 0;
-}
-
-#if HAVE_CLOCK_GETTIME
-/*
-** Gets current timestamp, using specified clock id.
-** @return number of microseconds.
-*/
-static long long get_curr_timestamp(int clk_id)
-{
- struct timespec ts;
- clock_gettime(clk_id, &ts);
- return (long long)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
-}
-#else
-/*
-** Gets current timestamp, using system time.
-** @return number of microseconds.
-*/
-static long long get_curr_timestamp(int clk_id)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (long long)tv.tv_sec * 1000000 + tv.tv_usec;
-}
-#endif
-
-/***********************************************************************\
- * *
- * *
- * 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 (v4l2_ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) {
- MP_ERR(priv, "ioctl set mute failed: %s\n", mp_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 (v4l2_ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
- MP_ERR(priv, "ioctl query control failed: %s\n", mp_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 (v4l2_ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) {
- MP_ERR(priv, "ioctl set %s %d failed: %s\n",
- qctrl.name, control->value, mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- MP_VERBOSE(priv, "set %s: %d [%d, %d]\n",
- 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 (v4l2_ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
- MP_ERR(priv, "ioctl query control failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
-
- if (v4l2_ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) {
- MP_ERR(priv, "ioctl get %s failed: %s\n", qctrl.name, mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- MP_VERBOSE(priv, "get %s: %d [%d, %d]\n",
- 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 do_control(priv_t *priv, int cmd, void *arg)
-{
- struct v4l2_control control;
- struct v4l2_frequency frequency;
- char buf[80];
-
- 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 (priv->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 = getfps(priv);
- MP_VERBOSE(priv, "get fps: %f\n", *(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_VERBOSE(priv, "get depth: %d\n", *(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_VERBOSE(priv, "get format: %s\n",
- pixfmt2name(buf, 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_VERBOSE(priv, "set format: %s\n",
- pixfmt2name(buf, priv->format.fmt.pix.pixelformat));
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) {
- MP_ERR(priv, "ioctl set format failed: %s\n", mp_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_VERBOSE(priv, "get width: %d\n", *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_CHK_WIDTH:
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_VID_SET_WIDTH_HEIGHT:
- if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;
- priv->format.fmt.pix.width = ((int *)arg)[0];
- priv->format.fmt.pix.height = ((int *)arg)[1];
- priv->format.fmt.pix.field = V4L2_FIELD_ANY;
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0)
- return TVI_CONTROL_FALSE;
- 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_VERBOSE(priv, "set width: %d\n", *(int *)arg);
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) {
- MP_ERR(priv, "ioctl set width failed: %s\n", mp_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_VERBOSE(priv, "get height: %d\n", *(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_VERBOSE(priv, "set height: %d\n", *(int *)arg);
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) {
- MP_ERR(priv, "ioctl set height failed: %s\n", mp_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_GAIN:
- {
-
- control.id = V4L2_CID_AUTOGAIN;
- if(get_control(priv,&control,0)!=TVI_CONTROL_TRUE)
- return TVI_CONTROL_FALSE;
-
- if(control.value){ //Auto Gain control is enabled
- *(int*)arg=0;
- return TVI_CONTROL_TRUE;
- }
-
- //Manual Gain control
- control.id = V4L2_CID_GAIN;
- if(get_control(priv,&control,0)!=TVI_CONTROL_TRUE)
- return TVI_CONTROL_FALSE;
-
- *(int*)arg=control.value?control.value:1;
-
- return TVI_CONTROL_TRUE;
- }
- case TVI_CONTROL_VID_SET_GAIN:
- {
- //value==0 means automatic gain control
- int value=*(int*)arg;
-
- if (value < 0 || value>100)
- return TVI_CONTROL_FALSE;
-
- control.id=value?V4L2_CID_GAIN:V4L2_CID_AUTOGAIN;
- control.value=value?value:1;
-
- return set_control(priv,&control,0);
- }
- 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 (v4l2_ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) {
- MP_ERR(priv, "ioctl get frequency failed: %s\n", mp_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 (v4l2_ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) {
- MP_ERR(priv, "ioctl set frequency failed: %s\n", mp_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_VERBOSE(priv, "get tuner\n");
- if (v4l2_ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) {
- MP_ERR(priv, "ioctl get tuner failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_SET_TUNER:
- MP_VERBOSE(priv, "set tuner\n");
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) {
- MP_ERR(priv, "ioctl set tuner failed: %s\n", mp_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_GET_SIGNAL:
- if (v4l2_ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) {
- MP_ERR(priv, "ioctl get tuner failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- *(int*)arg=100*(priv->tuner.signal>>8)/255;
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_TUN_SET_NORM:
- priv->standard.index = *(int *)arg;
- if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) {
- MP_ERR(priv, "ioctl enum norm failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- MP_VERBOSE(priv, "set norm: %s\n", priv->standard.name);
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) {
- MP_ERR(priv, "ioctl set norm failed: %s\n", mp_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 == v4l2_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 (v4l2_ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) {
- MP_ERR(priv, "ioctl get input failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_SPC_SET_INPUT:
- MP_VERBOSE(priv, "set input: %d\n", *(int *)arg);
- priv->input.index = *(int *)arg;
- if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) {
- MP_ERR(priv, "ioctl enum input failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- if (v4l2_ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) {
- MP_ERR(priv, "ioctl set input failed: %s\n", mp_strerror(errno));
- return TVI_CONTROL_FALSE;
- }
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_FORMAT:
- init_audio(priv);
- if (!priv->audio_initialized) return TVI_CONTROL_FALSE;
- *(int *)arg = AF_FORMAT_S16;
- MP_VERBOSE(priv, "get audio format: %d\n", *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_SAMPLERATE:
- init_audio(priv);
- if (!priv->audio_initialized) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->audio_in.samplerate;
- MP_VERBOSE(priv, "get audio samplerate: %d\n", *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_GET_CHANNELS:
- init_audio(priv);
- if (!priv->audio_initialized) return TVI_CONTROL_FALSE;
- *(int *)arg = priv->audio_in.channels;
- MP_VERBOSE(priv, "get audio channels: %d\n", *(int *)arg);
- return TVI_CONTROL_TRUE;
- case TVI_CONTROL_AUD_SET_SAMPLERATE:
- init_audio(priv);
- MP_VERBOSE(priv, "set audio samplerate: %d\n", *(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_VERBOSE(priv, "unknown control: %d\n", cmd);
- return TVI_CONTROL_UNKNOWN;
-}
-
-
-#define PRIV ((priv_t *) (tvi_handle->priv))
-
-/* handler creator - entry point ! */
-static tvi_handle_t *tvi_init_v4l2(struct mp_log *log, tv_param_t* tv_param)
-{
- tvi_handle_t *tvi_handle;
-
- tvi_handle = tv_new_handle(sizeof(priv_t), log, &functions);
- if (!tvi_handle) {
- re