summaryrefslogtreecommitdiff
authorTellen Yu <tellen.yu@amlogic.com>2018-01-10 07:26:31 (GMT)
committer Tellen Yu <tellen.yu@amlogic.com>2018-01-11 06:15:03 (GMT)
commit6512b877572c84b142484efabb67a7273a989a76 (patch)
tree4af4b5a702ac9deb496d646e5861cb2c9699094f
parentfe4b12da045c4e647db7c15729a51ba4f4aeeb88 (diff)
parent058e5138281aac1acc6e56dba9b7aed6a17be0c1 (diff)
downloadlibzvbi-6512b877572c84b142484efabb67a7273a989a76.zip
libzvbi-6512b877572c84b142484efabb67a7273a989a76.tar.gz
libzvbi-6512b877572c84b142484efabb67a7273a989a76.tar.bz2
Merge remote-tracking branch 'remotes/amlogic/ics-amlogic' into HEAD
Change-Id: Ic06a6c357a1a958cfd5d76001b7f61eb47439e4b
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/Android.mk b/Android.mk
index 9caaf2d..0493a45 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,9 +17,11 @@ endif
LOCAL_ARM_MODE := arm
LOCAL_C_INCLUDES := external/icu4c/common
+LOCAL_C_INCLUDES := vendor/amlogic/dvb/include/am_adp
+#LOCAL_C_INCLUDES := external/dvb/include/am_adp
LOCAL_C_INCLUDES += external/icu/icu4c/source/common
-LOCAL_SHARED_LIBRARIES += libicuuc liblog
+LOCAL_SHARED_LIBRARIES += libicuuc liblog libam_adp
LOCAL_PRELINK_MODULE := false
diff --git a/ntsc_decode/am_vbi.c b/ntsc_decode/am_vbi.c
index 85d82fb..3bb8411 100755
--- a/ntsc_decode/am_vbi.c
+++ b/ntsc_decode/am_vbi.c
@@ -205,7 +205,7 @@ static void vbi_xds_handler (vbi_event * ev, void * user_data)
* For details STFW for "v-chip"
* If unknown rating_auth == VBI_RATING_NONE
*/
- if(!(prog_info->rating_auth == VBI_RATING_AUTH_NONE))
+ if(!(prog_info->rating.auth == VBI_RATING_AUTH_NONE))
{
xds_program = VBI_XDS_PROGRAM_RATING;
AM_DEBUG("xds*********VBI_XDS_PROGRAM_RATING \n");
@@ -244,30 +244,30 @@ static void vbi_xds_handler (vbi_event * ev, void * user_data)
}
- if(prog_info->rating_auth != VBI_RATING_AUTH_NONE)
+ if(prog_info->rating.auth != VBI_RATING_AUTH_NONE)
{
- AM_DEBUG("xds**********prog_info->rating_auth = %d\n",prog_info->rating_auth );
+ AM_DEBUG("xds**********prog_info->rating_auth = %d\n",prog_info->rating.auth );
- if(prog_info->rating_auth == VBI_RATING_AUTH_MPAA)
+ if(prog_info->rating.auth == VBI_RATING_AUTH_MPAA)
AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_MPAA\n");
- if(prog_info->rating_auth == VBI_RATING_AUTH_TV_US)
+ if(prog_info->rating.auth == VBI_RATING_AUTH_TV_US)
AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_TV_US\n");
- if(prog_info->rating_auth == VBI_RATING_AUTH_TV_CA_EN)
+ if(prog_info->rating.auth == VBI_RATING_AUTH_TV_CA_EN)
AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_TV_CA_EN\n");
- if(prog_info->rating_auth == VBI_RATING_AUTH_TV_CA_FR)
+ if(prog_info->rating.auth == VBI_RATING_AUTH_TV_CA_FR)
AM_DEBUG("xds**********result*******************VBI_RATING_AUTH_TV_CA_FR\n");
- if(prog_info->rating_auth == VBI_RATING_AUTH_NONE)
+ if(prog_info->rating.auth == VBI_RATING_AUTH_NONE)
AM_DEBUG("result*******************VBI_RATING_AUTH_NONE\n");
- if (prog_info->rating_dlsv == VBI_RATING_D)
+ if (prog_info->rating.dlsv == VBI_RATING_D)
AM_DEBUG("xds**********result*******************VBI_RATING_D\n");
- if (prog_info->rating_dlsv == VBI_RATING_L)
+ if (prog_info->rating.dlsv == VBI_RATING_L)
AM_DEBUG("xds**********result*******************VBI_RATING_L\n");
- if (prog_info->rating_dlsv == VBI_RATING_S)
+ if (prog_info->rating.dlsv == VBI_RATING_S)
AM_DEBUG("xds**********result*******************VBI_RATING_S\n");
- if (prog_info->rating_dlsv == VBI_RATING_V)
+ if (prog_info->rating.dlsv == VBI_RATING_V)
AM_DEBUG("xds**********result*******************VBI_RATING_V\n");
- AM_DEBUG("xds**********result*******************prog_info->rating_id = %d\n",prog_info->rating_id );
+ AM_DEBUG("xds**********result*******************prog_info->rating_id = %d\n",prog_info->rating.id );
}
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
diff --git a/src/cc.h b/src/cc.h
index 2267b16..03dd8a3 100644
--- a/src/cc.h
+++ b/src/cc.h
@@ -54,6 +54,8 @@ typedef struct {
int col, col1;
int row, row1;
int roll;
+ int update_flag;
+ int pos_flag;
int nul_ct; // XXX should be 'silence count'
double time;
@@ -63,15 +65,25 @@ typedef struct {
vbi_char * line;
int hidden;
- vbi_page pg[2];
+ vbi_page pg[3];
+ int update;
} cc_channel;
struct caption {
pthread_mutex_t mutex;
uint8_t last[2]; /* field 1, cc command repetition */
+ uint8_t last_f1[2];
+ uint8_t last_f2[2];
int curr_chan;
+ int curr_chan_f1;
+ int curr_chan_f2;
+ int curr_chan_f1_d1;
+ int curr_chan_f1_d2;
+ int curr_chan_f2_d1;
+ int curr_chan_f2_d2;
+
vbi_char transp_space[2]; /* caption, text mode */
cc_channel channel[9]; /* caption 1-4, text 1-4, garbage */
@@ -83,6 +95,7 @@ struct caption {
int itv_count;
int info_cycle[2];
+ int flash_state;
};
/* Public */
diff --git a/src/dtvcc.c b/src/dtvcc.c
index bb12255..33c65b8 100644
--- a/src/dtvcc.c
+++ b/src/dtvcc.c
@@ -33,7 +33,7 @@
#include "libzvbi.h"
#include "dtvcc.h"
-#include <android/log.h>
+#include "am_debug.h"
#define elements(array) (sizeof(array) / sizeof(array[0]))
@@ -51,7 +51,6 @@
#define N_ELEMENTS(array) (sizeof (array) / sizeof ((array)[0]))
#define CLEAR(var) memset (&(var), 0, sizeof (var))
-
/* FIXME __typeof__ is a GCC extension. */
#undef SWAP
#define SWAP(x, y) \
@@ -84,6 +83,10 @@ do { \
_member)) : (_type *) 0; \
})
+#define VBI_RGBA(r, g, b) \
+ ((((r) & 0xFF) << 0) | (((g) & 0xFF) << 8) \
+ | (((b) & 0xFF) << 16) | (0xFF << 24))
+
/* These should be defined in inttypes.h. */
#ifndef PRId64
# define PRId64 "lld"
@@ -99,8 +102,8 @@ extern void
vbi_transp_colormap(vbi_decoder *vbi, vbi_rgba *d, vbi_rgba *s, int entries);
extern void
vbi_send_event(vbi_decoder *vbi, vbi_event *ev);
-extern void
-vbi_decode_caption(vbi_decoder *vbi, int line, uint8_t *buf);
+static void
+dtvcc_get_visible_windows(struct dtvcc_service *ds, int *cnt, struct dtvcc_window **windows);
/* EIA 608-B decoder. */
@@ -2068,7 +2071,7 @@ static int webtv_check(struct caption_recorder *cr, char * buf,int len)
}
sprintf(temp,"%04X\n",(int)~sum&0xffff);
buf++;
- if(!strncmp(buf,temp,4))
+ if (!strncmp(buf,temp,4))
{
buf[5]=0;
if (cr->cur_ch[cr->field] >= 0 && cr->cc_fp[cr->cur_ch[cr->field]]) {
@@ -2143,6 +2146,7 @@ dtvcc_g2 [96] = {
0x2019, /* 0x1032 Right single quotation mark */
0x201C, /* 0x1033 Left double quotation mark */
0x201D, /* 0x1034 Right double quotation mark */
+ 0x2022,
0,
0,
0,
@@ -2228,7 +2232,7 @@ dtvcc_map_color(dtvcc_color c)
return ret;
}
-static unsigned int
+unsigned int
dtvcc_unicode (unsigned int c)
{
if (unlikely (0 == (c & 0x60))) {
@@ -2236,7 +2240,9 @@ dtvcc_unicode (unsigned int c)
return 0;
} else if (likely (c < 0x100)) {
/* G0, G1 */
- if (unlikely (0x7F == c))
+ if (unlikely (0xAD == c))
+ return 0x2D;
+ else if (unlikely (0x7F == c))
return 0x266A; /* music note */
else
return c;
@@ -2249,7 +2255,7 @@ dtvcc_unicode (unsigned int c)
/* We map all G2/G3 characters which are not
representable in Unicode to private code U+E900
... U+E9FF. */
- return 0xE9A0; /* caption icon */
+ return 0xf101; /* caption icon */
}
return 0;
@@ -2258,8 +2264,68 @@ dtvcc_unicode (unsigned int c)
static void
dtvcc_render(struct dtvcc_decoder * dc, struct dtvcc_service * ds)
{
+#if 0
vbi_event event;
struct tvcc_decoder *td = PARENT(dc, struct tvcc_decoder, dtvcc);
+ struct dtvcc_window *win[8];
+ int i, cnt;
+
+ //printf("render check\n");
+
+ cnt = 8;
+ dtvcc_get_visible_windows(ds, &cnt, win);
+ //if (!cnt)
+ // return;
+
+ if (cnt != ds->old_win_cnt) {
+ //printf("cnt changed\n");
+ goto changed;
+ }
+
+ for (i = 0; i < cnt; i ++) {
+ struct dtvcc_window *w1 = win[i];
+ struct dtvcc_window *w2 = &ds->old_window[i];
+
+ if (memcmp(w1->buffer, w2->buffer, sizeof(w1->buffer))) {
+ //printf("text changed\n");
+ goto changed;
+ }
+
+ if (memcmp(&w1->style, &w2->style, sizeof(w1->style))) {
+ //printf("style changed\n");
+ goto changed;
+ }
+
+ if (memcmp(&w1->curr_pen, &w2->curr_pen, sizeof(w1->curr_pen))) {
+ //printf("pen changed\n");
+ goto changed;
+ }
+
+ if (w1->row_count != w2->row_count) {
+ //printf("row changed\n");
+ goto changed;
+ }
+
+ if (w1->column_count != w2->column_count) {
+ //printf("col changed\n");
+ goto changed;
+ }
+
+ if (w1->visible != w2->visible) {
+ //printf("vis changed\n");
+ goto changed;
+ }
+ }
+
+ return;
+changed:
+ for (i = 0; i < cnt; i ++) {
+ ds->old_window[i] = *win[i];
+ }
+ ds->old_win_cnt = cnt;
+#endif
+ ds->update = 1;
+#if 0
event.type = VBI_EVENT_CAPTION;
event.ev.caption.pgno = ds - dc->service + 1 + 8/*after 8 cc channels*/;
@@ -2270,6 +2336,7 @@ dtvcc_render(struct dtvcc_decoder * dc, struct dtvcc_service * ds)
vbi_send_event(td->vbi, &event);
pthread_mutex_lock(&td->mutex);
+#endif
}
static void
@@ -2306,9 +2373,9 @@ dtvcc_caption_window (struct dtvcc_service * ds)
continue;
if (!ds->window[window_id].visible)
continue;
- if (DIR_BOTTOM_TOP
+ /*if (DIR_BOTTOM_TOP
!= ds->window[window_id].style.scroll_direction)
- continue;
+ continue; */
if (ds->window[window_id].priority < max_priority) {
dw = &ds->window[window_id];
max_priority = ds->window[window_id].priority;
@@ -2382,62 +2449,124 @@ dtvcc_put_char (struct dtvcc_decoder * dc,
{
struct dtvcc_window *dw;
unsigned int row;
- unsigned int column;
+ unsigned int column,i;
dc = dc; /* unused */
dw = ds->curr_window;
+
+ //printf("putchar %c\n", c);
+
if (NULL == dw) {
ds->error_line = __LINE__;
+ //AM_DEBUG(1, "================ window null !!!!!");
return FALSE;
}
- row = dw->curr_row;
column = dw->curr_column;
+ row = dw->curr_row;
/* FIXME how should we handle TEXT_TAG_NOT_DISPLAYABLE? */
+ /* Add row column lock support */
+ switch (dw->style.print_direction) {
+ case DIR_LEFT_RIGHT:
+ if (column >= dw->column_count)
+ {
+ if (dw->column_lock == 1)
+ {
+ if (dw->row_lock == 0)
+ {
+ column = 0;
+ row++;
+ if (row >= dw->row_count)
+ {
+ // row moves up
+ }
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (column < 32)
+ {
+ if (dw->column_no_lock_length < column + 1)
+ dw->column_no_lock_length = column + 1;
+ }
+ else
+ {
+ if (dw->row_lock == 1)
+ return TRUE;
+ else
+ {
+ column = 0;
+ row++;
+ if (row >= dw->row_count)
+ {
+ // row moves up
+ }
+ }
+ }
+ }
+ }
+ break;
+ case DIR_RIGHT_LEFT:
+ case DIR_TOP_BOTTOM:
+ case DIR_BOTTOM_TOP:
+ break;
+ }
+
dw->buffer[row][column] = c;
+ dw->pen[row][column] = dw->curr_pen.style;
+ if (c == 0x1020 || c == 0x1021)
+ {
+ if (c == 0x1020)
+ dw->buffer[row][column] = 0x20;
+ else
+ dw->buffer[row][column] = 0xA0;
+ dw->pen[row][column].bg_opacity = OPACITY_TRANSPARENT;
+ dw->pen[row][column].fg_opacity = OPACITY_TRANSPARENT;
+ }
+ //AM_DEBUG(1, "========= putchar %x %c", c, c);
+ if (dw->visible)
+ dtvcc_render(dc, ds);
switch (dw->style.print_direction) {
case DIR_LEFT_RIGHT:
dw->streamed &= ~(1 << row);
if (!cc_timestamp_isset (&dw->timestamp_c0))
dw->timestamp_c0 = ds->timestamp;
- if (++column >= dw->column_count)
- return TRUE;
+ ++column;
break;
case DIR_RIGHT_LEFT:
dw->streamed &= ~(1 << row);
if (!cc_timestamp_isset (&dw->timestamp_c0))
dw->timestamp_c0 = ds->timestamp;
- if (column-- <= 0)
- return TRUE;
+ column--;
break;
case DIR_TOP_BOTTOM:
dw->streamed &= ~(1 << column);
if (!cc_timestamp_isset (&dw->timestamp_c0))
dw->timestamp_c0 = ds->timestamp;
- if (++row >= dw->row_count)
- return TRUE;
+ ++row;
break;
case DIR_BOTTOM_TOP:
dw->streamed &= ~(1 << column);
if (!cc_timestamp_isset (&dw->timestamp_c0))
dw->timestamp_c0 = ds->timestamp;
- if (row-- <= 0)
- return TRUE;
+ row--;
break;
}
dw->curr_row = row;
dw->curr_column = column;
- dtvcc_render(dc, ds);
-
return TRUE;
}
@@ -2509,9 +2638,11 @@ dtvcc_set_pen_color (struct dtvcc_service * ds,
c = buf[1];
dw->curr_pen.style.fg_opacity = c >> 6;
dw->curr_pen.style.fg_color = c & 0x3F;
+ dw->curr_pen.style.fg_flash = ((c>>6)==1)?1:0;
c = buf[2];
dw->curr_pen.style.bg_opacity = c >> 6;
dw->curr_pen.style.bg_color = c & 0x3F;
+ dw->curr_pen.style.bg_flash = ((c>>6)==1)?1:0;
return TRUE;
}
@@ -2535,10 +2666,12 @@ dtvcc_set_pen_attributes (struct dtvcc_service * ds,
c = buf[1];
offset = (c >> 2) & 3;
pen_size = c & 3;
+ //TODO: why not larger than 3
+ /*
if ((offset | pen_size) >= 3) {
ds->error_line = __LINE__;
return FALSE;
- }
+ } */
c = buf[2];
edge_type = (c >> 3) & 7;
@@ -2586,6 +2719,7 @@ dtvcc_set_window_attributes (struct dtvcc_service * ds,
c = buf[1];
dw->style.fill_opacity = c >> 6;
dw->style.fill_color = c & 0x3F;
+ dw->style.window_flash = ((c>>6)==1)?1:0;
c = buf[2];
dw->style.border_type = border_type;
dw->style.border_color = c & 0x3F;
@@ -2622,8 +2756,16 @@ dtvcc_clear_windows (struct dtvcc_decoder * dc,
dtvcc_stream_event (dc, ds, dw, dw->curr_row);
memset (dw->buffer, 0, sizeof (dw->buffer));
+ memset (dw->pen, 0, sizeof(dw->pen));
+
+ dw->curr_column = 0;
+ dw->curr_row = 0;
dw->streamed = 0;
+ dw->style.display_effect = 0;
+ dw->effect_status = 0;
+ if (dw->visible)
+ dtvcc_render(dc, ds);
/* FIXME CEA 708-C Section 7.1.4 (Form Feed)
and 8.10.5.3 confuse me. */
@@ -2715,6 +2857,8 @@ dtvcc_define_window (struct dtvcc_decoder * dc,
unsigned int pen_style_id;
unsigned int c;
+ //printf("define window\n");
+
if (0 != ((buf[1] | buf[6]) & 0xC0)) {
ds->error_line = __LINE__;
return FALSE;
@@ -2745,12 +2889,15 @@ dtvcc_define_window (struct dtvcc_decoder * dc,
return FALSE;
}
+ //printf("define window %d\n", column_count_m1);
+
column_count_m1 = buf[5];
/* We also check the top two zero bits. */
- if (unlikely (column_count_m1 >= 41)) {
+ if (unlikely (column_count_m1 >= 42)) {
ds->error_line = __LINE__;
return FALSE;
}
+ //printf("define windowa\n");
window_id = buf[0] & 7;
dw = &ds->window[window_id];
@@ -2761,7 +2908,7 @@ dtvcc_define_window (struct dtvcc_decoder * dc,
c = buf[1];
dw->visible = (c >> 5) & 1;
dw->row_lock = (c >> 4) & 1;
- dw->column_lock = (c >> 4) & 1;
+ dw->column_lock = (c >> 3) & 1;
dw->priority = c & 7;
dw->anchor_relative = anchor_relative;
@@ -2772,13 +2919,14 @@ dtvcc_define_window (struct dtvcc_decoder * dc,
c = buf[4];
dw->row_count = (c & 15) + 1;
dw->column_count = column_count_m1 + 1;
+ dw->column_no_lock_length = 0;
c = buf[6];
window_style_id = (c >> 3) & 7;
pen_style_id = c & 7;
if (window_style_id > 0) {
- dw->style = window_styles[window_style_id];
+ dw->style = window_styles[window_style_id-1];
} else if (0 == (ds->created & window_map)) {
dw->style = window_styles[1];
}
@@ -2804,6 +2952,8 @@ dtvcc_define_window (struct dtvcc_decoder * dc,
ds->created |= window_map;
+ //printf("define %x %x\n", ds->curr_window, ds->created);
+
return dtvcc_clear_windows (dc, ds, window_map);
}
@@ -2817,6 +2967,12 @@ dtvcc_display_windows (struct dtvcc_decoder * dc,
window_map &= ds->created;
+ //printf("display %02x %p %02x\n", c, ds->curr_window, ds->created);
+ if (ds->curr_window == NULL && ds->created == 0) {
+ return FALSE;
+ //return TRUE;
+ }
+
for (i = 0; i < 8; ++i) {
struct dtvcc_window *dw;
vbi_bool was_visible;
@@ -2830,17 +2986,23 @@ dtvcc_display_windows (struct dtvcc_decoder * dc,
switch (c) {
case 0x89: /* DSW DisplayWindows */
dw->visible = TRUE;
+ dw->effect_status = CC_EFFECT_DISPLAY;
break;
case 0x8A: /* HDW HideWindows */
dw->visible = FALSE;
+ dw->effect_status = CC_EFFECT_HIDE;
break;
case 0x8B: /* TGW ToggleWindows */
dw->visible = was_visible ^ TRUE;
+ dw->effect_status =
+ (dw->visible == TRUE)?CC_EFFECT_DISPLAY:CC_EFFECT_HIDE;
break;
}
+ clock_gettime(CLOCK_REALTIME, &dw->effect_timer);
+
if (!was_visible) {
unsigned int row;
@@ -2851,6 +3013,8 @@ dtvcc_display_windows (struct dtvcc_decoder * dc,
}
}
+ dtvcc_render(dc, ds);
+
return TRUE;
}
@@ -2875,10 +3039,21 @@ dtvcc_carriage_return (struct dtvcc_decoder * dc,
switch (dw->style.scroll_direction) {
case DIR_LEFT_RIGHT:
- dw->curr_row = 0;
- if (column > 0) {
- dw->curr_column = column - 1;
- break;
+ if (dw->style.print_direction == DIR_BOTTOM_TOP)
+ {
+ dw->curr_row = dw->row_count - 1;
+ if (column > 0) {
+ dw->curr_column = column - 1;
+ break;
+ }
+ }
+ else
+ {
+ dw->curr_row = 0;
+ if (column > 0) {
+ dw->curr_column = column - 1;
+ break;
+ }
}
dw->streamed = (dw->streamed << 1)
& ~(1 << dw->column_count);
@@ -2887,16 +3062,30 @@ dtvcc_carriage_return (struct dtvcc_decoder * dc,
column > 0; --column) {
dw->buffer[row][column] =
dw->buffer[row][column - 1];
+ dw->pen[row][column] =
+ dw->pen[row][column - 1];
}
dw->buffer[row][column] = 0;
+ memset(&dw->pen[row][column], 0, sizeof(dw->pen[0][0]));
}
break;
case DIR_RIGHT_LEFT:
- dw->curr_row = 0;
- if (column + 1 < dw->row_count) {
- dw->curr_column = column + 1;
- break;
+ if (dw->style.print_direction == DIR_BOTTOM_TOP)
+ {
+ dw->curr_row = dw->row_count - 1;
+ if (column + 1 < dw->row_count) {
+ dw->curr_column = column + 1;
+ break;
+ }
+ }
+ else
+ {
+ dw->curr_row = 0;
+ if (column + 1 < dw->row_count) {
+ dw->curr_column = column + 1;
+ break;
+ }
}
dw->streamed >>= 1;
for (row = 0; row < dw->row_count; ++row) {
@@ -2904,34 +3093,66 @@ dtvcc_carriage_return (struct dtvcc_decoder * dc,
column < dw->column_count - 1; ++column) {
dw->buffer[row][column] =
dw->buffer[row][column + 1];
+ dw->pen[row][column] =
+ dw->pen[row][column + 1];
}
dw->buffer[row][column] = 0;
+ memset(&dw->pen[row][column], 0, sizeof(dw->pen[0][0]));
}
break;
case DIR_TOP_BOTTOM:
- dw->curr_column = 0;
- if (row > 0) {
- dw->curr_row = row - 1;
- break;
+ if (dw->style.print_direction == DIR_RIGHT_LEFT)
+ {
+ AM_DEBUG(0, "CR: print_r_l cur_col %d row %d", dw->curr_column, dw->curr_row);
+ dw->curr_column = dw->column_count - 1;
+ if (row > 0) {
+ dw->curr_row = row - 1;
+ break;
+ }
+ }
+ else
+ {
+ dw->curr_column = 0;
+ if (row > 0) {
+ dw->curr_row = row - 1;
+ break;
+ }
}
dw->streamed = (dw->streamed << 1)
& ~(1 << dw->row_count);
memmove (&dw->buffer[1], &dw->buffer[0],
sizeof (dw->buffer[0]) * (dw->row_count - 1));
+ memmove (&dw->pen[1], &dw->pen[0],
+ sizeof (dw->pen[0]) * (dw->row_count - 1));
memset (&dw->buffer[0], 0, sizeof (dw->buffer[0]));
+ memset (&dw->pen[0], 0, sizeof(dw->pen[0]));
break;
case DIR_BOTTOM_TOP:
- dw->curr_column = 0;
- if (row + 1 < dw->row_count) {
- dw->curr_row = row + 1;
- break;
+ if (dw->style.print_direction == DIR_RIGHT_LEFT)
+ {
+ dw->curr_column = dw->column_count - 1;;
+ if (row + 1 < dw->row_count) {
+ dw->curr_row = row + 1;
+ break;
+ }
+ }
+ else
+ {
+ dw->curr_column = 0;
+ if (row + 1 < dw->row_count) {
+ dw->curr_row = row + 1;
+ break;
+ }
}
dw->streamed >>= 1;
memmove (&dw->buffer[0], &dw->buffer[1],
sizeof (dw->buffer[0]) * (dw->row_count - 1));
+ memmove (&dw->pen[0], &dw->pen[1],
+ sizeof (dw->pen[0]) * (dw->row_count - 1));
memset (&dw->buffer[row], 0, sizeof (dw->buffer[0]));
+ memset (&dw->pen[row], 0, sizeof (dw->pen[0]));
break;
}
@@ -3011,6 +3232,7 @@ dtvcc_backspace (struct dtvcc_decoder * dc,
if (0 != dw->buffer[row][column]) {
dw->streamed &= ~mask;
dw->buffer[row][column] = 0;
+ memset(&dw->pen[row][column], 0, sizeof(dw->pen[0][0]));
}
dw->curr_row = row;
@@ -3045,6 +3267,8 @@ dtvcc_hor_carriage_return (struct dtvcc_decoder * dc,
mask = 1 << row;
memset (&dw->buffer[row][0], 0,
sizeof (dw->buffer[0]));
+ memset (&dw->pen[row][0], 0,
+ sizeof (dw->pen[0]));
if (DIR_LEFT_RIGHT == dw->style.print_direction)
dw->curr_column = 0;
else
@@ -3054,8 +3278,10 @@ dtvcc_hor_carriage_return (struct dtvcc_decoder * dc,
case DIR_TOP_BOTTOM:
case DIR_BOTTOM_TOP:
mask = 1 << column;
- for (row = 0; row < dw->column_count; ++row)
+ for (row = 0; row < dw->column_count; ++row) {
dw->buffer[row][column] = 0;
+ memset(&dw->pen[row][column], 0, sizeof(dw->pen[0][0]));
+ }
if (DIR_TOP_BOTTOM == dw->style.print_direction)
dw->curr_row = 0;
else
@@ -3074,15 +3300,36 @@ dtvcc_delete_windows (struct dtvcc_decoder * dc,
dtvcc_window_map window_map)
{
struct dtvcc_window *dw;
+ int i;
+ int changed = 0;
- dw = ds->curr_window;
- if (NULL != dw) {
- unsigned int window_id;
-
- window_id = dtvcc_window_id (ds, dw);
- if (0 != (window_map & (1 << window_id))) {
- dtvcc_stream_event (dc, ds, dw, dw->curr_row);
- ds->curr_window = NULL;
+ for (i = 0; i < N_ELEMENTS(ds->window); i ++) {
+ dw = &ds->window[i];
+
+ if (NULL != dw) {
+ unsigned int window_id;
+ window_id = dtvcc_window_id (ds, dw);
+ if (ds->created & (1 << window_id)) {
+ if (window_map & (1 << window_id)) {
+ //printf("delete window %d\n", window_id);
+ dtvcc_stream_event (dc, ds, dw, dw->curr_row);
+
+ if (dw == ds->curr_window)
+ ds->curr_window = NULL;
+
+ if (dw->visible)
+ dtvcc_render(dc, ds);
+
+ memset (dw->buffer, 0, sizeof (dw->buffer));
+ memset (dw->pen, 0, sizeof(dw->pen));
+ dw->visible = 0;
+ dw->effect_status = 0;
+ dw->effect_percent = 0;
+ dw->style.display_effect = 0;
+
+ changed = 1;
+ }
+ }
}
}
@@ -3092,6 +3339,45 @@ dtvcc_delete_windows (struct dtvcc_decoder * dc,
}
static vbi_bool
+dtvcc_delay_cmd (struct dtvcc_decoder * dc,
+ struct dtvcc_service * ds,
+ uint8_t delay_cmd,
+ uint8_t delay_time)
+{
+ struct timespec now_ts;
+ int plus_one_second = 0;
+ clock_gettime(CLOCK_REALTIME, &now_ts);
+ if (delay_cmd == 0x8D)
+ {
+ /* Set trigger time
+ Until that time, sevice stop decoding.
+ */
+ /* Delay time is tenths of second */
+ /* We set the timer a little faster to avoid double delay conflict */
+ if ((1000000000 - (delay_time%10) * 100000000) > now_ts.tv_nsec)
+ {
+ ds->delay_timer.tv_nsec = ((delay_time % 10) * 100000000 + now_ts.tv_nsec) % 1000000000;
+ ds->delay_timer.tv_sec = (1 + now_ts.tv_sec + delay_time/10) -1;
+ }
+ else
+ {
+ ds->delay_timer.tv_nsec = (delay_time % 10) * 100000000 + now_ts.tv_nsec;
+ ds->delay_timer.tv_sec = (now_ts.tv_sec + delay_time / 10) -1;
+ }
+ ds->delay_timer.tv_sec = now_ts.tv_sec + 1;
+ ds->delay = 1;
+ ds->delay_cancel = 0;
+ //AM_DEBUG(1, "Enter delay cmd, now %d until %d", now_ts.tv_sec, ds->delay_timer.tv_sec);
+ }
+ else if (delay_cmd == 0x8E)
+ {
+ ds->delay = 0;
+ ds->delay_cancel = 1;
+ }
+ return TRUE;
+}
+
+static vbi_bool
dtvcc_command (struct dtvcc_decoder * dc,
struct dtvcc_service * ds,
unsigned int * se_length,
@@ -3110,9 +3396,8 @@ dtvcc_command (struct dtvcc_decoder * dc,
if (*se_length > n_bytes) {
ds->error_line = __LINE__;
- return FALSE;
+ return TRUE;
}
-
switch (c) {
case 0x08: /* BS Backspace */
return dtvcc_backspace (dc, ds);
@@ -3141,6 +3426,14 @@ dtvcc_command (struct dtvcc_decoder * dc,
case 0x89: /* DSW DisplayWindows */
return dtvcc_display_windows (dc, ds, c, buf[1]);
+ case 0x8D:
+ dtvcc_delay_cmd(dc, ds, 0x8d, buf[1]);
+ return 0;
+
+ case 0x8E:
+ dtvcc_delay_cmd(dc, ds, 0x8e, buf[1]);
+ return 0;
+
case 0x8A: /* HDW HideWindows */
return dtvcc_display_windows (dc, ds, c, buf[1]);
@@ -3244,17 +3537,21 @@ dtvcc_decode_syntactic_elements (struct dtvcc_decoder * dc,
unsigned int n_bytes)
{
ds->timestamp = dc->timestamp;
+ struct timespec ts_now;
+
+#if 0
+ AM_DEBUG(1, "+++++++++++++++++++++ servie %d\n", n_bytes);
+ {
+ int i;
+ for (i = 0; i < n_bytes; i ++)
+ AM_DEBUG(1, "++++++++++++++ %02x ", buf[i]);
+ }
+#endif
while (n_bytes > 0) {
unsigned int se_length;
-
- if (0x8D /* DLY */ == *buf
- || 0x8E /* DLC */ == *buf) {
- /* FIXME ignored for now. */
- ++buf;
- --n_bytes;
- continue;
- }
+
+ //printf("dec se %02x\n", buf[0]);
if (!dtvcc_decode_se (dc, ds,
&se_length,
@@ -3269,6 +3566,40 @@ dtvcc_decode_syntactic_elements (struct dtvcc_decoder * dc,
return TRUE;
}
+static void
+dtvcc_try_decode_channels (struct dtvcc_decoder *dc)
+{
+ int i;
+
+ for (i = 0; i < 6; ++i) {
+ struct dtvcc_service *ds;
+ struct program *pr;
+ vbi_bool success;
+
+ ds = &dc->service[i];
+ if (0 == ds->service_data_in)
+ continue;
+ if (!ds->delay ||
+ (ds->delay && ds->service_data_in>=128))
+ {
+ //AM_DEBUG(1, "service datain %d", ds->service_data_in);
+ success = dtvcc_decode_syntactic_elements
+ (dc, ds, ds->service_data, ds->service_data_in);
+ if (ds->service_data_in >= 128)
+ {
+ ds->delay = 0;
+ ds->delay_cancel = 0;
+ }
+ ds->service_data_in = 0;
+
+ if (success)
+ continue;
+ }
+ //dtvcc_reset_service (ds);
+ //dc->next_sequence_number = -1;
+ }
+}
+
void
dtvcc_decode_packet (struct dtvcc_decoder * dc,
const struct timeval * tv,
@@ -3278,6 +3609,14 @@ dtvcc_decode_packet (struct dtvcc_decoder * dc,
unsigned int packet_size;
unsigned int i;
+#if 0
+ printf("%d dtvcc decode packet %d: ", get_input_offset(), dc->packet_size);
+
+ for (i = 0; i < dc->packet_size; i ++) {
+ printf("%02x ", dc->packet[i]);
+ }
+ printf("\n");
+#endif
dc->timestamp.sys = *tv;
dc->timestamp.pts = pts;
@@ -3285,13 +3624,13 @@ dtvcc_decode_packet (struct dtvcc_decoder * dc,
/* sequence_number [2], packet_size_code [6],
packet_data [n * 8] */
-
+#if 1
if (dc->next_sequence_number >= 0
&& 0 != ((dc->packet[0] ^ dc->next_sequence_number) & 0xC0)) {
dtvcc_reset (dc);
return;
}
-
+#endif
dc->next_sequence_number = dc->packet[0] + 0x40;
packet_size_code = dc->packet[0] & 0x3F;
@@ -3302,8 +3641,10 @@ dtvcc_decode_packet (struct dtvcc_decoder * dc,
/* CEA 708-C Section 5: Apparently packet_size need not be
equal to the actually transmitted amount of data. */
if (packet_size > dc->packet_size) {
+ /*
dtvcc_reset (dc);
- return;
+ return;*/
+ packet_size = dc->packet_size;
}
/* Service Layer. */
@@ -3324,14 +3665,17 @@ dtvcc_decode_packet (struct dtvcc_decoder * dc,
(null_fill [2], extended_service_number [6]),
(Block_data [n * 8]) */
- c = dc->packet[i];
+ c = dc->packet[i];
service_number = (c & 0xE0) >> 5;
+ //printf("srv %d\n", service_number);
+
/* CEA 708-C Section 6.3: Ignore block_size if
service_number is zero. */
if (0 == service_number) {
/* NULL Service Block Header, no more data in
this Caption Channel Packet. */
+ dc->next_sequence_number = -1;
break;
}
@@ -3342,22 +3686,26 @@ dtvcc_decode_packet (struct dtvcc_decoder * dc,
if (7 == service_number) {
if (i + 1 > packet_size)
- goto service_block_incomplete;
+ break;
header_size = 2;
c = dc->packet[i + 1];
/* We also check the null_fill bits. */
if (c < 7 || c > 63)
- goto invalid_service_block;
+ break;
service_number = c;
}
+ //printf("srv %d %d %d %d\n", service_number, header_size, block_size, packet_size);
+
if (i + header_size + block_size > packet_size)
- goto service_block_incomplete;
+ {
+ break;
+ }
- if (service_number <= 2) {
+ if (service_number <= 6) {
struct dtvcc_service *ds;
unsigned int in;
@@ -3372,48 +3720,215 @@ dtvcc_decode_packet (struct dtvcc_decoder * dc,
i += header_size + block_size;
}
- for (i = 0; i < 2; ++i) {
- struct dtvcc_service *ds;
- struct program *pr;
- vbi_bool success;
+ dtvcc_try_decode_channels(dc);
+ return;
+}
- ds = &dc->service[i];
- if (0 == ds->service_data_in)
- continue;
+static int
+dtvcc_get_se_len (unsigned char *p, int left)
+{
+ unsigned char c;
+ int se_length;
- success = dtvcc_decode_syntactic_elements
- (dc, ds, ds->service_data, ds->service_data_in);
+ if (left < 1)
+ return 0;
- ds->service_data_in = 0;
+ c = p[0];
- if (success)
- continue;
+ if ((c == 0x8d) && (c == 0x8e))
+ return 1;
- dtvcc_reset_service (ds);
+ if (0 != (c & 0x60))
+ return 1;
+
+ if (0x10 != c) {
+ if ((int8_t) c < 0) {
+ se_length = dtvcc_c1_length[c - 0x80];
+ } else {
+ se_length = dtvcc_c0_length[c >> 3];
+ }
+
+ if (left < se_length)
+ return 0;
+
+ return se_length;
}
- return;
+ if (left < 2)
+ return 0;
- invalid_service_block:
- {
- dtvcc_reset (dc);
- return;
+ c = p[1];
+ if (0 != (c & 0x60))
+ return 2;
+
+ if ((int8_t) c >= 0) {
+ se_length = (c >> 3) + 2;
+ } else if (c < 0x90) {
+ se_length = (c >> 3) - 10;
+ } else {
+ if (left < 3)
+ return 0;
+
+ se_length = (p[2] & 0x1F) + 3;
}
- service_block_incomplete:
- {
- dtvcc_reset (dc);
+ if (left < se_length)
+ return 0;
+
+ return se_length;
+}
+
+void
+dtvcc_try_decode_packet (struct dtvcc_decoder * dc,
+ const struct timeval * tv,
+ int64_t pts)
+{
+ unsigned int packet_size_code;
+ unsigned int packet_size;
+ unsigned char *p;
+ int left;
+
+ if (dc->packet_size < 1)
+ return;
+
+ packet_size_code = dc->packet[0] & 0x3F;
+
+ packet_size = 128;
+ if (packet_size_code > 0)
+ packet_size = packet_size_code * 2;
+
+ if (packet_size <= dc->packet_size) {
+ dtvcc_decode_packet(dc, tv, pts);
+ dc->packet_size = 0;
return;
}
+ p = dc->packet + 1;
+ left = dc->packet_size - 1;
+ while (left > 0) {
+ unsigned int service_number;
+ unsigned int block_size;
+ unsigned int header_size;
+ unsigned int c;
+
+ header_size = 1;
+
+ c = p[0];
+ service_number = (c & 0xE0) >> 5;
+ if (0 == service_number)
+ break;
+
+ block_size = c & 0x1F;
+
+ if (7 == service_number) {
+ if (left < 2)
+ break;
+
+ header_size = 2;
+ c = p[1];
+
+ if (c < 7 || c > 63)
+ break;
+
+ service_number = c;
+ }
+
+ if (left >= header_size + block_size) {
+ if (service_number <= 6) {
+ struct dtvcc_service *ds;
+ unsigned int in;
+
+ ds = &dc->service[service_number - 1];
+ in = ds->service_data_in;
+ memcpy (ds->service_data + in,
+ p + header_size,
+ block_size);
+
+ ds->service_data_in = in + block_size;
+ }
+ } else {
+ unsigned char *s = p + header_size;
+ int sleft = left - header_size;
+
+ while (sleft > 0) {
+ int se_len;
+
+ se_len = dtvcc_get_se_len(s, sleft);
+ if (se_len <= 0)
+ break;
+
+ s += se_len;
+ sleft -= se_len;
+ }
+
+ if (sleft != left - header_size) {
+ int parsed = left - header_size - sleft;
+
+ if (service_number <= 6) {
+ struct dtvcc_service *ds;
+ unsigned int in;
+
+ ds = &dc->service[service_number - 1];
+ in = ds->service_data_in;
+ memcpy (ds->service_data + in,
+ p + header_size,
+ parsed);
+
+ ds->service_data_in = in + parsed;
+ }
+
+ memmove(p + header_size, s, sleft);
+ block_size -= parsed;
+ left -= parsed;
+
+ p[0] &= ~0x1f;
+ p[0] |= block_size;
+ }
+ break;
+ }
+
+ p += header_size + block_size;
+ left -= header_size + block_size;
+ }
+
+ if (left != dc->packet_size - 1) {
+ int parsed = dc->packet_size - 1 - left;
+
+ memmove(dc->packet + 1, p, left);
+
+ packet_size_code = ((dc->packet[0] & 0x3f) << 1) - parsed;
+ if (packet_size_code & 1)
+ packet_size_code ++;
+ packet_size_code >>= 1;
+
+ dc->packet[0] &= ~0x3f;
+ dc->packet[0] |= packet_size_code;
+ dc->packet_size = left + 1;
+
+ dtvcc_try_decode_channels(dc);
+ }
}
static void
dtvcc_reset_service (struct dtvcc_service * ds)
{
+ int i;
ds->curr_window = NULL;
ds->created = 0;
+ ds->delay = 0;
+ ds->delay_cancel = 0;
+ struct dtvcc_window *dw;
+ for (i=0;i<8;i++)
+ {
+ dw = &ds->window[i];
+ ds->window[i].visible = 0;
+ memset (dw->buffer, 0, sizeof (dw->buffer));
+ memset (dw->pen, 0, sizeof(dw->pen));
+ dw->effect_status = 0;
+ dw->streamed = 0;
+ }
+ ds->update = 1;
cc_timestamp_reset (&ds->timestamp);
}
@@ -3422,7 +3937,6 @@ dtvcc_reset (struct dtvcc_decoder * dc)
{
dtvcc_reset_service (&dc->service[0]);
dtvcc_reset_service (&dc->service[1]);
-
dc->packet_size = 0;
dc->next_sequence_number = -1;
}
@@ -3430,9 +3944,12 @@ dtvcc_reset (struct dtvcc_decoder * dc)
void
dtvcc_init (struct dtvcc_decoder * dc)
{
+ int i;
+ memset(dc, 0, sizeof(struct dtvcc_decoder));
dtvcc_reset (dc);
-
cc_timestamp_reset (&dc->timestamp);
+ for (i=0;i<6;i++)
+ dc->service[i].id = i;
}
static void dtvcc_window_to_page(vbi_decoder *vbi, struct dtvcc_window *dw, struct vbi_page *pg)
@@ -3440,21 +3957,22 @@ static void dtvcc_window_to_page(vbi_decoder *vbi, struct dtvcc_window *dw, stru
int i, j, c;
vbi_char ac;
vbi_opacity fg_opacity, bg_opacity;
-
+
static const vbi_opacity vbi_opacity_map[]={
VBI_OPAQUE,
VBI_OPAQUE,
VBI_SEMI_TRANSPARENT,
VBI_TRANSPARENT_SPACE
};
-
+
memset(pg, 0, sizeof(struct vbi_page));
#if 1
pg->rows = dw->row_count;
pg->columns = dw->column_count;
-
+
dtvcc_set_page_color_map(vbi, pg);
-
+ memset(dw->row_start, 0, sizeof(dw->row_start));
+
for (i=0; i<pg->rows; i++)
{
for (j=0; j<pg->columns; j++)
@@ -3472,22 +3990,23 @@ static void dtvcc_window_to_page(vbi_decoder *vbi, struct dtvcc_window *dw, stru
}else{
bg_opacity = vbi_opacity_map[dw->curr_pen.style.bg_opacity];
}
-
+
ac.opacity = (fg_opacity<<4) | bg_opacity;
ac.foreground = dtvcc_map_color(dw->curr_pen.style.fg_color);
ac.background = dtvcc_map_color(dw->curr_pen.style.bg_color);
-
+
c = dw->buffer[i][j];
if (0 == c) {
ac.unicode = 0x20;
ac.opacity = VBI_TRANSPARENT_SPACE;
+ dw->row_start[i] ++;
} else {
ac.unicode = dtvcc_unicode (c);
if (0 == ac.unicode) {
ac.unicode = 0x20;
+ dw->row_start[i] ++;
}
}
-
pg->text[i*pg->columns + j] = ac;
}
}
@@ -3545,7 +4064,7 @@ static void dtvcc_get_visible_windows(struct dtvcc_service *ds, int *cnt, struct
void tvcc_fetch_page(struct tvcc_decoder *td, int pgno, int *sub_cnt, struct vbi_page *sub_pages)
{
int sub_pg = 0;
-
+
if (pgno < 1 || pgno > 14 || *sub_cnt <= 0)
goto fetch_done;
@@ -3559,30 +4078,146 @@ void tvcc_fetch_page(struct tvcc_decoder *td, int pgno, int *sub_cnt, struct vbi
struct dtvcc_service *ds = &td->dtvcc.service[pgno - 1 - 8];
struct dtvcc_window *dw;
struct dtvcc_window *visible_windows[8];
-
+
sub_pg = *sub_cnt;
if (sub_pg > 8)
sub_pg = 8;
-
+
dtvcc_get_visible_windows(ds, &sub_pg, visible_windows);
-
+
for (i=0; i<sub_pg; i++){
dw = visible_windows[i];
-
- dtvcc_window_to_page(td->vbi, dw, &sub_pages[i]);
-
+
+ dtvcc_window_to_page(td->vbi, dw, &sub_pages[i]);
sub_pages[i].vbi = td->vbi;
sub_pages[i].pgno = pgno;
sub_pages[i].subno = dw - ds->window;
}
}
-
+
fetch_done:
*sub_cnt = sub_pg;
}
/* ATSC A/53 Part 4:2007 Closed Caption Data decoder */
+/* Only handle effect */
+static void update_service_status_internal (struct tvcc_decoder *td)
+{
+ int i, j, k, l;
+ struct timespec ts_now;
+ struct dtvcc_decoder *decoder;
+ struct dtvcc_pen_style *target_pen;
+ int flash;
+
+ decoder = &td->dtvcc;
+ clock_gettime(CLOCK_REALTIME, &ts_now);
+
+ flash = (ts_now.tv_nsec / 250000000) & 1;
+
+ /* CS1 - CS6 */
+ for (i = 0; i < 6; ++i)
+ {
+ struct dtvcc_service *ds;
+ struct program *pr;
+ vbi_bool success;
+ ds = &decoder->service[i];
+ /* Check every effect */
+ if (ds->delay)
+ {
+ struct vbi_event event;
+ /* time is up */
+ if ((ts_now.tv_sec > ds->delay_timer.tv_sec) ||
+ ((ts_now.tv_sec == ds->delay_timer.tv_sec) &&(ts_now.tv_nsec > ds->delay_timer.tv_nsec)) ||
+ ds->delay_cancel)
+ {
+ //AM_DEBUG(1, "delay timeup");
+ ds->delay = 0;
+ ds->delay_cancel = 0;
+ dtvcc_decode_syntactic_elements
+ (decoder, ds, ds->service_data, ds->service_data_in);
+
+ ds->service_data_in = 0;
+ }
+ }
+
+ if (flash == decoder->flash_state)
+ continue;
+
+ for (j = 0; j < 8; j++)
+ {
+ struct dtvcc_window *target_window;
+ target_window = &ds->window[j];
+ /*window flash treatment */
+ if (target_window->style.window_flash)
+ {
+ target_window->style.fill_opacity = flash?0:3;
+ ds->update = 1;
+ }
+
+ /* Wipe and fade treatment */
+ if (target_window->style.display_effect != 0 &&
+ target_window->effect_status != 0)
+ {
+ target_window->effect_percent =
+ ((ts_now.tv_sec - target_window->effect_timer.tv_sec) * 1000 +
+ (ts_now.tv_nsec - target_window->effect_timer.tv_nsec) / 1000000) *100/
+ (target_window->style.effect_speed * 500);
+ if (target_window->effect_percent > 100)
+ target_window->effect_percent = 100;
+ ds->update = 1;
+ }
+
+ /* Pen flash treatment */
+ for (k = 0; k < 16; k++)
+ {
+ for (l =0; l<42; l++)
+ {
+ target_pen = &target_window->pen[k][l];
+ if (target_pen->bg_flash)
+ {
+ target_pen->bg_opacity = flash?0:3;
+ ds->update = 1;
+ }
+ if (target_pen->fg_flash)
+ {
+ target_pen->fg_opacity = flash?0:3;
+ ds->update = 1;
+ }
+ }
+ }
+ }
+ }
+
+ decoder->flash_state = flash;
+}
+
+static void
+update_display (struct tvcc_decoder *td)
+{
+ int i;
+
+ for (i = 0; i < N_ELEMENTS(td->dtvcc.service); i ++) {
+ struct dtvcc_service *ds = &td->dtvcc.service[i];
+
+ if (ds->update) {
+ struct vbi_event event;
+
+ event.type = VBI_EVENT_CAPTION;
+ event.ev.caption.pgno = i + 1 + 8/*after 8 cc channels*/;
+
+ /* Permits calling tvcc_fetch_page from handler */
+ pthread_mutex_unlock(&td->mutex);
+
+ vbi_send_event(td->vbi, &event);
+ pthread_mutex_lock(&td->mutex);
+
+ ds->update = 0;
+ }
+ }
+}
+
+
/* Note pts may be < 0 if no PTS was received. */
void
tvcc_decode_data (struct tvcc_decoder *td,
@@ -3600,12 +4235,30 @@ tvcc_decode_data (struct tvcc_decoder *td,
return;
process_cc_data_flag = buf[1] & 0x40;
if (!process_cc_data_flag)
+ {
return;
+ }
cc_count = buf[1] & 0x1F;
dtvcc = FALSE;
+#if 0
+ printf("tvcc decode %d:\n", n_bytes);
+ {
+ int i;
+
+ for (i = 0; i < n_bytes; i ++) {
+ printf("%02x ", buf[i]);
+ if ((i + 1) % 16 == 0)
+ printf("\n");
+ }
+ printf("\n");
+ }
+#endif
pthread_mutex_lock(&td->mutex);
+
+ //printf("cc count %d\n", cc_count);
+
for (i = 0; i < cc_count; ++i) {
unsigned int b0;
unsigned int cc_valid;
@@ -3620,9 +4273,12 @@ tvcc_decode_data (struct tvcc_decoder *td,
cc_data_1 = buf[4 + i * 3];
cc_data_2 = buf[5 + i * 3];
+ //printf("cc type %02x %02x %02x %02x\n", cc_type, cc_valid, cc_data_1, cc_data_2);
+
switch (cc_type) {
case NTSC_F1:
case NTSC_F2:
+ //printf("ntsc cc\n");
/* Note CEA 708-C Table 4: Only one NTSC pair
will be present in field picture user_data
or in progressive video pictures, and up to
@@ -3647,10 +4303,7 @@ tvcc_decode_data (struct tvcc_decoder *td,
break;
} else if (!cc_valid) {
/* End of DTVCC packet. */
- dtvcc_decode_packet (&td->dtvcc,
- &now, pts);
- td->dtvcc.packet_size = 0;
- } else if (j >= 128) {
+ } else if (j + 2 > 128) {
/* Packet buffer overflow. */
dtvcc_reset (&td->dtvcc);
td->dtvcc.packet_size = 0;
@@ -3658,6 +4311,8 @@ tvcc_decode_data (struct tvcc_decoder *td,
td->dtvcc.packet[j] = cc_data_1;
td->dtvcc.packet[j + 1] = cc_data_2;
td->dtvcc.packet_size = j + 2;
+
+ dtvcc_try_decode_packet (&td->dtvcc, &now, pts);
}
break;
@@ -3676,10 +4331,26 @@ tvcc_decode_data (struct tvcc_decoder *td,
td->dtvcc.packet[0] = cc_data_1;
td->dtvcc.packet[1] = cc_data_2;
td->dtvcc.packet_size = 2;
+ dtvcc_try_decode_packet(&td->dtvcc, &now, pts);
}
break;
}
}
+
+ update_service_status_internal(td);
+ update_display(td);
+
+ pthread_mutex_unlock(&td->mutex);
+}
+
+/* Only handle effect */
+void update_service_status(struct tvcc_decoder *td)
+{
+ pthread_mutex_lock(&td->mutex);
+
+ update_service_status_internal(td);
+ update_display(td);
+
pthread_mutex_unlock(&td->mutex);
}
diff --git a/src/dtvcc.h b/src/dtvcc.h
index 24f4f58..32a7a7a 100644
--- a/src/dtvcc.h
+++ b/src/dtvcc.h
@@ -40,6 +40,12 @@ enum cc_mode {
CC_MODE_TEXT
};
+enum cc_effect_status {
+ CC_EFFECT_NONE,
+ CC_EFFECT_DISPLAY,
+ CC_EFFECT_HIDE
+};
+
/* EIA 608-B Section 4.1. */
#define VBI_CAPTION_CC1 1 /* primary synchronous caption service (F1) */
#define VBI_CAPTION_CC2 2 /* special non-synchronous use captions (F1) */
@@ -308,6 +314,8 @@ struct dtvcc_pen_style {
enum opacity bg_opacity;
dtvcc_color edge_color;
+ vbi_bool fg_flash;
+ vbi_bool bg_flash;
};
struct dtvcc_pen {
@@ -327,6 +335,7 @@ struct dtvcc_window_style {
dtvcc_color fill_color;
enum opacity fill_opacity;
+ vbi_bool window_flash;
enum edge border_type;
dtvcc_color border_color;
@@ -336,6 +345,8 @@ struct dtvcc_window {
/* EIA 708-C window state. */
uint16_t buffer[16][42];
+ struct dtvcc_pen_style pen[16][42];
+ int row_start[16];
vbi_bool visible;
@@ -352,6 +363,7 @@ struct dtvcc_window {
vbi_bool row_lock;
vbi_bool column_lock;
+ unsigned int column_no_lock_length;
unsigned int curr_row;
unsigned int curr_column;
@@ -360,6 +372,12 @@ struct dtvcc_window {
struct dtvcc_window_style style;
+ /* Used for fade and swipe */
+ struct timespec effect_timer;
+ /* 0~100 */
+ int effect_percent;
+ enum cc_effect_status effect_status;
+
/* Our stuff. */
/**
@@ -379,8 +397,13 @@ struct dtvcc_window {
struct dtvcc_service {
/* Interpretation Layer. */
+ int id;
struct dtvcc_window window[8];
+ struct dtvcc_window old_window[8];
+
+ int old_win_cnt;
+ int update;
struct dtvcc_window * curr_window;
@@ -393,6 +416,14 @@ struct dtvcc_service {
uint8_t service_data[128];
unsigned int service_data_in;
+ /* For 0x8D 0x8E delay command
+ * if delay flag is set, decoder stop decoding
+ */
+ struct timespec delay_timer;
+
+
+ int delay;
+ int delay_cancel;
/** The time when we last received data for this service. */
struct cc_timestamp timestamp;
@@ -413,6 +444,8 @@ struct dtvcc_decoder {
/** The time when we last received data. */
struct cc_timestamp timestamp;
+
+ int flash_state;
};
/* ATSC A/53 Part 4:2007 Closed Caption Data decoder. */
@@ -473,6 +506,7 @@ struct tvcc_decoder {
struct cc_decoder cc;
struct dtvcc_decoder dtvcc;
};
+unsigned int dtvcc_unicode (unsigned int c);
extern void tvcc_init(struct tvcc_decoder *td);
@@ -482,7 +516,7 @@ extern void tvcc_reset(struct tvcc_decoder *td);
extern void tvcc_destroy(struct tvcc_decoder *td);
-extern void tvcc_fetch_page(struct tvcc_decoder *td, int pgno, int *sub_cnt, struct vbi_page *sub_pages);
+extern void tvcc_fetch_page(struct tvcc_decoder *td, int pgno, int *cnt, struct vbi_page *sub_pages);
static void dtvcc_init(struct dtvcc_decoder * dc);
@@ -496,5 +530,14 @@ extern vbi_bool cc_feed(struct cc_decoder *cd, const uint8_t buffer[2], unsigned
extern void cc_reset(struct cc_decoder *cd);
+extern void vbi_decode_caption(vbi_decoder *vbi, int line, const uint8_t *buf);
+
+extern int get_input_offset();
+
+extern void update_service_status(struct tvcc_decoder *td);
+static vbi_bool dtvcc_carriage_return (struct dtvcc_decoder *dc, struct dtvcc_service * ds);
+
+
+
#endif
diff --git a/src/event.h b/src/event.h
index 7b699a3..1ba71ee 100644..100755
--- a/src/event.h
+++ b/src/event.h
@@ -128,6 +128,9 @@ typedef struct {
/** Private. */
int cycle;
+
+ /** Transmission Signal ID */
+ int ts_id;
} vbi_network;
/*
@@ -414,7 +417,16 @@ typedef enum {
*/
VBI_AUDIO_MODE_UNKNOWN
} vbi_audio_mode;
-
+typedef struct vbi_rating{
+ /*
+ * For details STFW for "v-chip"
+ * If unknown rating_auth == VBI_RATING_NONE
+ */
+ vbi_rating_auth auth;
+ int id;
+ /* Only valid when auth == VBI_RATING_TV_US */
+ int dlsv;
+}vbi_rating;
/**
* @ingroup Event
*
@@ -470,16 +482,7 @@ typedef struct vbi_program_info {
int type_id[33];
/* 05 Program rating */
-
- /*
- * For details STFW for "v-chip"
- * If unknown rating_auth == VBI_RATING_NONE
- */
- vbi_rating_auth rating_auth;
- int rating_id;
-
- /* Only valid when auth == VBI_RATING_TV_US */
- int rating_dlsv;
+ vbi_rating rating;
/* 06 Program Audio Services */
@@ -652,6 +655,7 @@ extern void vbi_reset_prog_info(vbi_program_info *pi);
* @since 0.2.20
*/
#define VBI_EVENT_NETWORK_ID 0x0100
+#define VBI_EVENT_RATING 0x0200
/** @} */
/**
diff --git a/src/exp-gfx.c b/src/exp-gfx.c
index c8ff3d5..4232dda 100644
--- a/src/exp-gfx.c
+++ b/src/exp-gfx.c
@@ -674,6 +674,8 @@ vbi_draw_vt_page_region(vbi_page *pg,
ac = &pg->text[row * pg->columns + column];
for (count = width; count > 0; count--, ac++) {
+ int transparent;
+
if ((ac->conceal & conceal) || (ac->flash & off))
unicode = 0x0020;
else
@@ -682,6 +684,53 @@ vbi_draw_vt_page_region(vbi_page *pg,
if (subtitle && (row == 0))
unicode = 0x0020;
+ if (!subtitle) {
+ transparent = 0;
+ } else if (subtitle == 1) {
+ if (vbi_is_drcs(unicode) || unicode==0x0020)
+ transparent = 1;
+ else
+ transparent = 0;
+ } else {
+ if (row == 0) {
+ transparent = 1;
+ } else if (vbi_is_drcs(unicode) || unicode==0x0020) {
+ vbi_char *tc;
+ int n, uc;
+ int left, right;
+
+ left = right = 0;
+
+ for (n = count + 1, tc = ac - 1; n <= width; tc --, n ++) {
+ if ((tc->conceal & conceal) || (tc->flash & off))
+ uc = 0x0020;
+ else
+ uc = tc->unicode;
+
+ if(!vbi_is_drcs(uc) && uc!=0x0020) {
+ left = 1;
+ break;
+ }
+ }
+
+ for (n = count - 1, tc = ac + 1; n > 0; tc ++, n --) {
+ if ((tc->conceal & conceal) || (tc->flash & off))
+ uc = 0x0020;
+ else
+ uc = tc->unicode;
+
+ if(!vbi_is_drcs(uc) && uc!=0x0020) {
+ right = 1;
+ break;
+ }
+ }
+
+ transparent = !(left & right);
+ } else {
+ transparent = 0;
+ }
+ }
+
if (canvas_type == 1) {
pen.pal8[0] = ac->background;
pen.pal8[1] = ac->foreground;
@@ -689,15 +738,13 @@ vbi_draw_vt_page_region(vbi_page *pg,
pen.rgba[0] = pg->color_map[ac->background];
pen.rgba[1] = pg->color_map[ac->foreground];
- if(subtitle){
- if(vbi_is_drcs(unicode) || unicode==0x0020) {
- pen.rgba[0] &= 0x00FFFFFF;
- pen.rgba[1] &= 0x00FFFFFF;
- }else{
- pen.rgba[0] &= 0x00FFFFFF;
- //pen.rgba[0] |= 0x80000000;
- }
- }
+ if (transparent) {
+ pen.rgba[0] = 0x00FFFFFF;
+ pen.rgba[1] = 0x00FFFFFF;
+ }
+
+ if (subtitle == 1)
+ pen.rgba[0] = 0x00FFFFFF;
}
switch (ac->size) {
diff --git a/src/libzvbi.h b/src/libzvbi.h
index 4f562ee..2e251bf 100644..100755
--- a/src/libzvbi.h
+++ b/src/libzvbi.h
@@ -275,6 +275,7 @@ typedef struct {
int cycle;
+ int ts_id;
} vbi_network;
/*
@@ -384,6 +385,18 @@ typedef enum {
VBI_AUDIO_MODE_UNKNOWN
} vbi_audio_mode;
+typedef struct vbi_rating{
+ /*
+ * For details STFW for "v-chip"
+ * If unknown rating_auth == VBI_RATING_NONE
+ */
+ vbi_rating_auth auth;
+ int id;
+ /* Only valid when auth == VBI_RATING_TV_US */
+ int dlsv;
+}vbi_rating;
+
+
typedef struct vbi_program_info {
/*
* Refers to the current or next program.
@@ -439,11 +452,7 @@ typedef struct vbi_program_info {
* For details STFW for "v-chip"
* If unknown rating_auth == VBI_RATING_NONE
*/
- vbi_rating_auth rating_auth;
- int rating_id;
-
- /* Only valid when auth == VBI_RATING_TV_US */
- int rating_dlsv;
+ vbi_rating rating;
/* 06 Program Audio Services */
@@ -508,6 +517,7 @@ extern void vbi_reset_prog_info(vbi_program_info *pi);
#define VBI_EVENT_ASPECT 0x0040
#define VBI_EVENT_PROG_INFO 0x0080
#define VBI_EVENT_NETWORK_ID 0x0100
+#define VBI_EVENT_RATING 0x0200
diff --git a/src/vbi.c b/src/vbi.c
index 687a02f..92cb363 100644..100755
--- a/src/vbi.c
+++ b/src/vbi.c
@@ -795,7 +795,7 @@ vbi_reset_prog_info(vbi_program_info *pi)
/* PT */
pi->type_classf = VBI_PROG_CLASSF_NONE;
/* PR */
- pi->rating_auth = VBI_RATING_AUTH_NONE;
+ pi->rating.auth = VBI_RATING_AUTH_NONE;
/* PAS */
pi->audio[0].mode = VBI_AUDIO_MODE_UNKNOWN;
pi->audio[0].language = NULL;