📄 tvi_v4l2.c
字号:
set_mute(priv, 1); } /* free memory and close device */ free(priv->map); priv->map = NULL; priv->mapcount = 0; 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; if (tv_param_immediate == 1) tv_param_noaudio = 1; priv->audio_ringbuffer = NULL; priv->audio_skew_buffer = NULL; priv->audio_skew_delta_buffer = NULL; /* 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 || getstd(priv) < 0) { uninit(priv); return 0; } /* ** 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; printf(" %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) { break; } mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, input.name); } if (ioctl(priv->video_fd, VIDIOC_G_INPUT, &i) < 0) { mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", info.short_name, strerror(errno)); } mp_msg(MSGT_TV, MSGL_INFO, "\n Current input: %d\n", i); for (i = 0; ; i++) { struct v4l2_fmtdesc fmtdesc; fmtdesc.index = i; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(priv->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) { break; } mp_msg(MSGT_TV, MSGL_V, " Format %-6s (%2d bits, %s): %s\n", pixfmt2name(fmtdesc.pixelformat), pixfmt2depth(fmtdesc.pixelformat), fmtdesc.description, vo_format_name(fcc_vl2mp(fmtdesc.pixelformat))); } mp_msg(MSGT_TV, MSGL_INFO, " Current format: %s\n", pixfmt2name(priv->format.fmt.pix.pixelformat)); /* set some nice defaults */ if (getfmt(priv) < 0) return 0; priv->format.fmt.pix.width = 640; priv->format.fmt.pix.height = 480; 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)); uninit(priv); return 0; }// if (!(priv->capability.capabilities & V4L2_CAP_AUDIO) && !tv_param_force_audio) tv_param_noaudio = 1; if (priv->capability.capabilities & V4L2_CAP_TUNER) { struct v4l2_control control; if (tv_param_amode >= 0) { mp_msg(MSGT_TV, MSGL_V, "%s: setting audio mode\n", info.short_name); priv->tuner.audmode = amode2v4l(tv_param_amode); 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; } } mp_msg(MSGT_TV, MSGL_INFO, "%s: current audio mode is :%s%s%s%s\n", info.short_name, (priv->tuner.audmode == V4L2_TUNER_MODE_MONO) ? " MONO" : "", (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", (priv->tuner.audmode == V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", (priv->tuner.audmode == V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); if (tv_param_volume >= 0) { control.id = V4L2_CID_AUDIO_VOLUME; control.value = tv_param_volume; set_control(priv, &control, 0); } if (tv_param_bass >= 0) { control.id = V4L2_CID_AUDIO_BASS; control.value = tv_param_bass; set_control(priv, &control, 0); } if (tv_param_treble >= 0) { control.id = V4L2_CID_AUDIO_TREBLE; control.value = tv_param_treble; set_control(priv, &control, 0); } if (tv_param_balance >= 0) { control.id = V4L2_CID_AUDIO_BALANCE; control.value = tv_param_balance; set_control(priv, &control, 0); } } /* audio init */ 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 0;// setup_audio_buffer_sizes(priv); } return 1;}static int get_capture_buffer_size(priv_t *priv){ int bufsize, cnt; int w = priv->format.fmt.pix.width; int h = priv->format.fmt.pix.height; int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); int bytesperline = w*d/8; if (tv_param_buffer_size >= 0) { bufsize = tv_param_buffer_size*1024*1024; } else {#ifdef HAVE_SYS_SYSINFO_H struct sysinfo si; sysinfo(&si); if (si.totalram<2*1024*1024) { bufsize = 1024*1024; } else { bufsize = si.totalram/2; }#else bufsize = 16*1024*1024;#endif } cnt = bufsize/(h*bytesperline); if (cnt < 2) cnt = 2; return cnt;}/* that's the real start, we'got the format parameters (checked with control) */static int start(priv_t *priv){ struct v4l2_requestbuffers request; int i; /* setup audio parameters */ /* we need this to size the audio buffer properly */ if (priv->immediate_mode) { priv->video_buffer_size_max = 2; } else { priv->video_buffer_size_max = get_capture_buffer_size(priv); } if (!tv_param_noaudio) { setup_audio_buffer_sizes(priv); priv->audio_skew_buffer = (long long*)malloc(sizeof(long long)*priv->aud_skew_cnt); if (!priv->audio_skew_buffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); return 0; } priv->audio_skew_delta_buffer = (long long*)malloc(sizeof(long long)*priv->aud_skew_cnt); if (!priv->audio_skew_delta_buffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); return 0; } priv->audio_ringbuffer = (unsigned char*)malloc(priv->audio_in.blocksize*priv->audio_buffer_size); if (!priv->audio_ringbuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); return 0; } priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate *priv->audio_in.channels *priv->audio_in.bytes_per_sample); priv->audio_head = 0; priv->audio_tail = 0; priv->audio_cnt = 0; priv->audio_drop = 0; priv->audio_skew = 0; priv->audio_skew_total = 0; priv->audio_skew_delta_total = 0; priv->audio_recv_blocks_total = 0; priv->audio_sent_blocks_total = 0; } /* setup video parameters */ if (!tv_param_noaudio) { if (priv->video_buffer_size_max < 3.0*(priv->standard.frameperiod.denominator / priv->standard.frameperiod.numerator) *priv->audio_secs_per_block) { mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" "You will probably experience heavy framedrops.\n"); } } { int bytesperline = priv->format.fmt.pix.width*pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", priv->video_buffer_size_max, priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); } priv->video_ringbuffer = (unsigned char**)malloc(priv->video_buffer_size_max*sizeof(unsigned char*)); if (!priv->video_ringbuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); return 0; } for (i = 0; i < priv->video_buffer_size_max; i++) priv->video_ringbuffer[i] = NULL; priv->video_timebuffer = (long long*)malloc(sizeof(long long) * priv->video_buffer_size_max); if (!priv->video_timebuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); return 0; } priv->video_head = 0; priv->video_tail = 0; priv->video_cnt = 0; /* request buffers */ if (priv->immediate_mode) { request.count = 2; } else { request.count = BUFFER_COUNT; } request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; request.memory = V4L2_MEMORY_MMAP; if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n", info.short_name, strerror(errno)); return 0; } /* query buffers */ if (!(priv->map = malloc(sizeof(struct map) * request.count))) { mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n", info.short_name, strerror(errno)); return 0; } /* map and queue buffers */ for (i = 0; i < request.count; i++) { memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf)); priv->map[i].buf.index = i; priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; priv->map[i].buf.memory = V4L2_MEMORY_MMAP; if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n", info.short_name, strerror(errno)); free(priv->map); priv->map = NULL; return 0; } priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); if (priv->map[i].addr == MAP_FAILED) { mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n", info.short_name, strerror(errno)); priv->map[i].len = 0; return 0; } priv->map[i].len = priv->map[i].buf.length; /* count up to make sure this is correct everytime */ priv->mapcount++; if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", info.short_name, strerror(errno)); return 0; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -