/*
* ISO 13818 stream multiplexer
* Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
* Author: Oskar Schirmer (oskar@convergence.de)
*/
#include <asm/types.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* for a timing and poll profile: */
#if 0
#define DEBUG_TIMEPOLL
#endif
#define MAX_MSEC_OUTDELAY 500
#define MAX_MSEC_PUSHJTTR (2 * 250)
#define MAX_MSEC_PCRDIST 100
#define PCR_INTERPOLSIZE 8
#define MAX_POLLFD (MAX_INFILE+3)
#define MAX_DATA_COMB 512
#define HIGHWATER_COM 8
#define BUFSIZ_FACTOR 32 * 2
#define MAX_CTRL_OUTB 32 * BUFSIZ_FACTOR
#define MAX_DATA_OUTB 4096 * BUFSIZ_FACTOR
#define HIGHWATER_OUT 512
#define MAX_WRITE_OUT (128 * 188)
#define OUT_TRIGCOND (MAX_DATA_OUTB / 2)
#define MAX_CTRL_INB 32 * BUFSIZ_FACTOR
#define MAX_DATA_INB 4096 * BUFSIZ_FACTOR
#define MAX_DATA_RAWB 4096 * BUFSIZ_FACTOR
#define HIGHWATER_IN (512 * 4 * 8)
#define MAX_READ_IN (1024 * 8)
#define IN_TRIGCOND (MAX_DATA_INB / 2)
#define MAX_INSTREAM 64 /* ? */
#define MAX_INFILE 8 /* ? */
#define MAX_STRPERPS (1<<8)
#define MAX_STRPERTS (1<<13)
#define MAX_STRPERPRG 42 /* ? */
#define MAX_PRGFORSTR 12 /* ? */
#define MAX_OUTPROG 16 /* ? */
/*
#define MAX_CTRL_MAPSTR 4
#define MAX_DATA_MAPSTR 4096
*/
#define MAX_PSI_SIZE 1025
#define MAX_PMTSTREAMS (MAX_PSI_SIZE / 4)
#define ENDFILE_CLOSE 0
#define ENDFILE_RESET 1
#define ENDFILE_CHAIN 2
#define ENDSTR_KILL 0
#define ENDSTR_CLOSE 1
#define ENDSTR_WAIT 2
#define PES_LOWEST_SID (0xBC)
#define NUMBER_ELEMD 19
#define TS_PACKET_SIZE 188
#define CRC_SIZE 4
#define boolean __u8
#define FALSE 0
#define TRUE 1
#define byte __u8
typedef struct {
unsigned long base;
unsigned short ext;
unsigned char ba33;
boolean valid;
} clockref;
/*
#define MIXTIME_MSEC 0x01
#define MIXTIME_TVAL 0x02
#define MIXTIME_CREF 0x04
#define mixflag cr.flags
typedef struct {
int msec;
struct timeval tv;
clockref cr;
clockref *localrelativeclockref;
} mixtime;
*/
typedef struct {
int read;
int push;
} time_stamp;
typedef struct {
int index;
int length;
int sequence;
int scramble;
time_stamp time;
clockref pcr; /* FIXME: this goes parallel to time.push */
clockref opcr;
} ctrl_buffer;
typedef struct {
ctrl_buffer *ptr;
int in;
int out;
int mask;
} refr_ctrl;
typedef struct {
byte *ptr;
int in;
int out;
int mask;
} refr_data;
#define list_empty(refr) ((refr).out == (refr).in)
#define list_create(refr,size) \
((((size) & ((size)-1)) || (size < 2)) ? \
warn (LERR,"List Create",EGLO,1,1,size), FALSE : \
((refr).ptr = malloc((size) * sizeof(*(refr).ptr))) == NULL ? \
warn (LERR,"List Create",EGLO,1,2,size), FALSE : \
((refr).mask = (size)-1, (refr).in = (refr).out = 0, TRUE))
#define list_release(refr) \
((refr).mask = 0, free((refr).ptr), (refr).ptr = NULL)
#define list_free(refr) \
(((refr).out - (refr).in - 1) & (refr).mask)
#define list_freeinend(refr) \
((refr).mask + 1 - (refr).in)
#define list_size(refr) \
(((refr).in - (refr).out) & (refr).mask)
#define list_full(refr) \
(list_free(refr) == 0)
#define list_incr(var,refr,incr) \
((var) = (((var) + (incr)) & (refr).mask))
#define clockref2msec(cref) \
((cref).base / 90)
#define msec2clockref(msec,cref) \
(((cref).base = (msec) * 90), ((cref).ext = 0), ((cref).ba33 = 0))
#define marker_check(data,val,mask) \
(((data & mask) != val) ? \
warn(LWAR,"Marker bit",EGLO,2,data,mask), TRUE : FALSE)
#define marker_bit(data,bit) \
marker_check(data,1<<bit,1<<bit)
#define mmin(a,b) ((a)<(b)?(a):(b))
#define mmax(a,b) ((a)<(b)?(b):(a))
#define unionalloc(typ,fld) \
(malloc (sizeof(typ)-sizeof(((typ*)0)->u)+sizeof(((typ*)0)->u.fld)))
typedef struct {
int sourceid;
int programnumber;
byte version;
byte *elemdnew[NUMBER_ELEMD];
} mapreference;
typedef struct pmtdescr {
struct pmtdescr *next;
short pat_section;
byte pmt_version;
int programnumber;
int pcr_pid;
int pmt_pid;
int streams;
short stream[MAX_PMTSTREAMS];
byte streamtype[MAX_PMTSTREAMS];
int descrlen;
byte elemdescr[MAX_PSI_SIZE];
} pmt_descr;
typedef struct {
int sprg, tprg, ssid, tsid;
} tsauto_descr;
typedef enum {
ct_none,
/* ct_elementary, */
ct_packetized,
ct_program,
ct_transport,
ct_unknown
} content_type;
typedef struct {
refr_data data;
char *name;
int handle;
struct stat stat;
struct pollfd *ufds;
int skipped; /* undesired bytes skipped, total */
int payload; /* split payload used total */
int total; /* split total (skipped, used, wasted) */
int sequence; /* source counter for PES sequence */
int opendatastreams;
int openmapstreams;
byte endaction;
boolean automatic; /* extract'o'use */
int auto_programnb;
content_type content;
union {
struct {
struct streamdescr *stream;
} pes;
struct {
time_stamp time;
struct {
clockref scr;
long muxrate;
} ph;
struct {
long ratebound;
int audiobound;
int videobound;
boolean csps_flag;
boolean fixed_flag;
boolean system_video_lock_flag;
boolean system_audio_lock_flag;
boolean packet_rate_restriction_flag;
short buffer_bound[MAX_STRPERPS-PES_LOWEST_SID];
} sh;
/*
struct {
} dir;
*/
struct streamdescr *stream[MAX_STRPERPS];
} ps;
struct {
int transportstreamid;
byte pat_version;
byte newpat_version;
pmt_descr *pat;
pmt_descr *newpat;
int tsautos;
tsauto_descr *tsauto;
struct streamdescr *stream[MAX_STRPERTS];
} ts;
} u;
} file_descr;
typedef struct {
int program_number;
int pcr_pid;
int pmt_pid;
int map_sequence; /* don't need ? */
byte pmt_conticnt;
byte pmt_version;
boolean changed;
int pat_section;
int streams;
struct streamdescr *stream[MAX_STRPERPRG];
} prog_descr;
typedef struct streamdescr {
refr_ctrl ctrl;
refr_data data;
int sourceid; /* index into fdescr->u.xx.stream[] */
byte stream_id; /* elementary stream id, table 2-35, etc */
byte stream_type;
byte version;
byte *elemdvld[NUMBER_ELEMD]; /* as valid for out */
byte elemdescr[MAX_PSI_SIZE];
/*what if a stream is leftupper corner in one prog, but elsewhere in another?*/
file_descr *fdescr;
byte conticnt;
byte endaction;
boolean isamap;
union {
struct {
int pid; /* splicets: 0010..1FFE, spliceps: ...FF */
struct streamdescr *mapstream;
boolean discontinuity;
boolean trigger;
boolean mention;
boolean has_clockref; /* in output */
int next_clockref;
int delta;
int lasttime;
int progs;
prog_descr *pdescr[MAX_PRGFORSTR];
} d;
struct {
int readtime;
int psi_length;
byte psi_data[MAX_PSI_SIZE+TS_PACKET_SIZE];
} m;
} u;
} stream_descr;
extern boolean timed_io;
extern boolean accept_weird_scr;
extern int global_delta;
extern int psi_frequency_msec;
extern boolean psi_frequency_changed;
int msec_now (void);
void global_init (void);
#ifdef DEBUG_TIMEPOLL
#define max_timepoll (1024*1024)
typedef struct {
struct timeval tv;
int msec_now;
int usec;
int tmo;
int sr, si, so;
unsigned char cnt_msecnow;
unsigned char nfdso, nfdsi;
unsigned char nfdsrevent;
unsigned char flags;
} timepoll;
#define LTP_FLAG_DELTASHIFT 0x80
#define LTP_FLAG_OUTPUT 0x40
#define LTP_FLAG_INPUT 0x20
#define LTP_FLAG_SPLIT 0x10
#define LTP_FLAG_PROCESS 0x08
extern timepoll logtp [max_timepoll];
extern long logtpc;
extern timepoll *ltp;
#endif
LinuxTV legacy CVS <linuxtv.org/cvs>