Add initial plugin framework

This commit is contained in:
Andreas Öman 2007-12-02 11:12:58 +00:00
parent 07eebcd58b
commit 972b501455
13 changed files with 313 additions and 23 deletions

View file

@ -1,7 +1,7 @@
-include ../config.mak -include ../config.mak
SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c \ 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 SRCS += http.c htmlui.c

View file

@ -34,7 +34,7 @@
#include "dvb.h" #include "dvb.h"
#include "v4l.h" #include "v4l.h"
#include "iptv_input.h" #include "iptv_input.h"
#include "psi.h"
#include "channels.h" #include "channels.h"
#include "transports.h" #include "transports.h"
@ -100,7 +100,7 @@ transport_set_channel(th_transport_t *t, th_channel_t *ch)
{ {
th_stream_t *st; th_stream_t *st;
char *chname; char *chname;
const char *n;
t->tht_channel = ch; t->tht_channel = ch;
LIST_INSERT_SORTED(&ch->ch_transports, t, tht_channel_link, transportcmp); 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); t->tht_name, chname);
free(chname); free(chname);
LIST_FOREACH(st, &t->tht_streams, st_link) LIST_FOREACH(st, &t->tht_streams, st_link) {
syslog(LOG_DEBUG, " Stream [%s] - pid %d", if(st->st_caid != 0) {
htstvstreamtype2txt(st->st_type), st->st_pid); 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; return 0;
} }

3
dvb.c
View file

@ -799,8 +799,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
len -= dlen; ptr += dlen; dllen -= dlen; len -= dlen; ptr += dlen; dllen -= dlen;
} }
if(stype == 1 && if(stype == 1) {
free_ca_mode == 0 /* We dont have any CA-support (yet) */) {
t = dvb_find_transport(tdmi, transport_stream_id, service_id, 0); t = dvb_find_transport(tdmi, transport_stream_id, service_id, 0);
if(t == NULL) if(t == NULL)

View file

@ -74,7 +74,7 @@ dvb_dvr_process_packets(th_dvb_adapter_t *tda, uint8_t *tsb, int r)
while(r >= 188) { while(r >= 188) {
pid = (tsb[1] & 0x1f) << 8 | tsb[2]; pid = (tsb[1] & 0x1f) << 8 | tsb[2];
LIST_FOREACH(t, &tda->tda_transports, tht_adapter_link) LIST_FOREACH(t, &tda->tda_transports, tht_adapter_link)
ts_recv_packet(t, pid, tsb); ts_recv_packet(t, pid, tsb, 1);
r -= 188; r -= 188;
tsb += 188; tsb += 188;
} }

View file

@ -62,7 +62,7 @@ iptv_fd_callback(int events, void *opaque, int fd)
while(r >= 188) { while(r >= 188) {
pid = (tsb[1] & 0x1f) << 8 | tsb[2]; pid = (tsb[1] & 0x1f) << 8 | tsb[2];
ts_recv_packet(t, pid, tsb); ts_recv_packet(t, pid, tsb, 1);
r -= 188; r -= 188;
tsb += 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 = transport_add_stream(t, 0, HTSTV_TABLE);
st->st_got_section = iptv_parse_pat; st->st_got_section = iptv_parse_pat;
st->st_section_docrc = 1;
t->tht_channel = channel_find(channel_name, 1); t->tht_channel = channel_find(channel_name, 1);
LIST_INSERT_HEAD(&iptv_probing_transports, t, tht_adapter_link); LIST_INSERT_HEAD(&iptv_probing_transports, t, tht_adapter_link);

90
plugin.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#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;
}

61
plugin.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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_ */

63
psi.c
View file

@ -29,6 +29,7 @@
#include "transports.h" #include "transports.h"
#include "dvb_support.h" #include "dvb_support.h"
#include "tsdemux.h" #include "tsdemux.h"
#include "strtab.h"
int int
psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len, 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) { if(prognum != 0) {
st = transport_add_stream(t, pid, HTSTV_TABLE); st = transport_add_stream(t, pid, HTSTV_TABLE);
st->st_section_docrc = 1;
st->st_got_section = pmt_callback; 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; uint8_t dtag, dlen;
uint16_t sid; uint16_t sid;
tv_streamtype_t hts_stream_type; tv_streamtype_t hts_stream_type;
th_stream_t *st;
if(len < 9) if(len < 9)
return -1; return -1;
@ -198,6 +201,17 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
if(dlen > len) if(dlen > len)
break; 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; len -= dlen; ptr += dlen; dllen -= dlen;
} }
@ -435,3 +449,52 @@ psi_crc32(uint8_t *data, size_t datalen)
return crc; 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);
}

2
psi.h
View file

@ -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); int psi_build_pmt(th_muxer_t *tm, uint8_t *buf0, int maxlen);
const char *psi_caid2name(uint16_t caid);
#endif /* PSI_H_ */ #endif /* PSI_H_ */

View file

