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