File:
[DVB] /
multiplexer /
showts.c
Revision
1.5:
download - view:
text,
annotated -
select for diffs
Tue Jan 27 19:46:07 2004 UTC (20 years, 3 months ago) by
jacob
Branches:
MAIN
CVS tags:
version-1-1-7,
version-1-1-6,
version-1-1-5,
version-1-1-4,
version-1-1-3,
version-1-1-2,
version-1-1-1,
version-1-1-0,
version-1-0-8,
version-1-0-7,
version-1-0-6,
version-1-0-5,
version-1-0-4,
version-1-0-3,
version-1-0-2,
HEAD
- added --pcr and --start options to indicate packets with PCR rsp. unit start
flag.
/*
* tiny debugging tool.
* when fed with a transport stream to stdin, produces one char
* per packet to stdout, and a few informative messages to stderr.
* Upper case letters denote a continuity counter mismatch.
*
* Author: Jacob Schroeder (jacob@convergence.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#define MAXPID 0x1fff
static struct option long_options[] = {
{"help" , 0, NULL, 'h'},
{"summary", 0, NULL, 's'},
{"analyse", 0, NULL, 'a'},
{"pcr" , 0, NULL, 'P'},
{"start", 0, NULL, 'S'},
{NULL, 0, NULL, 0}
};
static const char *program = NULL;
static int show_analysis = 0;
static int show_summary = 0;
static int show_packets = 1;
static int show_pids = 1;
static int show_cc_jumps = 1;
static int show_pcr = 0;
static int show_start = 0;
static int pid_cnt = 0;
static int packet_cnt = 0;
static int broken_sync_cnt = 0;
static int broken_alen_cnt = 0;
static int unusual_cc_cnt = 0;
static void usage ()
{
printf("Usage: %s [OPTION] < <TS file>\n"
" -h, --help show usage\n"
" -s, --summary show summary\n"
" -a, --analyse analyse stream statistics\n"
" -P, --pcr indicate PCR\n"
" -S, --start indicate unit start\n"
, program);
}
int main (int argc, char **argv)
{
int pids[MAXPID+1];
int ccs[MAXPID+1];
int pid_count = 0;
int i;
int count = 0;
char **next_arg = argv+1;
int option_index = 0;
if ((program = strrchr(argv[0], '/')) != NULL) {
program++;
} else {
program = argv[0];
}
while (1) {
int opt;
// char *endptr;
opt = getopt_long (argc, argv, "+hsPSa", long_options, &option_index);
if (opt == -1) break;
switch (opt) {
case 'a':
show_analysis = 1;
show_packets = 0;
break;
case 's':
show_summary = 1;
show_packets = 0;
break;
case 'S':
show_cc_jumps = 0;
show_start = 1;
show_pcr = 0;
break;
case 'P':
show_cc_jumps = 0;
show_start = 0;
show_pcr = 1;
break;
case 'h':
usage ();
exit (0);
default:
usage ();
exit (1);
}
}
next_arg = argv + optind;
for (i = 0; i <= MAXPID; i++)
{
pids[i] = -1;
ccs[i] = -1;
}
while (1)
{
unsigned char buffer[188];
int bytes_read;
int n;
bytes_read = 0;
do
{
n = read (0, buffer + bytes_read, sizeof (buffer) - bytes_read);
if (n < 0)
{
if (errno == EINTR)
continue;
perror ("read");
exit (1);
}
bytes_read += n;
}
while (bytes_read < sizeof (buffer) && n > 0);
if (n == 0)
{
int exit_value = 0;
if (bytes_read && bytes_read < sizeof (buffer))
{
fprintf (stderr, "incomplete ts packet read, size = %d\n", bytes_read);
}
if (show_summary)
{
printf ("packets: %-6d\n", packet_cnt);
printf ("pids: %-6d\n", pid_cnt);
printf ("sync errors: %-6d\n",
broken_sync_cnt);
printf ("adaptation field length errors: %-6d\n",
broken_alen_cnt);
printf ("unusual cc increments: %-6d\n",
unusual_cc_cnt);
printf ("\n");
}
if (show_analysis)
{
int quality = 1;
if (pid_cnt > packet_cnt / 10)
{
printf ("The number of different PIDs is higher than 10%% of the packet count.\n");
quality = -1;
}
else if (pid_cnt > packet_cnt / 100)
{
printf ("The number of different PIDs is higher than 1%% of the packet count.\n");
if (quality > 0)
quality = 0;
}
if (pid_cnt > 2048)
{
printf ("The number of different PIDs is higher than 2048.\n");
quality = -1;
}
if (broken_sync_cnt > 0)
{
if (broken_sync_cnt < packet_cnt / 100)
{
printf ("There are packets with a broken sync byte but it's less than 1%%.\n");
if (quality > 0)
quality = 0;
}
else if (broken_sync_cnt > packet_cnt / 10)
{
printf ("More than 10%% of the packets have a broken sync byte.\n");
quality = -2;
}
else
{
printf ("More than 1%% of the packets have a broken sync byte.\n");
if (quality > -1)
quality = -1;
}
}
if (broken_alen_cnt > 0)
{
if (broken_alen_cnt == 0)
{
printf ("All packets with a correct sync seem to have a consistent TS header.\n");
}
else if (broken_alen_cnt < packet_cnt / 100)
{
printf ("There are packets with an inconsistent TS header but it's less than 1%%.\n");
if (quality > 0)
quality = 0;
}
else if (broken_alen_cnt > packet_cnt / 10)
{
printf ("More than 10%% of the packets have an inconsistent TS header.\n");
quality = -2;
}
else
{
printf ("More than 1%% of the packets have an inconsistent TS header.\n");
if (quality > -1)
quality = -1;
}
}
if (quality == 1)
{
printf ("This transport stream seems to be ok.\n");
}
else if (quality == 0)
{
printf ("This transport stream has some flaws, but it might be ok.\n");
}
else if (quality == -1)
{
printf ("It is very likely, that this transport stream is broken.\n");
exit_value = 2;
}
else
{
printf ("This transport stream is broken.\n");
exit_value = 3;
}
}
exit (exit_value);
}
packet_cnt++;
// printf ("%02x%02x%02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3]);
{
int sync;
int pid;
int cc;
int ccok;
int error_ind;
int unit_start;
int priority;
int scrambling;
int adaptation;
int alen = 0;
int real_alen = 0;
int disc = 0;
int random = 0;
int espri = 0;
int pcr = 0;
int opcr = 0;
int splpt = 0;
int priv = 0;
int afext = 0;
int priv_len = 0;
int afext_len = 0;
char outbuf[1];
int pidtype;
int togglec;
sync = buffer[0];
error_ind = (buffer[1] & 0x80) >> 7;
unit_start = (buffer[1] & 0x40) >> 6;
priority = (buffer[1] & 0x20) >> 5;
pid = ((buffer[1] & 0x1f) << 8) | buffer[2];
scrambling = (buffer[3] & 0x60) >> 6;
adaptation = (buffer[3] & 0x30) >> 4;
cc = buffer[3] & 0x0f;
if (adaptation & 0x02)
{
alen = buffer[4];
if (alen > 0)
{
disc = (buffer[5] & 0x80) >> 7;
random = (buffer[5] & 0x40) >> 6;
espri = (buffer[5] & 0x20) >> 5;
pcr = (buffer[5] & 0x10) >> 4;
opcr = (buffer[5] & 0x08) >> 3;
splpt = (buffer[5] & 0x04) >> 2;
priv = (buffer[5] & 0x02) >> 1;
afext = (buffer[5] & 0x01) >> 0;
}
real_alen += 1;
if (pcr)
real_alen += 6;
if (opcr)
real_alen += 6;
if (priv)
{
priv_len = buffer[5+real_alen];
real_alen += 1 + priv_len;
}
if (afext)
{
afext_len = buffer[5+real_alen];
real_alen += 1 + afext_len;
}
}
// fprintf (stderr, "pid = 0x%04x, cc = 0x%x\n", pid, cc);
if (sync != 0x47)
{
// TODO, skip to next package
if (show_packets)
write (1, "?", 1);
broken_sync_cnt++;
goto char_written;
}
pidtype = pids[pid];
if (pidtype == -1)
{
pid_cnt++;
if (pid == 0)
{
fprintf (stderr, "# = pid 0x0000 (PAT)\n");
pidtype = pids[pid] = 0;
}
else if (pid == 0x1fff)
{
fprintf (stderr, "\" ' pid 0x1fff (invalid)\n");
pidtype = pids[pid] = 0;
}
else
{
if (pid_count < 26)
pid_count++;
pidtype = pids[pid] = pid_count;
if (show_pids)
fprintf (stderr, "%c %c pid 0x%04x "
"%s%s%s%s%s%s%s%s%s%s%s%salen=%d\n",
0x40 + pidtype, 0x60 + pidtype, pid,
priority ? "pri, " : "",
adaptation & 0x02 ? "adapt, " : "",
adaptation & 0x01 ? "payld, " : "",
scrambling > 0 ? "scrmb, " : "",
disc > 0 ? "disc, " : "",
random > 0 ? "rnd, " : "",
espri > 0 ? "ESpri, " : "",
pcr > 0 ? "PCR, " : "",
opcr > 0 ? "OPCR, " : "",
splpt > 0 ? "splpt, " : "",
priv > 0 ? "priv, " : "",
afext > 0 ? "afext, " : "",
alen
);
}
if ((adaptation == 1 && alen != 0) ||
(adaptation == 2 && alen != 183) ||
(adaptation == 3 && alen >= 183))
{
fprintf (stderr, "!!! pid 0x%04x: invalid adaptation_field_length %d\n",
pid, alen);
}
if ((adaptation & 2) != 0 && real_alen > alen )
{
fprintf (stderr, "!!! pid 0x%04x: adaptation field to long %d > %d\n",
pid, real_alen, alen);
}
ccok = 1;
}
else
{
ccok = ccs[pid] == cc ? 1 : 0;
}
if (!ccok)
unusual_cc_cnt++;
if ((adaptation == 0x01 && alen != 0) ||
(adaptation == 0x10 && alen != 183) ||
(adaptation == 0x11 && alen >= 183) ||
(alen < real_alen))
{
if (show_packets)
write (1, "@", 1);
broken_alen_cnt++;
goto char_written;
}
if (show_cc_jumps)
togglec = !ccok;
else if (show_pcr)
togglec = pcr;
else if (show_start)
togglec = unit_start;
else
togglec = 0;
if (pid == 0)
outbuf[0] = togglec ? '#' : '=';
else if (pid == 0x1fff)
outbuf[0] = togglec ? '"' : '\'';
else
outbuf[0] = 0x40 + pidtype + (togglec ? 0 : 0x20);
ccs[pid] = (cc + 1) & 0x0F;
if (show_packets)
write (1, outbuf, 1);
char_written:
count++;
if ((count % 64) == 0 && show_packets)
write (1, "\n", 1);
}
}
}
LinuxTV legacy CVS <linuxtv.org/cvs>