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