@ -52,6 +52,7 @@
#include "psi.h" #include "psi.h"
#include "pes.h" #include "pes.h"
#include "buffer.h" #include "buffer.h"
#include "plugin.h"
static dtimer_t transport_monitor_timer; static dtimer_t transport_monitor_timer;
@ -63,6 +64,7 @@ transport_stop(th_transport_t *t, int flush_subscriptions)
th_subscription_t *s; th_subscription_t *s;
th_stream_t *st; th_stream_t *st;
th_pkt_t *pkt; th_pkt_t *pkt;
th_plugin_t *p;
if(flush_subscriptions) { if(flush_subscriptions) {
while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL)
@ -72,6 +74,10 @@ transport_stop(th_transport_t *t, int flush_subscriptions)
return; 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_stop_feed(t);
t->tht_tt_commercial_advice = COMMERCIAL_UNKNOWN; t->tht_tt_commercial_advice = COMMERCIAL_UNKNOWN;
@ -144,6 +150,7 @@ transport_start(th_transport_t *t, unsigned int weight)
th_stream_t *st; th_stream_t *st;
AVCodec *c; AVCodec *c;
enum CodecID id; enum CodecID id;
th_plugin_t *p;
assert(t->tht_status != TRANSPORT_RUNNING); 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; return 0;
} }

View file

@ -48,6 +48,7 @@
#include "psi.h" #include "psi.h"
#include "buffer.h" #include "buffer.h"
#include "tsdemux.h" #include "tsdemux.h"
#include "plugin.h"
static int static int
ts_reassembly_pes(th_transport_t *t, th_stream_t *st, uint8_t *data, int len) 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; 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 * Process transport stream packets
*/ */
void 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_stream_t *st = NULL;
th_subscription_t *s; th_subscription_t *s;
int cc, err = 0, afc, afl = 0; int cc, err = 0, afc, afl = 0;
int len, pusi; int len, pusi;
pluginaux_t *pa;
th_plugin_t *p;
LIST_FOREACH(st, &t->tht_streams, st_link) LIST_FOREACH(st, &t->tht_streams, st_link)
if(st->st_pid == pid) if(st->st_pid == pid)
@ -124,12 +146,24 @@ ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb)
if(st == NULL) if(st == NULL)
return; 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) LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link)
if(s->ths_raw_input != NULL) if(s->ths_raw_input != NULL)
s->ths_raw_input(s, tsb, 188, st, s->ths_opaque); s->ths_raw_input(s, tsb, 188, st, s->ths_opaque);
avgstat_add(&t->tht_rate, 188, dispatch_clock);
afc = (tsb[3] >> 4) & 3; afc = (tsb[3] >> 4) & 3;
if(afc & 1) { 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; st->st_cc = (cc + 1) & 0xf;
} }
if(afc & 2) if(afc & 2)
afl = tsb[4] + 1; 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 > 0) {
if(len > 188 - afl) if(len > 188 - afl)
break; break;
if(!psi_section_reassemble(st->st_section, tsb + afl, len, 0, 1)) if(!psi_section_reassemble(st->st_section, tsb + afl, len, 0,
st->st_got_section(t, st, st->st_section->ps_data, st->st_section_docrc))
st->st_section->ps_offset); got_section(t, st);
afl += len; afl += len;
} }
} }
if(!psi_section_reassemble(st->st_section, tsb + afl, 188 - afl, pusi, 1)) if(!psi_section_reassemble(st->st_section, tsb + afl, 188 - afl, pusi,
st->st_got_section(t, st, st->st_section->ps_data, st->st_section_docrc))
st->st_section->ps_offset); got_section(t, st);
break; break;
case HTSTV_TELETEXT: case HTSTV_TELETEXT:

View file

@ -19,6 +19,6 @@
#ifndef TSDEMUX_H #ifndef TSDEMUX_H
#define 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 */ #endif /* TSDEMUX_H */

View file

@ -38,6 +38,17 @@ typedef enum {
} th_commercial_advice_t; } 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 * Dispatch timer
*/ */
@ -255,7 +266,9 @@ typedef struct th_stream {
int st_peak_presentation_delay; /* Max seen diff. of DTS and PTS */ int st_peak_presentation_delay; /* Max seen diff. of DTS and PTS */
struct psi_section *st_section; struct psi_section *st_section;
int st_section_docrc; /* Set if we should verify CRC on tables */
pid_section_callback_t *st_got_section; pid_section_callback_t *st_got_section;
void *st_got_section_opaque;
/* For transport stream packet reassembly */ /* For transport stream packet reassembly */
@ -300,9 +313,14 @@ typedef struct th_stream {
struct th_pkt_queue st_pktq; struct th_pkt_queue st_pktq;
/* ca id for this stream */
uint16_t st_caid;
} th_stream_t; } th_stream_t;
/* /*
* A Transport (or in MPEG TS terms: a 'service') * 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; th_commercial_advice_t tht_tt_commercial_advice;
int tht_tt_rundown_content_length; int tht_tt_rundown_content_length;
time_t tht_tt_clock; /* Network clock as determined by teletext time_t tht_tt_clock; /* Network clock as determined by teletext decoder */
decoder */
int tht_prio; int tht_prio;
struct th_stream_list tht_streams; struct th_stream_list tht_streams;
@ -365,6 +382,8 @@ typedef struct th_transport {
struct th_muxer_list tht_muxers; /* muxers */ struct th_muxer_list tht_muxers; /* muxers */
struct pluginaux_list tht_plugin_aux;
/* /*
* Per source type structs * Per source type structs
*/ */
@ -397,6 +416,9 @@ typedef struct th_transport {
struct { struct {
struct avgen *avgen; struct avgen *avgen;
} avgen; } avgen;
char pad[256]; /* for api stability */
} u; } u;
} th_transport_t; } th_transport_t;