File:  [DVB] / multiplexer / splicets.c
Revision 1.12: download - view: text, annotated - select for diffs
Thu Jul 19 09:52:34 2001 UTC (22 years, 10 months ago) by oskar
Branches: MAIN
CVS tags: HEAD
Fix segfault bug caused by PAT map stream closed without closing the whole file
because unparsed si is still done,
Fix potential bug that might cause endless loop skipping unparsed si.

/*
 * ISO 13818 stream multiplexer
 * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
 * Author: Oskar Schirmer (oskar@convergence.de)
 */

/*
 * Module:  Splice TS
 * Purpose: Generate transport stream.
 *
 * This module generates from the available input stream data (as
 * seperated by the split functions) the complete output stream.
 * It provides functions to handle programs for the resulting stream,
 * as these are output format dependent. Further, it accepts PSI data
 * just in time, validating it not earlier than with the arrival of
 * the corresponding payload at this stage.
 */

#include "global.h"
#include "crc.h"
#include "error.h"
#include "input.h"
#include "output.h"
#include "descref.h"
#include "splitts.h"
#include "pes.h"
#include "ts.h"
#include "splice.h"
#include "splicets.h"

const boolean splice_multipleprograms = TRUE;

static boolean changed_pat;
static int pat_section;
static const int last_patsection = 0;
static byte nextpat_version;
static byte pat_conticnt;

static int transportstreamid;

static int psi_size;
static int psi_done;
static byte psi_data [MAX_PSI_SIZE];

static byte unit_start;
static byte *conticnt;
static int psi_pid;

static int progs;
static prog_descr *prog [MAX_OUTPROG];

static int nextpid;
static stream_descr *outs [MAX_STRPERTS];

boolean splice_specific_init (void)
{
  progs = 0;
  nextpid = 0;
  memset (outs,0,sizeof(outs));
  changed_pat = TRUE;
  pat_section = 0;
  nextpat_version = 0;
  pat_conticnt = 0;
  psi_size = psi_done = 0;
  unit_start = TS_UNIT_START;
  transportstreamid = 0x4227;
  return (TRUE);
}

void splice_settransportstreamid (int tsid)
{
  transportstreamid = tsid;
}

void splice_setpsifrequency (t_msec freq)
{
  psi_frequency_msec = freq;
  psi_frequency_changed = TRUE;
}

static int findapid (stream_descr *s)
{
  boolean ok = TRUE;
  do {
    if ((nextpid < TS_PID_SPLICELO) || (nextpid >= TS_PID_SPLICEHI)) {
      if (!ok) {
        warn (LERR,"No PID found",ETSC,2,1,0);
        return (0);
      }
      ok = FALSE;
      nextpid = TS_PID_SPLICELO;
    } else {
      nextpid += 1;
    }
  } while (outs[nextpid] != NULL);
  outs[nextpid] = s;
  warn (LDEB,"Next PID",ETSC,2,2,nextpid);
  return (nextpid);
}

void splice_all_configuration (void)
{
  int i;
  if (configuration_on && configuration_changed) {
    i = progs;
    fprintf (stderr, configuration_total, i);
    while (--i >= 0) {
      splice_one_configuration (prog[i]);
    }
    configuration_changed = FALSE;
  }
}

prog_descr *splice_getprog (int programnb)
{
  int i;
  i = progs;
  while (--i >= 0) {
    if (prog[i]->program_number == programnb) {
      return (prog[i]);
    }
  }
  return (NULL);
}

prog_descr *splice_openprog (int programnb)
{
  prog_descr *p;
  int pid;
  warn (LIMP,"Open prog",ETSC,1,0,programnb);
  p = splice_getprog (programnb);
  if (p == NULL) {
    if (progs < MAX_OUTPROG) {
      if ((pid = findapid (PMT_STREAM)) > 0) {
        if ((p = malloc(sizeof(prog_descr))) != NULL) {
          p->program_number = programnb;
          p->pcr_pid = -1;
          p->pmt_pid = pid;
          p->pmt_conticnt = 0;
          p->pmt_version = 0;
          p->changed = TRUE;
          p->pat_section = 0; /* more ? */
          p->streams = 0;
          prog[progs++] = p;
          changed_pat = TRUE;
          configuration_changed = TRUE;
        } else {
          outs[pid] = NULL;
          warn (LERR,"Open prog",ETSC,1,1,0);
        }
      }
    } else {
      warn (LERR,"Max prog open",ETSC,1,2,0);
    }
  }
  return (p);
}

