Annotation of multiplexer/repeatts.c, revision 1.11

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"))) {
        !           220:       fprintf(stderr, "1.0.7\n");
        !           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>