00001
00002 #include <unistd.h>
00003 #include <fcntl.h>
00004
00005 #ifndef _WIN32
00006 #include <sys/ioctl.h>
00007 #endif
00008
00009
00010 #include <stdlib.h>
00011 #include <string.h>
00012 #include <stdio.h>
00013 #include <stdarg.h>
00014
00015
00016 #include "vt.h"
00017 #include "vbi.h"
00018 #include "hamm.h"
00019
00020 #define FAC (1<<16) // factor for fix-point arithmetic
00021
00022 static unsigned char *rawbuf;
00023 static int rawbuf_size;
00024
00025
00026
00027
00028 #define BASE_VIDIOCPRIVATE 192
00029 #define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
00030 #define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
00031
00032
00033
00034
00035
00036 enum v4l2_buf_type {
00037 V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
00038 V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
00039 V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
00040 V4L2_BUF_TYPE_VBI_CAPTURE = 4,
00041 V4L2_BUF_TYPE_VBI_OUTPUT = 5,
00042 V4L2_BUF_TYPE_PRIVATE = 0x80,
00043 };
00044
00045 struct v4l2_vbi_format
00046 {
00047 unsigned int sampling_rate;
00048 unsigned int offset;
00049 unsigned int samples_per_line;
00050 unsigned int sample_format;
00051 signed int start[2];
00052 unsigned int count[2];
00053 unsigned int flags;
00054 unsigned int reserved2;
00055 };
00056
00057 struct v4l2_format
00058 {
00059 enum v4l2_buf_type type;
00060 union
00061 {
00062 struct v4l2_vbi_format vbi;
00063 unsigned char raw_data[200];
00064 } fmt;
00065 };
00066
00067 #define V4L2_PIX_FMT_GREY 0x59455247
00068 #define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format)
00069
00070
00071
00072 static void
00073 error(char *str, ...)
00074 {
00075 va_list ap;
00076
00077 va_start(ap, str);
00078 vfprintf(stderr, str, ap);
00079 fprintf(stderr, "\n");
00080 va_end(ap);
00081 }
00082
00083 static void
00084 out_of_sync(struct vbi *vbi)
00085 {
00086 int i;
00087
00088
00089 for (i = 0; i < 8; ++i)
00090 vbi->rpage[i].page->flags &= ~PG_ACTIVE;
00091 }
00092
00093
00094
00095
00096 static void
00097 vbi_send(struct vbi *vbi, int type, int i1, int i2, int i3, void *p1)
00098 {
00099 struct vt_event ev[1];
00100 struct vbi_client *cl, *cln;
00101
00102 ev->resource = vbi;
00103 ev->type = type;
00104 ev->i1 = i1;
00105 ev->i2 = i2;
00106 ev->i3 = i3;
00107 ev->p1 = p1;
00108
00109 for (cl = (void*)vbi->clients->first; (cln = (void*)cl->node->next);
00110 (cl = cln))
00111 cl->handler(cl->data, ev);
00112 }
00113
00114 static void
00115 vbi_send_page(struct vbi *vbi, struct raw_page *rvtp, int page)
00116 {
00117 struct vt_page *cvtp = 0;
00118
00119 if (rvtp->page->flags & PG_ACTIVE)
00120 {
00121 if (rvtp->page->pgno % 256 != page)
00122 {
00123 rvtp->page->flags &= ~PG_ACTIVE;
00124 enhance(rvtp->enh, rvtp->page);
00125
00126
00127 vbi_send(vbi, EV_PAGE, 0, 0, 0, cvtp ?: rvtp->page);
00128 }
00129 }
00130 }
00131
00132
00133
00134
00135
00136
00137 #define PLL_SAMPLES 4 // number of err vals to collect
00138 #define PLL_ERROR 4 // if this err val is crossed, readjust
00139
00140
00141 static void
00142 pll_add(struct vbi *vbi, int n, int err)
00143 {
00144 if (vbi->pll_fixed)
00145 return;
00146
00147 if (err > PLL_ERROR*2/3)
00148 err = PLL_ERROR*2/3;
00149
00150 vbi->pll_err += err;
00151 vbi->pll_cnt += n;
00152 if (vbi->pll_cnt < PLL_SAMPLES)
00153 return;
00154
00155 if (vbi->pll_err > PLL_ERROR)
00156 {
00157 if (vbi->pll_err > vbi->pll_lerr)
00158 vbi->pll_dir = -vbi->pll_dir;
00159 vbi->pll_lerr = vbi->pll_err;
00160
00161 vbi->pll_adj += vbi->pll_dir;
00162 if (vbi->pll_adj < -PLL_ADJUST || vbi->pll_adj > PLL_ADJUST)
00163 {
00164 vbi->pll_adj = 0;
00165 vbi->pll_dir = -1;
00166 vbi->pll_lerr = 0;
00167 }
00168
00169 #ifdef DEBUG
00170 printf("pll_adj = %2d\n", vbi->pll_adj);
00171 #endif
00172 }
00173 vbi->pll_cnt = 0;
00174 vbi->pll_err = 0;
00175 }
00176
00177 void
00178 vbi_pll_reset(struct vbi *vbi, int fine_tune)
00179 {
00180 vbi->pll_fixed = fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST;
00181
00182 vbi->pll_err = 0;
00183 vbi->pll_lerr = 0;
00184 vbi->pll_cnt = 0;
00185 vbi->pll_dir = -1;
00186 vbi->pll_adj = 0;
00187 if (vbi->pll_fixed)
00188 vbi->pll_adj = fine_tune;
00189 #ifdef DEBUG
00190 if (vbi->pll_fixed)
00191 printf("pll_reset (fixed@%d)\n", vbi->pll_adj);
00192 else
00193 printf("pll_reset (auto)\n");
00194 #endif
00195 }
00196
00197
00198
00199 static int
00200 vt_line(struct vbi *vbi, unsigned char *p)
00201 {
00202 struct vt_page *cvtp;
00203 struct raw_page *rvtp;
00204 int hdr, mag, mag8, pkt, i;
00205 int err = 0;
00206
00207 hdr = hamm16(p, &err);
00208 if (err & 0xf000)
00209 return -4;
00210
00211 mag = hdr & 7;
00212 mag8 = mag?: 8;
00213 pkt = (hdr >> 3) & 0x1f;
00214 p += 2;
00215
00216 rvtp = vbi->rpage + mag;
00217 cvtp = rvtp->page;
00218
00219 switch (pkt)
00220 {
00221 case 0:
00222 {
00223 int b1, b2, b3, b4;
00224
00225 b1 = hamm16(p, &err);
00226 b2 = hamm16(p+2, &err);
00227 b3 = hamm16(p+4, &err);
00228 b4 = hamm16(p+6, &err);
00229
00230 if (vbi->ppage->page->flags & PG_MAGSERIAL)
00231 vbi_send_page(vbi, vbi->ppage, b1);
00232 vbi_send_page(vbi, rvtp, b1);
00233
00234 if (err & 0xf000)
00235 return 4;
00236
00237 cvtp->errors = (err >> 8) + chk_parity(p + 8, 32);;
00238 cvtp->pgno = mag8 * 256 + b1;
00239 cvtp->subno = (b2 + b3 * 256) & 0x3f7f;
00240 cvtp->lang = "\0\4\2\6\1\5\3\7"[b4 >> 5] + (latin1 ? 0 : 8);
00241 cvtp->flags = b4 & 0x1f;
00242 cvtp->flags |= b3 & 0xc0;
00243 cvtp->flags |= (b2 & 0x80) >> 2;
00244 cvtp->lines = 1;
00245 cvtp->flof = 0;
00246 vbi->ppage = rvtp;
00247
00248 pll_add(vbi, 1, cvtp->errors);
00249
00250 conv2latin(p + 8, 32, cvtp->lang);
00251 vbi_send(vbi, EV_HEADER, cvtp->pgno, cvtp->subno, cvtp->flags, p);
00252
00253 if (b1 == 0xff)
00254 return 0;
00255
00256 cvtp->flags |= PG_ACTIVE;
00257 init_enhance(rvtp->enh);
00258 memcpy(cvtp->data[0]+0, p, 40);
00259 memset(cvtp->data[0]+40, ' ', sizeof(cvtp->data)-40);
00260 return 0;
00261 }
00262
00263 case 1 ... 24:
00264 {
00265 pll_add(vbi, 1, err = chk_parity(p, 40));
00266
00267 if (~cvtp->flags & PG_ACTIVE)
00268 return 0;
00269
00270 cvtp->errors += err;
00271 cvtp->lines |= 1 << pkt;
00272 conv2latin(p, 40, cvtp->lang);
00273 memcpy(cvtp->data[pkt], p, 40);
00274 return 0;
00275 }
00276 case 26:
00277 {
00278 int d, t[13];
00279
00280 if (~cvtp->flags & PG_ACTIVE)
00281 return 0;
00282
00283
00284 d = hamm8(p, &err);
00285 if (err & 0xf000)
00286 return 4;
00287
00288 for (i = 0; i < 13; ++i)
00289 t[i] = hamm24(p + 1 + 3*i, &err);
00290 if (err & 0xf000)
00291 return 4;
00292
00293
00294 add_enhance(rvtp->enh, d, (unsigned int *)t);
00295 return 0;
00296 }
00297 case 27:
00298 {
00299
00300 int b1,b2,b3,x;
00301
00302 if (~cvtp->flags & PG_ACTIVE)
00303 return 0;
00304
00305 b1 = hamm8(p, &err);
00306 b2 = hamm8(p + 37, &err);
00307 if (err & 0xf000)
00308 return 4;
00309 if (b1 != 0 || !(b2 & 8))
00310 return 0;
00311
00312 for (i = 0; i < 6; ++i)
00313 {
00314 err = 0;
00315 b1 = hamm16(p+1+6*i, &err);
00316 b2 = hamm16(p+3+6*i, &err);
00317 b3 = hamm16(p+5+6*i, &err);
00318 if (err & 0xf000)
00319 return 1;
00320 x = (b2 >> 7) | ((b3 >> 5) & 0x06);
00321 cvtp->link[i].pgno = ((mag ^ x) ?: 8) * 256 + b1;
00322 cvtp->link[i].subno = (b2 + b3 * 256) & 0x3f7f;
00323 }
00324 cvtp->flof = 1;
00325 return 0;
00326 }
00327 case 30:
00328 {
00329 if (mag8 != 8)
00330 return 0;
00331
00332 p[0] = hamm8(p, &err);
00333 p[1] = hamm16(p+1, &err);
00334 p[3] = hamm16(p+3, &err);
00335 p[5] = hamm16(p+5, &err);
00336 if (err & 0xf000)
00337 return 4;
00338
00339 err += chk_parity(p+20, 20);
00340 conv2latin(p+20, 20, 0);
00341
00342 vbi_send(vbi, EV_XPACKET, mag8, pkt, err, p);
00343 return 0;
00344 }
00345 default:
00346
00347
00348 return 0;
00349 }
00350 return 0;
00351 }
00352
00353
00354
00355
00356
00357 static int
00358 vbi_line(struct vbi *vbi, unsigned char *p)
00359 {
00360 unsigned char data[43], min, max;
00361 int dt[256], hi[6], lo[6];
00362 int i, n, sync, thr;
00363 int bpb = vbi->bpb;
00364
00365
00366 for (i = vbi->soc; i < vbi->eoc; ++i)
00367 dt[i] = p[i+bpb/FAC] - p[i];
00368
00369
00370 for (i = vbi->eoc; i < vbi->eoc+16; i += 2)
00371 dt[i] = 100, dt[i+1] = -100;
00372
00373
00374 for (i = vbi->soc, n = 0; n < 6; ++n)
00375 {
00376 while (dt[i] < 32)
00377 i++;
00378 hi[n] = i;
00379 while (dt[i] > -32)
00380 i++;
00381 lo[n] = i;
00382 }
00383 if (i >= vbi->eoc)
00384 return -1;
00385
00386 i = hi[5] - hi[1];
00387 if (i < vbi->bp8bl || i > vbi->bp8bh)
00388 return -1;
00389
00390
00391 min = 255, max = 0, sync = 0;
00392 for (i = hi[4]; i < hi[5]; ++i)
00393 if (p[i] > max)
00394 max = p[i], sync = i;
00395 for (i = lo[4]; i < lo[5]; ++i)
00396 if (p[i] < min)
00397 min = p[i];
00398 thr = (min + max) / 2;
00399
00400 p += sync;
00401
00402
00403 for (i = 4*bpb + vbi->pll_adj*bpb/10; i < 16*bpb; i += bpb)
00404 if (p[i/FAC] > thr && p[(i+bpb)/FAC] > thr)
00405 {
00406
00407 memset(data, 0, sizeof(data));
00408
00409 for (n = 0; n < 43*8; ++n, i += bpb)
00410 if (p[i/FAC] > thr)
00411 data[n/8] |= 1 << (n%8);
00412
00413 if (data[0] != 0x27)
00414 return -1;
00415
00416 if ((i = vt_line(vbi, data+1)))
00417 {
00418 if (i < 0)
00419 pll_add(vbi, 2, -i);
00420 else
00421 pll_add(vbi, 1, i);
00422 }
00423 return 0;
00424 }
00425 return -1;
00426 }
00427
00428
00429
00430
00431
00432 void
00433 vbi_handler(struct vbi *vbi, int fd)
00434 {
00435 int n, i;
00436 unsigned int seq;
00437
00438 (void)fd;
00439
00440 n = read(vbi->fd, rawbuf, vbi->bufsize);
00441
00442 if (dl_empty(vbi->clients))
00443 return;
00444
00445 if (n != vbi->bufsize)
00446 return;
00447
00448 seq = *(unsigned int *)&rawbuf[n - 4];
00449 if (vbi->seq+1 != seq)
00450 {
00451 out_of_sync(vbi);
00452 if (seq < 3 && vbi->seq >= 3)
00453 vbi_reset(vbi);
00454 }
00455 vbi->seq = seq;
00456
00457 if (seq > 1)
00458 {
00459 #if 1
00460 for (i = 0; i+vbi->bpl <= n; i += vbi->bpl)
00461 vbi_line(vbi, rawbuf + i);
00462 #else
00463
00464 for (i = 16 * vbi->bpl; i + vbi->bpl <= n; i += vbi->bpl)
00465 vbi_line(vbi, rawbuf + i);
00466
00467 for (i = 0; i + vbi->bpl <= 16 * vbi->bpl; i += vbi->bpl)
00468 vbi_line(vbi, rawbuf + i);
00469 #endif
00470 }
00471 }
00472
00473
00474
00475 int
00476 vbi_add_handler(struct vbi *vbi, void *handler, void *data)
00477 {
00478 struct vbi_client *cl;
00479
00480 if (!(cl = malloc(sizeof(*cl))))
00481 return -1;
00482 cl->handler = handler;
00483 cl->data = data;
00484 dl_insert_last(vbi->clients, cl->node);
00485 return 0;
00486 }
00487
00488
00489
00490 void
00491 vbi_del_handler(struct vbi *vbi, void *handler, void *data)
00492 {
00493 struct vbi_client *cl;
00494
00495 for (cl = (void*) vbi->clients->first; cl->node->next; cl = (void*) cl->node->next)
00496 if (cl->handler == handler && cl->data == data)
00497 {
00498 dl_remove(cl->node);
00499 break;
00500 }
00501 return;
00502 }
00503
00504
00505
00506 static int
00507 set_decode_parms(struct vbi *vbi, struct v4l2_vbi_format *p)
00508 {
00509 double fs;
00510 double bpb;
00511 int soc, eoc;
00512 int bpl;
00513
00514 if (p->sample_format != V4L2_PIX_FMT_GREY)
00515 {
00516 fprintf(stderr, "got pix fmt %x\n", p->sample_format);
00517 error("v4l2: unsupported vbi data format");
00518 return -1;
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 bpl = p->samples_per_line;
00533 fs = p->sampling_rate;
00534 bpb = fs/6937500.0;
00535 soc = (int)(9.2e-6*fs) - (int)p->offset;
00536 eoc = (int)(12.9e-6*fs) - (int)p->offset;
00537 if (soc < 0)
00538 soc = 0;
00539 if (eoc > bpl - (int)(43*8*bpb))
00540 eoc = bpl - (int)(43*8*bpb);
00541 if (eoc - soc < (int)(16*bpb))
00542 {
00543
00544 error("v4l2: broken vbi format specification");
00545 return -1;
00546 }
00547 if (eoc > 240)
00548 {
00549
00550 error("v4l2: unable to handle these sampling parameters");
00551 return -1;
00552 }
00553
00554 vbi->bpb = bpb * FAC + 0.5;
00555 vbi->soc = soc;
00556 vbi->eoc = eoc;
00557 vbi->bp8bl = 0.97 * 8*bpb;
00558 vbi->bp8bh = 1.03 * 8*bpb;
00559
00560 vbi->bpl = bpl;
00561 vbi->bufsize = bpl * (p->count[0] + p->count[1]);
00562
00563 return 0;
00564 }
00565
00566
00567 static int
00568 setup_dev(struct vbi *vbi)
00569 {
00570 #ifdef _WIN32
00571 (void) vbi;
00572 #else // if !_WIN32
00573 struct v4l2_format v4l2_format[1];
00574 struct v4l2_vbi_format *vbifmt = &v4l2_format->fmt.vbi;
00575
00576 memset(&v4l2_format, 0, sizeof(v4l2_format));
00577 v4l2_format->type = V4L2_BUF_TYPE_VBI_CAPTURE;
00578 if (ioctl(vbi->fd, VIDIOC_G_FMT, v4l2_format) == -1)
00579 {
00580
00581 int size;
00582 perror("ioctl VIDIOC_G_FMT");
00583
00584 vbifmt->sample_format = V4L2_PIX_FMT_GREY;
00585 vbifmt->sampling_rate = 35468950;
00586 vbifmt->samples_per_line = 2048;
00587 vbifmt->offset = 244;
00588 if ((size = ioctl(vbi->fd, BTTV_VBISIZE, 0)) == -1)
00589 {
00590
00591 vbifmt->count[0] = 16;
00592 vbifmt->count[1] = 16;
00593 }
00594 else if (size % 2048)
00595 {
00596 error("broken bttv driver (bad buffer size)");
00597 return -1;
00598 }
00599 else
00600 {
00601 size /= 2048;
00602 vbifmt->count[0] = size/2;
00603 vbifmt->count[1] = size - size/2;
00604 }
00605 }
00606
00607 if (set_decode_parms(vbi, vbifmt) == -1)
00608 return -1;
00609
00610 if (vbi->bpl < 1 || vbi->bufsize < vbi->bpl || vbi->bufsize % vbi->bpl != 0)
00611 {
00612 error("strange size of vbi buffer (%d/%d)", vbi->bufsize, vbi->bpl);
00613 return -1;
00614 }
00615
00616
00617 if (rawbuf_size < vbi->bufsize)
00618 {
00619 if (rawbuf)
00620 free(rawbuf);
00621 if (!(rawbuf = malloc(rawbuf_size = vbi->bufsize)))
00622 error("malloc refused in setup_dev()\n");
00623 }
00624
00625 #endif // !_WIN32
00626 return 0;
00627 }
00628
00629
00630
00631 struct vbi *
00632 vbi_open(const char *vbi_name, struct cache *ca, int fine_tune, int big_buf)
00633 {
00634 static int inited = 0;
00635 struct vbi *vbi;
00636
00637 (void)ca;
00638
00639 if (! inited)
00640 lang_init();
00641 inited = 1;
00642
00643 if (!(vbi = malloc(sizeof(*vbi))))
00644 {
00645 error("out of memory");
00646 goto fail1;
00647 }
00648
00649 if ((vbi->fd = open(vbi_name, O_RDONLY)) == -1)
00650 {
00651 error("cannot open vbi device");
00652 goto fail2;
00653 }
00654
00655 if (big_buf != -1)
00656 error("-oldbttv/-newbttv is obsolete. option ignored.");
00657
00658 if (setup_dev(vbi) == -1)
00659 goto fail3;
00660
00661
00662
00663 dl_init(vbi->clients);
00664 vbi->seq = 0;
00665 out_of_sync(vbi);
00666 vbi->ppage = vbi->rpage;
00667
00668 vbi_pll_reset(vbi, fine_tune);
00669
00670 return vbi;
00671
00672 fail3:
00673 close(vbi->fd);
00674 fail2:
00675 free(vbi);
00676 fail1:
00677 return 0;
00678 }
00679
00680
00681
00682 void
00683 vbi_close(struct vbi *vbi)
00684 {
00685
00686
00687
00688 close(vbi->fd);
00689 free(vbi);
00690 }
00691
00692
00693 struct vt_page *
00694 vbi_query_page(struct vbi *vbi, int pgno, int subno)
00695 {
00696 struct vt_page *vtp = 0;
00697
00698 (void)pgno;
00699 (void)subno;
00700
00701
00702
00703 if (vtp == 0)
00704 {
00705
00706 return 0;
00707 }
00708
00709 vbi_send(vbi, EV_PAGE, 1, 0, 0, vtp);
00710 return vtp;
00711 }
00712
00713 void
00714 vbi_reset(struct vbi *vbi)
00715 {
00716
00717
00718 vbi_send(vbi, EV_RESET, 0, 0, 0, 0);
00719 }
00720