F5OEO-tstools/tsinfo.c

435 wiersze
12 KiB
C

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* Locate the PAT and PMT packets in an H.222 transport stream (TS),
* and report on their contents (i.e., the program and stream info).
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the MPEG TS, PS and ES tools.
*
* The Initial Developer of the Original Code is Amino Communications Ltd.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Amino Communications Ltd, Swavesey, Cambridge UK
*
* ***** END LICENSE BLOCK *****
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#ifdef _WIN32
#include <stddef.h>
#else // _WIN32
#include <unistd.h>
#endif // _WIN32
#include "compat.h"
#include "ts_fns.h"
#include "misc_fns.h"
#include "printing_fns.h"
#include "pidint_fns.h"
#include "version.h"
/*
* Report on the program streams, by looking at the PAT and PMT packets
* in the first `max` TS packets of the given input stream
*
* Returns 0 if all went well, 1 if something went wrong.
*/
static int report_streams(TS_reader_p tsreader,
int max,
int verbose)
{
int err;
int ii;
// TODO: Should really support multiple programs
// (some use of pidint_list to support program number -> PMT?)
pidint_list_p this_prog_list = NULL;
pidint_list_p last_prog_list = NULL;
pmt_p this_pmt = NULL;
pmt_p last_pmt = NULL;
uint32_t pmt_pid = 0; // which will get "masked" by the PAT pid
byte *pat_data = NULL;
int pat_data_len = 0;
int pat_data_used = 0;
byte *pmt_data = NULL;
int pmt_data_len = 0;
int pmt_data_used = 0;
int num_pats = 0;
int num_pmts = 0;
fprint_msg("Scanning %d TS packets\n",max);
for (ii=0; ii<max; ii++)
{
uint32_t pid;
int payload_unit_start_indicator;
byte *adapt, *payload;
int adapt_len, payload_len;
err = get_next_TS_packet(tsreader,&pid,
&payload_unit_start_indicator,
&adapt,&adapt_len,&payload,&payload_len);
if (err == EOF)
{
print_msg("EOF\n");
break;
}
else if (err)
{
fprint_err("### Error reading TS packet %d\n",ii+1);
if (pat_data) free(pat_data);
free_pidint_list(&last_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
return 1;
}
if (pid == 0x0000)
{
num_pats++;
if (verbose)
fprint_msg("Packet %d is PAT\n",ii+1);
if (payload_len == 0)
{
fprint_msg("Packet %d is PAT, but has no payload\n",ii+1);
continue;
}
if (payload_unit_start_indicator && pat_data)
{
// This is the start of a new PAT packet, but we'd already
// started one, so throw its data away
print_err("!!! Discarding previous (uncompleted) PAT data\n");
free(pat_data);
pat_data = NULL; pat_data_len = 0; pat_data_used = 0;
}
else if (!payload_unit_start_indicator && !pat_data)
{
// This is the continuation of a PAT packet, but we hadn't
// started one yet
print_err("!!! Discarding PAT continuation, no PAT started\n");
continue;
}
err = build_psi_data(verbose,payload,payload_len,pid,
&pat_data,&pat_data_len,&pat_data_used);
if (err)
{
fprint_err("### Error %s PAT\n",
(payload_unit_start_indicator?"starting new":"continuing"));
if (pat_data) free(pat_data);
free_pidint_list(&last_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
return 1;
}
// Do we need more data to complete this PAT?
if (pat_data_len > pat_data_used)
continue;
err = extract_prog_list_from_pat(verbose,pat_data,pat_data_len,
&this_prog_list);
if (err)
{
free_pidint_list(&last_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
free(pat_data);
return err;
}
free(pat_data);
pat_data = NULL; pat_data_len = 0; pat_data_used = 0;
num_pats++;
if (err)
{
free_pidint_list(&last_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
return err;
}
if (!same_pidint_list(this_prog_list,last_prog_list))
{
if (last_prog_list != NULL)
fprint_msg("\nPacket %d is PAT - content changed\n",ii+1);
else if (!verbose)
fprint_msg("\nPacket %d is PAT\n",ii+1);
report_pidint_list(this_prog_list,"Program list","Program",FALSE);
if (this_prog_list->length == 0)
fprint_msg("No programs defined in PAT (packet %d)\n",ii+1);
else
{
if (this_prog_list->length > 1)
fprint_msg("Multiple programs in PAT - using the first\n");
pmt_pid = this_prog_list->pid[0];
}
}
free_pidint_list(&last_prog_list);
last_prog_list = this_prog_list;
}
else if (pid == pmt_pid)
{
if (verbose)
fprint_msg("Packet %d is PMT with PID %04x (%d)%s\n",ii+1,pid,pid,
(payload_unit_start_indicator?"[pusi]":""));
if (payload_len == 0)
{
fprint_msg("Packet %d is PMT, but has no payload\n",ii+1);
continue;
}
if (payload_unit_start_indicator && pmt_data)
{
// This is the start of a new PMT packet, but we'd already
// started one, so throw its data away
print_err("!!! Discarding previous (uncompleted) PMT data\n");
free(pmt_data);
pmt_data = NULL; pmt_data_len = 0; pmt_data_used = 0;
}
else if (!payload_unit_start_indicator && !pmt_data)
{
// This is the continuation of a PMT packet, but we hadn't
// started one yet
print_err("!!! Discarding PMT continuation, no PMT started\n");
continue;
}
err = build_psi_data(verbose,payload,payload_len,pid,
&pmt_data,&pmt_data_len,&pmt_data_used);
if (err)
{
fprint_err("### Error %s PMT\n",
(payload_unit_start_indicator?"starting new":"continuing"));
free_pidint_list(&this_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
return 1;
}
// Do we need more data to complete this PMT?
if (pmt_data_len > pmt_data_used)
continue;
err = extract_pmt(verbose,pmt_data,pmt_data_len,pid,&this_pmt);
if (err)
{
free_pidint_list(&this_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
return err;
}
free(pmt_data);
pmt_data = NULL; pmt_data_len = 0; pmt_data_used = 0;
num_pmts++;
if (same_pmt(this_pmt,last_pmt)) // Nothing to do
{
free_pmt(&this_pmt);
continue;
}
if (last_pmt != NULL)
fprint_msg("\nPacket %d is PMT with PID %04x (%d)"
" - content changed\n",ii+1,pid,pid);
else if (!verbose)
fprint_msg("\nPacket %d is PMT with PID %04x (%d)\n",ii+1,pid,pid);
report_pmt(TRUE," ",this_pmt);
free_pmt(&last_pmt);
last_pmt = this_pmt;
}
}
fprint_msg("\nFound %d PAT packet%s and %d PMT packet%s in %d TS packets\n",
num_pats,(num_pats==1?"":"s"),
num_pmts,(num_pmts==1?"":"s"),max);
free_pidint_list(&last_prog_list);
free_pmt(&last_pmt);
if (pmt_data) free(pmt_data);
return 0;
}
static void print_usage()
{
print_msg(
"Usage: tsinfo [switches] [<infile>]\n"
"\n"
);
REPORT_VERSION("tsinfo");
print_msg(
"\n"
" Report on the program streams in a Transport Stream.\n"
"\n"
"Files:\n"
" <infile> is an H.222 Transport Stream file (but see -stdin)\n"
"\n"
"Switches:\n"
" -err stdout Write error messages to standard output (the default)\n"
" -err stderr Write error messages to standard error (Unix traditional)\n"
" -stdin Input from standard input, instead of a file\n"
" -verbose, -v Output extra information about packets\n"
" -max <n>, -m <n> Number of TS packets to scan. Defaults to 10000.\n"
" -repeat <n> Look for <n> PMT packets, and report on each\n"
);
}
int main(int argc, char **argv)
{
int use_stdin = FALSE;
char *input_name = NULL;
int had_input_name = FALSE;
int max = 10000;
int verbose = FALSE; // True => output diagnostic/progress messages
int lookfor = 1;
int err = 0;
TS_reader_p tsreader = NULL;
int ii = 1;
if (argc < 2)
{
print_usage();
return 0;
}
while (ii < argc)
{
if (argv[ii][0] == '-')
{
if (!strcmp("--help",argv[ii]) || !strcmp("-h",argv[ii]) ||
!strcmp("-help",argv[ii]))
{
print_usage();
return 0;
}
else if (!strcmp("-err",argv[ii]))
{
CHECKARG("tsinfo",ii);
if (!strcmp(argv[ii+1],"stderr"))
redirect_output_stderr();
else if (!strcmp(argv[ii+1],"stdout"))
redirect_output_stdout();
else
{
fprint_err("### tsinfo: "
"Unrecognised option '%s' to -err (not 'stdout' or"
" 'stderr')\n",argv[ii+1]);
return 1;
}
ii++;
}
else if (!strcmp("-verbose",argv[ii]) || !strcmp("-v",argv[ii]))
{
verbose = TRUE;
}
else if (!strcmp("-max",argv[ii]) || !strcmp("-m",argv[ii]))
{
CHECKARG("tsinfo",ii);
err = int_value("tsinfo",argv[ii],argv[ii+1],TRUE,10,&max);
if (err) return 1;
ii++;
}
else if (!strcmp("-repeat",argv[ii]))
{
CHECKARG("tsinfo",ii);
err = int_value("tsinfo",argv[ii],argv[ii+1],TRUE,10,&lookfor);
if (err) return 1;
ii++;
}
else if (!strcmp("-stdin",argv[ii]))
{
use_stdin = TRUE;
had_input_name = TRUE; // so to speak
}
else
{
fprint_err("### tsinfo: "
"Unrecognised command line switch '%s'\n",argv[ii]);
return 1;
}
}
else
{
if (had_input_name)
{
fprint_err("### tsinfo: Unexpected '%s'\n",argv[ii]);
return 1;
}
else
{
input_name = argv[ii];
had_input_name = TRUE;
}
}
ii++;
}
if (!had_input_name)
{
print_err("### tsinfo: No input file specified\n");
return 1;
}
err = open_file_for_TS_read((use_stdin?NULL:input_name),&tsreader);
if (err)
{
fprint_err("### tsinfo: Unable to open input file %s for reading TS\n",
use_stdin?"<stdin>":input_name);
return 1;
}
fprint_msg("Reading from %s\n",(use_stdin?"<stdin>":input_name));
err = report_streams(tsreader,max,verbose);
if (err)
{
print_err("### tsinfo: Error reporting on stream\n");
(void) close_TS_reader(&tsreader);
return 1;
}
err = close_TS_reader(&tsreader);
if (err) return 1;
return 0;
}
// Local Variables:
// tab-width: 8
// indent-tabs-mode: nil
// c-basic-offset: 2
// End:
// vim: set tabstop=8 shiftwidth=2 expandtab: