Re-written the EIT grabber, slight tweak to EPG api.

This commit is contained in:
Adam Sutton 2012-06-21 17:34:17 +01:00
parent 4cb753cc20
commit f39bb103da
7 changed files with 224 additions and 178 deletions

View file

@ -42,7 +42,9 @@
#define DVB_DESC_SHORT_EVENT 0x4d
#define DVB_DESC_EXT_EVENT 0x4e
#define DVB_DESC_SERVICE 0x48
#define DVB_DESC_COMPONENT 0x50
#define DVB_DESC_CONTENT 0x54
#define DVB_DESC_PARENTAL_RAT 0x55
#define DVB_DESC_TELETEXT 0x56
#define DVB_DESC_SUBTITLE 0x59
#define DVB_DESC_AC3 0x6a

View file

@ -125,7 +125,7 @@ static void _epg_event_deserialize ( htsmsg_t *c, epggrab_stats_t *stats )
/* Create broadcast */
save = 0;
ebc = epg_broadcast_find_by_time(ch, e_start, e_stop, 1, &save);
ebc = epg_broadcast_find_by_time(ch, e_start, e_stop, 0, 1, &save);
if (!ebc) return;
if (save) stats->broadcasts.total++;
@ -1410,7 +1410,8 @@ static epg_broadcast_t **_epg_broadcast_skel ( void )
}
epg_broadcast_t* epg_broadcast_find_by_time
( channel_t *channel, time_t start, time_t stop, int create, int *save )
( channel_t *channel, time_t start, time_t stop, uint16_t eid,
int create, int *save )
{
epg_broadcast_t **ebc;
if ( !channel || !start || !stop ) return NULL;
@ -1920,3 +1921,13 @@ void epg_query_sort(epg_query_result_t *eqr)
qsort(eqr->eqr_array, eqr->eqr_entries, sizeof(epg_broadcast_t*),
_epg_sort_start_ascending);
}
/* **************************************************************************
* Miscellaneous
* *************************************************************************/
/* Hash title/summary/description to form URI */
char *epg_hash ( const char *t, const char *s, const char *d )
{
return NULL; // TODO
}

View file

@ -318,7 +318,8 @@ struct epg_broadcast
/* Lookup */
epg_broadcast_t *epg_broadcast_find_by_time
( struct channel *ch, time_t start, time_t stop, int create, int *save );
( 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 );
@ -356,10 +357,6 @@ epg_broadcast_t *epg_broadcast_deserialize
* Channel - provides mapping from EPG channels to real channels
* ***********************************************************************/
/* Accessors */
epg_broadcast_t *epg_channel_get_broadcast
( struct channel *ch, time_t start, time_t stop, int create, int *save );
/* Unlink */
void epg_channel_unlink ( struct channel *ch );
@ -404,4 +401,10 @@ void epg_init (void);
void epg_save (void);
void epg_updated (void);
/* ************************************************************************
* Miscellaneous
* ***********************************************************************/
char *epg_hash ( const char *t, const char *s, const char *d );
#endif /* EPG_H */

View file

