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>