📄 tvi_v4l2.c
字号:
} priv->streamon = 0; /* unqueue all remaining buffers */ memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; while (!ioctl(priv->video_fd, VIDIOC_DQBUF, &buf)); } /* unmap all buffers */ for (i = 0; i < priv->mapcount; i++) { if (munmap(priv->map[i].addr, priv->map[i].len) < 0) { mp_msg(MSGT_TV, MSGL_ERR, "%s: munmap capture buffer failed: %s\n", info.short_name, strerror(errno)); } } /* stop audio thread */ if (!priv->tv_param->noaudio && priv->audio_grabber_thread) { pthread_join(priv->audio_grabber_thread, NULL); pthread_mutex_destroy(&priv->skew_mutex); pthread_mutex_destroy(&priv->audio_mutex); } set_mute(priv, 1); /* free memory and close device */ free(priv->map); priv->map = NULL; priv->mapcount = 0; if(priv->video_fd!=-1)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].data); } free(priv->video_ringbuffer); } if (!priv->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; priv->audio_ringbuffer = NULL; priv->audio_skew_buffer = NULL; priv->audio_skew_delta_buffer = NULL; priv->audio_inited = 0; /* 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) { uninit(priv); return 0; } getstd(priv); /* ** 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; mp_msg(MSGT_TV, MSGL_INFO, " %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) && !priv->tv_param->force_audio) priv->tv_param->noaudio = 1; if (priv->capability.capabilities & V4L2_CAP_TUNER) { struct v4l2_control control; if (priv->tv_param->amode >= 0) { mp_msg(MSGT_TV, MSGL_V, "%s: setting audio mode\n", info.short_name); priv->tuner.audmode = amode2v4l(priv->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 (priv->tv_param->volume >= 0) { control.id = V4L2_CID_AUDIO_VOLUME; control.value = priv->tv_param->volume; set_control(priv, &control, 0); } if (priv->tv_param->bass >= 0) { control.id = V4L2_CID_AUDIO_BASS; control.value = priv->tv_param->bass; set_control(priv, &control, 0); } if (priv->tv_param->treble >= 0) { control.id = V4L2_CID_AUDIO_TREBLE; control.value = priv->tv_param->treble; set_control(priv, &control, 0); } if (priv->tv_param->balance >= 0) { control.id = V4L2_CID_AUDIO_BALANCE; control.value = priv->tv_param->balance; set_control(priv, &control, 0); } } return 1;}static int get_capture_buffer_size(priv_t *priv){ int bufsize, cnt; if (priv->tv_param->buffer_size >= 0) { bufsize = priv->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/priv->format.fmt.pix.sizeimage; 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; unsigned int i; /* setup audio parameters */ init_audio(priv); if (!priv->tv_param->noaudio && !priv->audio_inited) return 0; /* 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 (!priv->tv_param->noaudio) { setup_audio_buffer_sizes(priv); priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); 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 = calloc(priv->aud_skew_cnt, sizeof(long long)); 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 = calloc(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_usecs_per_block = 1e6*priv->audio_secs_per_block; 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; priv->audio_null_blocks_inserted = 0; priv->audio_insert_null_samples = 0; priv->dropped_frames_timeshift = 0; priv->dropped_frames_compensated = 0; pthread_mutex_init(&priv->skew_mutex, NULL); pthread_mutex_init(&priv->audio_mutex, NULL); } /* setup video parameters */ if (!priv->tv_param->noaudio) { if (priv->video_buffer_size_max < (3*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 = calloc(priv->video_buffer_size_max, sizeof(video_buffer_entry)); if (!priv->video_ringbuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); return 0; } memset(priv->video_ringbuffer,0,priv->video_buffer_size_max * sizeof(video_buffer_entry)); pthread_mutex_init(&priv->video_buffer_mutex, NULL); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -