Annotation of multiplexer/repeatts.c, revision 1.9
1.1 oskar 1: /*
2: * ISO 13818 stream multiplexer / additional repeater tool
3: * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
1.8 oskar 4: * Author: Oskar Schirmer (oskar@scara.com)
1.9 ! 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: Repeater
23: * Purpose: Additional tool to repeat and pipe an input stream.
24: *
25: * This tool accepts a (time1,time2,filename) tuple via stdin,
26: * opens the filename, assuming it contains a ISO 13818 Transport Stream,
27: * and sends it packet-wise to stdout timed in such a way, that
28: * all pakets are sent equally distributed within time2 msec.
29: * As long as no further tuple is provided, after time1 msec the same
30: * file is sent over and over again.
31: */
32:
33:
34: #include <stdio.h>
35: #include "global.h"
36:
1.7 oskar 37: #define D(x) /* x */
1.1 oskar 38:
39: #define MAX_ANOTATE (16 * 256)
40:
41: static boolean quit;
42: static int cmdf, outf, nextf;
43:
44: static int combln, comlln;
45: static byte combuf[MAX_DATA_COMB];
1.7 oskar 46: static int pollc;
1.1 oskar 47:
48: static int dati, dato;
49: static byte data[MAX_ANOTATE];
50:
1.7 oskar 51: static t_msec nextrdelay, nextfdelay;
52: static off_t nextpackets;
1.1 oskar 53:
1.7 oskar 54: t_msec msec_now (void)
1.1 oskar 55: {
56: #define MSEC_EXPONENT 21
57: static long last;
58: static int local_delta;
1.7 oskar 59: struct timeval tv;
60: gettimeofday (&tv,NULL);
61: if ((tv.tv_sec & (~((1L << MSEC_EXPONENT) - 1))) != last) {
62: last = tv.tv_sec & (~((1L << MSEC_EXPONENT) - 1));
63: local_delta += 1000 * (1L << MSEC_EXPONENT);
64: }
1.1 oskar 65: return ((tv.tv_sec & ((1L << MSEC_EXPONENT) - 1)) * 1000
1.7 oskar 66: + tv.tv_usec / 1000 + local_delta);
1.1 oskar 67: }
68:
1.7 oskar 69: static void command_help (char *command, char *errmsg)
1.1 oskar 70: {
1.7 oskar 71: fprintf (stderr, "%s\nUsage:\t%s [OPTIONS...] [<file>]\n"
72: " -d <delay>\ttime in msec after which the sending shall be repeated\n"
73: " -t <time>\ttime in msec until the file shall be sent completely\n"
74: " -i\t\taccept from stdin tripels: <delay> <time> <file>\n\n"
75: "Send <file> repeated every <delay> msec evenly distributed within <time> msec.\n"
76: "When omitted, <time> defaults to <delay>. When <delay> is omitted, the file is\n"
77: "sent only once, and <time> must be given. When <file> is ommitted, only -i must\n"
78: "be given, to allow commands be enter through stdin.\n",
79: errmsg, command);
1.1 oskar 80: }
81:
1.7 oskar 82: static boolean line_complete (char **s1,
83: char **s2,
84: char **s3)
1.1 oskar 85: {
86: int i;
1.7 oskar 87: boolean b;
1.1 oskar 88: *s3 = NULL;
89: *s2 = NULL;
90: *s1 = NULL;
91: i = 0;
1.7 oskar 92: while (i < combln) {
93: if (combuf[i] == '\n') {
94: comlln = i;
95: while (i >= 0) {
96: if (combuf[i] <= ' ') {
97: combuf[i] = 0;
98: b = TRUE;
99: } else {
100: if (b) {
101: *s3 = *s2;
102: *s2 = *s1;
103: b = FALSE;
104: }
105: *s1 = &combuf[i];
1.1 oskar 106: }
1.7 oskar 107: i -= 1;
108: }
109: return (TRUE);
1.1 oskar 110: }
1.7 oskar 111: i += 1;
112: }
1.1 oskar 113: return (FALSE);
114: }
115:
1.7 oskar 116: static boolean is_long (char *s,
117: long *r)
1.1 oskar 118: {
119: long i;
120: char *e;
1.7 oskar 121: if (s == NULL) {
122: return (FALSE);
123: }
1.1 oskar 124: errno = 0;
1.7 oskar 125: i = strtol (s,&e,0);
126: if ((errno != 0)
127: || (*e != 0)) {
128: return (FALSE);
129: }
1.1 oskar 130: *r = i;
131: return (TRUE);
132: }
133:
1.7 oskar 134: static boolean command_do (char *arg1,
135: char *arg2,
136: char *arg3)
1.1 oskar 137: {
138: long l1, l2;
139: struct stat stat;
1.7 oskar 140: D(fprintf(stderr,"command_do(%s,%s,%s)\n",arg1,arg2,arg3));
141: if (arg1 != NULL) {
142: if (is_long (arg1, &l1)) {
143: if (l1 < 0) {
144: quit = TRUE;
145: return (TRUE);
146: }
147: if (arg2 != NULL) {
148: if (is_long (arg2, &l2)) {
149: if (l2 >= 0) {
150: if ((l1 >= l2) || (l1 == 0)) {
151: if (arg3 != NULL) {
152: if (nextf >= 0) {
153: close (nextf);
154: }
155: if ((nextf = open (arg3, O_RDONLY)) >= 0) {
156: if (fstat (nextf, &stat) == 0) {
157: D(fprintf(stderr,"file %d, mode %07o, name %s, ino %ld, size %ld\n",nextf,stat.st_mode,arg3,stat.st_ino,stat.st_size));
158: if (S_ISREG (stat.st_mode)) {
159: if ((stat.st_size % TS_PACKET_SIZE) == 0) {
160: nextrdelay = l2;
161: nextpackets = stat.st_size / TS_PACKET_SIZE;
162: nextfdelay = l1;
163: D(fprintf(stderr,"next opened(%d,%d,%d)\n",nextfdelay,nextrdelay,nextpackets));
164: return (TRUE);
165: } else {
166: fprintf (stderr, "File size not multiple of 188\n");
167: }
168: } else {
169: fprintf (stderr, "File not regular\n");
170: }
171: } else {
172: fprintf (stderr, "Cannot stat file\n");
173: }
174: close (nextf);
175: nextf = -1;
176: } else {
177: fprintf (stderr, "Cannot open file\n");
178: }
179: } else {
180: fprintf (stderr, "File name missing\n");
181: }
182: } else {
183: fprintf (stderr, "0<delay<time not allowed\n");
184: }
185: } else {
186: fprintf (stderr, "Time must not be negative\n");
187: }
188: } else {
189: fprintf (stderr, "Time must be numeric\n");
1.1 oskar 190: }
1.7 oskar 191: } else {
192: fprintf (stderr, "Time missing\n");
193: }
194: } else {
195: fprintf (stderr, "Delay must be numeric\n");
1.1 oskar 196: }
1.7 oskar 197: } else {
198: return (TRUE);
199: }
1.1 oskar 200: return (FALSE);
201: }
202:
1.7 oskar 203: static boolean command_init (int cargc,
204: char **cargv)
1.1 oskar 205: {
1.7 oskar 206: char *cdelay = NULL;
207: char *ctime = NULL;
208: char *cfile = NULL;
209: int cc = 0;
1.1 oskar 210: nextf = -1;
211: quit = FALSE;
212: combln = 0;
213: dati = dato = 0;
1.7 oskar 214: pollc = -1;
215: while (++cc < cargc) {
216: if (!strcmp (cargv[cc],"--help")) {
217: command_help (cargv[0],"");
218: return (FALSE);
219: } else if (!strcmp (cargv[cc],"-i")) {
220: pollc = 0;
221: } else if (!strcmp (cargv[cc],"-d")) {
222: if ((cdelay != NULL) || (++cc >= cargc)) {
223: command_help (cargv[0],"must not use -d twice.\n");
224: return (FALSE);
225: }
226: cdelay = cargv[cc];
227: } else if (!strcmp (cargv[cc],"-t")) {
228: if ((ctime != NULL) || (++cc >= cargc)) {
229: command_help (cargv[0],"must not use -t twice.\n");
230: return (FALSE);
231: }
232: ctime = cargv[cc];
233: } else {
234: if (cfile != NULL) {
235: command_help (cargv[0],"too many parameters.\n");
236: return (FALSE);
237: }
238: cfile = cargv[cc];
239: }
240: }
241: if (cfile != NULL) {
242: if (!command_do (cdelay ? cdelay : "0", ctime ? ctime : cdelay, cfile)) {
243: command_help (cargv[0],"");
244: return (FALSE);
1.1 oskar 245: }
1.7 oskar 246: } else if ((ctime != NULL) || (cdelay != NULL) || (pollc <= 0)) {
247: command_help (cargv[0],"only -i must be given when started with no file.\n");
248: return (FALSE);
249: }
1.1 oskar 250: cmdf = STDIN_FILENO;
251: outf = STDOUT_FILENO;
252: return ((cmdf >= 0) && (outf >= 0));
253: }
254:
1.7 oskar 255: int main (int argc,
256: char *argv[])
1.1 oskar 257: {
258: int polli, pollo, polls;
1.7 oskar 259: int toberead;
1.1 oskar 260: int currentf;
261: boolean dotime;
1.7 oskar 262: t_msec rtime, ftime, rdelay, fdelay, now;
263: struct pollfd ufds [3];
264: off_t rpackets, rpartial, rpdone;
265: if (command_init (argc,&argv[0])) {
266: currentf = -1;
267: rtime = ftime = msec_now ();
268: while (!quit) {
269: now = msec_now ();
270: D(fprintf(stderr,"now(%d)\n",now));
271: if (currentf < 0) {
272: toberead = 0;
273: if (nextpackets > 0) {
274: rpackets = nextpackets;
275: rdelay = nextrdelay / nextpackets;
276: rpartial = nextrdelay % nextpackets;
277: } else {
278: rpackets = 1;
279: rdelay = 0;
280: rpartial = 0;
281: }
282: rpdone = 0;
283: fdelay = nextfdelay;
284: if ((ftime-now) < 0) {
285: ftime = now;
286: }
287: rtime = ftime;
288: currentf = nextf;
289: nextf = -1;
290: D(fprintf(stderr,"next current(%d,%d,%d)\n",currentf,fdelay,rdelay));
291: }
292: if (currentf >= 0) {
293: if ((rtime - now) <= 0) {
294: if ((((dato-dati-1) & (MAX_ANOTATE-1)) - toberead) > TS_PACKET_SIZE) {
295: toberead += TS_PACKET_SIZE;
296: rtime += rdelay;
297: rpdone += rpartial;
298: if (rpdone >= rpackets) {
299: rpdone -= rpackets; /* equaly distribute the rounded msecs by */
300: rtime += 1; /* counting them in an rpackets modulo-space */
301: }
302: dotime = TRUE;
303: D(fprintf(stderr,"timer a(%d,%d,%d)\n",toberead,rtime,rpdone));
304: } else {
305: rtime = now;
306: dotime = FALSE;
307: D(fprintf(stderr,"timer b(%d,%d)\n",toberead,rtime));
308: }
309: } else {
310: dotime = TRUE;
311: D(fprintf(stderr,"timer c(%d,%d)\n",toberead,rtime));
312: }
313: } else {
314: dotime = FALSE;
315: D(fprintf(stderr,"timer c(%d,%d)\n",toberead,rtime));
316: }
317: polls = pollc+1;
318: if (pollc >= 0) {
319: ufds[pollc].fd = cmdf;
320: ufds[pollc].events = POLLIN;
321: }
322: if (dati != dato) {
323: pollo = polls++;
324: ufds[pollo].fd = outf;
325: ufds[pollo].events = POLLOUT;
326: } else {
327: pollo = -1;
328: }
329: if (toberead > 0) {
330: polli = polls++;
331: ufds[polli].fd = currentf;
332: ufds[polli].events = POLLIN;
333: } else {
334: polli = -1;
335: }
336: poll (&ufds[0], polls, dotime ? ((rtime-now) > 0) ? (rtime-now) : 0 : -1);
337: if ((pollc >= 0)
338: && (ufds[pollc].revents & POLLIN)) {
339: char *s1, *s2, *s3;
340: if (combln >= MAX_DATA_COMB-HIGHWATER_COM) {
341: combln -= HIGHWATER_COM;
342: memmove (&combuf[0], &combuf[HIGHWATER_COM], combln);
343: }
344: combln += read (cmdf, &combuf[combln], MAX_DATA_COMB-combln);
345: while (line_complete (&s1, &s2, &s3)) {
346: command_do (s1, s2, s3);
347: combln -= comlln;
348: memmove (&combuf[0], &combuf[comlln], combln);
349: }
350: }
351: if ((polli >= 0)
352: && (ufds[polli].revents & (POLLIN | POLLHUP | POLLERR))) {
353: int l;
354: if (ufds[polli].revents & POLLIN) {
355: l = toberead;
356: if (l > (MAX_ANOTATE - dati)) {
357: l = MAX_ANOTATE - dati;
358: }
359: l = read (currentf, &data[dati], l);
360: dati = (dati+l) & (MAX_ANOTATE-1);
361: toberead -= l;
362: } else {
363: l = 0;
364: }
365: if (l == 0) {
366: if ((nextf >= 0)
367: || (fdelay == 0)) {
368: close (currentf);
369: currentf = -1;
370: } else {
371: lseek (currentf,0,SEEK_SET);
372: toberead = ((toberead-1) / TS_PACKET_SIZE) * TS_PACKET_SIZE;
373: }
374: ftime += fdelay;
1.1 oskar 375: now = msec_now ();
1.7 oskar 376: if ((ftime-now) < 0) {
377: ftime = now;
378: }
379: rtime = ftime;
380: }
381: }
382: if ((pollo >= 0)
383: && (ufds[pollo].revents & (POLLOUT | POLLHUP | POLLERR))) {
384: if (ufds[pollo].revents & POLLOUT) {
385: int l;
386: if (dati < dato) {
387: l = MAX_ANOTATE - dato;
388: } else {
389: l = dati - dato;
390: }
391: l = write (outf, &data[dato], l);
392: dato = (dato+l) & (MAX_ANOTATE-1);
393: if (l == 0) {
394: quit = TRUE;
395: }
396: } else {
397: quit = TRUE;
1.1 oskar 398: }
1.7 oskar 399: }
1.1 oskar 400: }
1.7 oskar 401: return (EXIT_SUCCESS);
402: }
1.1 oskar 403: return (EXIT_FAILURE);
404: }
LinuxTV legacy CVS <linuxtv.org/cvs>