void splice_closeprog (prog_descr *p)
{
  int i, n;
  warn (LIMP,"Close prog",ETSC,3,0,p->program_number);
  configuration_changed = TRUE;
  while (p->streams > 0) {
    unlink_streamprog (p->stream[0],p);
  }
  n = -1;
  if (p->pmt_pid >= 0) {
    i = progs;
    while (--i >= 0) {
      if (prog[i]->pmt_pid == p->pmt_pid) {
        n += 1;
      }
    }
  }
  i = progs;
  while (--i >= 0) {
    if (prog[i] == p) {
      prog[i] = prog[--progs];
      if (n == 0) {
        outs[p->pmt_pid] = NULL;
      }
      free (p);
      changed_pat = TRUE;
      return;
    }
  }
  warn (LERR,"Close lost prog",ETSC,3,1,progs);
}

int splice_addstream (prog_descr *p,
    stream_descr *s,
    boolean force_sid)
{
  int pid = 0;
  warn (LIMP,"Add stream",ETSC,4,force_sid,s->stream_id);
  if (p->streams < MAX_STRPERPRG) {
    if ((pid = findapid (s)) > 0) {
      if (!force_sid) {
        s->stream_id = splice_findfreestreamid (p,s->stream_id);
      }
      p->stream[p->streams++] = s;
      p->changed = TRUE;
      s->u.d.pid = pid;
      configuration_changed = TRUE;
    }
  }
  return (pid);
}

boolean splice_delstream (prog_descr *p,
    stream_descr *s)
{
  int i;
  warn (LIMP,"Del stream",ETSC,5,0,s->u.d.pid);
  configuration_changed = TRUE;
  i = p->streams;
  while (--i >= 0) {
    if (p->stream[i] == s) {
      outs[s->u.d.pid] = NULL;
      p->stream[i] = p->stream[--(p->streams)];
      p->changed = TRUE;
      if (p->pcr_pid == s->u.d.pid) {
        p->pcr_pid = -1;
      }
      s->u.d.pid = 0;
      return (TRUE);
    }
  }
  warn (LERR,"Del lost stream",ETSC,5,1,p->streams);
  return (FALSE);
}

void process_finish (void)
{
  warn (LIMP,"Finish",ETSC,6,0,0);
}

static int make_patsection (int section,
    byte *dest)
{
  int i;
  byte *d;
  d = dest;
  *d++ = TS_TABLEID_PAT;
  d += 2;
  *d++ = transportstreamid >> 8;
  *d++ = (byte)transportstreamid;
  *d++ = 0xC0 | 0x01 | (nextpat_version << 1);
  *d++ = section;
  *d++ = last_patsection;
  i = progs;
  while (--i >= 0) {
    if (prog[i]->pat_section == section) {
      int x;
      x = prog[i]->program_number;
      *d++ = (x >> 8);
      *d++ = x;
      x = prog[i]->pmt_pid;
      *d++ = 0xE0 | (x >> 8);
      *d++ = x;
    }
  }
  i = d + CRC_SIZE - dest - TS_TRANSPORTID;
  dest[TS_SECTIONLEN] = 0xB0 | (i >> 8);
  dest[TS_SECTIONLEN+1] = i;
  crc32_calc (dest,i + TS_TRANSPORTID - CRC_SIZE,d);
  return (i + TS_TRANSPORTID);
}

static int make_pmtsection (stream_descr *s,
    prog_descr *p,
    byte *dest)
{
  int i;
  byte *d;
  p->changed = FALSE;
  d = dest;
  *d++ = TS_TABLEID_PMT;
  d += 2;
  i = p->program_number;
  *d++ = (i >> 8);
  *d++ = i;
  *d++ = 0xC0 | 0x01 | (p->pmt_version << 1);
  p->pmt_version = (p->pmt_version+1) & 0x1F;
  *d++ = 0;
  *d++ = 0;
  if (p->pcr_pid < 0) {
    stream_descr *pcrs;
    pcrs = splice_findpcrstream (p);
    if (pcrs == NULL) {
      pcrs = s;
    }
    pcrs->u.d.has_clockref = TRUE;
    pcrs->u.d.next_clockref = msec_now () - MAX_MSEC_PCRDIST;
    p->pcr_pid = pcrs->u.d.pid;
    configuration_changed = TRUE;
  }
  i = p->pcr_pid;
  *d++ = 0xE0 | (i >> 8);
  *d++ = i;
  d += 2;
  i = NUMBER_ELEMD;
  while (--i > 0) {
    if (s->fdescr->content == ct_program) {
      byte *y;
      y = s->fdescr->u.ps.stream[0]->elemdvld[i]; /* this one ? why ? */
      if (y != NULL) {
        memcpy (d,y,y[1]+2);
        d += y[1]+2;
      }
    }
  }
  i = d - dest - (TS_PMT_PILEN+2);
  dest[TS_PMT_PILEN] = 0xF0 | (i >> 8);
  dest[TS_PMT_PILEN+1] = i;
  i = p->streams;
  while (--i >= 0) {
    if (p->stream[i]->u.d.mention) {
      int x;
      byte *e;
      *d++ = p->stream[i]->stream_type;
      x = p->stream[i]->u.d.pid;
      *d++ = 0xE0 | (x >> 8);
      *d++ = x;
      d += 2;
      e = d;
      x = NUMBER_ELEMD;
      while (--x > 0) {
        byte *y;
        y = p->stream[i]->elemdvld[x];
        if (y != NULL) {
          memcpy (d,y,y[1]+2);
          d += y[1]+2;
        }
      }
      x = d - e;
      *--e = x;
      *--e = 0xF0 | (x >> 8);
    }
  }
  i = d + CRC_SIZE - dest - TS_TRANSPORTID;
  dest[TS_SECTIONLEN] = 0xB0 | (i >> 8);
  dest[TS_SECTIONLEN+1] = i;
  crc32_calc (dest,i + TS_TRANSPORTID - CRC_SIZE,d);
  return (i + TS_TRANSPORTID);
}

/* Check for generated psi data to-be-sent, select data source.
 * If PAT or PMT needs to be rebuild, do so. If PAT or PMT is (partially)
 * pending to be transmitted, select that to be packaged next. Otherwise
 * select data payload. Set pid, scramble mode and PES paket size.
 * Precondition: s!=NULL, !list_empty(s->ctrl), s->streamdata==sd_data.
 * Input: stream s, current ctrl fifo out c. 
 * Output: *pid, *scramble, *size (PES paket ~) for the stream to generate.
 */
static void procdata_check_psi (int *pid,
    byte *scramble,
    int *size,
    stream_descr *s,
    ctrl_buffer *c)
{
  t_msec now;
  if (psi_size > 0) {
    *pid = psi_pid;
    *scramble = 0;
    *size = psi_size;
  } else {
    if (unit_start != 0) {
      now = msec_now ();
      if ((psi_frequency_changed)
       || ((psi_frequency_msec > 0)
        && ((next_psi_periodic - now) <= 0))) {
        int l;
        changed_pat = TRUE;
        l = progs;
        while (--l >= 0) {
          prog[l]->changed = TRUE;
        }
        psi_frequency_changed = FALSE;
        next_psi_periodic = now + psi_frequency_msec;
      }
      if (changed_pat) {
        psi_pid = TS_PID_PAT;
        conticnt = &pat_conticnt;
        psi_data[0] = 0;
        psi_size = make_patsection (pat_section,&psi_data[1]) + 1;
        if (pat_section >= last_patsection) {
          changed_pat = FALSE;
          nextpat_version = (nextpat_version+1) & 0x1F;
          pat_section = 0;
        } else {
          pat_section += 1;
        }
        psi_done = 0;
        *pid = psi_pid;
        *scramble = 0;
        *size = psi_size;
      } else {
        int l;
        l = s->u.d.progs;
        while (--l >= 0) {
          if (s->u.d.pdescr[l]->changed) {
            int i;
            i = s->u.d.pdescr[l]->streams;
            while ((--i >= 0)
                && (!s->u.d.pdescr[l]->stream[i]->u.d.mention)) {
            }
            if (i >= 0) {
              psi_pid = s->u.d.pdescr[l]->pmt_pid;
              conticnt = &s->u.d.pdescr[l]->pmt_conticnt;
              psi_data[0] = 0;
              psi_size = make_pmtsection (s,s->u.d.pdescr[l],&psi_data[1]) + 1;
              psi_done = 0;
              *pid = psi_pid;
              *scramble = 0;
              *size = psi_size;
              return;
            }
          }
        }
        s->data.ptr[c->index+PES_STREAM_ID] = s->stream_id;
        conticnt = &s->conticnt;
        *pid = s->u.d.pid;
        *scramble = c->scramble;
        *size = c->length;
      }
    } else {
      *pid = s->u.d.pid;
      *scramble = c->scramble;
      *size = c->length;
    }
  }
}

