Commit 7114114e authored by Christophe Massiot's avatar Christophe Massiot

* examples/mpeg_print_pcr.c: New very basic (but useful) example program which...

* examples/mpeg_print_pcr.c: New very basic (but useful) example program which prints the PCR PID of the first PMT.
parent cd3f2856
......@@ -2,7 +2,7 @@
CFLAGS = -Wall -O2 -g
LDFLAGS =
OBJ = dvb_print_si dvb_ecmg dvb_ecmg_test
OBJ = dvb_print_si dvb_ecmg dvb_ecmg_test mpeg_print_pcr
all: $(OBJ)
......
/*****************************************************************************
* mpeg_print_pcr.c: Prints PCR PID from the first program of the stream
*****************************************************************************
* Copyright (C) 2011 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 <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <bitstream/mpeg/ts.h>
#include <bitstream/mpeg/psi.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);
/*****************************************************************************
* 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_compare(pp_current_pat_sections, pp_next_pat_sections)) {
/* Identical 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)) {
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)
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);
pp_sids[i_pmt]->p_current_pmt = NULL;
break;
}
}
}
}
psi_table_free(pp_old_pat_sections);
}
}
static void handle_pat_section(uint16_t i_pid, uint8_t *p_section)
{
if (i_pid != PAT_PID || !pat_validate(p_section)) {
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)) {
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) {
p_sid = pp_sids[i];
if (i_pid == p_sid->i_pmt_pid) {
printf("%"PRIu16"\n", pmt_get_pcrpid(p_pmt));
exit(EXIT_SUCCESS);
}
}
free(p_pmt);
}
/*****************************************************************************
* 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)) {
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;
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;
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);
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;
if (ppsz_argv[1] != NULL &&
(!strcmp(ppsz_argv[1], "-h") || !strcmp(ppsz_argv[1], "--help")))
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 );
}
p_pids[PAT_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)) {
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 EXIT_FAILURE;
}
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