00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
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>
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>
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 ) {
00155
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
00178
00179
00180
00181
00182
00183 rd.sampling_rate = 768 * 14750000 / 768;
00184
00185 rd.bytes_per_line = 768 * 2;
00186
00187
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;
00197 rd.synchronous = TRUE;
00198
00199 services = vbi_raw_decoder_add_services (&rd,
00200 VBI_SLICED_WSS_625,
00201 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
00232
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
00331
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
00343
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 ,
00389 buf.length,
00390 PROT_READ | PROT_WRITE ,
00391 MAP_SHARED ,
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
00428 vbi_set_log_fn ( -1,
00429 vbi_log_on_stderr,
00430 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
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