File:  [DVB] / multiplexer / input.c
Revision 1.28: download - view: text, annotated - select for diffs
Thu Oct 17 08:37:06 2013 UTC (10 years, 7 months ago) by oskar
Branches: MAIN
CVS tags: HEAD
v1.1.8

/*
 * ISO 13818 stream multiplexer
 * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
 * Copyright (C) 2004 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:  Input
 * Purpose: Data Acquisition from the various open files,
 *          promotion to the single split-functions.
 *
 * This module holds two main data structures, an unsorted list of
 * open input files, and an unsorted list of open input streams
 * (extracted from these files).
 * Further provided are functions to open and close files and streams,
 * to detect states of the input buffers, and to read data into the
 * (raw) file input buffers.
 */

#include "global.h"
#include "error.h"
#include "pes.h"
#include "splitpes.h"
#include "splitps.h"
#include "splitts.h"
#include "splice.h"
#include "input.h"
#include "descref.h"
#include "ts.h"

/* index of files in use, containing i.a. the raw input data buffers:
 */
static file_descr *inf [MAX_INFILE];
static int in_files;
static int in_openfiles[number_ct];

/* index of streams in use, containing i.a. the input pes buffers:
 */
static stream_descr *ins [MAX_INSTREAM];
static int in_streams;
static int in_openstreams[number_sd];

static t_msec trigger_msec_input;

boolean input_init (void)
{
  in_files = 0;
  memset (in_openfiles, 0, sizeof (in_openfiles));
  in_streams = 0;
  memset (in_openstreams, 0, sizeof (in_openstreams));
  trigger_msec_input = TRIGGER_MSEC_INPUT;
  return (TRUE);
}

#ifdef DEBUG_TIMEPOLL
int deb_inraw_free (int f)
{
  register int r;
  r = (f < in_files) ? list_free (inf[f]->data) : 0;
  return (r);
}

int deb_instr_free (int s)
{
  register int r;
  r = (s < in_streams) ? list_free (ins[s]->data) : 0;
  return (r);
}
#endif

/* Determine whether data is expected as input.
 * Return: TRUE, if any valuable file is open, FALSE otherwise
 */
boolean input_expected (void)
{
  return ((in_files > 0)
       && ((in_openfiles[ct_transport] != in_files)
        || (in_openstreams[sd_unparsedsi] != in_streams)));
}

/* Set trigger timing value.
 */
void input_settriggertiming (t_msec time)
{
  trigger_msec_input = time;
}

/* Determine whether input data is acceptable, i.e. there is space in buffers.
 * If so, set the poll struct accordingly for each file in question.
 * Check the streams for time stamps and set the timeout^ accordingly,
 * if the streams might be responsible alone for blocking pipes.
 * Return: TRUE, if at least one buffer has enough space to accept new data.
 *         FALSE otherwise.
 */
boolean input_acceptable (unsigned int *nfds,
    struct pollfd *ufds,
    t_msec *timeout,
    boolean outnotfull)
{
  boolean accept = FALSE;
  int i;
  t_msec t, now;
  file_descr *f;
  stream_descr *s;
  i = in_files;
  while (--i >= 0) {
    f = inf[i];
    warn (LDEB,"Acceptable",EINP,2,1,i);
    warn (LDEB,"Free Raw",EINP,2,2,list_free (f->data));
    if ((list_free (f->data) >= HIGHWATER_RAW)
     && (f->handle >= 0)) {
      ufds->fd = f->handle;
      ufds->events = POLLIN;
      *nfds += 1;
      accept = TRUE;
      f->ufds = ufds++;
    } else {
      f->ufds = NULL;
    }
  }
  if (outnotfull) {
    now = msec_now ();
    i = in_streams;
    while (--i >= 0) {
      s = ins[i];
      if (s->streamdata == sd_data) {
        if (!list_empty (s->ctrl)) {
          if (s->u.d.trigger) {
            t = s->ctrl.ptr[s->ctrl.out].msecpush - now + s->u.d.delta;
          } else {
            t = s->ctrl.ptr[s->ctrl.out].msecread - now + trigger_msec_input;
          }
          if ((t > 0)
           && ((*timeout < 0)
            || (*timeout > t))) {
            *timeout = t;
          }
        }
      }
    }
  }
  return (accept);
}

/* Set the trigger on a stream, enabling the data to be spliced now.
 * Set the trigger for all streams that correspond thru the target program, too
 * Precondition: s!=NULL
 */
static void set_trigger (stream_descr *s,
    t_msec now)
{
  int q, i;
  prog_descr *p;
  if (!list_empty (s->data)) {
    s->u.d.lasttime = now;
    s->u.d.delta =
      now - s->ctrl.ptr[s->ctrl.out].msecpush;
    warn (LDEB,"Set Trigger",EINP,8,s->u.d.pid,s->u.d.delta);
    s->u.d.trigger = TRUE;
    s->u.d.mention = TRUE;
    q = s->u.d.progs;
    while (--q >= 0) {
      p = s->u.d.pdescr[q];
      p->unchanged = TRUE;
      i = p->streams;
      while (--i >= 0) {
        if (!p->stream[i]->u.d.trigger) {
          set_trigger (p->stream[i],now);
        }
      }
    }
  }
}

/* Clear the trigger on a stream, clear it for all corresponding streams, too
 * Precondition: s!=NULL
 */
static void clear_trigger (stream_descr *s)
{
  int q, i;
  prog_descr *p;
  warn (LDEB,"Clear Trigger",EINP,13,s->u.d.pid,s->u.d.delta);
  s->u.d.discontinuity = TRUE;
  s->u.d.trigger = FALSE;
  q = s->u.d.progs;
  while (--q >= 0) {
    p = s->u.d.pdescr[q];
    i = p->streams;
    while (--i >= 0) {
      if (p->stream[i]->u.d.trigger) {
        clear_trigger (p->stream[i]);
      }
    }
  }
}

/* Check if mapstream provides prominent data.
 * Precondition: d!=NULL, !list_empty(d->ctrl)
 * Return: TRUE, if mapstream has prominent data, FALSE otherwise
 */
static boolean preceding_sequence (stream_descr *d,
    stream_descr *m)
{
  if (m != NULL) {
    if (!list_empty (m->ctrl)) {
      if (m->ctrl.ptr[m->ctrl.out].sequence
        - d->ctrl.ptr[d->ctrl.out].sequence <= 0) {
        return (TRUE);
      }
    }
  }
  return (FALSE);
}

/* Check for every stream whether data is available to be spliced.
 * Unparsed SI from an otherwise unused TS has priority.
 * If the stream with the lowest time stamp has a corresponding map stream,
 * that provides data to be spliced first, the map stream is returned.
 * Prior, check if a stream is empty and end it, if necessary; check if a
 * stream is ready but not yet triggered, so trigger it.
 * Return: stream to be spliced next.
 */
