summaryrefslogtreecommitdiff
Diffstat
-rw-r--r--Android.mk4
-rwxr-xr-xntsc_decode/am_vbi.c26
-rw-r--r--src/caption.c656
-rw-r--r--src/cc.h15
-rw-r--r--src/dtvcc.c893
-rw-r--r--src/dtvcc.h45
-rwxr-xr-x[-rw-r--r--]src/event.h26
-rw-r--r--src/exp-gfx.c65
-rwxr-xr-x[-rw-r--r--]src/libzvbi.h20
-rwxr-xr-x[-rw-r--r--]src/vbi.c2
10 files changed, 1393 insertions, 359 deletions
diff --git a/src/caption.c b/src/caption.c
index 90e7a67..82ca1e9 100644
--- a/src/caption.c
+++ b/src/caption.c
@@ -14,8 +14,8 @@
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*/
@@ -35,6 +35,7 @@
#include "tables.h"
#include "vbi.h"
#include <android/log.h>
+#include "am_debug.h"
#define elements(array) (sizeof(array) / sizeof(array[0]))
@@ -79,8 +80,8 @@ static const char *
language[8] = {
"Unknown",
"English",
- "Español",
- "Français",
+ "Español",
+ "Français",
"Deutsch",
"Italiano",
"Other",
@@ -132,7 +133,7 @@ xds_strfu(signed char *d, const uint8_t *s, int len)
return neq;
}
-#define xds_intfu(d, val) (neq |= d ^ (val), d = (val))
+#define xds_intfu(d, val) (neq |= d ^ (val), d = (val))
static void
flush_prog_info(vbi_decoder *vbi, vbi_program_info *pi, vbi_event *e)
@@ -159,17 +160,19 @@ xds_decoder(vbi_decoder *vbi, int _class, int type,
int neq, i;
vbi_event e;
- assert(length > 0 && length <= 32);
+ if ((length <= 0) || (length > 32))
+ return;
+ //assert(length > 0 && length <= 32);
// XXX we have no indication how long the program info applies.
// It will be canceled on channel switch, but who knows
// what the station transmits when the next program starts.
-// (Nothing, possibly.) A timeout seems necessary.
+// (Nothing, possibly.) A timeout seems necessary.
switch (_class) {
case XDS_CURRENT: /* 0 */
case XDS_FUTURE: /* 1 */
- if (!(vbi->event_mask & (VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO))){
+ if (!(vbi->event_mask & (VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO | VBI_EVENT_RATING))){
XDS_SEP_DEBUG("vbi->event_mask & VBI_EVENT_ASPECT | VBI_EVENT_PROG_INFO");
return;
}
@@ -307,9 +310,9 @@ xds_decoder(vbi_decoder *vbi, int _class, int type,
dlsv |= VBI_RATING_V;
if ((buffer[0] & 0x08) == 0) {
- if (r == 0) return;
+ //if (r == 0) return;
auth = VBI_RATING_AUTH_MPAA;
- pi->rating_dlsv = dlsv = 0;
+ pi->rating.dlsv = dlsv = 0;
} else if ((buffer[0] & 0x10) == 0) {
auth = VBI_RATING_AUTH_TV_US;
r = g;
@@ -321,24 +324,22 @@ xds_decoder(vbi_decoder *vbi, int _class, int type,
if ((r = g) > 5) return;
auth = VBI_RATING_AUTH_TV_CA_FR;
}
- pi->rating_dlsv = dlsv = 0;
+ pi->rating.dlsv = dlsv = 0;
} else
return;
- if ((neq = (pi->rating_auth != auth
- || pi->rating_id != r
- || pi->rating_dlsv != dlsv))) {
- pi->rating_auth = auth;
- pi->rating_id = r;
- pi->rating_dlsv = dlsv;
+ if ((neq = (pi->rating.auth != auth
+ || pi->rating.id != r
+ || pi->rating.dlsv != dlsv))) {
+ pi->rating.auth = auth;
+ pi->rating.id = r;
+ pi->rating.dlsv = dlsv;
+ }
+ if (vbi->event_mask & VBI_EVENT_RATING){
+ e.type = VBI_EVENT_RATING;
+ e.ev.prog_info = pi;
+ caption_send_event(vbi, &e);
}
-
- //***************************************zk
- //callback
- //e.type = VBI_EVENT_PROG_INFO;
- //e.ev.prog_info = pi;
- //caption_send_event(vbi, &e);
- //*******************************************finish
break;
}
@@ -490,7 +491,7 @@ xds_decoder(vbi_decoder *vbi, int _class, int type,
}
else if (vbi->cc.info_cycle[_class] & (1 << type)) {
/* Second occurance of this type with same data */
-
+
e.type = VBI_EVENT_PROG_INFO;
e.ev.prog_info = pi;
@@ -502,6 +503,8 @@ xds_decoder(vbi_decoder *vbi, int _class, int type,
break;
case XDS_CHANNEL:
+ n->ts_id = -1;
+
switch (type) {
case 1: /* network name */
if (xds_strfu(n->name, buffer, length)) {
@@ -554,6 +557,20 @@ xds_decoder(vbi_decoder *vbi, int _class, int type,
break;
+ case 4: /* Transmission Signal ID */
+ if (length < 4)
+ return;
+
+ n->ts_id =
+ ((buffer[3] & 15) << 0)
+ |((buffer[2] & 15) << 4)
+ |((buffer[1] & 15) << 8)
+ |((buffer[0] & 15) << 12);
+
+ vbi->network.type = VBI_EVENT_NETWORK;
+ caption_send_event(vbi, &vbi->network);
+ break;
+
default:
break;
}
@@ -733,70 +750,22 @@ itv_separator(vbi_decoder *vbi, struct caption *cc, char c)
#define COLUMNS 34
static void
-render(vbi_page *pg, int row)
+render(cc_channel *ch)
{
vbi_event event;
- if (row < 0 || pg->dirty.roll) {
- /* no particular row or not fetched
- since last roll/clear, redraw all */
- pg->dirty.y0 = 0;
- pg->dirty.y1 = ROWS - 1;
- pg->dirty.roll = 0;
- } else {
- pg->dirty.y0 = MIN(row, pg->dirty.y0);
- pg->dirty.y1 = MAX(row, pg->dirty.y1);
- }
-
- event.type = VBI_EVENT_CAPTION;
- event.ev.caption.pgno = pg->pgno;
-
- caption_send_event(pg->vbi, &event);
-}
-
-static void
-clear(vbi_page *pg)
-{
- vbi_event event;
-
- pg->dirty.y0 = 0;
- pg->dirty.y1 = ROWS - 1;
- pg->dirty.roll = -ROWS;
-
- event.type = VBI_EVENT_CAPTION;
- event.ev.caption.pgno = pg->pgno;
-
- caption_send_event(pg->vbi, &event);
-}
-
-static void
-roll_up(vbi_page *pg, int first_row, int last_row)
-{
- vbi_event event;
-
- if (pg->dirty.roll != 0 || pg->dirty.y0 <= pg->dirty.y1) {
- /* not fetched since last update, redraw all */
- pg->dirty.roll = 0;
- pg->dirty.y0 = MIN(first_row, pg->dirty.y0);
- pg->dirty.y1 = MAX(last_row, pg->dirty.y1);
- } else {
- pg->dirty.roll = -1;
- pg->dirty.y0 = first_row;
- pg->dirty.y1 = last_row;
- }
+ ch->pg[2] = ch->pg[ch->hidden ^ 1];
event.type = VBI_EVENT_CAPTION;
- event.ev.caption.pgno = pg->pgno;
+ event.ev.caption.pgno = ch->pg[0].pgno;
- caption_send_event(pg->vbi, &event);
+ caption_send_event(ch->pg[0].vbi, &event);
}
static inline void
update(cc_channel *ch)
{
- vbi_char *acp = ch->line - ch->pg[0].text + ch->pg[1].text;
-
- memcpy(acp, ch->line, sizeof(*acp) * COLUMNS);
+ ch->update_flag = 1;
}
static void
@@ -807,6 +776,7 @@ word_break(struct caption *cc, cc_channel *ch, int upd)
/*
* Add a leading and trailing space.
*/
+#if 0
if (ch->col > ch->col1) {
vbi_char c = ch->line[ch->col1];
@@ -824,7 +794,7 @@ word_break(struct caption *cc, cc_channel *ch, int upd)
ch->line[ch->col] = c;
}
}
-
+#endif
if (!upd || ch->mode == MODE_POP_ON)
return;
@@ -835,20 +805,74 @@ word_break(struct caption *cc, cc_channel *ch, int upd)
* for double buffering at word granularity.
*
* XXX should not render if space follows space,
- * but force in long words.
+ * but force in long words.
*/
-
update(ch);
- render(ch->pg + 1, ch->row);
+}
+
+static void
+clear_roll(cc_channel *ch)
+{
+ int i;
+
+ for (i = 0; i < ROWS; i ++) {
+ if ((i >= ch->row1) && (i < ch->row1 + ch->roll))
+ continue;
+
+ memset(ch->pg[ch->hidden ^ 1].text + i * COLUMNS, 0, sizeof(vbi_char) * COLUMNS);
+ }
+}
+
+static void
+roll_up (cc_channel *ch, int roll)
+{
+ vbi_char *acp = ch->pg[ch->hidden ^ 1].text;
+
+ memmove(acp, acp + roll * COLUMNS, (ROWS - roll) * COLUMNS * sizeof(vbi_char));
+ memset(acp + (ROWS - roll) * COLUMNS, 0, roll * COLUMNS * sizeof(vbi_char));
+
+ ch->row1 -= roll;
+ ch->row -= roll;
+
+ if (ch->row1 < 0)
+ ch->row1 = 0;
+ if (ch->row < 0)
+ ch->row = 0;
+ clear_roll(ch);
}
static inline void
set_cursor(cc_channel *ch, int col, int row)
{
+ int p;
+ if (row < ch->row1) {
+ ch->row1 = row;
+ if (ch->mode == MODE_ROLL_UP) {
+ clear_roll(ch);
+ update(ch);
+ }
+ } else if (row >= ch->row1 + ch->roll) {
+ ch->row1 = row - ch->roll + 1;
+ if (ch->mode == MODE_ROLL_UP) {
+ clear_roll(ch);
+ update(ch);
+ }
+ }
+
ch->col = ch->col1 = col;
ch->row = row;
- ch->line = ch->pg[ch->hidden].text + row * COLUMNS;
+ p = (ch->mode == MODE_POP_ON) ? ch->hidden : (ch->hidden ^ 1);
+ ch->line = ch->pg[p].text + row * COLUMNS;
+}
+
+static void
+set_char(cc_channel *ch, int col, vbi_char c)
+{
+ if (!ch->pos_flag)
+ return;
+
+ ch->line[col] = c;
}
static void
@@ -857,22 +881,56 @@ put_char(struct caption *cc, cc_channel *ch, vbi_char c)
/* c.foreground = rand() & 7; */
/* c.background = rand() & 7; */
- if (ch->col < COLUMNS - 1)
- ch->line[ch->col++] = c;
- else {
+ if (ch->col < COLUMNS - 1) {
+ set_char(ch, ch->col, c);
+ ch->col ++;
+ } else {
/* line break here? */
-
- ch->line[COLUMNS - 2] = c;
+ set_char(ch, COLUMNS - 2, c);
}
- if ((c.unicode & 0x7F) == 0x20)
- word_break(cc, ch, 1);
+ if (ch->mode == MODE_POP_ON)
+ return;
+
+ update(ch);
}
static inline cc_channel *
-switch_channel(struct caption *cc, cc_channel *ch, int new_chan)
+switch_channel(struct caption *cc, int new_chan)
{
- word_break(cc, ch, 1); // we leave for a number of frames
+ switch (new_chan) {
+ case 0:
+ case 4:
+ cc->curr_chan_f1_d1 = new_chan;
+ break;
+ case 1:
+ case 5:
+ cc->curr_chan_f1_d2 = new_chan;
+ break;
+ case 2:
+ case 6:
+ cc->curr_chan_f2_d1 = new_chan;
+ break;
+ case 3:
+ case 7:
+ cc->curr_chan_f2_d2 = new_chan;
+ break;
+ }
+
+ switch (new_chan) {
+ case 0:
+ case 1:
+ case 4:
+ case 5:
+ cc->curr_chan_f1 = new_chan;
+ break;
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ cc->curr_chan_f2 = new_chan;
+ break;
+ }
return &cc->channel[cc->curr_chan = new_chan];
}
@@ -881,16 +939,8 @@ static void
erase_memory(struct caption *cc, cc_channel *ch, int page)
{
vbi_page *pg = ch->pg + page;
- vbi_char *acp = pg->text;
- vbi_char c = cc->transp_space[ch >= &cc->channel[4]];
- int i;
-
- for (i = 0; i < COLUMNS * ROWS; acp++, i++)
- *acp = c;
- pg->dirty.y0 = 0;
- pg->dirty.y1 = ROWS - 1;
- pg->dirty.roll = ROWS;
+ memset(pg->text, 0, ROWS * COLUMNS * sizeof(vbi_char));
}
static const vbi_color
@@ -913,16 +963,26 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
{
XDS_SEP_DEBUG("caption_command\n");
cc_channel *ch;
+ vbi_char *c;
int chan, col, i;
int last_row;
+ //chan = (cc->curr_chan & 4) + field2 * 2 + ((c1 >> 3) & 1);
+
+ if (field2) {
+ chan = (c1 & 8) ? cc->curr_chan_f2_d2 : cc->curr_chan_f2_d1;
+ } else {
+ chan = (c1 & 8) ? cc->curr_chan_f1_d2 : cc->curr_chan_f1_d1;
+ }
+
+ switch_channel(cc, chan);
- chan = (cc->curr_chan & 4) + field2 * 2 + ((c1 >> 3) & 1);
ch = &cc->channel[chan];
c1 &= 7;
if (c2 >= 0x40) { /* Preamble Address Codes 001 crrr 1ri xxxu */
int row = row_mapping[(c1 << 1) + ((c2 >> 5) & 1)];
+ int old_row = ch->row;
if (row < 0 || !ch->mode)
return;
@@ -936,21 +996,22 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
if (ch->mode == MODE_ROLL_UP) {
int row1 = row - ch->roll + 1;
+ int roll;
if (row1 < 0)
row1 = 0;
- if (row1 != ch->row1) {
- ch->row1 = row1;
- erase_memory(cc, ch, ch->hidden);
- erase_memory(cc, ch, ch->hidden ^ 1);
+ roll = ch->row1 - row1;
+ if (roll > 0) {
+ roll_up(ch, ch->row1 - row1);
+ update(ch);
}
+ }
- set_cursor(ch, 1, ch->row1 + ch->roll - 1);
- } else
- set_cursor(ch, 1, row);
+ set_cursor(ch, 1, row);
if (c2 & 0x10) {
+ /*
col = ch->col;
for (i = (c2 & 14) * 2; i > 0 && col < COLUMNS - 1; i--)
@@ -958,9 +1019,14 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
if (col > ch->col)
ch->col = ch->col1 = col;
+ */
- ch->attr.italic = FALSE;
- ch->attr.foreground = VBI_WHITE;
+ ch->col = (c2 & 14) * 2 + 1;
+
+ if (old_row != ch->row) {
+ ch->attr.italic = FALSE;
+ ch->attr.foreground = VBI_WHITE;
+ }
} else {
// not verified
c2 = (c2 >> 1) & 7;
@@ -978,10 +1044,24 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
}
switch (c1) {
- case 0: /* Optional Attributes 001 c000 010 xxxt */
-// not verified
+ case 0:
+ /* Optional Attributes 001 c000 010 xxxt */
ch->attr.opacity = (c2 & 1) ? VBI_SEMI_TRANSPARENT : VBI_OPAQUE;
ch->attr.background = palette_mapping[(c2 >> 1) & 7];
+
+ for (i = 0; i < 2; i ++) {
+ int col = ch->col - i;
+
+ if ((col > 0) && (col < COLUMNS - 1)) {
+ vbi_char c = ch->line[col];
+
+ if (c.unicode == 0x20) {
+ c.background = ch->attr.background;
+ c.opacity = ch->attr.opacity;
+ set_char(ch, col, c);
+ }
+ }
+ }
return;
case 1:
@@ -991,11 +1071,12 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
if (c2 == 9) { // "transparent space"
if (ch->col < COLUMNS - 1) {
- ch->line[ch->col++] = cc->transp_space[chan >> 2];
+ set_char(ch, ch->col++, cc->transp_space[chan >> 2]);
ch->col1 = ch->col;
- } else
- ch->line[COLUMNS - 2] = cc->transp_space[chan >> 2];
- // XXX boxed logic?
+ } else {
+ set_char(ch, COLUMNS - 2, cc->transp_space[chan >> 2]);
+ }
+
} else {
vbi_char c = ch->attr;
@@ -1006,6 +1087,14 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
}
} else { /* Midrow Codes 001 c001 010 xxxu */
// not verified
+ vbi_char c = ch->attr;
+
+ c.flash = FALSE;
+ c.underline = FALSE;
+ c.unicode = ' ';
+
+ put_char(cc, ch, c);
+
ch->attr.flash = FALSE;
ch->attr.underline = c2 & 1;
@@ -1016,7 +1105,6 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
ch->attr.foreground = palette_mapping[c2];
} else {
ch->attr.italic = TRUE;
- ch->attr.foreground = VBI_WHITE;
}
}
@@ -1025,6 +1113,19 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
case 2: /* Optional Extended Characters 001 c01f 01x xxxx */
case 3:
/* Send specs to the maintainer of this code */
+ {
+ vbi_char c;
+
+ c = ch->attr;
+ c.unicode = vbi_caption_unicode((c1 << 8) | c2 | 0x1000, 0);
+
+ if (c.unicode) {
+ if (ch->col > 1)
+ ch->col --;
+
+ put_char(cc, ch, c);
+ }
+ }
return;
case 4: /* Misc Control Codes 001 c10f 010 xxxx */
@@ -1033,12 +1134,9 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
switch (c2 & 15) {
case 0: /* Resume Caption Loading 001 c10f 010 0000 */
- ch = switch_channel(cc, ch, chan & 3);
-
+ ch = switch_channel(cc, chan & 3);
+ ch->pos_flag = 1;
ch->mode = MODE_POP_ON;
-
-// no? erase_memory(cc, ch);
-
return;
/* case 4: reserved */
@@ -1049,51 +1147,56 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
{
int roll = (c2 & 7) - 3;
- ch = switch_channel(cc, ch, chan & 3);
+ ch = switch_channel(cc, chan & 3);
+ ch->pos_flag = 1;
if (ch->mode == MODE_ROLL_UP && ch->roll == roll)
return;
- erase_memory(cc, ch, ch->hidden);
- erase_memory(cc, ch, ch->hidden ^ 1);
-
ch->mode = MODE_ROLL_UP;
ch->roll = roll;
- set_cursor(ch, 1, 14);
-
- ch->row1 = 14 - roll + 1;
-
+ ch->row1 = ch->row - roll + 1;
+ if (ch->row1 < 0)
+ ch->row1 = 0;
return;
}
case 9: /* Resume Direct Captioning 001 c10f 010 1001 */
// not verified
- ch = switch_channel(cc, ch, chan & 3);
+ ch = switch_channel(cc, chan & 3);
ch->mode = MODE_PAINT_ON;
+ ch->pos_flag = 1;
return;
case 10: /* Text Restart 001 c10f 010 1010 */
// not verified
- ch = switch_channel(cc, ch, chan | 4);
+ erase_memory(cc, ch, ch->hidden);
+ erase_memory(cc, ch, ch->hidden ^ 1);
+ ch = switch_channel(cc, chan | 4);
+ ch->pos_flag = 1;
set_cursor(ch, 1, 0);
+ erase_memory(cc, ch, ch->hidden);
+ erase_memory(cc, ch, ch->hidden ^ 1);
return;
case 11: /* Resume Text Display 001 c10f 010 1011 */
- ch = switch_channel(cc, ch, chan | 4);
+ ch = switch_channel(cc, chan | 4);
+ ch->pos_flag = 1;
return;
case 15: /* End Of Caption 001 c10f 010 1111 */
- ch = switch_channel(cc, ch, chan & 3);
+ ch = switch_channel(cc, chan & 3);
+ ch->pos_flag = 1;
+
ch->mode = MODE_POP_ON;
word_break(cc, ch, 1);
ch->hidden ^= 1;
- render(ch->pg + (ch->hidden ^ 1), -1 /* ! */);
-
- erase_memory(cc, ch, ch->hidden); // yes?
+ //erase_memory(cc, ch, ch->hidden); // yes?
+ update(ch);
/*
* A Preamble Address Code should follow,
@@ -1112,11 +1215,38 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
case 1: /* Backspace 001 c10f 010 0001 */
// not verified
- if (ch->mode && ch->col > 1) {
- ch->line[--ch->col] = cc->transp_space[chan >> 2];
+ if (ch->mode) {
+ if (ch->col > 1) {
+ if (ch->line[ch->col - 1].unicode == 0)
+ break;
+ ch->col --;
+ } else if (ch->row > 0) {
+ vbi_char *acp;
+ int p = (ch->mode == MODE_POP_ON) ? ch->hidden : (ch->hidden ^ 1);
+
+ ch->row --;
+ ch->line = ch->pg[p].text + ch->row * COLUMNS;
+ ch->col1 = 1;
+ ch->col = COLUMNS - 1;
+ acp = ch->line + COLUMNS - 1;
+
+ while (ch->col > 1) {
+ if (acp->unicode != 0)
+ break;
+
+ acp --;
+ ch->col --;
+ }
+ } else {
+ break;
+ }
+
+ memset(&ch->line[ch->col], 0, sizeof(vbi_char));
if (ch->col < ch->col1)
ch->col1 = ch->col;
+
+ update(ch);
}
return;
@@ -1125,37 +1255,27 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
if (ch == cc->channel + 5)
itv_separator(vbi, cc, 0);
- if (!ch->mode)
- return;
-
- last_row = ch->row1 + ch->roll - 1;
-
- if (last_row > ROWS - 1)
- last_row = ROWS - 1;
-
- if (ch->row < last_row) {
- word_break(cc, ch, 1);
- set_cursor(ch, 1, ch->row + 1);
- } else {
- vbi_char *acp = &ch->pg[ch->hidden ^ (ch->mode != MODE_POP_ON)]
- .text[ch->row1 * COLUMNS];
-
- word_break(cc, ch, 1);
+ if ((ch->row >= ROWS - 1) && ((ch->mode == MODE_ROLL_UP) || (ch->mode == MODE_TEXT))) {
+ roll_up(ch, 1);
+ set_cursor(ch, 1, ROWS - 1);
update(ch);
-
- memmove(acp, acp + COLUMNS, sizeof(*acp) * (ch->roll - 1) * COLUMNS);
-
- for (i = 0; i <= COLUMNS; i++)
- ch->line[i] = cc->transp_space[chan >> 2];
-
- if (ch->mode != MODE_POP_ON) {
+ } else if (ch->row >= ROWS - 1) {
+ set_cursor(ch, 1, ROWS - 1);
+ if (ch->mode != MODE_POP_ON)
+ update(ch);
+ } else {
+ set_cursor(ch, 1, ch->row + 1);
+ if (ch->mode != MODE_POP_ON)
update(ch);
- roll_up(ch->pg + (ch->hidden ^ 1), ch->row1, last_row);
- }
-
- ch->col1 = ch->col = 1;
}
+ ch->attr.underline = FALSE;
+ ch->attr.background = VBI_BLACK;
+ ch->attr.opacity = VBI_OPAQUE;
+ ch->attr.flash = FALSE;
+ ch->attr.italic = FALSE;
+ ch->attr.foreground = VBI_WHITE;
+
return;
case 4: /* Delete To End Of Row 001 c10f 010 0100 */
@@ -1163,33 +1283,26 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
if (!ch->mode)
return;
- for (i = ch->col; i <= COLUMNS - 1; i++)
- ch->line[i] = cc->transp_space[chan >> 2];
+ for (i = ch->col; i <= COLUMNS - 1; i++) {
+ memset(&ch->line[i], 0, sizeof(vbi_char));
+ }
word_break(cc, ch, 0);
if (ch->mode != MODE_POP_ON) {
update(ch);
- render(ch->pg + (ch->hidden ^ 1), ch->row);
}
return;
case 12: /* Erase Displayed Memory 001 c10f 010 1100 */
-// s1, s4: EDM always before EOC
- if (ch->mode != MODE_POP_ON)
- erase_memory(cc, ch, ch->hidden);
-
- erase_memory(cc, ch, ch->hidden ^ 1);
- clear(ch->pg + (ch->hidden ^ 1));
-
+ if (chan < 4) {
+ erase_memory(cc, ch, ch->hidden ^ 1);
+ update(ch);
+ }
return;
-
case 14: /* Erase Non-Displayed Memory 001 c10f 010 1110 */
-// not verified
- if (ch->mode == MODE_POP_ON)
- erase_memory(cc, ch, ch->hidden);
-
+ erase_memory(cc, ch, ch->hidden);
return;
}
@@ -1204,13 +1317,18 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
switch (c2) {
case 0x21 ... 0x23: /* Misc Control Codes, Tabs 001 c111 010 00xx */
// not verified
+ /*
col = ch->col;
for (i = c2 & 3; i > 0 && col < COLUMNS - 1; i--)
ch->line[col++] = cc->transp_space[chan >> 2];
if (col > ch->col)
- ch->col = ch->col1 = col;
+ ch->col = ch->col1 = col;*/
+
+ ch->col += (c2 & 3);
+ if (ch->col >= COLUMNS)
+ ch->col = COLUMNS - 1;
return;
@@ -1241,12 +1359,29 @@ caption_command(vbi_decoder *vbi, struct caption *cc,
}
}
+static void
+update_display (vbi_decoder *vbi)
+{
+ struct caption *cc = &vbi->cc;
+ int i;
+
+ for (i=0; i<8; i++)
+ {
+ cc_channel *ch = &cc->channel[i];
+
+ if (ch->update_flag == 1) {
+ render(ch);
+ ch->update_flag = 0;
+ }
+ }
+}
+
/**
* @internal
* @param vbi Initialized vbi decoding context.
* @param line ITU-R line number this data originated from.
* @param buf Two bytes.
- *
+ *
* Decode two bytes of Closed Caption data (Caption, XDS, ITV),
* updating the decoder state accordingly. May send events.
*/
@@ -1257,8 +1392,19 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
struct caption *cc = &vbi->cc;
char c1 = buf[0] & 0x7F;
int field2 = 1, i;
+ int flash;
+ struct timespec now;
pthread_mutex_lock(&cc->mutex);
+ //AM_DEBUG(1, "vbi_data: line: %d %x %x", line, buf[0], buf[1]);
+
+ if (line == 21) {
+ cc->curr_chan = cc->curr_chan_f1;
+ memcpy(cc->last, cc->last_f1, sizeof(cc->last));
+ } else {
+ cc->curr_chan = cc->curr_chan_f2;
+ memcpy(cc->last, cc->last_f2, sizeof(cc->last));
+ }
switch (line) {
case 21: /* NTSC */
@@ -1284,6 +1430,13 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
cc->xds = (c1 != XDS_END);
goto finish;
} else if (c1 <= 0x1F) {
+ xds_sub_packet *sp = cc->curr_sp;
+ unsigned int class, type;
+ if (sp) {
+ class = (sp - cc->sub_packet[0]) / elements(cc->sub_packet[0]);
+ type = (sp - cc->sub_packet[0]) % elements(cc->sub_packet[0]);
+ xds_decoder(vbi, class, type, sp->buffer, sp->count - 2);
+ }
cc->xds = FALSE;
} else if (cc->xds) {
xds_separator(vbi, buf);
@@ -1293,7 +1446,7 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
xds_separator(vbi, buf);
goto finish;
}
-
+
break;
default:
@@ -1302,9 +1455,13 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
//if ( (buf[0]) < 0) { //vbi_unpar8 (buf[0]) < 0
if ( vbi_unpar8 (buf[0]) < 0) { //
+#if 0
c1 = 127;
buf[0] = c1; /* traditional 'bad' glyph, ccfont has */
buf[1] = c1; /* room, design a special glyph? */
+#else
+ goto finish;
+#endif
}
CC_DUMP(
@@ -1318,15 +1475,15 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
vbi_char c;
case 0x01 ... 0x0F:
- if (!field2)
+ /*if (!field2)*/
cc->last[0] = 0;
break; /* XDS field 1?? */
case 0x10 ... 0x1F:
//if ( (buf[1]) >= 0) { // vbi_unpar8 (buf[1])
- if ( vbi_unpar8 (buf[1]) >= 0) {
- if (!field2
- && buf[0] == cc->last[0]
+ if ( vbi_unpar8 (buf[1]) >= 0) {
+ if (/*!field2
+ &&*/ buf[0] == cc->last[0]
&& buf[1] == cc->last[1]) {
/* cmd repetition F1: already executed */
cc->last[0] = 0; /* one rep */
@@ -1335,11 +1492,11 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
caption_command(vbi, cc, c1, buf[1] & 0x7F, field2);
- if (!field2) {
+ /*if (!field2)*/ {
cc->last[0] = buf[0];
cc->last[1] = buf[1];
}
- } else if (!field2)
+ } else /*if (!field2)*/
cc->last[0] = 0;
break;
@@ -1350,6 +1507,10 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
putchar(_vbi_to_ascii (buf[1]));
fflush(stdout);
)
+#if 0
+ AM_DEBUG(1, "text value: %c %c %x %x", _vbi_to_ascii(buf[0]),
+ _vbi_to_ascii(buf[1]), buf[0], buf[1]);
+#endif
ch = &cc->channel[(cc->curr_chan & 5) + field2 * 2];
@@ -1363,7 +1524,7 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
break;
}
- if (!field2)
+ /*if (!field2)*/
cc->last[0] = 0;
ch->nul_ct = 0;
@@ -1377,7 +1538,7 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
for (i = 0; i < 2; i++) {
//char ci = (buf[i]) & 0x7F; /* 127 if bad */ //vbi_unpar8 (buf[i])
- char ci = vbi_unpar8 (buf[i]) & 0x7F; /* 127 if bad */
+ char ci = vbi_unpar8 (buf[i]) & 0x7F; /* 127 if bad */
if (ci <= 0x1F) /* 0x00 no char, 0x01 ... 0x1F invalid */
continue;
@@ -1390,14 +1551,51 @@ vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf)
}
}
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ flash = (now.tv_nsec / 250000000) & 1;
+
+ if (flash != vbi->cc.flash_state) {
+ int i, j;
+
+ vbi->cc.flash_state = flash;
+
+ for (i = 0; i < 8; i++)
+ {
+ cc_channel *ch;
+ vbi_page *spg;
+
+ ch = &vbi->cc.channel[i];
+ spg = ch->pg + 2;
+ for (j = 0; j < ROWS * COLUMNS; j++)
+ {
+ if (spg->text[j].flash)
+ {
+ update(ch);
+ break;
+ }
+ }
+ }
+ }
+
+ update_display(vbi);
+
+ if (line == 21) {
+ //cc->curr_chan_f1 = cc->curr_chan;
+ memcpy(cc->last_f1, cc->last, sizeof(cc->last));
+ } else {
+ //cc->curr_chan_f2 = cc->curr_chan;
+ memcpy(cc->last_f2, cc->last, sizeof(cc->last));
+ }
+
finish:
pthread_mutex_unlock(&cc->mutex);
}
/**
* @internal
- * @param vbi Initialized vbi decoding context.
- *
+ * @param vbi Initialized vbi decoding context.
+ *
* This function must be called after desynchronisation
* has been detected (i. e. vbi data has been lost)
* to reset the Closed Caption decoder.
@@ -1422,7 +1620,7 @@ vbi_caption_desync(vbi_decoder *vbi)
/**
* @internal
* @param vbi Initialized vbi decoding context.
- *
+ *
* This function must be called after a channel switch,
* to reset the Closed Caption decoder.
*/
@@ -1439,8 +1637,8 @@ vbi_caption_channel_switched(vbi_decoder *vbi)
if (i < 4) {
ch->mode = MODE_NONE; // MODE_ROLL_UP;
ch->row = ROWS - 1;
- ch->row1 = ROWS - 3;
- ch->roll = 3;
+ ch->row1 = ROWS - 4;
+ ch->roll = 4;
} else {
ch->mode = MODE_TEXT;
ch->row1 = ch->row = 0;
@@ -1479,7 +1677,7 @@ vbi_caption_channel_switched(vbi_decoder *vbi)
static vbi_rgba
default_color_map[8] = {
VBI_RGBA(0x00, 0x00, 0x00), VBI_RGBA(0xFF, 0x00, 0x00),
- VBI_RGBA(0x00, 0xFF, 0x00), VBI_RGBA(0xFF, 0xFF, 0x00),
+ VBI_RGBA(0x00, 0xFF, 0x00), VBI_RGBA(0xFF, 0xFF, 0x00),
VBI_RGBA(0x00, 0x00, 0xFF), VBI_RGBA(0xFF, 0x00, 0xFF),
VBI_RGBA(0x00, 0xFF, 0xFF), VBI_RGBA(0xFF, 0xFF, 0xFF)
};
@@ -1487,7 +1685,7 @@ default_color_map[8] = {
/**
* @internal
* @param vbi Initialized vbi decoding context.
- *
+ *
* After the client changed text brightness and saturation
* this function adjusts the Closed Caption color palette.
*/
@@ -1508,7 +1706,7 @@ vbi_caption_color_level(vbi_decoder *vbi)
/**
* @internal
* @param vbi VBI decoding context.
- *
+ *
* This function is called during @a vbi destruction
* to destroy Closed Caption subset of @a vbi.
*/
@@ -1521,7 +1719,7 @@ vbi_caption_destroy(vbi_decoder *vbi)
/**
* @internal
* @param vbi VBI decoding context.
- *
+ *
* This function is called during @a vbi initialization
* to initialize the Closed Caption subset of @a vbi.
*/
@@ -1534,6 +1732,13 @@ vbi_caption_init(vbi_decoder *vbi)
memset(cc, 0, sizeof(struct caption));
+ cc->curr_chan_f1 = 0;
+ cc->curr_chan_f2 = 2;
+ cc->curr_chan_f1_d1 = 0;
+ cc->curr_chan_f1_d2 = 1;
+ cc->curr_chan_f2_d1 = 2;
+ cc->curr_chan_f2_d2 = 3;
+
pthread_mutex_init(&cc->mutex, NULL);
for (i = 0; i < 9; i++) {
@@ -1554,6 +1759,7 @@ vbi_caption_init(vbi_decoder *vbi)
ch->pg[0].font[1] = vbi_font_descriptors;
memcpy(&ch->pg[1], &ch->pg[0], sizeof(ch->pg[1]));
+ memcpy(&ch->pg[2], &ch->pg[0], sizeof(ch->pg[2]));
}
for (i = 0; i < 2; i++) {
@@ -1577,7 +1783,7 @@ vbi_caption_init(vbi_decoder *vbi)
* @param reset @c TRUE resets the vbi_page dirty fields in cache after
* fetching. Pass @c FALSE only if you plan to call this function again
* to update other displays.
- *
+ *
* Fetches a Closed Caption page designated by @a pgno from the cache,
* formats and stores it in @a pg. CC pages are transmitted basically in
* two modes: at once and character by character ("roll-up" mode).
@@ -1587,11 +1793,11 @@ vbi_caption_init(vbi_decoder *vbi)
* (in case of "roll-up" mode that is with each new word received)
* and the vbi_page->dirty fields will mark the lines actually in
* need of updates, to speed up rendering.
- *
+ *
* Although safe to do, this function is not supposed to be
* called from an event handler, since rendering may block decoding
* for extended periods of time.
- *
+ *
* @return
* @c FALSE if some error occured.
*/
@@ -1608,7 +1814,7 @@ vbi_fetch_cc_page(vbi_decoder *vbi, vbi_page *pg, vbi_pgno pgno, vbi_bool reset)
pthread_mutex_lock(&vbi->cc.mutex);
- spg = ch->pg + (ch->hidden ^ 1);
+ spg = ch->pg + 2;
memcpy(pg, spg, sizeof(*pg)); /* shortcut? */
@@ -1621,6 +1827,44 @@ vbi_fetch_cc_page(vbi_decoder *vbi, vbi_page *pg, vbi_pgno pgno, vbi_bool reset)
return 1;
}
+void vbi_refresh_cc(vbi_decoder *vbi)
+{
+ cc_channel *ch;
+ vbi_page *spg;
+ int i, j;
+ vbi_event event;
+ struct timespec now;
+ int flash;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ flash = (now.tv_nsec / 250000000) & 1;
+
+ pthread_mutex_lock(&vbi->cc.mutex);
+
+ if (flash != vbi->cc.flash_state) {
+ vbi->cc.flash_state = flash;
+
+ for (i = 0; i < 8; i++)
+ {
+ ch = &vbi->cc.channel[i];
+ spg = ch->pg + 2;
+ for (j = 0; j < ROWS * COLUMNS; j++)
+ {
+ if (spg->text[j].flash)
+ {
+ update(ch);
+ break;
+ }
+ }
+ }
+
+ update_display(vbi);
+ }
+
+ pthread_mutex_unlock(&vbi->cc.mutex);
+}
+
/*
Local variables:
c-set-style: K&R