/* Check for adaption field items to be filled in.
 * First assume no adaption field is set and the complete packet except the
 * header is available for payload. Then check which adaption fields have
 * to be set and decrease the free space accordingly.
 * Precondition: s!=NULL, !list_empty(s->ctrl), s->streamdata==sd_data.
 * Input: stream s, current ctrl fifo out c.
 * Output: *adapt_flags1, *adapt_flags2, *adapt_ext_len.
 * Return: number of bytes of free space available for payload.
 */
static int procdata_adaptfield_flags (byte *adapt_flags1,
    byte *adapt_flags2,
    int *adapt_ext_len,
    stream_descr *s,
    ctrl_buffer *c)
{
  int space;
  *adapt_ext_len = 1;
  *adapt_flags2 = 0;
  *adapt_flags1 = 0;
  space = TS_PACKET_SIZE - TS_PACKET_HEADSIZE;
  if ((psi_size <= 0)
   && (s->u.d.discontinuity)) { /* o, not for contents, but PCR-disco ? */
    s->u.d.discontinuity = FALSE;
    *adapt_flags1 |= TS_ADAPT_DISCONTI;
  }
  if (0) {
    *adapt_flags1 |= TS_ADAPT_RANDOMAC;
  }
  if (0) {
    *adapt_flags1 |= TS_ADAPT_PRIORITY;
  }
  if ((psi_size <= 0)
   && (s->u.d.has_clockref)
   && ((c->pcr.valid)
    || (s->u.d.next_clockref - (c->msecpush + s->u.d.delta) <= 0))) {
    *adapt_flags1 |= TS_ADAPT_PCRFLAG;
    space -= 6;
  }
  if ((psi_size <= 0)
   && ((c->opcr.valid)
    || ((!s->u.d.has_opcr)
     && (c->pcr.valid)))) {
    *adapt_flags1 |= TS_ADAPT_OPCRFLAG;
    space -= 6;
  }
  if (0) {
    *adapt_flags1 |= TS_ADAPT_SPLICING;
    space -= 1;
  }
  if (0) {
    int privdata;
    *adapt_flags1 |= TS_ADAPT_TPRIVATE;
    privdata = 0;
    space -= (privdata + 1);
  }
  if (0) {
    *adapt_flags2 |= TS_ADAPT2_LTWFLAG;
    *adapt_ext_len += 2;
  }
  if (0) {
    *adapt_flags2 |= TS_ADAPT2_PIECEWRF;
    *adapt_ext_len += 3;
  }
  if (0) {
    *adapt_flags2 |= TS_ADAPT2_SEAMLESS;
    *adapt_ext_len += 5;
  }
  if (*adapt_flags2 != 0) {
    *adapt_flags1 |= TS_ADAPT_EXTENSIO;
    space -= *adapt_ext_len;
  }
  if (*adapt_flags1 != 0) {
    space -= 2;
  }
  return (space);
}

/* Adjust size of adaption field against size of payload. Set flags.
 * Input: *space (number of bytes of free space available for payload),
 *   *adapt_flags1, size (number of bytes left to be sent).
 * Output: *space (corrected in case of padding is done via adaption field),
 *   *adapt_field_ctrl.
 * Return: Number of bytes of payload to be inserted into THIS packet.
 */
static int procdata_adaptfield_frame (int *space,
    byte *adapt_field_ctrl,
    byte adapt_flags1,
    int size)
{
  int payload;
  if (size < *space) {
    payload = size;
    if (adapt_flags1 == 0) {
      *space -= 1;
      if (*space > payload) {
        *space -= 1;
      }
    }
    *adapt_field_ctrl = TS_AFC_BOTH;
  } else {
    payload = *space;
    if (payload == 0) {
      *adapt_field_ctrl = TS_AFC_ADAPT;
    } else if (adapt_flags1 == 0) {
      *adapt_field_ctrl = TS_AFC_PAYLD;
    } else {
      *adapt_field_ctrl = TS_AFC_BOTH;
    }
  }
  return (payload);
}

/* Generate packet header.
 * Keep track of continuity counter (which is selected in procdata_check_psi).
 * Precondition: d!=NULL (data destination).
 * Input: pid, scramble, adaption_field_ctrl.
 * Return: d (increased by header size).
 */
static byte *procdata_syn_head (byte *d,
    int pid,
    byte scramble,
    byte adapt_field_ctrl)
{
  *d++ = TS_SYNC_BYTE;
  warn (LSEC,"Splice unitstart",ETSC,7,1,unit_start);
  warn (LSEC,"Splice PID",ETSC,7,2,pid);
  *d++ = (0 << 7) /* transport_error_indicator */
       | unit_start
       | (0 << 5) /* transport_priority */
       | (pid >> 8);
  *d++ = pid;
  *d++ = (scramble << 6)
       | adapt_field_ctrl
       | *conticnt;
  warn (LSEC,"Splice continuity cnt",ETSC,7,3,*conticnt);
  if (adapt_field_ctrl & TS_AFC_PAYLD) {
    *conticnt = (*conticnt+1) & 0x0F;
  }
  return (d);
}

/* Generate adpation field.
 * This MUST match the calculations in procdata_adaptfield_flags.
 * Precondition: s!=NULL.
 * Input: s (stream), c (current ctrl fifo out), d (data destination),
 *   padding (number of padding bytes needed), payload (number of payload bytes
 *   to insert), adapt_field_ctrl, adapt_flags1, adapt_flags2, adapt_ext_len.
 * Return: d (increased by adaption field size).
 */
static byte *procdata_syn_adaptfield (stream_descr *s,
    ctrl_buffer *c,
    byte *d,
    int padding,
    int payload,
    byte adapt_field_ctrl,
    byte adapt_flags1,
    byte adapt_flags2,
    int adapt_ext_len)
{
  if (adapt_field_ctrl & TS_AFC_ADAPT) {
    if ((*d++ = (TS_PACKET_SIZE - TS_PACKET_FLAGS1) - payload) != 0) {
      *d++ = adapt_flags1;
      if (adapt_flags1 & TS_ADAPT_PCRFLAG) {
        clockref pcr;
        msec2cref (&s->u.d.conv,c->msecpush + s->u.d.delta,&pcr);
        *d++ = (pcr.base >> 25) | (pcr.ba33 << 7);
        *d++ = pcr.base >> 17;
        *d++ = pcr.base >> 9;
        *d++ = pcr.base >> 1;
        *d++ = (pcr.base << 7) | (pcr.ext >> 8) | 0x7E;
        *d++ = pcr.ext;
        s->u.d.next_clockref =
          (c->msecpush + s->u.d.delta) + MAX_MSEC_PCRDIST;
        c->pcr.valid = FALSE;
      }
      if (adapt_flags1 & TS_ADAPT_OPCRFLAG) {
        clockref *opcr;
        if (c->opcr.valid) {
          opcr = &c->opcr;
        } else {
          opcr = &c->pcr;
        }
        *d++ = (opcr->base >> 25) | (opcr->ba33 << 7);
        *d++ = opcr->base >> 17;
        *d++ = opcr->base >> 9;
        *d++ = opcr->base >> 1;
        *d++ = (opcr->base << 7) | (opcr->ext >> 8) | 0x7E;
        *d++ = opcr->ext;
        opcr->valid = FALSE;
      }
      if (adapt_flags1 & TS_ADAPT_SPLICING) {
      }
      if (adapt_flags1 & TS_ADAPT_TPRIVATE) {
      }
      if (adapt_flags1 & TS_ADAPT_EXTENSIO) {
        *d++ = adapt_ext_len;
        *d++ = adapt_flags2 | 0x1F;
        if (adapt_flags2 & TS_ADAPT2_LTWFLAG) {
        }
        if (adapt_flags2 & TS_ADAPT2_PIECEWRF) {
        }
        if (adapt_flags2 & TS_ADAPT2_SEAMLESS) {
        }
      }
    }
    if (padding > 0) {
      warn (LSEC,"Splice padding",ETSC,8,1,padding);
      memset (d,-1,padding);
      d += padding;
    }
  }
  return (d);
}

/* Generate payload portion.
 * Insert the appropriate payload (either PSI or data), check whether payload
 * from this PES packet or section is left.
 * Precondition: s!=NULL.
 * Input: s (stream), c (current ctrl fifo out), d (data destination),
 *   payload (number of payload bytes to insert).
 * Return: processed stream s, if there is more data from the current PES
 *   packet to be processed, NULL otherwise.
 */
static stream_descr *procdata_syn_payload (stream_descr *s,
    ctrl_buffer *c,
    byte *d,
    int payload)
{
  if (payload > 0) {
    if (psi_size > 0) {
      memcpy (d,&psi_data[psi_done],payload);
      if (payload < psi_size) {
        warn (LSEC,"Splice PSI Data",ETSC,9,s->stream_id,payload);
        psi_done += payload;
        psi_size -= payload;
        unit_start = 0;
      } else {
        warn (LINF,"Splice PSI Done",ETSC,9,s->stream_id,payload);
        psi_done = psi_size = 0;
        unit_start = TS_UNIT_START;
      }
    } else {
      memcpy (d,&s->data.ptr[c->index],payload);
      if (payload < c->length) {
        warn (LSEC,"Splice Data",ETSC,9,s->stream_id,payload);
        c->length -= payload;
        s->data.out = (c->index += payload);
        unit_start = 0;
      } else {
        warn (LINF,"Splice Done",ETSC,9,s->stream_id,payload);
        list_incr (s->ctrl.out,s->ctrl,1);
        if (list_empty (s->ctrl)) {
          s->data.out = s->data.in;
        } else {
          s->data.out = s->ctrl.ptr[s->ctrl.out].index;
        }
        unit_start = TS_UNIT_START;
        return (NULL);
      }
    }
  }
  return (s);
}

/* Process unparsed si data and generate output.
 * Take one TS paket, copy it to output stream data buffer.
 * Precondition: s!=NULL, !list_empty(s->ctrl), s->streamdata==sd_unparsedsi,
 *   s->ctrl.ptr[s->ctrl.out].length==TS_PACKET_SIZE, d!=NULL.
 */
static void proc_unparsedsi (stream_descr *s,
    byte *d)
{
  warn (LINF,"Splice Unparsed SI",ETSC,10,s->streamdata,s->u.usi.delta);
  warn (LDEB,"Splice Unparsed SI",ETSC,10,s->stream_id,s->sourceid);
  memcpy (d,&s->data.ptr[s->ctrl.ptr[s->ctrl.out].index],TS_PACKET_SIZE);
                /* check if ==  s->ctrl.ptr[s->ctrl.out].length); ? */
  list_incr (s->ctrl.out,s->ctrl,1);
  if (list_empty (s->ctrl)) {
    s->data.out = s->data.in;
    input_closefileifunused (s->fdescr);
  } else {
    s->data.out = s->ctrl.ptr[s->ctrl.out].index;
  }
}

stream_descr *process_something (stream_descr *s)
{
  byte *d;
  int pid;
  byte scramble;
  int size;
  ctrl_buffer *c;
  int payload;
  int space;
  int adapt_ext_len;
  byte adapt_field_ctrl;
  byte adapt_flags1, adapt_flags2;
  warn (LDEB,"Splice TS",ETSC,0,0,s->ctrl.out);
  switch (s->streamdata) {
    case sd_data:
      c = &s->ctrl.ptr[s->ctrl.out];
      procdata_check_psi (&pid, &scramble, &size, s, c);
      d = output_pushdata (TS_PACKET_SIZE,c->msecpush + s->u.d.delta);
      if (d == NULL) {
        return (s);
      }
      space = procdata_adaptfield_flags (&adapt_flags1, &adapt_flags2,
          &adapt_ext_len, s, c);
      payload = procdata_adaptfield_frame (&space, &adapt_field_ctrl,
          adapt_flags1, size);
      d = procdata_syn_head (d, pid, scramble, adapt_field_ctrl);
      d = procdata_syn_adaptfield (s, c, d, space-payload, payload,
          adapt_field_ctrl, adapt_flags1, adapt_flags2, adapt_ext_len);
      return (procdata_syn_payload (s, c, d, payload));
      break;
    case sd_map:
      validate_mapref (s);
      return (NULL);
      break;
    case sd_unparsedsi:
      c = &s->ctrl.ptr[s->ctrl.out];
      d = output_pushdata (TS_PACKET_SIZE,c->msecpush + s->u.usi.delta);
      if (d == NULL) {
        return (s);
      }
      proc_unparsedsi (s,d);
      return (NULL);
      break;
    default:
      return (NULL);
      break;
  }
}


LinuxTV legacy CVS <linuxtv.org/cvs>