1 #include <cstring>
2
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <inttypes.h>
7 #include <getopt.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <sys/ioctl.h>
14 #include <sys/time.h>
15 #include <dirent.h>
16 #include <math.h>
17 #include <cstdlib>
18
19 #include <sys/cdefs.h>
20 #include "v4l2-ctl.h"
21
22 static struct v4l2_format sliced_fmt; /* set_format/get_format for sliced VBI */
23 static struct v4l2_format sliced_fmt_out; /* set_format/get_format for sliced VBI output */
24 static struct v4l2_format raw_fmt; /* set_format/get_format for VBI */
25 static struct v4l2_format raw_fmt_out; /* set_format/get_format for VBI output */
26
vbi_usage()27 void vbi_usage()
28 {
29 printf("\nVBI Formats options:\n"
30 " --get-sliced-vbi-cap\n"
31 " query the sliced VBI capture capabilities\n"
32 " [VIDIOC_G_SLICED_VBI_CAP]\n"
33 " --get-sliced-vbi-out-cap\n"
34 " query the sliced VBI output capabilities\n"
35 " [VIDIOC_G_SLICED_VBI_CAP]\n"
36 " -B, --get-fmt-sliced-vbi\n"
37 " query the sliced VBI capture format [VIDIOC_G_FMT]\n"
38 " --get-fmt-sliced-vbi-out\n"
39 " query the sliced VBI output format [VIDIOC_G_FMT]\n"
40 " -b, --set-fmt-sliced-vbi\n"
41 " --try-fmt-sliced-vbi\n"
42 " --set-fmt-sliced-vbi-out\n"
43 " --try-fmt-sliced-vbi-out <mode>\n"
44 " set/try the sliced VBI capture/output format to <mode>\n"
45 " [VIDIOC_S/TRY_FMT], <mode> is a comma separated list of:\n"
46 " off: turn off sliced VBI (cannot be combined with\n"
47 " other modes)\n"
48 " teletext: teletext (PAL/SECAM)\n"
49 " cc: closed caption (NTSC)\n"
50 " wss: widescreen signal (PAL/SECAM)\n"
51 " vps: VPS (PAL/SECAM)\n"
52 " --get-fmt-vbi query the VBI capture format [VIDIOC_G_FMT]\n"
53 " --get-fmt-vbi-out query the VBI output format [VIDIOC_G_FMT]\n"
54 " --set-fmt-vbi\n"
55 " --try-fmt-vbi\n"
56 " --set-fmt-vbi-out\n"
57 " --try-fmt-vbi-out samplingrate=<r>,offset=<o>,samplesperline=<spl>,\n"
58 " start0=<s0>,count0=<c0>,start1=<s1>,count1=<c1>\n"
59 " set/try the raw VBI capture/output format [VIDIOC_S/TRY_FMT]\n"
60 " samplingrate: samples per second\n"
61 " offset: horizontal offset in samples\n"
62 " samplesperline: samples per line\n"
63 " start0: start line number of the first field\n"
64 " count0: number of lines in the first field\n"
65 " start1: start line number of the second field\n"
66 " count1: number of lines in the second field\n"
67 );
68 }
69
print_sliced_vbi_cap(struct v4l2_sliced_vbi_cap & cap)70 static void print_sliced_vbi_cap(struct v4l2_sliced_vbi_cap &cap)
71 {
72 printf("\tType : %s\n", buftype2s(cap.type).c_str());
73 printf("\tService Set : %s\n",
74 service2s(cap.service_set).c_str());
75 for (int i = 0; i < 24; i++) {
76 printf("\tService Line %2d: %8s / %-8s\n", i,
77 service2s(cap.service_lines[0][i]).c_str(),
78 service2s(cap.service_lines[1][i]).c_str());
79 }
80 }
81
vbi_cmd(int ch,char * optarg)82 void vbi_cmd(int ch, char *optarg)
83 {
84 char *value, *subs;
85 bool found_off = false;
86 v4l2_format *sliced = &sliced_fmt;
87 v4l2_format *raw = &raw_fmt;
88
89 switch (ch) {
90 case OptSetSlicedVbiOutFormat:
91 case OptTrySlicedVbiOutFormat:
92 sliced = &sliced_fmt_out;
93 ;
94 case OptSetSlicedVbiFormat:
95 case OptTrySlicedVbiFormat:
96 sliced->fmt.sliced.service_set = 0;
97 if (optarg[0] == 0) {
98 fprintf(stderr, "empty string\n");
99 vbi_usage();
100 std::exit(EXIT_FAILURE);
101 }
102 while (*optarg) {
103 subs = std::strchr(optarg, ',');
104 if (subs)
105 *subs = 0;
106
107 if (!strcmp(optarg, "off"))
108 found_off = true;
109 else if (!strcmp(optarg, "teletext"))
110 sliced->fmt.sliced.service_set |=
111 V4L2_SLICED_TELETEXT_B;
112 else if (!strcmp(optarg, "cc"))
113 sliced->fmt.sliced.service_set |=
114 V4L2_SLICED_CAPTION_525;
115 else if (!strcmp(optarg, "wss"))
116 sliced->fmt.sliced.service_set |=
117 V4L2_SLICED_WSS_625;
118 else if (!strcmp(optarg, "vps"))
119 sliced->fmt.sliced.service_set |=
120 V4L2_SLICED_VPS;
121 else
122 vbi_usage();
123 if (subs == NULL)
124 break;
125 optarg = subs + 1;
126 }
127 if (found_off && sliced->fmt.sliced.service_set) {
128 fprintf(stderr, "Sliced VBI mode 'off' cannot be combined with other modes\n");
129 vbi_usage();
130 std::exit(EXIT_FAILURE);
131 }
132 break;
133 case OptSetVbiOutFormat:
134 case OptTryVbiOutFormat:
135 raw = &raw_fmt_out;
136 ;
137 case OptSetVbiFormat:
138 case OptTryVbiFormat:
139 subs = optarg;
140 memset(&raw->fmt.vbi, 0, sizeof(raw->fmt.vbi));
141 while (*subs != '\0') {
142 static const char *const subopts[] = {
143 "samplingrate",
144 "offset",
145 "samplesperline",
146 "start0",
147 "start1",
148 "count0",
149 "count1",
150 NULL
151 };
152
153 switch (parse_subopt(&subs, subopts, &value)) {
154 case 0:
155 raw->fmt.vbi.sampling_rate = strtoul(value, NULL, 0);
156 break;
157 case 1:
158 raw->fmt.vbi.offset = strtoul(value, NULL, 0);
159 break;
160 case 2:
161 raw->fmt.vbi.samples_per_line = strtoul(value, NULL, 0);
162 break;
163 case 3:
164 raw->fmt.vbi.start[0] = strtoul(value, NULL, 0);
165 break;
166 case 4:
167 raw->fmt.vbi.start[1] = strtoul(value, NULL, 0);
168 break;
169 case 5:
170 raw->fmt.vbi.count[0] = strtoul(value, NULL, 0);
171 break;
172 case 6:
173 raw->fmt.vbi.count[1] = strtoul(value, NULL, 0);
174 break;
175 default:
176 vbi_usage();
177 break;
178 }
179 }
180 break;
181 }
182 }
183
fill_raw_vbi(v4l2_vbi_format & dst,const v4l2_vbi_format & src)184 static void fill_raw_vbi(v4l2_vbi_format &dst, const v4l2_vbi_format &src)
185 {
186 if (src.sampling_rate)
187 dst.sampling_rate = src.sampling_rate;
188 if (src.offset)
189 dst.offset = src.offset;
190 if (src.samples_per_line)
191 dst.samples_per_line = src.samples_per_line;
192 if (src.start[0])
193 dst.start[0] = src.start[0];
194 if (src.start[1])
195 dst.start[1] = src.start[1];
196 if (src.count[0])
197 dst.count[0] = src.count[0];
198 if (src.count[1])
199 dst.count[1] = src.count[1];
200 }
201
vbi_set(cv4l_fd & _fd)202 void vbi_set(cv4l_fd &_fd)
203 {
204 int fd = _fd.g_fd();
205 int ret;
206
207 if (options[OptSetSlicedVbiFormat] || options[OptTrySlicedVbiFormat]) {
208 sliced_fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
209 if (options[OptSetSlicedVbiFormat])
210 ret = doioctl(fd, VIDIOC_S_FMT, &sliced_fmt);
211 else
212 ret = doioctl(fd, VIDIOC_TRY_FMT, &sliced_fmt);
213 if (ret == 0 && (verbose || options[OptTrySlicedVbiFormat]))
214 printfmt(fd, sliced_fmt);
215 }
216
217 if (options[OptSetSlicedVbiOutFormat] || options[OptTrySlicedVbiOutFormat]) {
218 sliced_fmt_out.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
219 if (options[OptSetSlicedVbiOutFormat])
220 ret = doioctl(fd, VIDIOC_S_FMT, &sliced_fmt_out);
221 else
222 ret = doioctl(fd, VIDIOC_TRY_FMT, &sliced_fmt_out);
223 if (ret == 0 && (verbose || options[OptTrySlicedVbiOutFormat]))
224 printfmt(fd, sliced_fmt_out);
225 }
226
227 if (options[OptSetVbiFormat] || options[OptTryVbiFormat]) {
228 v4l2_format fmt;
229
230 fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
231 doioctl(fd, VIDIOC_G_FMT, &fmt);
232 fill_raw_vbi(fmt.fmt.vbi, raw_fmt.fmt.vbi);
233 if (options[OptSetVbiFormat])
234 ret = doioctl(fd, VIDIOC_S_FMT, &fmt);
235 else
236 ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt);
237 if (ret == 0 && (verbose || options[OptTryVbiFormat]))
238 printfmt(fd, fmt);
239 }
240
241 if (options[OptSetVbiOutFormat] || options[OptTryVbiOutFormat]) {
242 v4l2_format fmt;
243
244 fmt.type = V4L2_BUF_TYPE_VBI_OUTPUT;
245 doioctl(fd, VIDIOC_G_FMT, &fmt);
246 fill_raw_vbi(fmt.fmt.vbi, raw_fmt.fmt.vbi);
247 if (options[OptSetVbiOutFormat])
248 ret = doioctl(fd, VIDIOC_S_FMT, &fmt);
249 else
250 ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt);
251 if (ret == 0 && (verbose || options[OptTryVbiOutFormat]))
252 printfmt(fd, fmt);
253 }
254 }
255
vbi_get(cv4l_fd & _fd)256 void vbi_get(cv4l_fd &_fd)
257 {
258 int fd = _fd.g_fd();
259
260 if (options[OptGetSlicedVbiFormat]) {
261 sliced_fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
262 if (doioctl(fd, VIDIOC_G_FMT, &sliced_fmt) == 0)
263 printfmt(fd, sliced_fmt);
264 }
265
266 if (options[OptGetSlicedVbiOutFormat]) {
267 sliced_fmt_out.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
268 if (doioctl(fd, VIDIOC_G_FMT, &sliced_fmt_out) == 0)
269 printfmt(fd, sliced_fmt_out);
270 }
271
272 if (options[OptGetVbiFormat]) {
273 raw_fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
274 if (doioctl(fd, VIDIOC_G_FMT, &raw_fmt) == 0)
275 printfmt(fd, raw_fmt);
276 }
277
278 if (options[OptGetVbiOutFormat]) {
279 raw_fmt_out.type = V4L2_BUF_TYPE_VBI_OUTPUT;
280 if (doioctl(fd, VIDIOC_G_FMT, &raw_fmt_out) == 0)
281 printfmt(fd, raw_fmt_out);
282 }
283 }
284
vbi_list(cv4l_fd & fd)285 void vbi_list(cv4l_fd &fd)
286 {
287 if (options[OptGetSlicedVbiCap]) {
288 struct v4l2_sliced_vbi_cap cap;
289
290 cap.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
291 if (doioctl(fd.g_fd(), VIDIOC_G_SLICED_VBI_CAP, &cap) == 0) {
292 print_sliced_vbi_cap(cap);
293 }
294 }
295
296 if (options[OptGetSlicedVbiOutCap]) {
297 struct v4l2_sliced_vbi_cap cap;
298
299 cap.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
300 if (doioctl(fd.g_fd(), VIDIOC_G_SLICED_VBI_CAP, &cap) == 0) {
301 print_sliced_vbi_cap(cap);
302 }
303 }
304 }
305