examples/wss.c

WSS capture example.

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 */

Generated on Mon Jun 9 21:39:24 2008 for ZVBI Library by  doxygen 1.4.7