@ -31,78 +31,14 @@ static epggrab_module_t _eit_mod;
* Processing
* ***********************************************************************/
static const char *
longest_string ( const char *a, const char *b )
{
if (!a) return b;
if (!b) return a;
if (strlen(a) - strlen(b) >= 0) return a;
}
static void eit_callback ( channel_t *ch, int id, time_t start, time_t stop,
const char *title, const char *desc,
const char *extitem, const char *extdesc,
const char *exttext,
const uint8_t *genre, int genre_cnt ) {
int save = 0;
epg_broadcast_t *ebc;
epg_episode_t *ee;
const char *summary = NULL;
const char *description = NULL;
char *uri;
/* Ignore */
if (!ch || !ch->ch_name || !ch->ch_name[0]) return;
if (!title) return;
/* Find broadcast */
ebc = epg_broadcast_find_by_time(ch, start, stop, 1, &save);
if (!ebc) return;
/* Determine summary */
description = summary = desc;
description = longest_string(description, extitem);
description = longest_string(description, extdesc);
description = longest_string(description, exttext);
if (summary == description) description = NULL;
// TODO: is this correct?
/* Create episode URI */
uri = md5sum(longest_string(title, longest_string(description, summary)));
/* Create/Replace episode */
if ( !ebc->episode ||
!epg_episode_fuzzy_match(ebc->episode, uri, title,
summary, description) ) {
/* Create episode */
ee = epg_episode_find_by_uri(uri, 1, &save);
/* Set fields */
if (title)
save |= epg_episode_set_title(ee, title);
if (summary)
save |= epg_episode_set_summary(ee, summary);
if (description)
save |= epg_episode_set_description(ee, description);
if (genre_cnt)
save |= epg_episode_set_genre(ee, genre, genre_cnt);
/* Update */
save |= epg_broadcast_set_episode(ebc, ee);
}
free(uri);
}
/**
* DVB Descriptor; Short Event
*/
static int
dvb_desc_short_event(uint8_t *ptr, int len,
char *title, size_t titlelen,
char *desc, size_t desclen,
char *dvb_default_charset)
char *title, size_t titlelen,
char *desc, size_t desclen,
char *dvb_default_charset)
{
int r;
@ -125,11 +61,11 @@ dvb_desc_short_event(uint8_t *ptr, int len,
*/
static int
dvb_desc_extended_event(uint8_t *ptr, int len,
char *desc, size_t desclen,
char *item, size_t itemlen,
char *text, size_t textlen,
char *dvb_default_charset)
char *desc, size_t desclen,
char *text, size_t textlen,
char *dvb_default_charset)
{
#if TODO
int count = ptr[4], r;
uint8_t *localptr = ptr + 5, *items = localptr;
int locallen = len - 5;
@ -178,100 +114,100 @@ dvb_desc_extended_event(uint8_t *ptr, int len,
/* get text */
if((r = dvb_get_string_with_len(text, textlen, localptr, locallen, dvb_default_charset)) < 0)
return -1;
#endif
return 0;
}
/**
* DVB EIT (Event Information Table)
*/
static int
_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
uint8_t tableid, void *opaque)
// TODO: reg interest th_dvb_mux_instance_t *otdmi = tdmi;
static int _eit_callback
( th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
uint8_t tableid, void *opaque )
{
service_t *t;
th_dvb_adapter_t *tda;
service_t *svc;
channel_t *ch;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
uint16_t serviceid;
uint16_t transport_stream_id;
uint16_t event_id;
time_t start_time, stop_time;
int ok;
int duration;
int dllen;
uint8_t dtag, dlen;
char title[256];
char desc[5000];
char extdesc[5000];
char extitem[5000];
char exttext[5000];
uint8_t genre[10]; // max 10 genres
epg_broadcast_t *ebc;
epg_episode_t *ee;
int resched = 0, save = 0, save2 = 0, dllen, dtag, dlen;
uint16_t tsid, sid, eid;
uint8_t bw, hd, ws, ad, ds, st;
time_t start, stop;
int genre_idx = 0;
uint8_t genre[10];
char title[256];
char summary[256];
char desc[5000];
char info[5000];
/* Global disable */
if (!_eit_mod.enabled) return 0;
lock_assert(&global_lock);
// printf("EIT!, tid = %x\n", tableid);
/* Disabled */
if(!_eit_mod.enabled) return 0;
/* Invalid */
if(tableid < 0x4e || tableid > 0x6f || len < 11)
return -1;
serviceid = ptr[0] << 8 | ptr[1];
// version = ptr[2] >> 1 & 0x1f;
// section_number = ptr[3];
// last_section_number = ptr[4];
transport_stream_id = ptr[5] << 8 | ptr[6];
// original_network_id = ptr[7] << 8 | ptr[8];
// segment_last_section_number = ptr[9];
// last_table_id = ptr[10];
/* Skip */
if((ptr[2] & 1) == 0)
return 0;
if((ptr[2] & 1) == 0) {
/* current_next_indicator == next, skip this */
return -1;
/* Get tsid/sid */
sid = ptr[0] << 8 | ptr[1];
tsid = ptr[5] << 8 | ptr[6];
/* Get transport stream */
// Note: tableid=0x4f,0x60-0x6f is other TS
// so must find the tdmi
if(tableid == 0x4f || tableid >= 0x60) {
tda = tdmi->tdmi_adapter;
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
if(tdmi->tdmi_transport_stream_id == tsid)
break;
}
if(!tdmi) return -1;
/* TODO: register mux interest for more interesting stuff */
/* Get service */
svc = dvb_transport_find(tdmi, sid, 0, NULL);
if (!svc || !svc->s_enabled || (ch = svc->s_ch)) return 0;
/* Ignore (disabled or up to date) */
if (!svc->s_dvb_eit_enable) return 0;
#if TODO_INCLUDE_EIT_VER_CHECK
ver = ptr[2] >> 1 & 0x1f;
if (svc->s_dvb_eit_version[tableid-0x4f] == ver) return 0;
svc->s_dvb_eit_version[tableid-0x4e] = ver;
#endif
/* Process events */
len -= 11;
ptr += 11;
/* Search all muxes on adapter */
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
if(tdmi->tdmi_transport_stream_id == transport_stream_id)
break;
if(tdmi == NULL)
return -1;
t = dvb_transport_find(tdmi, serviceid, 0, NULL);
if(t == NULL || !t->s_enabled || (ch = t->s_ch) == NULL)
return 0;
if(!t->s_dvb_eit_enable)
return 0;
while(len >= 12) {
ok = 1;
event_id = ptr[0] << 8 | ptr[1];
start_time = dvb_convert_date(&ptr[2]);
duration = bcdtoint(ptr[7] & 0xff) * 3600 +
bcdtoint(ptr[8] & 0xff) * 60 +
bcdtoint(ptr[9] & 0xff);
dllen = ((ptr[10] & 0x0f) << 8) | ptr[11];
eid = ptr[0] << 8 | ptr[1];
start = dvb_convert_date(&ptr[2]);
stop = start + bcdtoint(ptr[7] & 0xff) * 3600 +
bcdtoint(ptr[8] & 0xff) * 60 +
bcdtoint(ptr[9] & 0xff);
dllen = ((ptr[10] & 0x0f) << 8) | ptr[11];
len -= 12;
ptr += 12;
if(dllen > len) break;
stop_time = start_time + duration;
*title = 0;
*desc = 0;
/* Get the event */
ebc = epg_broadcast_find_by_time(ch, start, stop, eid, 1, &save2);
if (!ebc) {
len -= dllen;
ptr += dllen;
continue;
}
/* Mark re-schedule detect */
if (save2 && tableid < 0x50) resched = 1;
/* Process tags */
*title = *summary = *desc = *info = 0;
genre_idx = 0;
hd = ws = bw = ad = st = ds = 0;
while(dllen > 0) {
dtag = ptr[0];
dlen = ptr[1];
@ -281,39 +217,131 @@ _eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
if(dlen > len) break;
switch(dtag) {
case DVB_DESC_SHORT_EVENT:
if(dvb_desc_short_event(ptr, dlen,
title, sizeof(title),
desc, sizeof(desc),
t->s_dvb_default_charset)) ok = 0;
break;
case DVB_DESC_CONTENT:
if(dlen >= 2) {
if (genre_idx < 10)
genre[genre_idx++] = (*ptr);
}
break;
case DVB_DESC_EXT_EVENT:
if(dvb_desc_extended_event(ptr, dlen,
extdesc, sizeof(extdesc),
extitem, sizeof(extitem),
exttext, sizeof(exttext),
t->s_dvb_default_charset)) ok = 0;
/* Short descriptor (title/summary) */
case DVB_DESC_SHORT_EVENT:
dvb_desc_short_event(ptr, dlen,
title, sizeof(title),
summary, sizeof(summary),
svc->s_dvb_default_charset);
break;
default:
/* Extended (description) */
case DVB_DESC_EXT_EVENT:
dvb_desc_extended_event(ptr, dlen,
desc, sizeof(desc),
info, sizeof(info),
svc->s_dvb_default_charset);
break;
/* Content type */
case DVB_DESC_CONTENT:
while (dlen > 0) {
ptr += 2;
dlen -= 2;
if ( *ptr == 0xb1 )
bw = 1;
else if ( *ptr < 0xb0 && genre_idx < sizeof(genre) )
genre[genre_idx++] = *ptr;
}
break;
/* Component descriptor */
case DVB_DESC_COMPONENT: {
uint8_t c = *ptr & 0x0f;
uint8_t t = ptr[1];
/* MPEG2 (video) */
if (c == 0x1) {
if (t > 0x08 && t < 0x11) {
hd = 1;
if ( t != 0x09 && t != 0x0d )
ws = 1;
} else if (t == 0x02 || t == 0x03 || t == 0x04 || t == 0x06 || t == 0x07 || t == 0x08 ) {
ws = 1;
}
/* MPEG2 (audio) */
} else if (c == 0x2) {
/* Described */
if (t == 0x40 || t == 0x41)
ad = 1;
/* Subtitles */
} else if (c == 0x3) {
st = 1;
/* H264 */
} else if (c == 0x5) {
if (t == 0x0b || t == 0x0c || t == 0x10)
hd = ws = 1;
else if (t == 0x03 || t == 0x04 || t == 0x07 || t == 0x08)
ws = 1;
/* AAC */
} else if ( c == 0x6 ) {
/* Described */
if (t == 0x40 || t == 0x44)
ad = 1;
}
}
break;
/* Parental Rating */
#if TODO_AGE_RATING
case DVB_DESC_PARENTAL_RAT:
if (*ptr > 0 && *ptr < 15)
minage = *ptr + 3;
#endif
/* Ignore */
default:
break;
}
len -= dlen; ptr += dlen; dllen -= dlen;
}
/* Pass to EIT handler */
if (ok)
eit_callback(ch, event_id, start_time, stop_time,
title, desc, extitem, extdesc, exttext,
genre, genre_idx);
/* Metadata */
if ( save2 ) {
save |= epg_broadcast_set_is_hd(ebc, hd);
save |= epg_broadcast_set_is_widescreen(ebc, ws);
save |= epg_broadcast_set_is_audio_desc(ebc, ad);
save |= epg_broadcast_set_is_subtitled(ebc, st);
save |= epg_broadcast_set_is_deafsigned(ebc, ds);
}
/* Create episode */
ee = ebc->episode;
if ( !ee || save2 ) {
char *uri;
uri = epg_hash(title, desc, summary);
ee = epg_episode_find_by_uri(uri, 1, &save2);
save |= epg_broadcast_set_episode(ebc, ee);
free(uri);
}
save |= save2;
if (!ee) continue;
/* Episode data */
// Note: currently we don't update if already set (else things fight)
save |= epg_episode_set_is_bw(ee, bw);
if ( !ee->title && *title )
save |= epg_episode_set_title(ee, title);
if ( !ee->summary && *summary )
save |= epg_episode_set_summary(ee, summary);
if ( !ee->description && *desc )
save |= epg_episode_set_description(ee, desc);
if ( !ee->genre_cnt && genre_idx )
save |= epg_episode_set_genre(ee, genre, genre_idx);
}
/* Update EPG */
if (resched) tvhlog(LOG_DEBUG, "eit", "alert grabbers to resched");
if (save) epg_updated();
return 0;
}
@ -323,7 +351,8 @@ _eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
static void _eit_tune ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi )
{
tdt_add(tdmi, NULL, _eit_callback, NULL, "eit", TDT_CRC, 0x12, NULL);
if (_eit_mod.enabled)
tdt_add(tdmi, NULL, _eit_callback, NULL, "eit", TDT_CRC, 0x12, NULL);
}
void eit_init ( epggrab_module_list_t *list )

View file

@ -328,7 +328,7 @@ static int _opentv_parse_event_section
if (ev.start && ev.duration) {
time_t start = ev.start + ((mjd - 40587) * 86400);
time_t stop = start + ev.duration;
ebc = epg_broadcast_find_by_time(ec->channel, start, stop, 1, &save);
ebc = epg_broadcast_find_by_time(ec->channel, start, stop, ev.eid, 1, &save);
} else {
ebc = epg_broadcast_find_by_eid(ev.eid, ec->channel);
}

View file

@ -330,7 +330,8 @@ static int _pyepg_parse_broadcast
if (!_pyepg_parse_time(stop, &tm_stop)) return 0;
/* Find broadcast */
broadcast = epg_broadcast_find_by_time(channel, tm_start, tm_stop, 1, &save);
broadcast
= epg_broadcast_find_by_time(channel, tm_start, tm_stop, 0, 1, &save);
if ( broadcast == NULL ) return 0;
stats->broadcasts.total++;
if ( save ) stats->broadcasts.created++;

View file

@ -327,7 +327,7 @@ _xmltv_parse_programme_tags(channel_t *ch, htsmsg_t *tags,
//if (onscreen) save |= epg_episode_set_onscreen(ee, onscreen);
/* Create/Find broadcast */
ebc = epg_broadcast_find_by_time(ch, start, stop, 1, &save2);
ebc = epg_broadcast_find_by_time(ch, start, stop, 0, 1, &save2);
if ( ebc ) {
stats->broadcasts.total++;
if (save2) stats->broadcasts.created++;