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
00036
00037
00038
00039
00040
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>
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>
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 ) {
00162
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
00185
00186
00187
00188
00189
00190 rd.sampling_rate = 768 * 14.75e6 / 768;
00191
00192 rd.bytes_per_line = 768 * 2;
00193
00194
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;
00204 rd.synchronous = TRUE;
00205
00206 services = vbi_raw_decoder_add_services (&rd,
00207 VBI_SLICED_WSS_625,
00208 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
00239
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
00338
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
00350
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 ,
00396 buf.length,
00397 PROT_READ | PROT_WRITE ,
00398 MAP_SHARED ,
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
00435 vbi_set_log_fn ( -1,
00436 vbi_log_on_stderr,
00437 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
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