Commit ab181e94 authored by Adam Charrett's avatar Adam Charrett Committed by Jean-Paul Saman

Add support for parsing ATSC tables: EIT STT VCT & new descriptors

Adds ATSC table support for: EIT STT VCT
Adds descriptor support for: 13 14 62 66 73 76 83
Signed-off-by: default avatarAdam Charrett <adam@dvbstreamer.org>
Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
parent 385db261
......@@ -17,6 +17,8 @@ pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.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/atsc_vct.h tables/atsc_stt.h \
tables/atsc_eit.h \
descriptors/dr_02.h \
descriptors/dr_03.h \
descriptors/dr_04.h \
......@@ -31,6 +33,8 @@ pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.h \
descriptors/dr_0d.h \
descriptors/dr_0e.h \
descriptors/dr_0f.h \
descriptors/dr_13.h \
descriptors/dr_14.h \
descriptors/dr_42.h \
descriptors/dr_43.h \
descriptors/dr_44.h \
......@@ -45,7 +49,12 @@ pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.h \
descriptors/dr_58.h \
descriptors/dr_59.h \
descriptors/dr_5a.h \
descriptors/dr_62.h \
descriptors/dr_66.h \
descriptors/dr_69.h \
descriptors/dr_73.h \
descriptors/dr_76.h \
descriptors/dr_83.h \
descriptors/dr_8a.h \
descriptors/dr.h
......@@ -63,6 +72,8 @@ descriptors_src = descriptors/dr_02.c \
descriptors/dr_0d.c \
descriptors/dr_0e.c \
descriptors/dr_0f.c \
descriptors/dr_13.c \
descriptors/dr_14.c \
descriptors/dr_42.c \
descriptors/dr_43.c \
descriptors/dr_44.c \
......@@ -77,7 +88,12 @@ descriptors_src = descriptors/dr_02.c \
descriptors/dr_58.c \
descriptors/dr_59.c \
descriptors/dr_5a.c \
descriptors/dr_62.c \
descriptors/dr_66.c \
descriptors/dr_69.c \
descriptors/dr_73.c \
descriptors/dr_76.c \
descriptors/dr_83.c \
descriptors/dr_8a.c
tables_src = tables/pat.c tables/pat_private.h \
......@@ -88,5 +104,8 @@ tables_src = tables/pat.c tables/pat_private.h \
tables/nit.c tables/nit_private.h \
tables/tot.c tables/tot_private.h \
tables/sis.c tables/sis_private.h \
tables/bat.c tables/bat_private.h
tables/bat.c tables/bat_private.h \
tables/atsc_vct.c tables/atsc_vct.h \
tables/atsc_stt.c tables/atsc_stt.h \
tables/atsc_eit.c tables/atsc_eit.h
/*
Copyright (C) 2010 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_13.c
Decode Carousel Id Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_13.h"
/*****************************************************************************
* dvbpsi_DecodeCarouselIdDr
*****************************************************************************/
dvbpsi_carousel_id_dr_t *dvbpsi_DecodeCarouselIdDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_carousel_id_dr_t *p_decoded;
/* Check the tag */
if (p_descriptor->i_tag != 0x13)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
/* Check length */
if (p_descriptor->i_length < 4)
{
return NULL;
}
p_decoded = (dvbpsi_carousel_id_dr_t*)malloc(sizeof(dvbpsi_carousel_id_dr_t) + p_descriptor->i_length - 4);
if (!p_decoded)
{
return NULL;
}
p_decoded->i_carousel_id= ((p_descriptor->p_data[0] & 0xff) << 24) | ((p_descriptor->p_data[1] & 0xff) << 16)|
((p_descriptor->p_data[2] & 0xff) << 8) | (p_descriptor->p_data[3] & 0xff);
p_decoded->i_private_data_len= p_descriptor->i_length - 4;
memcpy(p_decoded->s_private_data, &p_descriptor->p_data[4], p_decoded->i_private_data_len);
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
/*
Copyright (C) 2010 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_13.h
Decode Carousel id Descriptor.
*/
#ifndef _DR_13_H
#define _DR_13_H
/*****************************************************************************
* dvbpsi_carousel_id_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_carousel_id_dr_s
* \brief Data Broadcast id Descriptor
*
* This structure is used to store a decoded Carsouel ID descriptor.
*/
/*!
* \typedef struct dvbpsi_carousel_id_dr_s dvbpsi_carousel_id_dr_t
* \brief dvbpsi_carousel_id_dr_t type definition.
*/
typedef struct dvbpsi_carousel_id_dr_s
{
uint32_t i_carousel_id;
uint8_t i_private_data_len;
uint8_t s_private_data[0];
}dvbpsi_carousel_id_dr_t;
/*****************************************************************************
* dvbpsi_DecodeCarouselIdDr
*****************************************************************************/
/*!
* \fn dvbpsi_carousel_id_dr_t *dvbpsi_DecodeCarouselIdDr(
* dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Carousel id descriptor (tag 0x13)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_carousel_id_dr_t structure.
*/
dvbpsi_carousel_id_dr_t *dvbpsi_DecodeCarouselIdDr(dvbpsi_descriptor_t *p_descriptor);
#endif
/*
Copyright (C) 2010 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_14.c
Decode Assocation Tag Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_14.h"
/*****************************************************************************
* dvbpsi_DecodeAssociationTagDr
*****************************************************************************/
dvbpsi_association_tag_dr_t *dvbpsi_DecodeAssociationTagDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_association_tag_dr_t *p_decoded;
uint8_t selector_len;
uint8_t private_data_len;
/* Check the tag */
if (p_descriptor->i_tag != 0x14)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
/* Check length */
if (p_descriptor->i_length < 5)
{
return NULL;
}
selector_len = p_descriptor->p_data[4];
/* Invalid selector length */
if (selector_len + 5 > p_descriptor->i_length)
{
return NULL;
}
private_data_len= p_descriptor->i_length - (5 + selector_len);
p_decoded = (dvbpsi_association_tag_dr_t*)malloc(sizeof(dvbpsi_association_tag_dr_t) + selector_len + private_data_len);
if (!p_decoded)
{
return NULL;
}
p_decoded->i_tag = ((p_descriptor->p_data[0] & 0xff) << 8) | (p_descriptor->p_data[1] & 0xff);
p_decoded->i_use = ((p_descriptor->p_data[2] & 0xff) << 8) | (p_descriptor->p_data[3] & 0xff);
p_decoded->i_selector_len = selector_len;
p_decoded->i_private_data_len= private_data_len;
p_decoded->p_selector = ((void*)p_decoded) + sizeof(dvbpsi_association_tag_dr_t);
p_decoded->p_private_data = p_decoded->p_selector + selector_len;
memcpy(p_decoded->p_selector, &p_descriptor->p_data[5 ], selector_len);
memcpy(p_decoded->p_private_data, &p_descriptor->p_data[5 + selector_len], private_data_len);
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
/*
Copyright (C) 2010 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_14.h
Decode Association Tag Descriptor.
*/
#ifndef _DR_14_H
#define _DR_14_H
/*****************************************************************************
* dvbpsi_association_tag_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_association_tag_dr_s
* \brief Data Broadcast id Descriptor
*
* This structure is used to store a decoded Association Tag descriptor.
*/
/*!
* \typedef struct dvbpsi_association_tag_dr_s dvbpsi_association_tag_dr_t
* \brief dvbpsi_association_tag_dr_t type definition.
*/
typedef struct dvbpsi_association_tag_dr_s
{
uint16_t i_tag;
uint16_t i_use;
uint8_t i_selector_len;
uint8_t *p_selector;
uint8_t i_private_data_len;
uint8_t *p_private_data;
}dvbpsi_association_tag_dr_t;
/*****************************************************************************
* dvbpsi_DecodeAssociationTagDr
*****************************************************************************/
/*!
* \fn dvbpsi_association_tag_dr_t *dvbpsi_DecodeAssociationTagDr(
* dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Association Tag descriptor (tag 0x14)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_association_tag_dr_t structure.
*/
dvbpsi_association_tag_dr_t *dvbpsi_DecodeAssociationTagDr(dvbpsi_descriptor_t *p_descriptor);
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_62.c
Decode Frequency List Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_62.h"
/*****************************************************************************
* dvbpsi_DecodeFrequencyListDr
*****************************************************************************/
dvbpsi_frequency_list_dr_t *dvbpsi_DecodeFrequencyListDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_frequency_list_dr_t *p_decoded;
int i;
/* Check the tag */
if (p_descriptor->i_tag != 0x62)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
/* Check length */
if ((p_descriptor->i_length - 1) % 4)
{
return NULL;
}
p_decoded = (dvbpsi_frequency_list_dr_t*)malloc(sizeof(dvbpsi_frequency_list_dr_t));
if (!p_decoded)
{
return NULL;
}
p_decoded->i_number_of_frequencies = (p_descriptor->i_length - 1) / 4;
p_decoded->i_coding_type = p_descriptor->p_data[0] & 0x3;
for (i = 0; i < p_decoded->i_number_of_frequencies; i ++)
{
p_decoded->p_center_frequencies[i] = (p_descriptor->p_data[(i * 4) + 1] << 24) |
(p_descriptor->p_data[(i * 4) + 2] << 16) |
(p_descriptor->p_data[(i * 4) + 3] << 8) |
p_descriptor->p_data[(i * 4) + 4];
if ((p_decoded->i_coding_type == 1) || (p_decoded->i_coding_type == 2))
{
p_decoded->p_center_frequencies[i] = dvbpsi_Bcd8ToUint32(p_decoded->p_center_frequencies[i]);
}
}
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
uint32_t dvbpsi_Bcd8ToUint32(uint32_t bcd)
{
uint32_t i_decoded;
i_decoded = ((bcd >> 28) & 0xf) * 10000000;
i_decoded += ((bcd >> 24) & 0xf) * 1000000;
i_decoded += ((bcd >> 20) & 0xf) * 100000;
i_decoded += ((bcd >> 16) & 0xf) * 10000;
i_decoded += ((bcd >> 12) & 0xf) * 1000;
i_decoded += ((bcd >> 8) & 0xf) * 100;
i_decoded += ((bcd >> 4) & 0xf) * 10;
i_decoded += ((bcd >> 0) & 0xf) * 1;
return i_decoded;
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_62.h
Decode Frequency List Descriptor.
*/
#ifndef _DR_62_H
#define _DR_62_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_frequency_list_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_frequency_list_dr_s
* \brief Frequency List Descriptor
*
* This structure is used to store a decoded Frequency List descriptor.
*/
/*!
* \typedef struct dvbpsi_frequency_list_dr_s dvbpsi_frequency_list_dr_t
* \brief dvbpsi_frequency_list_dr_t type definition.
*/
typedef struct dvbpsi_frequency_list_dr_s
{
uint8_t i_coding_type; /*!< Coding type, 1 = Satellite, 2 = Cable, 3 = Terrestrial */
uint8_t i_number_of_frequencies; /*!< Number of center frequencies present */
uint32_t p_center_frequencies[63]; /*!< Center frequency as defined by a delivery_system_descriptor */
}dvbpsi_frequency_list_dr_t;
/*****************************************************************************
* dvbpsi_DecodeFrequencyListDr
*****************************************************************************/
/*!
* \fn dvbpsi_frequency_list_dr_t *dvbpsi_DecodeFrequencyListDr(
* dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Frequency List descriptor (tag 0x62)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_frequency_list_dr_t structure.
*/
dvbpsi_frequency_list_dr_t *dvbpsi_DecodeFrequencyListDr(dvbpsi_descriptor_t *p_descriptor);
/*****************************************************************************
* dvbpsi_Bcd8ToUint32
*****************************************************************************/
/*!
* \fn uint32_t dvbpsi_Bcd8ToUint32(uint32_t bcd)
* \brief Decode an 8 character BCD encoded number into a uint32_t.
* \param bcd BCD value to convert.
* \return Decoded value as a uint32_t.
*/
uint32_t dvbpsi_Bcd8ToUint32(uint32_t bcd);
#ifdef __cplusplus
};
#endif
#endif
/*
Copyright (C) 2010 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_66.c
Decode Data Broadcast Id Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_66.h"
/*****************************************************************************
* dvbpsi_DecodeDataBroadcastIdDr
*****************************************************************************/
dvbpsi_data_broadcast_id_dr_t *dvbpsi_DecodeDataBroadcastIdDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_data_broadcast_id_dr_t *p_decoded;
/* Check the tag */
if (p_descriptor->i_tag != 0x66)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
/* Check length */
if (p_descriptor->i_length < 2)
{
return NULL;
}
p_decoded = (dvbpsi_data_broadcast_id_dr_t*)malloc(sizeof(dvbpsi_data_broadcast_id_dr_t) + p_descriptor->i_length - 2);
if (!p_decoded)
{
return NULL;
}
p_decoded->i_data_broadcast_id = ((p_descriptor->p_data[0] & 0xff) << 8) | (p_descriptor->p_data[1] & 0xff);
p_decoded->i_id_selector_len = p_descriptor->i_length - 2;
memcpy(p_decoded->s_id_selector, &p_descriptor->p_data[2], p_decoded->i_id_selector_len);
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
/*
Copyright (C) 2010 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_66.h
Decode Data Broadcast id Descriptor.
*/
#ifndef _DR_66_H
#define _DR_66_H
/*****************************************************************************
* dvbpsi_data_broadcast_id_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_data_broadcast_id_dr_s
* \brief Data Broadcast id Descriptor
*
* This structure is used to store a decoded Data Broadcast id descriptor.
*/
/*!
* \typedef struct dvbpsi_data_broadcast_id_dr_s dvbpsi_data_broadcast_id_dr_t
* \brief dvbpsi_data_broadcast_id_dr_t type definition.
*/
typedef struct dvbpsi_data_broadcast_id_dr_s
{
uint16_t i_data_broadcast_id;
uint8_t i_id_selector_len;
uint8_t s_id_selector[0];
}dvbpsi_data_broadcast_id_dr_t;
/*****************************************************************************
* dvbpsi_DecodeDataBroadcastIdDr
*****************************************************************************/
/*!
* \fn dvbpsi_data_broadcast_id_dr_t *dvbpsi_DecodeDataBroadcastIdDr(
* dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Data broadcast id descriptor (tag 0x66)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_data_broadcast_id_dr_t structure.
*/
dvbpsi_data_broadcast_id_dr_t *dvbpsi_DecodeDataBroadcastIdDr(dvbpsi_descriptor_t *p_descriptor);
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_73.c
Decode Default Authority Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_73.h"
/*****************************************************************************
* dvbpsi_DecodeDefaultAuthorityDr
*****************************************************************************/
dvbpsi_default_authority_dr_t *dvbpsi_DecodeDefaultAuthorityDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_default_authority_dr_t *p_decoded;
/* Check the tag */
if (p_descriptor->i_tag != 0x73)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
p_decoded = (dvbpsi_default_authority_dr_t*)malloc(sizeof(dvbpsi_default_authority_dr_t));
if (!p_decoded)
{
return NULL;
}
memcpy(&p_decoded->authority, p_descriptor->p_data, p_descriptor->i_length);
p_decoded->authority[p_descriptor->i_length] = 0;
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_73.h
Decode Default Authority Descriptor.
*/
#ifndef _DR_73_H
#define _DR_73_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_content_id_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_default_authority_dr_s
* \brief Default Authority Descriptor
*
* This structure is used to store a decoded Default Authority descriptor.
*/
/*!
* \typedef struct dvbpsi_default_authority_dr_s dvbpsi_default_authority_dr_t
* \brief dvbpsi_default_authority_dr_t type definition.
*/
typedef struct dvbpsi_default_authority_dr_s
{
uint8_t authority[255];
}dvbpsi_default_authority_dr_t;
/*****************************************************************************
* dvbpsi_DecodeLCNDr
*****************************************************************************/
/*!
* \fn dvbpsi_default_authority_dr_t *dvbpsi_DecodeDefaultAuthorityDr(dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Default Authority descriptor (tag 0x73)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_default_authority_dr_t structure.
*/
dvbpsi_default_authority_dr_t *dvbpsi_DecodeDefaultAuthorityDr(dvbpsi_descriptor_t *p_descriptor);
#ifdef __cplusplus
};
#endif
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_76.c
Decode Content Identifier Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_76.h"
/*****************************************************************************
* dvbpsi_DecodeLCNDr
*****************************************************************************/
dvbpsi_content_id_dr_t *dvbpsi_DecodeContentIdDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_content_id_dr_t *p_decoded;
int byte;
/* Check the tag */
if (p_descriptor->i_tag != 0x76)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
p_decoded = (dvbpsi_content_id_dr_t*)malloc(sizeof(dvbpsi_content_id_dr_t));
if (!p_decoded)
{
return NULL;
}
p_decoded->i_number_of_entries = 0;
for (byte = 0; byte < p_descriptor->i_length; p_decoded->i_number_of_entries ++)
{
dvbpsi_crid_entry_t *entry = &p_decoded->p_entries[p_decoded->i_number_of_entries];
entry->i_type = (p_descriptor->p_data[byte] >> 2) & 0x3f;
entry->i_location = p_descriptor->p_data[byte] & 3;
byte ++;
if (entry->i_location == CRID_LOCATION_DESCRIPTOR)
{
uint8_t len = p_descriptor->p_data[byte];
unsigned int i;
byte ++;
for (i = 0; i < len; i ++)
{
entry->value.path[i] = p_descriptor->p_data[byte + i];
}
byte += len;
entry->value.path[i] = 0;
}
else if (entry->i_location == CRID_LOCATION_CIT)
{
entry->value.ref = (p_descriptor->p_data[byte] << 8) | p_descriptor->p_data[byte + 1];
byte += 2;
}
else
{
/* Unknown location */
free(p_decoded);
return NULL;
}
}
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_76.h
Decode Content Identifier Descriptor.
*/
#ifndef _DR_76_H
#define _DR_76_H
#ifdef __cplusplus
extern "C" {
#endif
#define CRID_TYPE_UNDEFINED 0
#define CRID_TYPE_CONTENT 1
#define CRID_TYPE_SERIES 2
#define CRID_TYPE_RECOMMENDATION 3
#define CRID_LOCATION_DESCRIPTOR 0
#define CRID_LOCATION_CIT 1
/*****************************************************************************
* dvbpsi_lcn_entry_t
*****************************************************************************/
/*!
* \struct dvbpsi_crid_entry_s
* \brief CRID Entry
*
* This structure is used to store a decoded CRID entry.
*/
/*!
* \typedef struct dvbpsi_crid_entry_s dvbpsi_crid_entry_t
* \brief dvbpsi_crid_entry_t type definition.
*/
typedef struct dvbpsi_crid_entry_s
{
uint8_t i_type;
uint8_t i_location;
union
{
uint8_t path[253];
uint16_t ref;
}value;
}dvbpsi_crid_entry_t;
/*****************************************************************************
* dvbpsi_content_id_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_content_id_dr_s
* \brief Content Identifier Descriptor
*
* This structure is used to store a decoded Content Identifier descriptor.
*/
/*!
* \typedef struct dvbpsi_content_id_dr_s dvbpsi_content_id_dr_t
* \brief dvbpsi_content_id_dr_t type definition.
*/
typedef struct dvbpsi_content_id_dr_s
{
uint8_t i_number_of_entries; /*!< Number of CRID entries present. */
dvbpsi_crid_entry_t p_entries[85];/*!< Array of CRID entries. */
}dvbpsi_content_id_dr_t;
/*****************************************************************************
* dvbpsi_DecodeLCNDr
*****************************************************************************/
/*!
* \fn dvbpsi_content_id_dr_s dvbpsi_DecodeContentIdDr(dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Content Identifier descriptor (tag 0x76)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_content_id_dr_t structure.
*/
dvbpsi_content_id_dr_t *dvbpsi_DecodeContentIdDr(dvbpsi_descriptor_t *p_descriptor);
#ifdef __cplusplus
};
#endif
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_83.c
Decode Logical Channel Number Descriptor.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "../dvbpsi_private.h"
#include "descriptor.h"
#include "dr_83.h"
/*****************************************************************************
* dvbpsi_DecodeLCNDr
*****************************************************************************/
dvbpsi_lcn_dr_t *dvbpsi_DecodeLCNDr(dvbpsi_descriptor_t *p_descriptor)
{
dvbpsi_lcn_dr_t *p_decoded;
int i;
/* Check the tag */
if (p_descriptor->i_tag != 0x83)
{
return NULL;
}
/* Don't decode twice */
if (p_descriptor->p_decoded)
{
return p_descriptor->p_decoded;
}
/* Check length */
if (p_descriptor->i_length % 4)
{
return NULL;
}
p_decoded = (dvbpsi_lcn_dr_t*)malloc(sizeof(dvbpsi_lcn_dr_t));
if (!p_decoded)
{
return NULL;
}
p_decoded->i_number_of_entries = p_descriptor->i_length / 4;
for (i = 0; i < p_decoded->i_number_of_entries; i ++)
{
p_decoded->p_entries[i].i_service_id = (p_descriptor->p_data[i * 4] << 8) |
p_descriptor->p_data[(i * 4) + 1];
p_decoded->p_entries[i].b_visible_service_flag = (p_descriptor->p_data[(i * 4) + 2] >> 7) & 1;
p_decoded->p_entries[i].i_logical_channel_number = ((p_descriptor->p_data[(i * 4) + 2] << 8) |
p_descriptor->p_data[(i * 4) + 3]) & 0x3ff;
}
p_descriptor->p_decoded = (void*)p_decoded;
return p_decoded;
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dr_83.h
Decode Logical Channel Number Descriptor.
*/
#ifndef _DR_83_H
#define _DR_83_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_lcn_entry_t
*****************************************************************************/
/*!
* \struct dvbpsi_lcn_entry_s
* \brief Logical Channel Number Entry
*
* This structure is used to store a decoded Logical Channel Number entry.
*/
/*!
* \typedef struct dvbpsi_lcn_entry_s dvbpsi_lcn_entry_t
* \brief dvbpsi_lcn_entry_t type definition.
*/
typedef struct dvbpsi_lcn_entry_s
{
uint16_t i_service_id; /*!< Service ID this logical channel number refers to */
int b_visible_service_flag; /*!< Whether this LCN should be visible to the user. */
uint16_t i_logical_channel_number; /*!<The logical channel number for this service. */
}dvbpsi_lcn_entry_t;
/*****************************************************************************
* dvbpsi_lcn_dr_s
*****************************************************************************/
/*!
* \struct dvbpsi_lcn_dr_s
* \brief Logical Channel Number Descriptor
*
* This structure is used to store a decoded Logical Channel Number descriptor.
*/
/*!
* \typedef struct dvbpsi_lcn_dr_s dvbpsi_lcn_dr_t
* \brief dvbpsi_lcn_dr_t type definition.
*/
typedef struct dvbpsi_lcn_dr_s
{
uint8_t i_number_of_entries; /*!< Number of LCN entries present. */
dvbpsi_lcn_entry_t p_entries[64];/*!< Array of LCN entries. */
}dvbpsi_lcn_dr_t;
/*****************************************************************************
* dvbpsi_DecodeLCNDr
*****************************************************************************/
/*!
* \fn dvbpsi_lcn_dr_t dvbpsi_DecodeLCNDr(dvbpsi_descriptor_t *p_descriptor)
* \brief Decode a Logical Channel Number descriptor (tag 0x83)
* \param p_descriptor Raw descriptor to decode.
* \return NULL if the descriptor could not be decoded or a pointer to a
* dvbpsi_lcn_dr_t structure.
*/
dvbpsi_lcn_dr_t *dvbpsi_DecodeLCNDr(dvbpsi_descriptor_t *p_descriptor);
#ifdef __cplusplus
};
#endif
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
eit.c
Decode PSIP Virtual Channel Table.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "dvbpsi_private.h"
#include "psi.h"
#include "descriptor.h"
#include "demux.h"
#include "atsc_eit.h"
typedef struct dvbpsi_atsc_eit_decoder_s
{
dvbpsi_atsc_eit_callback pf_callback;
void * p_cb_data;
dvbpsi_atsc_eit_t current_eit;
dvbpsi_atsc_eit_t * p_building_eit;
int b_current_valid;
uint8_t i_last_section_number;
dvbpsi_psi_section_t * ap_sections [256];
} dvbpsi_atsc_eit_decoder_t;
dvbpsi_atsc_eit_event_t *dvbpsi_atsc_EITAddEvent(dvbpsi_atsc_eit_t* p_eit,
uint16_t i_event_id,
uint32_t i_start_time,
uint8_t i_etm_location,
uint32_t i_length_seconds,
uint8_t i_title_length,
uint8_t *p_title);
dvbpsi_descriptor_t *dvbpsi_atsc_EITEventAddDescriptor(
dvbpsi_atsc_eit_event_t *p_table,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data);
void dvbpsi_atsc_GatherEITSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section);
void dvbpsi_atsc_DecodeEITSections(dvbpsi_atsc_eit_t* p_eit,
dvbpsi_psi_section_t* p_section);
/*****************************************************************************
* dvbpsi_atsc_AttachEIT
*****************************************************************************
* Initialize a EIT subtable decoder.
*****************************************************************************/
int dvbpsi_atsc_AttachEIT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id, uint16_t i_extension,
dvbpsi_atsc_eit_callback pf_callback, void* p_cb_data)
{
dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_psi_decoder->p_private_decoder;
dvbpsi_demux_subdec_t* p_subdec;
dvbpsi_atsc_eit_decoder_t* p_eit_decoder;
unsigned int i;
if(dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension))
{
DVBPSI_ERROR_ARG("EIT decoder",
"Already a decoder for (table_id == 0x%02x extension == 0x%04x)",
i_table_id, i_extension);
return 1;
}
p_subdec = (dvbpsi_demux_subdec_t*)malloc(sizeof(dvbpsi_demux_subdec_t));
if(p_subdec == NULL)
{
return 1;
}
p_eit_decoder = (dvbpsi_atsc_eit_decoder_t*)malloc(sizeof(dvbpsi_atsc_eit_decoder_t));
if(p_eit_decoder == NULL)
{
free(p_subdec);
return 1;
}
/* subtable decoder configuration */
p_subdec->pf_callback = &dvbpsi_atsc_GatherEITSections;
p_subdec->p_cb_data = p_eit_decoder;
p_subdec->i_id = ((uint32_t)i_table_id << 16) | i_extension;
p_subdec->pf_detach = dvbpsi_atsc_DetachEIT;
/* Attach the subtable decoder to the demux */
p_subdec->p_next = p_demux->p_first_subdec;
p_demux->p_first_subdec = p_subdec;
/* EIT decoder information */
p_eit_decoder->pf_callback = pf_callback;
p_eit_decoder->p_cb_data = p_cb_data;
/* EIT decoder initial state */
p_eit_decoder->b_current_valid = 0;
p_eit_decoder->p_building_eit = NULL;
for(i = 0; i <= 255; i++)
p_eit_decoder->ap_sections[i] = NULL;
return 0;
}
/*****************************************************************************
* dvbpsi_atsc_DetachEIT
*****************************************************************************
* Close a EIT decoder.
*****************************************************************************/
void dvbpsi_atsc_DetachEIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id, uint16_t i_extension)
{
dvbpsi_demux_subdec_t* p_subdec;
dvbpsi_demux_subdec_t** pp_prev_subdec;
dvbpsi_atsc_eit_decoder_t* p_eit_decoder;
unsigned int i;
p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension);
if(p_demux == NULL)
{
DVBPSI_ERROR_ARG("EIT Decoder",
"No such EIT decoder (table_id == 0x%02x,"
"extension == 0x%04x)",
i_table_id, i_extension);
return;
}
p_eit_decoder = (dvbpsi_atsc_eit_decoder_t*)p_subdec->p_cb_data;
if (p_eit_decoder->p_building_eit)
{
free(p_eit_decoder->p_building_eit);
}
for(i = 0; i <= 255; i++)
{
if(p_eit_decoder->ap_sections[i])
dvbpsi_DeletePSISections(p_eit_decoder->ap_sections[i]);
}
free(p_subdec->p_cb_data);
pp_prev_subdec = &p_demux->p_first_subdec;
while(*pp_prev_subdec != p_subdec)
pp_prev_subdec = &(*pp_prev_subdec)->p_next;
*pp_prev_subdec = p_subdec->p_next;
free(p_subdec);
}
/*****************************************************************************
* dvbpsi_atsc_InitEIT
*****************************************************************************
* Initialize a pre-allocated dvbpsi_atsc_eit_t structure.
*****************************************************************************/
void dvbpsi_atsc_InitEIT(dvbpsi_atsc_eit_t* p_eit,uint8_t i_version, int b_current_next,
uint8_t i_protocol, uint16_t i_source_id)
{
p_eit->i_version = i_version;
p_eit->b_current_next = b_current_next;
p_eit->i_protocol = i_protocol;
p_eit->i_source_id = i_source_id;
p_eit->p_first_event = NULL;
}
/*****************************************************************************
* dvbpsi_atsc_EmptyEIT
*****************************************************************************
* Clean a dvbpsi_atsc_eit_t structure.
*****************************************************************************/
void dvbpsi_atsc_EmptyEIT(dvbpsi_atsc_eit_t* p_eit)
{
dvbpsi_atsc_eit_event_t* p_event = p_eit->p_first_event;
while(p_event != NULL)
{
dvbpsi_atsc_eit_event_t* p_tmp = p_event->p_next;
dvbpsi_DeleteDescriptors(p_event->p_first_descriptor);
free(p_event);
p_event = p_tmp;
}
p_eit->p_first_event = NULL;
}
/*****************************************************************************
* dvbpsi_atsc_EITAddChannel
*****************************************************************************
* Add a Channel description at the end of the EIT.
*****************************************************************************/
dvbpsi_atsc_eit_event_t *dvbpsi_atsc_EITAddEvent(dvbpsi_atsc_eit_t* p_eit,
uint16_t i_event_id,
uint32_t i_start_time,
uint8_t i_etm_location,
uint32_t i_length_seconds,
uint8_t i_title_length,
uint8_t *p_title)
{
dvbpsi_atsc_eit_event_t * p_event
= (dvbpsi_atsc_eit_event_t*)malloc(sizeof(dvbpsi_atsc_eit_event_t));
if(p_event)
{
p_event->i_event_id = i_event_id;
p_event->i_start_time = i_start_time;
p_event->i_etm_location = i_etm_location;
p_event->i_length_seconds = i_length_seconds;
p_event->i_title_length = i_title_length;
memcpy(p_event->i_title, p_title, i_title_length);
p_event->p_first_descriptor = NULL;
p_event->p_next = NULL;
if(p_eit->p_first_event== NULL)
{
p_eit->p_first_event = p_event;
}
else
{
dvbpsi_atsc_eit_event_t * p_last_event = p_eit->p_first_event;
while(p_last_event->p_next != NULL)
p_last_event = p_last_event->p_next;
p_last_event->p_next = p_event;
}
}
return p_event;
}
/*****************************************************************************
* dvbpsi_EITTableAddDescriptor
*****************************************************************************
* Add a descriptor in the EIT table description.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_atsc_EITChannelAddDescriptor(
dvbpsi_atsc_eit_event_t *p_event,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data)
{
dvbpsi_descriptor_t * p_descriptor
= dvbpsi_NewDescriptor(i_tag, i_length, p_data);
if(p_descriptor)
{
if(p_event->p_first_descriptor == NULL)
{
p_event->p_first_descriptor = p_descriptor;
}
else
{
dvbpsi_descriptor_t * p_last_descriptor = p_event->p_first_descriptor;
while(p_last_descriptor->p_next != NULL)
p_last_descriptor = p_last_descriptor->p_next;
p_last_descriptor->p_next = p_descriptor;
}
}
return p_descriptor;
}
/*****************************************************************************
* dvbpsi_atsc_GatherEITSections
*****************************************************************************
* Callback for the subtable demultiplexor.
*****************************************************************************/
void dvbpsi_atsc_GatherEITSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section)
{
dvbpsi_atsc_eit_decoder_t * p_eit_decoder
= (dvbpsi_atsc_eit_decoder_t*)p_private_decoder;
int b_append = 1;
int b_reinit = 0;
unsigned int i;
DVBPSI_DEBUG_ARG("EIT decoder",
"Table version %2d, " "i_table_id %2d, " "i_extension %5d, "
"section %3d up to %3d, " "current %1d",
p_section->i_version, p_section->i_table_id,
p_section->i_extension,
p_section->i_number, p_section->i_last_number,
p_section->b_current_next);
if(!p_section->b_syntax_indicator)
{
/* Invalid section_syntax_indicator */
DVBPSI_ERROR("EIT decoder",
"invalid section (section_syntax_indicator == 0)");
b_append = 0;
}
/* Now if b_append is true then we have a valid EIT section */
if(b_append)
{
/* TS discontinuity check */
if(p_psi_decoder->b_discontinuity)
{
b_reinit = 1;
p_psi_decoder->b_discontinuity = 0;
}
else
{
/* Perform a few sanity checks */
if(p_eit_decoder->p_building_eit)
{
if(p_eit_decoder->p_building_eit->i_source_id != p_section->i_extension)
{
/* transport_stream_id */
DVBPSI_ERROR("EIT decoder",
"'transport_stream_id' differs"
" whereas no TS discontinuity has occured");
b_reinit = 1;
}
else if(p_eit_decoder->p_building_eit->i_version
!= p_section->i_version)
{
/* version_number */
DVBPSI_ERROR("EIT decoder",
"'version_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
}
else if(p_eit_decoder->i_last_section_number !=
p_section->i_last_number)
{
/* last_section_number */
DVBPSI_ERROR("EIT decoder",
"'last_section_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
}
}
else
{
if( (p_eit_decoder->b_current_valid)
&& (p_eit_decoder->current_eit.i_version == p_section->i_version))
{
/* Signal a new EIT if the previous one wasn't active */
if( (!p_eit_decoder->current_eit.b_current_next)
&& (p_section->b_current_next))
{
dvbpsi_atsc_eit_t * p_eit = (dvbpsi_atsc_eit_t*)malloc(sizeof(dvbpsi_atsc_eit_t));
p_eit_decoder->current_eit.b_current_next = 1;
*p_eit = p_eit_decoder->current_eit;
p_eit_decoder->pf_callback(p_eit_decoder->p_cb_data, p_eit);
}
/* Don't decode since this version is already decoded */
b_append = 0;
}
}
}
}
/* Reinit the decoder if wanted */
if(b_reinit)
{
/* Force redecoding */
p_eit_decoder->b_current_valid = 0;
/* Free structures */
if(p_eit_decoder->p_building_eit)
{
free(p_eit_decoder->p_building_eit);
p_eit_decoder->p_building_eit = NULL;
}
/* Clear the section array */
for(i = 0; i <= 255; i++)
{
if(p_eit_decoder->ap_sections[i] != NULL)
{
dvbpsi_DeletePSISections(p_eit_decoder->ap_sections[i]);
p_eit_decoder->ap_sections[i] = NULL;
}
}
}
/* Append the section to the list if wanted */
if(b_append)
{
int b_complete;
/* Initialize the structures if it's the first section received */
if(!p_eit_decoder->p_building_eit)
{
dvbpsi_atsc_NewEIT(p_eit_decoder->p_building_eit,
p_section->i_version,
p_section->b_current_next,
p_section->p_payload_start[0],
p_section->i_extension);
p_eit_decoder->i_last_section_number = p_section->i_last_number;
}
/* Fill the section array */
if(p_eit_decoder->ap_sections[p_section->i_number] != NULL)
{
DVBPSI_DEBUG_ARG("EIT decoder", "overwrite section number %d",
p_section->i_number);
dvbpsi_DeletePSISections(p_eit_decoder->ap_sections[p_section->i_number]);
}
p_eit_decoder->ap_sections[p_section->i_number] = p_section;
/* Check if we have all the sections */
b_complete = 0;
for(i = 0; i <= p_eit_decoder->i_last_section_number; i++)
{
if(!p_eit_decoder->ap_sections[i])
break;
if(i == p_eit_decoder->i_last_section_number)
b_complete = 1;
}
if(b_complete)
{
/* Save the current information */
p_eit_decoder->current_eit = *p_eit_decoder->p_building_eit;
p_eit_decoder->b_current_valid = 1;
/* Chain the sections */
if(p_eit_decoder->i_last_section_number)
{
for(i = 0; i <= p_eit_decoder->i_last_section_number - 1; i++)
p_eit_decoder->ap_sections[i]->p_next =
p_eit_decoder->ap_sections[i + 1];
}
/* Decode the sections */
dvbpsi_atsc_DecodeEITSections(p_eit_decoder->p_building_eit,
p_eit_decoder->ap_sections[0]);
/* Delete the sections */
dvbpsi_DeletePSISections(p_eit_decoder->ap_sections[0]);
/* signal the new EIT */
p_eit_decoder->pf_callback(p_eit_decoder->p_cb_data,
p_eit_decoder->p_building_eit);
/* Reinitialize the structures */
p_eit_decoder->p_building_eit = NULL;
for(i = 0; i <= p_eit_decoder->i_last_section_number; i++)
p_eit_decoder->ap_sections[i] = NULL;
}
}
else
{
dvbpsi_DeletePSISections(p_section);
}
}
/*****************************************************************************
* dvbpsi_DecodeEITSection
*****************************************************************************
* EIT decoder.
*****************************************************************************/
void dvbpsi_atsc_DecodeEITSections(dvbpsi_atsc_eit_t* p_eit,
dvbpsi_psi_section_t* p_section)
{
uint8_t *p_byte, *p_end;
while(p_section)
{
uint16_t i_number_events = p_section->p_payload_start[1];
uint16_t i_events_count = 0;
uint16_t i_length = 0;
for(p_byte = p_section->p_payload_start + 2;
((p_byte + 4) < p_section->p_payload_end) && (i_events_count < i_number_events);
i_events_count ++)
{
dvbpsi_atsc_eit_event_t* p_event;
uint16_t i_event_id = ((uint16_t)(p_byte[0] & 0x3f) << 8) | ((uint16_t) p_byte[1]);
uint32_t i_start_time = ((uint32_t)(p_byte[2] << 24)) |
((uint32_t)(p_byte[3] << 16)) |
((uint32_t)(p_byte[4] << 8)) |
((uint32_t)(p_byte[5]));
uint8_t i_etm_location = (uint8_t)((p_byte[6] & 0x30) >> 4);
uint32_t i_length_seconds = ((uint32_t)((p_byte[6] & 0x0f) << 16)) |
((uint32_t)(p_byte[7] << 8)) |
((uint32_t)(p_byte[8]));
uint8_t i_title_length = p_byte[9];
p_byte += 10;
p_event = dvbpsi_atsc_EITAddEvent(p_eit, i_event_id, i_start_time,
i_etm_location, i_length_seconds, i_title_length,
p_byte);
p_byte += i_title_length;
i_length = ((uint16_t)(p_byte[0] & 0xf) <<8) | p_byte[1];
/* Table descriptors */
p_byte += 2;
p_end = p_byte + i_length;
if( p_end > p_section->p_payload_end ) break;
while(p_byte + 2 <= p_end)
{
uint8_t i_tag = p_byte[0];
uint8_t i_length = p_byte[1];
if(i_length + 2 <= p_end - p_byte)
dvbpsi_atsc_EITChannelAddDescriptor(p_event, i_tag, i_length, p_byte + 2);
p_byte += 2 + i_length;
}
}
p_section = p_section->p_next;
}
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
eit.h
Decode PSIP Event Information Table.
*/
#ifndef _ATSC_EIT_H
#define _ATSC_EIT_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_atsc_eit_event_t
*****************************************************************************/
/*!
* \struct dvbpsi_atsc_eit_event_s
* \brief EIT Event structure.
*
* This structure is used to store decoded event information.
*/
/*!
* \typedef struct dvbpsi_atsc_eit_event_s dvbpsi_atsc_eit_event_t
* \brief dvbpsi_atsc_eit_event_t type definition.
*/
typedef struct dvbpsi_atsc_eit_event_s
{
uint16_t i_event_id; /*!< Event ID */
uint32_t i_start_time; /*!< Start time in GPS seconds */
uint8_t i_etm_location; /*!< Extended Text Message location. */
uint32_t i_length_seconds;/*!< Length of program in seconds. */
uint8_t i_title_length; /*!< Length of the title in bytes */
uint8_t i_title[256]; /*!< Title in multiple string structure format. */
dvbpsi_descriptor_t *p_first_descriptor; /*!< First descriptor structure. */
struct dvbpsi_atsc_eit_event_s *p_next;/*!< Next event information structure. */
} dvbpsi_atsc_eit_event_t;
/*****************************************************************************
* dvbpsi_atsc_eit_t
*****************************************************************************/
/*!
* \struct dvbpsi_atsc_eit_s
* \brief EIT structure.
*
* This structure is used to store a decoded EIT.
*/
/*!
* \typedef struct dvbpsi_atsc_eit_s dvbpsi_atsc_eit_t
* \brief dvbpsi_atsc_eit_t type definition.
*/
typedef struct dvbpsi_atsc_eit_s
{
uint8_t i_version; /*!< version_number */
int b_current_next; /*!< current_next_indicator */
uint16_t i_source_id; /*!< Source id used to match against channels */
uint8_t i_protocol; /*!< PSIP Protocol version */
dvbpsi_atsc_eit_event_t *p_first_event; /*!< First event information structure. */
} dvbpsi_atsc_eit_t;
/*****************************************************************************
* dvbpsi_eit_callback
*****************************************************************************/
/*!
* \typedef void (* dvbpsi_atsc_eit_callback)(void* p_cb_data,
dvbpsi_atsc_eit_t* p_new_eit)
* \brief Callback type definition.
*/
typedef void (* dvbpsi_atsc_eit_callback)(void* p_cb_data, dvbpsi_atsc_eit_t* p_new_eit);
/*****************************************************************************
* dvbpsi_atsc_AttachEIT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_AttachEIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
dvbpsi_atsc_eit_callback pf_callback, void* p_cb_data)
*
* \brief Creation and initialization of a EIT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0xCB.
* \param i_extension Table ID extension, here TS ID.
* \param pf_callback function to call back on new EIT.
* \param p_cb_data private data given in argument to the callback.
* \return 0 if everything went ok.
*/
int dvbpsi_atsc_AttachEIT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
uint16_t i_extension, dvbpsi_atsc_eit_callback pf_callback, void* p_cb_data);
/*****************************************************************************
* dvbpsi_DetachEIT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_DetachEIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id)
*
* \brief Destroy a EIT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0xCB.
* \param i_extension Table ID extension, here TS ID.
* \return nothing.
*/
void dvbpsi_atsc_DetachEIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
uint16_t i_extension);
/*****************************************************************************
* dvbpsi_atsc_InitEIT/dvbpsi_atsc_NewEIT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_InitEIT(dvbpsi_atsc_eit_t* p_eit, uint8_t i_version,
int b_current_next, uint8_t i_protocol, uint16_t i_source_id)
* \brief Initialize a user-allocated dvbpsi_atsc_eit_t structure.
* \param p_eit pointer to the EIT structure
* \param i_version EIT version
* \param b_current_next current next indicator
* \param i_protocol PSIP Protocol version.
* \param i_source_id Source id.
* \return nothing.
*/
void dvbpsi_atsc_InitEIT(dvbpsi_atsc_eit_t* p_eit,uint8_t i_version, int b_current_next,
uint8_t i_protocol, uint16_t i_source_id);
/*!
* \def dvbpsi_atsc_NewEIT(p_eit, i_network_id, i_version, b_current_next,
i_protocol i_source_id)
* \brief Allocate and initialize a new dvbpsi_eit_t structure. Use ObjectRefDec to delete it.
* \param p_eit pointer to the EIT structure
* \param i_network_id network id
* \param i_version EIT version
* \param b_current_next current next indicator
* \param i_protocol PSIP Protocol version.
* \param b_cable_eit Whether this is CEIT or a TEIT.
* \return nothing.
*/
#define dvbpsi_atsc_NewEIT(p_eit, i_version, b_current_next, i_protocol, \
i_source_id) \
do { \
p_eit = (dvbpsi_atsc_eit_t*)malloc(sizeof(dvbpsi_atsc_eit_t)); \
if(p_eit != NULL) \
dvbpsi_atsc_InitEIT(p_eit, i_version, b_current_next, i_protocol, \
i_source_id); \
} while(0);
/*****************************************************************************
* dvbpsi_atsc_EmptyEIT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_EmptyEIT(dvbpsi_atsc_eit_t* p_eit)
* \brief Clean a dvbpsi_eit_t structure.
* \param p_eit pointer to the EIT structure
* \return nothing.
*/
void dvbpsi_atsc_EmptyEIT(dvbpsi_atsc_eit_t *p_eit);
/*!
* \def dvbpsi_atsc_DeleteEIT(p_eit)
* \brief Clean and free a dvbpsi_eit_t structure.
* \param p_vct pointer to the EIT structure
* \return nothing.
*/
#define dvbpsi_atsc_DeleteEIT(p_eit) \
do { \
dvbpsi_atsc_EmptyEIT(p_eit); \
free(p_eit); \
} while(0);
#ifdef __cplusplus
};
#endif
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
stt.c
Decode PSIP System Time Table.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "dvbpsi_private.h"
#include "psi.h"
#include "descriptor.h"
#include "demux.h"
#include "atsc_stt.h"
typedef struct dvbpsi_atsc_stt_decoder_s
{
dvbpsi_atsc_stt_callback pf_callback;
void * p_cb_data;
} dvbpsi_atsc_stt_decoder_t;
dvbpsi_descriptor_t *dvbpsi_atsc_STTAddDescriptor(
dvbpsi_atsc_stt_t *p_stt,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data);
void dvbpsi_atsc_GatherSTTSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section);
void dvbpsi_atsc_DecodeSTTSections(dvbpsi_atsc_stt_t* p_stt,
dvbpsi_psi_section_t* p_section);
/*****************************************************************************
* dvbpsi_atsc_AttachSTT
*****************************************************************************
* Initialize a STT subtable decoder.
*****************************************************************************/
int dvbpsi_atsc_AttachSTT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
dvbpsi_atsc_stt_callback pf_callback, void* p_cb_data)
{
dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_psi_decoder->p_private_decoder;
dvbpsi_demux_subdec_t* p_subdec;
dvbpsi_atsc_stt_decoder_t* p_stt_decoder;
if(dvbpsi_demuxGetSubDec(p_demux, i_table_id, 0))
{
DVBPSI_ERROR_ARG("STT decoder",
"Already a decoder for (table_id == 0x%02x)",
i_table_id);
return 1;
}
p_subdec = (dvbpsi_demux_subdec_t*)malloc(sizeof(dvbpsi_demux_subdec_t));
if(p_subdec == NULL)
{
return 1;
}
p_stt_decoder = (dvbpsi_atsc_stt_decoder_t*)malloc(sizeof(dvbpsi_atsc_stt_decoder_t));
if(p_stt_decoder == NULL)
{
free(p_subdec);
return 1;
}
/* subtable decoder configuration */
p_subdec->pf_callback = &dvbpsi_atsc_GatherSTTSections;
p_subdec->p_cb_data = p_stt_decoder;
p_subdec->i_id = (uint32_t)i_table_id << 16;
p_subdec->pf_detach = dvbpsi_atsc_DetachSTT;
/* Attach the subtable decoder to the demux */
p_subdec->p_next = p_demux->p_first_subdec;
p_demux->p_first_subdec = p_subdec;
/* STT decoder information */
p_stt_decoder->pf_callback = pf_callback;
p_stt_decoder->p_cb_data = p_cb_data;
return 0;
}
/*****************************************************************************
* dvbpsi_atsc_DetachSTT
*****************************************************************************
* Close a STT decoder.
*****************************************************************************/
void dvbpsi_atsc_DetachSTT(dvbpsi_demux_t * p_demux, uint8_t i_table_id, uint16_t i_extension)
{
dvbpsi_demux_subdec_t* p_subdec;
dvbpsi_demux_subdec_t** pp_prev_subdec;
dvbpsi_atsc_stt_decoder_t* p_stt_decoder;
p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, 0);
if(p_demux == NULL)
{
DVBPSI_ERROR_ARG("STT Decoder",
"No such STT decoder (table_id == 0x%02x,"
"extension == 0x00)",
i_table_id);
return;
}
p_stt_decoder = (dvbpsi_atsc_stt_decoder_t*)p_subdec->p_cb_data;
free(p_subdec->p_cb_data);
pp_prev_subdec = &p_demux->p_first_subdec;
while(*pp_prev_subdec != p_subdec)
pp_prev_subdec = &(*pp_prev_subdec)->p_next;
*pp_prev_subdec = p_subdec->p_next;
free(p_subdec);
}
/*****************************************************************************
* dvbpsi_atsc_InitSTT
*****************************************************************************
* Initialize a pre-allocated dvbpsi_atsc_stt_t structure.
*****************************************************************************/
void dvbpsi_atsc_InitSTT(dvbpsi_atsc_stt_t *p_stt, uint8_t i_protocol)
{
p_stt->i_protocol = i_protocol;
p_stt->p_first_descriptor = NULL;
}
/*****************************************************************************
* dvbpsi_atsc_EmptySTT
*****************************************************************************
* Clean a dvbpsi_atsc_stt_t structure.
*****************************************************************************/
void dvbpsi_atsc_EmptySTT(dvbpsi_atsc_stt_t* p_stt)
{
dvbpsi_DeleteDescriptors(p_stt->p_first_descriptor);
p_stt->p_first_descriptor = NULL;
}
/*****************************************************************************
* dvbpsi_atsc_STTAddDescriptor
*****************************************************************************
* Add a descriptor to the STT table.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_atsc_STTAddDescriptor(
dvbpsi_atsc_stt_t *p_stt,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data)
{
dvbpsi_descriptor_t * p_descriptor
= dvbpsi_NewDescriptor(i_tag, i_length, p_data);
if(p_descriptor)
{
if(p_stt->p_first_descriptor == NULL)
{
p_stt->p_first_descriptor = p_descriptor;
}
else
{
dvbpsi_descriptor_t * p_last_descriptor = p_stt->p_first_descriptor;
while(p_last_descriptor->p_next != NULL)
p_last_descriptor = p_last_descriptor->p_next;
p_last_descriptor->p_next = p_descriptor;
}
}
return p_descriptor;
}
/*****************************************************************************
* dvbpsi_atsc_GatherSTTSections
*****************************************************************************
* Callback for the subtable demultiplexor.
*****************************************************************************/
void dvbpsi_atsc_GatherSTTSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section)
{
dvbpsi_atsc_stt_decoder_t * p_stt_decoder
= (dvbpsi_atsc_stt_decoder_t*)p_private_decoder;
dvbpsi_atsc_stt_t *p_stt;
if(!p_section->b_syntax_indicator)
{
/* Invalid section_syntax_indicator */
DVBPSI_ERROR("STT decoder",
"invalid section (section_syntax_indicator == 0)");
}
else
{
dvbpsi_atsc_NewSTT(p_stt, p_section->p_payload_start[0]);
if (p_stt)
{
/* Decode the sections */
dvbpsi_atsc_DecodeSTTSections(p_stt,
p_section);
/* Delete the sections */
dvbpsi_DeletePSISections(p_section);
/* signal the new STT */
p_stt_decoder->pf_callback(p_stt_decoder->p_cb_data,
p_stt);
}
}
}
/*****************************************************************************
* dvbpsi_DecodeSTTSection
*****************************************************************************
* STT decoder.
*****************************************************************************/
void dvbpsi_atsc_DecodeSTTSections(dvbpsi_atsc_stt_t* p_stt,
dvbpsi_psi_section_t* p_section)
{
uint8_t *p_byte, *p_end;
uint16_t i_length = 0;
p_byte = p_section->p_payload_start + 1;
p_stt->i_system_time = (((uint32_t)p_byte[0]) << 24) |
(((uint32_t)p_byte[1]) << 16) |
(((uint32_t)p_byte[2]) << 8) |
((uint32_t)p_byte[3]);
p_stt->i_gps_utc_offset = p_byte[4];
p_stt->i_daylight_savings = (((uint16_t)p_byte[5]) << 16) |
((uint16_t)p_byte[6]);
p_byte += 7;
/* Table descriptors */
i_length = (p_section->i_length - 17);
p_end = p_byte + i_length;
while(p_byte + 2 <= p_end)
{
uint8_t i_tag = p_byte[0];
uint8_t i_length = p_byte[1];
if(i_length + 2 <= p_end - p_byte)
dvbpsi_atsc_STTAddDescriptor(p_stt, i_tag, i_length, p_byte + 2);
p_byte += 2 + i_length;
}
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
stt.h
Decode PSIP System Time Table.
*/
#ifndef _ATSC_STT_H
#define _ATSC_STT_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_atsc_stt_t
*****************************************************************************/
/*!
* \struct dvbpsi_atsc_stt_s
* \brief STT structure.
*
* This structure is used to store a decoded STT.
*/
/*!
* \typedef struct dvbpsi_atsc_stt_s dvbpsi_atsc_stt_t
* \brief dvbpsi_atsc_stt_t type definition.
*/
typedef struct dvbpsi_atsc_stt_s
{
uint8_t i_protocol; /*!< PSIP Protocol version */
uint32_t i_system_time; /*!< GPS seconds since 1 January 1980 00:00:00 UTC. */
uint8_t i_gps_utc_offset; /*!< Seconds offset between GPS and UTC time. */
uint16_t i_daylight_savings; /*!< Daylight savings control bytes. */
dvbpsi_descriptor_t *p_first_descriptor; /*!< First descriptor. */
} dvbpsi_atsc_stt_t;
/*****************************************************************************
* dvbpsi_atsc_stt_callback
*****************************************************************************/
/*!
* \typedef void (* dvbpsi_atsc_stt_callback)(void* p_cb_data,
dvbpsi_atsc_stt_t* p_new_stt)
* \brief Callback type definition.
*/
typedef void (* dvbpsi_atsc_stt_callback)(void* p_cb_data, dvbpsi_atsc_stt_t* p_new_stt);
/*****************************************************************************
* dvbpsi_atsc_AttachSTT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_AttachSTT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
dvbpsi_atsc_stt_callback pf_callback, void* p_cb_data)
*
* \brief Creation and initialization of a STT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0xCD.
* \param pf_callback function to call back on new STT.
* \param p_cb_data private data given in argument to the callback.
* \return 0 if everything went ok.
*/
int dvbpsi_atsc_AttachSTT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
dvbpsi_atsc_stt_callback pf_callback, void* p_cb_data);
/*****************************************************************************
* dvbpsi_atsc_DetachSTT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_DetachSTT(dvbpsi_demux_t * p_demux, uint8_t i_table_id)
*
* \brief Destroy a STT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0xCD.
* \param i_extension Table extension, ignored as this should always be 0.
* (Required to match prototype for demux)
* \return nothing.
*/
void dvbpsi_atsc_DetachSTT(dvbpsi_demux_t * p_demux, uint8_t i_table_id, uint16_t i_externsion);
/*****************************************************************************
* dvbpsi_atsc_InitSTT/dvbpsi_atsc_NewSTT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_InitSTT(dvbpsi_atsc_stt_t* p_stt, uint8_t i_version,
int b_current_next, uint8_t i_protocol)
* \brief Initialize a user-allocated dvbpsi_atsc_stt_t structure.
* \param p_stt pointer to the STT structure
* \param i_protocol PSIP Protocol version.
* \return nothing.
*/
void dvbpsi_atsc_InitSTT(dvbpsi_atsc_stt_t *p_stt,uint8_t i_protocol);
/*!
* \def dvbpsi_NewSTT(p_stt, i_network_id, i_version, b_current_next)
* \brief Allocate and initialize a new dvbpsi_atsc_stt_t structure. Use ObjectRefDec to delete it.
* \param p_stt pointer to the STT structure
* \param i_protocol PSIP Protocol version.
* \return nothing.
*/
#define dvbpsi_atsc_NewSTT(p_stt, i_protocol) \
do { \
p_stt = (dvbpsi_atsc_stt_t*)malloc(sizeof(dvbpsi_atsc_stt_t)); \
if(p_stt != NULL) \
dvbpsi_atsc_InitSTT(p_stt, i_protocol); \
} while(0);
/*****************************************************************************
* dvbpsi_atsc_EmptySTT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_EmptySTT(dvbpsi_atsc_stt_t* p_stt)
* \brief Clean a dvbpsi_atsc_stt_t structure.
* \param p_stt pointer to the STT structure
* \return nothing.
*/
void dvbpsi_atsc_EmptySTT(dvbpsi_atsc_stt_t *p_stt);
/*!
* \def dvbpsi_atsc_DeleteSTT(p_vct)
* \brief Clean and free a dvbpsi_stt_t structure.
* \param p_vct pointer to the STT structure
* \return nothing.
*/
#define dvbpsi_atsc_DeleteSTT(p_stt) \
do { \
dvbpsi_atsc_EmptySTT(p_stt); \
free(p_stt); \
} while(0);
#ifdef __cplusplus
};
#endif
#endif
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
vct.c
Decode PSIP Virtual Channel Table.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dvbpsi.h"
#include "dvbpsi_private.h"
#include "psi.h"
#include "descriptor.h"
#include "demux.h"
#include "atsc_vct.h"
typedef struct dvbpsi_atsc_vct_decoder_s
{
dvbpsi_atsc_vct_callback pf_callback;
void * p_cb_data;
dvbpsi_atsc_vct_t current_vct;
dvbpsi_atsc_vct_t * p_building_vct;
int b_current_valid;
uint8_t i_last_section_number;
dvbpsi_psi_section_t * ap_sections [256];
} dvbpsi_atsc_vct_decoder_t;
dvbpsi_descriptor_t *dvbpsi_atsc_VCTAddDescriptor(
dvbpsi_atsc_vct_t *p_vct,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data);
dvbpsi_atsc_vct_channel_t *dvbpsi_atsc_VCTAddChannel(dvbpsi_atsc_vct_t* p_vct,
uint8_t *p_short_name,
uint16_t i_major_number,
uint16_t i_minor_number,
uint8_t i_modulation,
uint32_t i_carrier_freq,
uint16_t i_channel_tsid,
uint16_t i_program_number,
uint8_t i_etm_location,
int b_access_controlled,
int b_hidden,
int b_path_select,
int b_out_of_band,
int b_hide_guide,
uint8_t i_service_type,
uint16_t i_source_id);
dvbpsi_descriptor_t *dvbpsi_atsc_VCTChannelAddDescriptor(
dvbpsi_atsc_vct_channel_t *p_table,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data);
void dvbpsi_atsc_GatherVCTSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section);
void dvbpsi_atsc_DecodeVCTSections(dvbpsi_atsc_vct_t* p_vct,
dvbpsi_psi_section_t* p_section);
/*****************************************************************************
* dvbpsi_atsc_AttachVCT
*****************************************************************************
* Initialize a VCT subtable decoder.
*****************************************************************************/
int dvbpsi_atsc_AttachVCT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id, uint16_t i_extension,
dvbpsi_atsc_vct_callback pf_callback, void* p_cb_data)
{
dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_psi_decoder->p_private_decoder;
dvbpsi_demux_subdec_t* p_subdec;
dvbpsi_atsc_vct_decoder_t* p_vct_decoder;
unsigned int i;
if(dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension))
{
DVBPSI_ERROR_ARG("VCT decoder",
"Already a decoder for (table_id == 0x%02x extension == 0x%04x)",
i_table_id, i_extension);
return 1;
}
p_subdec = (dvbpsi_demux_subdec_t*)malloc(sizeof(dvbpsi_demux_subdec_t));
if(p_subdec == NULL)
{
return 1;
}
p_vct_decoder = (dvbpsi_atsc_vct_decoder_t*)malloc(sizeof(dvbpsi_atsc_vct_decoder_t));
if(p_vct_decoder == NULL)
{
free(p_subdec);
return 1;
}
/* subtable decoder configuration */
p_subdec->pf_callback = &dvbpsi_atsc_GatherVCTSections;
p_subdec->p_cb_data = p_vct_decoder;
p_subdec->i_id = ((uint32_t)i_table_id << 16) | i_extension;
p_subdec->pf_detach = dvbpsi_atsc_DetachVCT;
/* Attach the subtable decoder to the demux */
p_subdec->p_next = p_demux->p_first_subdec;
p_demux->p_first_subdec = p_subdec;
/* VCT decoder information */
p_vct_decoder->pf_callback = pf_callback;
p_vct_decoder->p_cb_data = p_cb_data;
/* VCT decoder initial state */
p_vct_decoder->b_current_valid = 0;
p_vct_decoder->p_building_vct = NULL;
for(i = 0; i <= 255; i++)
p_vct_decoder->ap_sections[i] = NULL;
return 0;
}
/*****************************************************************************
* dvbpsi_atsc_DetachVCT
*****************************************************************************
* Close a VCT decoder.
*****************************************************************************/
void dvbpsi_atsc_DetachVCT(dvbpsi_demux_t * p_demux, uint8_t i_table_id, uint16_t i_extension)
{
dvbpsi_demux_subdec_t* p_subdec;
dvbpsi_demux_subdec_t** pp_prev_subdec;
dvbpsi_atsc_vct_decoder_t* p_vct_decoder;
unsigned int i;
p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension);
if(p_demux == NULL)
{
DVBPSI_ERROR_ARG("VCT Decoder",
"No such VCT decoder (table_id == 0x%02x,"
"extension == 0x%04x)",
i_table_id, i_extension);
return;
}
p_vct_decoder = (dvbpsi_atsc_vct_decoder_t*)p_subdec->p_cb_data;
if (p_vct_decoder->p_building_vct)
{
free(p_vct_decoder->p_building_vct);
}
for(i = 0; i <= 255; i++)
{
if(p_vct_decoder->ap_sections[i])
dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[i]);
}
free(p_subdec->p_cb_data);
pp_prev_subdec = &p_demux->p_first_subdec;
while(*pp_prev_subdec != p_subdec)
pp_prev_subdec = &(*pp_prev_subdec)->p_next;
*pp_prev_subdec = p_subdec->p_next;
free(p_subdec);
}
/*****************************************************************************
* dvbpsi_atsc_InitVCT
*****************************************************************************
* Initialize a pre-allocated dvbpsi_atsc_vct_t structure.
*****************************************************************************/
void dvbpsi_atsc_InitVCT(dvbpsi_atsc_vct_t* p_vct,uint8_t i_version, int b_current_next,
uint8_t i_protocol, uint16_t i_ts_id, int b_cable_vct)
{
p_vct->i_version = i_version;
p_vct->b_current_next = b_current_next;
p_vct->i_protocol = i_protocol;
p_vct->i_ts_id = i_ts_id;
p_vct->b_cable_vct = b_cable_vct;
p_vct->p_first_channel = NULL;
p_vct->p_first_descriptor = NULL;
}
/*****************************************************************************
* dvbpsi_atsc_EmptyVCT
*****************************************************************************
* Clean a dvbpsi_atsc_vct_t structure.
*****************************************************************************/
void dvbpsi_atsc_EmptyVCT(dvbpsi_atsc_vct_t* p_vct)
{
dvbpsi_atsc_vct_channel_t* p_channel = p_vct->p_first_channel;
while(p_channel != NULL)
{
dvbpsi_atsc_vct_channel_t* p_tmp = p_channel->p_next;
dvbpsi_DeleteDescriptors(p_channel->p_first_descriptor);
free(p_channel);
p_channel = p_tmp;
}
dvbpsi_DeleteDescriptors(p_vct->p_first_descriptor);
p_vct->p_first_channel = NULL;
p_vct->p_first_descriptor = NULL;
}
/*****************************************************************************
* dvbpsi_atsc_VCTAddDescriptor
*****************************************************************************
* Add a descriptor to the VCT table.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_atsc_VCTAddDescriptor(
dvbpsi_atsc_vct_t *p_vct,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data)
{
dvbpsi_descriptor_t * p_descriptor
= dvbpsi_NewDescriptor(i_tag, i_length, p_data);
if(p_descriptor)
{
if(p_vct->p_first_descriptor == NULL)
{
p_vct->p_first_descriptor = p_descriptor;
}
else
{
dvbpsi_descriptor_t * p_last_descriptor = p_vct->p_first_descriptor;
while(p_last_descriptor->p_next != NULL)
p_last_descriptor = p_last_descriptor->p_next;
p_last_descriptor->p_next = p_descriptor;
}
}
return p_descriptor;
}
/*****************************************************************************
* dvbpsi_atsc_VCTAddChannel
*****************************************************************************
* Add a Channel description at the end of the VCT.
*****************************************************************************/
dvbpsi_atsc_vct_channel_t *dvbpsi_atsc_VCTAddChannel(dvbpsi_atsc_vct_t* p_vct,
uint8_t *p_short_name,
uint16_t i_major_number,
uint16_t i_minor_number,
uint8_t i_modulation,
uint32_t i_carrier_freq,
uint16_t i_channel_tsid,
uint16_t i_program_number,
uint8_t i_etm_location,
int b_access_controlled,
int b_hidden,
int b_path_select,
int b_out_of_band,
int b_hide_guide,
uint8_t i_service_type,
uint16_t i_source_id)
{
dvbpsi_atsc_vct_channel_t * p_channel
= (dvbpsi_atsc_vct_channel_t*)malloc(sizeof(dvbpsi_atsc_vct_channel_t));
if(p_channel)
{
memcpy(p_channel->i_short_name, p_short_name, sizeof(uint16_t) * 7);
p_channel->i_major_number = i_major_number;
p_channel->i_minor_number = i_minor_number;
p_channel->i_modulation = i_modulation;
p_channel->i_carrier_freq = i_carrier_freq;
p_channel->i_channel_tsid = i_channel_tsid;
p_channel->i_program_number = i_program_number;
p_channel->i_etm_location = i_etm_location;
p_channel->b_access_controlled = b_access_controlled;
p_channel->b_path_select = b_path_select;
p_channel->b_out_of_band = b_out_of_band;
p_channel->b_hidden = b_hidden;
p_channel->b_hide_guide = b_hide_guide;
p_channel->i_service_type = i_service_type;
p_channel->i_source_id = i_source_id;
p_channel->p_first_descriptor = NULL;
p_channel->p_next = NULL;
if(p_vct->p_first_channel== NULL)
{
p_vct->p_first_channel = p_channel;
}
else
{
dvbpsi_atsc_vct_channel_t * p_last_channel = p_vct->p_first_channel;
while(p_last_channel->p_next != NULL)
p_last_channel = p_last_channel->p_next;
p_last_channel->p_next = p_channel;
}
}
return p_channel;
}
/*****************************************************************************
* dvbpsi_VCTTableAddDescriptor
*****************************************************************************
* Add a descriptor in the VCT table description.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_atsc_VCTChannelAddDescriptor(
dvbpsi_atsc_vct_channel_t *p_channel,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data)
{
dvbpsi_descriptor_t * p_descriptor
= dvbpsi_NewDescriptor(i_tag, i_length, p_data);
if(p_descriptor)
{
if(p_channel->p_first_descriptor == NULL)
{
p_channel->p_first_descriptor = p_descriptor;
}
else
{
dvbpsi_descriptor_t * p_last_descriptor = p_channel->p_first_descriptor;
while(p_last_descriptor->p_next != NULL)
p_last_descriptor = p_last_descriptor->p_next;
p_last_descriptor->p_next = p_descriptor;
}
}
return p_descriptor;
}
/*****************************************************************************
* dvbpsi_atsc_GatherVCTSections
*****************************************************************************
* Callback for the subtable demultiplexor.
*****************************************************************************/
void dvbpsi_atsc_GatherVCTSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section)
{
dvbpsi_atsc_vct_decoder_t * p_vct_decoder
= (dvbpsi_atsc_vct_decoder_t*)p_private_decoder;
int b_append = 1;
int b_reinit = 0;
unsigned int i;
DVBPSI_DEBUG_ARG("VCT decoder",
"Table version %2d, " "i_table_id %2d, " "i_extension %5d, "
"section %3d up to %3d, " "current %1d",
p_section->i_version, p_section->i_table_id,
p_section->i_extension,
p_section->i_number, p_section->i_last_number,
p_section->b_current_next);
if(!p_section->b_syntax_indicator)
{
/* Invalid section_syntax_indicator */
DVBPSI_ERROR("VCT decoder",
"invalid section (section_syntax_indicator == 0)");
b_append = 0;
}
/* Now if b_append is true then we have a valid VCT section */
if(b_append)
{
/* TS discontinuity check */
if(p_psi_decoder->b_discontinuity)
{
b_reinit = 1;
p_psi_decoder->b_discontinuity = 0;
}
else
{
/* Perform a few sanity checks */
if(p_vct_decoder->p_building_vct)
{
if(p_vct_decoder->p_building_vct->i_ts_id != p_section->i_extension)
{
/* transport_stream_id */
DVBPSI_ERROR("VCT decoder",
"'transport_stream_id' differs"
" whereas no TS discontinuity has occured");
b_reinit = 1;
}
else if(p_vct_decoder->p_building_vct->i_version
!= p_section->i_version)
{
/* version_number */
DVBPSI_ERROR("VCT decoder",
"'version_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
}
else if(p_vct_decoder->i_last_section_number !=
p_section->i_last_number)
{
/* last_section_number */
DVBPSI_ERROR("VCT decoder",
"'last_section_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
}
}
else
{
if( (p_vct_decoder->b_current_valid)
&& (p_vct_decoder->current_vct.i_version == p_section->i_version))
{
/* Signal a new VCT if the previous one wasn't active */
if( (!p_vct_decoder->current_vct.b_current_next)
&& (p_section->b_current_next))
{
dvbpsi_atsc_vct_t * p_vct = (dvbpsi_atsc_vct_t*)malloc(sizeof(dvbpsi_atsc_vct_t));
p_vct_decoder->current_vct.b_current_next = 1;
*p_vct = p_vct_decoder->current_vct;
p_vct_decoder->pf_callback(p_vct_decoder->p_cb_data, p_vct);
}
/* Don't decode since this version is already decoded */
b_append = 0;
}
}
}
}
/* Reinit the decoder if wanted */
if(b_reinit)
{
/* Force redecoding */
p_vct_decoder->b_current_valid = 0;
/* Free structures */
if(p_vct_decoder->p_building_vct)
{
free(p_vct_decoder->p_building_vct);
p_vct_decoder->p_building_vct = NULL;
}
/* Clear the section array */
for(i = 0; i <= 255; i++)
{
if(p_vct_decoder->ap_sections[i] != NULL)
{
dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[i]);
p_vct_decoder->ap_sections[i] = NULL;
}
}
}
/* Append the section to the list if wanted */
if(b_append)
{
int b_complete;
/* Initialize the structures if it's the first section received */
if(!p_vct_decoder->p_building_vct)
{
p_vct_decoder->p_building_vct =
(dvbpsi_atsc_vct_t*)malloc(sizeof(dvbpsi_atsc_vct_t));
dvbpsi_atsc_InitVCT(p_vct_decoder->p_building_vct,
p_section->i_version,
p_section->b_current_next,
p_section->p_payload_start[0],
p_section->i_extension,
p_section->i_table_id == 0xC9);
p_vct_decoder->i_last_section_number = p_section->i_last_number;
}
/* Fill the section array */
if(p_vct_decoder->ap_sections[p_section->i_number] != NULL)
{
DVBPSI_DEBUG_ARG("VCT decoder", "overwrite section number %d",
p_section->i_number);
dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[p_section->i_number]);
}
p_vct_decoder->ap_sections[p_section->i_number] = p_section;
/* Check if we have all the sections */
b_complete = 0;
for(i = 0; i <= p_vct_decoder->i_last_section_number; i++)
{
if(!p_vct_decoder->ap_sections[i])
break;
if(i == p_vct_decoder->i_last_section_number)
b_complete = 1;
}
if(b_complete)
{
/* Save the current information */
p_vct_decoder->current_vct = *p_vct_decoder->p_building_vct;
p_vct_decoder->b_current_valid = 1;
/* Chain the sections */
if(p_vct_decoder->i_last_section_number)
{
for(i = 0; i <= p_vct_decoder->i_last_section_number - 1; i++)
p_vct_decoder->ap_sections[i]->p_next =
p_vct_decoder->ap_sections[i + 1];
}
/* Decode the sections */
dvbpsi_atsc_DecodeVCTSections(p_vct_decoder->p_building_vct,
p_vct_decoder->ap_sections[0]);
/* Delete the sections */
dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[0]);
/* signal the new VCT */
p_vct_decoder->pf_callback(p_vct_decoder->p_cb_data,
p_vct_decoder->p_building_vct);
/* Reinitialize the structures */
p_vct_decoder->p_building_vct = NULL;
for(i = 0; i <= p_vct_decoder->i_last_section_number; i++)
p_vct_decoder->ap_sections[i] = NULL;
}
}
else
{
dvbpsi_DeletePSISections(p_section);
}
}
/*****************************************************************************
* dvbpsi_DecodeVCTSection
*****************************************************************************
* VCT decoder.
*****************************************************************************/
void dvbpsi_atsc_DecodeVCTSections(dvbpsi_atsc_vct_t* p_vct,
dvbpsi_psi_section_t* p_section)
{
uint8_t *p_byte, *p_end;
while(p_section)
{
uint16_t i_channels_defined = p_section->p_payload_start[1];
uint16_t i_channels_count = 0;
uint16_t i_length = 0;
for(p_byte = p_section->p_payload_start + 2;
((p_byte + 6) < p_section->p_payload_end) && (i_channels_count < i_channels_defined);
i_channels_count ++)
{
dvbpsi_atsc_vct_channel_t* p_channel;
uint16_t i_major_number = ((uint16_t)(p_byte[14] & 0xf) << 6) | ((uint16_t)(p_byte[15] & 0xfc) >> 2);
uint16_t i_minor_number = ((uint16_t)(p_byte[15] & 0x3) << 8) | ((uint16_t) p_byte[16]);
uint8_t i_modulation = p_byte[17];
uint32_t i_carrier_freq = ((uint32_t)(p_byte[18] << 24)) |
((uint32_t)(p_byte[19] << 16)) |
((uint32_t)(p_byte[20] << 8)) |
((uint32_t)(p_byte[21]));
uint16_t i_channel_tsid = ((uint16_t)(p_byte[22] << 8)) | ((uint16_t)p_byte[23]);
uint16_t i_program_number = ((uint16_t)(p_byte[24] << 8)) | ((uint16_t)p_byte[25]);
uint8_t i_etm_location = (uint8_t)((p_byte[26] & 0xC0) >> 6);
int b_access_controlled = (p_byte[26] & 0x20) >> 5;
int b_hidden = (p_byte[26] & 0x10) >> 4;
int b_path_select = (p_byte[26] & 0x08) >> 3;
int b_out_of_band = (p_byte[26] & 0x04) >> 2;
int b_hide_guide = (p_byte[26] & 0x02) >> 1;
uint8_t i_service_type = (uint8_t)(p_byte[27] & 0x3f);
uint16_t i_source_id = ((uint16_t)(p_byte[28] << 8)) | ((uint16_t)p_byte[29]);
i_length = ((uint16_t)(p_byte[30] & 0x3) <<8) | p_byte[31];
p_channel = dvbpsi_atsc_VCTAddChannel(p_vct, p_byte,
i_major_number, i_minor_number,
i_modulation, i_carrier_freq,
i_channel_tsid, i_program_number,
i_etm_location, b_access_controlled,
b_hidden, b_path_select, b_out_of_band,
b_hide_guide, i_service_type, i_source_id);
/* Table descriptors */
p_byte += 32;
p_end = p_byte + i_length;
if( p_end > p_section->p_payload_end ) break;
while(p_byte + 2 <= p_end)
{
uint8_t i_tag = p_byte[0];
uint8_t i_length = p_byte[1];
if(i_length + 2 <= p_end - p_byte)
dvbpsi_atsc_VCTChannelAddDescriptor(p_channel, i_tag, i_length, p_byte + 2);
p_byte += 2 + i_length;
}
}
/* Table descriptors */
i_length = ((uint16_t)(p_byte[0] & 0x3) <<8) | p_byte[1];
p_byte += 2;
p_end = p_byte + i_length;
while(p_byte + 2 <= p_end)
{
uint8_t i_tag = p_byte[0];
uint8_t i_length = p_byte[1];
if(i_length + 2 <= p_end - p_byte)
dvbpsi_atsc_VCTAddDescriptor(p_vct, i_tag, i_length, p_byte + 2);
p_byte += 2 + i_length;
}
p_section = p_section->p_next;
}
}
/*
Copyright (C) 2006 Adam Charrett
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
vct.h
Decode PSIP Virtual Channel Table.
*/
#ifndef _ATSC_VCT_H
#define _ATSC_VCT_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_atsc_vct_channel_t
*****************************************************************************/
/*!
* \struct dvbpsi_atsc_vct_channel_s
* \brief VCT channel structure.
*
* This structure is used to store a decoded VCT channel information.
*/
/*!
* \typedef struct dvbpsi_atsc_vct_channel_s dvbpsi_atsc_vct_channel_t
* \brief dvbpsi_atsc_vct_channel_t type definition.
*/
typedef struct dvbpsi_atsc_vct_channel_s
{
uint8_t i_short_name[14];/*!< Channel name (7*UTF16-BE)*/
uint16_t i_major_number; /*!< Channel major number */
uint16_t i_minor_number; /*!< Channel minor number */
uint8_t i_modulation; /*!< Modulation mode. */
uint32_t i_carrier_freq; /*!< Carrier center frequency. */
uint16_t i_channel_tsid; /*!< Channel Transport stream id. */
uint16_t i_program_number;/*!< Channel MPEG program number. */
uint8_t i_etm_location; /*!< Extended Text Message location. */
int b_access_controlled; /*!< Whether the channel is scrambled. */
int b_path_select; /*!< Path selection, only used by CVCT. */
int b_out_of_band; /*!< Whether the channel is carried on the out-of-band
physical transmission channel, only used by CVCT. */
int b_hidden; /*!< Not accessible directly by the user. */
int b_hide_guide; /*!< Whether the channel should not be displayed in the guide. */
uint8_t i_service_type; /*!< Channel type. */
uint16_t i_source_id; /*!< Programming source associated with the channel.*/
dvbpsi_descriptor_t *p_first_descriptor; /*!< First descriptor. */
struct dvbpsi_atsc_vct_channel_s *p_next; /*!< next element of the list */
} dvbpsi_atsc_vct_channel_t;
/*****************************************************************************
* dvbpsi_atsc_vct_t
*****************************************************************************/
/*!
* \struct dvbpsi_atsc_vct_s
* \brief VCT structure.
*
* This structure is used to store a decoded VCT.
*/
/*!
* \typedef struct dvbpsi_atsc_vct_s dvbpsi_atsc_vct_t
* \brief dvbpsi_atsc_vct_t type definition.
*/
typedef struct dvbpsi_atsc_vct_s
{
uint8_t i_version; /*!< version_number */
int b_current_next; /*!< current_next_indicator */
uint16_t i_ts_id; /*!< transport stream id */
uint8_t i_protocol; /*!< PSIP Protocol version */
int b_cable_vct; /*!< 1 if this is a cable VCT, 0 if it is a Terrestrial VCT. */
dvbpsi_atsc_vct_channel_t *p_first_channel; /*!< First channel information structure. */
dvbpsi_descriptor_t *p_first_descriptor; /*!< First descriptor. */
} dvbpsi_atsc_vct_t;
/*****************************************************************************
* dvbpsi_vct_callback
*****************************************************************************/
/*!
* \typedef void (* dvbpsi_atsc_vct_callback)(void* p_cb_data,
dvbpsi_atsc_vct_t* p_new_vct)
* \brief Callback type definition.
*/
typedef void (* dvbpsi_atsc_vct_callback)(void* p_cb_data, dvbpsi_atsc_vct_t* p_new_vct);
/*****************************************************************************
* dvbpsi_atsc_AttachVCT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_AttachVCT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
dvbpsi_atsc_vct_callback pf_callback, void* p_cb_data)
*
* \brief Creation and initialization of a VCT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0xC8 or 0xC9.
* \param i_extension Table ID extension, here TS ID.
* \param pf_callback function to call back on new VCT.
* \param p_cb_data private data given in argument to the callback.
* \return 0 if everything went ok.
*/
int dvbpsi_atsc_AttachVCT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
uint16_t i_extension, dvbpsi_atsc_vct_callback pf_callback, void* p_cb_data);
/*****************************************************************************
* dvbpsi_DetachVCT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_DetachVCT(dvbpsi_demux_t * p_demux, uint8_t i_table_id)
*
* \brief Destroy a VCT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0xC8 or 0xC9.
* \param i_extension Table ID extension, here TS ID.
* \return nothing.
*/
void dvbpsi_atsc_DetachVCT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
uint16_t i_extension);
/*****************************************************************************
* dvbpsi_atsc_InitVCT/dvbpsi_atsc_NewVCT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_InitVCT(dvbpsi_atsc_vct_t* p_vct, uint8_t i_version,
int b_current_next, uint8_t i_protocol)
* \brief Initialize a user-allocated dvbpsi_atsc_vct_t structure.
* \param p_vct pointer to the VCT structure
* \param i_version VCT version
* \param b_current_next current next indicator
* \param i_protocol PSIP Protocol version.
* \param i_ts_id Transport Stream id.
* \param b_cable_vct Whether this is CVCT or a TVCT.
* \return nothing.
*/
void dvbpsi_atsc_InitVCT(dvbpsi_atsc_vct_t* p_vct,uint8_t i_version, int b_current_next,
uint8_t i_protocol, uint16_t i_ts_id, int b_cable_vct);
/*!
* \def dvbpsi_atsc_NewVCT(p_vct, i_network_id, i_version, b_current_next)
* \brief Allocate and initialize a new dvbpsi_vct_t structure.
* \param p_vct pointer to the VCT structure
* \param i_network_id network id
* \param i_version VCT version
* \param b_current_next current next indicator
* \param i_protocol PSIP Protocol version.
* \param b_cable_vct Whether this is CVCT or a TVCT.
* \return nothing.
*/
#define dvbpsi_atsc_NewVCT(p_vct, i_version, b_current_next, i_protocol, \
i_ts_id, b_cable_vct) \
do { \
p_vct = (dvbpsi_atsc_vct_t*)malloc(sizeof(dvbpsi_atsc_vct_t)); \
if(p_vct != NULL) \
dvbpsi_atsc_InitVCT(p_vct, i_version, b_current_next, i_protocol, \
i_ts_id, b_cable_vct); \
} while(0);
/*****************************************************************************
* dvbpsi_atsc_EmptyVCT/dvbpsi_atsc_DeleteVCT
*****************************************************************************/
/*!
* \fn void dvbpsi_atsc_EmptyVCT(dvbpsi_atsc_vct_t* p_vct)
* \brief Clean a dvbpsi_vct_t structure.
* \param p_vct pointer to the VCT structure
* \return nothing.
*/
void dvbpsi_atsc_EmptyVCT(dvbpsi_atsc_vct_t *p_vct);
/*!
* \def dvbpsi_atsc_DeleteVCT(p_vct)
* \brief Clean and free a dvbpsi_vct_t structure.
* \param p_vct pointer to the VCT structure
* \return nothing.
*/
#define dvbpsi_atsc_DeleteVCT(p_vct) \
do { \
dvbpsi_atsc_EmptyVCT(p_vct); \
free(p_vct); \
} while(0);
#ifdef __cplusplus
};
#endif
#endif
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