File:  [DVB] / multiplexer / splitpes.c
Revision 1.3: download - view: text, annotated - select for diffs
Tue Apr 3 21:14:33 2001 UTC (23 years, 2 months ago) by oskar
Branches: MAIN
CVS tags: HEAD
cleaning up.
buffer sizes now depend on split data type (video,audio,other).
new functions to unlink and remove streams from programs.
do not start dispatcher when command line is --help.
new command "crop" to remove program or stream from target.

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

/*
 * Module:  Split PES
 * Purpose: Split a packetized elementary stream.
 *
 * This module examines a packetized elementary stream and copies the
 * packets to the input stream buffer. Some of the service functions
 * provided are also used by module Split PS due to similarity of the
 * format.
 */

#include "global.h"
#include "error.h"
#include "pes.h"
#include "splitpes.h"
#include "input.h"
#include "splice.h"

int guess_streamtype (int streamid)
{
  if ((streamid >= PES_CODE_AUDIO)
   && (streamid < PES_CODE_AUDIO + PES_NUMB_AUDIO)) {
    return (PES_STRTYP_AUDIO13818);
  }
  if ((streamid >= PES_CODE_VIDEO)
   && (streamid < PES_CODE_VIDEO + PES_NUMB_VIDEO)) {
    return (PES_STRTYP_VIDEO13818);
  }
  switch (streamid) {
    case PES_CODE_PRIVATE1:
    case PES_CODE_PRIVATE2:
      return (PES_STRTYP_PRIVATDATA);
    case PES_CODE_DSMCC:
      return (PES_STRTYP_DSMCC);
    case PES_CODE_ITU222A:
    case PES_CODE_ITU222B:
    case PES_CODE_ITU222C:
    case PES_CODE_ITU222D:
    case PES_CODE_ITU222E:
      return (PES_STRTYP_ITUH222);
    case PES_CODE_ISO13522:
      return (PES_STRTYP_MHEG13522);
    default:
      return (0); 
  }
}

boolean pes_skip_to_prefix (file_descr *f)
{
  unsigned int p;
  int i, l, k;
  boolean r = FALSE;
  l = k = list_size (f->data);
  i = f->data.out;
  p = 2;
  while ((l > 0)
      && ((p != 0x000001) || (r = TRUE, FALSE))) {
    p = ((p & 0x0000FFFF) << 8) | f->data.ptr[i];
    list_incr (i,f->data,1);
    l -= 1;
  }
  k = k - l - PES_SYNC_SIZE;
  if (k > 0) {
    warn (LWAR,"Skipped",EPES,1,1,k);
    f->skipped += k; /* evaluate: skip > good and skip > CONST -> bad */
    f->total += k;
    list_incr (f->data.out,f->data,k);
  }
  return (r);
}

int pes_stream_id (refr_data *d)
{
  int i;
  i = d->out;
  list_incr (i,*d,PES_STREAM_ID);
  warn (LINF,"Stream Id",EPES,2,1,d->ptr[i]);
  return (d->ptr[i]);
}

int pes_packet_length (refr_data *d)
{ /* special case len = 0: to do 2.4.3.7 */
#define MAX_PACKETSIZE_PROCESSABLE \
    (mmin((MAX_DATA_RAWB-HIGHWATER_RAW),(MAX_DATA_INB/2)) - PES_HEADER_SIZE)
  int i;
  __u16 l;
  i = d->out;
  list_incr (i,*d,PES_PACKET_LENGTH);
  l = d->ptr[i] << 8;
  list_incr (i,*d,1);
  l = l | d->ptr[i];
  if (l > MAX_PACKETSIZE_PROCESSABLE) {
    warn (LWAR,"Packet too large",EPES,3,2,l);
    l = MAX_PACKETSIZE_PROCESSABLE;
  }
  warn (LINF,"Packet Length",EPES,3,1,l);
  return (l);
}

int pes_transfer (refr_data *src,
    refr_data *dst,
    int size)
{
  int l, r;
  if (size > list_freeinend (*dst)) {
    dst->in = 0;
  }
  r = dst->in;
  while (size > 0) {
    l = MAX_DATA_RAWB - src->out;
    if (l > size) {
      l = size;
    }
    memcpy (&dst->ptr[dst->in],&src->ptr[src->out],l);
    list_incr (dst->in,*dst,l);
    list_incr (src->out,*src,l);
    warn (LDEB,"Transfer",EPES,4,1,l);
    size -= l;
  }
  return (r);
}

boolean split_pes (file_descr *f)
{
  int l, p, q;
  stream_descr *s;
  ctrl_buffer *c;
  warn (LDEB,"Split PES",EPES,0,0,f);
  if (pes_skip_to_prefix (f)) {
    l = list_size (f->data);
    if (l >= PES_HDCODE_SIZE) {
      p = pes_stream_id (&f->data);
      if (p >= PES_LOWEST_SID) {
        if (f->u.pes.stream == NULL) {
          if (f->automatic) {
            f->u.pes.stream = connect_streamprog (f,f->auto_programnb,
                p,-p,guess_streamtype(p),NULL,NULL,FALSE);
            if (f->u.pes.stream == NULL) {
              f->automatic = FALSE;
              return (FALSE);
            }
          } else {
            if (list_free (f->data) < HIGHWATER_RAW) {
              if (!S_ISREG(f->st_mode)) {
                f->skipped += PES_SYNC_SIZE;
                f->total += PES_SYNC_SIZE;
                list_incr (f->data.out,f->data,PES_SYNC_SIZE);
                return (TRUE);
              }
            }
            return (FALSE);
          }
        }
        s = f->u.pes.stream;
        if (l >= PES_HEADER_SIZE) {
          q = pes_packet_length (&f->data);
          q += PES_HEADER_SIZE;
          if (l >= q) {
            if (p == s->stream_id) {
              if (list_free (s->data) >= 2*q-1) {
                c = &s->ctrl.ptr[s->ctrl.in];
                c->length = q;
                f->payload += q;
                f->total += q;
                c->index = pes_transfer (&f->data,&s->data,q);
                warn (LDEB,"Sequence",EPES,0,1,f->sequence);
                c->sequence = f->sequence++;
                c->scramble = 0;
                c->msecread = msec_now ();
                if (S_ISREG (f->st_mode)) {
                  c->msecpush = c->msecread; /* wrong, but how ? */
                } else {
                  c->msecpush = c->msecread; /* enough ? */
                }
                c->pcr.valid = FALSE;
                c->opcr.valid = FALSE;
                list_incr (s->ctrl.in,s->ctrl,1);
                return (TRUE);
              }
            } else {
              warn (LDEB,"Dropped PES Packet",EPES,0,p,q);
              f->skipped += q;
              f->total += q;
              list_incr (f->data.out,f->data,q);
              return (TRUE);
            }
          }
        }
      } else {
        warn (LWAR,"Unknown PES Packet",EPES,0,2,p);
        f->skipped += PES_SYNC_SIZE;
        f->total += PES_SYNC_SIZE;
        list_incr (f->data.out,f->data,PES_SYNC_SIZE);
        return (TRUE);
      }
    }
  }
  return (FALSE);
}


LinuxTV legacy CVS <linuxtv.org/cvs>