stream_descr *input_available (void)
{
  int i, s, q;
  t_msec t, u, now;
  stream_descr *d, *e;
  ctrl_buffer *c;
  file_descr *f;
  now = msec_now ();
  i = in_files;
  while (--i >= 0) {
    f = inf[i];
    if (f->content == ct_transport) {
      d = ts_file_stream (f,TS_UNPARSED_SI);
      if (d != NULL) {
        if (((f->openstreams[sd_data] == 0)
          && (!list_empty (d->ctrl)))
         || (list_full (d->ctrl))) {
          return (d);
        }
      }
    }
  }
  i = in_streams;
  while (--i >= 0) {
    d = ins[i];
    if (d->streamdata == sd_data) {
      if (list_empty (d->ctrl)) {
        switch (d->endaction) {
          case ENDSTR_CLOSE:
            input_endstream (d);
            if (i > in_streams) {
              i = in_streams;
            }
            break;
          case ENDSTR_KILL:
            input_endstreamkill (d);
            if (i > in_streams) {
              i = in_streams;
            }
            break;
          case ENDSTR_WAIT:
            break;
          default:
            warn (LERR,"End Action",EINP,3,1,d->endaction);
            break;
        }
        /* trigger:=false if empty? no ! */
      } else {
        if (!d->u.d.trigger) {
          if (list_full (d->ctrl)
           || list_partialfull (d->data)
        /* || (list_free (d->fdescr->data) < HIGHWATER_IN) */
           || (d->endaction == ENDSTR_CLOSE)
           || (d->endaction == ENDSTR_KILL)
           || ((now - d->ctrl.ptr[d->ctrl.out].msecread)
                 >= trigger_msec_input)) {
            set_trigger (d,now);
          }
        }
      }
    }
  }
  d = NULL;
  i = in_streams;
  while (--i >= 0) {
    e = ins[i];
    if ((e->streamdata == sd_data)
     && (e->u.d.trigger)) {
      if (!list_empty (e->ctrl)) {
        warn (LDEB,"Available",EINP,3,2,i);
        c = &(e->ctrl.ptr[e->ctrl.out]);
        t = c->msecpush + e->u.d.delta;
        if (t - e->u.d.lasttime < 0) {
          warn (LWAR,"Time Decrease",EINP,3,3,t - e->u.d.lasttime);
          clear_trigger (e);
        } else {
          e->u.d.lasttime = t; 
          t -= now;
          if ((t > MAX_MSEC_PUSHJTTR)
           || (t < -MAX_MSEC_PUSHJTTR)) {
            warn (LWAR,"Time Jumpness",EINP,3,4,t);
            clear_trigger (e);
          } else {
            q = c->sequence;
            if ((t <= 0)
             && ((d == NULL)
              || (t < u)
              || ((t == u) && (q - s < 0)))) {
              u = t;
              s = q;
              d = e;
            }
          }
        }
      }
    }
  }
  if (d != NULL) {
    switch (d->fdescr->content) {
      case ct_transport:
        e = d;
        if (preceding_sequence (d, ts_file_stream (d->fdescr,0))) {
          d = ts_file_stream (d->fdescr,0);
        } else {
          if (preceding_sequence (d, d->u.d.mapstream)) {
            d = d->u.d.mapstream;
          } else {
            if (preceding_sequence (d,
                  ts_file_stream (d->fdescr,TS_UNPARSED_SI))) {
              d = ts_file_stream (d->fdescr,TS_UNPARSED_SI);
            }
          }
        }
        break;
      case ct_program:
        if (preceding_sequence (d,d->u.d.mapstream)) {
          d = d->u.d.mapstream;
        }
        break;
      default:
        break;
    }
  }
  return (d);
}

/* Check all files for a given filerefnum.
 * Precondition: filerefnum>=0
 * Return: filename, if filerefnum matches, NULL otherwise
 */
char *input_filerefername (int filerefnum)
{
  int i;
  file_descr *f;
  i = in_files;
  while (--i >= 0) {
    f = inf[i];
    if (f->filerefnum == filerefnum) {
      return (f->name);
    }
    if ((f->append_name != NULL)
     && (f->append_filerefnum == filerefnum)) {
      return (f->append_name);
    }
  }
  return (NULL);
}

/* Open a file. Allocate and initialize it.
 * Precondition: name!=NULL
 * Return: file, if successful, NULL otherwise
 */
