blob: dc7b4282c72e894835ab8c7670bfd03e5881b164 [file] [log] [blame]
#include <cstring>
#include "compiler.h"
#include "v4l2-ctl.h"
static struct v4l2_format sliced_fmt; /* set_format/get_format for sliced VBI */
static struct v4l2_format sliced_fmt_out; /* set_format/get_format for sliced VBI output */
static struct v4l2_format raw_fmt; /* set_format/get_format for VBI */
static struct v4l2_format raw_fmt_out; /* set_format/get_format for VBI output */
void vbi_usage()
{
printf("\nVBI Formats options:\n"
" --get-sliced-vbi-cap\n"
" query the sliced VBI capture capabilities\n"
" [VIDIOC_G_SLICED_VBI_CAP]\n"
" --get-sliced-vbi-out-cap\n"
" query the sliced VBI output capabilities\n"
" [VIDIOC_G_SLICED_VBI_CAP]\n"
" -B, --get-fmt-sliced-vbi\n"
" query the sliced VBI capture format [VIDIOC_G_FMT]\n"
" --get-fmt-sliced-vbi-out\n"
" query the sliced VBI output format [VIDIOC_G_FMT]\n"
" -b, --set-fmt-sliced-vbi\n"
" --try-fmt-sliced-vbi\n"
" --set-fmt-sliced-vbi-out\n"
" --try-fmt-sliced-vbi-out <mode>\n"
" set/try the sliced VBI capture/output format to <mode>\n"
" [VIDIOC_S/TRY_FMT], <mode> is a comma separated list of:\n"
" off: turn off sliced VBI (cannot be combined with\n"
" other modes)\n"
" teletext: teletext (PAL/SECAM)\n"
" cc: closed caption (NTSC)\n"
" wss: widescreen signal (PAL/SECAM)\n"
" vps: VPS (PAL/SECAM)\n"
" --get-fmt-vbi query the VBI capture format [VIDIOC_G_FMT]\n"
" --get-fmt-vbi-out query the VBI output format [VIDIOC_G_FMT]\n"
" --set-fmt-vbi\n"
" --try-fmt-vbi\n"
" --set-fmt-vbi-out\n"
" --try-fmt-vbi-out samplingrate=<r>,offset=<o>,samplesperline=<spl>,\n"
" start0=<s0>,count0=<c0>,start1=<s1>,count1=<c1>\n"
" set/try the raw VBI capture/output format [VIDIOC_S/TRY_FMT]\n"
" samplingrate: samples per second\n"
" offset: horizontal offset in samples\n"
" samplesperline: samples per line\n"
" start0: start line number of the first field\n"
" count0: number of lines in the first field\n"
" start1: start line number of the second field\n"
" count1: number of lines in the second field\n"
);
}
static void print_sliced_vbi_cap(struct v4l2_sliced_vbi_cap &cap)
{
printf("\tType : %s\n", buftype2s(cap.type).c_str());
printf("\tService Set : %s\n",
service2s(cap.service_set).c_str());
for (int i = 0; i < 24; i++) {
printf("\tService Line %2d: %8s / %-8s\n", i,
service2s(cap.service_lines[0][i]).c_str(),
service2s(cap.service_lines[1][i]).c_str());
}
}
void vbi_cmd(int ch, char *optarg)
{
char *value, *subs;
bool found_off = false;
v4l2_format *sliced = &sliced_fmt;
v4l2_format *raw = &raw_fmt;
switch (ch) {
case OptSetSlicedVbiOutFormat:
case OptTrySlicedVbiOutFormat:
sliced = &sliced_fmt_out;
fallthrough;
case OptSetSlicedVbiFormat:
case OptTrySlicedVbiFormat:
sliced->fmt.sliced.service_set = 0;
if (optarg[0] == 0) {
fprintf(stderr, "empty string\n");
vbi_usage();
std::exit(EXIT_FAILURE);
}
while (*optarg) {
subs = std::strchr(optarg, ',');
if (subs)
*subs = 0;
if (!strcmp(optarg, "off"))
found_off = true;
else if (!strcmp(optarg, "teletext"))
sliced->fmt.sliced.service_set |=
V4L2_SLICED_TELETEXT_B;
else if (!strcmp(optarg, "cc"))
sliced->fmt.sliced.service_set |=
V4L2_SLICED_CAPTION_525;
else if (!strcmp(optarg, "wss"))
sliced->fmt.sliced.service_set |=
V4L2_SLICED_WSS_625;
else if (!strcmp(optarg, "vps"))
sliced->fmt.sliced.service_set |=
V4L2_SLICED_VPS;
else
vbi_usage();
if (subs == nullptr)
break;
optarg = subs + 1;
}
if (found_off && sliced->fmt.sliced.service_set) {
fprintf(stderr, "Sliced VBI mode 'off' cannot be combined with other modes\n");
vbi_usage();
std::exit(EXIT_FAILURE);
}
break;
case OptSetVbiOutFormat:
case OptTryVbiOutFormat:
raw = &raw_fmt_out;
fallthrough;
case OptSetVbiFormat:
case OptTryVbiFormat:
subs = optarg;
memset(&raw->fmt.vbi, 0, sizeof(raw->fmt.vbi));
while (*subs != '\0') {
static constexpr const char *subopts[] = {
"samplingrate",
"offset",
"samplesperline",
"start0",
"start1",
"count0",
"count1",
nullptr
};
switch (parse_subopt(&subs, subopts, &value)) {
case 0:
raw->fmt.vbi.sampling_rate = strtoul(value, nullptr, 0);
break;
case 1:
raw->fmt.vbi.offset = strtoul(value, nullptr, 0);
break;
case 2:
raw->fmt.vbi.samples_per_line = strtoul(value, nullptr, 0);
break;
case 3:
raw->fmt.vbi.start[0] = strtoul(value, nullptr, 0);
break;
case 4:
raw->fmt.vbi.start[1] = strtoul(value, nullptr, 0);
break;
case 5:
raw->fmt.vbi.count[0] = strtoul(value, nullptr, 0);
break;
case 6:
raw->fmt.vbi.count[1] = strtoul(value, nullptr, 0);
break;
default:
vbi_usage();
break;
}
}
break;
}
}
static void fill_raw_vbi(v4l2_vbi_format &dst, const v4l2_vbi_format &src)
{
if (src.sampling_rate)
dst.sampling_rate = src.sampling_rate;
if (src.offset)
dst.offset = src.offset;
if (src.samples_per_line)
dst.samples_per_line = src.samples_per_line;
if (src.start[0])
dst.start[0] = src.start[0];
if (src.start[1])
dst.start[1] = src.start[1];
if (src.count[0])
dst.count[0] = src.count[0];
if (src.count[1])
dst.count[1] = src.count[1];
}
void vbi_set(cv4l_fd &_fd)
{
int fd = _fd.g_fd();
int ret;
if (options[OptSetSlicedVbiFormat] || options[OptTrySlicedVbiFormat]) {
sliced_fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
if (options[OptSetSlicedVbiFormat])
ret = doioctl(fd, VIDIOC_S_FMT, &sliced_fmt);
else
ret = doioctl(fd, VIDIOC_TRY_FMT, &sliced_fmt);
if (ret == 0 && (verbose || options[OptTrySlicedVbiFormat]))
printfmt(fd, sliced_fmt);
}
if (options[OptSetSlicedVbiOutFormat] || options[OptTrySlicedVbiOutFormat]) {
sliced_fmt_out.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
if (options[OptSetSlicedVbiOutFormat])
ret = doioctl(fd, VIDIOC_S_FMT, &sliced_fmt_out);
else
ret = doioctl(fd, VIDIOC_TRY_FMT, &sliced_fmt_out);
if (ret == 0 && (verbose || options[OptTrySlicedVbiOutFormat]))
printfmt(fd, sliced_fmt_out);
}
if (options[OptSetVbiFormat] || options[OptTryVbiFormat]) {
v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
doioctl(fd, VIDIOC_G_FMT, &fmt);
fill_raw_vbi(fmt.fmt.vbi, raw_fmt.fmt.vbi);
if (options[OptSetVbiFormat])
ret = doioctl(fd, VIDIOC_S_FMT, &fmt);
else
ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt);
if (ret == 0 && (verbose || options[OptTryVbiFormat]))
printfmt(fd, fmt);
}
if (options[OptSetVbiOutFormat] || options[OptTryVbiOutFormat]) {
v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VBI_OUTPUT;
doioctl(fd, VIDIOC_G_FMT, &fmt);
fill_raw_vbi(fmt.fmt.vbi, raw_fmt.fmt.vbi);
if (options[OptSetVbiOutFormat])
ret = doioctl(fd, VIDIOC_S_FMT, &fmt);
else
ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt);
if (ret == 0 && (verbose || options[OptTryVbiOutFormat]))
printfmt(fd, fmt);
}
}
void vbi_get(cv4l_fd &_fd)
{
int fd = _fd.g_fd();
if (options[OptGetSlicedVbiFormat]) {
sliced_fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
if (doioctl(fd, VIDIOC_G_FMT, &sliced_fmt) == 0)
printfmt(fd, sliced_fmt);
}
if (options[OptGetSlicedVbiOutFormat]) {
sliced_fmt_out.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
if (doioctl(fd, VIDIOC_G_FMT, &sliced_fmt_out) == 0)
printfmt(fd, sliced_fmt_out);
}
if (options[OptGetVbiFormat]) {
raw_fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
if (doioctl(fd, VIDIOC_G_FMT, &raw_fmt) == 0)
printfmt(fd, raw_fmt);
}
if (options[OptGetVbiOutFormat]) {
raw_fmt_out.type = V4L2_BUF_TYPE_VBI_OUTPUT;
if (doioctl(fd, VIDIOC_G_FMT, &raw_fmt_out) == 0)
printfmt(fd, raw_fmt_out);
}
}
void vbi_list(cv4l_fd &fd)
{
if (options[OptGetSlicedVbiCap]) {
struct v4l2_sliced_vbi_cap cap;
cap.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
if (doioctl(fd.g_fd(), VIDIOC_G_SLICED_VBI_CAP, &cap) == 0) {
print_sliced_vbi_cap(cap);
}
}
if (options[OptGetSlicedVbiOutCap]) {
struct v4l2_sliced_vbi_cap cap;
cap.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
if (doioctl(fd.g_fd(), VIDIOC_G_SLICED_VBI_CAP, &cap) == 0) {
print_sliced_vbi_cap(cap);
}
}
}