Iñaki García Etxebarria wrote:
>
> > Hi,
> Hi,
>
> > After installing bttv-0.7.46 I get uresolved symbols in btaudio.o
> > After installing the bttv2 driver I get unresolved symbols in bttv.o and
> > bttv2.o.
> I've had the same problems with a test8 kernel.
> The attached patch fixes it for me.
>
> BTW, which program has been used for testing VBI support in the bttv2 driver?
> AleVT 1.6.0 doesn't work for me.
>
> Regards,
> Iñaki
Thanks for the patch - I just want to test it on 2.2 series kernels, and
if it works, I will include it. (Perhaps you should also forward it to
Gerd, as this will affect bttv too).
Below is a patch to get alevt working with bttv2. It is not fully v4l2
compliant yet, but at least it works!
-justin
diff -urN alevt-1.6.0/vbi.c alevt-1.6.0.wks/vbi.c
--- alevt-1.6.0/vbi.c Wed Oct 11 19:39:19 2000
+++ alevt-1.6.0.wks/vbi.c Wed Oct 25 19:00:06 2000
@@ -11,6 +11,10 @@
#include "fdset.h"
#include "hamm.h"
#include "lang.h"
+#include <linux/fs.h>
+#include <linux/videodev.h>
+#include <errno.h>
+#include <sys/mman.h>
#define FAC (1<<16) // factor for fix-point arithmetic
@@ -24,34 +28,6 @@
#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
-/***** v4l2 vbi-api *****/
-
-struct v4l2_vbi_format
-{
- u32 sampling_rate; /* in 1 Hz */
- u32 offset; /* sampling starts # samples after rising hs */
- u32 samples_per_line;
- u32 sample_format; /* V4L2_VBI_SF_* */
- s32 start[2];
- u32 count[2];
- u32 flags; /* V4L2_VBI_* */
- u32 reserved2; /* must be zero */
-};
-
-struct v4l2_format
-{
- u32 type; /* V4L2_BUF_TYPE_* */
- union
- {
- struct v4l2_vbi_format vbi; /* VBI data */
- u8 raw_data[200]; /* user-defined */
- } fmt;
-};
-
-#define V4L2_VBI_SF_UBYTE 1
-#define V4L2_BUF_TYPE_VBI 0x00000009
-#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format)
-
/***** end of api definitions *****/
@@ -357,8 +333,7 @@
i = hi[5] - hi[1]; // length of 4 periods (8 bits)
if (i < vbi->bp8bl || i > vbi->bp8bh)
- return -1; // bad frequency
-
+ return -2; // bad frequency
/* AGC and sync-reference */
min = 255, max = 0, sync = 0;
for (i = hi[4]; i < hi[5]; ++i)
@@ -375,6 +350,7 @@
for (i = 4*bpb + vbi->pll_adj*bpb/10; i < 16*bpb; i += bpb)
if (p[i/FAC] > thr && p[(i+bpb)/FAC] > thr) // two ones is enough...
{
+ fprintf(stderr, "startbyte\n");
/* got it... */
memset(data, 0, sizeof(data));
@@ -383,7 +359,7 @@
data[n/8] |= 1 << (n%8);
if (data[0] != 0x27) // really 11100100? (rev order!)
- return -1;
+ return -3;
if (i = vt_line(vbi, data+1))
if (i < 0)
@@ -392,7 +368,7 @@
pll_add(vbi, 1, i);
return 0;
}
- return -1;
+ return -4;
}
@@ -404,16 +380,31 @@
{
int n, i;
u32 seq;
-
- n = read(vbi->fd, rawbuf, vbi->bufsize);
+ struct v4l2_buffer qbuf;
+ fd_set fds;
+
+/* n = -1;
+ while(n<=0)
+ {
+ FD_ZERO(&fds);
+ FD_SET(vbi->fd, &fds);
+ n = select(vbi->fd + 1, &fds, NULL, NULL, NULL);
+ if(n < 0 && errno == EINTR) continue;
+ if(n<0) perror("select");
+ } */
+ qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+ if(ioctl(vbi->fd, VIDIOC_DQBUF, &qbuf)<0)
+ {
+ perror("dqbuf");
+ return;
+ }
+ fprintf(stderr, "%d %d\n", qbuf.index, qbuf.sequence);
+ rawbuf = vbi->bufs[qbuf.index];
if (dl_empty(vbi->clients))
- return;
+ goto done;
- if (n != vbi->bufsize)
- return;
-
- seq = *(u32 *)&rawbuf[n - 4];
+ seq = qbuf.sequence;
if (vbi->seq+1 != seq)
{
out_of_sync(vbi);
@@ -422,9 +413,15 @@
}
vbi->seq = seq;
- if (seq > 1) // the first may contain data from prev channel
- for (i = 0; i+vbi->bpl <= n; i += vbi->bpl)
- vbi_line(vbi, rawbuf + i);
+ if (seq > 0) // the first may contain data from prev channel
+ for (i = 0; i < vbi->bufsize; i += vbi->bpl)
+ {
+ fprintf(stderr, "line %d %d\n", i/vbi->bpl, vbi_line(vbi, rawbuf + i));
+ }
+
+done:
+ if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+ perror("qbuf");
}
@@ -498,13 +495,13 @@
{
// line too short or offset too large or wrong sample_rate
error("v4l2: broken vbi format specification");
- return -1;
+// return -1;
}
if (eoc > 240)
{
// the vbi_line routine can hold max 240 values in its work buffer
error("v4l2: unable to handle these sampling parameters");
- return -1;
+// return -1;
}
vbi->bpb = bpb * FAC + 0.5;
@@ -519,58 +516,69 @@
return 0;
}
-
static int
setup_dev(struct vbi *vbi)
{
struct v4l2_format v4l2_format[1];
struct v4l2_vbi_format *vbifmt = &v4l2_format->fmt.vbi;
-
- if (ioctl(vbi->fd, VIDIOC_G_FMT, v4l2_format) == -1
- || v4l2_format->type != V4L2_BUF_TYPE_VBI)
+ struct v4l2_requestbuffers req;
+ struct v4l2_buffer qbuf;
+ int i;
+
+ vbifmt->start[0]=0;
+ vbifmt->start[1]=313;
+ vbifmt->count[0]=16;
+ vbifmt->count[1]=16;
+ ioctl(vbi->fd, VIDIOC_S_FMT, v4l2_format);
+
+ req.type = V4L2_BUF_TYPE_CAPTURE;
+ req.count = BUFS;
+ if(ioctl(vbi->fd, VIDIOC_REQBUFS, &req)<0)
+ {
+ perror("req");
+ return -1;
+
+ }
+ vbi->nbufs = req.count;
+ for(i=0; i<vbi->nbufs; i++)
{
- // not a v4l2 device. assume bttv and create a standard fmt-struct.
- int size;
-
- vbifmt->sample_format = V4L2_VBI_SF_UBYTE;
- vbifmt->sampling_rate = 35468950;
- vbifmt->samples_per_line = 2048;
- vbifmt->offset = 244;
- if ((size = ioctl(vbi->fd, BTTV_VBISIZE, 0)) == -1)
- {
- // BSD or older bttv driver.
- vbifmt->count[0] = 16;
- vbifmt->count[1] = 16;
- }
- else if (size % 2048)
- {
- error("broken bttv driver (bad buffer size)");
- return -1;
- }
- else
- {
- size /= 2048;
- vbifmt->count[0] = size/2;
- vbifmt->count[1] = size - size/2;
- }
+ qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+ qbuf.index = i;
+ if(ioctl(vbi->fd, VIDIOC_QUERYBUF, &qbuf)<0)
+ {
+ perror("querybuf");
+ return -1;
+ }
+ vbi->bufs[i] = mmap(NULL, qbuf.length, PROT_READ, MAP_SHARED, vbi->fd, qbuf.offset);
+ if((int)vbi->bufs[i]==-1)
+ {
+ perror("mmap");
+ return -1;
+ }
+ if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+ {
+ perror("qbuf");
+ return -1;
+ }
+ }
+ i = V4L2_BUF_TYPE_CAPTURE;
+ if(ioctl(vbi->fd, VIDIOC_STREAMON, &i)<0)
+ {
+ perror("streamon");
+ return -1;
}
+ vbifmt->offset = 240;
+
if (set_decode_parms(vbi, vbifmt) == -1)
return -1;
+
+ fprintf(stderr, "%d %d\n", vbi->bpl, vbi->bufsize);
if (vbi->bpl < 1 || vbi->bufsize < vbi->bpl || vbi->bufsize % vbi->bpl != 0)
{
error("strange size of vbi buffer (%d/%d)", vbi->bufsize, vbi->bpl);
return -1;
- }
-
- // grow buffer if necessary
- if (rawbuf_size < vbi->bufsize)
- {
- if (rawbuf)
- free(rawbuf);
- if (not(rawbuf = malloc(rawbuf_size = vbi->bufsize)))
- out_of_mem(rawbuf_size); // old buffer already freed. abort.
}
return 0;
diff -urN alevt-1.6.0/vbi.c~ alevt-1.6.0.wks/vbi.c~
--- alevt-1.6.0/vbi.c~ Thu Jan 1 02:00:00 1970
+++ alevt-1.6.0.wks/vbi.c~ Wed Oct 25 18:58:38 2000
@@ -0,0 +1,673 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include "os.h"
+#include "vt.h"
+#include "misc.h"
+#include "vbi.h"
+#include "fdset.h"
+#include "hamm.h"
+#include "lang.h"
+#include <linux/fs.h>
+#include <linux/videodev.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#define FAC (1<<16) // factor for fix-point arithmetic
+
+static u8 *rawbuf; // one common buffer for raw vbi data.
+static int rawbuf_size; // its current size
+
+
+/***** bttv api *****/
+
+#define BASE_VIDIOCPRIVATE 192
+#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
+
+/***** end of api definitions *****/
+
+
+
+static void
+out_of_sync(struct vbi *vbi)
+{
+ int i;
+
+ // discard all in progress pages
+ for (i = 0; i < 8; ++i)
+ vbi->rpage[i].page->flags &= ~PG_ACTIVE;
+}
+
+
+// send an event to all clients
+
+static void
+vbi_send(struct vbi *vbi, int type, int i1, int i2, int i3, void *p1)
+{
+ struct vt_event ev[1];
+ struct vbi_client *cl, *cln;
+
+ ev->resource = vbi;
+ ev->type = type;
+ ev->i1 = i1;
+ ev->i2 = i2;
+ ev->i3 = i3;
+ ev->p1 = p1;
+
+ for (cl = $ vbi->clients->first; cln = $ cl->node->next; cl = cln)
+ cl->handler(cl->data, ev);
+}
+
+static void
+vbi_send_page(struct vbi *vbi, struct raw_page *rvtp, int page)
+{
+ struct vt_page *cvtp = 0;
+
+ if (rvtp->page->flags & PG_ACTIVE)
+ {
+ if (rvtp->page->pgno % 256 != page)
+ {
+ rvtp->page->flags &= ~PG_ACTIVE;
+ enhance(rvtp->enh, rvtp->page);
+ if (vbi->cache)
+ cvtp = vbi->cache->op->put(vbi->cache, rvtp->page);
+ vbi_send(vbi, EV_PAGE, 0, 0, 0, cvtp ?: rvtp->page);
+ }
+ }
+}
+
+// fine tune pll
+// this routines tries to adjust the sampling point of the decoder.
+// it collects parity and hamming errors and moves the sampling point
+// a 10th of a bitlength left or right.
+
+#define PLL_SAMPLES 4 // number of err vals to collect
+#define PLL_ERROR 4 // if this err val is crossed, readjust
+//#define PLL_ADJUST 4 // max/min adjust (10th of bitlength)
+
+static void
+pll_add(struct vbi *vbi, int n, int err)
+{
+ if (vbi->pll_fixed)
+ return;
+
+ if (err > PLL_ERROR*2/3) // limit burst errors
+ err = PLL_ERROR*2/3;
+
+ vbi->pll_err += err;
+ vbi->pll_cnt += n;
+ if (vbi->pll_cnt < PLL_SAMPLES)
+ return;
+
+ if (vbi->pll_err > PLL_ERROR)
+ {
+ if (vbi->pll_err > vbi->pll_lerr)
+ vbi->pll_dir = -vbi->pll_dir;
+ vbi->pll_lerr = vbi->pll_err;
+
+ vbi->pll_adj += vbi->pll_dir;
+ if (vbi->pll_adj < -PLL_ADJUST || vbi->pll_adj > PLL_ADJUST)
+ {
+ vbi->pll_adj = 0;
+ vbi->pll_dir = -1;
+ vbi->pll_lerr = 0;
+ }
+
+ if (debug)
+ printf("pll_adj = %2d\n", vbi->pll_adj);
+ }
+ vbi->pll_cnt = 0;
+ vbi->pll_err = 0;
+}
+
+void
+vbi_pll_reset(struct vbi *vbi, int fine_tune)
+{
+ vbi->pll_fixed = fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST;
+
+ vbi->pll_err = 0;
+ vbi->pll_lerr = 0;
+ vbi->pll_cnt = 0;
+ vbi->pll_dir = -1;
+ vbi->pll_adj = 0;
+ if (vbi->pll_fixed)
+ vbi->pll_adj = fine_tune;
+ if (debug)
+ if (vbi->pll_fixed)
+ printf("pll_reset (fixed@%d)\n", vbi->pll_adj);
+ else
+ printf("pll_reset (auto)\n");
+}
+
+// process one videotext packet
+
+static int
+vt_line(struct vbi *vbi, u8 *p)
+{
+ struct vt_page *cvtp;
+ struct raw_page *rvtp;
+ int hdr, mag, mag8, pkt, i;
+ int err = 0;
+
+ hdr = hamm16(p, &err);
+ if (err & 0xf000)
+ return -4;
+
+ mag = hdr & 7;
+ mag8 = mag?: 8;
+ pkt = (hdr >> 3) & 0x1f;
+ p += 2;
+
+ rvtp = vbi->rpage + mag;
+ cvtp = rvtp->page;
+
+ switch (pkt)
+ {
+ case 0:
+ {
+ int b1, b2, b3, b4;
+
+ b1 = hamm16(p, &err); // page number
+ b2 = hamm16(p+2, &err); // subpage number + flags
+ b3 = hamm16(p+4, &err); // subpage number + flags
+ b4 = hamm16(p+6, &err); // language code + more flags
+
+ if (vbi->ppage->page->flags & PG_MAGSERIAL)
+ vbi_send_page(vbi, vbi->ppage, b1);
+ vbi_send_page(vbi, rvtp, b1);
+
+ if (err & 0xf000)
+ return 4;
+
+ cvtp->errors = (err >> 8) + chk_parity(p + 8, 32);;
+ cvtp->pgno = mag8 * 256 + b1;
+ cvtp->subno = (b2 + b3 * 256) & 0x3f7f;
+ cvtp->lang = "\0\4\2\6\1\5\3\7"[b4 >> 5] + (latin1 ? 0 : 8);
+ cvtp->flags = b4 & 0x1f;
+ cvtp->flags |= b3 & 0xc0;
+ cvtp->flags |= (b2 & 0x80) >> 2;
+ cvtp->lines = 1;
+ cvtp->flof = 0;
+ vbi->ppage = rvtp;
+
+ pll_add(vbi, 1, cvtp->errors);
+
+ conv2latin(p + 8, 32, cvtp->lang);
+ vbi_send(vbi, EV_HEADER, cvtp->pgno, cvtp->subno, cvtp->flags, p);
+
+ if (b1 == 0xff)
+ return 0;
+
+ cvtp->flags |= PG_ACTIVE;
+ init_enhance(rvtp->enh);
+ memcpy(cvtp->data[0]+0, p, 40);
+ memset(cvtp->data[0]+40, ' ', sizeof(cvtp->data)-40);
+ return 0;
+ }
+
+ case 1 ... 24:
+ {
+ pll_add(vbi, 1, err = chk_parity(p, 40));
+
+ if (~cvtp->flags & PG_ACTIVE)
+ return 0;
+
+ cvtp->errors += err;
+ cvtp->lines |= 1 << pkt;
+ conv2latin(p, 40, cvtp->lang);
+ memcpy(cvtp->data[pkt], p, 40);
+ return 0;
+ }
+ case 26:
+ {
+ int d, t[13];
+
+ if (~cvtp->flags & PG_ACTIVE)
+ return 0;
+
+ d = hamm8(p, &err);
+ if (err & 0xf000)
+ return 4;
+
+ for (i = 0; i < 13; ++i)
+ t[i] = hamm24(p + 1 + 3*i, &err);
+ if (err & 0xf000)
+ return 4;
+
+ //printf("enhance on %x/%x\n", cvtp->pgno, cvtp->subno);
+ add_enhance(rvtp->enh, d, t);
+ return 0;
+ }
+ case 27:
+ {
+ // FLOF data (FastText)
+ int b1,b2,b3,x;
+
+ if (~cvtp->flags & PG_ACTIVE)
+ return 0; // -1 flushes all pages. we may never resync again :(
+
+ b1 = hamm8(p, &err);
+ b2 = hamm8(p + 37, &err);
+ if (err & 0xf000)
+ return 4;
+ if (b1 != 0 || not(b2 & 8))
+ return 0;
+
+ for (i = 0; i < 6; ++i)
+ {
+ err = 0;
+ b1 = hamm16(p+1+6*i, &err);
+ b2 = hamm16(p+3+6*i, &err);
+ b3 = hamm16(p+5+6*i, &err);
+ if (err & 0xf000)
+ return 1;
+ x = (b2 >> 7) | ((b3 >> 5) & 0x06);
+ cvtp->link[i].pgno = ((mag ^ x) ?: 8) * 256 + b1;
+ cvtp->link[i].subno = (b2 + b3 * 256) & 0x3f7f;
+ }
+ cvtp->flof = 1;
+ return 0;
+ }
+ case 30:
+ {
+ if (mag8 != 8)
+ return 0;
+
+ p[0] = hamm8(p, &err); // designation code
+ p[1] = hamm16(p+1, &err); // initial page
+ p[3] = hamm16(p+3, &err); // initial subpage + mag
+ p[5] = hamm16(p+5, &err); // initial subpage + mag
+ if (err & 0xf000)
+ return 4;
+
+ err += chk_parity(p+20, 20);
+ conv2latin(p+20, 20, 0);
+
+ vbi_send(vbi, EV_XPACKET, mag8, pkt, err, p);
+ return 0;
+ }
+ default:
+ // unused at the moment...
+ //vbi_send(vbi, EV_XPACKET, mag8, pkt, err, p);
+ return 0;
+ }
+ return 0;
+}
+
+
+
+// process one raw vbi line
+
+static int
+vbi_line(struct vbi *vbi, u8 *p)
+{
+ u8 data[43], min, max;
+ int dt[256], hi[6], lo[6];
+ int i, n, sync, thr;
+ int bpb = vbi->bpb;
+
+ /* remove DC. edge-detector */
+ for (i = vbi->soc; i < vbi->eoc; ++i)
+ dt[i] = p[i+bpb/FAC] - p[i]; // amplifies the edges best.
+
+ /* set barrier */
+ for (i = vbi->eoc; i < vbi->eoc+16; i += 2)
+ dt[i] = 100, dt[i+1] = -100;
+
+ /* find 6 rising and falling edges */
+ for (i = vbi->soc, n = 0; n < 6; ++n)
+ {
+ while (dt[i] < 32)
+ i++;
+ hi[n] = i;
+ while (dt[i] > -32)
+ i++;
+ lo[n] = i;
+ }
+ if (i >= vbi->eoc)
+ return -1; // not enough periods found
+
+ i = hi[5] - hi[1]; // length of 4 periods (8 bits)
+ if (i < vbi->bp8bl || i > vbi->bp8bh)
+ return -2; // bad frequency
+
+ /* AGC and sync-reference */
+ min = 255, max = 0, sync = 0;
+ for (i = hi[4]; i < hi[5]; ++i)
+ if (p[i] > max)
+ max = p[i], sync = i;
+ for (i = lo[4]; i < lo[5]; ++i)
+ if (p[i] < min)
+ min = p[i];
+ thr = (min + max) / 2;
+
+ p += sync;
+
+ /* search start-byte 11100100 */
+ for (i = 4*bpb + vbi->pll_adj*bpb/10; i < 16*bpb; i += bpb)
+ if (p[i/FAC] > thr && p[(i+bpb)/FAC] > thr) // two ones is enough...
+ {
+ fprintf(stderr, "startbyte\n");
+ /* got it... */
+ memset(data, 0, sizeof(data));
+
+ for (n = 0; n < 43*8; ++n, i += bpb)
+ if (p[i/FAC] > thr)
+ data[n/8] |= 1 << (n%8);
+
+ if (data[0] != 0x27) // really 11100100? (rev order!)
+ return -3;
+
+ if (i = vt_line(vbi, data+1))
+ if (i < 0)
+ pll_add(vbi, 2, -i);
+ else
+ pll_add(vbi, 1, i);
+ return 0;
+ }
+ return -4;
+}
+
+
+
+// called when new vbi data is waiting
+
+static void
+vbi_handler(struct vbi *vbi, int fd)
+{
+ int n, i;
+ u32 seq;
+ struct v4l2_buffer qbuf;
+ fd_set fds;
+
+/* n = -1;
+ while(n<=0)
+ {
+ FD_ZERO(&fds);
+ FD_SET(vbi->fd, &fds);
+ n = select(vbi->fd + 1, &fds, NULL, NULL, NULL);
+ if(n < 0 && errno == EINTR) continue;
+ if(n<0) perror("select");
+ } */
+ qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+ if(ioctl(vbi->fd, VIDIOC_DQBUF, &qbuf)<0)
+ {
+ perror("dqbuf");
+ return;
+ }
+ fprintf(stderr, "%d %d\n", qbuf.index, qbuf.sequence);
+ rawbuf = vbi->bufs[qbuf.index];
+
+ if (dl_empty(vbi->clients))
+ goto done;
+
+ seq = qbuf.sequence;
+ if (vbi->seq+1 != seq)
+ {
+ out_of_sync(vbi);
+ if (seq < 3 && vbi->seq >= 3)
+ vbi_reset(vbi);
+ }
+ vbi->seq = seq;
+
+ if (seq > 0) // the first may contain data from prev channel
+ for (i = 0; i < vbi->bufsize; i += vbi->bpl)
+ {
+ fprintf(stderr, "line %d %d\n", i/vbi->bpl, vbi_line(vbi, rawbuf + i));
+ }
+
+done:
+ if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+ perror("qbuf");
+}
+
+
+
+int
+vbi_add_handler(struct vbi *vbi, void *handler, void *data)
+{
+ struct vbi_client *cl;
+
+ if (not(cl = malloc(sizeof(*cl))))
+ return -1;
+ cl->handler = handler;
+ cl->data = data;
+ dl_insert_last(vbi->clients, cl->node);
+ return 0;
+}
+
+
+
+void
+vbi_del_handler(struct vbi *vbi, void *handler, void *data)
+{
+ struct vbi_client *cl;
+
+ for (cl = $ vbi->clients->first; cl->node->next; cl = $ cl->node->next)
+ if (cl->handler == handler && cl->data == data)
+ {
+ dl_remove(cl->node);
+ break;
+ }
+ return;
+}
+
+
+
+static int
+set_decode_parms(struct vbi *vbi, struct v4l2_vbi_format *p)
+{
+ double fs; // sampling rate
+ double bpb; // bytes per bit
+ int soc, eoc; // start/end of clock run-in
+ int bpl; // bytes per line
+
+ if (p->sample_format != V4L2_VBI_SF_UBYTE)
+ {
+ error("v4l2: unsupported vbi data format");
+ return -1;
+ }
+
+ // some constants from the standard:
+ // horizontal frequency fh = 15625Hz
+ // teletext bitrate ft = 444*fh = 6937500Hz
+ // teletext identification sequence 10101010 10101010 11100100
+ // 13th bit of seq rel to falling hsync 12us -1us +0.4us
+ // I search for the clock run-in (10101010 10101010) from 12us-1us-12.5/ft
+ // (earliest first bit) to 12us+0.4us+3.5/ft (latest last bit)
+ // earlist first bit tf = 12us-1us-12.5/ft = 9.2us
+ // latest last bit tl = 12us+0.4us+3.5/ft = 12.9us
+ // total number of used bits n = (2+1+2+40)*8 = 360
+
+ bpl = p->samples_per_line;
+ fs = p->sampling_rate;
+ bpb = fs/6937500.0;
+ soc = (int)(9.2e-6*fs) - (int)p->offset;
+ eoc = (int)(12.9e-6*fs) - (int)p->offset;
+ if (soc < 0)
+ soc = 0;
+ if (eoc > bpl - (int)(43*8*bpb))
+ eoc = bpl - (int)(43*8*bpb);
+ if (eoc - soc < (int)(16*bpb))
+ {
+ // line too short or offset too large or wrong sample_rate
+ error("v4l2: broken vbi format specification");
+// return -1;
+ }
+ if (eoc > 240)
+ {
+ // the vbi_line routine can hold max 240 values in its work buffer
+ error("v4l2: unable to handle these sampling parameters");
+// return -1;
+ }
+
+ vbi->bpb = bpb * FAC + 0.5;
+ vbi->soc = soc;
+ vbi->eoc = eoc;
+ vbi->bp8bl = 0.97 * 8*bpb; // -3% tolerance
+ vbi->bp8bh = 1.03 * 8*bpb; // +3% tolerance
+
+ vbi->bpl = bpl;
+ vbi->bufsize = bpl * (p->count[0] + p->count[1]);
+
+ return 0;
+}
+
+static int
+setup_dev(struct vbi *vbi)
+{
+ struct v4l2_format v4l2_format[1];
+ struct v4l2_vbi_format *vbifmt = &v4l2_format->fmt.vbi;
+ struct v4l2_requestbuffers req;
+ struct v4l2_buffer qbuf;
+ int i;
+
+ vbifmt->start[0]=0;
+ vbifmt->start[1]=313;
+ vbifmt->count[0]=16;
+ vbifmt->count[1]=16;
+ ioctl(vbi->fd, VIDIOC_S_FMT, v4l2_format);
+
+ req.type = V4L2_BUF_TYPE_CAPTURE;
+ req.count = BUFS;
+ if(ioctl(vbi->fd, VIDIOC_REQBUFS, &req)<0)
+ {
+ perror("req");
+ return -1;
+
+ }
+ vbi->nbufs = req.count;
+ for(i=0; i<vbi->nbufs; i++)
+ {
+ qbuf.type = V4L2_BUF_TYPE_CAPTURE;
+ qbuf.index = i;
+ if(ioctl(vbi->fd, VIDIOC_QUERYBUF, &qbuf)<0)
+ {
+ perror("querybuf");
+ return -1;
+ }
+ vbi->bufs[i] = mmap(NULL, qbuf.length, PROT_READ, MAP_SHARED, vbi->fd, qbuf.offset);
+ if((int)vbi->bufs[i]==-1)
+ {
+ perror("mmap");
+ return -1;
+ }
+ if(ioctl(vbi->fd, VIDIOC_QBUF, &qbuf)<0)
+ {
+ perror("qbuf");
+ return -1;
+ }
+ }
+ i = V4L2_BUF_TYPE_CAPTURE;
+ if(ioctl(vbi->fd, VIDIOC_STREAMON, &i)<0)
+ {
+ perror("streamon");
+ return -1;
+ }
+
+ vbifmt->offset = 240;
+
+ if (set_decode_parms(vbi, vbifmt) == -1)
+ return -1;
+
+ fprintf(stderr, "%d %d\n", vbi->bpl, vbi->bufsize);
+
+ if (vbi->bpl < 1 || vbi->bufsize < vbi->bpl || vbi->bufsize % vbi->bpl != 0)
+ {
+ error("strange size of vbi buffer (%d/%d)", vbi->bufsize, vbi->bpl);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+struct vbi *
+vbi_open(char *vbi_name, struct cache *ca, int fine_tune, int big_buf)
+{
+ static int inited = 0;
+ struct vbi *vbi;
+
+ if (not inited)
+ lang_init();
+ inited = 1;
+
+ if (not(vbi = malloc(sizeof(*vbi))))
+ {
+ error("out of memory");
+ goto fail1;
+ }
+
+ if ((vbi->fd = open(vbi_name, O_RDONLY)) == -1)
+ {
+ ioerror(vbi_name);
+ goto fail2;
+ }
+
+ if (big_buf != -1)
+ error("-oldbttv/-newbttv is obsolete. option ignored.");
+
+ if (setup_dev(vbi) == -1)
+ goto fail3;
+
+ vbi->cache = ca;
+
+ dl_init(vbi->clients);
+ vbi->seq = 0;
+ out_of_sync(vbi);
+ vbi->ppage = vbi->rpage;
+
+ vbi_pll_reset(vbi, fine_tune);
+ fdset_add_fd(fds, vbi->fd, vbi_handler, vbi);
+ return vbi;
+
+fail3:
+ close(vbi->fd);
+fail2:
+ free(vbi);
+fail1:
+ return 0;
+}
+
+
+
+void
+vbi_close(struct vbi *vbi)
+{
+ fdset_del_fd(fds, vbi->fd);
+ if (vbi->cache)
+ vbi->cache->op->close(vbi->cache);
+ close(vbi->fd);
+ free(vbi);
+}
+
+
+struct vt_page *
+vbi_query_page(struct vbi *vbi, int pgno, int subno)
+{
+ struct vt_page *vtp = 0;
+
+ if (vbi->cache)
+ vtp = vbi->cache->op->get(vbi->cache, pgno, subno);
+ if (vtp == 0)
+ {
+ // EV_PAGE will come later...
+ return 0;
+ }
+
+ vbi_send(vbi, EV_PAGE, 1, 0, 0, vtp);
+ return vtp;
+}
+
+void
+vbi_reset(struct vbi *vbi)
+{
+ if (vbi->cache)
+ vbi->cache->op->reset(vbi->cache);
+ vbi_send(vbi, EV_RESET, 0, 0, 0, 0);
+}
diff -urN alevt-1.6.0/vbi.h alevt-1.6.0.wks/vbi.h
--- alevt-1.6.0/vbi.h Thu Sep 21 20:48:13 2000
+++ alevt-1.6.0.wks/vbi.h Wed Oct 25 18:57:56 2000
@@ -14,6 +14,8 @@
struct enhance enh[1];
};
+#define BUFS 4
+
struct vbi
{
int fd;
@@ -21,6 +23,8 @@
struct dl_head clients[1];
// raw buffer management
int bufsize; // nr of bytes sent by this device
+ int nbufs;
+ unsigned char *bufs[BUFS];
int bpl; // bytes per line
u32 seq;
// page assembly