File:  [DVB] / multiplexer / global.h
Revision 1.13: download - view: text, annotated - select for diffs
Fri Jul 20 16:49:55 2001 UTC (22 years, 10 months ago) by oskar
Branches: MAIN
CVS tags: HEAD
Fix segfaulty bug that occured when unparsed si was found to be processable
in precedence to data. Now the precedence is PAT comes first, next is PMT,
last is other unparsed si.
Increase number of programs per output file etc.

/*
 * 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 PES_LOWEST_SID    (0xBC)
#define NUMBER_ELEMD  19
#define TS_PACKET_SIZE 188

#define CRC_SIZE 4

#define MAX_MSEC_OUTDELAY  500
#define MAX_MSEC_PUSHJTTR  (2 * 250)
#define MAX_MSEC_PCRDIST   (100 * 80/100)

#define TRIGGER_MSEC_INPUT  250
#define TRIGGER_MSEC_OUTPUT 250

#define MAX_DATA_COMB 512
#define HIGHWATER_COM 8

#define MAX_CTRL_OUTB (1 << 16)
#define MAX_DATA_OUTB (MAX_CTRL_OUTB << 7)
#define HIGHWATER_OUT 512
#define MAX_WRITE_OUT (44 * TS_PACKET_SIZE)

#define MAX_CTRL_INB  (1 << 10)
#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_PSI_SIZE  (4096+1)
#define CAN_PSI_SIZE  (1024+1)
#define MAX_PMTSTREAMS (CAN_PSI_SIZE / 4)

#define MAX_STRPERPRG 42 /* ? */
#define MAX_OUTPROG   32  /* ? */
#define MAX_PRGFORSTR MAX_OUTPROG

#define MAX_POLLFD    (MAX_INFILE+3)

#define ENDSTR_KILL      0
#define ENDSTR_CLOSE     1
#define ENDSTR_WAIT      2

#define boolean __u8
#define FALSE   0
#define TRUE    1

#define byte __u8
#define t_msec __s32

/* ISO 13818 clock reference 90kHz (33 bit) with 27MHz extension (9 bit).
 * ba33 holds the high bit of base.
 */
typedef struct {
  __u32 base;
  __u16 ext;
  byte ba33;
  boolean valid;
} clockref;

/* For conversion purposes, this pair of values holds a partial clock
 * reference and an internal value in milliseconds. This is to eliminate
 * wrapping faults without producing conversion inaccuracies.
 */
typedef struct {
  __u32 base;
  t_msec msec;
} conversion_base;

/* On reference to a controlled data buffer, this one holds the control
 * information, mainly: index into the data buffer, length of the referenced
 * data block. In a controlled data buffer, a data block is never split to
 * wrap at the end of the buffer. The other fields are usage dependend.
 */
typedef struct {
  int index;
  int length;
  int sequence;
  t_msec msecread;
  t_msec msecpush;
  clockref pcr;
  clockref opcr;
  byte scramble;
} ctrl_buffer;

/* Control buffer */
typedef struct {
  ctrl_buffer *ptr;
  int in;
  int out;
  int mask;
} refr_ctrl;

/* Data buffer */
typedef struct {
  byte *ptr;
  int in;
  int out;
  int mask;
} refr_data;


/* Create a new buffer, return TRUE on success, FALSE otherwise */
#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))

/* Release a buffer no longer used */
#define list_release(refr) \
  ((refr).mask = 0, free((refr).ptr), (refr).ptr = NULL)

/* Test on buffer emptiness */
#define list_empty(refr) ((refr).out == (refr).in)

/* Compute number of free elements in buffer */
#define list_free(refr) \
  (((refr).out - (refr).in - 1) & (refr).mask)

/* Compute number of free elements up to the wrapping point, if the
   latter is included in the free part of the buffer */
#define list_freeinend(refr) \
  ((refr).mask + 1 - (refr).in)

/* Compute number of used elements in buffer (i.e. its current size) */
#define list_size(refr) \
  (((refr).in - (refr).out) & (refr).mask)

/* Test on buffer fullness */
#define list_full(refr) \
  (list_free(refr) == 0)

/* Test on buffer partial fullness (as trigger criterium) */
#define list_partialfull(refr) \
  (list_size(refr) > ((refr).mask * 3/4))

/* Increment an index variable that points in to a buffer by a given value */
#define list_incr(var,refr,incr) \
  ((var) = (((var) + (incr)) & (refr).mask))


/* Check a data byte against a mask */
#define marker_check(data,val,mask) \
  (((data & mask) != val) ? \
    warn(LWAR,"Marker bit",EGLO,2,data,mask), TRUE : FALSE)

/* Check whether a given bit is set in a data byte */
#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))

/* Allocate memory for a struct with known union usage */
#define unionalloc(typ,fld) \
  (malloc (sizeof(typ)-sizeof(((typ*)0)->u)+sizeof(((typ*)0)->u.fld)))

/* Release a chained list completely */
#define releasechain(typ,root) \
  { register typ *n, *p = root; \
    while (p != NULL) { \
      n = p->next; free (p); p = n; \
  } }

/* Supported input file types */
typedef enum {
  ct_packetized, /* packetized elementary stream */
  ct_program,    /* program stream */
  ct_transport,  /* transport stream */
  number_ct
} content_type;

/* stream data types, dependend on buffer contents */
typedef enum {
  sd_data,       /* PES packet */
  sd_map,        /* mapreference containing descriptors */
  sd_unparsedsi, /* TS packet containing raw partial SI sections */
  number_sd
} streamdata_type;

/* Reference descriptors as these are parsed from PSI */
typedef struct {
  int programnumber;
  short sourceid;
  byte version;
  byte *elemdnew[NUMBER_ELEMD];
} mapreference;

/* Source TS PMT list */
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;

/* Automatic stream usage requests as stated via command */
typedef struct tsautodescr {
  struct tsautodescr *next;
  int sprg;
  int tprg;
  int ssid; /* ssid<0 when referencing a complete program */
  int tsid;
} tsauto_descr;

/* Declaration of pid ranges as being not-to-be-parsed SI */
typedef struct tssidescr {
  struct tssidescr *next;
  short pid_low;
  short pid_high;
} tssi_descr;

/* Source file */
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 openstreams[number_sd];
  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;
      tsauto_descr *tsauto;
      tssi_descr *tssi;
      struct streamdescr *stream[MAX_STRPERTS];
    } ts;
  } u;
} file_descr;

/* Target program */
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;

/* Single data or map stream */
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?*/
  streamdata_type streamdata;
  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;
    struct {
      t_msec delta;
    } usi;
  } 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>