file_descr* input_openfile (char *name,
    int filerefnum,
    content_type content,
    boolean automatic,
    int programnb)
{
  file_descr *f;
  struct stat stat;
  warn (LIMP,"Create file",EINP,4,automatic,content);
  warn (LIMP,name,EINP,4,4,programnb);
  if (in_files < MAX_INFILE) {
    switch (content) {
      case ct_packetized:
        f = unionalloc (file_descr,pes);
        break;
      case ct_program:
        f = unionalloc (file_descr,ps);
        break;
      case ct_transport:
        f = unionalloc (file_descr,ts);
        break;
      default:
        warn (LERR,"Unknown contents",EINP,4,7,0);
        f = NULL;
        break;
    }
    if (f != NULL) {
      if ((f->name = malloc (strlen(name) + 1)) != NULL) {
        if (list_create (f->data,MAX_DATA_RAWB)) {
          if ((f->handle = open (name,O_RDONLY|O_NONBLOCK)) >= 0) {
            if (fstat (f->handle,&stat) == 0) {
              f->st_mode = stat.st_mode;
              if (!S_ISREG (f->st_mode)) {
                timed_io = TRUE;
              }
              strcpy (f->name,name);
              f->filerefnum = filerefnum;
              f->skipped = 0;
              f->payload = 0;
              f->total = 0;
              f->sequence = 0;
              memset (f->openstreams,0,sizeof(f->openstreams));
              f->append_name = NULL;
              f->repeatitions = 0;
              f->auto_programnb = programnb;
              f->automatic = automatic;
              f->stopfile = FALSE;
              f->content = content;
              switch (content) {
                case ct_packetized:
                  f->u.pes.stream = NULL;
                  in_openfiles[content] += 1;
                  inf[in_files++] = f;
                  return (f);
                  break;
                case ct_program:
                  memset (f->u.ps.stream,0,sizeof(f->u.ps.stream));
                  f->u.ps.stream[0] = input_openstream (f,0,0,0,sd_map,NULL);
                  if (f->u.ps.stream[0] != NULL) {
                    in_openfiles[content] += 1;
                    inf[in_files++] = f;
                    return (f);
                  }
                  break;
                case ct_transport:
                  f->u.ts.pat_version = 0xFF;
                  f->u.ts.newpat_version = 0xFF;
                  f->u.ts.pat = NULL;
                  f->u.ts.newpat = NULL;
                  f->u.ts.tsauto = NULL;
                  f->u.ts.tssi = NULL;
                  memset (f->u.ts.stream,0,sizeof(f->u.ts.stream));
                  ts_file_stream (f,0) = input_openstream (f,0,0,0,sd_map,NULL);
                  if (ts_file_stream (f,0) != NULL) {
                    in_openfiles[content] += 1;
                    inf[in_files++] = f;
                    return (f);
                  }
                  break;
                default:
                  break;
              }
            } else {
              warn (LERR,"FStat fail",EINP,4,6,0);
            }
            close (f->handle);
          } else {
            warn (LERR,"Open fail",EINP,4,5,f->handle);
          }
          list_release (f->data);
        }
        free (f->name);
      } else {
        warn (LERR,"Alloc fail",EINP,4,8,in_files);
      }
      free (f);
    } else {
      warn (LERR,"Alloc fail",EINP,4,2,in_files);
    }
  } else {
    warn (LERR,"Max file open",EINP,4,3,in_files);
  }
  return (NULL);
}

/* Check if a file with a given name is yet open.
 * The file name comparision is purely textual.
 * Precondition: name!=NULL
 * Return: file if found, NULL otherwise.
 */
file_descr* input_existfile (char *name)
{
  int i;
  i = in_files;
  while (--i >= 0) {
    if (!strcmp (name,inf[i]->name)) {
      return (inf[i]);
    }
  }
  return (NULL);
}

/* Mark all streams in a file to end soon, close the file itself
 * Precondition: f!=NULL
 */
static void input_endfile (file_descr *f)
{
  int i;
  stream_descr *s;
  i = in_streams;
  while (--i >= 0) {
    s = ins[i];
    if (s->fdescr == f) {
      s->endaction = ENDSTR_CLOSE;
    }
  }
  if (f->handle >= 0) {
    close (f->handle);
    f->handle = -1;
  }
  input_closefileifunused (f);
}

/* Close a file and release all corresponding data structures
 * Precondition: f!=NULL, f->u.*.stream[*]==NULL
 */
