rework much of the internal transport stream handling
This commit is contained in:
parent
895acc0180
commit
412cce5ea6
16 changed files with 308 additions and 115 deletions
4
Makefile
4
Makefile
|
@ -1,12 +1,12 @@
|
|||
include ../config.mak
|
||||
|
||||
SRCS = main.c dispatch.c channels.c transports.c teletext.c
|
||||
SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c
|
||||
|
||||
SRCS += pvr.c pvr_rec.c
|
||||
|
||||
SRCS += epg.c epg_xmltv.c
|
||||
|
||||
SRCS += dvb.c dvb_support.c dvb_pmt.c dvb_dvr.c dvb_muxconfig.c
|
||||
SRCS += dvb.c dvb_support.c dvb_dvr.c dvb_muxconfig.c
|
||||
|
||||
SRCS += iptv_input.c iptv_output.c
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "v4l.h"
|
||||
#include "iptv_input.h"
|
||||
|
||||
#include "dvb_pmt.h"
|
||||
#include "channels.h"
|
||||
#include "transports.h"
|
||||
|
||||
|
|
61
dispatch.c
61
dispatch.c
|
@ -45,7 +45,7 @@ typedef struct stimer {
|
|||
LIST_ENTRY(stimer) link;
|
||||
void (*callback)(void *aux);
|
||||
void *aux;
|
||||
time_t t;
|
||||
int64_t t;
|
||||
} stimer_t;
|
||||
|
||||
LIST_HEAD(, stimer) dispatch_timers;
|
||||
|
@ -54,24 +54,33 @@ LIST_HEAD(, stimer) dispatch_timers;
|
|||
static int
|
||||
stimercmp(stimer_t *a, stimer_t *b)
|
||||
{
|
||||
return a->t - b->t;
|
||||
if(a->t < b->t)
|
||||
return -1;
|
||||
else if(a->t > b->t)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
stimer_add_hires(void (*callback)(void *aux), void *aux, int64_t t)
|
||||
{
|
||||
stimer_t *ti = malloc(sizeof(stimer_t));
|
||||
ti->t = t;
|
||||
ti->aux = aux;
|
||||
ti->callback = callback;
|
||||
LIST_INSERT_SORTED(&dispatch_timers, ti, link, stimercmp);
|
||||
return ti;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *
|
||||
stimer_add(void (*callback)(void *aux), void *aux, int delta)
|
||||
{
|
||||
time_t now;
|
||||
stimer_t *ti = malloc(sizeof(stimer_t));
|
||||
|
||||
time(&now);
|
||||
|
||||
ti->t = now + delta;
|
||||
ti->aux = aux;
|
||||
ti->callback = callback;
|
||||
|
||||
LIST_INSERT_SORTED(&dispatch_timers, ti, link, stimercmp);
|
||||
return ti;
|
||||
return stimer_add_hires(callback, aux, (uint64_t)(now + delta) * 1000000ULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -87,37 +96,23 @@ static int
|
|||
stimer_next(void)
|
||||
{
|
||||
stimer_t *ti = LIST_FIRST(&dispatch_timers);
|
||||
struct timeval tv;
|
||||
int64_t next, now, delta;
|
||||
int64_t delta;
|
||||
|
||||
if(ti == NULL)
|
||||
return -1;
|
||||
|
||||
next = (uint64_t)ti->t * 1000000ULL;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
|
||||
|
||||
delta = next - now;
|
||||
delta = ti->t - getclock_hires();
|
||||
return delta < 0 ? 0 : delta / 1000ULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
stimer_dispatch(time_t now)
|
||||
stimer_dispatch(int64_t now)
|
||||
{
|
||||
stimer_t *ti;
|
||||
|
||||
while((ti = LIST_FIRST(&dispatch_timers)) != NULL) {
|
||||
if(ti->t > now)
|
||||
break;
|
||||
|
||||
LIST_REMOVE(ti, link);
|
||||
ti->callback(ti->aux);
|
||||
free(ti);
|
||||
|
@ -227,12 +222,18 @@ dispatcher(void)
|
|||
{
|
||||
struct epoll_entry *e;
|
||||
int i, n;
|
||||
struct timeval tv;
|
||||
int64_t now;
|
||||
|
||||
static struct epoll_event events[EPOLL_FDS_PER_ROUND];
|
||||
|
||||
n = epoll_wait(epoll_fd, events, EPOLL_FDS_PER_ROUND, stimer_next());
|
||||
|
||||
time(&dispatch_clock);
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
dispatch_clock = tv.tv_sec;
|
||||
now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
|
||||
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
e = events[i].data.ptr;
|
||||
|
@ -257,5 +258,5 @@ dispatcher(void)
|
|||
dispatch_deref(e);
|
||||
}
|
||||
|
||||
stimer_dispatch(dispatch_clock);
|
||||
stimer_dispatch(now);
|
||||
}
|
||||
|
|
14
dispatch.h
14
dispatch.h
|
@ -19,6 +19,8 @@
|
|||
#ifndef DISPATCH_H
|
||||
#define DISPATCH_H
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
extern time_t dispatch_clock;
|
||||
|
||||
#define DISPATCH_READ 0x1
|
||||
|
@ -26,6 +28,17 @@ extern time_t dispatch_clock;
|
|||
#define DISPATCH_ERR 0x4
|
||||
#define DISPATCH_PRI 0x8
|
||||
|
||||
extern inline int64_t
|
||||
getclock_hires(void)
|
||||
{
|
||||
int64_t now;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
|
||||
return now;
|
||||
}
|
||||
|
||||
int dispatch_init(void);
|
||||
void *dispatch_addfd(int fd,
|
||||
void (*callback)(int events, void *opaque, int fd),
|
||||
|
@ -36,6 +49,7 @@ void dispatch_clr(void *handle, int flags);
|
|||
void dispatcher(void);
|
||||
|
||||
void *stimer_add(void (*callback)(void *aux), void *aux, int delta);
|
||||
void *stimer_add_hires(void (*callback)(void *aux), void *aux, int64_t t);
|
||||
void stimer_del(void *handle);
|
||||
|
||||
#endif /* DISPATCH_H */
|
||||
|
|
4
dvb.c
4
dvb.c
|
@ -41,8 +41,8 @@
|
|||
#include "transports.h"
|
||||
#include "teletext.h"
|
||||
#include "epg.h"
|
||||
#include "psi.h"
|
||||
#include "dvb_support.h"
|
||||
#include "dvb_pmt.h"
|
||||
#include "dvb_dvr.h"
|
||||
#include "dvb_muxconfig.h"
|
||||
|
||||
|
@ -327,7 +327,7 @@ dvb_service_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
{
|
||||
th_transport_t *t = opaque;
|
||||
|
||||
return dvb_parse_pmt(t, ptr, len);
|
||||
return psi_parse_pmt(t, ptr, len, 1);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
transport_recv_tsb(t, pid, tsb);
|
||||
transport_recv_tsb(t, pid, tsb, 1, AV_NOPTS_VALUE);
|
||||
r -= 188;
|
||||
tsb += 188;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,8 @@ cprintf(client_t *c, const char *fmt, ...)
|
|||
|
||||
|
||||
static void
|
||||
client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
|
||||
client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
|
||||
int64_t pcr)
|
||||
{
|
||||
client_t *c = s->ths_opaque;
|
||||
char stoppkt[4];
|
||||
|
@ -87,7 +88,7 @@ client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
|
|||
}
|
||||
|
||||
memcpy(s->ths_pkt + s->ths_pkt_ptr, pkt, 188);
|
||||
|
||||
s->ths_pkt[s->ths_pkt_ptr] = pi->tp_type;
|
||||
s->ths_pkt_ptr += 188;
|
||||
|
||||
if(s->ths_pkt_ptr == c->c_pkt_maxsiz + 2) {
|
||||
|
|
36
iptv_input.c
36
iptv_input.c
|
@ -39,6 +39,7 @@
|
|||
#include "channels.h"
|
||||
#include "transports.h"
|
||||
#include "dispatch.h"
|
||||
#include "psi.h"
|
||||
|
||||
static void
|
||||
iptv_fd_callback(int events, void *opaque, int fd)
|
||||
|
@ -52,7 +53,7 @@ iptv_fd_callback(int events, void *opaque, int fd)
|
|||
|
||||
while(r >= 188) {
|
||||
pid = (tsb[1] & 0x1f) << 8 | tsb[2];
|
||||
transport_recv_tsb(t, pid, tsb);
|
||||
transport_recv_tsb(t, pid, tsb, 1, AV_NOPTS_VALUE);
|
||||
r -= 188;
|
||||
tsb += 188;
|
||||
}
|
||||
|
@ -121,6 +122,35 @@ iptv_stop_feed(th_transport_t *t)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
iptv_parse_pmt(struct th_transport *t, struct th_pid *pi,
|
||||
uint8_t *table, int table_len)
|
||||
{
|
||||
if(table[0] != 2)
|
||||
return;
|
||||
|
||||
psi_parse_pmt(t, table + 3, table_len - 3, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
iptv_parse_pat(struct th_transport *t, struct th_pid *pi,
|
||||
uint8_t *table, int table_len)
|
||||
{
|
||||
if(table[0] != 0)
|
||||
return;
|
||||
|
||||
psi_parse_pat(t, table + 3, table_len - 3, iptv_parse_pmt);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
@ -134,6 +164,7 @@ iptv_configure_transport(th_transport_t *t, const char *muxname)
|
|||
char buf[100];
|
||||
char ifname[100];
|
||||
struct ifreq ifr;
|
||||
th_pid_t *pi;
|
||||
|
||||
if((ce = find_mux_config("iptvmux", muxname)) == NULL)
|
||||
return -1;
|
||||
|
@ -178,5 +209,8 @@ iptv_configure_transport(th_transport_t *t, const char *muxname)
|
|||
ifname, inet_ntoa(t->tht_iptv_group_addr), t->tht_iptv_port);
|
||||
t->tht_name = strdup(buf);
|
||||
|
||||
pi = transport_add_pid(t, 0, HTSTV_TABLE);
|
||||
pi->tp_got_section = iptv_parse_pat;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,8 @@ typedef struct output_multicast {
|
|||
|
||||
|
||||
static void
|
||||
om_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
|
||||
om_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
|
||||
int64_t pcr)
|
||||
{
|
||||
output_multicast_t *om = s->ths_opaque;
|
||||
struct sockaddr_in sin;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TV Input - DVB - Program Map Table parser
|
||||
* Multicasted IPTV Input
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -16,34 +16,45 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ffmpeg/common.h>
|
||||
|
||||
#include "tvhead.h"
|
||||
#include "psi.h"
|
||||
#include "transports.h"
|
||||
#include "dvb_support.h"
|
||||
|
||||
const char *
|
||||
htstvstreamtype2txt(tv_streamtype_t s)
|
||||
int
|
||||
psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len,
|
||||
int start, int chkcrc)
|
||||
{
|
||||
switch(s) {
|
||||
case HTSTV_MPEG2VIDEO: return "mpeg2video";
|
||||
case HTSTV_MPEG2AUDIO: return "mpeg2audio";
|
||||
case HTSTV_H264: return "h264";
|
||||
case HTSTV_AC3: return "AC-3";
|
||||
case HTSTV_TELETEXT: return "teletext";
|
||||
case HTSTV_SUBTITLES: return "subtitles";
|
||||
default: return "<unknown>";
|
||||
int remain, a, tsize;
|
||||
|
||||
if(start)
|
||||
ps->ps_offset = 0;
|
||||
|
||||
if(ps->ps_offset < 0)
|
||||
return -1;
|
||||
|
||||
remain = PSI_SECTION_SIZE - ps->ps_offset;
|
||||
|
||||
a = FFMAX(0, FFMIN(remain, len));
|
||||
|
||||
memcpy(ps->ps_data + ps->ps_offset, data, a);
|
||||
ps->ps_offset += a;
|
||||
tsize = 3 + (((ps->ps_data[1] & 0xf) << 8) | ps->ps_data[2]);
|
||||
if(ps->ps_offset < tsize)
|
||||
return -1;
|
||||
|
||||
if(chkcrc) {
|
||||
/* XXX: Add CRC check */
|
||||
}
|
||||
ps->ps_offset = tsize - (chkcrc ? 4 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,32 +62,73 @@ htstvstreamtype2txt(tv_streamtype_t s)
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* PAT parser, from ISO 13818-1
|
||||
*/
|
||||
|
||||
int
|
||||
dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
|
||||
psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
|
||||
pid_section_callback_t *pmt_callback)
|
||||
{
|
||||
uint16_t prognum;
|
||||
uint16_t pid;
|
||||
th_pid_t *pi;
|
||||
|
||||
if(len < 5)
|
||||
return -1;
|
||||
|
||||
ptr += 5;
|
||||
len -= 5;
|
||||
|
||||
while(len >= 4) {
|
||||
|
||||
prognum = ptr[0] << 8 | ptr[1];
|
||||
pid = (ptr[2] & 0x1f) << 8 | ptr[3];
|
||||
|
||||
if(prognum != 0) {
|
||||
pi = transport_add_pid(t, pid, HTSTV_TABLE);
|
||||
pi->tp_got_section = pmt_callback;
|
||||
|
||||
}
|
||||
ptr += 4;
|
||||
len -= 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* PMT parser, from ISO 13818-1 and ETSI EN 300 468
|
||||
*/
|
||||
|
||||
int
|
||||
psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
||||
{
|
||||
uint16_t pcr_pid, pid;
|
||||
uint8_t estype;
|
||||
int dllen;
|
||||
uint8_t dtag, dlen;
|
||||
uint16_t sid;
|
||||
|
||||
tv_streamtype_t hts_stream_type;
|
||||
|
||||
if(len < 9)
|
||||
return -1;
|
||||
|
||||
sid = ptr[0] << 8 | ptr[1];
|
||||
|
||||
pcr_pid = (ptr[5] & 0x1f) << 8 | ptr[6];
|
||||
dllen = (ptr[7] & 0xf) << 8 | ptr[8];
|
||||
|
||||
t->tht_pcr_pid = pcr_pid;
|
||||
|
||||
ptr += 9;
|
||||
len -= 9;
|
||||
|
||||
if(sid != t->tht_dvb_service_id)
|
||||
if(chksvcid && sid != t->tht_dvb_service_id)
|
||||
return -1;
|
||||
|
||||
|
||||
|
||||
while(dllen > 2) {
|
||||
dtag = ptr[0];
|
||||
dlen = ptr[1];
|
||||
|
@ -92,7 +144,7 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
|
|||
estype = ptr[0];
|
||||
pid = (ptr[1] & 0x1f) << 8 | ptr[2];
|
||||
dllen = (ptr[3] & 0xf) << 8 | ptr[4];
|
||||
|
||||
|
||||
ptr += 5;
|
||||
len -= 5;
|
||||
|
||||
|
@ -123,7 +175,6 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
|
|||
if(dlen > len)
|
||||
break;
|
||||
|
||||
|
||||
switch(dtag) {
|
||||
case DVB_DESC_TELETEXT:
|
||||
if(estype == 0x06)
|
||||
|
@ -134,7 +185,7 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
|
|||
break;
|
||||
|
||||
case DVB_DESC_AC3:
|
||||
if(estype == 0x06)
|
||||
if(estype == 0x06 || estype == 0x81)
|
||||
hts_stream_type = HTSTV_AC3;
|
||||
break;
|
||||
}
|
||||
|
@ -147,3 +198,22 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const char *
|
||||
htstvstreamtype2txt(tv_streamtype_t s)
|
||||
{
|
||||
switch(s) {
|
||||
case HTSTV_MPEG2VIDEO: return "mpeg2video";
|
||||
case HTSTV_MPEG2AUDIO: return "mpeg2audio";
|
||||
case HTSTV_H264: return "h264";
|
||||
case HTSTV_AC3: return "AC-3";
|
||||
case HTSTV_TELETEXT: return "teletext";
|
||||
case HTSTV_SUBTITLES: return "subtitles";
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Multicasted IPTV Input
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -16,11 +16,23 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DVB_PMT_H
|
||||
#define DVB_PMT_H
|
||||
#ifndef PSI_H_
|
||||
#define PSI_H_
|
||||
|
||||
int dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len);
|
||||
#define PSI_SECTION_SIZE 4096
|
||||
|
||||
const char *htstvstreamtype2txt(tv_streamtype_t s);
|
||||
typedef struct psi_section {
|
||||
int ps_offset;
|
||||
uint8_t ps_data[PSI_SECTION_SIZE];
|
||||
} psi_section_t;
|
||||
|
||||
#endif /* DVB_PMT_H */
|
||||
|
||||
int psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len,
|
||||
int pusi, int chkcrc);
|
||||
|
||||
int psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
|
||||
pid_section_callback_t *pmt_callback);
|
||||
|
||||
int psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid);
|
||||
|
||||
#endif /* PSI_H_ */
|
5
pvr.c
5
pvr.c
|
@ -441,7 +441,7 @@ pvr_wait_thread(pvr_rec_t *pvrr)
|
|||
|
||||
|
||||
static void pvr_record_callback(struct th_subscription *s, uint8_t *pkt,
|
||||
th_pid_t *pi);
|
||||
th_pid_t *pi, int64_t pcr);
|
||||
|
||||
|
||||
static void
|
||||
|
@ -528,7 +528,8 @@ pvrr_fsm(pvr_rec_t *pvrr)
|
|||
*/
|
||||
|
||||
static void
|
||||
pvr_record_callback(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi)
|
||||
pvr_record_callback(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
|
||||
int64_t pcr)
|
||||
{
|
||||
pvr_data_t *pd;
|
||||
pvr_rec_t *pvrr = s->ths_opaque;
|
||||
|
|
99
transports.c
99
transports.c
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
@ -34,6 +35,8 @@
|
|||
|
||||
#include <libhts/htscfg.h>
|
||||
|
||||
#include <ffmpeg/avcodec.h>
|
||||
|
||||
#include "tvhead.h"
|
||||
#include "dispatch.h"
|
||||
#include "dvb_dvr.h"
|
||||
|
@ -43,6 +46,7 @@
|
|||
#include "v4l.h"
|
||||
#include "dvb_dvr.h"
|
||||
#include "iptv_input.h"
|
||||
#include "psi.h"
|
||||
|
||||
/*
|
||||
* transport_mutex protects all operations concerning subscription lists
|
||||
|
@ -214,7 +218,7 @@ subscription_unsubscribe(th_subscription_t *s)
|
|||
{
|
||||
pthread_mutex_lock(&subscription_mutex);
|
||||
|
||||
s->ths_callback(s, NULL, NULL);
|
||||
s->ths_callback(s, NULL, NULL, AV_NOPTS_VALUE);
|
||||
|
||||
LIST_REMOVE(s, ths_global_link);
|
||||
LIST_REMOVE(s, ths_channel_link);
|
||||
|
@ -249,7 +253,7 @@ subscription_sort(th_subscription_t *a, th_subscription_t *b)
|
|||
th_subscription_t *
|
||||
channel_subscribe(th_channel_t *ch, void *opaque,
|
||||
void (*callback)(struct th_subscription *s,
|
||||
uint8_t *pkt, th_pid_t *pi),
|
||||
uint8_t *pkt, th_pid_t *pi, int64_t pcr),
|
||||
unsigned int weight,
|
||||
const char *name)
|
||||
{
|
||||
|
@ -316,7 +320,7 @@ transport_flush_subscribers(th_transport_t *t)
|
|||
while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) {
|
||||
LIST_REMOVE(s, ths_transport_link);
|
||||
s->ths_transport = NULL;
|
||||
s->ths_callback(s, NULL, NULL);
|
||||
s->ths_callback(s, NULL, NULL, AV_NOPTS_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,13 +349,14 @@ transport_compute_weight(struct th_transport_list *head)
|
|||
*/
|
||||
|
||||
void
|
||||
transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
|
||||
transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb, int scanpcr,
|
||||
int64_t pcr)
|
||||
{
|
||||
th_pid_t *pi = NULL;
|
||||
th_subscription_t *s;
|
||||
th_channel_t *ch;
|
||||
int cc, err = 0;
|
||||
|
||||
int cc, err = 0, afc, afl = 0;
|
||||
int len, pusi;
|
||||
|
||||
LIST_FOREACH(pi, &t->tht_pids, tp_link)
|
||||
if(pi->tp_pid == pid)
|
||||
break;
|
||||
|
@ -359,9 +364,12 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
|
|||
if(pi == NULL)
|
||||
return;
|
||||
|
||||
cc = tsb[3] & 0xf;
|
||||
avgstat_add(&t->tht_rate, 188, dispatch_clock);
|
||||
|
||||
if(tsb[3] & 0x10) {
|
||||
afc = (tsb[3] >> 4) & 3;
|
||||
|
||||
if(afc & 1) {
|
||||
cc = tsb[3] & 0xf;
|
||||
if(pi->tp_cc_valid && cc != pi->tp_cc) {
|
||||
/* Incorrect CC */
|
||||
avgstat_add(&t->tht_cc_errors, 1, dispatch_clock);
|
||||
|
@ -371,25 +379,63 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
|
|||
pi->tp_cc = (cc + 1) & 0xf;
|
||||
}
|
||||
|
||||
avgstat_add(&t->tht_rate, 188, dispatch_clock);
|
||||
if(afc & 2) {
|
||||
afl = tsb[4] + 1;
|
||||
|
||||
ch = t->tht_channel;
|
||||
if(afl > 0 && scanpcr && tsb[5] & 0x10) {
|
||||
pcr = (uint64_t)tsb[6] << 25;
|
||||
pcr |= (uint64_t)tsb[7] << 17;
|
||||
pcr |= (uint64_t)tsb[8] << 9;
|
||||
pcr |= (uint64_t)tsb[9] << 1;
|
||||
pcr |= (uint64_t)(tsb[10] >> 7) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
switch(pi->tp_type) {
|
||||
|
||||
if(pi->tp_type == HTSTV_TELETEXT) {
|
||||
/* teletext */
|
||||
case HTSTV_TABLE:
|
||||
if(pi->tp_section == NULL)
|
||||
pi->tp_section = calloc(1, sizeof(struct psi_section));
|
||||
|
||||
afl += 4;
|
||||
if(err || afl >= 188) {
|
||||
pi->tp_section->ps_offset = -1; /* hold parser until next pusi */
|
||||
break;
|
||||
}
|
||||
|
||||
pusi = tsb[1] & 0x40;
|
||||
|
||||
if(pusi) {
|
||||
len = tsb[afl++];
|
||||
if(len > 0) {
|
||||
if(len > 188 - afl)
|
||||
break;
|
||||
if(!psi_section_reassemble(pi->tp_section, tsb + afl, len, 0, 1))
|
||||
pi->tp_got_section(t, pi, pi->tp_section->ps_data,
|
||||
pi->tp_section->ps_offset);
|
||||
|
||||
afl += len;
|
||||
}
|
||||
}
|
||||
|
||||
if(!psi_section_reassemble(pi->tp_section, tsb + afl, 188 - afl, pusi, 1))
|
||||
pi->tp_got_section(t, pi, pi->tp_section->ps_data,
|
||||
pi->tp_section->ps_offset);
|
||||
break;
|
||||
|
||||
case HTSTV_TELETEXT:
|
||||
teletext_input(t, tsb);
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
pthread_mutex_lock(&subscription_mutex);
|
||||
LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) {
|
||||
s->ths_total_err += err;
|
||||
s->ths_callback(s, tsb, pi, pcr);
|
||||
}
|
||||
pthread_mutex_unlock(&subscription_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
tsb[0] = pi->tp_type;
|
||||
|
||||
pthread_mutex_lock(&subscription_mutex);
|
||||
|
||||
LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) {
|
||||
s->ths_total_err += err;
|
||||
s->ths_callback(s, tsb, pi);
|
||||
}
|
||||
pthread_mutex_unlock(&subscription_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
@ -477,7 +523,7 @@ transport_scheduler_init(void)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
th_pid_t *
|
||||
transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
|
||||
{
|
||||
th_pid_t *pi;
|
||||
|
@ -485,7 +531,7 @@ transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
|
|||
LIST_FOREACH(pi, &t->tht_pids, tp_link) {
|
||||
i++;
|
||||
if(pi->tp_pid == pid)
|
||||
return;
|
||||
return pi;
|
||||
}
|
||||
|
||||
pi = calloc(1, sizeof(th_pid_t));
|
||||
|
@ -495,4 +541,5 @@ transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
|
|||
pi->tp_demuxer_fd = -1;
|
||||
|
||||
LIST_INSERT_HEAD(&t->tht_pids, pi, tp_link);
|
||||
return pi;
|
||||
}
|
||||
|
|
10
transports.h
10
transports.h
|
@ -19,6 +19,7 @@
|
|||
#ifndef TRANSPORTS_H
|
||||
#define TRANSPORTS_H
|
||||
|
||||
#include <ffmpeg/avcodec.h>
|
||||
|
||||
void subscription_unsubscribe(th_subscription_t *s);
|
||||
void subscription_set_weight(th_subscription_t *s, unsigned int weight);
|
||||
|
@ -30,11 +31,13 @@ unsigned int transport_compute_weight(struct th_transport_list *head);
|
|||
|
||||
void transport_flush_subscribers(th_transport_t *t);
|
||||
|
||||
void transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb);
|
||||
void transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb,
|
||||
int scanpcr, int64_t pcr);
|
||||
|
||||
void transport_monitor_init(th_transport_t *t);
|
||||
|
||||
void transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type);
|
||||
th_pid_t *transport_add_pid(th_transport_t *t, uint16_t pid,
|
||||
tv_streamtype_t type);
|
||||
|
||||
int transport_set_channel(th_transport_t *th, const char *name);
|
||||
|
||||
|
@ -43,7 +46,8 @@ void transport_scheduler_init(void);
|
|||
th_subscription_t *channel_subscribe(th_channel_t *ch, void *opaque,
|
||||
void (*ths_callback)
|
||||
(struct th_subscription *s,
|
||||
uint8_t *pkt, th_pid_t *pi),
|
||||
uint8_t *pkt, th_pid_t *pi,
|
||||
int64_t pcr),
|
||||
unsigned int weight,
|
||||
const char *name);
|
||||
|
||||
|
|
17
tvhead.h
17
tvhead.h
|
@ -209,7 +209,12 @@ typedef struct th_iptv_adapter {
|
|||
*
|
||||
*/
|
||||
|
||||
struct th_transport;
|
||||
struct th_pid;
|
||||
|
||||
typedef void (pid_section_callback_t)(struct th_transport *t,
|
||||
struct th_pid *pi,
|
||||
uint8_t *section, int section_len);
|
||||
|
||||
typedef struct th_pid {
|
||||
LIST_ENTRY(th_pid) tp_link;
|
||||
|
@ -221,6 +226,8 @@ typedef struct th_pid {
|
|||
int tp_demuxer_fd;
|
||||
int tp_index;
|
||||
|
||||
struct psi_section *tp_section;
|
||||
pid_section_callback_t *tp_got_section;
|
||||
} th_pid_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -257,6 +264,7 @@ typedef struct th_transport {
|
|||
|
||||
struct th_pid_list tht_pids;
|
||||
|
||||
uint16_t tht_pcr_pid;
|
||||
uint16_t tht_dvb_network_id;
|
||||
uint16_t tht_dvb_transport_id;
|
||||
uint16_t tht_dvb_service_id;
|
||||
|
@ -288,10 +296,7 @@ typedef struct th_transport {
|
|||
struct th_v4l_adapter *adapter;
|
||||
} v4l;
|
||||
|
||||
|
||||
|
||||
struct {
|
||||
|
||||
struct in_addr group_addr;
|
||||
struct in_addr interface_addr;
|
||||
int ifindex;
|
||||
|
@ -299,9 +304,7 @@ typedef struct th_transport {
|
|||
int port;
|
||||
int fd;
|
||||
void *dispatch_handle;
|
||||
|
||||
} iptv;
|
||||
|
||||
} u;
|
||||
|
||||
|
||||
|
@ -398,7 +401,8 @@ typedef struct th_subscription {
|
|||
LIST_ENTRY(th_subscription) ths_subscriber_link; /* Caller is responsible
|
||||
for this link */
|
||||
|
||||
void (*ths_callback)(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi);
|
||||
void (*ths_callback)(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi,
|
||||
int64_t pcr);
|
||||
|
||||
void *ths_opaque;
|
||||
|
||||
|
@ -547,5 +551,6 @@ config_entry_t *find_mux_config(const char *muxtype, const char *muxname);
|
|||
|
||||
char *utf8toprintable(const char *in);
|
||||
char *utf8tofilename(const char *in);
|
||||
const char *htstvstreamtype2txt(tv_streamtype_t s);
|
||||
|
||||
#endif /* TV_HEAD_H */
|
||||
|
|
14
v4l.c
14
v4l.c
|
@ -464,7 +464,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
|
|||
uint32_t sc;
|
||||
uint8_t tsb0[188];
|
||||
uint8_t *tsb, *src;
|
||||
int64_t ts;
|
||||
int64_t ts, pcr = AV_NOPTS_VALUE;
|
||||
int hlen, tlen, slen, plen, cc, pad;
|
||||
uint16_t u16;
|
||||
th_transport_t *t;
|
||||
|
@ -482,6 +482,8 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
|
|||
sc = 0x1e0;
|
||||
p.tp_type = HTSTV_MPEG2VIDEO;
|
||||
p.tp_pid = 100;
|
||||
if(pts != AV_NOPTS_VALUE)
|
||||
pcr = dts;
|
||||
}
|
||||
|
||||
tsb = tsb0;
|
||||
|
@ -489,7 +491,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
|
|||
slen = len;
|
||||
len += 13;
|
||||
|
||||
*tsb++ = type;
|
||||
*tsb++ = 0x47;
|
||||
*tsb++ = p.tp_pid >> 8 | 0x40; /* payload unit start indicator */
|
||||
*tsb++ = p.tp_pid;
|
||||
|
||||
|
@ -549,8 +551,10 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
|
|||
memcpy(tsb, src, plen);
|
||||
|
||||
|
||||
LIST_FOREACH(t, &tva->tva_transports, tht_adapter_link)
|
||||
transport_recv_tsb(t, p.tp_pid, tsb0);
|
||||
LIST_FOREACH(t, &tva->tva_transports, tht_adapter_link) {
|
||||
transport_recv_tsb(t, p.tp_pid, tsb0, 0, pcr);
|
||||
pcr = AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
slen -= plen;
|
||||
if(slen == 0)
|
||||
|
@ -560,7 +564,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type,
|
|||
|
||||
tsb = tsb0;
|
||||
|
||||
*tsb++ = type;
|
||||
*tsb++ = 0x47;
|
||||
*tsb++ = p.tp_pid >> 8;
|
||||
*tsb++ = p.tp_pid;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue