📄 tvi_v4l.c
字号:
} switch(priv->audio[i].mode) { case VIDEO_SOUND_MONO: case VIDEO_SOUND_LANG1: case VIDEO_SOUND_LANG2: priv->audio_channels[i] = 1; break; case VIDEO_SOUND_STEREO: priv->audio_channels[i] = 2; break; default: mp_msg(MSGT_TV, MSGL_ERR, "Card reports an unknown audio mode !\n"); mp_msg(MSGT_TV, MSGL_ERR, "Trying two channel audio. Use forcechan to override.\n"); priv->audio_channels[i] = 2; break; } if (reqmode >= 0 && priv->audio[i].mode != reqmode) { mp_msg(MSGT_TV, MSGL_ERR, "Audio mode setup warning!\n"); mp_msg(MSGT_TV, MSGL_ERR, "Requested mode was %s, but v4l still reports %s.\n", audio_mode2name(reqmode), audio_mode2name(priv->audio[i].mode)); mp_msg(MSGT_TV, MSGL_ERR, "You may need \"forcechan\" option to force stereo/mono audio recording.\n"); } /* display stuff */ mp_msg(MSGT_TV, MSGL_V, " %d: %s: ", priv->audio[i].audio, priv->audio[i].name); if (priv->audio[i].flags & VIDEO_AUDIO_MUTABLE) { mp_msg(MSGT_TV, MSGL_V, "muted=%s ", (priv->audio[i].flags & VIDEO_AUDIO_MUTE) ? "yes" : "no"); } mp_msg(MSGT_TV, MSGL_V, "vol=%d bass=%d treble=%d balance=%d mode=%s", priv->audio[i].volume, priv->audio[i].bass, priv->audio[i].treble, priv->audio[i].balance, audio_mode2name(priv->audio[i].mode)); mp_msg(MSGT_TV, MSGL_V, " chan=%d\n", priv->audio_channels[i]); if (priv->tv_param->forcechan >= 0) priv->audio_channels[i] = priv->tv_param->forcechan; // we'll call VIDIOCSAUDIO again when starting capture // let's set audio mode to requested mode again for the case // when VIDIOCGAUDIO just cannot report the mode correctly if (reqmode >= 0) priv->audio[i].mode = reqmode; }}#if !defined(__LINUX_VIDEODEV2_H) && !defined(VIDIOC_QUERYCAP)struct v4l2_capability{ __u8 driver[16]; /* i.e. "bttv" */ __u8 card[32]; /* i.e. "Hauppauge WinTV" */ __u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */ __u32 version; /* should use KERNEL_VERSION() */ __u32 capabilities; /* Device capabilities */ __u32 reserved[4];};#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability)#endifstatic int init(priv_t *priv){ int i; if (priv->tv_param->immediate == 1) priv->tv_param->noaudio = 1; priv->video_ringbuffer = NULL; priv->video_timebuffer = NULL; priv->video_avg_buffer = NULL; priv->audio_ringbuffer = NULL; priv->audio_skew_buffer = NULL; priv->video_fd = open(priv->video_device, O_RDWR); mp_msg(MSGT_TV, MSGL_DBG2, "Video fd: %d, %p\n", priv->video_fd, priv->video_device); if (priv->video_fd == -1) { mp_msg(MSGT_TV, MSGL_ERR, "unable to open '%s': %s\n", priv->video_device, strerror(errno)); goto err; } /* check for v4l2 */ if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) == 0) { mp_msg(MSGT_TV, MSGL_ERR, "=================================================================\n"); mp_msg(MSGT_TV, MSGL_ERR, " WARNING: YOU ARE USING V4L DEMUXER WITH V4L2 DRIVERS!!!\n"); mp_msg(MSGT_TV, MSGL_ERR, " As the V4L1 compatibility layer is broken, this may not work.\n"); mp_msg(MSGT_TV, MSGL_ERR, " If you encounter any problems, use driver=v4l2 instead.\n"); mp_msg(MSGT_TV, MSGL_ERR, " Bugreports on driver=v4l with v4l2 drivers will be ignored.\n"); mp_msg(MSGT_TV, MSGL_ERR, "=================================================================\n"); } /* get capabilities (priv->capability is needed!) */ if (ioctl(priv->video_fd, VIDIOCGCAP, &priv->capability) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "ioctl get capabilites failed: %s\n", strerror(errno)); goto err; } fcntl(priv->video_fd, F_SETFD, FD_CLOEXEC); mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.name); mp_msg(MSGT_TV, MSGL_INFO, " Capabilites: "); for (i = 0; device_cap2name[i] != NULL; i++) if (priv->capability.type & (1 << i)) mp_msg(MSGT_TV, MSGL_INFO, "%s ", device_cap2name[i]); mp_msg(MSGT_TV, MSGL_INFO, "\n"); mp_msg(MSGT_TV, MSGL_INFO, " Device type: %d\n", priv->capability.type); mp_msg(MSGT_TV, MSGL_INFO, " Supported sizes: %dx%d => %dx%d\n", priv->capability.minwidth, priv->capability.minheight, priv->capability.maxwidth, priv->capability.maxheight); priv->width = priv->capability.minwidth; priv->height = priv->capability.minheight; /* somewhere here could disable priv->tv_param->mjpeg, if it is not a capability */ /* initialize if necessary */ if ( priv->tv_param->mjpeg ) { struct mjpeg_params bparm; struct mjpeg_requestbuffers breq; /* buffer requests */ if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0) { mp_msg(MSGT_TV, MSGL_ERR, " MJP: Error getting video parameters: %s\n", strerror(errno)); goto err; } mp_msg(MSGT_TV, MSGL_INFO, " MJP: previous params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n", bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height, bparm.decimation, bparm.field_per_buff); mp_msg(MSGT_TV, MSGL_INFO, " MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n", bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm); bparm.input = priv->tv_param->input; /* tv */ if (!strcasecmp(priv->tv_param->norm, "pal")) bparm.norm = 0; /* PAL */ else if (!strcasecmp(priv->tv_param->norm, "ntsc")) bparm.norm = 1; /* NTSC */ else if (!strcasecmp(priv->tv_param->norm, "secam")) bparm.norm = 2; /* SECAM */ bparm.quality = priv->tv_param->quality; bparm.decimation = priv->tv_param->decimation; mp_msg(MSGT_TV, MSGL_INFO, " MJP: setting params to decimation: %d, quality: %d\n", bparm.decimation, bparm.quality); if (ioctl(priv->video_fd, MJPIOC_S_PARAMS, &bparm) < 0) { mp_msg(MSGT_TV, MSGL_ERR, " MJP: Error setting video parameters: %s\n", strerror(errno)); goto err; } if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0) { mp_msg(MSGT_TV, MSGL_ERR, " MJP: Error getting video parameters: %s\n", strerror(errno)); goto err; } mp_msg(MSGT_TV, MSGL_INFO, " MJP: current params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n", bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height, bparm.decimation, bparm.field_per_buff); mp_msg(MSGT_TV, MSGL_INFO, " MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n", bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm); breq.count = 64; priv -> nbuf = breq.count; priv->mbuf.frames = priv -> nbuf; priv->mjpeg_bufsize = 256*1024; if (priv->tv_param->buffer_size >= 0) priv->mjpeg_bufsize = priv->tv_param->buffer_size*1024; breq.size = priv -> mjpeg_bufsize; if (ioctl(priv->video_fd, MJPIOC_REQBUFS,&(breq)) < 0) { mp_msg (MSGT_TV, MSGL_ERR, " MJP: Error requesting video buffers: %s\n", strerror(errno)); goto err; } mp_msg(MSGT_TV, MSGL_INFO, " MJP: Got %ld buffers of size %ld KB\n", breq.count, breq.size/1024); priv -> mmap = mmap(0, breq.count * breq.size, PROT_READ|PROT_WRITE, MAP_SHARED, priv->video_fd, 0); if (priv -> mmap == MAP_FAILED) { mp_msg(MSGT_TV, MSGL_INFO, " MJP: Error mapping video buffers: %s\n", strerror(errno)); goto err; } } mp_msg(MSGT_TV, MSGL_INFO, " Inputs: %d\n", priv->capability.channels); priv->channels = calloc(priv->capability.channels, sizeof(struct video_channel)); if (!priv->channels) goto malloc_failed; memset(priv->channels, 0, sizeof(struct video_channel)*priv->capability.channels); for (i = 0; i < priv->capability.channels; i++) { priv->channels[i].channel = i; if (ioctl(priv->video_fd, VIDIOCGCHAN, &priv->channels[i]) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "ioctl get channel failed: %s\n", strerror(errno)); break; } mp_msg(MSGT_TV, MSGL_INFO, " %d: %s: %s%s%s%s (tuner:%d, norm:%s)\n", i, priv->channels[i].name, (priv->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "", (priv->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "", (priv->channels[i].flags & VIDEO_TYPE_TV) ? "tv " : "", (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "", priv->channels[i].tuners, norm2name(priv->channels[i].norm)); } priv->act_channel = 0; if (!(priv->capability.type & VID_TYPE_CAPTURE)) { mp_msg(MSGT_TV, MSGL_ERR, "Only grabbing supported (for overlay use another program)\n"); goto err; } /* init v4l audio even when we don't capture */ init_v4l_audio(priv); if (!priv->capability.audios && !priv->tv_param->force_audio) priv->tv_param->noaudio = 1; /* audio init */ if (!priv->tv_param->noaudio) {#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) if (priv->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_device) { audio_in_set_device(&priv->audio_in, priv->audio_device); } if (priv->tv_param->audio_id < priv->capability.audios) priv->audio_id = priv->tv_param->audio_id; else priv->audio_id = 0; audio_in_set_samplerate(&priv->audio_in, 44100); if (priv->capability.audios) { audio_in_set_channels(&priv->audio_in, priv->audio_channels[priv->audio_id]); } 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 0; setup_audio_buffer_sizes(priv); } return(1);malloc_failed: if (priv->channels) free(priv->channels); if (priv->buf) free(priv->buf);err: if (priv->video_fd != -1) close(priv->video_fd); return(0);}static int uninit(priv_t *priv){ unsigned long num;#ifdef HAVE_TV_TELETEXT priv->vbi_shutdown=1; if(priv->vbi_grabber_thread) pthread_join(priv->vbi_grabber_thread, NULL); teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1); priv->priv_vbi=NULL; if(priv->vbi_fd){ close(priv->vbi_fd); priv->vbi_fd=0; } if(priv->vbi_dev){ free(priv->vbi_dev); priv->vbi_dev=0; }#endif priv->shutdown = 1; mp_msg(MSGT_TV, MSGL_V, "Waiting for threads to finish... "); if (!priv->tv_param->noaudio) { pthread_join(priv->audio_grabber_thread, NULL); pthread_mutex_destroy(&priv->audio_starter); pthread_mutex_destroy(&priv->skew_mutex); } pthread_mutex_destroy(&priv->video_buffer_mutex); pthread_join(priv->video_grabber_thread, NULL); mp_msg(MSGT_TV, MSGL_V, "done\n"); if (priv->capability.audios) { priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE; ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); } if ( priv->tv_param->mjpeg ) { num = -1; if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) mp_msg(MSGT_TV, MSGL_ERR, "\n MJP: ioctl MJPIOC_QBUF_CAPT failed: %s\n", strerror(errno)); } else { // We need to munmap as close don't close mem mappings if(munmap(priv->mmap,priv->mbuf.size)) mp_msg(MSGT_TV, MSGL_ERR, "Munmap failed: %s\n",strerror(errno)); } if(close(priv->video_fd)) mp_msg(MSGT_TV, MSGL_ERR, "Close tv failed: %s\n",strerror(errno)); audio_in_uninit(&priv->audio_in); 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 (priv->video_avg_buffer) free(priv->video_avg_buffer); if (!priv->tv_param->noaudio) { if (priv->audio_ringbuffer) free(priv->audio_ringbuffer); if (priv->audio_skew_buffer) free(priv->audio_skew_buffer); } return(1);}static int get_capture_buffer_size(priv_t *priv){ int bufsize, cnt; if (priv->tv_param->buffer_size >= 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -