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

Generated on Mon Jul 17 12:37:21 2006 for ZVBI Library by  doxygen 1.4.7