Annotation of multiplexer/showts.c, revision 1.4
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'},
! 43: {NULL, 0, NULL, 0}
! 44: };
! 45:
! 46: static const char *program = NULL;
! 47:
! 48: static int show_analysis = 0;
! 49: static int show_summary = 0;
! 50: static int show_packets = 1;
! 51: static int show_pids = 1;
! 52:
! 53: static int pid_cnt = 0;
! 54: static int packet_cnt = 0;
! 55: static int broken_sync_cnt = 0;
! 56: static int broken_alen_cnt = 0;
! 57: static int unusual_cc_cnt = 0;
! 58:
! 59: static void usage ()
! 60: {
! 61: printf("Usage: %s [OPTION] < <TS file>\n"
! 62: " -h, --help show usage\n"
! 63: " -s, --summary show summary\n"
! 64: " -a, --analyse analyse stream statistics\n"
! 65: , program);
! 66: }
! 67:
! 68:
1.1 jacob 69: int main (int argc, char **argv)
70: {
71:
1.4 ! jacob 72: int pids[MAXPID+1];
! 73: int ccs[MAXPID+1];
! 74: int pid_count = 0;
! 75: int i;
! 76: int count = 0;
! 77:
! 78: char **next_arg = argv+1;
! 79: int option_index = 0;
! 80:
! 81: if ((program = strrchr(argv[0], '/')) != NULL) {
! 82: program++;
! 83: } else {
! 84: program = argv[0];
! 85: }
! 86:
! 87: while (1) {
! 88: int opt;
! 89: // char *endptr;
! 90:
! 91: opt = getopt_long (argc, argv, "+hsa", long_options, &option_index);
! 92: if (opt == -1) break;
! 93:
! 94: switch (opt) {
! 95: case 'a':
! 96: show_analysis = 1;
! 97: show_packets = 0;
! 98: break;
! 99:
! 100: case 's':
! 101: show_summary = 1;
! 102: show_packets = 0;
! 103: break;
! 104:
! 105: case 'h':
! 106: usage ();
! 107: exit (0);
! 108:
! 109: default:
! 110: usage ();
! 111: exit (1);
! 112: }
! 113: }
! 114:
! 115: next_arg = argv + optind;
1.1 jacob 116:
117: for (i = 0; i <= MAXPID; i++)
1.2 oskar 118: {
119: pids[i] = -1;
120: ccs[i] = -1;
121: }
1.1 jacob 122:
123: while (1)
124: {
125: unsigned char buffer[188];
126: int bytes_read;
127:
128: int n;
129:
130:
131: bytes_read = 0;
132:
1.4 ! jacob 133: do
1.1 jacob 134: {
135: n = read (0, buffer + bytes_read, sizeof (buffer) - bytes_read);
136:
137: if (n < 0)
138: {
1.4 ! jacob 139: if (errno == EINTR)
! 140: continue;
! 141:
1.1 jacob 142: perror ("read");
143: exit (1);
144: }
145:
146: bytes_read += n;
147: }
148: while (bytes_read < sizeof (buffer) && n > 0);
149:
150: if (n == 0)
151: {
1.4 ! jacob 152: int exit_value = 0;
! 153:
1.1 jacob 154: if (bytes_read && bytes_read < sizeof (buffer))
155: {
156: fprintf (stderr, "incomplete ts packet read, size = %d\n", bytes_read);
157: }
1.4 ! jacob 158:
! 159: if (show_summary)
! 160: {
! 161: printf ("packets: %-6d\n", packet_cnt);
! 162: printf ("pids: %-6d\n", pid_cnt);
! 163: printf ("sync errors: %-6d\n",
! 164: broken_sync_cnt);
! 165: printf ("adaptation field length errors: %-6d\n",
! 166: broken_alen_cnt);
! 167: printf ("unusual cc increments: %-6d\n",
! 168: unusual_cc_cnt);
! 169: printf ("\n");
! 170: }
! 171:
! 172: if (show_analysis)
! 173: {
! 174: int quality = 1;
! 175:
! 176: if (pid_cnt > packet_cnt / 10)
! 177: {
! 178: printf ("The number of different PIDs is higher than 10%% of the packet count.\n");
! 179: quality = -1;
! 180: }
! 181: else if (pid_cnt > packet_cnt / 100)
! 182: {
! 183: printf ("The number of different PIDs is higher than 1%% of the packet count.\n");
! 184: if (quality > 0)
! 185: quality = 0;
! 186: }
! 187:
! 188: if (pid_cnt > 2048)
! 189: {
! 190: printf ("The number of different PIDs is higher than 2048.\n");
! 191: quality = -1;
! 192: }
! 193:
! 194: if (broken_sync_cnt > 0)
! 195: {
! 196: if (broken_sync_cnt < packet_cnt / 100)
! 197: {
! 198: printf ("There are packets with a broken sync byte but it's less than 1%%.\n");
! 199: if (quality > 0)
! 200: quality = 0;
! 201: }
! 202: else if (broken_sync_cnt > packet_cnt / 10)
! 203: {
! 204: printf ("More than 10%% of the packets have a broken sync byte.\n");
! 205: quality = -2;
! 206: }
! 207: else
! 208: {
! 209: printf ("More than 1%% of the packets have a broken sync byte.\n");
! 210: if (quality > -1)
! 211: quality = -1;
! 212: }
! 213: }
! 214:
! 215: if (broken_alen_cnt > 0)
! 216: {
! 217: if (broken_alen_cnt == 0)
! 218: {
! 219: printf ("All packets with a correct sync seem to have a consistent TS header.\n");
! 220: }
! 221: else if (broken_alen_cnt < packet_cnt / 100)
! 222: {
! 223: printf ("There are packets with an inconsistent TS header but it's less than 1%%.\n");
! 224: if (quality > 0)
! 225: quality = 0;
! 226: }
! 227: else if (broken_alen_cnt > packet_cnt / 10)
! 228: {
! 229: printf ("More than 10%% of the packets have an inconsistent TS header.\n");
! 230: quality = -2;
! 231: }
! 232: else
! 233: {
! 234: printf ("More than 1%% of the packets have an inconsistent TS header.\n");
! 235: if (quality > -1)
! 236: quality = -1;
! 237: }
! 238: }
! 239:
! 240: if (quality == 1)
! 241: {
! 242: printf ("This transport stream seems to be ok.\n");
! 243: }
! 244: else if (quality == 0)
! 245: {
! 246: printf ("This transport stream has some flaws, but it might be ok.\n");
! 247: }
! 248: else if (quality == -1)
! 249: {
! 250: printf ("It is very likely, that this transport stream is broken.\n");
! 251: exit_value = 2;
! 252: }
! 253: else
! 254: {
! 255: printf ("This transport stream is broken.\n");
! 256: exit_value = 3;
! 257: }
! 258: }
! 259:
! 260: exit (exit_value);
1.1 jacob 261: }
262:
1.4 ! jacob 263: packet_cnt++;
! 264:
1.1 jacob 265: // printf ("%02x%02x%02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3]);
266: {
267: int sync;
268: int pid;
269: int cc;
1.2 oskar 270: int ccok;
1.1 jacob 271:
1.4 ! jacob 272: int error_ind;
! 273: int unit_start;
! 274: int priority;
! 275: int scrambling;
! 276: int adaptation;
! 277:
! 278: int alen = 0;
! 279: int real_alen = 0;
! 280:
! 281: int disc = 0;
! 282: int random = 0;
! 283: int espri = 0;
! 284: int pcr = 0;
! 285: int opcr = 0;
! 286: int splpt = 0;
! 287: int priv = 0;
! 288: int afext = 0;
! 289:
! 290: int priv_len = 0;
! 291: int afext_len = 0;
! 292:
1.1 jacob 293: char outbuf[1];
294:
295: int pidtype;
296:
297: sync = buffer[0];
1.4 ! jacob 298: error_ind = (buffer[1] & 0x80) >> 7;
! 299: unit_start = (buffer[1] & 0x40) >> 6;
! 300: priority = (buffer[1] & 0x20) >> 5;
1.1 jacob 301: pid = ((buffer[1] & 0x1f) << 8) | buffer[2];
1.4 ! jacob 302: scrambling = (buffer[3] & 0x60) >> 6;
! 303: adaptation = (buffer[3] & 0x30) >> 4;
1.1 jacob 304: cc = buffer[3] & 0x0f;
305:
1.4 ! jacob 306: if (adaptation & 0x02)
! 307: {
! 308: alen = buffer[4];
! 309: if (alen > 0)
! 310: {
! 311: disc = (buffer[5] & 0x80) >> 7;
! 312: random = (buffer[5] & 0x40) >> 6;
! 313: espri = (buffer[5] & 0x20) >> 5;
! 314: pcr = (buffer[5] & 0x10) >> 4;
! 315: opcr = (buffer[5] & 0x08) >> 3;
! 316: splpt = (buffer[5] & 0x04) >> 2;
! 317: priv = (buffer[5] & 0x02) >> 1;
! 318: afext = (buffer[5] & 0x01) >> 0;
! 319: }
! 320: real_alen += 1;
! 321:
! 322: if (pcr)
! 323: real_alen += 6;
! 324:
! 325: if (opcr)
! 326: real_alen += 6;
! 327:
! 328: if (priv)
! 329: {
! 330: priv_len = buffer[5+real_alen];
! 331: real_alen += 1 + priv_len;
! 332: }
! 333:
! 334: if (afext)
! 335: {
! 336: afext_len = buffer[5+real_alen];
! 337: real_alen += 1 + afext_len;
! 338: }
! 339: }
! 340:
1.1 jacob 341: // fprintf (stderr, "pid = 0x%04x, cc = 0x%x\n", pid, cc);
342:
343: if (sync != 0x47)
344: {
345: // TODO, skip to next package
1.4 ! jacob 346: if (show_packets)
! 347: write (1, "?", 1);
! 348:
! 349: broken_sync_cnt++;
! 350: goto char_written;
1.1 jacob 351: }
1.4 ! jacob 352:
! 353: pidtype = pids[pid];
! 354:
! 355: if (pidtype == -1)
1.2 oskar 356: {
1.4 ! jacob 357: pid_cnt++;
1.1 jacob 358:
1.4 ! jacob 359: if (pid == 0)
1.1 jacob 360: {
1.4 ! jacob 361: fprintf (stderr, "# = pid 0x0000 (PAT)\n");
! 362: pidtype = pids[pid] = 0;
! 363: }
! 364: else if (pid == 0x1fff)
! 365: {
! 366: fprintf (stderr, "\" ' pid 0x1fff (invalid)\n");
! 367: pidtype = pids[pid] = 0;
1.1 jacob 368: }
1.2 oskar 369: else
1.1 jacob 370: {
1.4 ! jacob 371: if (pid_count < 26)
! 372: pid_count++;
! 373:
! 374: pidtype = pids[pid] = pid_count;
! 375:
! 376: if (show_pids)
! 377: fprintf (stderr, "%c %c pid 0x%04x "
! 378: "%s%s%s%s%s%s%s%s%s%s%s%salen=%d\n",
! 379: 0x40 + pidtype, 0x60 + pidtype, pid,
! 380: priority ? "pri, " : "",
! 381: adaptation & 0x02 ? "adapt, " : "",
! 382: adaptation & 0x01 ? "payld, " : "",
! 383: scrambling > 0 ? "scrmb, " : "",
! 384: disc > 0 ? "disc, " : "",
! 385: random > 0 ? "rnd, " : "",
! 386: espri > 0 ? "ESpri, " : "",
! 387: pcr > 0 ? "PCR, " : "",
! 388: opcr > 0 ? "OPCR, " : "",
! 389: splpt > 0 ? "splpt, " : "",
! 390: priv > 0 ? "priv, " : "",
! 391: afext > 0 ? "afext, " : "",
! 392: alen
! 393: );
! 394: }
! 395:
! 396: if ((adaptation == 1 && alen != 0) ||
! 397: (adaptation == 2 && alen != 183) ||
! 398: (adaptation == 3 && alen >= 183))
! 399: {
! 400: fprintf (stderr, "!!! pid 0x%04x: invalid adaptation_field_length %d\n",
! 401: pid, alen);
1.1 jacob 402: }
1.2 oskar 403:
1.4 ! jacob 404: if ((adaptation & 2) != 0 && real_alen > alen )
! 405: {
! 406: fprintf (stderr, "!!! pid 0x%04x: adaptation field to long %d > %d\n",
! 407: pid, real_alen, alen);
! 408: }
! 409:
! 410: ccok = 1;
! 411: }
! 412: else
! 413: {
! 414: ccok = ccs[pid] == cc ? 1 : 0;
! 415: }
! 416:
! 417: if (!ccok)
! 418: unusual_cc_cnt++;
! 419:
! 420: if ((adaptation == 0x01 && alen != 0) ||
! 421: (adaptation == 0x10 && alen != 183) ||
! 422: (adaptation == 0x11 && alen >= 183) ||
! 423: (alen < real_alen))
! 424: {
! 425: if (show_packets)
! 426: write (1, "@", 1);
1.1 jacob 427:
1.4 ! jacob 428: broken_alen_cnt++;
! 429: goto char_written;
1.1 jacob 430: }
431:
1.4 ! jacob 432: if (pid == 0)
! 433: outbuf[0] = ccok ? '=' : '#';
! 434: else if (pid == 0x1fff)
! 435: outbuf[0] = ccok ? '\'' : '"';
! 436: else
! 437: outbuf[0] = 0x40 + pidtype + (ccok ? 0x20 : 0);
! 438:
! 439: ccs[pid] = (cc + 1) & 0x0F;
! 440:
! 441: if (show_packets)
! 442: write (1, outbuf, 1);
! 443:
! 444: char_written:
1.1 jacob 445: count++;
1.4 ! jacob 446: if ((count % 64) == 0 && show_packets)
1.1 jacob 447: write (1, "\n", 1);
448: }
449: }
450: }
LinuxTV legacy CVS <linuxtv.org/cvs>