Commit 0403c639 authored by Christophe Massiot's avatar Christophe Massiot

* mpeg/psi.h: Fix a bug with descriptor 0x05. * mpeg/psi.h, dvb/si.h: Cosmetic...

* mpeg/psi.h: Fix a bug with descriptor 0x05. * mpeg/psi.h, dvb/si.h: Cosmetic changes in print functions. * examples/dvb_print_si.c: New example file to print DVB tables in a TS stream.
parent 088e84d9
......@@ -166,7 +166,7 @@ static inline void desc56_print(uint8_t *p_desc, f_print pf_print,
while ((p_desc_n = desc56_get_language(p_desc, j)) != NULL) {
j++;
pf_print(opaque,
" - desc 56 telx language=%3.3s type=%hhu mag=%hhu page=%hhu",
" - desc 56 telx language=%3.3s type=0x%hhx mag=%hhu page=%hhu",
(const char *)desc56n_get_code(p_desc_n),
desc56n_get_teletexttype(p_desc_n),
desc56n_get_teletextmagazine(p_desc_n),
......@@ -239,7 +239,7 @@ static inline void desc59_print(uint8_t *p_desc, f_print pf_print,
while ((p_desc_n = desc59_get_language(p_desc, j)) != NULL) {
j++;
pf_print(opaque,
" - desc 59 dvbs language=%3.3s type=%hhu composition=%hu ancillary=%hu",
" - desc 59 dvbs language=%3.3s type=0x%hhx composition=%hu ancillary=%hu",
(const char *)desc59n_get_code(p_desc_n),
desc59n_get_subtitlingtype(p_desc_n),
desc59n_get_compositionpage(p_desc_n),
......
# $Id$
CFLAGS = -Wall -O2
LDFLAGS =
OBJ = dvb_print_si
all: $(OBJ)
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
-rm $(OBJ)
/*****************************************************************************
* dvb_print_si.c: Prints tables from a TS file
*****************************************************************************
* Copyright (C) 2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <bitstream/mpeg/ts.h>
#include <bitstream/mpeg/psi.h>
#include <bitstream/dvb/si.h>
#include <bitstream/mpeg/psi_print.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;
typedef struct sid_t {
uint16_t i_sid, i_pmt_pid;
uint8_t *p_current_pmt;
} sid_t;
ts_pid_t p_pids[MAX_PIDS];
static sid_t **pp_sids = NULL;
static int i_nb_sids = 0;
static PSI_TABLE_DECLARE(pp_current_pat_sections);
static PSI_TABLE_DECLARE(pp_next_pat_sections);
static PSI_TABLE_DECLARE(pp_current_nit_sections);
static PSI_TABLE_DECLARE(pp_next_nit_sections);
static PSI_TABLE_DECLARE(pp_current_sdt_sections);
static PSI_TABLE_DECLARE(pp_next_sdt_sections);
/*****************************************************************************
* print
*****************************************************************************/
static void print(void *_unused, const char *psz_format, ...)
{
char psz_fmt[strlen(psz_format) + 2];
va_list args;
va_start(args, psz_format);
strcpy(psz_fmt, psz_format);
strcat(psz_fmt, "\n");
vprintf(psz_fmt, args);
}
/*****************************************************************************
* handle_pat
*****************************************************************************/
static void handle_pat(void)
{
PSI_TABLE_DECLARE(pp_old_pat_sections);
uint8_t i_last_section = psi_table_get_lastsection(pp_next_pat_sections);
uint8_t i;
if (psi_table_validate(pp_current_pat_sections) &&
psi_table_get_version(pp_current_pat_sections)
== psi_table_get_version(pp_next_pat_sections)) {
/* Same version PAT. Shortcut. */
psi_table_free(pp_next_pat_sections);
psi_table_init(pp_next_pat_sections);
return;
}
if (!pat_table_validate(pp_next_pat_sections)) {
printf("invalid PAT received");
psi_table_free(pp_next_pat_sections);
psi_table_init(pp_next_pat_sections);
return;
}
/* Switch tables. */
psi_table_copy(pp_old_pat_sections, pp_current_pat_sections);
psi_table_copy(pp_current_pat_sections, pp_next_pat_sections);
psi_table_init(pp_next_pat_sections);
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_current_pat_sections, i);
const uint8_t *p_program;
int j = 0;
while ((p_program = pat_get_program(p_section, j)) != NULL) {
const uint8_t *p_old_program = NULL;
uint16_t i_sid = patn_get_program(p_program);
uint16_t i_pid = patn_get_pid(p_program);
j++;
if (i_sid == 0) {
if (i_pid != NIT_PID)
printf(
"NIT is carried on PID %hu which isn't DVB compliant",
i_pid);
continue; /* NIT */
}
if (!psi_table_validate(pp_old_pat_sections)
|| (p_old_program =
pat_table_find_program(pp_old_pat_sections, i_sid))
== NULL
|| patn_get_pid(p_old_program) != i_pid) {
sid_t *p_sid;
int i_pmt;
if (p_old_program != NULL)
p_pids[patn_get_pid(p_old_program)].i_psi_refcount--;
p_pids[i_pid].i_psi_refcount++;
for (i_pmt = 0; i_pmt < i_nb_sids; i_pmt++)
if (pp_sids[i_pmt]->i_sid == i_sid ||
pp_sids[i_pmt]->i_sid == 0)
break;
if (i_pmt == i_nb_sids) {
p_sid = malloc(sizeof(sid_t));
pp_sids = realloc(pp_sids, ++i_nb_sids * sizeof(sid_t *));
pp_sids[i_pmt] = p_sid;
p_sid->p_current_pmt = NULL;
}
else
p_sid = pp_sids[i_pmt];
p_sid->i_sid = i_sid;
p_sid->i_pmt_pid = i_pid;
}
}
}
if (psi_table_validate(pp_old_pat_sections)) {
i_last_section = psi_table_get_lastsection( pp_old_pat_sections );
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_old_pat_sections, i);
const uint8_t *p_program;
int j = 0;
while ((p_program = pat_get_program(p_section, j)) != NULL) {
uint16_t i_sid = patn_get_program(p_program);
j++;
if (i_sid == 0)
continue; /* NIT */
if (pat_table_find_program(pp_current_pat_sections, i_sid)
== NULL) {
int i_pmt;
for (i_pmt = 0; i_pmt < i_nb_sids; i_pmt++)
if (pp_sids[i_pmt]->i_sid == i_sid) {
pp_sids[i_pmt]->i_sid = 0;
free(pp_sids[i_pmt]->p_current_pmt);
break;
}
}
}
}
psi_table_free(pp_old_pat_sections);
}
pat_table_print( pp_current_pat_sections, print, NULL );
}
static void handle_pat_section(uint16_t i_pid, uint8_t *p_section)
{
if (i_pid != PAT_PID || !pat_validate(p_section)) {
printf("invalid PAT section received on PID %hu", i_pid);
free(p_section);
return;
}
if (!psi_table_section(pp_next_pat_sections, p_section))
return;
handle_pat();
}
/*****************************************************************************
* handle_pmt
*****************************************************************************/
static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
{
uint16_t i_sid = pmt_get_program(p_pmt);
sid_t *p_sid;
int i;
/* we do this before checking the service ID */
if (!pmt_validate(p_pmt)) {
printf("invalid PMT section received on PID %hu", i_pid);
free(p_pmt);
return;
}
for (i = 0; i < i_nb_sids; i++)
if (pp_sids[i]->i_sid && pp_sids[i]->i_sid == i_sid)
break;
if (i == i_nb_sids) {
printf("ghost PMT for service %hu carried on PID %hu", i_sid, i_pid);
p_sid = malloc(sizeof(sid_t));
pp_sids = realloc(pp_sids, ++i_nb_sids * sizeof(sid_t *));
pp_sids[i] = p_sid;
p_sid->i_sid = i_sid;
p_sid->i_pmt_pid = i_pid;
p_sid->p_current_pmt = NULL;
} else {
p_sid = pp_sids[i];
if (i_pid != p_sid->i_pmt_pid)
printf("ghost PMT for service %hu carried on PID %hu", i_sid,
i_pid);
}
if (p_sid->p_current_pmt != NULL &&
psi_get_version(p_sid->p_current_pmt) == psi_get_version(p_pmt)) {
/* Same version PMT. Shortcut. */
free(p_pmt);
return;
}
free(p_sid->p_current_pmt);
p_sid->p_current_pmt = p_pmt;
pmt_print(p_pmt, print, NULL);
}
/*****************************************************************************
* handle_nit
*****************************************************************************/
static void handle_nit(void)
{
if (psi_table_validate(pp_current_nit_sections) &&
psi_table_get_version(pp_current_nit_sections)
== psi_table_get_version(pp_next_nit_sections)) {
/* Same version NIT. Shortcut. */
psi_table_free(pp_next_nit_sections);
psi_table_init(pp_next_nit_sections);
return;
}
if (!nit_table_validate(pp_next_nit_sections)) {
printf("invalid NIT received");
psi_table_free( pp_next_nit_sections );
psi_table_init( pp_next_nit_sections );
return;
}
/* Switch tables. */
psi_table_free(pp_current_nit_sections);
psi_table_copy(pp_current_nit_sections, pp_next_nit_sections);
psi_table_init(pp_next_nit_sections);
nit_table_print(pp_current_nit_sections, print, NULL);
}
static void handle_nit_section(uint16_t i_pid, uint8_t *p_section)
{
if (i_pid != NIT_PID || !nit_validate(p_section)) {
printf("invalid NIT section received on PID %hu", i_pid);
free(p_section);
return;
}
if (!psi_table_section(pp_next_nit_sections, p_section))
return;
handle_nit();
}
/*****************************************************************************
* handle_sdt
*****************************************************************************/
static void handle_sdt(void)
{
if (psi_table_validate(pp_current_sdt_sections) &&
psi_table_get_version(pp_current_sdt_sections)
== psi_table_get_version(pp_next_sdt_sections)) {
/* Same version SDT. Shortcut. */
psi_table_free(pp_next_sdt_sections);
psi_table_init(pp_next_sdt_sections);
return;
}
if (!sdt_table_validate(pp_next_sdt_sections)) {
printf("invalid SDT received");
psi_table_free(pp_next_sdt_sections);
psi_table_init(pp_next_sdt_sections);
return;
}
/* Switch tables. */
psi_table_free(pp_current_sdt_sections);
psi_table_copy(pp_current_sdt_sections, pp_next_sdt_sections);
psi_table_init(pp_next_sdt_sections);
sdt_table_print(pp_current_sdt_sections, print, NULL);
}
static void handle_sdt_section(uint16_t i_pid, uint8_t *p_section)
{
if (i_pid != SDT_PID || !sdt_validate(p_section)) {
printf("invalid SDT section received on PID %hu", i_pid);
free(p_section);
return;
}
if (!psi_table_section(pp_next_sdt_sections, p_section))
return;
handle_sdt();
}
/*****************************************************************************
* 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", i_pid);
free(p_section);
return;
}
switch (i_table_id) {
case PAT_TABLE_ID:
handle_pat_section(i_pid, p_section);
break;
case PMT_TABLE_ID:
handle_pmt(i_pid, p_section);
break;
case NIT_TABLE_ID_ACTUAL:
handle_nit_section(i_pid, p_section);
break;
case SDT_TABLE_ID_ACTUAL:
handle_sdt_section(i_pid, p_section);
break;
default:
free( p_section );
break;
}
}
/*****************************************************************************
* 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 = ts_payload(p_ts);
uint8_t i_length;
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);
if (psi_assemble_empty(&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;
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
*****************************************************************************/
int main(int i_argc, char **ppsz_argv)
{
int i;
if (ppsz_argv[1] != NULL &&
(!strcmp(ppsz_argv[1], "-h") || !strcmp(ppsz_argv[1], "--help"))) {
fprintf(stderr, "usage: %s < <input file> [> <output>]\n",
ppsz_argv[0]);
return 1;
}
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 );
}
p_pids[PAT_PID].i_psi_refcount++;
p_pids[NIT_PID].i_psi_refcount++;
p_pids[SDT_PID].i_psi_refcount++;
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))
printf("invalid TS packet");
else {
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);
}
}
return 0;
}
......@@ -73,7 +73,7 @@ static inline void desc_print(const uint8_t *p_desc, f_print pf_print,
static inline void desc05_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x05);
desc_set_length(p_desc, DESC05_HEADER_SIZE);
desc_set_length(p_desc, DESC05_HEADER_SIZE - DESC_HEADER_SIZE);
}
static inline void desc05_set_identifier(uint8_t *p_desc, uint8_t p_id[4])
......@@ -114,7 +114,7 @@ static inline uint16_t desc09_get_pid(const uint8_t *p_desc)
static inline void desc09_print(const uint8_t *p_desc, f_print pf_print,
void *opaque)
{
pf_print(opaque, " - desc 09 sysid=%hx pid=%hu",
pf_print(opaque, " - desc 09 sysid=0x%hx pid=%hu",
desc09_get_sysid(p_desc), desc09_get_pid(p_desc));
}
......@@ -168,7 +168,7 @@ static inline void desc0a_print(uint8_t *p_desc, f_print pf_print,
while ((p_desc_n = desc0a_get_language(p_desc, j)) != NULL) {
j++;
pf_print(opaque, " - desc 0a language=%3.3s audiotype=%hhu",
pf_print(opaque, " - desc 0a language=%3.3s audiotype=0x%hhx",
(const char *)desc0an_get_code(p_desc_n),
desc0an_get_audiotype(p_desc_n));
}
......@@ -648,6 +648,8 @@ static inline void psi_table_copy(uint8_t **pp_dest, uint8_t **pp_src)
psi_get_tableid(pp_sections[0])
#define psi_table_get_version(pp_sections) \
psi_get_version(pp_sections[0])
#define psi_table_get_current(pp_sections) \
psi_get_current(pp_sections[0])
#define psi_table_get_lastsection(pp_sections) \
psi_get_lastsection(pp_sections[0])
#define psi_table_get_tableidext(pp_sections) \
......@@ -830,9 +832,10 @@ static inline void pat_table_print(uint8_t **pp_sections, f_print pf_print,
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
pf_print(opaque, "new PAT tsid=%hu version=%hhu",
pf_print(opaque, "new PAT tsid=%hu version=%hhu%s",
psi_table_get_tableidext(pp_sections),
psi_table_get_version(pp_sections));
psi_table_get_version(pp_sections),
!psi_table_get_current(pp_sections) ? " (next)" : "");
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
......@@ -840,10 +843,14 @@ static inline void pat_table_print(uint8_t **pp_sections, f_print pf_print,
int j = 0;
while ((p_program = pat_get_program(p_section, j)) != NULL) {
uint16_t i_program = patn_get_program(p_program);
uint16_t i_pid = patn_get_pid(p_program);
j++;
if (i_program == 0)
pf_print(opaque, " * NIT pid=%hu", i_pid);
else
pf_print(opaque, " * program number=%hu pid=%hu",
patn_get_program(p_program),
patn_get_pid(p_program));
i_program, i_pid);
}
}
......
......@@ -81,8 +81,9 @@ static inline void pmt_print(uint8_t *p_pmt, f_print pf_print, void *opaque)
uint8_t *p_es;
uint8_t j = 0;
pf_print(opaque, "new PMT program=%hu version=%hhu pcrpid=%hu",
pf_print(opaque, "new PMT program=%hu version=%hhu%s pcrpid=%hu",
pmt_get_program(p_pmt), psi_get_version(p_pmt),
!psi_get_current(p_pmt) ? " (next)" : "",
pmt_get_pcrpid(p_pmt));
descs_print(pmt_get_descs(p_pmt), pf_print, opaque);
......@@ -105,17 +106,18 @@ static inline void nit_table_print(uint8_t **pp_sections, f_print pf_print,
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
pf_print(opaque, "new NIT %s networkid=%hu version=%hhu",
pf_print(opaque, "new NIT %s networkid=%hu version=%hhu%s",
psi_table_get_tableid(pp_sections) == NIT_TABLE_ID_ACTUAL ?
"actual" : "other",
psi_table_get_tableidext(pp_sections),
psi_table_get_version(pp_sections));
psi_table_get_version(pp_sections),
!psi_table_get_current(pp_sections) ? " (next)" : "");
descs_print(nit_get_descs(psi_table_get_section(pp_sections, 0)),
pf_print, opaque);
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
const uint8_t *p_ts;
uint8_t *p_ts;
int j = 0;
while ((p_ts = nit_get_ts(p_section, j)) != NULL) {
......@@ -138,16 +140,17 @@ static inline void sdt_table_print(uint8_t **pp_sections, f_print pf_print,
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
pf_print(opaque, "new SDT %s tsid=%hu version=%hhu onid=%hu",
pf_print(opaque, "new SDT %s tsid=%hu version=%hhu%s onid=%hu",
psi_table_get_tableid(pp_sections) == SDT_TABLE_ID_ACTUAL ?
"actual" : "other",
psi_table_get_tableidext(pp_sections),
psi_table_get_version(pp_sections),
!psi_table_get_current(pp_sections) ? " (next)" : "",
sdt_get_onid(psi_table_get_section(pp_sections, 0)));
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
const uint8_t *p_service;
uint8_t *p_service;
int j = 0;
while ((p_service = sdt_get_service(p_section, j)) != NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment