📄 tvi_v4l2.c
字号:
/*** 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@gmail.com>** ** 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 <mplaylib.h>#include <mplaylib.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/time.h>#include <sys/types.h>#include <mplaylib.h>#ifdef HAVE_SYS_SYSINFO_H#include <sys/sysinfo.h>#endif#include <linux/types.h>#include <linux/videodev2.h>#include "mp_msg.h"#include "libmpcodecs/img_format.h"#include "libaf/af_format.h"#include "tv.h"#include "audio_in.h"#undef memcpy#define memcpy uc_memcpy#define info tvi_info_v4l2static tvi_handle_t *tvi_init_v4l2(tv_param_t* tv_param);/* information about this file */tvi_info_t tvi_info_v4l2 = { tvi_init_v4l2, "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/** 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 { /* video */ char *video_dev; int video_fd;#ifdef HAVE_TV_TELETEXT char *vbi_dev; int vbi_fd; int vbi_bufsize; int vbi_shutdown; pthread_t vbi_grabber_thread; void *priv_vbi;#endif 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; 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_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; tv_param_t *tv_param;} 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; case IMGFMT_MJPEG: return V4L2_PIX_FMT_MJPEG; } 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; case V4L2_PIX_FMT_MJPEG: return IMGFMT_MJPEG; } 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"; case V4L2_PIX_FMT_MJPEG: return "MJPEG"; } 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 sizesstatic 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -