00001 /* 00002 * libzvbi WSS capture example 00003 * 00004 * Copyright (C) 2005 Michael H. Schimek 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in 00013 * the documentation and/or other materials provided with the 00014 * distribution. 00015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00016 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00017 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00018 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00019 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00020 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00021 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00022 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00023 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00025 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 /* $Id: wss.c,v 1.11 2008/02/19 00:52:04 mschimek Exp $ */ 00029 00030 /* This example shows how to extract Wide Screen Signalling data 00031 (EN 300 294) from video images. The signal is transmitted on the 00032 first half of PAL/SECAM scan line 23, which ITU-R BT.601 defines 00033 as the first line of a 576 line picture. 00034 00035 The author is not aware of any drivers which can capture a scan 00036 line as raw VBI and video data at the same time, and sliced VBI 00037 capturing is not supported yet by libzvbi. Note some drivers like 00038 the Linux saa7134 driver cannot capture line 23 at all. 00039 00040 gcc -o wss wss.c `pkg-config zvbi-0.2 --cflags --libs` */ 00041 00042 #ifdef HAVE_CONFIG_H 00043 # include "config.h" 00044 #endif 00045 00046 #include <stdio.h> 00047 #include <stdlib.h> 00048 #include <string.h> 00049 #include <assert.h> 00050 00051 #ifdef ENABLE_V4L2 00052 00053 #include <fcntl.h> /* low-level i/o */ 00054 #include <unistd.h> 00055 #include <errno.h> 00056 #include <sys/stat.h> 00057 #include <sys/types.h> 00058 #include <sys/time.h> 00059 #include <sys/mman.h> 00060 #include <sys/ioctl.h> 00061 00062 #include <libzvbi.h> 00063 00064 #include <asm/types.h> /* for videodev2.h */ 00065 #include "videodev2k.h" 00066 00067 #define CLEAR(x) memset (&(x), 0, sizeof (x)) 00068 00069 struct buffer { 00070 void * start; 00071 size_t length; 00072 }; 00073 00074 static const char * dev_name = "/dev/video"; 00075 00076 static int fd; 00077 static struct buffer * buffers; 00078 static unsigned int n_buffers; 00079 00080 static int quit; 00081 00082 static vbi_raw_decoder rd; 00083 00084 static void 00085 errno_exit (const char * s) 00086 { 00087 fprintf (stderr, "%s error %d, %s\n", 00088 s, errno, strerror (errno)); 00089 00090 exit (EXIT_FAILURE); 00091 } 00092 00093 static int 00094 xioctl (int fd, 00095 int request, 00096 void * p) 00097 { 00098 int r; 00099 00100 do r = ioctl (fd, request, p); 00101 while (-1 == r && EINTR == errno); 00102 00103 return r; 00104 } 00105 00106 static void 00107 decode_wss_625 (uint8_t * buf) 00108 { 00109 static const char *formats [] = { 00110 "Full format 4:3, 576 lines", 00111 "Letterbox 14:9 centre, 504 lines", 00112 "Letterbox 14:9 top, 504 lines", 00113 "Letterbox 16:9 centre, 430 lines", 00114 "Letterbox 16:9 top, 430 lines", 00115 "Letterbox > 16:9 centre", 00116 "Full format 14:9 centre, 576 lines", 00117 "Anamorphic 16:9, 576 lines" 00118 }; 00119 static const char *subtitles [] = { 00120 "none", 00121 "in active image area", 00122 "out of active image area", 00123 "<invalid>" 00124 }; 00125 int g1; 00126 int parity; 00127 00128 g1 = buf[0] & 15; 00129 00130 parity = g1; 00131 parity ^= parity >> 2; 00132 parity ^= parity >> 1; 00133 g1 &= 7; 00134 00135 printf ("WSS PAL: "); 00136 if (!(parity & 1)) 00137 printf ("<parity error> "); 00138 printf ("%s; %s mode; %s colour coding; %s helper; " 00139 "reserved b7=%d; %s Teletext subtitles; " 00140 "open subtitles: %s; %s surround sound; " 00141 "copyright %s; copying %s\n", 00142 formats[g1], 00143 (buf[0] & 0x10) ? "film" : "camera", 00144 (buf[0] & 0x20) ? "MA/CP" : "standard", 00145 (buf[0] & 0x40) ? "modulated" : "no", 00146 !!(buf[0] & 0x80), 00147 (buf[1] & 0x01) ? "have" : "no", 00148 subtitles[(buf[1] >> 1) & 3], 00149 (buf[1] & 0x08) ? "have" : "no", 00150 (buf[1] & 0x10) ? "asserted" : "unknown", 00151 (buf[1] & 0x20) ? "restricted" : "not restricted"); 00152 } 00153 00154 static void 00155 process_image (const void * p) 00156 { 00157 vbi_sliced sliced[1]; 00158 unsigned int n_lines; 00159 00160 n_lines = vbi_raw_decode (&rd, (uint8_t *) p, sliced); 00161 if (0 /* test */) { 00162 /* Error ignored. */ 00163 write (STDOUT_FILENO, p, rd.bytes_per_line); 00164 } else if (n_lines > 0) { 00165 assert (VBI_SLICED_WSS_625 == sliced[0].id); 00166 assert (1 == n_lines); 00167 decode_wss_625 (sliced[0].data); 00168 } else { 00169 fputc ('.', stdout); 00170 fflush (stdout); 00171 } 00172 } 00173 00174 static void 00175 init_decoder (void) 00176 { 00177 unsigned int services; 00178 00179 vbi_raw_decoder_init (&rd); 00180 00181 rd.scanning = 625; 00182 rd.sampling_format = VBI_PIXFMT_YUYV; 00183 00184 /* Should be calculated from VIDIOC_CROPCAP information. 00185 Common sampling rates are 14.75 MHz to get 768 PAL/SECAM 00186 square pixels per line, and 13.5 MHz according to ITU-R Rec. 00187 BT.601 with 720 pixels/line. Note BT.601 overscans the line: 00188 13.5e6 / 720 > 14.75e6 / 768. Don't be fooled by a driver 00189 scaling 768 square pixels to 720. */ 00190 rd.sampling_rate = 768 * 14.75e6 / 768; 00191 00192 rd.bytes_per_line = 768 * 2; 00193 00194 /* Should be calculated from VIDIOC_CROPCAP information. */ 00195 rd.offset = 0; 00196 00197 rd.start[0] = 23; 00198 rd.count[0] = 1; 00199 00200 rd.start[1] = 0; 00201 rd.count[1] = 0; 00202 00203 rd.interlaced = FALSE; /* just one line */ 00204 rd.synchronous = TRUE; 00205 00206 services = vbi_raw_decoder_add_services (&rd, 00207 VBI_SLICED_WSS_625, 00208 /* strict */ 2); 00209 if (0 == services) { 00210 fprintf (stderr, "Cannot decode WSS\n"); 00211 exit (EXIT_FAILURE); 00212 } 00213 } 00214 00215 static void 00216 mainloop (void) 00217 { 00218 quit = 0; 00219 00220 while (!quit) { 00221 struct v4l2_buffer buf; 00222 00223 for (;;) { 00224 fd_set fds; 00225 struct timeval tv; 00226 int r; 00227 00228 FD_ZERO (&fds); 00229 FD_SET (fd, &fds); 00230 00231 tv.tv_sec = 2; 00232 tv.tv_usec = 0; 00233 00234 r = select (fd + 1, &fds, NULL, NULL, &tv); 00235 00236 if (-1 == r) { 00237 if (EINTR == errno) { 00238 /* XXX should subtract the elapsed 00239 time from timeout here. */ 00240 continue; 00241 } 00242 00243 errno_exit ("select"); 00244 } 00245 00246 if (0 == r) { 00247 fprintf (stderr, "select timeout\n"); 00248 exit (EXIT_FAILURE); 00249 } 00250 00251 break; 00252 } 00253 00254 CLEAR (buf); 00255 00256 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00257 buf.memory = V4L2_MEMORY_MMAP; 00258 00259 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 00260 if (EAGAIN == errno) 00261 continue; 00262 00263 errno_exit ("VIDIOC_DQBUF"); 00264 } 00265 00266 assert (buf.index < n_buffers); 00267 00268 process_image (buffers[buf.index].start); 00269 00270 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 00271 errno_exit ("VIDIOC_QBUF"); 00272 } 00273 } 00274 00275 static void 00276 start_capturing (void) 00277 { 00278 unsigned int i; 00279 enum v4l2_buf_type type; 00280 00281 for (i = 0; i < n_buffers; ++i) { 00282 struct v4l2_buffer buf; 00283 00284 CLEAR (buf); 00285 00286 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00287 buf.memory = V4L2_MEMORY_MMAP; 00288 buf.index = i; 00289 00290 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 00291 errno_exit ("VIDIOC_QBUF"); 00292 } 00293 00294 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00295 00296 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) 00297 errno_exit ("VIDIOC_STREAMON"); 00298 } 00299 00300 static void 00301 init_device (void) 00302 { 00303 struct v4l2_capability cap; 00304 v4l2_std_id std_id; 00305 struct v4l2_format fmt; 00306 struct v4l2_requestbuffers req; 00307 00308 if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) { 00309 if (EINVAL == errno) { 00310 fprintf (stderr, "%s is no V4L2 device\n", 00311 dev_name); 00312 exit (EXIT_FAILURE); 00313 } else { 00314 errno_exit ("VIDIOC_QUERYCAP"); 00315 } 00316 } 00317 00318 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 00319 fprintf (stderr, "%s is no video capture device\n", 00320 dev_name); 00321 exit (EXIT_FAILURE); 00322 } 00323 00324 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 00325 fprintf (stderr, "%s does not support streaming I/O\n", 00326 dev_name); 00327 exit (EXIT_FAILURE); 00328 } 00329 00330 std_id = V4L2_STD_PAL; 00331 00332 if (-1 == xioctl (fd, VIDIOC_S_STD, &std_id)) 00333 errno_exit ("VIDIOC_S_STD"); 00334 00335 CLEAR (fmt); 00336 00337 /* We need the top field without vertical scaling, 00338 width must be at least 320 pixels. */ 00339 00340 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00341 fmt.fmt.pix.width = 768; 00342 fmt.fmt.pix.height = 576; 00343 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 00344 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 00345 00346 if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) 00347 errno_exit ("VIDIOC_S_FMT"); 00348 00349 /* XXX the driver may adjust width and height, some 00350 even change the pixelformat, that should be checked here. */ 00351 00352 CLEAR (req); 00353 00354 req.count = 4; 00355 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00356 req.memory = V4L2_MEMORY_MMAP; 00357 00358 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { 00359 if (EINVAL == errno) { 00360 fprintf (stderr, "%s does not support " 00361 "memory mapping\n", dev_name); 00362 exit (EXIT_FAILURE); 00363 } else { 00364 errno_exit ("VIDIOC_REQBUFS"); 00365 } 00366 } 00367 00368 if (req.count < 2) { 00369 fprintf (stderr, "Insufficient buffer memory on %s\n", 00370 dev_name); 00371 exit (EXIT_FAILURE); 00372 } 00373 00374 buffers = calloc (req.count, sizeof (*buffers)); 00375 00376 if (!buffers) { 00377 fprintf (stderr, "Out of memory\n"); 00378 exit (EXIT_FAILURE); 00379 } 00380 00381 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 00382 struct v4l2_buffer buf; 00383 00384 CLEAR (buf); 00385 00386 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00387 buf.memory = V4L2_MEMORY_MMAP; 00388 buf.index = n_buffers; 00389 00390 if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) 00391 errno_exit ("VIDIOC_QUERYBUF"); 00392 00393 buffers[n_buffers].length = buf.length; 00394 buffers[n_buffers].start = 00395 mmap (NULL /* start anywhere */, 00396 buf.length, 00397 PROT_READ | PROT_WRITE /* required */, 00398 MAP_SHARED /* recommended */, 00399 fd, buf.m.offset); 00400 00401 if (MAP_FAILED == buffers[n_buffers].start) 00402 errno_exit ("mmap"); 00403 } 00404 } 00405 00406 static void 00407 open_device (void) 00408 { 00409 struct stat st; 00410 00411 if (-1 == stat (dev_name, &st)) { 00412 fprintf (stderr, "Cannot identify '%s': %d, %s\n", 00413 dev_name, errno, strerror (errno)); 00414 exit (EXIT_FAILURE); 00415 } 00416 00417 if (!S_ISCHR (st.st_mode)) { 00418 fprintf (stderr, "%s is no device\n", dev_name); 00419 exit (EXIT_FAILURE); 00420 } 00421 00422 fd = open (dev_name, O_RDWR | O_NONBLOCK, 0); 00423 00424 if (-1 == fd) { 00425 fprintf (stderr, "Cannot open '%s': %d, %s\n", 00426 dev_name, errno, strerror (errno)); 00427 exit (EXIT_FAILURE); 00428 } 00429 } 00430 00431 int 00432 main (void) 00433 { 00434 /* Helps debugging. */ 00435 vbi_set_log_fn (/* mask: log everything */ -1, 00436 vbi_log_on_stderr, 00437 /* user_data */ NULL); 00438 00439 open_device (); 00440 00441 init_device (); 00442 00443 init_decoder (); 00444 00445 start_capturing (); 00446 00447 mainloop (); 00448 00449 exit (EXIT_SUCCESS); 00450 00451 return 0; 00452 } 00453 00454 #else /* !ENABLE_V4L2 */ 00455 00456 int 00457 main (int argc, 00458 char ** argv) 00459 { 00460 fprintf (stderr, "Sorry, V4L2 only. Patches welcome.\n"); 00461 00462 exit (EXIT_FAILURE); 00463 00464 return 0; 00465 } 00466 00467 #endif /* !ENABLE_V4L2 */