/*****************************************************************************
|
|
* section_demux.c: Prints sections from a TS file
|
|
*****************************************************************************
|
|
*****************************************************************************/
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <inttypes.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
#include <getopt.h>
|
|
|
|
#include <bitstream/mpeg/ts.h>
|
|
#include <bitstream/mpeg/psi.h>
|
|
#include <bitstream/dvb/si.h>
|
|
|
|
/*****************************************************************************
|
|
* Local declarations
|
|
*****************************************************************************/
|
|
#define MAX_PIDS 8192
|
|
#define READ_ONCE 7
|
|
|
|
typedef struct ts_pid_t {
|
|
int i_psi_refcount;
|
|
int8_t i_last_cc;
|
|
|
|
/* biTStream PSI section gathering */
|
|
uint8_t *p_psi_buffer;
|
|
uint16_t i_psi_buffer_used;
|
|
} ts_pid_t;
|
|
|
|
static ts_pid_t p_pids[MAX_PIDS];
|
|
|
|
static uint8_t i_want_table_id = 0;
|
|
static uint16_t i_want_pid = 0;
|
|
|
|
/*****************************************************************************
|
|
* handle_section
|
|
*****************************************************************************/
|
|
static void handle_section(uint16_t i_pid, uint8_t *p_section) {
|
|
uint8_t i_table_id = psi_get_tableid(p_section);
|
|
|
|
if (!psi_validate(p_section)) {
|
|
printf("invalid section on PID %hu\n", i_pid);
|
|
free(p_section);
|
|
return;
|
|
}
|
|
// if(i_table_id == i_want_table_id){
|
|
// printf("Wanted section: T<%02x>P<%04x> -> %02x %02x %02x %02x\n", i_table_id, i_pid, p_section[0], p_section[1],
|
|
// p_section[2], p_section[3]);
|
|
// }
|
|
if (i_pid == i_want_pid && i_table_id == i_want_table_id) {
|
|
// This is the section I want;
|
|
printf("Wanted section: T<%02x>P<%04x> -> %02x %02x %02x %02x\n", i_table_id, i_pid, p_section[0], p_section[1],
|
|
p_section[2], p_section[3]);
|
|
// Call SW_S32 Minitor_DataRevc(SW_U8 *data_p, SW_S8 slot,SW_U32 markid) here !!!
|
|
} else {
|
|
// printf("Ignored section: T<%02x>P<%04x> -> %02x %02x %02x %02x\n", i_table_id, i_pid, p_section[0], p_section[1],
|
|
// p_section[2], p_section[3]);
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* handle_psi_packet
|
|
*****************************************************************************/
|
|
static void handle_psi_packet(uint8_t *p_ts) {
|
|
uint16_t i_pid = ts_get_pid(p_ts);
|
|
ts_pid_t *p_pid = &p_pids[i_pid];
|
|
uint8_t i_cc = ts_get_cc(p_ts);
|
|
const uint8_t *p_payload;
|
|
uint8_t i_length;
|
|
|
|
// printf("handle_psi_packet:> %02x %02x %02x %02x\n",p_ts[0],p_ts[1],p_ts[2],p_ts[3]);
|
|
if (ts_check_duplicate(i_cc, p_pid->i_last_cc) || !ts_has_payload(p_ts))
|
|
return;
|
|
|
|
if (p_pid->i_last_cc != -1
|
|
&& ts_check_discontinuity(i_cc, p_pid->i_last_cc))
|
|
psi_assemble_reset(&p_pid->p_psi_buffer, &p_pid->i_psi_buffer_used);
|
|
|
|
p_payload = ts_section(p_ts);
|
|
i_length = p_ts + TS_SIZE - p_payload;
|
|
|
|
if (!psi_assemble_empty(&p_pid->p_psi_buffer, &p_pid->i_psi_buffer_used)) {
|
|
uint8_t *p_section = psi_assemble_payload(&p_pid->p_psi_buffer,
|
|
&p_pid->i_psi_buffer_used,
|
|
&p_payload, &i_length);
|
|
if (p_section != NULL) {
|
|
handle_section(i_pid, p_section);
|
|
}
|
|
|
|
}
|
|
|
|
p_payload = ts_next_section(p_ts);
|
|
i_length = p_ts + TS_SIZE - p_payload;
|
|
|
|
while (i_length) {
|
|
uint8_t *p_section = psi_assemble_payload(&p_pid->p_psi_buffer,
|
|
&p_pid->i_psi_buffer_used,
|
|
&p_payload, &i_length);
|
|
if (p_section != NULL)
|
|
handle_section(i_pid, p_section);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Main loop
|
|
*****************************************************************************/
|
|
static void usage(const char *psz) {
|
|
fprintf(stderr, "usage: %s < <input file> [> <output>]\n", psz);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
int main(int i_argc, char **ppsz_argv) {
|
|
int i, c;
|
|
i_want_pid = 0x0021;
|
|
i_want_table_id = 0xfe;
|
|
|
|
static const struct option long_options[] = {
|
|
{"table_id", required_argument, NULL, 't'},
|
|
{"pid", required_argument, NULL, 'p'},
|
|
{"help", no_argument, NULL, 'h'},
|
|
{"version", no_argument, NULL, 'V'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
while ((c = getopt_long(i_argc, ppsz_argv, "t:hVp:", long_options, NULL)) != -1) {
|
|
switch (c) {
|
|
case 't':
|
|
break;
|
|
case 'p':
|
|
break;
|
|
case 'V':
|
|
fprintf(stderr, "biTStream %d.%d.%d\n", BITSTREAM_VERSION_MAJOR,
|
|
BITSTREAM_VERSION_MINOR, BITSTREAM_VERSION_REVISION);
|
|
exit(0);
|
|
break;
|
|
|
|
|
|
case 'h':
|
|
default:
|
|
usage(ppsz_argv[0]);
|
|
}
|
|
}
|
|
if (optind < i_argc)
|
|
usage(ppsz_argv[0]);
|
|
|
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
|
|
|
memset(p_pids, 0, sizeof(p_pids));
|
|
|
|
for (i = 0; i < 8192; i++) {
|
|
p_pids[i].i_last_cc = -1;
|
|
psi_assemble_init(&p_pids[i].p_psi_buffer,
|
|
&p_pids[i].i_psi_buffer_used);
|
|
}
|
|
|
|
bool b_is_last_invalid = false;
|
|
while (!feof(stdin) && !ferror(stdin)) {
|
|
uint8_t p_ts[TS_SIZE];
|
|
size_t i_ret = fread(p_ts, sizeof(p_ts), 1, stdin);
|
|
if (i_ret != 1) continue;
|
|
if (!ts_validate(p_ts)) {
|
|
if (!b_is_last_invalid) {
|
|
printf("invalid TS packet\n");
|
|
b_is_last_invalid = true;
|
|
}
|
|
|
|
int i;
|
|
for (i = 1; i < TS_SIZE; i++) {
|
|
if (ts_validate(p_ts + i)) {
|
|
memmove(p_ts, p_ts + i, TS_SIZE - i);
|
|
i_ret = fread(p_ts + TS_SIZE - i, i, 1, stdin);
|
|
if (i_ret != 1) continue;
|
|
break;
|
|
}
|
|
}
|
|
if (i == TS_SIZE)
|
|
continue;
|
|
}
|
|
|
|
uint16_t i_pid = ts_get_pid(p_ts);
|
|
ts_pid_t *p_pid = &p_pids[i_pid];
|
|
// if (p_pid->i_psi_refcount)
|
|
handle_psi_packet(p_ts);
|
|
p_pid->i_last_cc = ts_get_cc(p_ts);
|
|
b_is_last_invalid = false;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|