From 972b50145584aec09da8cc628b406f912b4fbee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Sun, 2 Dec 2007 11:12:58 +0000 Subject: [PATCH] Add initial plugin framework --- Makefile | 2 +- channels.c | 15 ++++++--- dvb.c | 3 +- dvb_dvr.c | 2 +- iptv_input.c | 3 +- plugin.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ plugin.h | 61 +++++++++++++++++++++++++++++++++++ psi.c | 63 ++++++++++++++++++++++++++++++++++++ psi.h | 2 ++ transports.c | 13 ++++++++ tsdemux.c | 54 +++++++++++++++++++++++++------ tsdemux.h | 2 +- tvhead.h | 26 +++++++++++++-- 13 files changed, 313 insertions(+), 23 deletions(-) create mode 100644 plugin.c create mode 100644 plugin.h diff --git a/Makefile b/Makefile index cd4cd01f..480bd4c9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -include ../config.mak SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c \ - subscriptions.c tsmux.c tsdemux.c pes.c buffer.c tcp.c + subscriptions.c tsmux.c tsdemux.c pes.c buffer.c tcp.c plugin.c SRCS += http.c htmlui.c diff --git a/channels.c b/channels.c index b82268a9..386402ae 100644 --- a/channels.c +++ b/channels.c @@ -34,7 +34,7 @@ #include "dvb.h" #include "v4l.h" #include "iptv_input.h" - +#include "psi.h" #include "channels.h" #include "transports.h" @@ -100,7 +100,7 @@ transport_set_channel(th_transport_t *t, th_channel_t *ch) { th_stream_t *st; char *chname; - + const char *n; t->tht_channel = ch; LIST_INSERT_SORTED(&ch->ch_transports, t, tht_channel_link, transportcmp); @@ -110,9 +110,14 @@ transport_set_channel(th_transport_t *t, th_channel_t *ch) t->tht_name, chname); free(chname); - LIST_FOREACH(st, &t->tht_streams, st_link) - syslog(LOG_DEBUG, " Stream [%s] - pid %d", - htstvstreamtype2txt(st->st_type), st->st_pid); + LIST_FOREACH(st, &t->tht_streams, st_link) { + if(st->st_caid != 0) { + n = psi_caid2name(st->st_caid); + } else { + n = htstvstreamtype2txt(st->st_type); + } + syslog(LOG_DEBUG, " Stream [%s] - pid %d", n, st->st_pid); + } return 0; } diff --git a/dvb.c b/dvb.c index 1be98864..0b1e276e 100644 --- a/dvb.c +++ b/dvb.c @@ -799,8 +799,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, len -= dlen; ptr += dlen; dllen -= dlen; } - if(stype == 1 && - free_ca_mode == 0 /* We dont have any CA-support (yet) */) { + if(stype == 1) { t = dvb_find_transport(tdmi, transport_stream_id, service_id, 0); if(t == NULL) diff --git a/dvb_dvr.c b/dvb_dvr.c index dd52c972..7114651e 100644 --- a/dvb_dvr.c +++ b/dvb_dvr.c @@ -74,7 +74,7 @@ dvb_dvr_process_packets(th_dvb_adapter_t *tda, uint8_t *tsb, int r) while(r >= 188) { pid = (tsb[1] & 0x1f) << 8 | tsb[2]; LIST_FOREACH(t, &tda->tda_transports, tht_adapter_link) - ts_recv_packet(t, pid, tsb); + ts_recv_packet(t, pid, tsb, 1); r -= 188; tsb += 188; } diff --git a/iptv_input.c b/iptv_input.c index a99b724b..6056b657 100644 --- a/iptv_input.c +++ b/iptv_input.c @@ -62,7 +62,7 @@ iptv_fd_callback(int events, void *opaque, int fd) while(r >= 188) { pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - ts_recv_packet(t, pid, tsb); + ts_recv_packet(t, pid, tsb, 1); r -= 188; tsb += 188; } @@ -225,6 +225,7 @@ iptv_configure_transport(th_transport_t *t, const char *iptv_type, st = transport_add_stream(t, 0, HTSTV_TABLE); st->st_got_section = iptv_parse_pat; + st->st_section_docrc = 1; t->tht_channel = channel_find(channel_name, 1); LIST_INSERT_HEAD(&iptv_probing_transports, t, tht_adapter_link); diff --git a/plugin.c b/plugin.c new file mode 100644 index 00000000..1ee64104 --- /dev/null +++ b/plugin.c @@ -0,0 +1,90 @@ +/* + * tvheadend, Plugin framework + * 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 +#include +#include +#include +#include + +#include "tvhead.h" +#include "plugin.h" + +struct th_plugin_list th_plugins; + +/** + * + */ +void * +plugin_aux_create(struct pluginaux_list *h, struct th_plugin *p, size_t siz) +{ + pluginaux_t *pa; + + pa = calloc(1, siz); + pa->pa_plugin = p; + LIST_INSERT_HEAD(h, pa, pa_link); + return pa; +} + + +/** + * + */ +void * +plugin_aux_find(struct pluginaux_list *h, struct th_plugin *p) +{ + pluginaux_t *pa; + + LIST_FOREACH(pa, h, pa_link) + if(pa->pa_plugin == p) + break; + + return pa; +} + +/** + * + */ +void +plugin_aux_destroy(void *pa) +{ + pluginaux_t *pa0 = pa; + LIST_REMOVE(pa0, pa_link); + free(pa); +} + +/** + * + */ +th_plugin_t * +plugin_alloc(const char *name, void *opaque, size_t minsiz) +{ + th_plugin_t *p; + + if(sizeof(th_plugin_t) < minsiz) + return NULL; + + p = calloc(1, sizeof(th_plugin_t)); + + p->thp_name = strdup(name); + p->thp_opaque = opaque; + + LIST_INSERT_HEAD(&th_plugins, p, thp_link); + + return p; +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 00000000..6eeb786e --- /dev/null +++ b/plugin.h @@ -0,0 +1,61 @@ +/* + * tvheadend, Plugin framework + * 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 . + */ + +#ifndef PLUGIN_H_ +#define PLUGIN_H_ + +#include "tvhead.h" + +LIST_HEAD(th_plugin_list, th_plugin); + +extern struct th_plugin_list th_plugins; +struct th_plugin; + +typedef struct th_plugin { + + LIST_ENTRY(th_plugin) thp_link; + + void *thp_opaque; + + const char *thp_name; + + void (*thp_transport_start)(struct th_plugin *p, struct pluginaux_list *h, + th_transport_t *t); + + void (*thp_transport_stop)(struct th_plugin *p, struct pluginaux_list *h, + th_transport_t *t); + + void (*thp_psi_table)(struct th_plugin *p, struct pluginaux_list *h, + th_transport_t *t, struct th_stream *st, + const uint8_t *data, size_t len); + + int (*thp_tsb_process)(pluginaux_t *pa, th_transport_t *t, + struct th_stream *st, uint8_t *tsb); + +} th_plugin_t; + +void *plugin_aux_create(struct pluginaux_list *h, struct th_plugin *p, + size_t siz); + +void *plugin_aux_find(struct pluginaux_list *h, struct th_plugin *p); + +void plugin_aux_destroy(void *pa); + +th_plugin_t *plugin_alloc(const char *name, void *opaque, size_t minsiz); + +#endif /* PLUGIN_H_ */ diff --git a/psi.c b/psi.c index 4fc3cd2b..b5488d9c 100644 --- a/psi.c +++ b/psi.c @@ -29,6 +29,7 @@ #include "transports.h" #include "dvb_support.h" #include "tsdemux.h" +#include "strtab.h" int psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len, @@ -89,6 +90,7 @@ psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len, if(prognum != 0) { st = transport_add_stream(t, pid, HTSTV_TABLE); + st->st_section_docrc = 1; st->st_got_section = pmt_callback; } @@ -173,6 +175,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) uint8_t dtag, dlen; uint16_t sid; tv_streamtype_t hts_stream_type; + th_stream_t *st; if(len < 9) return -1; @@ -198,6 +201,17 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) if(dlen > len) break; + switch(dtag) { + case DVB_DESC_CA: + st = transport_add_stream(t, (ptr[2] & 0x1f) << 8 | ptr[3], HTSTV_TABLE); + st->st_caid = (ptr[0] << 8) | ptr[1]; + break; + + default: + break; + } + + len -= dlen; ptr += dlen; dllen -= dlen; } @@ -435,3 +449,52 @@ psi_crc32(uint8_t *data, size_t datalen) return crc; } + + +static struct strtab caidnametab[] = { + { "Seca", 0x0100 }, + { "CCETT", 0x0200 }, + { "Deutsche Telecom", 0x0300 }, + { "Eurodec", 0x0400 }, + { "Viaccess", 0x0500 }, + { "Irdeto", 0x0600 }, + { "Irdeto", 0x0602 }, + { "Irdeto", 0x0604 }, + { "Jerroldgi", 0x0700 }, + { "Matra", 0x0800 }, + { "NDS", 0x0900 }, + { "Nokia", 0x0A00 }, + { "Conax", 0x0B00 }, + { "NTL", 0x0C00 }, + { "CryptoWorks", 0x0D00 }, + { "PowerVu", 0x0E00 }, + { "Sony", 0x0F00 }, + { "Tandberg", 0x1000 }, + { "Thompson", 0x1100 }, + { "TV-Com", 0x1200 }, + { "HPT", 0x1300 }, + { "HRT", 0x1400 }, + { "IBM", 0x1500 }, + { "Nera", 0x1600 }, + { "BetaCrypt", 0x1700 }, + { "BetaCrypt", 0x1702 }, + { "BetaCrypt", 0x1722 }, + { "BetaCrypt", 0x1762 }, + { "NagraVision", 0x1800 }, + { "Titan", 0x1900 }, + { "Telefonica", 0x2000 }, + { "Stentor", 0x2100 }, + { "Tadiran Scopus", 0x2200 }, + { "BARCO AS", 0x2300 }, + { "StarGuide", 0x2400 }, + { "Mentor", 0x2500 }, + { "EBU", 0x2600 }, + { "GI", 0x4700 }, + { "Telemann", 0x4800 } +}; + +const char * +psi_caid2name(uint16_t caid) +{ + return val2str(caid, caidnametab); +} diff --git a/psi.h b/psi.h index 20968cb4..751e9437 100644 --- a/psi.h +++ b/psi.h @@ -41,4 +41,6 @@ int psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen); int psi_build_pmt(th_muxer_t *tm, uint8_t *buf0, int maxlen); +const char *psi_caid2name(uint16_t caid); + #endif /* PSI_H_ */ diff --git a/transports.c b/transports.c index 623724c5..24d8c14d 100644 --- a/transports.c +++ b/transports.c @@ -52,6 +52,7 @@ #include "psi.h" #include "pes.h" #include "buffer.h" +#include "plugin.h" static dtimer_t transport_monitor_timer; @@ -63,6 +64,7 @@ transport_stop(th_transport_t *t, int flush_subscriptions) th_subscription_t *s; th_stream_t *st; th_pkt_t *pkt; + th_plugin_t *p; if(flush_subscriptions) { while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) @@ -72,6 +74,10 @@ transport_stop(th_transport_t *t, int flush_subscriptions) return; } + LIST_FOREACH(p, &th_plugins, thp_link) + if(p->thp_transport_stop != NULL) + p->thp_transport_stop(p, &t->tht_plugin_aux, t); + t->tht_stop_feed(t); t->tht_tt_commercial_advice = COMMERCIAL_UNKNOWN; @@ -144,6 +150,7 @@ transport_start(th_transport_t *t, unsigned int weight) th_stream_t *st; AVCodec *c; enum CodecID id; + th_plugin_t *p; assert(t->tht_status != TRANSPORT_RUNNING); @@ -181,6 +188,12 @@ transport_start(th_transport_t *t, unsigned int weight) } } } + + LIST_FOREACH(p, &th_plugins, thp_link) + if(p->thp_transport_start != NULL) + p->thp_transport_start(p, &t->tht_plugin_aux, t); + + return 0; } diff --git a/tsdemux.c b/tsdemux.c index 8b9a30b7..8eb181bf 100644 --- a/tsdemux.c +++ b/tsdemux.c @@ -48,6 +48,7 @@ #include "psi.h" #include "buffer.h" #include "tsdemux.h" +#include "plugin.h" static int ts_reassembly_pes(th_transport_t *t, th_stream_t *st, uint8_t *data, int len) @@ -105,17 +106,38 @@ ts_reassembly(th_transport_t *t, th_stream_t *st, uint8_t *data, int len, st->st_buffer_ptr += len; } +/** + * Code for dealing with a complete section + */ + +static void +got_section(th_transport_t *t, th_stream_t *st) +{ + th_plugin_t *p; + LIST_FOREACH(p, &th_plugins, thp_link) + if(p->thp_psi_table != NULL) + p->thp_psi_table(p, &t->tht_plugin_aux, t, st, + st->st_section->ps_data, st->st_section->ps_offset); + + if(st->st_got_section != NULL) + st->st_got_section(t, st, st->st_section->ps_data, + st->st_section->ps_offset); +} + + /* * Process transport stream packets */ void -ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb) +ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb, int doplugin) { th_stream_t *st = NULL; th_subscription_t *s; int cc, err = 0, afc, afl = 0; int len, pusi; + pluginaux_t *pa; + th_plugin_t *p; LIST_FOREACH(st, &t->tht_streams, st_link) if(st->st_pid == pid) @@ -124,12 +146,24 @@ ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb) if(st == NULL) return; + if(doplugin) { + LIST_FOREACH(pa, &t->tht_plugin_aux, pa_link) { + p = pa->pa_plugin; + if(p->thp_tsb_process != NULL) + if(p->thp_tsb_process(pa, t, st, tsb)) + return; + } + } + + avgstat_add(&t->tht_rate, 188, dispatch_clock); + if((tsb[3] >> 6) & 3) + return; /* channel is encrypted */ + + LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) if(s->ths_raw_input != NULL) s->ths_raw_input(s, tsb, 188, st, s->ths_opaque); - avgstat_add(&t->tht_rate, 188, dispatch_clock); - afc = (tsb[3] >> 4) & 3; if(afc & 1) { @@ -144,6 +178,7 @@ ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb) st->st_cc = (cc + 1) & 0xf; } + if(afc & 2) afl = tsb[4] + 1; @@ -167,17 +202,16 @@ ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb) if(len > 0) { if(len > 188 - afl) break; - if(!psi_section_reassemble(st->st_section, tsb + afl, len, 0, 1)) - st->st_got_section(t, st, st->st_section->ps_data, - st->st_section->ps_offset); - + if(!psi_section_reassemble(st->st_section, tsb + afl, len, 0, + st->st_section_docrc)) + got_section(t, st); afl += len; } } - if(!psi_section_reassemble(st->st_section, tsb + afl, 188 - afl, pusi, 1)) - st->st_got_section(t, st, st->st_section->ps_data, - st->st_section->ps_offset); + if(!psi_section_reassemble(st->st_section, tsb + afl, 188 - afl, pusi, + st->st_section_docrc)) + got_section(t, st); break; case HTSTV_TELETEXT: diff --git a/tsdemux.h b/tsdemux.h index 03296171..acce4320 100644 --- a/tsdemux.h +++ b/tsdemux.h @@ -19,6 +19,6 @@ #ifndef TSDEMUX_H #define TSDEMUX_H -void ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb); +void ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb, int doplugin); #endif /* TSDEMUX_H */ diff --git a/tvhead.h b/tvhead.h index 1d149996..f9a47a36 100644 --- a/tvhead.h +++ b/tvhead.h @@ -38,6 +38,17 @@ typedef enum { } th_commercial_advice_t; +/** + * Auxiliary data for plugins + */ +typedef struct pluginaux { + LIST_ENTRY(pluginaux) pa_link; + struct th_plugin *pa_plugin; +} pluginaux_t; + +LIST_HEAD(pluginaux_list, pluginaux); + + /* * Dispatch timer */ @@ -255,7 +266,9 @@ typedef struct th_stream { int st_peak_presentation_delay; /* Max seen diff. of DTS and PTS */ struct psi_section *st_section; + int st_section_docrc; /* Set if we should verify CRC on tables */ pid_section_callback_t *st_got_section; + void *st_got_section_opaque; /* For transport stream packet reassembly */ @@ -300,9 +313,14 @@ typedef struct th_stream { struct th_pkt_queue st_pktq; + /* ca id for this stream */ + + uint16_t st_caid; + } th_stream_t; + /* * A Transport (or in MPEG TS terms: a 'service') */ @@ -328,8 +346,7 @@ typedef struct th_transport { th_commercial_advice_t tht_tt_commercial_advice; int tht_tt_rundown_content_length; - time_t tht_tt_clock; /* Network clock as determined by teletext - decoder */ + time_t tht_tt_clock; /* Network clock as determined by teletext decoder */ int tht_prio; struct th_stream_list tht_streams; @@ -365,6 +382,8 @@ typedef struct th_transport { struct th_muxer_list tht_muxers; /* muxers */ + struct pluginaux_list tht_plugin_aux; + /* * Per source type structs */ @@ -397,6 +416,9 @@ typedef struct th_transport { struct { struct avgen *avgen; } avgen; + + char pad[256]; /* for api stability */ + } u; } th_transport_t;