rework much of the internal transport stream handling

This commit is contained in:
Andreas Öman 2007-09-14 21:45:21 +00:00
parent 895acc0180
commit 412cce5ea6
16 changed files with 308 additions and 115 deletions

View file

@ -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

View file

@ -35,7 +35,6 @@
#include "v4l.h"
#include "iptv_input.h"
#include "dvb_pmt.h"
#include "channels.h"
#include "transports.h"

View file

@ -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);
}

View file

@ -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
View file

@ -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);
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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>";
}
}

View file

@ -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
View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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
View file

@ -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;