📄 stream_pvr.c
字号:
if (!pvr) return -1; if (pvr->dev_fd < 0) return -1; /* -tv noaudio */ if (pvr->mute) { struct v4l2_control ctrl; ctrl.id = V4L2_CID_AUDIO_MUTE; ctrl.value = 1; if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't mute (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } } /* -tv input=x */ if (pvr->input != 0) { if (ioctl (pvr->dev_fd, VIDIOC_S_INPUT, &pvr->input) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set input (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } } /* -tv normid=x */ if (pvr->normid != -1) { struct v4l2_standard std; std.index = pvr->normid; if (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &std) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } mp_msg (MSGT_OPEN, MSGL_V, "%s set norm to %s\n", LOG_LEVEL_V4L2, std.name); if (ioctl (pvr->dev_fd, VIDIOC_S_STD, &std.id) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } } /* -tv brightness=x */ if (pvr->brightness != 0) { struct v4l2_control ctrl; ctrl.id = V4L2_CID_BRIGHTNESS; ctrl.value = pvr->brightness; if (ctrl.value < 0) ctrl.value = 0; if (ctrl.value > 255) ctrl.value = 255; if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set brightness to %d (%s).\n", LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); return -1; } } /* -tv contrast=x */ if (pvr->contrast != 0) { struct v4l2_control ctrl; ctrl.id = V4L2_CID_CONTRAST; ctrl.value = pvr->contrast; if (ctrl.value < 0) ctrl.value = 0; if (ctrl.value > 127) ctrl.value = 127; if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set contrast to %d (%s).\n", LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); return -1; } } /* -tv hue=x */ if (pvr->hue != 0) { struct v4l2_control ctrl; ctrl.id = V4L2_CID_HUE; ctrl.value = pvr->hue; if (ctrl.value < -128) ctrl.value = -128; if (ctrl.value > 127) ctrl.value = 127; if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set hue to %d (%s).\n", LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); return -1; } } /* -tv saturation=x */ if (pvr->saturation != 0) { struct v4l2_control ctrl; ctrl.id = V4L2_CID_SATURATION; ctrl.value = pvr->saturation; if (ctrl.value < 0) ctrl.value = 0; if (ctrl.value > 127) ctrl.value = 127; if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set saturation to %d (%s).\n", LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); return -1; } } /* -tv width=x:height=y */ if (pvr->width && pvr->height) { struct v4l2_format vfmt; vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vfmt.fmt.pix.width = pvr->width; vfmt.fmt.pix.height = pvr->height; if (ioctl (pvr->dev_fd, VIDIOC_S_FMT, &vfmt) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set resolution to %dx%d (%s).\n", LOG_LEVEL_V4L2, pvr->width, pvr->height, strerror (errno)); return -1; } } if (pvr->freq < 0) { int freq = get_v4l2_freq (pvr); mp_msg (MSGT_OPEN, MSGL_INFO, "%s Using current set frequency %d, to set channel\n", LOG_LEVEL_V4L2, freq); if (0 < freq) return set_station_by_channelname_or_freq (pvr, NULL, freq, 1); } if (0 < pvr->freq) return set_v4l2_freq (pvr) ; return 0;}static intv4l2_list_capabilities (struct pvr_t *pvr){ struct v4l2_audio vaudio; struct v4l2_standard vs; struct v4l2_input vin; int err = 0; if (!pvr) return -1; if (pvr->dev_fd < 0) return -1; /* list available video inputs */ vin.index = 0; err = 1; mp_msg (MSGT_OPEN, MSGL_INFO, "%s Available video inputs: ", LOG_LEVEL_V4L2); while (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) >= 0) { err = 0; mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vin.index, vin.name); vin.index++; } if (err) { mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); return -1; } else mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); /* list available audio inputs */ vaudio.index = 0; err = 1; mp_msg (MSGT_OPEN, MSGL_INFO, "%s Available audio inputs: ", LOG_LEVEL_V4L2); while (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) >= 0) { err = 0; mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vaudio.index, vaudio.name); vaudio.index++; } if (err) { mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); return -1; } else mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); /* list available norms */ vs.index = 0; mp_msg (MSGT_OPEN, MSGL_INFO, "%s Available norms: ", LOG_LEVEL_V4L2); while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0) { err = 0; mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vs.index, vs.name); vs.index++; } if (err) { mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); return -1; } else mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); return 0;}static intv4l2_display_settings (struct pvr_t *pvr){ struct v4l2_audio vaudio; struct v4l2_standard vs; struct v4l2_input vin; v4l2_std_id std; int input; if (!pvr) return -1; if (pvr->dev_fd < 0) return -1; /* get current video input */ if (ioctl (pvr->dev_fd, VIDIOC_G_INPUT, &input) == 0) { vin.index = input; if (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } else mp_msg (MSGT_OPEN, MSGL_INFO, "%s Video input: %s\n", LOG_LEVEL_V4L2, vin.name); } else { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } /* get current audio input */ if (ioctl (pvr->dev_fd, VIDIOC_G_AUDIO, &vaudio) == 0) { mp_msg (MSGT_OPEN, MSGL_INFO, "%s Audio input: %s\n", LOG_LEVEL_V4L2, vaudio.name); } else { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } /* get current video format */ if (ioctl (pvr->dev_fd, VIDIOC_G_STD, &std) == 0) { vs.index = 0; while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0) { if (vs.id == std) { mp_msg (MSGT_OPEN, MSGL_INFO, "%s Norm: %s.\n", LOG_LEVEL_V4L2, vs.name); break; } vs.index++; } } else { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); return -1; } return 0;}/* stream layer */static voidpvr_stream_close (stream_t *stream){ struct pvr_t *pvr; if (!stream) return; pvr = (struct pvr_t *) stream->priv; pvr_uninit (pvr);}static intpvr_stream_read (stream_t *stream, char *buffer, int size){ struct pollfd pfds[1]; struct pvr_t *pvr; int rk, fd, pos; if (!stream || !buffer) return 0; pvr = (struct pvr_t *) stream->priv; fd = pvr->dev_fd; pos = 0; if (fd < 0) return 0; while (pos < size) { pfds[0].fd = fd; pfds[0].events = POLLIN | POLLPRI; rk = size - pos; if (poll (pfds, 1, 500) <= 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s failed with errno %d when reading %d bytes\n", LOG_LEVEL_PVR, errno, size-pos); break; } rk = read (fd, &buffer[pos], rk); if (rk > 0) { pos += rk; mp_msg (MSGT_OPEN, MSGL_DBG3, "%s read (%d) bytes\n", LOG_LEVEL_PVR, pos); } } if (!pos) mp_msg (MSGT_OPEN, MSGL_ERR, "%s read %d bytes\n", LOG_LEVEL_PVR, pos); return pos;}static intpvr_stream_open (stream_t *stream, int mode, void *opts, int *file_format){ struct v4l2_capability vcap; struct v4l2_ext_controls ctrls; struct pvr_t *pvr = NULL; if (mode != STREAM_READ) return STREAM_UNSUPPORTED; pvr = pvr_init (); /** * if the url, i.e. 'pvr://8', contains the channel, use it, * else use the tv parameter. */ if (stream->url && strlen (stream->url) > 6 && stream->url[6] != '\0') pvr->param_channel = strdup (stream->url + 6); else if (stream_tv_defaults.channel && strlen (stream_tv_defaults.channel)) pvr->param_channel = strdup (stream_tv_defaults.channel); parse_v4l2_tv_options (pvr); parse_encoder_options (pvr); /* open device */ pvr->dev_fd = open (pvr->video_dev, O_RDWR); mp_msg (MSGT_OPEN, MSGL_INFO, "%s Using device %s\n", LOG_LEVEL_PVR, pvr->video_dev); if (pvr->dev_fd == -1) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s error opening device %s\n", LOG_LEVEL_PVR, pvr->video_dev); pvr_uninit (pvr); return STREAM_ERROR; } /* query capabilities (i.e test V4L2 support) */ if (ioctl (pvr->dev_fd, VIDIOC_QUERYCAP, &vcap) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s device is not V4L2 compliant (%s).\n", LOG_LEVEL_PVR, strerror (errno)); pvr_uninit (pvr); return STREAM_ERROR; } else mp_msg (MSGT_OPEN, MSGL_INFO, "%s Detected %s\n", LOG_LEVEL_PVR, vcap.card); /* check for a valid V4L2 capture device */ if (!(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s device is not a valid V4L2 capture device.\n", LOG_LEVEL_PVR); pvr_uninit (pvr); return STREAM_ERROR; } /* check for device hardware MPEG encoding capability */ ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; ctrls.count = 0; ctrls.controls = NULL; if (ioctl (pvr->dev_fd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s device do not support MPEG input.\n", LOG_LEVEL_ENCODER); return STREAM_ERROR; } /* list V4L2 capabilities */ if (v4l2_list_capabilities (pvr) == -1) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get v4l2 capabilities\n", LOG_LEVEL_PVR); pvr_uninit (pvr); return STREAM_ERROR; } /* apply V4L2 settings */ if (set_v4l2_settings (pvr) == -1) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set v4l2 settings\n", LOG_LEVEL_PVR); pvr_uninit (pvr); return STREAM_ERROR; } /* apply encoder settings */ if (set_encoder_settings (pvr) == -1) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set encoder settings\n", LOG_LEVEL_PVR); pvr_uninit (pvr); return STREAM_ERROR; } /* display current V4L2 settings */ if (v4l2_display_settings (pvr) == -1) { mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get v4l2 settings\n", LOG_LEVEL_PVR); pvr_uninit (pvr); return STREAM_ERROR; } stream->priv = pvr; stream->type = STREAMTYPE_PVR; stream->fill_buffer = pvr_stream_read; stream->close = pvr_stream_close; return STREAM_OK;}/* PVR Public API access */const char *pvr_get_current_stationname (stream_t *stream){ struct pvr_t *pvr; if (!stream || stream->type != STREAMTYPE_PVR) return NULL; pvr = (struct pvr_t *) stream->priv; if (pvr->stationlist.list && pvr->stationlist.used > pvr->chan_idx && pvr->chan_idx >= 0) return pvr->stationlist.list[pvr->chan_idx].station; return NULL;}const char *pvr_get_current_channelname (stream_t *stream){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; if (pvr->stationlist.list && pvr->stationlist.used > pvr->chan_idx && pvr->chan_idx >= 0) return pvr->stationlist.list[pvr->chan_idx].name; return NULL;}intpvr_get_current_frequency (stream_t *stream){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; return pvr->freq;}intpvr_set_channel (stream_t *stream, const char * channel){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; return set_station_by_channelname_or_freq (pvr, channel, -1, 1);}intpvr_set_lastchannel (stream_t *stream){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; if (pvr->stationlist.list && pvr->stationlist.used > pvr->chan_idx_last && pvr->chan_idx_last >= 0) return set_station_by_channelname_or_freq (pvr, pvr->stationlist.list[pvr->chan_idx_last].name, -1, 1); return -1;}intpvr_set_freq (stream_t *stream, int freq){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; return set_station_by_channelname_or_freq (pvr, NULL, freq, 1);}intpvr_set_channel_step (stream_t *stream, int step){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; return set_station_by_step (pvr, step, 1);}intpvr_force_freq_step (stream_t *stream, int step){ struct pvr_t *pvr = (struct pvr_t *) stream->priv; return force_freq_step (pvr, step);}stream_info_t stream_info_pvr = { "V4L2 MPEG Input (a.k.a PVR)", "pvr", "Benjamin Zores", "", pvr_stream_open, { "pvr", NULL }, NULL, 1};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -