aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-04-01 09:24:39 (GMT)
committerGerd Hoffmann <kraxel@redhat.com>2010-04-01 09:24:39 (GMT)
commitbc7f101b0c874e21473aca15d9b08de8bd164392 (patch)
tree878e2a671f9bd0b3401383406a513c8056f25e17 /common
parenta4a3e6b21da7d11e66364ab9ab67795a3f78020a (diff)
v3.75
Diffstat (limited to 'common')
-rw-r--r--common/capture.c1
-rw-r--r--common/commands.c13
-rw-r--r--common/commands.h11
-rw-r--r--common/joystick.c2
-rw-r--r--common/lirc.c2
-rw-r--r--common/list.h169
-rw-r--r--common/vbi-data.c365
-rw-r--r--common/vbi-data.h46
-rw-r--r--common/vbi-sim.c475
9 files changed, 1082 insertions, 2 deletions
diff --git a/common/capture.c b/common/capture.c
index a309bf2..5bca96e 100644
--- a/common/capture.c
+++ b/common/capture.c
@@ -4,6 +4,7 @@
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
+#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/types.h>
diff --git a/common/commands.c b/common/commands.c
index 846c782..6f1c577 100644
--- a/common/commands.c
+++ b/common/commands.c
@@ -28,8 +28,13 @@
/* feedback for the user */
void (*update_title)(char *message);
void (*display_message)(char *message);
-void (*vtx_message)(struct TEXTELEM *tt);
void (*rec_status)(char *message);
+#if TT
+void (*vtx_message)(struct TEXTELEM *tt);
+#endif
+#ifdef HAVE_ZVBI
+void (*vtx_subtitle)(struct vbi_page *pg, struct vbi_rect *rect);
+#endif
/* for updating GUI elements / whatever */
void (*attr_notify)(struct ng_attribute *attr, int val);
@@ -86,7 +91,9 @@ static int movie_handler(char *name, int argc, char **argv);
static int fullscreen_handler(char *name, int argc, char **argv);
static int msg_handler(char *name, int argc, char **argv);
static int showtime_handler(char *name, int argc, char **argv);
+#if TT
static int vtx_handler(char *name, int argc, char **argv);
+#endif
static int exit_handler(char *name, int argc, char **argv);
static int keypad_handler(char *name, int argc, char **argv);
@@ -120,7 +127,9 @@ static struct COMMANDS {
{ "movie", 1, movie_handler },
{ "fullscreen", 0, fullscreen_handler },
{ "msg", 1, msg_handler },
+#if 0
{ "vtx", 0, vtx_handler },
+#endif
{ "message", 0, msg_handler },
{ "exit", 0, exit_handler },
{ "quit", 0, exit_handler },
@@ -1146,6 +1155,7 @@ exit_handler(char *name, int argc, char **argv)
/* ----------------------------------------------------------------------- */
+#if TT
static struct TEXTELEM*
parse_vtx(int lines, char **text)
{
@@ -1251,6 +1261,7 @@ vtx_handler(char *name, int argc, char **argv)
}
return 0;
}
+#endif
/* ----------------------------------------------------------------------- */
diff --git a/common/commands.h b/common/commands.h
index 20b4229..8ee1531 100644
--- a/common/commands.h
+++ b/common/commands.h
@@ -1,4 +1,7 @@
+#include "vbi-data.h"
+#define TT 0
+#if TT
#define VTX_COUNT 256
#define VTX_LEN 64
@@ -10,14 +13,20 @@ struct TEXTELEM {
int line;
int x,y;
};
+#endif
/*------------------------------------------------------------------------*/
/* feedback for the user */
extern void (*update_title)(char *message);
extern void (*display_message)(char *message);
-extern void (*vtx_message)(struct TEXTELEM *tt);
extern void (*rec_status)(char *message);
+#if TT
+extern void (*vtx_message)(struct TEXTELEM *tt);
+#endif
+#ifdef HAVE_ZVBI
+extern void (*vtx_subtitle)(struct vbi_page *pg, struct vbi_rect *rect);
+#endif
/* for updating GUI elements / whatever */
extern void (*attr_notify)(struct ng_attribute *attr, int val);
diff --git a/common/joystick.c b/common/joystick.c
index 69ed3fe..3498bf0 100644
--- a/common/joystick.c
+++ b/common/joystick.c
@@ -81,6 +81,8 @@ int joystick_tv_init(char *dev)
event_register_list(joy_events);
return fd;
#else
+ if (debug)
+ fprintf(stderr,"joystick: not enabled at compile time\n");
return -1;
#endif
}
diff --git a/common/lirc.c b/common/lirc.c
index a39f5ab..ad7545e 100644
--- a/common/lirc.c
+++ b/common/lirc.c
@@ -108,6 +108,8 @@ int lirc_tv_init()
return fd;
#else
+ if (debug)
+ fprintf(stderr,"lirc: not enabled at compile time\n");
return -1;
#endif
}
diff --git a/common/list.h b/common/list.h
new file mode 100644
index 0000000..902f7d4
--- /dev/null
+++ b/common/list.h
@@ -0,0 +1,169 @@
+#ifndef _LIST_H
+#define _LIST_H 1
+
+/*
+ * Simple doubly linked list implementation.
+ * -- shameless stolen from the linux kernel sources
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list in reverse order
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+#endif /* _LIST_H */
diff --git a/common/vbi-data.c b/common/vbi-data.c
new file mode 100644
index 0000000..ddeb307
--- /dev/null
+++ b/common/vbi-data.c
@@ -0,0 +1,365 @@
+#include "config.h"
+#ifdef HAVE_ZVBI
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <time.h>
+#include <fcntl.h>
+#include <iconv.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include <X11/Intrinsic.h>
+
+#include "vbi-data.h"
+#include "vbi-sim.c"
+
+char *vbi_colors[8] = { "black", "red", "green", "yellow",
+ "blue", "magenta", "cyan", "white" };
+struct vbi_rect vbi_fullrect = {
+ x1: 0, y1: 0, x2: 41, y2: 25,
+};
+
+/*---------------------------------------------------------------------*/
+
+struct vbi_state*
+vbi_open(char *dev, int debug, int sim)
+{
+ struct vbi_state *vbi;
+ int services = VBI_SLICED_VBI_525 | VBI_SLICED_VBI_625
+ | VBI_SLICED_TELETEXT_B | VBI_SLICED_CAPTION_525
+ | VBI_SLICED_CAPTION_625 | VBI_SLICED_VPS
+ | VBI_SLICED_WSS_625 | VBI_SLICED_WSS_CPR1204;
+ int p[2];
+
+ /* init vbi */
+ vbi = malloc(sizeof(*vbi));
+ if (NULL == vbi)
+ goto oops;
+ memset(vbi,0,sizeof(*vbi));
+ vbi->debug = debug;
+ vbi->sim = sim;
+ vbi->dec = vbi_decoder_new();
+ if (NULL == vbi->dec)
+ goto oops;
+
+ if (vbi->sim) {
+ vbi->par = init_sim(625,services);
+ /* simulation for select */
+ pipe(p);
+ switch (fork()) {
+ case -1:
+ perror("fork");
+ exit(1);
+ case 0:
+ close(p[0]);
+ for (;;) {
+ if (1 != write(p[1],"x",1))
+ exit(0);
+ usleep(100*1000);
+ }
+ default:
+ vbi->fd = p[0];
+ close(p[1]);
+ };
+ } else {
+ vbi->cap = vbi_capture_v4l2_new(dev,16,&services,-1,&vbi->err,debug);
+ if (NULL == vbi->cap) {
+ vbi->cap = vbi_capture_v4l_new(dev,16,&services,-1,&vbi->err,debug);
+ if (NULL == vbi->cap)
+ goto oops;
+ }
+ vbi->par = vbi_capture_parameters(vbi->cap);
+ vbi->fd = vbi_capture_fd(vbi->cap);
+ }
+ vbi->lines = (vbi->par->count[0] + vbi->par->count[1]);
+ vbi->raw = malloc(vbi->lines * vbi->par->bytes_per_line);
+ if (NULL == vbi->raw)
+ goto oops;
+ vbi->sliced = malloc(vbi->lines * sizeof(struct vbi_sliced));
+ if (NULL == vbi->sliced)
+ goto oops;
+ vbi->tv.tv_sec = 1;
+ vbi->tv.tv_usec = 0;
+ return vbi;
+
+ oops:
+ if (vbi) {
+ if (vbi->sliced)
+ free(vbi->sliced);
+ if (vbi->raw)
+ free(vbi->raw);
+ if (vbi->cap)
+ vbi_capture_delete(vbi->cap);
+ if (vbi->dec)
+ vbi_decoder_delete(vbi->dec);
+ free(vbi);
+ }
+ fprintf(stderr,"vbi: open failed [%s]\n",dev);
+ return NULL;
+}
+
+int
+vbi_hasdata(struct vbi_state *vbi)
+{
+ char buf[1];
+ int rc;
+
+ if (vbi->sim) {
+ read(vbi->fd,buf,1);
+ read_sim(vbi->raw, vbi->sliced, &vbi->lines, &vbi->ts);
+ rc = 1;
+ } else {
+ rc = vbi_capture_read(vbi->cap, vbi->raw, vbi->sliced,
+ &vbi->lines, &vbi->ts, &vbi->tv);
+ }
+ vbi_decode(vbi->dec, vbi->sliced, vbi->lines, vbi->ts);
+ return rc;
+}
+
+void
+vbi_close(struct vbi_state *vbi)
+{
+ if (vbi) {
+ if (vbi->sliced)
+ free(vbi->sliced);
+ if (vbi->raw)
+ free(vbi->raw);
+ if (vbi->cap)
+ vbi_capture_delete(vbi->cap);
+ if (vbi->dec)
+ vbi_decoder_delete(vbi->dec);
+ free(vbi);
+ }
+}
+
+void
+vbi_dump_event(struct vbi_event *ev, void *user)
+{
+ switch (ev->type) {
+ case VBI_EVENT_TTX_PAGE:
+ fprintf(stderr,"vbi ev: ttx page %03x.%02x \r",
+ ev->ev.ttx_page.pgno,
+ ev->ev.ttx_page.subno);
+ break;
+ case VBI_EVENT_CLOSE:
+ fprintf(stderr,"vbi ev: close \n");
+ break;
+ case VBI_EVENT_CAPTION:
+ fprintf(stderr,"vbi ev: caption \n");
+ break;
+ case VBI_EVENT_NETWORK:
+ fprintf(stderr,"vbi ev: network id=%d name=\"%s\" call=\"%s\"\n",
+ ev->ev.network.nuid,
+ ev->ev.network.name,
+ ev->ev.network.call);
+ break;
+ case VBI_EVENT_TRIGGER:
+ switch (ev->ev.trigger->type) {
+ case VBI_LINK_NONE:
+ fprintf(stderr,"vbi ev: trigger none \n");
+ break;
+ case VBI_LINK_MESSAGE:
+ fprintf(stderr,"vbi ev: trigger message \n");
+ break;
+ case VBI_LINK_PAGE:
+ fprintf(stderr,"vbi ev: trigger page [%03x.%02x]\n",
+ ev->ev.trigger->pgno,
+ ev->ev.trigger->subno);
+ break;
+ case VBI_LINK_SUBPAGE:
+ fprintf(stderr,"vbi ev: trigger subpage \n");
+ break;
+ case VBI_LINK_HTTP:
+ fprintf(stderr,"vbi ev: trigger http [%s]\n",
+ ev->ev.trigger->url);
+ break;
+ case VBI_LINK_FTP:
+ fprintf(stderr,"vbi ev: trigger ftp \n");
+ break;
+ case VBI_LINK_EMAIL:
+ fprintf(stderr,"vbi ev: trigger email \n");
+ break;
+ case VBI_LINK_LID:
+ fprintf(stderr,"vbi ev: trigger lid \n");
+ break;
+ case VBI_LINK_TELEWEB:
+ fprintf(stderr,"vbi ev: trigger teleweb \n");
+ break;
+ }
+ break;
+ case VBI_EVENT_ASPECT:
+ fprintf(stderr,"vbi ev: aspect \n");
+ break;
+ case VBI_EVENT_PROG_INFO:
+ fprintf(stderr,"vbi ev: prog info \n");
+ break;
+ default:
+ fprintf(stderr,"vbi ev: UNKNOWN[0x%x] \n",ev->type);
+ break;
+ }
+}
+
+int vbi_calc_page(int pagenr, int offset)
+{
+ int result;
+
+ result = pagenr + offset;
+ if (offset < 0) {
+ while ((result & 0x0f) > 0x09)
+ result -= 0x01;
+ while ((result & 0xf0) > 0x90)
+ result -= 0x10;
+ if (result < 0x100)
+ result = 0x100;
+ }
+ if (offset > 0) {
+ while ((result & 0x0f) > 0x09)
+ result += 0x01;
+ while ((result & 0xf0) > 0x90)
+ result += 0x10;
+ if (result > 0x899)
+ result = 0x899;
+ }
+ return result;
+}
+
+int vbi_calc_subpage(struct vbi_decoder *dec, int pgno, int subno, int offset)
+{
+ vbi_page pg;
+ int newno;
+
+ for (newno = subno+offset; newno != subno;) {
+ if (vbi_fetch_vt_page(dec,&pg,pgno,newno,
+ VBI_WST_LEVEL_1,0,0))
+ break;
+ if (offset < 0) {
+ newno--;
+ if (newno < 0)
+ newno += VBI_MAX_SUBPAGES;
+ while ((newno & 0x0f) > 0x09)
+ newno -= 0x01;
+ }
+ if (offset > 0) {
+ newno++;
+ while ((newno & 0x0f) > 0x09)
+ newno += 0x01;
+ if (newno >= VBI_MAX_SUBPAGES)
+ newno = 0;
+ }
+ }
+ return newno;
+}
+
+int vbi_export_txt(char *dest, char *charset, int size,
+ struct vbi_page *pg, struct vbi_rect *rect,
+ enum vbi_txt_colors color)
+{
+ int x,y,rc,olen,ilen;
+ int fg,bg,len=0;
+ char *ibuf, *obuf;
+ vbi_char *ch;
+ wchar_t wch;
+ iconv_t ic;
+
+ ic = iconv_open(charset,"WCHAR_T");
+ if (NULL == ic)
+ return -1;
+
+ obuf = dest;
+ olen = size;
+ for (y = rect->y1; y < rect->y2; y++) {
+ ch = pg->text + 41*y;
+ fg = -1;
+ bg = -1;
+ for (x = rect->x1; x <= rect->x2; x++) {
+ if (x < rect->x2) {
+ wch = ch[x].unicode;
+ if (ch[x].size > VBI_DOUBLE_SIZE)
+ wch = ' ';
+ if (ch[x].conceal)
+ wch = ' ';
+ } else {
+ wch = '\n';
+ }
+ if (fg != ch[x].foreground || bg != ch[x].background) {
+ fg = ch[x].foreground;
+ bg = ch[x].background;
+ switch (color) {
+ case VBI_ANSICOLOR:
+ len = sprintf(obuf,"\033[%d;%dm",
+ 30 + (fg & 7), 40 + (bg & 7));
+ break;
+ case VBI_NOCOLOR:
+ len = 0;
+ break;
+ }
+ olen -= len;
+ obuf += len;
+ }
+ ibuf = (char*)(&wch);
+ ilen = sizeof(wch);
+ retry:
+ rc = iconv(ic,&ibuf,&ilen,&obuf,&olen);
+ if (-1 == rc && EILSEQ == errno && wch != '?') {
+ if (vbi_is_gfx(wch))
+ wch = '#';
+ else
+ wch = '?';
+ goto retry;
+ }
+ if (-1 == rc)
+ goto done;
+ }
+ switch (color) {
+ case VBI_ANSICOLOR:
+ len = sprintf(obuf,"\033[0m");
+ break;
+ case VBI_NOCOLOR:
+ len = 0;
+ break;
+ }
+ olen -= len;
+ obuf += len;
+ }
+
+ done:
+ return obuf - dest;
+}
+
+void vbi_find_subtitle(struct vbi_page *pg, struct vbi_rect *rect)
+{
+ int x,y,showline;
+ vbi_char *ch;
+
+ *rect = vbi_fullrect;
+
+ for (y = 1; y < 25; y++) {
+ showline = 0;
+ ch = pg->text + 41*y;
+ for (x = 0; x <= 40; x++)
+ if (ch[x].unicode != ' ')
+ showline = 1;
+ if (showline)
+ break;
+ }
+ rect->y1 = y;
+
+ for (y = 25; y >= rect->y1; y--) {
+ showline = 0;
+ ch = pg->text + 41*y;
+ for (x = 0; x <= 40; x++)
+ if (ch[x].unicode != ' ')
+ showline = 1;
+ if (showline)
+ break;
+ }
+ rect->y2 = y+1;
+}
+
+#endif /* HAVE_ZVBI */
diff --git a/common/vbi-data.h b/common/vbi-data.h
new file mode 100644
index 0000000..4d6adc0
--- /dev/null
+++ b/common/vbi-data.h
@@ -0,0 +1,46 @@
+#ifndef _VBI_DATA_H
+#define _VBI_DATA_H 1
+
+#ifdef HAVE_ZVBI
+#include <libzvbi.h>
+
+#define VBI_MAX_SUBPAGES 64
+
+struct vbi_state {
+ struct vbi_decoder *dec;
+ struct vbi_capture *cap;
+ struct vbi_raw_decoder *par;
+ struct vbi_sliced *sliced;
+ uint8_t *raw;
+ char *err;
+ int lines,fd,sim,debug;
+ double ts;
+ struct timeval tv;
+};
+
+struct vbi_rect {
+ int x1,x2,y1,y2;
+};
+
+enum vbi_txt_colors {
+ VBI_NOCOLOR = 0,
+ VBI_ANSICOLOR = 1,
+};
+
+extern char *vbi_colors[8];
+extern struct vbi_rect vbi_fullrect;
+
+struct vbi_state* vbi_open(char *dev, int debug, int sim);
+int vbi_hasdata(struct vbi_state *vbi);
+void vbi_close(struct vbi_state *vbi);
+void vbi_dump_event(struct vbi_event *ev, void *user);
+int vbi_to_utf8(struct vbi_char *src, unsigned char *dest, int n);
+int vbi_calc_page(int pagenr, int offset);
+int vbi_calc_subpage(struct vbi_decoder *dec, int pgno, int subno, int offset);
+int vbi_export_txt(char *dest, char *charset, int size,
+ struct vbi_page *pg, struct vbi_rect *rect,
+ enum vbi_txt_colors);
+void vbi_find_subtitle(struct vbi_page *pg, struct vbi_rect *rect);
+
+#endif /* HAVE_ZVBI */
+#endif /* _VBI_DATA_H */
diff --git a/common/vbi-sim.c b/common/vbi-sim.c
new file mode 100644
index 0000000..88c7e45
--- /dev/null
+++ b/common/vbi-sim.c
@@ -0,0 +1,475 @@
+#include <math.h>
+
+#define AMP 110
+#define DC 60
+
+static vbi_raw_decoder sim;
+static double sim_time;
+
+static inline double
+shape(double ph)
+{
+ double x = sin(ph);
+
+ return x * x;
+}
+
+/*
+ * Closed Caption Signal Simulator
+ */
+
+static inline double
+cc_sim(double t, double F, unsigned char b1, unsigned char b2)
+{
+ int bits = (b2 << 10) + (b1 << 2) + 2; /* start bit 0 -> 1 */
+ double t1 = 10.5e-6 - .25 / F;
+ double t2 = t1 + 7 / F; /* CRI 7 cycles */
+ double t3 = t2 + 1.5 / F;
+ double t4 = t3 + 18 / F; /* 17 bits + raise and fall time */
+ double ph;
+
+ if (t < t1) {
+ return 0.0;
+ } else if (t < t2) {
+ t -= t2;
+ ph = M_PI * 2 * t * F - (M_PI * .5);
+ return sin(ph) / 2 + .5;
+ } else if (t < t3) {
+ return 0.0;
+ } else if (t < t4) {
+ int i, n;
+
+ t -= t3;
+ i = (t * F - .0);
+ n = (bits >> i) & 3; /* low = 0, up, down, high */
+ if (n == 0)
+ return 0.0;
+ else if (n == 3)
+ return 1.0;
+
+ if ((n ^ i) & 1) /* down */
+ ph = M_PI * 2 * (t - 1 / F) * F / 4;
+ else /* up */
+ ph = M_PI * 2 * (t - 0 / F) * F / 4;
+
+ return shape(ph);
+ } else {
+ return 0.0;
+ }
+}
+
+/*
+ * Wide Screen Signalling Simulator
+ */
+
+static inline double
+wss625_sim(double t, double F, unsigned int bits)
+{
+ static int twobit[] = { 0xE38, 0xE07, 0x1F8, 0x1C7 };
+ static char frame[] =
+ "\0"
+ "\1\1\1\1\1\0\0\0\1\1\1\0\0\0"
+ "\1\1\1\0\0\0\1\1\1\0\0\0\1\1\1"
+ "\0\0\0\1\1\1\1\0\0\0\1\1\1\1\0\0\0\0\0\1\1\1\1\1"
+ "x";
+ double t1 = 11.0e-6 - .5 / F;
+ double t4 = t1 + (29 + 24 + 84) / F;
+ double ph;
+ int i, j, n;
+
+ frame[1 + 29 + 24] = bits & 1;
+
+ if (t < t1) {
+ return 0.0;
+ } else if (t < t4) {
+ t -= t1;
+ i = (t * F - .0);
+ if (i < 29 + 24) {
+ n = frame[i] + 2 * frame[i + 1];
+ } else {
+ j = i - 29 - 24;
+ n = twobit[(bits >> (j / 6)) & 3];
+ n = (n >> (j % 6)) & 3;
+ }
+
+ /* low = 0, down, up, high */
+ if (n == 0)
+ return 0.0;
+ else if (n == 3)
+ return 1.0;
+ if ((n ^ i) & 1)
+ ph = M_PI * 2 * (t - 1 / F) * F / 4;
+ else /* down */
+ ph = M_PI * 2 * (t - 0 / F) * F / 4;
+
+ return shape(ph);
+ } else {
+ return 0.0;
+ }
+}
+
+static inline double
+wss525_sim(double t, double F, unsigned int bits)
+{
+ double t1 = 11.2e-6 - .5 / F;
+ double t4 = t1 + (2 + 14 + 6 + 1) / F;
+ double ph;
+ int i, n;
+
+ bits = bits * 2 + (2 << 21); /* start bits 10, stop 0 */
+
+ if (t < t1) {
+ return 0.0;
+ } else if (t < t4) {
+ t -= t1;
+ i = (t * F - .0);
+ n = (bits >> (22 - i)) & 3; /* low = 0, up, down, high */
+
+ if (n == 0)
+ return 0.0;
+ else if (n == 3)
+ return 1.0;
+ if ((n ^ i) & 1)
+ ph = M_PI * 2 * (t - 0 / F) * F / 4;
+ else /* down */
+ ph = M_PI * 2 * (t - 1 / F) * F / 4;
+
+ return shape(ph);
+ } else
+ return 0.0;
+}
+
+/*
+ * Teletext Signal Simulator
+ */
+
+static inline double
+ttx_sim(double t, double F, const uint8_t *text)
+{
+ double t1 = 10.3e-6 - .5 / F;
+ double t2 = t1 + (45 * 8 + 1) / F; /* 45 bytes + raise and fall time */
+ double ph;
+
+ if (t < t1) {
+ return 0.0;
+ } else if (t < t2) {
+ int i, j, n;
+
+ t -= t1;
+ i = (t * F);
+ j = i >> 3;
+ i &= 7;
+
+ if (j == 0)
+ n = ((text[0] * 2) >> i) & 3;
+ else
+ n = (((text[j - 1] >> 7) + text[j] * 2) >> i) & 3;
+
+ if (n == 0) {
+ return 0.0;
+ } else if (n == 3) {
+ return 1.0;
+ } else if ((n ^ i) & 1) {
+ ph = M_PI * 2 * (t - 1 / F) * F / 4;
+ return shape(ph);
+ } else { /* up */
+ ph = M_PI * 2 * (t - 0 / F) * F / 4;
+ return shape(ph);
+ }
+ } else {
+ return 0.0;
+ }
+
+ if (t < t1) {
+ return 0.0;
+ } else if (t < t2) {
+ int i, j, n;
+
+ t -= t1;
+ i = (t * F - .0);
+ j = i >> 3;
+ if (j < 44)
+ n = ((text[j + 1] * 256 + text[j]) >> i) & 3;
+ else
+ n = (text[i] >> i) & 3;
+
+ return shape(ph);
+ }
+}
+
+static int caption_i = 0;
+static const uint8_t caption_text[] = {
+ 0x14, 0x25, 0x14, 0x25, 'L', 'I', 'B', 'Z',
+ 'V', 'B', 'I', ' ', 'C', 'A', 'P', 'T',
+ 'I', 'O', 'N', ' ', 'S', 'I', 'M', 'U',
+ 'L', 'A', 'T', 'I', 'O', 'N', 0x14, 0x2D,
+ 0x14, 0x2D /* even size please, add 0 if neccessary */
+};
+
+static inline int
+odd(int c)
+{
+ int n;
+
+ n = c ^ (c >> 4);
+ n = n ^ (n >> 2);
+ n = n ^ (n >> 1);
+
+ if (!(n & 1))
+ c |= 0x80;
+
+ return c;
+}
+
+static uint8_t *
+ttx_next(void)
+{
+ static uint8_t s1[2][10] = {
+ { 0x02, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 },
+ { 0x02, 0x15, 0x02, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 }
+ };
+ static uint8_t s2[32] = "100\2LIBZVBI\7 00:00:00";
+ static uint8_t s3[40] = " LIBZVBI TELETEXT SIMULATION ";
+ static uint8_t s4[40] = " Page 100 ";
+ static uint8_t s5[10][42] = {
+ { 0x02, 0x2f, 0x97, 0x20, 0x37, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0xb5, 0x20 },
+ { 0xc7, 0x2f, 0x97, 0x0d, 0xb5, 0x04, 0x20, 0x9d, 0x83, 0x8c,
+ 0x08, 0x2a, 0x2a, 0x2a, 0x89, 0x20, 0x20, 0x0d, 0x54, 0x45,
+ 0xd3, 0x54, 0x20, 0xd0, 0xc1, 0xc7, 0x45, 0x8c, 0x20, 0x20,
+ 0x08, 0x2a, 0x2a, 0x2a, 0x89, 0x0d, 0x20, 0x20, 0x1c, 0x97,
+ 0xb5, 0x20 },
+ { 0x02, 0xd0, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xea, 0x20 },
+ { 0xc7, 0xd0, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xb5, 0x20 },
+ { 0x02, 0xc7, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x15, 0x1a, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+ 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+ 0x2c, 0x2c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x97, 0x19,
+ 0xb5, 0x20 },
+ { 0xc7, 0xc7, 0x97, 0x20, 0xb5, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xb5, 0x20 },
+ { 0x02, 0x8c, 0x97, 0x9e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x13,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x16, 0x7f, 0x7f, 0x7f, 0x7f, 0x92,
+ 0x7f, 0x92, 0x7f, 0x7f, 0x15, 0x7f, 0x7f, 0x15, 0x7f, 0x91,
+ 0x91, 0x7f, 0x7f, 0x91, 0x94, 0x7f, 0x94, 0x7f, 0x94, 0x97,
+ 0xb5, 0x20 },
+ { 0xc7, 0x8c, 0x97, 0x9e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x13,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x16, 0x7f, 0x7f, 0x7f, 0x7f, 0x92,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x15, 0x7f, 0x7f, 0x7f, 0x7f, 0x91,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x94, 0x7f, 0x7f, 0x7f, 0x7f, 0x97,
+ 0xb5, 0x20 },
+ { 0x02, 0x9b, 0x97, 0x9e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x13,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x16, 0x7f, 0x7f, 0x7f, 0x7f, 0x92,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x15, 0x7f, 0x7f, 0x7f, 0x7f, 0x91,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x94, 0x7f, 0x7f, 0x7f, 0x7f, 0x97,
+ 0xb5, 0x20 },
+ { 0xc7, 0x9b, 0x97, 0x20, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+ 0xa1, 0x20 }
+ };
+ static uint8_t buf[45];
+ static int row = 0, page = 0;
+ int i;
+
+ buf[0] = 0x55;
+ buf[1] = 0x55;
+ buf[2] = 0x27;
+
+ if (row == 0) {
+ memcpy(buf + 3, s1[page], 10);
+ page ^= 1;
+ for (i = 0; i < 32; i++)
+ buf[13 + i] = odd(s2[i]);
+ } else if (row == 1) {
+ buf[3] = 0x02; buf[4] = 0x02;
+ for (i = 0; i < 40; i++)
+ buf[5 + i] = odd(s3[i]);
+ } else if (row == 2) {
+ buf[3] = 0x02; buf[4] = 0x49;
+ for (i = 0; i < 40; i++)
+ buf[5 + i] = odd(s4[i]);
+ } else {
+ memcpy(buf + 3, s5[row - 3], 42);
+ }
+
+ if (++row >= 13) row = 0;
+
+ return buf;
+}
+
+static void
+read_sim(uint8_t *raw_data, vbi_sliced *sliced_data,
+ int *lines, double *timestamp)
+{
+ uint8_t *buf;
+ double start, inc;
+ int i;
+
+ memset(raw_data, 0, (sim.count[0] + sim.count[1])
+ * sim.bytes_per_line);
+
+ *timestamp = sim_time;
+
+ if (sim.scanning == 525)
+ sim_time += 1001 / 30000.0;
+ else
+ sim_time += 1 / 25.0;
+
+ start = sim.offset / (double) sim.sampling_rate;
+ inc = 1 / (double) sim.sampling_rate;
+
+ if (sim.scanning == 525) {
+ /* Closed Caption */
+ {
+ buf = raw_data + (21 - sim.start[0])
+ * sim.bytes_per_line;
+
+ for (i = 0; i < sim.bytes_per_line; i++)
+ buf[i] = cc_sim(start + i * inc, 15734 * 32,
+ odd(caption_text[caption_i]),
+ odd(caption_text[caption_i + 1]))
+ * AMP + DC;
+
+ if ((caption_i += 2) > sizeof(caption_text))
+ caption_i = 0;
+ }
+
+ /* WSS NTSC-Japan */
+ {
+ const int poly = (1 << 6) + (1 << 1) + 1;
+ int b0 = 1, b1 = 1;
+ int bits = (b0 << 13) + (b1 << 12);
+ int crc, j;
+
+ crc = (((1 << 6) - 1) << (14 + 6)) + (bits << 6);
+
+ for (j = 14 + 6 - 1; j >= 0; j--) {
+ if (crc & ((1 << 6) << j))
+ crc ^= poly << j;
+ }
+
+ bits <<= 6;
+ bits |= crc;
+
+ /* fprintf(stderr, "WSS CPR << %08x\n", bits); */
+
+ buf = raw_data + (20 - sim.start[0])
+ * sim.bytes_per_line;
+
+ for (i = 0; i < sim.bytes_per_line; i++)
+ buf[i] = wss525_sim(start + i * inc,
+ 447443, bits)
+ * AMP + DC;
+ }
+ } else {
+ /* Closed Caption */
+ {
+ buf = raw_data + (22 - sim.start[0])
+ * sim.bytes_per_line;
+
+ for (i = 0; i < sim.bytes_per_line; i++)
+ buf[i] = cc_sim(start + i * inc, 15625 * 32,
+ odd(caption_text[caption_i]),
+ odd(caption_text[caption_i + 1]))
+ * AMP + DC;
+
+ if ((caption_i += 2) > sizeof(caption_text))
+ caption_i = 0;
+ }
+
+ /* WSS PAL */
+ {
+ int g0 = 1, g1 = 2, g2 = 3, g3 = 4;
+ int bits = (g3 << 11) + (g2 << 8) + (g1 << 4) + g0;
+
+ buf = raw_data + (23 - sim.start[0])
+ * sim.bytes_per_line;
+
+ for (i = 0; i < sim.bytes_per_line; i++)
+ buf[i] = wss625_sim(start + i * inc, 15625 * 320,
+ bits) * AMP + DC;
+ }
+
+ /* Teletext */
+ {
+ int line, count;
+ uint8_t *text;
+
+ buf = raw_data;
+
+ for (line = sim.start[0], count = sim.count[0];
+ count > 0; line++, count--, buf += sim.bytes_per_line)
+ if ((line >= 7 && line <= 15)
+ || (line >= 19 && line <= 21)) {
+ text = ttx_next();
+ for (i = 0; i < sim.bytes_per_line; i++) {
+ buf[i] = ttx_sim(start + i * inc,
+ 15625 * 444,
+ text) * AMP + DC;
+ }
+ }
+ for (line = sim.start[1], count = sim.count[1];
+ count > 0; line++, count--, buf += sim.bytes_per_line)
+ if ((line >= 320 && line <= 328)
+ || (line >= 332 && line <= 335)) {
+ text = ttx_next();
+ for (i = 0; i < sim.bytes_per_line; i++) {
+ buf[i] = ttx_sim(start + i * inc,
+ 15625 * 444,
+ text) * AMP + DC;
+ }
+ }
+ }
+ }
+
+ *lines = vbi_raw_decode(&sim, raw_data, sliced_data);
+}
+
+static vbi_raw_decoder *
+init_sim(int scanning, unsigned int services)
+{
+ vbi_raw_decoder_init(&sim);
+
+ sim.scanning = scanning;
+ sim.sampling_format = VBI_PIXFMT_YUV420;
+ sim.sampling_rate = 2 * 13500000;
+ sim.bytes_per_line = 1440;
+ sim.offset = 9.7e-6 * sim.sampling_rate;
+ sim.interlaced = FALSE;
+ sim.synchronous = TRUE;
+
+ if (scanning == 525) {
+ sim.start[0] = 10;
+ sim.count[0] = 21 - 10 + 1;
+ sim.start[1] = 272;
+ sim.count[1] = 285 - 272 + 1;
+ } else if (scanning == 625) {
+ sim.start[0] = 6;
+ sim.count[0] = 23 - 6 + 1;
+ sim.start[1] = 318;
+ sim.count[1] = 335 - 318 + 1;
+ } else
+ assert(!"invalid scanning value");
+
+ sim_time = 0.0;
+
+ vbi_raw_decoder_add_services(&sim, services, 0);
+
+ return &sim;
+}

Privacy Policy