static void input_closefile (file_descr *f)
{
  int i;
  if (f->handle >= 0) {
    close (f->handle);
  }
  list_release (f->data);
  free (f->name);
  switch (f->content) {
    case ct_transport:
      releasechain (pmt_descr,f->u.ts.pat);
      releasechain (pmt_descr,f->u.ts.newpat);
      releasechain (tsauto_descr,f->u.ts.tsauto);
      releasechain (tssi_descr,f->u.ts.tssi);
      break;
    default:
      break;
  }
  i = in_files;
  while (--i >= 0) {
    if (inf[i] == f) {
      inf[i] = inf[--in_files];
      in_openfiles[f->content] -= 1;
      warn (LDEB,"Close file",EINP,11,1,in_files);
      free (f);
      return;
    }
  }
  warn (LERR,"Close lost file",EINP,11,2,in_files);
  free (f);
}

/* Close a file if there are no more data streams open.
 * If so, close any map streams.
 * Precondition: f!=NULL
 */
void input_closefileifunused (file_descr *f)
{
  int i;
  stream_descr *s;
  if (f->openstreams[sd_data] <= 0) {
    if (f->openstreams[sd_unparsedsi] > 0) {
      switch (f->content) {
        case ct_transport:
          i = MAX_STRPERTS;
          while ((f->openstreams[sd_unparsedsi] > 0)
              && (--i >= 0)) {
            s = ts_file_stream (f,i);
            if ((s != NULL)
             && (s->streamdata == sd_unparsedsi)
             && (s->endaction == ENDSTR_CLOSE)
             && (list_empty (s->ctrl))) {
              input_closestream (ts_file_stream (f,i));
            }
          }
          break;
        default:
          break;
      }
    }
    if (f->openstreams[sd_unparsedsi] <= 0) {
      if (f->openstreams[sd_map] > 0) {
        switch (f->content) {
          case ct_program:
            i = MAX_STRPERPS;
            while (--i >= 0) {
              if (f->u.ps.stream[i] != NULL) {
                input_closestream (f->u.ps.stream[i]);
              }
            }
            break;
          case ct_transport:
            i = MAX_STRPERTS;
            while (--i >= 0) {
              s = ts_file_stream (f,i);
              if ((s != NULL)
               && (s->streamdata == sd_map)) {
                input_closestream (ts_file_stream (f,i));
              }
            }
            break;
          default:
            warn (LERR,"unexpected map",EINP,12,1,f->content);
            break;
        }
      }
      input_closefile (f);
    }
  }
}

/* Add a target program to a stream's list of programs that contain it.
 * Precondition: s!=NULL, p!=NULL, p not in s->u.d.pdescr[*]
 * Postcondition: p in s->u.d.pdescr[*] not more than once.
 * Return: TRUE if successful, FALSE otherwise.
 */
boolean input_addprog (stream_descr *s,
    prog_descr *p)
{
  if (s->u.d.progs < MAX_PRGFORSTR) {
    s->u.d.pdescr[s->u.d.progs++] = p;
    warn (LDEB,"Add prog",EINP,10,2,s->u.d.progs);
    return (TRUE);
  }
  warn (LERR,"Max add prog",EINP,10,1,s->u.d.progs);
  return (FALSE);
}

/* Delete a target program from a stream's list of programs that contain it.
 * Precondition: s!=NULL, p!=NULL, p in s->u.d.pdescr[*] not more than once.
 * Postcondition: p not in s->u.d.pdescr[*]
 * Return: TRUE if successful, FALSE otherwise.
 */
boolean input_delprog (stream_descr *s,
    prog_descr *p)
{
  int i;
  i = s->u.d.progs;
  while (--i >= 0) {
    if (s->u.d.pdescr[i] == p) {
      s->u.d.pdescr[i] = s->u.d.pdescr[--(s->u.d.progs)];
      warn (LDEB,"Del prog",EINP,9,2,i);
      return (TRUE);
    }
  }
  warn (LERR,"Del lost prog",EINP,9,1,s->u.d.progs);
  return (FALSE);
}

/* Open a stream in a file. Allocate and initialize it.
 * sourceid is the stream's ID in the source file.
 * streamid is the PES packet stream id.
 * streamtype is the stream type according to ISO 13818-1 table 2-29.
 * isamap is TRUE for a map stream, FALSE for data stream.
 * mapstream is the superior correlated map stream.
 * Precondition: f!=NULL
 * Return: stream if successful, NULL otherwise
 */
