summaryrefslogtreecommitdiffstats
path: root/stream/tvi_v4l2.c
diff options
context:
space:
mode:
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) {
- return NULL;
- }
- PRIV->log = log;
- PRIV->video_fd = -1;
-
- PRIV->video_dev = strdup(tv_param->device? tv_param->device: "/dev/video0");
- if (!PRIV->video_dev) {
- tv_free_handle(tvi_handle);
- return NULL;
- }
-
- if (tv_param->adevice) {
- PRIV->audio_dev = strdup(tv_param->adevice);
- if (!PRIV->audio_dev) {
- free(PRIV->video_dev);
- tv_free_handle(tvi_handle);
- return NULL;
- }
- }
-
- PRIV->tv_param=tv_param;
- 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) {
- /* get performance */
- frames = 1 + lrintf((double)(priv->curr_frame - priv->first_frame) / 1e6 * getfps(priv));
- dropped = frames - priv->frames;
-
- /* turn off streaming */
- if (v4l2_ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) {
- MP_ERR(priv, "ioctl streamoff failed: %s\n", mp_strerror(errno));
- }
- priv->streamon = 0;
-
- /* unqueue all remaining buffers (not sure if this code is correct) */
- for (i = 0; i < priv->mapcount; i++) {
- if (v4l2_ioctl(priv->