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>