Commit 14fbe121 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Add new API for chaining PSI table decoders based on table_id and extension (subtable_id).

This API deprecates the dvbpsi_demux* API.
parent d220dd16
......@@ -38,3 +38,4 @@ misc/gen_crc
misc/gen_pat
misc/gen_pmt
misc/test_dr
misc/test_chain
## Process this file with automake to produce Makefile.in
noinst_PROGRAMS = gen_crc gen_pat gen_pmt \
test_dr
test_dr test_chain
gen_crc_SOURCES = gen_crc.c
......@@ -13,6 +13,9 @@ gen_pmt_SOURCES = gen_pmt.c
gen_pmt_CPPFLAGS = -DDVBPSI_DIST
gen_pmt_LDFLAGS = -L../src -ldvbpsi
test_chain_SOURCES = test_chain.c
test_chain_CPPFLAGS = -DDVBPSI_DIST
test_chain_LDFLAGS = -L../src -ldvbpsi
test_dr_SOURCES = test_dr.c
test_dr_CPPFLAGS = -DDVBPSI_DIST
......
/*****************************************************************************
* chain.c: decoder chain test
*----------------------------------------------------------------------------
* Copyright (C) 2015 VideoLAN
* $Id: $
*
* Authors: Jean-Paul Saman <jpsaman@videolan.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*----------------------------------------------------------------------------
*
*****************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#elif defined(HAVE_STDINT_H)
#include <stdint.h>
#endif
/* the libdvbpsi distribution defines DVBPSI_DIST */
#ifdef DVBPSI_DIST
#include "../src/dvbpsi.h"
#include "../src/psi.h"
#include "../src/chain.h"
#else
#include <dvbpsi/dvbpsi.h>
#include <dvbpsi/psi.h>
#include <dvbpsi/chain.h>
#endif
#define TEST_PASSED(msg) fprintf(stderr, "test %s -- PASSED\n", (msg));
#define TEST_FAILED(msg) fprintf(stderr, "test %s -- FAILED\n", (msg));
static void message(dvbpsi_t *handle, const dvbpsi_msg_level_t level, const char* msg)
{
switch(level)
{
case DVBPSI_MSG_ERROR: fprintf(stderr, "Error: "); break;
case DVBPSI_MSG_WARN: fprintf(stderr, "Warning: "); break;
case DVBPSI_MSG_DEBUG: fprintf(stderr, "Debug: "); break;
default: /* do nothing */
return;
}
fprintf(stderr, "%s\n", msg);
}
static bool chain_add(dvbpsi_t *p_dvbpsi, const int count)
{
for (int i = 0; i < count; i++) {
dvbpsi_decoder_t *p_dec = calloc(1,sizeof(dvbpsi_decoder_t));
if (p_dec == NULL) {
fprintf(stderr, "out of memory\n");
return false;
}
p_dec->i_table_id = i;
p_dec->i_extension = i;
if (!dvbpsi_decoder_chain_add(p_dvbpsi, p_dec)) {
fprintf(stderr, "failed to add decoder to chain\n");
return false;
}
assert(p_dvbpsi->p_decoder);
/* verify adding to chain */
p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, i, i);
if (p_dec == NULL) {
fprintf(stderr, "could not find decoder (%d:%d)\n", i, i);
return false;
}
}
return true;
}
static bool chain_add_table_extension(dvbpsi_t *p_dvbpsi, const int count)
{
for (int i = 0; i < count; i++) {
dvbpsi_decoder_t *p_dec = calloc(1,sizeof(dvbpsi_decoder_t));
if (p_dec == NULL) {
fprintf(stderr, "out of memory\n");
return false;
}
const int i_extension = i + 1;
p_dec->i_table_id = i;
p_dec->i_extension = i_extension;
if (!dvbpsi_decoder_chain_add(p_dvbpsi, p_dec)) {
fprintf(stderr, "failed to add decoder to chain\n");
return false;
}
assert(p_dvbpsi->p_decoder);
/* verify adding to chain */
p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, i, i_extension);
if (p_dec == NULL) {
fprintf(stderr, "could not find decoder (%d:%d)\n", i, i_extension);
return false;
}
}
return true;
}
static bool chain_find(dvbpsi_t *p_dvbpsi, const int count)
{
for (int i = 0; i < count; i++) {
dvbpsi_decoder_t *p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, i, i);
if (p_dec == NULL) {
fprintf(stderr, "could not find decoder (%d:%d)\n", i, i);
return false;
}
}
return true;
}
static bool chain_release(dvbpsi_t *p_dvbpsi, const int count)
{
for (int i = 0; i < count; i++) {
dvbpsi_decoder_t *p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, i, i);
if (p_dec == NULL) {
fprintf(stderr, "failed to find decoder (%d:%d) in chain\n", i, i);
return false;
}
if (!dvbpsi_decoder_chain_del(p_dvbpsi, p_dec)) {
fprintf(stderr, "failed to delete decoder (%d:%d) from chain\n", i, i);
return false;
}
/* NOTE: normally we would call dvbpsi_decoder_delete(p_dec) for
* a PSI table decoder allocated with dvbpsi_decoder_new(). However
* for this test the contents of the decoder does not really matter
* and therefor we allocate with calloc() and free with free(). */
free(p_dec);
p_dec = NULL;
}
return true;
}
static bool chain_release_with_extension(dvbpsi_t *p_dvbpsi, const int count)
{
for (int i = 0; i < count; i++) {
const int i_extension = i + 1;
dvbpsi_decoder_t *p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, i, i_extension);
if (p_dec == NULL) {
fprintf(stderr, "failed to find decoder (%d:%d) in chain\n", i, i_extension);
return false;
}
if (!dvbpsi_decoder_chain_del(p_dvbpsi, p_dec)) {
fprintf(stderr, "failed to delete decoder (%d:%d) from chain\n", i, i_extension);
return false;
}
/* NOTE: normally we would call dvbpsi_decoder_delete(p_dec) for
* a PSI table decoder allocated with dvbpsi_decoder_new(). However
* for this test the contents of the decoder does not really matter
* and therefor we allocate with calloc() and free with free(). */
free(p_dec);
p_dec = NULL;
}
return true;
}
/*****************************************************************************
* main
*****************************************************************************/
#define CHAIN_DECODERS (20)
int main(int i_argc, char* pa_argv[])
{
dvbpsi_t *p_dvbpsi = dvbpsi_new(&message, DVBPSI_MSG_DEBUG);
if (p_dvbpsi == NULL)
return 1;
/* Test dvbpsi_decoder_chain_add() */
if (!chain_add(p_dvbpsi, CHAIN_DECODERS)) {
TEST_FAILED("dvbpsi_decoder_chain_add");
goto error;
}
TEST_PASSED("dvbpsi_decoder_chain_add");
/* Test dvbpsi_decoder_chain_get() */
if (!chain_find(p_dvbpsi, CHAIN_DECODERS)) {
TEST_FAILED("dvbpsi_decoder_chain_get");
goto error;
}
TEST_PASSED("dvbpsi_decoder_chain_get");
/* Test dvbpsi_decoder_chain_add() with table extensions */
if (!chain_add_table_extension(p_dvbpsi, CHAIN_DECODERS)) {
TEST_FAILED("dvbpsi_decoder_chain_add with extensions");
goto error;
}
TEST_PASSED("dvbpsi_decoder_chain_add with extensions");
/* Test dvbpsi_decoder_chain_del() */
if (!chain_release(p_dvbpsi, CHAIN_DECODERS)) {
TEST_FAILED("dvbpsi_decoder_chain_del");
dvbpsi_delete(p_dvbpsi);
return 1;
}
TEST_PASSED("dvbpsi_decoder_chain_del");
/* Test dvbpsi_decoder_chain_del() */
if (!chain_release_with_extension(p_dvbpsi, CHAIN_DECODERS)) {
TEST_FAILED("dvbpsi_decoder_chain_del with extensions");
dvbpsi_delete(p_dvbpsi);
return 1;
}
TEST_PASSED("dvbpsi_decoder_chain_del with extensions");
//dvbpsi_decoder_chain_dump(p_dvbpsi);
assert(!p_dvbpsi->p_decoder);
p_dvbpsi->p_decoder = NULL;
dvbpsi_delete(p_dvbpsi);
fprintf(stderr, "ALL CHAIN TESTS PASSED\n");
return 0;
error:
/* cleanup */
if (!chain_release(p_dvbpsi, CHAIN_DECODERS))
fprintf(stderr, "failed to cleanup after errors\n");
p_dvbpsi->p_decoder = NULL;
dvbpsi_delete(p_dvbpsi);
return 1;
}
......@@ -7,13 +7,14 @@ lib_LTLIBRARIES = libdvbpsi.la
libdvbpsi_la_SOURCES = dvbpsi.c dvbpsi_private.h \
psi.c \
demux.c \
chain.c \
descriptor.c \
$(tables_src) \
$(descriptors_src)
libdvbpsi_la_LDFLAGS = -version-info 11:0:0 -no-undefined
pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.h \
pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.h chain.h \
tables/pat.h tables/pmt.h tables/sdt.h tables/eit.h \
tables/cat.h tables/nit.h tables/tot.h tables/sis.h \
tables/bat.h tables/rst.h \
......
/*****************************************************************************
* chain.c: DVB subtables decoder chain functions
*----------------------------------------------------------------------------
* Copyright (C) 2015 VideoLAN
* $Id: $
*
* Authors: Jean-Paul Saman <jpsaman@videolan.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*----------------------------------------------------------------------------
*
*****************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#elif defined(HAVE_STDINT_H)
#include <stdint.h>
#endif
#include <assert.h>
#include "dvbpsi.h"
#include "dvbpsi_private.h"
#include "psi.h"
#include "chain.h"
/*****************************************************************************
* dvbpsi_decoder_chain_add
*****************************************************************************
* Add decoder to chain
*****************************************************************************/
bool dvbpsi_decoder_chain_add(dvbpsi_t *p_dvbpsi, dvbpsi_decoder_t *p_decoder)
{
assert(p_decoder);
assert(!p_decoder->p_next);
dvbpsi_decoder_t *p_list = (dvbpsi_decoder_t *) p_dvbpsi->p_decoder;
while (p_list) {
if (p_decoder->i_table_id == p_list->i_table_id) {
if (p_decoder->i_extension == p_list->i_extension) {
dvbpsi_error(p_dvbpsi, "chain", "decoder (%d:%d) already present",
p_decoder->i_table_id, p_decoder->i_extension);
return false;
}
/* insert in reverse sequential order based on i_extension */
if (p_decoder->i_extension > p_list->i_extension) {
p_decoder->p_next = p_list->p_next;
p_list->p_next = p_decoder;
return true;
}
}
/* append to end of list */
if (p_list->p_next == NULL) {
p_list->p_next = p_decoder;
return true;
}
/* insert in sequential order based on i_table_id */
if (p_decoder->i_table_id < p_list->p_next->i_table_id) {
p_decoder->p_next = p_list->p_next;
p_list->p_next = p_decoder;
return true;
}
p_list = p_list->p_next;
}
/* empty list */
p_dvbpsi->p_decoder = p_decoder;
return true;
}
/*****************************************************************************
* dvbpsi_decoder_chain_del
*****************************************************************************
* Remove decoder from chain
*****************************************************************************/
bool dvbpsi_decoder_chain_del(dvbpsi_t *p_dvbpsi, const dvbpsi_decoder_t *p_decoder)
{
if (!p_decoder) return false;
dvbpsi_decoder_t *p = (dvbpsi_decoder_t *)p_dvbpsi->p_decoder;
dvbpsi_decoder_t *last = NULL;
while (p) {
if ((p_decoder->i_table_id == p->i_table_id) &&
(p_decoder->i_extension == p->i_extension)) {
assert(p == p_decoder);
if (last == NULL)
p_dvbpsi->p_decoder = p->p_next;
else
last->p_next = p->p_next;
/* NOTE: caller must call dvbpsi_decoder_delete(p_decoder) */
return true;
}
last = p;
p = p->p_next;
}
dvbpsi_warning(p_dvbpsi, "chain", "decoder not found");
return false;
}
/*****************************************************************************
* dvbpsi_decoder_chain_get
*****************************************************************************
* Return pointer to decoder in chain
*****************************************************************************/
dvbpsi_decoder_t *dvbpsi_decoder_chain_get(dvbpsi_t *p_dvbpsi, const uint16_t table_id, const uint16_t extension)
{
dvbpsi_decoder_t *p = (dvbpsi_decoder_t *)p_dvbpsi->p_decoder;
while (p) {
if ((table_id == p->i_table_id) &&
(extension == p->i_extension))
return p;
p = p->p_next;
}
dvbpsi_error(p_dvbpsi, "chain", "decoder not found");
return NULL;
}
#if 0 /* debug */
void dvbpsi_decoder_chain_dump(dvbpsi_t *p_dvbpsi)
{
dvbpsi_decoder_t *p = (dvbpsi_decoder_t *)p_dvbpsi->p_decoder;
while (p) {
dvbpsi_debug(p_dvbpsi, "dump chain", "found decoder %d:%d",
p->i_table_id, p->i_extension);
p = p->p_next;
}
}
#endif
/*****************************************************************************
* chain.h
*
* Copyright (C) 2015 VideoLAN
* $Id$
*
* Authors: Jean-Paul Saman <jpsaman@videolan.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
/*!
* \file <chain.h>
* \author Jean-Paul Saman <jpsaman@videolan.org>
* \brief Chain PSI table decoders based on table_id and extension.
*
* Chain PSI table decoders based on table_id and extension. The
* decoder chain is kept inside the dvbpsi_t handle at the
* dvbpsi_t::dvbpsi_decoder_t member variable.
*/
#ifndef _DVBPSI_CHAIN_H_
#define _DVBPSI_CHAIN_H_
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_decoder_chain_add
*****************************************************************************/
/*!
* \fn bool dvbpsi_decoder_chain_add(dvbpsi_t *p_dvbpsi, dvbpsi_decoder_t *p_decoder)
* \brief Adds decoder to the chain in handle 'p_dvbpsi' at dvbpsi_t::dvbpsi_decoder_t
* \param p_dvbpsi pointer to dvbpsi_t handle
* \param p_decoder pointer to dvbpsi_decoder_t for adding to chain
* \return true on success, false on failure
*/
bool dvbpsi_decoder_chain_add(dvbpsi_t *p_dvbpsi, dvbpsi_decoder_t *p_decoder);
/*****************************************************************************
* dvbpsi_decoder_chain_del
*****************************************************************************/
/*!
* \fn bool dvbpsi_decoder_chain_del(dvbpsi_t *p_dvbpsi, const dvbpsi_decoder_t *p_decoder)
* \brief Deletes decoder from the chain in handle 'p_dvbpsi' at dvbpsi_t::dvbpsi_decoder_t
* \note Use @see dvbpsi_decoder_chain_get() to find the decoder pointer, then call
* dvbpsi_decoder_chain_del() to remove the pointer from the chain. The caller is
* responsible for freeing the associated memory of the just removed decoder pointer
* and needs to call decoder_delete(p_decoder).
* \param p_dvbpsi pointer to dvbpsi_t handle
* \param p_decoder pointer to dvbpsi_decoder_t for deletion from chain
* \return true on success, false on failure
*/
bool dvbpsi_decoder_chain_del(dvbpsi_t *p_dvbpsi, const dvbpsi_decoder_t *p_decoder);
/*****************************************************************************
* dvbpsi_decoder_chain_get
*****************************************************************************/
/*!
* \fn dvbpsi_decoder_t *dvbpsi_decoder_chain_get(dvbpsi_t *p_dvbpsi, const uint16_t table_id, const uint16_t extension)
* \brief Gets decoder from the chain based on given table_id and extension.
* If extension is 0, then the search is performed on table_id only and the first match is returned.
* \param p_dvbpsi pointer to dvbpsi_t handle
* \param table_id PSI table id to get
* \param extension PSI subtable id to get
* \return true on success, false on failure
*/
dvbpsi_decoder_t *dvbpsi_decoder_chain_get(dvbpsi_t *p_dvbpsi, const uint16_t table_id, const uint16_t extension);
#if 0 /* debug code */
void dvbpsi_decoder_chain_dump(dvbpsi_t *p_dvbpsi);
#endif
#ifdef __cplusplus
};
#endif
#else
#error "Multiple inclusions of chain.h"
#endif
......@@ -245,6 +245,10 @@ typedef void (* dvbpsi_callback_gather_t)(dvbpsi_t *p_dvbpsi, /*!< pointer to d
dvbpsi_callback_gather_t pf_gather;/*!< PSI decoder's callback */ \
int i_section_max_size; /*!< Max size of a section for this decoder */ \
int i_need; /*!< Bytes needed */ \
/* since version 2.0.0 */ \
uint16_t i_table_id; /*!< PSI table id */ \
uint16_t i_extension; /*!< PSI subtable id */ \
dvbpsi_decoder_t *p_next; /*!< Pointer to next decoder the list */
/**@}*/
/*****************************************************************************
......
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