Annotation of multiplexer/input.c, revision 1.28
1.1 oskar 1: /*
2: * ISO 13818 stream multiplexer
3: * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
1.27 oskar 4: * Copyright (C) 2004 Oskar Schirmer (schirmer@scara.com)
1.24 oskar 5: *
6: * This program is free software; you can redistribute it and/or modify
7: * it under the terms of the GNU General Public License as published by
8: * the Free Software Foundation; either version 2 of the License, or
9: * (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with this program; if not, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.1 oskar 19: */
20:
21: /*
22: * Module: Input
23: * Purpose: Data Acquisition from the various open files,
24: * promotion to the single split-functions.
25: *
26: * This module holds two main data structures, an unsorted list of
27: * open input files, and an unsorted list of open input streams
28: * (extracted from these files).
29: * Further provided are functions to open and close files and streams,
30: * to detect states of the input buffers, and to read data into the
31: * (raw) file input buffers.
32: */
33:
34: #include "global.h"
35: #include "error.h"
36: #include "pes.h"
37: #include "splitpes.h"
38: #include "splitps.h"
39: #include "splitts.h"
40: #include "splice.h"
41: #include "input.h"
1.18 oskar 42: #include "descref.h"
1.9 oskar 43: #include "ts.h"
1.1 oskar 44:
1.6 oskar 45: /* index of files in use, containing i.a. the raw input data buffers:
46: */
1.1 oskar 47: static file_descr *inf [MAX_INFILE];
48: static int in_files;
1.13 oskar 49: static int in_openfiles[number_ct];
1.1 oskar 50:
1.6 oskar 51: /* index of streams in use, containing i.a. the input pes buffers:
52: */
1.1 oskar 53: static stream_descr *ins [MAX_INSTREAM];
54: static int in_streams;
1.13 oskar 55: static int in_openstreams[number_sd];
1.1 oskar 56:
1.15 oskar 57: static t_msec trigger_msec_input;
58:
1.1 oskar 59: boolean input_init (void)
60: {
61: in_files = 0;
1.13 oskar 62: memset (in_openfiles, 0, sizeof (in_openfiles));
1.1 oskar 63: in_streams = 0;
1.13 oskar 64: memset (in_openstreams, 0, sizeof (in_openstreams));
1.15 oskar 65: trigger_msec_input = TRIGGER_MSEC_INPUT;
1.1 oskar 66: return (TRUE);
67: }
68:
69: #ifdef DEBUG_TIMEPOLL
70: int deb_inraw_free (int f)
71: {
72: register int r;
73: r = (f < in_files) ? list_free (inf[f]->data) : 0;
74: return (r);
75: }
76:
77: int deb_instr_free (int s)
78: {
79: register int r;
80: r = (s < in_streams) ? list_free (ins[s]->data) : 0;
81: return (r);
82: }
83: #endif
84:
1.6 oskar 85: /* Determine whether data is expected as input.
1.13 oskar 86: * Return: TRUE, if any valuable file is open, FALSE otherwise
1.6 oskar 87: */
1.1 oskar 88: boolean input_expected (void)
89: {
1.13 oskar 90: return ((in_files > 0)
91: && ((in_openfiles[ct_transport] != in_files)
92: || (in_openstreams[sd_unparsedsi] != in_streams)));
1.1 oskar 93: }
94:
1.15 oskar 95: /* Set trigger timing value.
96: */
97: void input_settriggertiming (t_msec time)
98: {
99: trigger_msec_input = time;
100: }
101:
1.6 oskar 102: /* Determine whether input data is acceptable, i.e. there is space in buffers.
103: * If so, set the poll struct accordingly for each file in question.
104: * Check the streams for time stamps and set the timeout^ accordingly,
105: * if the streams might be responsible alone for blocking pipes.
106: * Return: TRUE, if at least one buffer has enough space to accept new data.
107: * FALSE otherwise.
108: */
1.1 oskar 109: boolean input_acceptable (unsigned int *nfds,
110: struct pollfd *ufds,
1.4 oskar 111: t_msec *timeout,
1.1 oskar 112: boolean outnotfull)
113: {
114: boolean accept = FALSE;
1.4 oskar 115: int i;
1.21 oskar 116: t_msec t, now;
117: file_descr *f;
118: stream_descr *s;
1.1 oskar 119: i = in_files;
120: while (--i >= 0) {
1.21 oskar 121: f = inf[i];
1.1 oskar 122: warn (LDEB,"Acceptable",EINP,2,1,i);
1.21 oskar 123: warn (LDEB,"Free Raw",EINP,2,2,list_free (f->data));
124: if ((list_free (f->data) >= HIGHWATER_RAW)
125: && (f->handle >= 0)) {
126: ufds->fd = f->handle;
1.1 oskar 127: ufds->events = POLLIN;
128: *nfds += 1;
129: accept = TRUE;
1.21 oskar 130: f->ufds = ufds++;
1.1 oskar 131: } else {
1.21 oskar 132: f->ufds = NULL;
1.1 oskar 133: }
134: }
135: if (outnotfull) {
1.21 oskar 136: now = msec_now ();
1.1 oskar 137: i = in_streams;
138: while (--i >= 0) {
1.21 oskar 139: s = ins[i];
140: if (s->streamdata == sd_data) {
141: if (!list_empty (s->ctrl)) {
142: if (s->u.d.trigger) {
143: t = s->ctrl.ptr[s->ctrl.out].msecpush - now + s->u.d.delta;
1.15 oskar 144: } else {
1.21 oskar 145: t = s->ctrl.ptr[s->ctrl.out].msecread - now + trigger_msec_input;
1.15 oskar 146: }
147: if ((t > 0)
148: && ((*timeout < 0)
149: || (*timeout > t))) {
150: *timeout = t;
1.1 oskar 151: }
152: }
153: }
154: }
155: }
156: return (accept);
157: }
158:
1.6 oskar 159: /* Set the trigger on a stream, enabling the data to be spliced now.
160: * Set the trigger for all streams that correspond thru the target program, too
161: * Precondition: s!=NULL
162: */
1.1 oskar 163: static void set_trigger (stream_descr *s,
1.4 oskar 164: t_msec now)
1.1 oskar 165: {
1.21 oskar 166: int q, i;
167: prog_descr *p;
1.1 oskar 168: if (!list_empty (s->data)) {
169: s->u.d.lasttime = now;
170: s->u.d.delta =
1.3 oskar 171: now - s->ctrl.ptr[s->ctrl.out].msecpush;
1.1 oskar 172: warn (LDEB,"Set Trigger",EINP,8,s->u.d.pid,s->u.d.delta);
173: s->u.d.trigger = TRUE;
174: s->u.d.mention = TRUE;
1.21 oskar 175: q = s->u.d.progs;
176: while (--q >= 0) {
177: p = s->u.d.pdescr[q];
1.22 oskar 178: p->unchanged = TRUE;
1.21 oskar 179: i = p->streams;
1.1 oskar 180: while (--i >= 0) {
1.21 oskar 181: if (!p->stream[i]->u.d.trigger) {
182: set_trigger (p->stream[i],now);
1.1 oskar 183: }
184: }
185: }
186: }
187: }
188:
1.6 oskar 189: /* Clear the trigger on a stream, clear it for all corresponding streams, too
190: * Precondition: s!=NULL
191: */
1.1 oskar 192: static void clear_trigger (stream_descr *s)
193: {
1.21 oskar 194: int q, i;
195: prog_descr *p;
1.11 oskar 196: warn (LDEB,"Clear Trigger",EINP,13,s->u.d.pid,s->u.d.delta);
1.1 oskar 197: s->u.d.discontinuity = TRUE;
198: s->u.d.trigger = FALSE;
1.21 oskar 199: q = s->u.d.progs;
200: while (--q >= 0) {
201: p = s->u.d.pdescr[q];
202: i = p->streams;
1.1 oskar 203: while (--i >= 0) {
1.21 oskar 204: if (p->stream[i]->u.d.trigger) {
205: clear_trigger (p->stream[i]);
1.1 oskar 206: }
207: }
208: }
209: }
210:
1.9 oskar 211: /* Check if mapstream provides prominent data.
212: * Precondition: d!=NULL, !list_empty(d->ctrl)
213: * Return: TRUE, if mapstream has prominent data, FALSE otherwise
214: */
215: static boolean preceding_sequence (stream_descr *d,
216: stream_descr *m)
217: {
218: if (m != NULL) {
219: if (!list_empty (m->ctrl)) {
220: if (m->ctrl.ptr[m->ctrl.out].sequence
221: - d->ctrl.ptr[d->ctrl.out].sequence <= 0) {
222: return (TRUE);
223: }
224: }
225: }
226: return (FALSE);
227: }
228:
1.6 oskar 229: /* Check for every stream whether data is available to be spliced.
1.9 oskar 230: * Unparsed SI from an otherwise unused TS has priority.
1.6 oskar 231: * If the stream with the lowest time stamp has a corresponding map stream,
232: * that provides data to be spliced first, the map stream is returned.
233: * Prior, check if a stream is empty and end it, if necessary; check if a
234: * stream is ready but not yet triggered, so trigger it.
235: * Return: stream to be spliced next.
236: */
1.1 oskar 237: stream_descr *input_available (void)
238: {
1.4 oskar 239: int i, s, q;
240: t_msec t, u, now;
1.20 oskar 241: stream_descr *d, *e;
242: ctrl_buffer *c;
1.21 oskar 243: file_descr *f;
1.1 oskar 244: now = msec_now ();
1.9 oskar 245: i = in_files;
246: while (--i >= 0) {
1.21 oskar 247: f = inf[i];
248: if (f->content == ct_transport) {
249: d = ts_file_stream (f,TS_UNPARSED_SI);
1.18 oskar 250: if (d != NULL) {
1.21 oskar 251: if (((f->openstreams[sd_data] == 0)
1.18 oskar 252: && (!list_empty (d->ctrl)))
253: || (list_full (d->ctrl))) {
254: return (d);
255: }
1.9 oskar 256: }
257: }
258: }
1.1 oskar 259: i = in_streams;
260: while (--i >= 0) {
1.15 oskar 261: d = ins[i];
262: if (d->streamdata == sd_data) {
263: if (list_empty (d->ctrl)) {
264: switch (d->endaction) {
1.1 oskar 265: case ENDSTR_CLOSE:
1.15 oskar 266: input_endstream (d);
1.1 oskar 267: if (i > in_streams) {
268: i = in_streams;
269: }
270: break;
271: case ENDSTR_KILL:
1.15 oskar 272: input_endstreamkill (d);
1.1 oskar 273: if (i > in_streams) {
274: i = in_streams;
275: }
276: break;
277: case ENDSTR_WAIT:
278: break;
279: default:
1.15 oskar 280: warn (LERR,"End Action",EINP,3,1,d->endaction);
1.1 oskar 281: break;
282: }
283: /* trigger:=false if empty? no ! */
284: } else {
1.15 oskar 285: if (!d->u.d.trigger) {
286: if (list_full (d->ctrl)
287: || list_partialfull (d->data)
288: /* || (list_free (d->fdescr->data) < HIGHWATER_IN) */
289: || (d->endaction == ENDSTR_CLOSE)
290: || (d->endaction == ENDSTR_KILL)
1.21 oskar 291: || ((now - d->ctrl.ptr[d->ctrl.out].msecread)
292: >= trigger_msec_input)) {
1.15 oskar 293: set_trigger (d,now);
1.1 oskar 294: }
295: }
296: }
297: }
298: }
299: d = NULL;
300: i = in_streams;
301: while (--i >= 0) {
1.20 oskar 302: e = ins[i];
303: if ((e->streamdata == sd_data)
304: && (e->u.d.trigger)) {
305: if (!list_empty (e->ctrl)) {
1.1 oskar 306: warn (LDEB,"Available",EINP,3,2,i);
1.20 oskar 307: c = &(e->ctrl.ptr[e->ctrl.out]);
308: t = c->msecpush + e->u.d.delta;
309: if (t - e->u.d.lasttime < 0) {
310: warn (LWAR,"Time Decrease",EINP,3,3,t - e->u.d.lasttime);
311: clear_trigger (e);
1.1 oskar 312: } else {
1.20 oskar 313: e->u.d.lasttime = t;
1.1 oskar 314: t -= now;
315: if ((t > MAX_MSEC_PUSHJTTR)
316: || (t < -MAX_MSEC_PUSHJTTR)) {
317: warn (LWAR,"Time Jumpness",EINP,3,4,t);
1.20 oskar 318: clear_trigger (e);
1.1 oskar 319: } else {
1.20 oskar 320: q = c->sequence;
1.1 oskar 321: if ((t <= 0)
322: && ((d == NULL)
323: || (t < u)
1.20 oskar 324: || ((t == u) && (q - s < 0)))) {
1.1 oskar 325: u = t;
326: s = q;
1.21 oskar 327: d = e;
1.1 oskar 328: }
329: }
330: }
331: }
332: }
333: }
334: if (d != NULL) {
335: switch (d->fdescr->content) {
1.9 oskar 336: case ct_transport:
1.20 oskar 337: e = d;
1.21 oskar 338: if (preceding_sequence (d, ts_file_stream (d->fdescr,0))) {
1.9 oskar 339: d = ts_file_stream (d->fdescr,0);
1.17 oskar 340: } else {
1.21 oskar 341: if (preceding_sequence (d, d->u.d.mapstream)) {
1.17 oskar 342: d = d->u.d.mapstream;
343: } else {
1.21 oskar 344: if (preceding_sequence (d,
345: ts_file_stream (d->fdescr,TS_UNPARSED_SI))) {
1.17 oskar 346: d = ts_file_stream (d->fdescr,TS_UNPARSED_SI);
347: }
348: }
1.9 oskar 349: }
1.17 oskar 350: break;
1.1 oskar 351: case ct_program:
1.9 oskar 352: if (preceding_sequence (d,d->u.d.mapstream)) {
353: d = d->u.d.mapstream;
354: }
1.1 oskar 355: break;
356: default:
357: break;
358: }
359: }
360: return (d);
361: }
362:
1.6 oskar 363: /* Check all files for a given filerefnum.
364: * Precondition: filerefnum>=0
365: * Return: filename, if filerefnum matches, NULL otherwise
366: */
1.5 oskar 367: char *input_filerefername (int filerefnum)
368: {
369: int i;
1.21 oskar 370: file_descr *f;
1.5 oskar 371: i = in_files;
372: while (--i >= 0) {
1.21 oskar 373: f = inf[i];
374: if (f->filerefnum == filerefnum) {
375: return (f->name);
376: }
377: if ((f->append_name != NULL)
378: && (f->append_filerefnum == filerefnum)) {
379: return (f->append_name);
1.6 oskar 380: }
1.5 oskar 381: }
382: return (NULL);
383: }
384:
1.6 oskar 385: /* Open a file. Allocate and initialize it.
386: * Precondition: name!=NULL
387: * Return: file, if successful, NULL otherwise
388: */
1.1 oskar 389: file_descr* input_openfile (char *name,
1.5 oskar 390: int filerefnum,
1.1 oskar 391: content_type content,
392: boolean automatic,
393: int programnb)
394: {
395: file_descr *f;
1.4 oskar 396: struct stat stat;
1.1 oskar 397: warn (LIMP,"Create file",EINP,4,automatic,content);
398: warn (LIMP,name,EINP,4,4,programnb);
399: if (in_files < MAX_INFILE) {
400: switch (content) {
401: case ct_packetized:
402: f = unionalloc (file_descr,pes);
403: break;
404: case ct_program:
405: f = unionalloc (file_descr,ps);
406: break;
407: case ct_transport:
408: f = unionalloc (file_descr,ts);
409: break;
410: default:
411: warn (LERR,"Unknown contents",EINP,4,7,0);
412: f = NULL;
413: break;
414: }
415: if (f != NULL) {
416: if ((f->name = malloc (strlen(name) + 1)) != NULL) {
417: if (list_create (f->data,MAX_DATA_RAWB)) {
1.26 oskar 418: if ((f->handle = open (name,O_RDONLY|O_NONBLOCK)) >= 0) {
1.4 oskar 419: if (fstat (f->handle,&stat) == 0) {
420: f->st_mode = stat.st_mode;
421: if (!S_ISREG (f->st_mode)) {
1.1 oskar 422: timed_io = TRUE;
423: }
424: strcpy (f->name,name);
1.5 oskar 425: f->filerefnum = filerefnum;
1.1 oskar 426: f->skipped = 0;
427: f->payload = 0;
428: f->total = 0;
429: f->sequence = 0;
1.13 oskar 430: memset (f->openstreams,0,sizeof(f->openstreams));
1.5 oskar 431: f->append_name = NULL;
1.2 oskar 432: f->repeatitions = 0;
1.1 oskar 433: f->auto_programnb = programnb;
1.5 oskar 434: f->automatic = automatic;
435: f->stopfile = FALSE;
1.1 oskar 436: f->content = content;
437: switch (content) {
438: case ct_packetized:
439: f->u.pes.stream = NULL;
1.13 oskar 440: in_openfiles[content] += 1;
1.1 oskar 441: inf[in_files++] = f;
442: return (f);
443: break;
444: case ct_program:
445: memset (f->u.ps.stream,0,sizeof(f->u.ps.stream));
1.10 oskar 446: f->u.ps.stream[0] = input_openstream (f,0,0,0,sd_map,NULL);
1.1 oskar 447: if (f->u.ps.stream[0] != NULL) {
1.13 oskar 448: in_openfiles[content] += 1;
1.1 oskar 449: inf[in_files++] = f;
450: return (f);
451: }
452: break;
453: case ct_transport:
454: f->u.ts.pat_version = 0xFF;
455: f->u.ts.newpat_version = 0xFF;
456: f->u.ts.pat = NULL;
457: f->u.ts.newpat = NULL;
458: f->u.ts.tsauto = NULL;
1.9 oskar 459: f->u.ts.tssi = NULL;
1.1 oskar 460: memset (f->u.ts.stream,0,sizeof(f->u.ts.stream));
1.10 oskar 461: ts_file_stream (f,0) = input_openstream (f,0,0,0,sd_map,NULL);
1.6 oskar 462: if (ts_file_stream (f,0) != NULL) {
1.13 oskar 463: in_openfiles[content] += 1;
1.1 oskar 464: inf[in_files++] = f;
465: return (f);
466: }
467: break;
468: default:
469: break;
470: }
471: } else {
472: warn (LERR,"FStat fail",EINP,4,6,0);
473: }
474: close (f->handle);
475: } else {
476: warn (LERR,"Open fail",EINP,4,5,f->handle);
477: }
478: list_release (f->data);
479: }
480: free (f->name);
481: } else {
482: warn (LERR,"Alloc fail",EINP,4,8,in_files);
483: }
484: free (f);
485: } else {
486: warn (LERR,"Alloc fail",EINP,4,2,in_files);
487: }
488: } else {
489: warn (LERR,"Max file open",EINP,4,3,in_files);
490: }
491: return (NULL);
492: }
493:
1.6 oskar 494: /* Check if a file with a given name is yet open.
495: * The file name comparision is purely textual.
496: * Precondition: name!=NULL
497: * Return: file if found, NULL otherwise.
498: */
1.1 oskar 499: file_descr* input_existfile (char *name)
500: {
501: int i;
502: i = in_files;
503: while (--i >= 0) {
504: if (!strcmp (name,inf[i]->name)) {
505: return (inf[i]);
506: }
507: }
508: return (NULL);
509: }
510:
1.6 oskar 511: /* Mark all streams in a file to end soon, close the file itself
512: * Precondition: f!=NULL
513: */
1.14 oskar 514: static void input_endfile (file_descr *f)
1.1 oskar 515: {
516: int i;
1.21 oskar 517: stream_descr *s;
1.1 oskar 518: i = in_streams;
519: while (--i >= 0) {
1.21 oskar 520: s = ins[i];
521: if (s->fdescr == f) {
522: s->endaction = ENDSTR_CLOSE;
1.1 oskar 523: }
524: }
1.5 oskar 525: if (f->handle >= 0) {
526: close (f->handle);
527: f->handle = -1;
528: }
1.1 oskar 529: input_closefileifunused (f);
530: }
531:
1.6 oskar 532: /* Close a file and release all corresponding data structures
533: * Precondition: f!=NULL, f->u.*.stream[*]==NULL
534: */
1.1 oskar 535: static void input_closefile (file_descr *f)
536: {
537: int i;
538: if (f->handle >= 0) {
539: close (f->handle);
540: }
541: list_release (f->data);
542: free (f->name);
543: switch (f->content) {
544: case ct_transport:
1.9 oskar 545: releasechain (pmt_descr,f->u.ts.pat);
546: releasechain (pmt_descr,f->u.ts.newpat);
547: releasechain (tsauto_descr,f->u.ts.tsauto);
548: releasechain (tssi_descr,f->u.ts.tssi);
1.1 oskar 549: break;
550: default:
551: break;
552: }
553: i = in_files;
554: while (--i >= 0) {
555: if (inf[i] == f) {
556: inf[i] = inf[--in_files];
1.13 oskar 557: in_openfiles[f->content] -= 1;
1.1 oskar 558: warn (LDEB,"Close file",EINP,11,1,in_files);
1.13 oskar 559: free (f);
1.1 oskar 560: return;
561: }
562: }
563: warn (LERR,"Close lost file",EINP,11,2,in_files);
1.13 oskar 564: free (f);
1.1 oskar 565: }
566:
1.6 oskar 567: /* Close a file if there are no more data streams open.
568: * If so, close any map streams.
569: * Precondition: f!=NULL
570: */
1.1 oskar 571: void input_closefileifunused (file_descr *f)
572: {
573: int i;
1.13 oskar 574: stream_descr *s;
575: if (f->openstreams[sd_data] <= 0) {
576: if (f->openstreams[sd_unparsedsi] > 0) {
577: switch (f->content) {
578: case ct_transport:
579: i = MAX_STRPERTS;
580: while ((f->openstreams[sd_unparsedsi] > 0)
581: && (--i >= 0)) {
582: s = ts_file_stream (f,i);
583: if ((s != NULL)
584: && (s->streamdata == sd_unparsedsi)
1.14 oskar 585: && (s->endaction == ENDSTR_CLOSE)
1.13 oskar 586: && (list_empty (s->ctrl))) {
587: input_closestream (ts_file_stream (f,i));
588: }
589: }
590: break;
591: default:
592: break;
593: }
594: }
1.16 oskar 595: if (f->openstreams[sd_unparsedsi] <= 0) {
596: if (f->openstreams[sd_map] > 0) {
597: switch (f->content) {
598: case ct_program:
599: i = MAX_STRPERPS;
600: while (--i >= 0) {
601: if (f->u.ps.stream[i] != NULL) {
602: input_closestream (f->u.ps.stream[i]);
603: }
1.1 oskar 604: }
1.16 oskar 605: break;
606: case ct_transport:
607: i = MAX_STRPERTS;
608: while (--i >= 0) {
609: s = ts_file_stream (f,i);
610: if ((s != NULL)
611: && (s->streamdata == sd_map)) {
612: input_closestream (ts_file_stream (f,i));
613: }
1.1 oskar 614: }
1.16 oskar 615: break;
616: default:
617: warn (LERR,"unexpected map",EINP,12,1,f->content);
618: break;
619: }
1.1 oskar 620: }
1.13 oskar 621: input_closefile (f);
622: }
1.1 oskar 623: }
624: }
625:
1.6 oskar 626: /* Add a target program to a stream's list of programs that contain it.
627: * Precondition: s!=NULL, p!=NULL, p not in s->u.d.pdescr[*]
628: * Postcondition: p in s->u.d.pdescr[*] not more than once.
629: * Return: TRUE if successful, FALSE otherwise.
630: */
1.1 oskar 631: boolean input_addprog (stream_descr *s,
632: prog_descr *p)
633: {
634: if (s->u.d.progs < MAX_PRGFORSTR) {
635: s->u.d.pdescr[s->u.d.progs++] = p;
636: warn (LDEB,"Add prog",EINP,10,2,s->u.d.progs);
637: return (TRUE);
638: }
639: warn (LERR,"Max add prog",EINP,10,1,s->u.d.progs);
640: return (FALSE);
641: }
642:
1.6 oskar 643: /* Delete a target program from a stream's list of programs that contain it.
644: * Precondition: s!=NULL, p!=NULL, p in s->u.d.pdescr[*] not more than once.
645: * Postcondition: p not in s->u.d.pdescr[*]
646: * Return: TRUE if successful, FALSE otherwise.
647: */
1.1 oskar 648: boolean input_delprog (stream_descr *s,
649: prog_descr *p)
650: {
651: int i;
652: i = s->u.d.progs;
653: while (--i >= 0) {
654: if (s->u.d.pdescr[i] == p) {
655: s->u.d.pdescr[i] = s->u.d.pdescr[--(s->u.d.progs)];
656: warn (LDEB,"Del prog",EINP,9,2,i);
657: return (TRUE);
658: }
659: }
660: warn (LERR,"Del lost prog",EINP,9,1,s->u.d.progs);
661: return (FALSE);
662: }
663:
1.6 oskar 664: /* Open a stream in a file. Allocate and initialize it.
665: * sourceid is the stream's ID in the source file.
666: * streamid is the PES packet stream id.
667: * streamtype is the stream type according to ISO 13818-1 table 2-29.
668: * isamap is TRUE for a map stream, FALSE for data stream.
669: * mapstream is the superior correlated map stream.
670: * Precondition: f!=NULL
671: * Return: stream if successful, NULL otherwise
672: */
1.1 oskar 673: stream_descr *input_openstream (file_descr *f,
674: int sourceid,
675: int streamid,
676: int streamtype,
1.10 oskar 677: streamdata_type streamdata,
1.1 oskar 678: stream_descr *mapstream)
679: {
680: stream_descr *s;
681: warn (LIMP,"Open stream",EINP,5,sourceid,streamid);
682: if (in_streams < MAX_INSTREAM) {
1.10 oskar 683: switch (streamdata) {
684: case sd_data:
685: s = unionalloc (stream_descr,d);
686: break;
687: case sd_map:
688: s = unionalloc (stream_descr,m);
689: break;
690: case sd_unparsedsi:
691: s = unionalloc (stream_descr,usi);
692: break;
693: default:
694: s = NULL;
695: break;
1.1 oskar 696: }
1.18 oskar 697: if ((s != NULL)
698: && ((s->autodescr = malloc (sizeof (descr_descr))) != NULL)
699: && ((s->manudescr = malloc (sizeof (descr_descr))) != NULL)) {
1.1 oskar 700: if (list_create (s->ctrl,MAX_CTRL_INB)) {
1.20 oskar 701: if ((streamdata == sd_map) ?
702: list_create (s->data,MAX_DATA_INBPSI) :
703: streamtype_isvideo (streamtype) ?
1.4 oskar 704: list_create (s->data,MAX_DATA_INBV) :
705: streamtype_isaudio (streamtype) ?
706: list_create (s->data,MAX_DATA_INBA) :
707: list_create (s->data,MAX_DATA_INB)) {
1.10 oskar 708: s->streamdata = streamdata;
709: switch (streamdata) {
710: case sd_data:
711: s->u.d.mapstream = mapstream;
712: s->u.d.discontinuity = FALSE;
713: s->u.d.trigger = FALSE;
714: s->u.d.mention = FALSE;
715: s->u.d.has_clockref = FALSE;
716: s->u.d.has_opcr = FALSE;
717: s->u.d.conv.base = 0;
718: s->u.d.conv.msec = 0;
719: s->u.d.progs = 0;
1.13 oskar 720: f->openstreams[streamdata] += 1;
721: in_openstreams[streamdata] += 1;
1.10 oskar 722: break;
723: case sd_map:
724: s->u.m.msectime = 0;
725: s->u.m.conv.base = 0;
726: s->u.m.conv.msec = 0;
727: s->u.m.psi_length = 0;
1.13 oskar 728: f->openstreams[streamdata] += 1;
729: in_openstreams[streamdata] += 1;
1.10 oskar 730: break;
731: case sd_unparsedsi:
1.13 oskar 732: f->openstreams[streamdata] += 1;
733: in_openstreams[streamdata] += 1;
1.10 oskar 734: break;
735: default:
736: break;
1.1 oskar 737: }
738: s->ctrl.ptr[0].length = 0;
739: s->ctrl.ptr[0].pcr.valid = FALSE;
740: s->ctrl.ptr[0].opcr.valid = FALSE;
1.4 oskar 741: s->fdescr = f;
1.1 oskar 742: s->sourceid = sourceid;
743: s->stream_id = streamid;
744: s->stream_type = streamtype;
1.28 ! oskar 745: warn (LINF,"Open Streamtype",EINP,5,3,streamtype);
1.1 oskar 746: s->version = 0xFF;
747: s->conticnt = 0;
748: s->endaction = ENDSTR_WAIT;
1.18 oskar 749: clear_descrdescr (s->autodescr);
750: clear_descrdescr (s->manudescr);
1.1 oskar 751: ins[in_streams++] = s;
752: return (s);
753: }
754: list_release (s->ctrl);
755: }
756: free (s);
757: } else {
758: warn (LERR,"Alloc fail",EINP,5,1,in_streams);
759: }
760: } else {
761: warn (LERR,"Max stream open",EINP,5,2,in_streams);
762: }
763: return (NULL);
764: }
765:
1.6 oskar 766: /* End a stream, if opportune.
767: * Check all target programs this stream is in, close those that
768: * do not contain another stream from the same file that is still running.
769: * Note, that the stream stays open if there is at least one other stream
770: * from the same file, that is still running together with it in a program.
771: * Precondition: s!=NULL
772: */
1.1 oskar 773: void input_endstream (stream_descr *s)
774: {
1.21 oskar 775: int q, i;
776: prog_descr *p;
777: stream_descr *t;
778: q = s->u.d.progs;
779: while (--q >= 0) {
780: p = s->u.d.pdescr[q];
781: i = p->streams;
1.1 oskar 782: while (--i >= 0) {
1.21 oskar 783: t = p->stream[i];
784: if ((!list_empty (t->ctrl))
785: && (t->u.d.trigger)
786: && (t->fdescr == s->fdescr)) {
1.1 oskar 787: break;
788: }
789: }
790: if (i < 0) {
1.21 oskar 791: splice_closeprog (p);
1.1 oskar 792: }
793: }
794: }
795:
1.6 oskar 796: /* End a stream.
797: * Unlink it from all target programs, no matter what is left therein.
798: * Precondition: s!=NULL
799: */
1.1 oskar 800: void input_endstreamkill (stream_descr *s)
801: {
1.4 oskar 802: int i;
803: i = s->u.d.progs;
1.1 oskar 804: while (--i >= 0) {
805: prog_descr *p;
806: p = s->u.d.pdescr[i];
807: if (p->streams > 1) {
1.4 oskar 808: unlink_streamprog (s,p);
1.1 oskar 809: } else {
1.21 oskar 810: splice_closeprog (p);
1.1 oskar 811: }
812: }
813: }
814:
1.6 oskar 815: /* Close a stream.
816: * Release all structures. If this is the only data stream related to the
817: * corresponding map stream, close the map stream, too.
818: * Precondition: s!=NULL
819: */
1.1 oskar 820: void input_closestream (stream_descr *s)
821: {
822: int i;
1.14 oskar 823: warn (LIMP,"Close stream",EINP,6,0,s->sourceid);
1.1 oskar 824: switch (s->fdescr->content) {
825: case ct_packetized:
826: s->fdescr->u.pes.stream = NULL;
827: break;
828: case ct_program:
829: s->fdescr->u.ps.stream[s->sourceid] = NULL;
830: break;
831: case ct_transport:
1.6 oskar 832: ts_file_stream (s->fdescr,s->sourceid) = NULL;
1.1 oskar 833: break;
834: default:
835: warn (LERR,"Unknown contents",EINP,6,2,s->fdescr->content);
836: break;
837: }
1.13 oskar 838: s->fdescr->openstreams[s->streamdata] -= 1;
839: if (s->streamdata == sd_data) {
1.1 oskar 840: switch (s->fdescr->content) {
841: case ct_transport:
1.19 oskar 842: if (s->u.d.mapstream != ts_file_stream (s->fdescr,0)) {
843: i = MAX_STRPERTS;
844: while ((--i >= 0)
845: && ((ts_file_stream (s->fdescr,i) == NULL)
846: || (ts_file_stream (s->fdescr,i)->streamdata != sd_data)
847: || (ts_file_stream (s->fdescr,i)->u.d.mapstream
848: != s->u.d.mapstream))) {
849: }
850: if (i < 0) {
851: if (s->u.d.mapstream->endaction == ENDSTR_CLOSE) {
852: input_closestream (s->u.d.mapstream);
853: }
1.1 oskar 854: }
855: }
856: break;
857: default:
858: break;
859: }
860: }
861: i = in_streams;
862: while (--i >= 0) {
863: if (ins[i] == s) {
864: ins[i] = ins[--in_streams];
1.13 oskar 865: in_openstreams[s->streamdata] -= 1;
1.1 oskar 866: break;
867: }
868: }
869: if (i < 0) {
870: warn (LERR,"Close lost stream",EINP,6,1,in_streams);
871: }
872: list_release (s->data);
873: list_release (s->ctrl);
1.18 oskar 874: free (s->manudescr);
875: free (s->autodescr);
1.1 oskar 876: free (s);
877: }
878:
1.6 oskar 879: /* Split data from raw input buffers to PES data stream buffers.
880: * Return: TRUE, if something was processed, FALSE if no data/space available
881: */
1.1 oskar 882: boolean split_something (void)
883: {
884: int i;
885: boolean r = FALSE;
886: warn (LDEB,"Split some",EINP,7,0,in_files);
887: i = in_files;
888: while (--i >= 0) {
889: switch (inf[i]->content) {
890: case ct_packetized:
891: if (split_pes (inf[i])) {
892: r = TRUE;
893: }
894: break;
895: case ct_program:
896: if (split_ps (inf[i])) {
897: r = TRUE;
898: }
899: break;
900: case ct_transport:
901: if (split_ts (inf[i])) {
902: r = TRUE;
903: }
904: break;
905: default:
906: warn (LERR,"Unknown contents",EINP,7,3,inf[i]->content);
907: /* error ? */
908: break;
909: }
910: }
911: return (r);
1.18 oskar 912: }
913:
914: /* Check all files of type ct_transport for --si ranges.
915: * Return: higher bound of range, if match is found, -1 otherwise
916: */
917: int input_tssiinafilerange (int pid)
918: {
919: int i;
920: i = in_files;
921: while (--i >= 0) {
922: warn (LDEB,"TSSI in file",EINP,14,-1,inf[i]->content);
923: if (inf[i]->content == ct_transport) {
924: int h;
925: h = split_unparsedsi (inf[i],pid);
926: if (h >= 0) {
927: warn (LDEB,"TSSI in file",EINP,14,pid,h);
928: return (h);
929: }
930: }
931: }
932: warn (LDEB,"TSSI in file",EINP,14,pid,-1);
933: return (-1);
1.1 oskar 934: }
935:
1.6 oskar 936: /* Determine the appropriate file for a given handle
937: * Return: file, if found, NULL otherwise
938: */
1.1 oskar 939: file_descr *input_filehandle (int handle)
940: {
941: int i;
942: i = in_files;
943: while (--i >= 0) {
944: if (inf[i]->handle == handle) {
945: return (inf[i]);
946: }
947: }
948: return (NULL);
949: }
950:
1.6 oskar 951: /* Check whether there is a pair of filerefnum and filename among the open
952: * files, that fits the criteria.
953: * Precondition: filename!=NULL or filerefnum>=0
954: * Return: file, if found, NULL otherwise
955: */
1.5 oskar 956: file_descr *input_filereferenced (int filerefnum,
957: char *filename)
958: {
959: int i;
1.21 oskar 960: file_descr *f;
1.5 oskar 961: i = in_files;
962: while (--i >= 0) {
1.21 oskar 963: f = inf[i];
1.5 oskar 964: if ((filename == NULL)
1.21 oskar 965: ? (filerefnum == f->filerefnum)
966: : ((!strcmp (filename, f->name))
1.5 oskar 967: && ((filerefnum < 0)
1.21 oskar 968: || (filerefnum == f->filerefnum)))) {
969: return (f);
1.5 oskar 970: }
971: }
972: return (NULL);
973: }
974:
1.6 oskar 975: /* Mark a file to be stopped.
976: * If stopped, the file will be handled as if eof was encountered, the
977: * next time there is data to be read from it.
978: * Precondition: f!=NULL
979: */
1.5 oskar 980: void input_stopfile (file_descr *f)
981: {
982: f->stopfile = TRUE;
983: }
984:
1.6 oskar 985: /* Read some data from the file into the raw buffer.
986: * On eof or f->stopfile, end the file, or handle repeatitions or append,
987: * if applicable.
988: * Precondition: poll has stated data or error for the file
989: */
1.1 oskar 990: void input_something (file_descr *f,
991: boolean readable)
992: {
993: int l, m;
994: if (f != NULL) {
995: if (f->handle >= 0) {
996: warn (LDEB,"Something",EINP,0,1,f);
1.5 oskar 997: if (readable && !f->stopfile) {
1.1 oskar 998: l = list_freeinend (f->data);
999: if (l > MAX_READ_IN) {
1000: l = MAX_READ_IN;
1001: }
1002: m = list_free (f->data);
1003: if (l > m) {
1004: l = m;
1005: }
1006: l = read (f->handle,&f->data.ptr[f->data.in],l);
1007: } else {
1008: l = 0;
1009: }
1010: warn (LDEB,"Some Read",EINP,0,2,l);
1011: if (l > 0) {
1012: list_incr (f->data.in,f->data,l);
1013: } else if (l == 0) {
1.5 oskar 1014: f->stopfile = FALSE;
1015: if (f->repeatitions != 0) {
1016: if (f->repeatitions > 0) {
1017: f->repeatitions -= 1;
1018: }
1019: if (lseek (f->handle,0,SEEK_CUR) > 255) {
1020: lseek (f->handle,0,SEEK_SET);
1021: warn (LIMP,"End Repeat",EINP,0,4,f);
1022: } else {
1023: warn (LWAR,"Repeat fail",EINP,0,5,f);
1024: }
1025: } else if (f->append_name != NULL) {
1026: free (f->name);
1027: f->name = f->append_name;
1028: f->append_name = NULL;
1029: if (f->append_filerefnum >= 0) {
1030: f->filerefnum = f->append_filerefnum;
1031: }
1032: close (f->handle);
1.26 oskar 1033: if ((f->handle = open (f->name,O_RDONLY|O_NONBLOCK)) >= 0) {
1.5 oskar 1034: struct stat stat;
1035: if (fstat (f->handle,&stat) == 0) {
1036: f->st_mode = stat.st_mode;
1037: if (!S_ISREG (f->st_mode)) {
1038: timed_io = TRUE;
1.7 oskar 1039: if (f->append_repeatitions != 0) {
1040: warn (LWAR,"Cannot repeat nonregular file",
1041: EINP,0,9,f->append_repeatitions);
1042: }
1.5 oskar 1043: f->repeatitions = 0;
1044: } else {
1045: f->repeatitions = f->append_repeatitions;
1.2 oskar 1046: }
1.12 oskar 1047: configuration_changed = TRUE;
1.5 oskar 1048: warn (LIMP,"End Append",EINP,0,f->repeatitions,f);
1.2 oskar 1049: } else {
1.6 oskar 1050: warn (LWAR,"Append fail",EINP,0,7,f);
1.5 oskar 1051: input_endfile (f);
1.2 oskar 1052: }
1.5 oskar 1053: } else {
1.6 oskar 1054: warn (LWAR,"Append fail",EINP,0,8,f);
1.1 oskar 1055: input_endfile (f);
1.5 oskar 1056: }
1057: } else {
1058: input_endfile (f);
1.1 oskar 1059: }
1060: } else {
1061: /* read error */
1062: }
1063: }
1064: }
1065: }
1066:
LinuxTV legacy CVS <linuxtv.org/cvs>