stream_descr *input_openstream (file_descr *f,
    int sourceid,
    int streamid,
    int streamtype,
    streamdata_type streamdata,
    stream_descr *mapstream)
{
  stream_descr *s;
  warn (LIMP,"Open stream",EINP,5,sourceid,streamid);
  if (in_streams < MAX_INSTREAM) {
    switch (streamdata) {
      case sd_data:
        s = unionalloc (stream_descr,d);
        break;
      case sd_map:
        s = unionalloc (stream_descr,m);
        break;
      case sd_unparsedsi:
        s = unionalloc (stream_descr,usi);
        break;
      default:
        s = NULL;
        break;
    }
    if ((s != NULL)
     && ((s->autodescr = malloc (sizeof (descr_descr))) != NULL)
     && ((s->manudescr = malloc (sizeof (descr_descr))) != NULL)) {
      if (list_create (s->ctrl,MAX_CTRL_INB)) {
        if ((streamdata == sd_map) ?
            list_create (s->data,MAX_DATA_INBPSI) :
            streamtype_isvideo (streamtype) ?
            list_create (s->data,MAX_DATA_INBV) :
            streamtype_isaudio (streamtype) ?
            list_create (s->data,MAX_DATA_INBA) :
            list_create (s->data,MAX_DATA_INB)) {
          s->streamdata = streamdata;
          switch (streamdata) {
            case sd_data:
              s->u.d.mapstream = mapstream;
              s->u.d.discontinuity = FALSE;
              s->u.d.trigger = FALSE;
              s->u.d.mention = FALSE;
              s->u.d.has_clockref = FALSE;
              s->u.d.has_opcr = FALSE;
              s->u.d.conv.base = 0;
              s->u.d.conv.msec = 0;
              s->u.d.progs = 0;
              f->openstreams[streamdata] += 1;
              in_openstreams[streamdata] += 1;
              break;
            case sd_map:
              s->u.m.msectime = 0;
              s->u.m.conv.base = 0;
              s->u.m.conv.msec = 0;
              s->u.m.psi_length = 0;
              f->openstreams[streamdata] += 1;
              in_openstreams[streamdata] += 1;
              break;
            case sd_unparsedsi:
              f->openstreams[streamdata] += 1;
              in_openstreams[streamdata] += 1;
              break;
            default:
              break;
          }
          s->ctrl.ptr[0].length = 0;
          s->ctrl.ptr[0].pcr.valid = FALSE;
          s->ctrl.ptr[0].opcr.valid = FALSE;
          s->fdescr = f;
          s->sourceid = sourceid;
          s->stream_id = streamid;
          s->stream_type = streamtype;
          warn (LINF,"Open Streamtype",EINP,5,3,streamtype);
          s->version = 0xFF;
          s->conticnt = 0;
          s->endaction = ENDSTR_WAIT;
          clear_descrdescr (s->autodescr);
          clear_descrdescr (s->manudescr);
          ins[in_streams++] = s;
          return (s);
        }
        list_release (s->ctrl);
      }
      free (s);
    } else {
      warn (LERR,"Alloc fail",EINP,5,1,in_streams);
    }
  } else {
    warn (LERR,"Max stream open",EINP,5,2,in_streams);
  }
  return (NULL);
}

/* End a stream, if opportune.
 * Check all target programs this stream is in, close those that
 * do not contain another stream from the same file that is still running.
 * Note, that the stream stays open if there is at least one other stream
 * from the same file, that is still running together with it in a program.
 * Precondition: s!=NULL
 */
void input_endstream (stream_descr *s)
{
  int q, i;
  prog_descr *p;
  stream_descr *t;
  q = s->u.d.progs;
  while (--q >= 0) {
    p = s->u.d.pdescr[q];
    i = p->streams;
    while (--i >= 0) {
      t = p->stream[i];
      if ((!list_empty (t->ctrl))
       && (t->u.d.trigger)
       && (t->fdescr == s->fdescr)) {
        break;
      }
    }
    if (i < 0) {
      splice_closeprog (p);
    }
  }
}

