Annotation of multiplexer/showts.c, revision 1.5

1.2       oskar       1: /*
                      2:  * tiny debugging tool.
                      3:  * when fed with a transport stream to stdin, produces one char
                      4:  * per packet to stdout, and a few informative messages to stderr.
                      5:  * Upper case letters denote a continuity counter mismatch.
                      6:  *
                      7:  * Author: Jacob Schroeder (jacob@convergence.de)
1.3       oskar       8:  *
                      9:  * This program is free software; you can redistribute it and/or modify
                     10:  * it under the terms of the GNU General Public License as published by
                     11:  * the Free Software Foundation; either version 2 of the License, or
                     12:  * (at your option) any later version.
                     13:  *
                     14:  * This program is distributed in the hope that it will be useful,
                     15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17:  * GNU General Public License for more details.
                     18:  *
                     19:  * You should have received a copy of the GNU General Public License
                     20:  * along with this program; if not, write to the Free Software
                     21:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1.2       oskar      22:  */
                     23: 
1.1       jacob      24: #include <stdlib.h>
                     25: #include <stdio.h>
                     26: #include <unistd.h>
                     27: 
1.4       jacob      28: #include <getopt.h>
                     29: #include <string.h>
                     30: #include <errno.h>
                     31: #include <signal.h>
                     32: #include <sys/types.h>
                     33: #include <sys/wait.h>
                     34: #include <sys/time.h>
                     35: #include <sys/resource.h>
                     36: 
1.1       jacob      37: #define MAXPID 0x1fff
                     38: 
1.4       jacob      39: static struct option long_options[] = {
                     40:        {"help"   , 0, NULL, 'h'},
                     41:        {"summary", 0, NULL, 's'},
                     42:        {"analyse", 0, NULL, 'a'},
1.5     ! jacob      43:        {"pcr"    , 0, NULL, 'P'},
        !            44:        {"start",   0, NULL, 'S'},
1.4       jacob      45:        {NULL, 0, NULL, 0}
                     46: };
                     47: 
                     48: static const char *program = NULL;
                     49: 
                     50: static int         show_analysis = 0;
                     51: static int         show_summary = 0;
                     52: static int         show_packets = 1;
                     53: static int         show_pids    = 1;
                     54: 
1.5     ! jacob      55: static int         show_cc_jumps = 1;
        !            56: static int         show_pcr      = 0;
        !            57: static int         show_start    = 0;
        !            58: 
1.4       jacob      59: static int         pid_cnt = 0;
                     60: static int         packet_cnt = 0;
                     61: static int         broken_sync_cnt = 0;
                     62: static int         broken_alen_cnt = 0;
                     63: static int         unusual_cc_cnt  = 0;
                     64: 
                     65: static void usage ()
                     66: {
                     67:        printf("Usage: %s [OPTION] < <TS file>\n"
                     68:                         " -h, --help                    show usage\n"
                     69:                         " -s, --summary                 show summary\n"
                     70:                         " -a, --analyse                 analyse stream statistics\n"
1.5     ! jacob      71:                         " -P, --pcr                     indicate PCR\n"
        !            72:                         " -S, --start                   indicate unit start\n"
1.4       jacob      73:                        , program);
                     74: }
                     75: 
                     76: 
1.1       jacob      77: int main (int argc, char **argv)
                     78: {
                     79: 
1.4       jacob      80:   int    pids[MAXPID+1];
                     81:   int    ccs[MAXPID+1];
                     82:   int    pid_count = 0;
                     83:   int    i;
                     84:   int    count = 0;
                     85: 
                     86:   char **next_arg = argv+1;
                     87:   int    option_index = 0;
                     88: 
                     89:   if ((program = strrchr(argv[0], '/')) != NULL) {
                     90:       program++;
                     91:   } else {
                     92:       program = argv[0];
                     93:   }
                     94: 
                     95:   while (1) {
                     96:       int opt;
                     97:       // char *endptr;
                     98: 
1.5     ! jacob      99:       opt = getopt_long (argc, argv, "+hsPSa", long_options, &option_index);
1.4       jacob     100:       if (opt == -1) break;
                    101: 
                    102:       switch (opt) {
                    103:         case 'a':
                    104:           show_analysis = 1;
                    105:           show_packets = 0;
                    106:           break;
                    107: 
                    108:         case 's':
                    109:           show_summary = 1;
                    110:           show_packets = 0;
                    111:           break;
                    112: 
1.5     ! jacob     113:         case 'S':
        !           114:           show_cc_jumps = 0;
        !           115:           show_start    = 1;
        !           116:           show_pcr      = 0;
        !           117:           break;
        !           118: 
        !           119:         case 'P':
        !           120:           show_cc_jumps = 0;
        !           121:           show_start    = 0;
        !           122:           show_pcr      = 1;
        !           123:           break;
        !           124: 
1.4       jacob     125:         case 'h':
                    126:           usage ();
                    127:           exit (0);
                    128: 
                    129:         default:
                    130:           usage ();
                    131:           exit (1);
                    132:       }
                    133:   }
                    134: 
                    135:   next_arg = argv + optind;
1.1       jacob     136: 
                    137:   for (i = 0; i <= MAXPID; i++)
1.2       oskar     138:     {
                    139:       pids[i] = -1;
                    140:       ccs[i] = -1;
                    141:     }
1.1       jacob     142: 
                    143:   while (1)
                    144:     {
                    145:       unsigned char buffer[188];
                    146:       int           bytes_read;
                    147: 
                    148:       int n;
                    149: 
                    150: 
                    151:       bytes_read = 0;
                    152: 
1.4       jacob     153:       do
1.1       jacob     154:         {
                    155:           n = read (0, buffer + bytes_read, sizeof (buffer) - bytes_read);
                    156: 
                    157:           if (n < 0)
                    158:             {
1.4       jacob     159:               if (errno == EINTR)
                    160:                 continue;
                    161: 
1.1       jacob     162:               perror ("read");
                    163:               exit (1);
                    164:             }
                    165: 
                    166:           bytes_read += n;
                    167:         }
                    168:       while (bytes_read < sizeof (buffer) && n > 0);
                    169: 
                    170:       if (n == 0)
                    171:         {
1.4       jacob     172:           int exit_value = 0;
                    173: 
1.1       jacob     174:           if (bytes_read && bytes_read < sizeof (buffer))
                    175:             {
                    176:               fprintf (stderr, "incomplete ts packet read, size = %d\n", bytes_read);
                    177:             }
1.4       jacob     178: 
                    179:           if (show_summary)
                    180:             {
                    181:               printf ("packets:                        %-6d\n", packet_cnt);
                    182:               printf ("pids:                           %-6d\n", pid_cnt);
                    183:               printf ("sync errors:                    %-6d\n",
                    184:                       broken_sync_cnt);
                    185:               printf ("adaptation field length errors: %-6d\n",
                    186:                       broken_alen_cnt);
                    187:               printf ("unusual cc increments:          %-6d\n",
                    188:                       unusual_cc_cnt);
                    189:               printf ("\n");
                    190:             }
                    191: 
                    192:           if (show_analysis)
                    193:             {
                    194:               int quality = 1;
                    195: 
                    196:               if (pid_cnt > packet_cnt / 10)
                    197:                 {
                    198:                   printf ("The number of different PIDs is higher than 10%% of the packet count.\n");
                    199:                   quality = -1;
                    200:                 }
                    201:               else if (pid_cnt > packet_cnt / 100)
                    202:                 {
                    203:                   printf ("The number of different PIDs is higher than 1%% of the packet count.\n");
                    204:                   if (quality > 0)
                    205:                     quality = 0;
                    206:                 }
                    207: 
                    208:               if (pid_cnt > 2048)
                    209:                 {
                    210:                   printf ("The number of different PIDs is higher than 2048.\n");
                    211:                   quality = -1;
                    212:                 }
                    213: 
                    214:               if (broken_sync_cnt > 0)
                    215:                 {
                    216:                   if (broken_sync_cnt < packet_cnt / 100)
                    217:                     {
                    218:                       printf ("There are packets with a broken sync byte but it's less than 1%%.\n");
                    219:                       if (quality > 0)
                    220:                         quality = 0;
                    221:                     }
                    222:                   else if (broken_sync_cnt > packet_cnt / 10)
                    223:                     {
                    224:                       printf ("More than 10%% of the packets have a broken sync byte.\n");
                    225:                       quality = -2;
                    226:                     }
                    227:                   else
                    228:                     {
                    229:                       printf ("More than 1%% of the packets have a broken sync byte.\n");
                    230:                       if (quality > -1)
                    231:                         quality = -1;
                    232:                     }
                    233:                 }
                    234: 
                    235:               if (broken_alen_cnt > 0)
                    236:                 {
                    237:                   if (broken_alen_cnt == 0)
                    238:                     {
                    239:                       printf ("All packets with a correct sync seem to have a consistent TS header.\n");
                    240:                     }
                    241:                   else if (broken_alen_cnt < packet_cnt / 100)
                    242:                     {
                    243:                       printf ("There are packets with an inconsistent TS header but it's less than 1%%.\n");
                    244:                       if (quality > 0)
                    245:                         quality = 0;
                    246:                     }
                    247:                   else if (broken_alen_cnt > packet_cnt / 10)
                    248:                     {
                    249:                       printf ("More than 10%% of the packets have an inconsistent TS header.\n");
                    250:                       quality = -2;
                    251:                     }
                    252:                   else
                    253:                     {
                    254:                       printf ("More than 1%% of the packets have an inconsistent TS header.\n");
                    255:                       if (quality > -1)
                    256:                         quality = -1;
                    257:                     }
                    258:                 }
                    259: 
                    260:               if (quality == 1)
                    261:                 {
                    262:                   printf ("This transport stream seems to be ok.\n");
                    263:                 }
                    264:               else if (quality == 0)
                    265:                 {
                    266:                   printf ("This transport stream has some flaws, but it might be ok.\n");
                    267:                 }
                    268:               else if (quality == -1)
                    269:                 {
                    270:                   printf ("It is very likely, that this transport stream is broken.\n");
                    271:                   exit_value = 2;
                    272:                 }
                    273:               else
                    274:                 {
                    275:                   printf ("This transport stream is broken.\n");
                    276:                   exit_value = 3;
                    277:                 }
                    278:             }
                    279: 
                    280:           exit (exit_value);
1.1       jacob     281:         }
                    282: 
1.4       jacob     283:       packet_cnt++;
                    284: 
1.1       jacob     285:       // printf ("%02x%02x%02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3]);
                    286:       {
                    287:         int   sync;
                    288:         int   pid;
                    289:         int   cc;
1.2       oskar     290:         int   ccok;
1.1       jacob     291: 
1.4       jacob     292:         int   error_ind;
                    293:         int   unit_start;
                    294:         int   priority;
                    295:         int   scrambling;
                    296:         int   adaptation;
                    297: 
                    298:         int   alen = 0;
                    299:         int   real_alen = 0;
                    300: 
                    301:         int   disc = 0;
                    302:         int   random = 0;
                    303:         int   espri = 0;
                    304:         int   pcr = 0;
                    305:         int   opcr = 0;
                    306:         int   splpt = 0;
                    307:         int   priv = 0;
                    308:         int   afext = 0;
                    309: 
                    310:         int   priv_len = 0;
                    311:         int   afext_len = 0;
                    312: 
1.1       jacob     313:         char  outbuf[1];
                    314: 
                    315:         int   pidtype;
1.5     ! jacob     316:         int   togglec;
1.1       jacob     317: 
                    318:         sync = buffer[0];
1.4       jacob     319:         error_ind  = (buffer[1] & 0x80) >> 7;
                    320:         unit_start = (buffer[1] & 0x40) >> 6;
                    321:         priority   = (buffer[1] & 0x20) >> 5;
1.1       jacob     322:         pid  = ((buffer[1] & 0x1f) << 8) | buffer[2];
1.4       jacob     323:         scrambling  = (buffer[3] & 0x60) >> 6;
                    324:         adaptation  = (buffer[3] & 0x30) >> 4;
1.1       jacob     325:         cc   = buffer[3] & 0x0f;
                    326: 
1.4       jacob     327:         if (adaptation & 0x02)
                    328:           {
                    329:             alen = buffer[4];
                    330:             if (alen > 0)
                    331:               {
                    332:                 disc   = (buffer[5] & 0x80) >> 7;
                    333:                 random = (buffer[5] & 0x40) >> 6;
                    334:                 espri  = (buffer[5] & 0x20) >> 5;
                    335:                 pcr    = (buffer[5] & 0x10) >> 4;
                    336:                 opcr   = (buffer[5] & 0x08) >> 3;
                    337:                 splpt  = (buffer[5] & 0x04) >> 2;
                    338:                 priv   = (buffer[5] & 0x02) >> 1;
                    339:                 afext  = (buffer[5] & 0x01) >> 0;
                    340:               }
                    341:             real_alen += 1;
                    342: 
                    343:             if (pcr)
                    344:               real_alen += 6;
                    345: 
                    346:             if (opcr)
                    347:               real_alen += 6;
                    348: 
                    349:             if (priv)
                    350:               {
                    351:                 priv_len = buffer[5+real_alen];
                    352:                 real_alen += 1 + priv_len;
                    353:               }
                    354: 
                    355:             if (afext)
                    356:               {
                    357:                 afext_len = buffer[5+real_alen];
                    358:                 real_alen += 1 + afext_len;
                    359:               }
                    360:           }
                    361: 
1.1       jacob     362:         // fprintf (stderr, "pid = 0x%04x, cc = 0x%x\n", pid, cc);
                    363: 
                    364:         if (sync != 0x47)
                    365:           {
                    366:             // TODO, skip to next package
1.4       jacob     367:             if (show_packets)
                    368:               write (1, "?", 1);
                    369: 
                    370:             broken_sync_cnt++;
                    371:             goto char_written;
1.1       jacob     372:           }
1.4       jacob     373: 
                    374:         pidtype = pids[pid];
                    375: 
                    376:         if (pidtype == -1)
1.2       oskar     377:           {
1.4       jacob     378:             pid_cnt++;
1.1       jacob     379: 
1.4       jacob     380:             if (pid == 0)
1.1       jacob     381:               {
1.4       jacob     382:                 fprintf (stderr, "# =  pid 0x0000 (PAT)\n");
                    383:                 pidtype = pids[pid] = 0;
                    384:               }
                    385:             else if (pid == 0x1fff)
                    386:               {
                    387:                 fprintf (stderr, "\" '  pid 0x1fff (invalid)\n");
                    388:                 pidtype = pids[pid] = 0;
1.1       jacob     389:               }
1.2       oskar     390:             else
1.1       jacob     391:               {
1.4       jacob     392:                 if (pid_count < 26)
                    393:                   pid_count++;
                    394: 
                    395:                 pidtype = pids[pid] = pid_count;
                    396: 
                    397:                 if (show_pids)
                    398:                   fprintf (stderr, "%c %c  pid 0x%04x  "
                    399:                            "%s%s%s%s%s%s%s%s%s%s%s%salen=%d\n",
                    400:                            0x40 + pidtype, 0x60 + pidtype,  pid,
                    401:                            priority ? "pri, " : "",
                    402:                            adaptation & 0x02 ? "adapt, " : "",
                    403:                            adaptation & 0x01 ? "payld, " : "",
                    404:                            scrambling > 0 ? "scrmb, " : "",
                    405:                            disc > 0 ? "disc, " : "",
                    406:                            random > 0 ? "rnd, " : "",
                    407:                            espri > 0 ? "ESpri, " : "",
                    408:                            pcr > 0 ? "PCR, " : "",
                    409:                            opcr > 0 ? "OPCR, " : "",
                    410:                            splpt > 0 ? "splpt, " : "",
                    411:                            priv > 0 ? "priv, " : "",
                    412:                            afext > 0 ? "afext, " : "",
                    413:                            alen
                    414:                           );
                    415:               }
                    416: 
                    417:             if ((adaptation == 1 && alen != 0) ||
                    418:                 (adaptation == 2 && alen != 183) ||
                    419:                 (adaptation == 3 && alen >= 183))
                    420:               {
                    421:                 fprintf (stderr, "!!! pid 0x%04x: invalid adaptation_field_length %d\n",
                    422:                          pid, alen);
1.1       jacob     423:               }
1.2       oskar     424: 
1.4       jacob     425:             if ((adaptation & 2) != 0 && real_alen > alen )
                    426:               {
                    427:                 fprintf (stderr, "!!! pid 0x%04x: adaptation field to long %d > %d\n",
                    428:                          pid, real_alen, alen);
                    429:               }
                    430: 
                    431:             ccok = 1;
                    432:           }
                    433:         else
                    434:           {
                    435:             ccok = ccs[pid] == cc ? 1 : 0;
                    436:           }
                    437: 
                    438:         if (!ccok)
                    439:           unusual_cc_cnt++;
                    440: 
                    441:         if ((adaptation == 0x01 && alen != 0) ||
                    442:             (adaptation == 0x10 && alen != 183) ||
                    443:             (adaptation == 0x11 && alen >= 183) ||
                    444:             (alen < real_alen))
                    445:           {
                    446:             if (show_packets)
                    447:               write (1, "@", 1);
1.1       jacob     448: 
1.4       jacob     449:             broken_alen_cnt++;
                    450:             goto char_written;
1.1       jacob     451:           }
                    452: 
1.5     ! jacob     453:         if (show_cc_jumps)
        !           454:           togglec = !ccok;
        !           455:         else if (show_pcr)
        !           456:           togglec = pcr;
        !           457:         else if (show_start)
        !           458:           togglec = unit_start;
        !           459:         else
        !           460:           togglec = 0;
        !           461: 
1.4       jacob     462:         if (pid == 0)
1.5     ! jacob     463:           outbuf[0] = togglec ? '#' : '=';
1.4       jacob     464:         else if (pid == 0x1fff)
1.5     ! jacob     465:           outbuf[0] = togglec ? '"' : '\'';
1.4       jacob     466:         else
1.5     ! jacob     467:           outbuf[0] = 0x40 + pidtype + (togglec ? 0 : 0x20);
1.4       jacob     468: 
                    469:         ccs[pid] = (cc + 1) & 0x0F;
                    470: 
                    471:         if (show_packets)
                    472:           write (1, outbuf, 1);
                    473: 
                    474: char_written:
1.1       jacob     475:         count++;
1.4       jacob     476:         if ((count % 64) == 0 && show_packets)
1.1       jacob     477:           write (1, "\n", 1);
                    478:       }
                    479:     }
                    480: }

LinuxTV legacy CVS <linuxtv.org/cvs>