examples/wss.c

WSS capture example.

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

Generated on Sun Mar 18 18:17:47 2007 for ZVBI Library by  doxygen 1.4.7