/* End a stream.
 * Unlink it from all target programs, no matter what is left therein.
 * Precondition: s!=NULL
 */
void input_endstreamkill (stream_descr *s)
{
  int i;
  i = s->u.d.progs;
  while (--i >= 0) {
    prog_descr *p;
    p = s->u.d.pdescr[i];
    if (p->streams > 1) {
      unlink_streamprog (s,p);
    } else {
      splice_closeprog (p);
    }
  }
}

/* Close a stream.
 * Release all structures. If this is the only data stream related to the
 * corresponding map stream, close the map stream, too.
 * Precondition: s!=NULL
 */
void input_closestream (stream_descr *s)
{
  int i;
  warn (LIMP,"Close stream",EINP,6,0,s->sourceid);
  switch (s->fdescr->content) {
    case ct_packetized:
      s->fdescr->u.pes.stream = NULL;
      break;
    case ct_program:
      s->fdescr->u.ps.stream[s->sourceid] = NULL;
      break;
    case ct_transport:
      ts_file_stream (s->fdescr,s->sourceid) = NULL;
      break;
    default:
      warn (LERR,"Unknown contents",EINP,6,2,s->fdescr->content);
      break;
  }
  s->fdescr->openstreams[s->streamdata] -= 1;
  if (s->streamdata == sd_data) {
    switch (s->fdescr->content) {
      case ct_transport:
        if (s->u.d.mapstream != ts_file_stream (s->fdescr,0)) {
          i = MAX_STRPERTS;
          while ((--i >= 0)
            && ((ts_file_stream (s->fdescr,i) == NULL)
             || (ts_file_stream (s->fdescr,i)->streamdata != sd_data)
             || (ts_file_stream (s->fdescr,i)->u.d.mapstream
                != s->u.d.mapstream))) {
          }
          if (i < 0) {
            if (s->u.d.mapstream->endaction == ENDSTR_CLOSE) {
              input_closestream (s->u.d.mapstream);
            }
          }
        }
        break;
      default:
        break;
    }
  }
  i = in_streams;
  while (--i >= 0) {
    if (ins[i] == s) {
      ins[i] = ins[--in_streams];
      in_openstreams[s->streamdata] -= 1;
      break;
    }
  }
  if (i < 0) {
    warn (LERR,"Close lost stream",EINP,6,1,in_streams);
  }
  list_release (s->data);
  list_release (s->ctrl);
  free (s->manudescr);
  free (s->autodescr);
  free (s);
}

/* Split data from raw input buffers to PES data stream buffers.
 * Return: TRUE, if something was processed, FALSE if no data/space available
 */
boolean split_something (void)
{
  int i;
  boolean r = FALSE;
  warn (LDEB,"Split some",EINP,7,0,in_files);
  i = in_files;
  while (--i >= 0) {
    switch (inf[i]->content) {
      case ct_packetized:
        if (split_pes (inf[i])) {
          r = TRUE;
        }
        break;
      case ct_program:
        if (split_ps (inf[i])) {
          r = TRUE;
        }
        break;
      case ct_transport:
        if (split_ts (inf[i])) {
          r = TRUE;
        }
        break;
      default:
        warn (LERR,"Unknown contents",EINP,7,3,inf[i]->content);
        /* error ? */
        break;
    }
  }
  return (r);
}

/* Check all files of type ct_transport for --si ranges.
 * Return: higher bound of range, if match is found, -1 otherwise
 */
int input_tssiinafilerange (int pid)
{
  int i;
  i = in_files;
  while (--i >= 0) {
    warn (LDEB,"TSSI in file",EINP,14,-1,inf[i]->content);
    if (inf[i]->content == ct_transport) {
      int h;
      h = split_unparsedsi (inf[i],pid);
      if (h >= 0) {
        warn (LDEB,"TSSI in file",EINP,14,pid,h);
        return (h);
      }
    }
  }
  warn (LDEB,"TSSI in file",EINP,14,pid,-1);
  return (-1);
}

