Annotation of multiplexer/repeatts.c, revision 1.4
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.4 ! jacob 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];
32:
33: static int dati, dato;
34: static byte data[MAX_ANOTATE];
35:
36: static t_msec nextrdelay, nextfdelay;
37:
1.4 ! jacob 38: t_msec
! 39: msec_now (void)
1.1 oskar 40: {
41: #define MSEC_EXPONENT 21
42: static long last;
43: static int local_delta;
44: struct timeval tv;
1.4 ! jacob 45: gettimeofday (&tv, NULL);
! 46: if ((tv.tv_sec & (~((1L << MSEC_EXPONENT) - 1))) != last)
! 47: {
! 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.4 ! jacob 52: + tv.tv_usec / 1000 + local_delta);
1.1 oskar 53: }
54:
1.4 ! jacob 55: static void
! 56: command_help (char *command)
1.1 oskar 57: {
1.4 ! jacob 58: fprintf (stderr,
! 59: "Usage:\t%s [<delay> <time> <file>]\n"
! 60: "\tSend <file> repeated every <delay> msec evenly distributed within\n"
! 61: "\t<time> msec, Feed a (delay,time,file) tuple to stdin to reset\n"
! 62: "\tbehaviour, quit program with negative delay, don't repeat with delay=0.\n",
! 63: command);
1.1 oskar 64: }
65:
1.4 ! jacob 66: static boolean
! 67: line_complete (char **s1, char **s2, char **s3)
1.1 oskar 68: {
69: int i;
1.4 ! jacob 70: boolean b = FALSE;
1.1 oskar 71: *s3 = NULL;
72: *s2 = NULL;
73: *s1 = NULL;
74: i = 0;
1.4 ! jacob 75: while (i < combln)
! 76: {
! 77: if (combuf[i] == '\n')
! 78: {
! 79: comlln = i;
! 80: while (i >= 0)
! 81: {
! 82: if (combuf[i] <= ' ')
! 83: {
! 84: combuf[i] = 0;
! 85: b = TRUE;
! 86: }
! 87: else
! 88: {
! 89: if (b)
! 90: {
! 91: *s3 = *s2;
! 92: *s2 = *s1;
! 93: b = FALSE;
! 94: }
! 95: *s1 = &combuf[i];
! 96: }
! 97: i -= 1;
! 98: }
! 99: return (TRUE);
1.1 oskar 100: }
1.4 ! jacob 101: i += 1;
1.1 oskar 102: }
103: return (FALSE);
104: }
105:
1.4 ! jacob 106: static boolean
! 107: is_long (char *s, long *r)
1.1 oskar 108: {
109: long i;
110: char *e;
1.4 ! jacob 111: if (s == NULL)
! 112: {
! 113: return (FALSE);
! 114: }
1.1 oskar 115: errno = 0;
1.4 ! jacob 116: i = strtol (s, &e, 0);
! 117: if ((errno != 0) || (*e != 0))
! 118: {
! 119: return (FALSE);
! 120: }
1.1 oskar 121: *r = i;
122: return (TRUE);
123: }
124:
1.4 ! jacob 125: static boolean
! 126: command_do (char *arg1, char *arg2, char *arg3)
1.1 oskar 127: {
128: long l1, l2;
129: struct stat stat;
1.4 ! jacob 130: D (fprintf (stderr, "command_do(%s,%s,%s)\n", arg1, arg2, arg3));
! 131: if (arg1 != NULL)
! 132: {
! 133: if (is_long (arg1, &l1))
! 134: {
! 135: if (l1 < 0)
! 136: {
! 137: quit = TRUE;
! 138: return (TRUE);
! 139: }
! 140: if (arg2 != NULL)
! 141: {
! 142: if (is_long (arg2, &l2))
! 143: {
! 144: if (l2 >= 0)
! 145: {
! 146: if ((l1 >= l2) || (l1 == 0))
! 147: {
! 148: if (arg3 != NULL)
! 149: {
! 150: if (nextf >= 0)
! 151: {
! 152: close (nextf);
! 153: }
! 154: if ((nextf = open (arg3, O_RDONLY)) >= 0)
! 155: {
! 156: if (fstat (nextf, &stat) == 0)
! 157: {
! 158: D (fprintf (stderr, "file %d, mode %07o, name %s, ino %ld, size %ld\n",
! 159: nextf, stat.st_mode, arg3, stat.st_ino, stat.st_size));
! 160: if (S_ISREG (stat.st_mode))
! 161: {
! 162: if ((stat.st_size %
! 163: TS_PACKET_SIZE) == 0)
! 164: {
! 165: if (stat.st_size > 0)
! 166: {
! 167: nextrdelay =
! 168: l2 / (stat.st_size /
! 169: TS_PACKET_SIZE);
! 170: }
! 171: else
! 172: {
! 173: nextrdelay = 0;
! 174: }
! 175: nextfdelay = l1;
! 176: D (fprintf (stderr, "next opened(%d,%d)\n", nextfdelay, nextrdelay));
! 177: return (TRUE);
! 178: }
! 179: else
! 180: {
! 181: fprintf (stderr,
! 182: "File size not multiple of 188\n");
! 183: }
! 184: }
! 185: else
! 186: {
! 187: fprintf (stderr,
! 188: "File not regular\n");
! 189: }
! 190: }
! 191: else
! 192: {
! 193: fprintf (stderr, "Cannot stat file\n");
! 194: }
! 195: close (nextf);
! 196: nextf = -1;
! 197: }
! 198: else
! 199: {
! 200: fprintf (stderr, "Cannot open file\n");
! 201: }
! 202: }
! 203: else
! 204: {
! 205: fprintf (stderr, "File name missing\n");
! 206: }
! 207: }
! 208: else
! 209: {
! 210: fprintf (stderr, "0<delay<time not allowed\n");
1.3 oskar 211: }
1.4 ! jacob 212: }
! 213: else
! 214: {
! 215: fprintf (stderr, "Time must not be negative\n");
! 216: }
! 217: }
! 218: else
! 219: {
! 220: fprintf (stderr, "Time must be numeric\n");
! 221: }
! 222: }
! 223: else
! 224: {
! 225: fprintf (stderr, "Time missing\n");
! 226: }
! 227: }
! 228: else
! 229: {
! 230: fprintf (stderr, "Delay must be numeric\n");
1.1 oskar 231: }
232: }
1.4 ! jacob 233: else
! 234: {
! 235: return (TRUE);
! 236: }
1.1 oskar 237: return (FALSE);
238: }
239:
1.4 ! jacob 240: static boolean
! 241: command_init (int cargc, char **cargv)
1.1 oskar 242: {
243: nextf = -1;
244: quit = FALSE;
245: combln = 0;
246: dati = dato = 0;
1.4 ! jacob 247: if (cargc > 1)
! 248: {
! 249: if (!strcmp (cargv[1], "--help"))
! 250: {
! 251: command_help (cargv[0]);
! 252: return (FALSE);
! 253: }
! 254: else
! 255: if (!command_do
! 256: (cargv[1], cargc > 2 ? cargv[2] : NULL,
! 257: cargc > 3 ? cargv[3] : NULL))
! 258: {
! 259: command_help (cargv[0]);
! 260: return (FALSE);
! 261: }
1.1 oskar 262: }
263: cmdf = STDIN_FILENO;
264: outf = STDOUT_FILENO;
265: return ((cmdf >= 0) && (outf >= 0));
266: }
267:
1.4 ! jacob 268: int
! 269: main (int argc, char *argv[])
1.1 oskar 270: {
271: int polli, pollo, polls;
1.4 ! jacob 272: int toberead = 0; /* to make gcc happy */
1.1 oskar 273: int currentf;
274: boolean dotime;
1.4 ! jacob 275: t_msec rtime;
! 276: t_msec ftime;
! 277: t_msec rdelay = 0; /* to make gcc happy */
! 278: t_msec fdelay = 0; /* to make gcc happy */
! 279: t_msec now;
! 280: struct pollfd ufds[3];
! 281: if (command_init (argc, &argv[0]))
! 282: {
! 283: currentf = -1;
! 284: rtime = ftime = msec_now ();
! 285: while (!quit)
! 286: {
1.1 oskar 287: now = msec_now ();
1.4 ! jacob 288: D (fprintf (stderr, "now(%d)\n", now));
! 289: if (currentf < 0)
! 290: {
! 291: toberead = 0;
! 292: rdelay = nextrdelay;
! 293: fdelay = nextfdelay;
! 294: if ((ftime - now) < 0)
! 295: {
! 296: ftime = now;
! 297: }
! 298: rtime = ftime;
! 299: currentf = nextf;
! 300: nextf = -1;
! 301: D (fprintf (stderr, "next current(%d,%d,%d)\n", currentf, fdelay, rdelay));
! 302: }
! 303: if (currentf >= 0)
! 304: {
! 305: if ((rtime - now) <= 0)
! 306: {
! 307: if ((((dato - dati - 1) & (MAX_ANOTATE - 1)) - toberead) >
! 308: TS_PACKET_SIZE)
! 309: {
! 310: toberead += TS_PACKET_SIZE;
! 311: rtime += rdelay;
! 312: dotime = TRUE;
! 313: D (fprintf (stderr, "timer a(%d,%d)\n", toberead, rtime));
! 314: }
! 315: else
! 316: {
! 317: rtime = now;
! 318: dotime = FALSE;
! 319: D (fprintf (stderr, "timer b(%d,%d)\n", toberead, rtime));
! 320: }
! 321: }
! 322: else
! 323: {
! 324: dotime = TRUE;
! 325: D (fprintf (stderr, "timer c(%d,%d)\n", toberead, rtime));
! 326: }
! 327: }
! 328: else
! 329: {
! 330: dotime = FALSE;
! 331: D (fprintf (stderr, "timer c(%d,%d)\n", toberead, rtime));
! 332: }
! 333: ufds[0].fd = cmdf;
! 334: ufds[0].events = POLLIN;
! 335: if (dati != dato)
! 336: {
! 337: ufds[1].fd = outf;
! 338: ufds[1].events = POLLOUT;
! 339: pollo = 1;
! 340: }
! 341: else
! 342: {
! 343: pollo = 0;
! 344: }
! 345: polls = pollo + 1;
! 346: if (toberead > 0)
! 347: {
! 348: polli = polls++;
! 349: ufds[polli].fd = currentf;
! 350: ufds[polli].events = POLLIN;
! 351: }
! 352: else
! 353: {
! 354: polli = 0;
! 355: }
! 356: poll (&ufds[0], polls,
! 357: dotime ? ((rtime - now) > 0) ? (rtime - now) : 0 : -1);
! 358: if (ufds[0].revents & POLLIN)
! 359: {
! 360: char *s1, *s2, *s3;
! 361: if (combln >= MAX_DATA_COMB - HIGHWATER_COM)
! 362: {
! 363: combln -= HIGHWATER_COM;
! 364: memmove (&combuf[0], &combuf[HIGHWATER_COM], combln);
! 365: }
! 366: combln += read (cmdf, &combuf[combln], MAX_DATA_COMB - combln);
! 367: while (line_complete (&s1, &s2, &s3))
! 368: {
! 369: command_do (s1, s2, s3);
! 370: combln -= comlln;
! 371: memmove (&combuf[0], &combuf[comlln], combln);
! 372: }
! 373: }
! 374: if ((polli != 0)
! 375: && (ufds[polli].revents & (POLLIN | POLLHUP | POLLERR)))
! 376: {
! 377: int l;
! 378: if (ufds[polli].revents & POLLIN)
! 379: {
! 380: l = toberead;
! 381: if (l > (MAX_ANOTATE - dati))
! 382: {
! 383: l = MAX_ANOTATE - dati;
! 384: }
! 385: l = read (currentf, &data[dati], l);
! 386: dati = (dati + l) & (MAX_ANOTATE - 1);
! 387: toberead -= l;
! 388: }
! 389: else
! 390: {
! 391: l = 0;
! 392: }
! 393: if (l == 0)
! 394: {
! 395: if ((nextf >= 0) || (fdelay == 0))
! 396: {
! 397: close (currentf);
! 398: currentf = -1;
! 399: }
! 400: else
! 401: {
! 402: lseek (currentf, 0, SEEK_SET);
! 403: toberead =
! 404: ((toberead - 1) / TS_PACKET_SIZE) * TS_PACKET_SIZE;
! 405: }
! 406: ftime += fdelay;
! 407: now = msec_now ();
! 408: if ((ftime - now) < 0)
! 409: {
! 410: ftime = now;
! 411: }
! 412: rtime = ftime;
! 413: }
! 414: }
! 415: if ((pollo != 0)
! 416: && (ufds[1].revents & (POLLOUT | POLLHUP | POLLERR)))
! 417: {
! 418: if (ufds[1].revents & POLLOUT)
! 419: {
! 420: int l;
! 421: if (dati < dato)
! 422: {
! 423: l = MAX_ANOTATE - dato;
! 424: }
! 425: else
! 426: {
! 427: l = dati - dato;
! 428: }
! 429: l = write (outf, &data[dato], l);
! 430: dato = (dato + l) & (MAX_ANOTATE - 1);
! 431: if (l == 0)
! 432: {
! 433: quit = TRUE;
! 434: }
! 435: }
! 436: else
! 437: {
! 438: quit = TRUE;
! 439: }
! 440: }
1.1 oskar 441: }
1.4 ! jacob 442: return (EXIT_SUCCESS);
1.1 oskar 443: }
444: return (EXIT_FAILURE);
445: }
LinuxTV legacy CVS <linuxtv.org/cvs>