From 2faac703f051ddbf1d7c64f4924ba78849e70742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Wed, 1 Oct 2008 20:04:38 +0000 Subject: [PATCH] Fix teletext parsing and add support for parsing TV4 rundown. --- Makefile | 2 +- channels.c | 13 --- channels.h | 8 -- packet.h | 2 +- teletext.c | 318 +++++++++++++++++++++++++++++++---------------------- teletext.h | 4 +- tsdemux.c | 2 +- tvhead.h | 23 ---- 8 files changed, 188 insertions(+), 184 deletions(-) diff --git a/Makefile b/Makefile index 5df684cc..646d3a08 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SRCS = main.c access.c dtable.c tcp.c http.c notify.c epg.c xmltv.c spawn.c -SRCS += packet.c streaming.c +SRCS += packet.c streaming.c teletext.c VPATH += dvr SRCS += dvr_db.c dvr_rec.c dvr_autorec.c diff --git a/channels.c b/channels.c index 7f04fe8a..fe939bf4 100644 --- a/channels.c +++ b/channels.c @@ -225,15 +225,6 @@ channel_find_by_identifier(int id) return ch; } - - - -static struct strtab commercial_detect_tab[] = { - { "none", COMMERCIAL_DETECT_NONE }, - { "ttp192", COMMERCIAL_DETECT_TTP192 }, -}; - - /** * */ @@ -326,10 +317,6 @@ channel_save(channel_t *ch) if(ch->ch_icon != NULL) htsmsg_add_str(m, "icon", ch->ch_icon); - htsmsg_add_str(m, "commercial-detect", - val2str(ch->ch_commercial_detection, - commercial_detect_tab) ?: "?"); - tags = htsmsg_create_array(); LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) htsmsg_add_str(tags, NULL, ctm->ctm_tag->ct_identifier); diff --git a/channels.h b/channels.h index 9aa22ebb..a98e6e51 100644 --- a/channels.h +++ b/channels.h @@ -43,14 +43,6 @@ typedef struct channel { LIST_HEAD(, th_transport) ch_transports; LIST_HEAD(, th_subscription) ch_subscriptions; - - struct tt_decoder ch_tt; - - enum { - COMMERCIAL_DETECT_NONE, - COMMERCIAL_DETECT_TTP192, - } ch_commercial_detection; - struct event_tree ch_epg_events; struct event *ch_epg_current; diff --git a/packet.h b/packet.h index f11b4f88..e53e3827 100644 --- a/packet.h +++ b/packet.h @@ -34,9 +34,9 @@ typedef struct th_pkt { int pkt_duration; int pkt_refcount; + uint8_t pkt_commercial; uint8_t pkt_componentindex; uint8_t pkt_frametype; - uint8_t pkt_commercial; uint8_t *pkt_payload; int pkt_payloadlen; diff --git a/teletext.c b/teletext.c index 2f54a235..e72938dc 100644 --- a/teletext.c +++ b/teletext.c @@ -32,8 +32,30 @@ #include "tvhead.h" #include "teletext.h" -static void teletext_rundown(th_transport_t *t, channel_t *ch, - tt_page_t *ttp); +/** + * + */ +typedef struct tt_mag { + int ttm_curpage; + uint8_t ttm_page[23*40 + 1]; +} tt_mag_t; + + +/** + * + */ +typedef struct tt_private { + tt_mag_t ttp_mags[8]; + + int ttp_rundown_valid; + uint8_t ttp_rundown[23*40 + 1]; + +} tt_private_t; + + +static void teletext_rundown_copy(tt_private_t *ttp, tt_mag_t *ttm); + +static void teletext_rundown_scan(th_transport_t *t, tt_private_t *ttp); #define bitreverse(b) \ (((b) * 0x0202020202ULL & 0x010884422010ULL) % 1023) @@ -82,42 +104,22 @@ ham_decode(uint8_t a, uint8_t b) return (b << 4) | (a & 0xf); } - -tt_page_t * -tt_get_page(tt_decoder_t *ttd, int page) -{ - tt_page_t *p; - - if(page >= 900) - return NULL; - - p = ttd->pages[page]; - - if(p == NULL) { - p = malloc(sizeof(tt_page_t)); - p->ttp_page = page; - p->ttp_subpage = 0; - p->ttp_ver = 0; - memset(p->ttp_pagebuf, ' ', 23 * 40); - p->ttp_pagebuf[40*23] = 0; - ttd->pages[page] = p; - } - return p; -} - +/** + * + */ static time_t -tt_construct_unix_time(char *buf) +tt_construct_unix_time(uint8_t *buf) { time_t t, r[3], v[3]; int i; struct tm tm; - time(&t); + t = dispatch_clock; localtime_r(&t, &tm); - tm.tm_hour = atoi(buf); - tm.tm_min = atoi(buf + 3); - tm.tm_sec = atoi(buf + 6); + tm.tm_hour = atoi((char *)buf); + tm.tm_min = atoi((char *)buf + 3); + tm.tm_sec = atoi((char *)buf + 6); r[0] = mktime(&tm); tm.tm_mday--; @@ -138,9 +140,11 @@ tt_construct_unix_time(char *buf) } - +/** + * + */ static int -str_is_tt_clock(const char *str) +is_tt_clock(const uint8_t *str) { return isdigit(str[0]) && isdigit(str[1]) && str[2] == ':' && @@ -149,19 +153,21 @@ str_is_tt_clock(const char *str) } +/** + * + */ static int -update_tt_clock(th_transport_t *t, char *buf) +update_tt_clock(th_transport_t *t, const uint8_t *buf) { - char str[10]; + uint8_t str[10]; int i; time_t ti; - for(i = 0; i < 8; i++) str[i] = buf[i] & 0x7f; str[8] = 0; - if(!str_is_tt_clock(str)) + if(!is_tt_clock(str)) return 0; ti = tt_construct_unix_time(str); @@ -169,68 +175,104 @@ update_tt_clock(th_transport_t *t, char *buf) return 0; t->tht_tt_clock = ti; + // printf("teletext clock is: %s", ctime(&ti)); return 1; } +/** + * + */ +#if 0 static void -tt_decode_line(th_transport_t *t, uint8_t *buf) +dump_page(tt_mag_t *ttm) +{ + int i, j, v; + char buf[41]; + + printf("------------------------------------------------\n"); + printf("------------------------------------------------\n"); + for(i = 0; i < 23; i++) { + + for(j = 0; j < 40; j++) { + v = ttm->ttm_page[40 * i + j]; + v &= 0x7f; + if(v < 32) + v = ' '; + buf[j] = v; + } + buf[j] = 0; + printf("%s | %x %x %x\n", buf, + ttm->ttm_page[40 * i + 0], + ttm->ttm_page[40 * i + 1], + ttm->ttm_page[40 * i + 2]); + } +} +#endif + +/** + * + */ +static void +tt_decode_line(th_transport_t *t, th_stream_t *st, uint8_t *buf) { uint8_t mpag, line, s12, s34, c; int page, magidx, i; - tt_mag_t *mag; - channel_t *ch = t->tht_ch; - tt_decoder_t *ttd = &ch->ch_tt; - tt_page_t *ttp; + tt_mag_t *ttm; + tt_private_t *ttp; + + if(st->st_priv == NULL) { + /* Allocate privdata for reassembly */ + ttp = st->st_priv = calloc(1, sizeof(tt_private_t)); + } else { + ttp = st->st_priv; + } - if(ch == NULL) - return; /* Not mapped to a channel, do not do anything */ mpag = ham_decode(buf[0], buf[1]); - magidx = mpag & 7; - mag = &ttd->mags[magidx]; + ttm = &ttp->ttp_mags[magidx]; line = mpag >> 3; if(line >= 30) return; /* Network lines, PDC, etc, dont worry about these */ - if(line == 0) { + switch(line) { + case 0: + if(ttm->ttm_curpage != 0) { - if(mag->pageptr != NULL) - mag->pageptr->ttp_ver++; + if(ttm->ttm_curpage == 192) { + // dump_page(ttm); + teletext_rundown_copy(ttp, ttm); + } - page = ham_decode(buf[2], buf[3]); - if(page == 0xff) + memset(ttm->ttm_page, ' ', 23 * 40); + ttm->ttm_curpage = 0; + } + + if((page = ham_decode(buf[2], buf[3])) == 0xff) return; /* The page is BDC encoded, mag 0 is displayed as page 800+ */ - page = (magidx ?: 8) * 100 + (page >> 4) * 10 + (page & 0xf); - - mag->pageptr = tt_get_page(ttd, page); - if(mag->pageptr == NULL) - return; + + ttm->ttm_curpage = page; s12 = ham_decode(buf[4], buf[5]); s34 = ham_decode(buf[6], buf[7]); c = ham_decode(buf[8], buf[9]); - ttd->magazine_serial = c & 0x10 ? 1 : 0; + // ttd->magazine_serial = c & 0x10 ? 1 : 0; if(s12 & 0x80) { /* Erase page */ - memset(mag->pageptr->ttp_pagebuf, ' ', 23 * 40); + memset(ttm->ttm_page, ' ', 23 * 40); } - if(update_tt_clock(t, (char *)buf + 34)) { - if(ch->ch_commercial_detection == COMMERCIAL_DETECT_TTP192) { - ttp = tt_get_page(ttd, 192); - teletext_rundown(t, ch, ttp); - } - } + if(update_tt_clock(t, buf + 34)) + teletext_rundown_scan(t, ttp); #if 0 printf("%02x: %s\n", s12, buf[9 - 4] & (1 << 7) ? "Erase" : "Not Erase"); @@ -243,31 +285,28 @@ tt_decode_line(th_transport_t *t, uint8_t *buf) printf("%s\n", buf[12 - 4] & (1 << 1) ? "Supress" : ""); #endif - } + break; - if((ttp = mag->pageptr) != NULL) { - - switch(line) { - case 1 ... 23: - for(i = 0; i < 40; i++) { - c = buf[i + 2] & 0x7f; - if(c < 32) - c += 0x80; - ttp->ttp_pagebuf[i + 40 * (line - 1)] = c; - } - break; + case 1 ... 23: + for(i = 0; i < 40; i++) { + c = buf[i + 2] & 0x7f; + if(c < 32) + c += 0x80; + ttm->ttm_page[i + 40 * (line - 1)] = c; } + break; - if(ttp->ttp_page == 192 && - ch->ch_commercial_detection == COMMERCIAL_DETECT_TTP192) - teletext_rundown(t, ch, ttp); + default: + break; } } - +/** + * + */ void -teletext_input(th_transport_t *t, uint8_t *tsb) +teletext_input(th_transport_t *t, th_stream_t *st, uint8_t *tsb) { int i, j; uint8_t *x, buf[42]; @@ -277,7 +316,7 @@ teletext_input(th_transport_t *t, uint8_t *tsb) if(*x == 2) { for(j = 0; j < 42; j++) buf[j] = bitreverse(x[4 + j]); - tt_decode_line(t, buf); + tt_decode_line(t, st, buf); } x += 46; } @@ -286,22 +325,43 @@ teletext_input(th_transport_t *t, uint8_t *tsb) +/** + * Swedish TV4 rundown dump (page 192) + * + Starttid Titel L{ngd | 20 83 53 + ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, | 94 2c 2c + 23:47:05 Reklam block 00:04:15 | 8d 83 32 + | 20 20 20 + ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, | 94 2c 2c + 23:47:30 HV3 BENGT OCH PETRA 00:00:03 | 20 86 32 + 23:47:34 S-6/6 : Spoons I 6 ( 00:10:23 | 20 87 32 + 23:57:57 RV3 FOLK I TRAPPAN 00:00:03 | 20 86 32 + 23:59:36 Reklam block 00:02:50 | 20 83 32 + 00:00:01 LINEUP13 BENGT OCH P 00:00:13 | 20 86 30 + 00:00:14 AABILO6123 00:00:13 | 20 86 30 + 00:00:28 S-4/6 : Allo Allo IV 00:10:28 | 20 87 30 + 00:10:57 RV3 VITA RENA PRICKA 00:00:03 | 20 86 30 + 00:11:00 LOKAL REKLAM 00:01:31 | 20 81 30 + 00:16:37 Reklam block 00:04:25 | 20 83 30 + 00:16:58 HV3 BYGGLOV 2 00:00:03 | 20 86 30 + 00:17:51 Trailer block 00:01:20 | 20 82 30 + 00:18:21 S-4/6 : Allo Allo IV 00:14:14 | 20 87 30 + 00:32:36 AABILO6123 00:00:13 | 20 86 30 + ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, | 94 2c 2c + se {ven rundown.tv4.se | 83 73 65 + | 83 20 20 + 23:43 | 83 20 20 -/* - *06: | 21:54:44 RV3 KYLTJEJ ST[NGER 00:00:03| - 08: | 22:10:40 RV3 KYSS 00:00:03| (0s) - */ +*/ static int -tt_time_to_len(const char *buf) +tt_time_to_len(const uint8_t *buf) { int l; char str[10]; - if(!str_is_tt_clock(buf)) - return 0; memcpy(str, buf, 8); str[2] = 0; @@ -316,59 +376,49 @@ tt_time_to_len(const char *buf) * Decode the Swedish TV4 teletext rundown page to figure out if we are * currently in a commercial break */ +static void +teletext_rundown_copy(tt_private_t *ttp, tt_mag_t *ttm) +{ + /* Sanity check */ + if(memcmp((char *)ttm->ttm_page + 2, "Starttid", strlen("Starttid")) || + memcmp((char *)ttm->ttm_page + 11,"Titel", strlen("Titel")) || + memcmp((char *)ttm->ttm_page + 20 * 40 + 9, + "rundown.tv4.se", strlen("rundown.tv4.se"))) + return; + + memcpy(ttp->ttp_rundown, ttm->ttm_page, 23 * 40); + ttp->ttp_rundown_valid = 1; +} + static void -teletext_rundown(th_transport_t *t, channel_t *ch, tt_page_t *ttp) +teletext_rundown_scan(th_transport_t *t, tt_private_t *ttp) { - char r[50]; int i; - time_t ti, d, l; - int curlen = -1; - th_commercial_advice_t prev; + uint8_t *l; + time_t now = t->tht_tt_clock, start, stop, last = 0; + th_commercial_advice_t ca; -#if 0 - printf("%c", 0x0c); - printf("%-20s %s\n", - t->tht_tt_rundown_content_length > 400 ? "real stuff" : "commercial", - ctime(&t->tht_tt_clock)); -#endif - for(i = 0; i < 22; i++) { - memcpy(r, &ttp->ttp_pagebuf[i * 40], 40); - r[40] = 0; - - if(!str_is_tt_clock(r + 2)) { - continue; - } - ti = tt_construct_unix_time(r + 2); - l = tt_time_to_len(r + 32); - d = ti - t->tht_tt_clock; - - if(d < 1) { - /* Currently playing show */ - curlen = l; - } - // printf("%02d|%s|\t(%5lds) : %ld, %d\n", i, r, l, d, curlen); - } - - t->tht_tt_rundown_content_length = curlen; - - prev = t->tht_tt_commercial_advice; - - if(curlen < 0) + if(ttp->ttp_rundown_valid == 0) return; - if(curlen < 400) - t->tht_tt_commercial_advice = COMMERCIAL_YES; - else - t->tht_tt_commercial_advice = COMMERCIAL_NO; + for(i = 0; i < 23; i++) { + l = ttp->ttp_rundown + 40 * i; + if((l[1] & 0xf0) != 0x80 || !is_tt_clock(l + 32) || !is_tt_clock(l + 2)) + continue; + + if(!memcmp(l + 11, "Nyhetspuff", strlen("Nyhetspuff"))) + ca = COMMERCIAL_YES; + else + ca = (l[1] & 0xf) == 7 ? COMMERCIAL_NO : COMMERCIAL_YES; - if(prev != t->tht_tt_commercial_advice) { - - tvhlog(LOG_DEBUG, "teletext", - "teletext-rundown: \"%s\" on \"%s\": " - "%s commercial break (chunk %ds)", - ch->ch_name, t->tht_name, - t->tht_tt_commercial_advice == COMMERCIAL_YES ? "In" : "Not in", - curlen); + start = tt_construct_unix_time(l + 2); + stop = start + tt_time_to_len(l + 32); + + if(start <= now && stop > now) + t->tht_tt_commercial_advice = ca; + + if(start > now && ca != t->tht_tt_commercial_advice && last == 0) + last = start; } } diff --git a/teletext.h b/teletext.h index 64b92e4d..fe225152 100644 --- a/teletext.h +++ b/teletext.h @@ -19,8 +19,6 @@ #ifndef TELETEXT_H #define TELETEXT_H -void teletext_input(th_transport_t *t, uint8_t *tsb); - -tt_page_t *tt_get_page(tt_decoder_t *ttd, int page); +void teletext_input(th_transport_t *t, th_stream_t *st, uint8_t *tsb); #endif /* TELETEXT_H */ diff --git a/tsdemux.c b/tsdemux.c index 0ba3cd9e..87d9a658 100644 --- a/tsdemux.c +++ b/tsdemux.c @@ -126,7 +126,7 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, uint8_t *tsb) break; case SCT_TELETEXT: - // teletext_input(t, tsb); + teletext_input(t, st, tsb); break; default: diff --git a/tvhead.h b/tvhead.h index e2f783b3..9b1fc0c9 100644 --- a/tvhead.h +++ b/tvhead.h @@ -832,29 +832,6 @@ typedef struct th_muxstream { #endif -/* - * Teletext - */ -typedef struct tt_page { - int ttp_page; - int ttp_subpage; - int ttp_ver; - unsigned char ttp_pagebuf[23*40 + 1]; -} tt_page_t; - -typedef struct tt_mag { - tt_page_t *pageptr; -} tt_mag_t; - -typedef struct tt_decoder { - tt_mag_t mags[8]; - tt_page_t *pages[900]; - int magazine_serial; -} tt_decoder_t; - - - - char *utf8toprintable(const char *in); char *utf8tofilename(const char *in); const char *streaming_component_type2txt(streaming_component_type_t s);