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