/* Determine the appropriate file for a given handle
 * Return: file, if found, NULL otherwise
 */
file_descr *input_filehandle (int handle)
{
  int i;
  i = in_files;
  while (--i >= 0) {
    if (inf[i]->handle == handle) {
      return (inf[i]);
    }
  }
  return (NULL);
}

/* Check whether there is a pair of filerefnum and filename among the open
 * files, that fits the criteria.
 * Precondition: filename!=NULL or filerefnum>=0
 * Return: file, if found, NULL otherwise
 */
file_descr *input_filereferenced (int filerefnum,
    char *filename)
{
  int i;
  file_descr *f;
  i = in_files;
  while (--i >= 0) {
    f = inf[i];
    if ((filename == NULL)
        ? (filerefnum == f->filerefnum)
        : ((!strcmp (filename, f->name))
        && ((filerefnum < 0)
         || (filerefnum == f->filerefnum)))) {
      return (f);
    }
  }
  return (NULL);
}

/* Mark a file to be stopped.
 * If stopped, the file will be handled as if eof was encountered, the
 * next time there is data to be read from it.
 * Precondition: f!=NULL
 */
void input_stopfile (file_descr *f)
{
  f->stopfile = TRUE;
}

/* Read some data from the file into the raw buffer.
 * On eof or f->stopfile, end the file, or handle repeatitions or append,
 * if applicable.
 * Precondition: poll has stated data or error for the file
 */
void input_something (file_descr *f,
  boolean readable)
{
  int l, m;
  if (f != NULL) {
    if (f->handle >= 0) {
      warn (LDEB,"Something",EINP,0,1,f);
      if (readable && !f->stopfile) {
        l = list_freeinend (f->data);
        if (l > MAX_READ_IN) {
          l = MAX_READ_IN;
        }
        m = list_free (f->data);
        if (l > m) {
          l = m;
        }
        l = read (f->handle,&f->data.ptr[f->data.in],l);
      } else {
        l = 0;
      }
      warn (LDEB,"Some Read",EINP,0,2,l);
      if (l > 0) {
        list_incr (f->data.in,f->data,l);
      } else if (l == 0) {
        f->stopfile = FALSE;
        if (f->repeatitions != 0) {
          if (f->repeatitions > 0) {
            f->repeatitions -= 1;
          }
          if (lseek (f->handle,0,SEEK_CUR) > 255) {
            lseek (f->handle,0,SEEK_SET);
            warn (LIMP,"End Repeat",EINP,0,4,f);
          } else {
            warn (LWAR,"Repeat fail",EINP,0,5,f);
          }
        } else if (f->append_name != NULL) {
          free (f->name);
          f->name = f->append_name;
          f->append_name = NULL;
          if (f->append_filerefnum >= 0) {
            f->filerefnum = f->append_filerefnum;
          }
          close (f->handle);
          if ((f->handle = open (f->name,O_RDONLY|O_NONBLOCK)) >= 0) {
            struct stat stat;
            if (fstat (f->handle,&stat) == 0) {
              f->st_mode = stat.st_mode;
              if (!S_ISREG (f->st_mode)) {
                timed_io = TRUE;
                if (f->append_repeatitions != 0) {
                  warn (LWAR,"Cannot repeat nonregular file",
                        EINP,0,9,f->append_repeatitions);
                }
                f->repeatitions = 0;
              } else {
                f->repeatitions = f->append_repeatitions;
              }
              configuration_changed = TRUE;
              warn (LIMP,"End Append",EINP,0,f->repeatitions,f);
            } else {
              warn (LWAR,"Append fail",EINP,0,7,f);
              input_endfile (f);
            }
          } else {
            warn (LWAR,"Append fail",EINP,0,8,f);
            input_endfile (f);
          }
        } else {
          input_endfile (f);
        }
      } else {
        /* read error */
      }
    }
  }
}


LinuxTV legacy CVS <linuxtv.org/cvs>