/*
* 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 * 80/100)
#define MAX_POLLFD (MAX_INFILE+3)
#define MAX_DATA_COMB 512
#define HIGHWATER_COM 8
#define MAX_CTRL_OUTB (1 << 11)
#define MAX_DATA_OUTB (MAX_CTRL_OUTB << 7)
#define HIGHWATER_OUT 512
#define MAX_WRITE_OUT (128 * 188)
#define MAX_CTRL_INB (1 << 8)
#define MAX_DATA_INBV (MAX_CTRL_INB << 10)
#define MAX_DATA_INBA (MAX_CTRL_INB << 9)
#define MAX_DATA_INB (MAX_CTRL_INB << 9)
#define HIGHWATER_IN (16 * 1024)
#define MAX_DATA_RAWB (1 << 18)
#define HIGHWATER_RAW (16 * 1024)
#define MAX_READ_IN (8 * 1024)
#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_PSI_SIZE 1025
#define MAX_PMTSTREAMS (MAX_PSI_SIZE / 4)
#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
#define t_msec __s32
typedef struct {
__u32 base;
__u16 ext;
byte ba33;
boolean valid;
} clockref;
typedef struct {
__u32 base;
t_msec msec;
} conversion_base;
typedef struct {
int index;
int length;
int sequence;
t_msec msecread;
t_msec msecpush;
clockref pcr;
clockref opcr;
byte scramble;
} 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_halffull(refr) \
(list_size(refr) > ((refr).mask >> 1))
#define list_incr(var,refr,incr) \
((var) = (((var) + (incr)) & (refr).mask))
#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 programnumber;
short sourceid;
byte version;
byte *elemdnew[NUMBER_ELEMD];
} mapreference;
typedef struct pmtdescr {
struct pmtdescr *next;
short pat_section;
byte pmt_version;
int programnumber;
short pcr_pid;
short pmt_pid;
short streams;
short stream[MAX_PMTSTREAMS];
byte streamtype[MAX_PMTSTREAMS];
short descrlen;
byte elemdescr[MAX_PSI_SIZE];
} pmt_descr;
typedef struct {
int sprg, tprg, ssid, tsid;
} tsauto_descr;
typedef enum {
ct_none,
ct_packetized,
ct_program,
ct_transport,
ct_unknown
} content_type;
typedef struct {
refr_data data;
int handle;
char *name;
int filerefnum;
int st_mode;
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 */
short opendatastreams;
short openmapstreams;
char *append_name;
int append_filerefnum;
int append_repeatitions;
int repeatitions;
int auto_programnb;
boolean automatic; /* extract'o'use */
boolean stopfile;
content_type content;
union {
struct {
struct streamdescr *stream;
} pes;
struct {
struct {
clockref scr;
__u32 muxrate;
} ph;
struct {
__u32 ratebound;
byte audiobound;
byte 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 {
__u16 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;
short pcr_pid;
short pmt_pid;
byte pmt_conticnt;
byte pmt_version;
boolean changed;
short pat_section;
short streams;
struct streamdescr *stream[MAX_STRPERPRG];
} prog_descr;
typedef struct streamdescr {
refr_ctrl ctrl;
refr_data data;
file_descr *fdescr;
short sourceid; /* index into fdescr->u.xx.stream[] */
byte stream_id; /* elementary stream id, table 2-35, etc */
byte stream_type;
byte version;
byte conticnt;
byte endaction;
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?*/
boolean isamap;
union {
struct {
struct streamdescr *mapstream;
t_msec next_clockref;
t_msec delta;
conversion_base conv;
t_msec lasttime;
short pid; /* splicets: 0010..1FFE, spliceps: ...FF */
boolean discontinuity;
boolean trigger;
boolean mention;
boolean has_clockref; /* in output */
boolean has_opcr; /* in input */
short progs;
prog_descr *pdescr[MAX_PRGFORSTR];
} d;
struct {
t_msec msectime;
conversion_base conv;
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 t_msec global_delta;
extern t_msec psi_frequency_msec;
extern boolean psi_frequency_changed;
t_msec msec_now (void);
void cref2msec (conversion_base *b,
clockref c,
t_msec *m);
void msec2cref (conversion_base *b,
t_msec m,
clockref *c);
void global_init (void);
#ifdef DEBUG_TIMEPOLL
#define max_timepoll (1024*1024)
typedef struct {
struct timeval tv;
t_msec 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>