Annotation of multiplexer/repeatts.c, revision 1.12
1.1 oskar 1: /*
2: * ISO 13818 stream multiplexer / additional repeater tool
3: * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
1.11 oskar 4: * Copyright (C) 2005 Oskar Schirmer (schirmer@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) {
1.11 oskar 216: if ((!strcmp(cargv[cc],"--help")) || (!strcmp(cargv[cc],"-h"))) {
1.7 oskar 217: command_help (cargv[0],"");
218: return (FALSE);
1.11 oskar 219: } else if ((!strcmp(cargv[cc],"--version")) || (!strcmp(cargv[cc],"-V"))) {
1.12 ! oskar 220: fprintf(stderr, "1.0.8\n");
1.11 oskar 221: return FALSE;
1.7 oskar 222: } else if (!strcmp (cargv[cc],"-i")) {
223: pollc = 0;
224: } else if (!strcmp (cargv[cc],"-d")) {
225: if ((cdelay != NULL) || (++cc >= cargc)) {
226: command_help (cargv[0],"must not use -d twice.\n");
227: return (FALSE);
228: }
229: cdelay = cargv[cc];
230: } else if (!strcmp (cargv[cc],"-t")) {
231: if ((ctime != NULL) || (++cc >= cargc)) {
232: command_help (cargv[0],"must not use -t twice.\n");
233: return (FALSE);
234: }
235: ctime = cargv[cc];
236: } else {
237: if (cfile != NULL) {
238: command_help (cargv[0],"too many parameters.\n");
239: return (FALSE);
240: }
241: cfile = cargv[cc];
242: }
243: }
244: if (cfile != NULL) {
245: if (!command_do (cdelay ? cdelay : "0", ctime ? ctime : cdelay, cfile)) {
246: command_help (cargv[0],"");
247: return (FALSE);
1.1 oskar 248: }
1.11 oskar 249: } else if ((ctime != NULL) || (cdelay != NULL) || (pollc < 0)) {
250: D(fprintf(stderr,"ctime=%p, cdelay=%p, pollc=%d\n", ctime, cdelay, pollc));
1.7 oskar 251: command_help (cargv[0],"only -i must be given when started with no file.\n");
252: return (FALSE);
253: }
1.1 oskar 254: cmdf = STDIN_FILENO;
255: outf = STDOUT_FILENO;
256: return ((cmdf >= 0) && (outf >= 0));
257: }
258:
1.7 oskar 259: int main (int argc,
260: char *argv[])
1.1 oskar 261: {
262: int polli, pollo, polls;
1.7 oskar 263: int toberead;
1.1 oskar 264: int currentf;
265: boolean dotime;
1.7 oskar 266: t_msec rtime, ftime, rdelay, fdelay, now;
267: struct pollfd ufds [3];
268: off_t rpackets, rpartial, rpdone;
269: if (command_init (argc,&argv[0])) {
270: currentf = -1;
271: rtime = ftime = msec_now ();
272: while (!quit) {
273: now = msec_now ();
274: D(fprintf(stderr,"now(%d)\n",now));
275: if (currentf < 0) {
276: toberead = 0;
277: if (nextpackets > 0) {
278: rpackets = nextpackets;
279: rdelay = nextrdelay / nextpackets;
280: rpartial = nextrdelay % nextpackets;
281: } else {
282: rpackets = 1;
283: rdelay = 0;
284: rpartial = 0;
285: }
286: rpdone = 0;
287: fdelay = nextfdelay;
288: if ((ftime-now) < 0) {
289: ftime = now;
290: }
291: rtime = ftime;
292: currentf = nextf;
293: nextf = -1;
294: D(fprintf(stderr,"next current(%d,%d,%d)\n",currentf,fdelay,rdelay));
295: }
296: if (currentf >= 0) {
297: if ((rtime - now) <= 0) {
298: if ((((dato-dati-1) & (MAX_ANOTATE-1)) - toberead) > TS_PACKET_SIZE) {
299: toberead += TS_PACKET_SIZE;
300: rtime += rdelay;
301: rpdone += rpartial;
302: if (rpdone >= rpackets) {
303: rpdone -= rpackets; /* equaly distribute the rounded msecs by */
304: rtime += 1; /* counting them in an rpackets modulo-space */
305: }
306: dotime = TRUE;
307: D(fprintf(stderr,"timer a(%d,%d,%d)\n",toberead,rtime,rpdone));
308: } else {
309: rtime = now;
310: dotime = FALSE;
311: D(fprintf(stderr,"timer b(%d,%d)\n",toberead,rtime));
312: }
313: } else {
314: dotime = TRUE;
315: D(fprintf(stderr,"timer c(%d,%d)\n",toberead,rtime));
316: }
317: } else {
318: dotime = FALSE;
319: D(fprintf(stderr,"timer c(%d,%d)\n",toberead,rtime));
320: }
321: polls = pollc+1;
322: if (pollc >= 0) {
323: ufds[pollc].fd = cmdf;
324: ufds[pollc].events = POLLIN;
325: }
326: if (dati != dato) {
327: pollo = polls++;
328: ufds[pollo].fd = outf;
329: ufds[pollo].events = POLLOUT;
330: } else {
331: pollo = -1;
332: }
333: if (toberead > 0) {
334: polli = polls++;
335: ufds[polli].fd = currentf;
336: ufds[polli].events = POLLIN;
337: } else {
338: polli = -1;
339: }
340: poll (&ufds[0], polls, dotime ? ((rtime-now) > 0) ? (rtime-now) : 0 : -1);
341: if ((pollc >= 0)
342: && (ufds[pollc].revents & POLLIN)) {
343: char *s1, *s2, *s3;
344: if (combln >= MAX_DATA_COMB-HIGHWATER_COM) {
345: combln -= HIGHWATER_COM;
346: memmove (&combuf[0], &combuf[HIGHWATER_COM], combln);
347: }
348: combln += read (cmdf, &combuf[combln], MAX_DATA_COMB-combln);
349: while (line_complete (&s1, &s2, &s3)) {
350: command_do (s1, s2, s3);
351: combln -= comlln;
352: memmove (&combuf[0], &combuf[comlln], combln);
353: }
354: }
355: if ((polli >= 0)
356: && (ufds[polli].revents & (POLLIN | POLLHUP | POLLERR))) {
357: int l;
358: if (ufds[polli].revents & POLLIN) {
359: l = toberead;
360: if (l > (MAX_ANOTATE - dati)) {
361: l = MAX_ANOTATE - dati;
362: }
363: l = read (currentf, &data[dati], l);
364: dati = (dati+l) & (MAX_ANOTATE-1);
365: toberead -= l;
366: } else {
367: l = 0;
368: }
369: if (l == 0) {
370: if ((nextf >= 0)
371: || (fdelay == 0)) {
372: close (currentf);
373: currentf = -1;
374: } else {
375: lseek (currentf,0,SEEK_SET);
376: toberead = ((toberead-1) / TS_PACKET_SIZE) * TS_PACKET_SIZE;
377: }
378: ftime += fdelay;
1.1 oskar 379: now = msec_now ();
1.7 oskar 380: if ((ftime-now) < 0) {
381: ftime = now;
382: }
383: rtime = ftime;
384: }
385: }
386: if ((pollo >= 0)
387: && (ufds[pollo].revents & (POLLOUT | POLLHUP | POLLERR))) {
388: if (ufds[pollo].revents & POLLOUT) {
389: int l;
390: if (dati < dato) {
391: l = MAX_ANOTATE - dato;
392: } else {
393: l = dati - dato;
394: }
395: l = write (outf, &data[dato], l);
396: dato = (dato+l) & (MAX_ANOTATE-1);
397: if (l == 0) {
398: quit = TRUE;
399: }
400: } else {
401: quit = TRUE;
1.1 oskar 402: }
1.7 oskar 403: }
1.1 oskar 404: }
1.7 oskar 405: return (EXIT_SUCCESS);
406: }
1.1 oskar 407: return (EXIT_FAILURE);
408: }
LinuxTV legacy CVS <linuxtv.org/cvs>