File:  [DVB] / multiplexer / splicets.c
Revision 1.24: download - view: text, annotated - select for diffs
Sat Jan 15 20:39:50 2005 UTC (19 years, 4 months ago) by oskar
Branches: MAIN
CVS tags: version-1-1-7, version-1-1-6, version-1-1-5, version-1-1-4, version-1-1-3, version-1-1-2, version-1-1-1, version-1-1-0, version-1-0-8, version-1-0-7, version-1-0-6, HEAD
add command --nit to control network pid in pat

/*
 * ISO 13818 stream multiplexer
 * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
 * Copyright (C) 2004..2005 Oskar Schirmer (schirmer@scara.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * 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 "crc32.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 boolean unchanged_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 short network_pid = 0;

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

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

static stump_descr *globalstumps;

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;
  globalstumps = NULL;
  return (TRUE);
}

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

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

void splice_setnetworkpid (short pid)
{
  if ((pid < 0) || (pid > TS_PID_HIGHEST)) {
    network_pid = 0;
  } else {
    network_pid = pid;
  }
}

static int findapid (stream_descr *s, int desire)
{
  byte okness = 2;
  int h;
  if (conservative_pid_assignment
   && (desire >= 0)
   && (outs[desire] == NULL)
   && (input_tssiinafilerange (desire) < 0)) {
    return (desire);
  }
  do {
    if ((nextpid < TS_PID_SPLICELO) || (nextpid >= TS_PID_SPLICEHI)) {
      warn (LDEB,"Next PID",ETSC,1,okness,nextpid);
      if (okness == 0) {
        warn (LERR,"No PID found",ETSC,2,1,0);
        return (0);
      }
      okness -= 1;
      nextpid = TS_PID_SPLICELO;
    } else {
      warn (LDEB,"Next PID",ETSC,2,okness,nextpid);
      nextpid += 1;
    }
    if (okness != 0) {
      h = input_tssiinafilerange (nextpid);
      warn (LDEB,"Next PID",ETSC,3,h,nextpid);
      if (h >= 0) {
        nextpid = h;
      }
    } else {
      h = -1;
    }
  } while ((h >= 0)
        || (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_must_print) {
    i = progs;
    fprintf (stderr, configuration_total, i);
    while (--i >= 0) {
      splice_one_configuration (prog[i]);
    }
    configuration_was_printed;
  }
}

void splice_addsirange (file_descr *f,
    int lower,
    int upper)
{
  int i, r;
  tssi_descr *tssi;
  prog_descr *p;
  tssi = malloc (sizeof (tssi_descr));
  if (tssi != NULL) {
    if (ts_file_stream (f,TS_UNPARSED_SI) == NULL) {
      ts_file_stream (f,TS_UNPARSED_SI) = input_openstream (f,
              TS_UNPARSED_SI,0,0,sd_unparsedsi,NULL);
    }
    if (ts_file_stream (f,TS_UNPARSED_SI) != NULL) {
      tssi->next = f->u.ts.tssi;
      tssi->pid_low = lower;
      tssi->pid_high = upper;
      f->u.ts.tssi = tssi;
      r = upper; /* check for collision against existing PIDs, first sd_data */
      while (r >= lower) {
        stream_descr *s;
        s = outs[r];
        if ((s != NULL)
         && (s != PMT_STREAM)) {
          if (s->streamdata == sd_data) {
            i = findapid (s, -1);
            if (input_tssiinafilerange (i) >= 0) { /* none free! */
              outs[i] = NULL;
            } else {
              int j;
              s->u.d.pid = i;
              j = s->u.d.progs;
              while (--j >= 0) {
                p = s->u.d.pdescr[j];
                p->changed = TRUE;
                if (p->pcr_pid == r) {
                  p->pcr_pid = i;
                }
              }
              configuration_changed = TRUE;
              outs[r] = NULL;
            }
          } else {
            warn (LERR,"Bad PID",ETSC,11,s->streamdata,r);
          }
        }
        r -= 1;
      }
      i = progs; /* ...then sd_map */
      while (--i >= 0) {
        p = prog[i];
        r = p->pmt_pid;
        if ((r >= lower)
         && (r <= upper)) {
          int q;
          q = findapid (PMT_STREAM, -1);
          if (input_tssiinafilerange (q) >= 0) { /* none free! */
            outs[q] = NULL;
          } else {
            int j;
            outs[r] = NULL;
            j = i;
            while (--j >= 0) {
              if (prog[j]->pmt_pid == r) {
                prog[j]->pmt_pid = q;
              }
            }
            p->pmt_pid = q;
            changed_pat = TRUE;
            configuration_changed = TRUE;
          }
        }
      }
    } else {
      free (tssi);
    }
  }
}

void splice_createstump (int programnb,
    short pid,
    byte styp)
{
  prog_descr *p;
  stump_descr **pst;
  stump_descr *st;
  p = splice_getprog (programnb);
  if (p != NULL) {
    configuration_changed = TRUE;
    p->changed = TRUE;
    pst = &(p->stump);
  } else {
    pst = &globalstumps;
  }
  st = *pst;
  while ((st != NULL)
      && ((st->pid != pid)
       || (st->program_number != programnb))) {
    st = st->next;
  }
  if (st == NULL) {
    st = malloc (sizeof(stump_descr));
    st->next = *pst;
    st->program_number = programnb;
    st->pid = pid;
    *pst = st;
  }
  st->stream_type = styp;
  clear_descrdescr (&(st->manudescr));
  splice_modifycheckmatch (programnb,p,NULL,st);
}

stump_descr *splice_getstumps (int programnb,
    short pid)
{
  prog_descr *p;
  stump_descr **pst;
  stump_descr *rl;
  rl = NULL;
  p = splice_getprog (programnb);
  if (p != NULL) {
    pst = &(p->stump);
  } else {
    pst = &globalstumps;
  }
  while (*pst != NULL) {
    stump_descr *st;
    st = *pst;
    if ((st->program_number == programnb)
     && ((pid < 0)
      || (pid == st->pid))) {
      st = *pst;
      *pst = st->next;
      st->next = rl;
      rl = st;
      if (p != NULL) {
        configuration_changed = TRUE;
        p->changed = TRUE;
      }
    } else {
      pst = &((*pst)->next);
    }
  }
  return (rl);
}

void splice_modifytargetdescriptor (int programnb,
    short sid,
    short pid,
    int dtag,
    int dlength,
    byte *data)
{
  int i;
  if (programnb < 0) {
    i = progs;
    while (--i >= 0) {
      splice_modifytargetdescrprog (prog[i],
          prog[i]->program_number,-1,0,-1,-1,NULL,globalstumps);
    }
    splice_modifytargetdescrprog (NULL,-1,-1,0,-1,-1,NULL,globalstumps);
  } else {
    splice_modifytargetdescrprog (splice_getprog (programnb),
        programnb,sid,pid,dtag,dlength,data,globalstumps);
  }
}

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, -1)) > 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;
          p->stump = splice_getstumps (programnb,-1);
          clear_descrdescr (&p->manudescr);
          prog[progs++] = p;
          changed_pat = TRUE;
          configuration_changed = TRUE;
          splice_modifycheckmatch (programnb,p,NULL,NULL);
        } 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);
  }
  releasechain (stump_descr,p->stump);
  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) {
    pid = findapid (s,(s->fdescr->content == ct_transport) ? s->sourceid : -1);
    if (pid > 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;
      splice_modifycheckmatch (p->program_number,p,s,NULL);
    }
  }
  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;
  prog_descr *p;
  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) {
    p = prog[i];
    if (p->pat_section == section) {
      int x;
      x = p->program_number;
      *d++ = (x >> 8);
      *d++ = x;
      x = p->pmt_pid;
      *d++ = 0xE0 | (x >> 8);
      *d++ = x;
    }
  }
  if (network_pid > 0) {
    *d++ = 0;
    *d++ = 0;
    *d++ = 0xE0 | (network_pid >> 8);
    *d++ = network_pid;
  }
  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;
  stump_descr *st;
  stream_descr *t;
  d = dest;
  *d++ = TS_TABLEID_PMT;
  d += 2;
  i = p->program_number;
  *d++ = (i >> 8);
  *d++ = i;
  *d++ = 0xC0 | 0x01 | (p->pmt_version << 1);
  *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_DESCR;
  while (--i >= 0) {
    byte *y;
    y = p->manudescr.refx[i];
    if ((y == NULL)
     && (s->u.d.mapstream != NULL)) {
      y = s->u.d.mapstream->autodescr->refx[i]; /* why this one? */
    }
    if (y != NULL) {
      int yl = y[1];
      if (yl != 0) {
        yl += 2;
        memcpy (d,y,yl);
        d += yl;
      }
    }
  }
  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) {
    t = p->stream[i];
    if (t->u.d.mention) {
      int x;
      byte *e;
      *d++ = t->stream_type;
      x = t->u.d.pid;
      *d++ = 0xE0 | (x >> 8);
      *d++ = x;
      d += 2;
      e = d;
      x = NUMBER_DESCR;
      while (--x >= 0) {
        byte *y;
        y = t->manudescr->refx[x];
        if (y == NULL) {
          y = t->autodescr->refx[x];
        }
        if (y != NULL) {
          int yl = y[1];
          if (yl != 0) {
            yl += 2;
            memcpy (d,y,yl);
            d += yl;
          }
        }
      }
      x = d - e;
      *--e = x;
      *--e = 0xF0 | (x >> 8);
    }
  }
  st = p->stump;
  while (st != NULL) {
    int x;
    byte *e;
    *d++ = st->stream_type;
    x = st->pid;
    *d++ = 0xE0 | (x >> 8);
    *d++ = x;
    d += 2;
    e = d;
    x = NUMBER_DESCR;
    while (--x >= 0) {
      byte *y;
      y = st->manudescr.refx[x];
      if (y != NULL) {
        int yl = y[1];
        if (yl != 0) {
          yl += 2;
          memcpy (d,y,yl);
          d += yl;
        }
      }
    }
    x = d - e;
    *--e = x;
    *--e = 0xF0 | (x >> 8);
    st = st->next;
  }
  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;
  int i, l;
  prog_descr *p;
  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))) {
        unchanged_pat = TRUE;
        l = progs;
        while (--l >= 0) {
          prog[l]->unchanged = TRUE;
        }
        psi_frequency_changed = FALSE;
        next_psi_periodic = now + psi_frequency_msec;
      }
      if (unchanged_pat || changed_pat) {
        psi_pid = TS_PID_PAT;
        conticnt = &pat_conticnt;
        psi_data[0] = 0;
        if ((pat_section == 0)
         && (changed_pat)) {
          nextpat_version = (nextpat_version+1) & 0x1F;
        }
        psi_size = make_patsection (pat_section,&psi_data[1]) + 1;
        if (pat_section >= last_patsection) {
          changed_pat = FALSE;
          unchanged_pat = FALSE;
          pat_section = 0;
        } else {
          pat_section += 1;
        }
        psi_done = 0;
        *pid = psi_pid;
        *scramble = 0;
        *size = psi_size;
      } else {
        l = s->u.d.progs;
        while (--l >= 0) {
          p = s->u.d.pdescr[l];
          if (p->unchanged || p->changed) {
            i = p->streams;
            while ((--i >= 0)
                && (!p->stream[i]->u.d.mention)) {
            }
            if (i >= 0) {
              psi_pid = p->pmt_pid;
              conticnt = &p->pmt_conticnt;
              psi_data[0] = 0;
              if (p->changed) {
                p->pmt_version = (p->pmt_version+1) & 0x1F;
              }
              psi_size = make_pmtsection (s,p,&psi_data[1]) + 1;
              p->changed = FALSE;
              p->unchanged = FALSE;
              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->sourceid,s->streamdata);
  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, TRUE, 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, FALSE, 0);
      if (d == NULL) {
        return (s);
      }
      proc_unparsedsi (s,d);
      return (NULL);
      break;
    default:
      return (NULL);
      break;
  }
}


LinuxTV legacy CVS <linuxtv.org/cvs>