From: Jaroslav Kysela Date: Sat, 20 May 2017 18:41:28 +0000 (+0200) Subject: HBBTV: collect AIT PSI table X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7143df05a7e4491b591455f566fdff06ca7d5ba9;p=thirdparty%2Ftvheadend.git HBBTV: collect AIT PSI table --- diff --git a/Makefile b/Makefile index c286c1b06..4592d6a8c 100644 --- a/Makefile +++ b/Makefile @@ -361,6 +361,7 @@ SRCS-MPEGTS = \ src/input/mpegts/mpegts_pid.c \ src/input/mpegts/mpegts_input.c \ src/input/mpegts/tsdemux.c \ + src/input/mpegts/dvb_psi_hbbtv.c \ src/input/mpegts/dvb_psi_lib.c \ src/input/mpegts/mpegts_network.c \ src/input/mpegts/mpegts_mux.c \ diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h index a4217dba1..45b88b67e 100644 --- a/src/input/mpegts/dvb.h +++ b/src/input/mpegts/dvb.h @@ -168,6 +168,19 @@ struct lang_str; #define DVB_DESC_FREESAT_LCN 0xD3 #define DVB_DESC_FREESAT_REGIONS 0xD4 +/* HBBTV */ +#define DVB_DESC_APP 0x00 +#define DVB_DESC_APP_NAME 0x01 +#define DVB_DESC_APP_TRANSPORT 0x02 +#define DVB_DESC_APP_EXT_AUTH 0x05 +#define DVB_DESC_APP_REC 0x06 +#define DVB_DESC_APP_ICONS 0x0B +#define DVB_DESC_APP_STORAGE 0x10 +#define DVB_DESC_APP_GRAPHICS_CONSTR 0x14 +#define DVB_DESC_APP_SIMPLE_LOCATION 0x15 +#define DVB_DESC_APP_USAGE 0x16 +#define DVB_DESC_APP_SIMPLE_BOUNDARY 0x17 + /* Descriptors defined in A/65:2009 */ #define ATSC_DESC_STUFFING 0x80 @@ -228,7 +241,7 @@ do {\ lptr = 2 + off + ptr;\ ptr += 2 + off + llen;\ len -= 2 + off + llen;\ - if (len < 0) {tvhtrace(mt->mt_subsys, "%s: len < 0", mt->mt_name); return -1; }\ + if (len < 0) {tvhtrace(mt->mt_subsys, "%s: len < 0", mt->mt_name);goto dvberr;}\ } while(0) #define DVB_LOOP_EACH(ptr, len, min)\ @@ -239,13 +252,9 @@ do {\ DVB_LOOP_EACH(lptr, llen, min) #define DVB_DESC_EACH(mt, ptr, len, dtag, dlen, dptr)\ - DVB_LOOP_EACH(ptr, len, 2)\ - if (!(dtag = ptr[0])) {tvhtrace(mt->mt_subsys, "%s: 1", mt->mt_name);return -1;}\ - else if ((dlen = ptr[1]) < 0) {tvhtrace(mt->mt_subsys, "%s: 2", mt->mt_name);return -1;}\ - else if (!(dptr = ptr+2)) {tvhtrace(mt->mt_subsys, "%s: 3", mt->mt_name);return -1;}\ - else if ( (len -= 2 + dlen) < 0) {tvhtrace(mt->mt_subsys, "%s: 4", mt->mt_name);return -1;}\ - else if (!(ptr += 2 + dlen)) {tvhtrace(mt->mt_subsys, "%s: 5", mt->mt_name);return -1;}\ - else + DVB_LOOP_EACH(ptr, len, 2) { \ + dtag = ptr[0], dlen = ptr[1], dptr = ptr+2, ptr += 2+dlen; \ + if ((len -= 2+dlen) < 0) {tvhtrace(mt->mt_subsys, "%s: dlen < 0", mt->mt_name);goto dvberr;}\ #define DVB_DESC_FOREACH(mt, ptr, len, off, lptr, llen, dtag, dlen, dptr)\ DVB_LOOP_INIT(mt, ptr, len, off, lptr, llen);\ diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index ed09856a1..1b0bc1cee 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -1328,9 +1328,12 @@ lcn: #endif break; } - } + }} return lptr - lptr_orig; + +dvberr: + return -1; } int @@ -1458,7 +1461,7 @@ dvb_nit_callback #endif break; } - } + }} /* Fastscan */ if (tableid == DVB_FASTSCAN_NIT_BASE) { @@ -1528,6 +1531,9 @@ dvb_nit_callback if (retry) return 0; return dvb_table_end((mpegts_psi_table_t *)mt, st, sect); + +dvberr: + return -1; } /** @@ -1598,7 +1604,7 @@ dvb_sdt_mux return -1; break; } - } + }} tvhtrace(mt->mt_subsys, "%s: type %02X (%d) name [%s] provider [%s] def_auth [%s]", mt->mt_name, stype, stype, sname, sprov, sauth); @@ -1665,6 +1671,9 @@ dvb_sdt_mux } return 0; + +dvberr: + return -1; } int @@ -1926,7 +1935,7 @@ dvb_fs_sdt_mux } break; } - } + }} continue; } @@ -1955,7 +1964,7 @@ dvb_fs_sdt_mux return -1; break; } - } + }} tvhtrace(mt->mt_subsys, "%s: type %d name [%s] provider [%s]", mt->mt_name, stype, sname, sprov); @@ -2012,6 +2021,9 @@ dvb_fs_sdt_mux } return 0; + +dvberr: + return -1; } diff --git a/src/input/mpegts/dvb_psi_hbbtv.c b/src/input/mpegts/dvb_psi_hbbtv.c new file mode 100644 index 000000000..b13dee7e0 --- /dev/null +++ b/src/input/mpegts/dvb_psi_hbbtv.c @@ -0,0 +1,186 @@ +/* + * tvheadend, MPEG transport stream demuxer + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tvheadend.h" +#include "streaming.h" +#include "parsers.h" +#include "tsdemux.h" +#include "htsmsg.h" +#include "htsmsg_binary.h" + +/** + * Extract Hbbtv + */ +void +ts_recv_hbbtv_cb(mpegts_psi_table_t *mt, const uint8_t *buf, int len) +{ + static const char *visibility_table[4] = { + "none", + "apps", + "reserved", + "all", + }; + elementary_stream_t *st = (elementary_stream_t *)mt->mt_opaque; + service_t *t = st->es_service; + mpegts_psi_table_state_t *tst = NULL; + int r, sect, last, ver, l, l2, l3, dllen, dlen, flags; + uint8_t tableid = buf[0], dtag; + const uint8_t *p, *dlptr, *dptr; + uint16_t app_type, app_id, protocol_id; + uint32_t org_id; + char title[256], name[256], location[256], *str; + htsmsg_t *map, *apps = NULL, *titles = NULL; + void *bin; + size_t binlen; + + if (tableid != 0x74 || len < 16) + return; + app_type = (buf[3] << 8) | buf[4]; + if (app_type & 1) /* testing */ + return; + + r = dvb_table_begin(mt, buf + 3, len - 3, + tableid, app_type, 5, &tst, §, &last, &ver); + if (r != 1) return; + + p = buf; + l = len; + + DVB_DESC_FOREACH(mt, p, l, 8, dlptr, dllen, dtag, dlen, dptr) { + tvhtrace(mt->mt_subsys, "%s: common dtag %02X dlen %d", mt->mt_name, dtag, dlen); + }} + + l2 = ((p[0] << 8) | p[1]) & 0xfff; + p += 2; + l += 2; + while (l2 >= 9) { + org_id = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + app_id = (p[4] << 8) | p[5]; + tvhtrace(mt->mt_subsys, "%s: app org %08X id %04X control %02X", mt->mt_name, org_id, app_id, p[6]); + l2 -= 9; + title[0] = name[0] = location[0] = '\0'; + titles = NULL; + flags = 0; + DVB_DESC_FOREACH(mt, p, l, 7, dlptr, dllen, dtag, dlen, dptr) { + l2 -= dlen + 2; + tvhtrace(mt->mt_subsys, "%s: dtag %02X dlen %d", mt->mt_name, dtag, dlen); + switch (dtag) { + case DVB_DESC_APP: + l3 = *dptr++; dlen--; + if (l3 % 5) goto dvberr; + while (l3 >= 5) { + tvhtrace(mt->mt_subsys, "%s: profile %04X %d.%d.%d", mt->mt_name, (dptr[0] << 8) | dptr[1], dptr[2], dptr[3], dptr[4]); + dptr += 5; + dlen -= 5; + l3 -= 5; + } + if (dlen < 3) goto dvberr; + flags = dptr[0]; + tvhtrace(mt->mt_subsys, "%s: flags %02X prio %02X", mt->mt_name, dptr[0], dptr[1]); + dptr += 2; + dlen -= 2; + while (dlen-- > 0) { + tvhtrace(mt->mt_subsys, "%s: transport protocol label %02X", mt->mt_name, dptr[0]); + dptr++; + } + break; + case DVB_DESC_APP_NAME: + titles = htsmsg_create_list(); + while (dlen > 4) { + r = dvb_get_string_with_len(title, sizeof(title), dptr + 3, dlen - 3, "UTF-8", NULL); + if (r < 0) goto dvberr; + tvhtrace(mt->mt_subsys, "%s: lang '%c%c%c' name '%s'", mt->mt_name, dptr[0], dptr[1], dptr[2], title); + map = htsmsg_create_map(); + htsmsg_add_str(map, "name", title); + memcpy(title, dptr, 3); + title[3] = '\0'; + htsmsg_add_str(map, "lang", title); + htsmsg_add_msg(titles, NULL, map); + dptr += r; + dlen -= r; + } + break; + case DVB_DESC_APP_TRANSPORT: + if (dlen < 4) goto dvberr; + protocol_id = (dptr[0] << 8) | dptr[1]; + tvhtrace(mt->mt_subsys, "%s: protocol_id %04X transport protocol label %02X", mt->mt_name, protocol_id, dptr[2]); + dptr += 3; dlen -= 3; + if (protocol_id == 0x0003) { + r = dvb_get_string_with_len(name, sizeof(name), dptr, dlen, "UTF-8", NULL); + if (r < 0) goto dvberr; + tvhtrace(mt->mt_subsys, "%s: http '%s'", mt->mt_name, name); + } else { + while (dlen-- > 0) { + tvhtrace(mt->mt_subsys, "%s: selector %02X", mt->mt_name, dptr[0]); + dptr++; + } + } + break; + case DVB_DESC_APP_SIMPLE_LOCATION: + r = dvb_get_string(location, sizeof(location), dptr, dlen, "UTF-8", NULL); + if (r < 0) goto dvberr; + tvhtrace(mt->mt_subsys, "%s: simple location '%s'", mt->mt_name, location); + break; + } + }} + if (titles && name[0] && location[0]) { + map = htsmsg_create_map(); + htsmsg_add_msg(map, "title", titles); + titles = NULL; + str = malloc(strlen(name) + strlen(location) + 1); + strcpy(str, name); + strcat(str, location); + htsmsg_add_str(map, "url", str); + free(str); + if (apps == NULL) + apps = htsmsg_create_list(); + htsmsg_add_str(map, "visibility", visibility_table[(flags >> 5) & 3]); + htsmsg_add_msg(apps, NULL, map); + } else { + htsmsg_destroy(titles); + } + } + if (l2 != 0) + goto dvberr; + + dvb_table_end(mt, tst, sect); + + if (t->s_hbbtv == NULL) + t->s_hbbtv = htsmsg_create_map(); + if (apps) { + snprintf(location, sizeof(location), "%d", sect); + htsmsg_set_msg(t->s_hbbtv, location, apps); + apps = NULL; + service_request_save(t, 0); + } + + if (streaming_pad_probe_type(&t->s_streaming_pad, SMT_PACKET)) { + parse_mpeg_ts(t, st, buf, len, 1, 0); + if (t->s_hbbtv) { + if (!htsmsg_binary_serialize(t->s_hbbtv, &bin, &binlen, 128*1024)) { + parse_mpeg_ts(t, st, bin, binlen, 1, 0); + free(bin); + } + } + } + +dvberr: + htsmsg_destroy(apps); + htsmsg_destroy(titles); + return; +} diff --git a/src/input/mpegts/dvb_psi_lib.c b/src/input/mpegts/dvb_psi_lib.c index aa2ec3ef6..56460ab46 100644 --- a/src/input/mpegts/dvb_psi_lib.c +++ b/src/input/mpegts/dvb_psi_lib.c @@ -401,7 +401,9 @@ void dvb_table_parse_init void dvb_table_parse_done( mpegts_psi_table_t *mt ) { + dvb_table_release(mt); free(mt->mt_name); + mt->mt_name = NULL; } struct psi_parse { diff --git a/src/input/mpegts/tsdemux.c b/src/input/mpegts/tsdemux.c index c8cee5636..d1f39f848 100644 --- a/src/input/mpegts/tsdemux.c +++ b/src/input/mpegts/tsdemux.c @@ -15,22 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#define _GNU_SOURCE -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include #include "tvheadend.h" #include "subscriptions.h" @@ -211,6 +195,11 @@ ts_recv_packet0 if (st->es_type == SCT_CA) continue; + if (st->es_type == SCT_HBBTV) { + dvb_table_parse(&st->es_psi, "ts", tsb2, 188, 1, 0, ts_recv_hbbtv_cb); + continue; + } + if (off <= 188 && t->s_status == SERVICE_RUNNING) parse_mpeg_ts((service_t*)t, st, tsb2 + off, 188 - off, pusi, error); diff --git a/src/input/mpegts/tsdemux.h b/src/input/mpegts/tsdemux.h index f726013c3..d90840d77 100644 --- a/src/input/mpegts/tsdemux.h +++ b/src/input/mpegts/tsdemux.h @@ -33,4 +33,6 @@ void ts_skip_packet2(struct mpegts_service *t, const uint8_t *tsb, int len); void ts_recv_raw(struct mpegts_service *t, const uint8_t *tsb, int len); +void ts_recv_hbbtv_cb(mpegts_psi_table_t *mt, const uint8_t *buf, int len); + #endif /* TSDEMUX_H */ diff --git a/src/parsers/parsers.c b/src/parsers/parsers.c index df274aee6..16b98a207 100644 --- a/src/parsers/parsers.c +++ b/src/parsers/parsers.c @@ -94,6 +94,9 @@ static void parse_subtitles(service_t *t, elementary_stream_t *st, static void parse_teletext(service_t *t, elementary_stream_t *st, const uint8_t *data, int len, int start); +static void parse_hbbtv(service_t *t, elementary_stream_t *st, + const uint8_t *data, int len, int start); + static int parse_mpa(service_t *t, elementary_stream_t *st, size_t len, uint32_t next_startcode, int sc_offset); @@ -197,6 +200,10 @@ parse_mpeg_ts(service_t *t, elementary_stream_t *st, const uint8_t *data, parse_teletext(t, st, data, len, start); break; + case SCT_HBBTV: + parse_hbbtv(t, st, data, len, start); + break; + default: break; } @@ -1792,6 +1799,18 @@ parse_teletext(service_t *t, elementary_stream_t *st, const uint8_t *data, } } +/** + * Hbbtv parser (=forwarder) + */ +static void +parse_hbbtv(service_t *t, elementary_stream_t *st, const uint8_t *data, + int len, int start) +{ + th_pkt_t *pkt = pkt_alloc(st->es_type, data, len, t->s_current_pcr, t->s_current_pcr, t->s_current_pcr); + pkt->pkt_err = st->es_buf.sb_err; + parser_deliver(t, st, pkt); +} + /** * */ diff --git a/src/service.c b/src/service.c index 05fa172fa..6d93dda60 100644 --- a/src/service.c +++ b/src/service.c @@ -277,6 +277,9 @@ stream_init(elementary_stream_t *st) st->es_blank = 0; + if (st->es_type == SCT_HBBTV) + dvb_table_parse_init(&st->es_psi, "hbbtv", LS_TS, st->es_pid, st); + TAILQ_INIT(&st->es_backlog); } @@ -328,6 +331,9 @@ service_stream_destroy(service_t *t, elementary_stream_t *es) if(t->s_status == SERVICE_RUNNING) stream_clean(es); + if (es->es_psi.mt_name) + dvb_table_parse_done(&es->es_psi); + if (t->s_last_es == es) { t->s_last_pid = -1; t->s_last_es = NULL; @@ -955,6 +961,11 @@ service_destroy(service_t *t, int delconf) while((st = TAILQ_FIRST(&t->s_components)) != NULL) service_stream_destroy(t, st); + if (t->s_hbbtv) { + htsmsg_destroy(t->s_hbbtv); + t->s_hbbtv = NULL; + } + switch (t->s_type) { case STYPE_RAW: TAILQ_REMOVE(&service_raw_all, t, s_all_link); @@ -2002,7 +2013,7 @@ htsmsg_t *servicetype_list ( void ) void service_save ( service_t *t, htsmsg_t *m ) { elementary_stream_t *st; - htsmsg_t *list, *sub; + htsmsg_t *list, *sub, *hbbtv; idnode_save(&t->s_id, m); @@ -2066,8 +2077,14 @@ void service_save ( service_t *t, htsmsg_t *m ) htsmsg_add_msg(list, NULL, sub); } + + hbbtv = htsmsg_copy(t->s_hbbtv); + pthread_mutex_unlock(&t->s_stream_mutex); + htsmsg_add_msg(m, "stream", list); + if (hbbtv) + htsmsg_add_msg(m, "hbbtv", hbbtv); } /** @@ -2190,7 +2207,7 @@ load_caid(htsmsg_t *m, elementary_stream_t *st) void service_load ( service_t *t, htsmsg_t *c ) { - htsmsg_t *m; + htsmsg_t *m, *hbbtv; htsmsg_field_t *f; uint32_t u32, pid; elementary_stream_t *st; @@ -2204,6 +2221,14 @@ void service_load ( service_t *t, htsmsg_t *c ) if(!htsmsg_get_u32(c, "pmt", &u32)) t->s_pmt_pid = u32; + hbbtv = htsmsg_get_map(c, "hbbtv"); + if (hbbtv) { + t->s_hbbtv = htsmsg_copy(hbbtv); + } else { + htsmsg_destroy(t->s_hbbtv); + t->s_hbbtv = NULL; + } + pthread_mutex_lock(&t->s_stream_mutex); m = htsmsg_get_list(c, "stream"); if (m) { diff --git a/src/service.h b/src/service.h index 75d50cc49..fcbf2e077 100644 --- a/src/service.h +++ b/src/service.h @@ -23,6 +23,7 @@ #include "idnode.h" #include "profile.h" #include "descrambler.h" +#include "input/mpegts/dvb.h" extern const idclass_t service_class; extern const idclass_t service_raw_class; @@ -144,6 +145,9 @@ typedef struct elementary_stream { /* Filter temporary variable */ uint32_t es_filter; + /* HBBTV PSI table (AIT) */ + mpegts_psi_table_t es_psi; + } elementary_stream_t; @@ -501,6 +505,11 @@ typedef struct service { */ LIST_HEAD(,service_lcn) s_lcns; + /* + * HBBTV + */ + htsmsg_t *s_hbbtv; + } service_t;