From 8fb4324bbec42ebcf6b39eb58b7328c91860e644 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Tue, 26 Jun 2012 12:06:45 +0100 Subject: [PATCH] Updates to the new OpenTV code based on early testing on bombadil and some cleanup. This code is untested. --- src/epg.c | 2 +- src/epg.h | 4 +- src/epggrab/opentv.c | 202 +++++++++++++++++++++++++------------------ src/epggrab/ota.c | 9 +- src/epggrab/ota.h | 1 + 5 files changed, 128 insertions(+), 90 deletions(-) diff --git a/src/epg.c b/src/epg.c index fab96adb..1e7c0fef 100644 --- a/src/epg.c +++ b/src/epg.c @@ -1433,7 +1433,7 @@ epg_broadcast_t *epg_broadcast_find_by_id ( uint64_t id, channel_t *ch ) return (epg_broadcast_t*)_epg_object_find_by_id(id); } -epg_broadcast_t *epg_broadcast_find_by_eid ( int eid, channel_t *ch ) +epg_broadcast_t *epg_broadcast_find_by_eid ( channel_t *ch, int eid ) { epg_broadcast_t *e; RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) { diff --git a/src/epg.h b/src/epg.h index c64f6de1..a40527e0 100644 --- a/src/epg.h +++ b/src/epg.h @@ -320,8 +320,8 @@ struct epg_broadcast epg_broadcast_t *epg_broadcast_find_by_time ( struct channel *ch, time_t start, time_t stop, uint16_t eid, int create, int *save ); -epg_broadcast_t *epg_broadcast_find_by_id ( uint64_t id, struct channel *ch ); -epg_broadcast_t *epg_broadcast_find_by_eid ( int eid, struct channel *ch ); +epg_broadcast_t *epg_broadcast_find_by_eid ( struct channel *ch, int eid ); +epg_broadcast_t *epg_broadcast_find_by_id ( uint64_t id, struct channel *ch ); /* Mutators */ int epg_broadcast_set_episode ( epg_broadcast_t *b, epg_episode_t *e ) diff --git a/src/epggrab/opentv.c b/src/epggrab/opentv.c index 806dbf0b..b7ec3134 100644 --- a/src/epggrab/opentv.c +++ b/src/epggrab/opentv.c @@ -67,7 +67,6 @@ typedef struct opentv_dict huffman_node_t *codes; RB_ENTRY(opentv_dict) h_link; } opentv_dict_t; - int begbat; /* Provider configuration */ typedef struct opentv_module_t @@ -117,6 +116,7 @@ static opentv_status_t *_opentv_module_get_status if (sta->pid == pid) break; if (!sta) { sta = calloc(1, sizeof(opentv_status_t)); + sta->pid = pid; LIST_INSERT_HEAD(&mod->status, sta, link); } return sta; @@ -137,8 +137,9 @@ static int* _pid_list_to_array ( htsmsg_t *m, opentv_module_t *mod ) i = 0; HTSMSG_FOREACH(f, m) if (f->hmf_s64) { + ret[i] = (int)f->hmf_s64; if (mod) (void)_opentv_module_get_status(mod, ret[i]); - ret[i++] = (int)f->hmf_s64; + i++; } return ret; } @@ -316,7 +317,7 @@ typedef struct opentv_event uint8_t cat; ///< Event category uint16_t series; ///< Series (link) reference - uint8_t status; ///< 0x1=title, 0x2=summary + uint8_t type; ///< 0x1=title, 0x2=summary } opentv_event_t; /* List of partial events */ @@ -340,9 +341,9 @@ static char *_opentv_parse_string char *ret, *tmp; // Note: unlikely decoded string will be longer (though its possible) - ret = tmp = malloc(len+1); + ret = tmp = malloc(2*len); *ret = 0; - if (huffman_decode(prov->dict->codes, buf, len, 0x20, tmp, len)) { + if (huffman_decode(prov->dict->codes, buf, len, 0x20, tmp, 2*len)) { /* Ignore (empty) strings */ while (*tmp) { @@ -362,7 +363,8 @@ static char *_opentv_parse_string /* Parse a specific record */ static int _opentv_parse_event_record - ( opentv_module_t *prov, opentv_event_t *ev, uint8_t *buf, int len, time_t mjd ) + ( opentv_module_t *prov, opentv_event_t *ev, uint8_t *buf, int len, + time_t mjd ) { uint8_t rtag = buf[0]; uint8_t rlen = buf[1]; @@ -398,27 +400,29 @@ static int _opentv_parse_event_record /* Parse a specific event */ static int _opentv_parse_event ( opentv_module_t *prov, uint8_t *buf, int len, int cid, time_t mjd, - opentv_event_t **ev ) + opentv_event_t *ev, int type ) { - static opentv_event_t *skel = NULL; int slen = ((int)buf[2] & 0xf << 8) | buf[3]; int i = 4; + opentv_event_t *e; - /* Create/Find event entry */ - if (!skel) skel = calloc(1, sizeof(opentv_event_t)); - skel->cid = cid; - skel->eid = ((uint16_t)buf[0] << 8) | buf[1]; - *ev = RB_INSERT_SORTED(&_opentv_events, skel, ev_link, _ev_cmp); - if (!*ev) { - *ev = skel; - skel = NULL; + ev->cid = cid; + ev->eid = ((uint16_t)buf[0] << 8) | buf[1]; + + /* Get existing summary */ + if ( type == OPENTV_TITLE ) { + e = RB_FIND(&_opentv_events, ev, ev_link, _ev_cmp); + if (e) { + RB_REMOVE(&_opentv_events, e, ev_link); + memcpy(ev, e, sizeof(opentv_event_t)); + free(e); + } } + ev->type |= type; /* Process records */ - if (*ev) { - while (i < slen+4) { - i += _opentv_parse_event_record(prov, *ev, buf+i, len-i, mjd); - } + while (i < slen+4) { + i += _opentv_parse_event_record(prov, ev, buf+i, len-i, mjd); } return slen+4; } @@ -434,7 +438,7 @@ static int _opentv_parse_event_section epg_broadcast_t *ebc; epg_episode_t *ee; epg_season_t *es; - opentv_event_t *ev; + opentv_event_t ev; /* Channel */ cid = ((int)buf[0] << 8) | buf[1]; @@ -449,54 +453,66 @@ static int _opentv_parse_event_section /* Loop around event entries */ i = 7; while (i < len) { - i += _opentv_parse_event(mod, buf+i, len-i, cid, mjd, &ev); + memset(&ev, 0, sizeof(opentv_event_t)); + i += _opentv_parse_event(mod, buf+i, len-i, cid, mjd, &ev, type); - /* Error */ - if (!ev) continue; + /* Find broadcast */ + if (ev.type & OPENTV_TITLE) { + ebc = epg_broadcast_find_by_time(ec->channel, ev.start, ev.stop, ev.eid, + 1, &save); + } else { + ebc = epg_broadcast_find_by_eid(ec->channel, ev.eid); - /* Incomplete */ - ev->status |= type; - if (ev->status != (OPENTV_TITLE | OPENTV_SUMMARY)) continue; + /* Store */ + if (!ebc) { + opentv_event_t *skel = malloc(sizeof(opentv_event_t)); + memcpy(skel, &ev, sizeof(opentv_event_t)); + assert(!RB_INSERT_SORTED(&_opentv_events, skel, ev_link, _ev_cmp)); + continue; // don't want to free() anything + } + } /* Find episode */ - uri = epg_hash(ev->title, ev->summary, ev->desc); - if (uri) { - ee = epg_episode_find_by_uri(uri, 1, &save); - free(uri); - } else { - ee = NULL; - } + if (ebc) { + ee = NULL; - /* Set episode data */ - if (ee) { - if (ev->title) - save |= epg_episode_set_title(ee, ev->title); - if (ev->summary) - save |= epg_episode_set_summary(ee, ev->summary); - if (ev->desc) - save |= epg_episode_set_description(ee, ev->desc); - if (ev->cat) - save |= epg_episode_set_genre(ee, &ev->cat, 1); - // Note: don't override the season (since the ID is channel specific - // it'll keep changing! - if (ev->series && !ee->season) { - es = _opentv_find_season(mod, cid, ev->series); - if (es) save |= epg_episode_set_season(ee, es); + /* Find episode */ + if (ev.type & OPENTV_SUMMARY || !ebc->episode) { + uri = epg_hash(ev.title, ev.summary, ev.desc); + if (uri) { + ee = epg_episode_find_by_uri(uri, 1, &save); + free(uri); + } } - /* Find broadcast */ - ebc = epg_broadcast_find_by_time(ec->channel, ev->start, ev->stop, - ev->eid, 1, &save); - if (ebc) + /* Use existing */ + if (!ee) ee = ebc->episode; + + /* Update */ + if (ee) { + if (ev.title) + save |= epg_episode_set_title(ee, ev.title); + if (ev.summary) + save |= epg_episode_set_summary(ee, ev.summary); + if (ev.desc) + save |= epg_episode_set_description(ee, ev.desc); + if (ev.cat) + save |= epg_episode_set_genre(ee, &ev.cat, 1); + // Note: don't override the season (since the ID is channel specific + // it'll keep changing! + if (ev.series && !ee->season) { + es = _opentv_find_season(mod, cid, ev.series); + if (es) save |= epg_episode_set_season(ee, es); + } + save |= epg_broadcast_set_episode(ebc, ee); + } } - /* Remove and cleanup */ - RB_REMOVE(&_opentv_events, ev, ev_link); - if (ev->title) free(ev->title); - if (ev->summary) free(ev->summary); - if (ev->desc) free(ev->desc); - free(ev); + /* Cleanup */ + if (ev.title) free(ev.title); + if (ev.summary) free(ev.summary); + if (ev.desc) free(ev.desc); } /* Update EPG */ @@ -508,7 +524,7 @@ static int _opentv_parse_event_section * OpenTV channel processing * ***********************************************************************/ -static void _opentv_parse_sky_channels +static void _opentv_parse_channels ( opentv_module_t *mod, uint8_t *buf, int len, uint16_t tsid ) { epggrab_channel_t *ec; @@ -541,7 +557,7 @@ static int _opentv_parse_ts_desc int dlen = buf[1]; if (dlen+2 > len) return -1; if (dtag == 0xb1) - _opentv_parse_sky_channels(mod, buf+2, dlen, tsid); + _opentv_parse_channels(mod, buf+2, dlen, tsid); return dlen + 2; } @@ -561,6 +577,8 @@ static int _opentv_bat_section //lst = buf[4]; /* Check for finish */ + // Note: this is NOT the most robust of approaches, but it works + // most of the time i = 0x80000000 | (bid << 8) | sec; if (!mod->begbat) { mod->begbat = i; @@ -571,12 +589,12 @@ static int _opentv_bat_section /* Skip (ignore bouquet info for now) */ bdlen = ((int)buf[5] & 0xf << 8) | buf[6]; + if (bdlen+7 > len) return -1; buf += (7 + bdlen); len -= (7 + bdlen); - if (bdlen > len) return -1; /* TS descriptors */ - tllen = ((int)buf[0] << 8) | buf[1]; + tllen = ((int)buf[0] & 0xf << 8) | buf[1]; buf += 2; len -= 2; if (tllen > len) return -1; @@ -611,6 +629,9 @@ static opentv_module_t *_opentv_table_callback opentv_module_t *mod = (opentv_module_t*)tdt->tdt_opaque; epggrab_ota_mux_t *ota; opentv_status_t *sta; + + /* Ignore BAT not complete */ + if (!mod->endbat) return NULL; /* Ignore (not enough data) */ if (len < 20) return NULL; @@ -620,30 +641,53 @@ static opentv_module_t *_opentv_table_callback OPENTV_SCAN_MAX, OPENTV_SCAN_PER); if (!ota) return NULL; - /* Finished */ + /* Finished / Blocked */ if (epggrab_ota_is_complete(ota)) return NULL; + if (epggrab_ota_is_blocked(ota)) return NULL; - /* Begin */ - epggrab_ota_begin(ota); + /* Begin (reset state) */ + if (epggrab_ota_begin(ota)) { + opentv_event_t *ev; + + /* Remove outstanding event data */ + while ((ev = RB_FIRST(&_opentv_events))) { + RB_REMOVE(&_opentv_events, ev, ev_link); + if (ev->title) free(ev->title); + if (ev->desc) free(ev->desc); + if (ev->summary) free(ev->summary); + free(ev); + } + + /* Reset status */ + LIST_FOREACH(sta, &mod->status, link) + sta->status = OPENTV_STA_INIT; + } /* Insert/Find */ sta = _opentv_module_get_status(mod, tdt->tdt_pid); - /* Set init */ - if (!sta->status) { + /* Begin PID */ + if (sta->status == OPENTV_STA_INIT) { sta->status = OPENTV_STA_STARTED; memcpy(sta->start, buf, 20); return mod; + + /* PID Already complete */ + } else if (sta->status == OPENTV_STA_COMPLETE) { + return NULL; - /* Complete */ - } else if (sta->status == OPENTV_STA_STARTED && - !memcmp(sta->start, buf, 20)) { + /* End PID */ + } else if (!memcmp(sta->start, buf, 20)) { sta->status = OPENTV_STA_COMPLETE; /* Check rest */ LIST_FOREACH(sta, &mod->status, link) if (sta->status != OPENTV_STA_COMPLETE) return mod; - } + + /* PID in progress */ + } else { + return mod; + } /* Mark complete */ epggrab_ota_complete(ota); @@ -687,8 +731,6 @@ static void _opentv_tune ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi ) int *t; struct dmx_sct_filter_params *fp; opentv_module_t *mod = (opentv_module_t*)m; - opentv_event_t *ev; - opentv_status_t *sta; /* Install tables */ if (m->enabled && (mod->tsid == tdmi->tdmi_transport_stream_id)) { @@ -725,18 +767,8 @@ static void _opentv_tune ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi ) m->id, TDT_CRC | TDT_TDT, *t++, NULL); } - /* Clear status (new search) */ - // TODO: not sure about this! + /* Must rebuild the BAT */ mod->begbat = mod->endbat = 0; - LIST_FOREACH(sta, &mod->status, link) - sta->status = OPENTV_STA_INIT; - while((ev = RB_FIRST(&_opentv_events))) { - RB_REMOVE(&_opentv_events, ev, ev_link); - if (ev->title) free(ev->title); - if (ev->desc) free(ev->desc); - if (ev->summary) free(ev->summary); - free(ev); - } } } diff --git a/src/epggrab/ota.c b/src/epggrab/ota.c index a1f3b5bb..2804a616 100644 --- a/src/epggrab/ota.c +++ b/src/epggrab/ota.c @@ -109,11 +109,16 @@ void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ) void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ) { epggrab_ota_complete(ota); - // TODO: for now just treat as completed, stops it being allowed - // to immediately re-enter the queue } int epggrab_ota_is_complete ( epggrab_ota_mux_t *ota ) { return ota->status == EPGGRAB_OTA_COMPLETED; } + +int epggrab_ota_is_blocked ( epggrab_ota_mux_t *ota ) +{ + time_t t; + time(&t); + return t < (ota->completed + ota->interval); +} diff --git a/src/epggrab/ota.h b/src/epggrab/ota.h index 2b3c52c1..f1220906 100644 --- a/src/epggrab/ota.h +++ b/src/epggrab/ota.h @@ -71,5 +71,6 @@ void epggrab_ota_complete ( epggrab_ota_mux_t *ota ); void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ); void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ); int epggrab_ota_is_complete ( epggrab_ota_mux_t *ota ); +int epggrab_ota_is_blocked ( epggrab_ota_mux_t *ota ); #endif /* __TVH_EPGGRAB_OTA_H__ */