Commit 151adbdd authored by Daniel Kamil Kozar's avatar Daniel Kamil Kozar Committed by Jean-Paul Saman

Support for the content labelling descriptor

This patch provides decoding and generation of the content labelling descriptor.
Signed-off-by: default avatarJean-Paul Saman <jpsaman@videolan.org>
parent 9cb706c5
......@@ -41,6 +41,7 @@ pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.h \
descriptors/dr_14.h \
descriptors/dr_1b.h \
descriptors/dr_1c.h \
descriptors/dr_24.h \
descriptors/dr_40.h \
descriptors/dr_41.h \
descriptors/dr_42.h \
......@@ -101,6 +102,7 @@ descriptors_src = descriptors/dr_02.c \
descriptors/dr_14.c \
descriptors/dr_1b.c \
descriptors/dr_1c.c \
descriptors/dr_24.c \
descriptors/dr_40.c \
descriptors/dr_41.c \
descriptors/dr_42.c \
......
/*
Copyright (C) 2015 Daniel Kamil Kozar
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#elif defined(HAVE_STDINT_H)
#include <stdint.h>
#endif
#include "../dvbpsi.h"
#include "../dvbpsi_private.h"
#include "../descriptor.h"
#include "dr_24.h"
/* the minimum size of a valid content labelling descriptor. it consists of
* metadata_application_format, content_{reference_id_record_flag, time_base_
* indicator}, and a reserved field. they all sum up to 24 bits. */
#define DR_24_MIN_SIZE 3
static int decode_content_reference_id(dvbpsi_content_labelling_dr_t *p_decoded,
const uint8_t **pp_data, uint8_t *pi_left)
{
uint8_t i_left = *pi_left;
const uint8_t *p_data = *pp_data;
if(i_left < 1)
return 1;
p_decoded->i_content_reference_id_record_length = *p_data;
i_left--; p_data++;
/* H.222.0 says that content_reference_id_record_length "shall not be coded
* with the value '0'". reject such data as invalid. */
if(i_left < p_decoded->i_content_reference_id_record_length ||
p_decoded->i_content_reference_id_record_length == 0)
return 1;
p_decoded->p_content_reference_id = malloc(
p_decoded->i_content_reference_id_record_length);
if(!p_decoded->p_content_reference_id)
return 1;
memcpy(p_decoded->p_content_reference_id, p_data,
p_decoded->i_content_reference_id_record_length);
i_left -= p_decoded->i_content_reference_id_record_length;
p_data += p_decoded->i_content_reference_id_record_length;
*pp_data = p_data;
*pi_left = i_left;
return 0;
}
static int decode_content_time_base_indicator(dvbpsi_content_labelling_dr_t
*p_decoded, const uint8_t **pp_data, uint8_t *pi_left)
{
const uint8_t *p_data = *pp_data;
uint8_t i_left = *pi_left;
if(p_decoded->i_content_time_base_indicator == 1 ||
p_decoded->i_content_time_base_indicator == 2)
{
if(i_left < 10)
return 1;
p_decoded->i_content_time_base_value =
(((uint64_t)(p_data[0] & 0x01)) << 32) |
((uint64_t)p_data[1] << 24) |
((uint64_t)p_data[2] << 16) |
((uint64_t)p_data[3] << 8) |
(uint64_t)p_data[4];
p_decoded->i_metadata_time_base_value =
(((uint64_t)(p_data[5] & 0x01)) << 32) |
((uint64_t)p_data[6] << 24) |
((uint64_t)p_data[7] << 16) |
((uint64_t)p_data[8] << 8) |
(uint64_t)p_data[9];
p_data += 10; i_left -= 10;
}
if(p_decoded->i_content_time_base_indicator == 2)
{
if(i_left < 1)
return 1;
p_decoded->i_contentId = *p_data & 0x7f;
p_data++; i_left--;
}
if(p_decoded->i_content_time_base_indicator >= 3 &&
p_decoded->i_content_time_base_indicator <= 7)
{
if(i_left < 1)
return 1;
p_decoded->i_time_base_association_data_length = *p_data;
p_data++; i_left--;
if(i_left < p_decoded->i_time_base_association_data_length)
return 1;
if(p_decoded->i_time_base_association_data_length)
{
p_decoded->p_time_base_association_data = malloc(
p_decoded->i_time_base_association_data_length);
if(!p_decoded->p_time_base_association_data)
return 1;
memcpy(p_decoded->p_time_base_association_data, p_data,
p_decoded->i_time_base_association_data_length);
}
p_data += p_decoded->i_time_base_association_data_length;
i_left -= p_decoded->i_time_base_association_data_length;
}
*pp_data = p_data;
*pi_left = i_left;
return 0;
}
dvbpsi_content_labelling_dr_t* dvbpsi_DecodeContentLabellingDr(
dvbpsi_descriptor_t * p_descriptor)
{
dvbpsi_content_labelling_dr_t *p_decoded;
const uint8_t *p_data = p_descriptor->p_data;
uint8_t i_left = p_descriptor->i_length;
/* check the tag. */
if (!dvbpsi_CanDecodeAsDescriptor(p_descriptor, 0x24))
return NULL;
/* don't decode twice. */
if (dvbpsi_IsDescriptorDecoded(p_descriptor))
return p_descriptor->p_decoded;
/* simplest descriptors of this type contain 3 bytes of payload. */
if (p_descriptor->i_length < DR_24_MIN_SIZE)
return NULL;
p_decoded = malloc(sizeof(*p_decoded));
if (!p_decoded)
return NULL;
/* set the pointers to NULL so we can safely free() them in err: */
p_decoded->p_content_reference_id = NULL;
p_decoded->p_time_base_association_data = NULL;
p_decoded->p_private_data = NULL;
p_decoded->i_metadata_application_format =
((uint16_t)p_data[0] << 8) | (uint16_t)p_data[1];
i_left -= 2; p_data += 2;
if(p_decoded->i_metadata_application_format == 0xFFFF)
{
if(i_left < 4)
goto err;
p_decoded->i_metadata_application_format_identifier =
((uint32_t)p_data[0] << 24) |
((uint32_t)p_data[1] << 16) |
((uint32_t)p_data[2] << 8) |
(uint32_t)p_data[3];
i_left -= 4; p_data += 4;
}
if(i_left < 1)
goto err;
p_decoded->b_content_reference_id_record_flag = (*p_data & 0x80);
p_decoded->i_content_time_base_indicator = ((*p_data & 0x78) >> 3);
i_left--; p_data++;
if(p_decoded->b_content_reference_id_record_flag &&
decode_content_reference_id(p_decoded, &p_data, &i_left) != 0)
goto err;
if(p_decoded->i_content_time_base_indicator &&
decode_content_time_base_indicator(p_decoded, &p_data, &i_left) != 0)
goto err;
p_decoded->i_private_data_len = i_left;
if(p_decoded->i_private_data_len)
{
p_decoded->p_private_data = malloc(p_decoded->i_private_data_len);
if(!p_decoded->p_private_data)
goto err;
memcpy(p_decoded->p_private_data, p_data, p_decoded->i_private_data_len);
}
p_descriptor->p_decoded = p_decoded;
return p_decoded;
err:
free(p_decoded->p_private_data);
free(p_decoded->p_time_base_association_data);
free(p_decoded->p_content_reference_id);
free(p_decoded);
return NULL;
}
static unsigned int generate_get_descriptor_size(const
dvbpsi_content_labelling_dr_t * p_decoded)
{
unsigned int size = DR_24_MIN_SIZE + p_decoded->i_private_data_len;
if(p_decoded->i_metadata_application_format == 0xFFFF)
size += 4;
if(p_decoded->b_content_reference_id_record_flag)
size += p_decoded->i_content_reference_id_record_length + 1;
if(p_decoded->i_content_time_base_indicator == 1 ||
p_decoded->i_content_time_base_indicator == 2)
size += 10;
if(p_decoded->i_content_time_base_indicator == 2)
size += 1;
if(p_decoded->i_content_time_base_indicator >= 3 &&
p_decoded->i_content_time_base_indicator <= 7)
size += p_decoded->i_time_base_association_data_length + 1;
return size;
}
static bool generate_check_struct_valid(const
dvbpsi_content_labelling_dr_t * p_decoded)
{
/* check if the pointers are valid if relevant sizes are nonzero. also,
* check if i_content_reference_id_record_length isn't zero if the flag is
* set, as this is explicitly forbidden by H.222.0. */
if((p_decoded->b_content_reference_id_record_flag &&
!p_decoded->i_content_reference_id_record_length) ||
(p_decoded->i_content_reference_id_record_length &&
!p_decoded->p_content_reference_id))
return false;
if(p_decoded->i_time_base_association_data_length &&
!p_decoded->p_time_base_association_data)
return false;
if(p_decoded->i_private_data_len && !p_decoded->p_private_data)
return false;
return true;
}
dvbpsi_descriptor_t * dvbpsi_GenContentLabellingDr(
dvbpsi_content_labelling_dr_t * p_decoded)
{
unsigned int size;
dvbpsi_descriptor_t * p_descriptor;
uint8_t *p_data;
if(!generate_check_struct_valid(p_decoded))
return NULL;
size = generate_get_descriptor_size(p_decoded);
if(size > 253) /* maximum possible descriptor payload size. */
return NULL;
p_descriptor = dvbpsi_NewDescriptor(0x24, size, NULL);
if (!p_descriptor)
return NULL;
p_data = p_descriptor->p_data;
p_data[0] = (p_decoded->i_metadata_application_format & 0xFF00) >> 8;
p_data[1] = (p_decoded->i_metadata_application_format & 0x00FF);
p_data += 2;
if(p_decoded->i_metadata_application_format == 0xFFFF)
{
p_data[0] = (p_decoded->i_metadata_application_format_identifier & 0xFF000000) >> 24;
p_data[1] = (p_decoded->i_metadata_application_format_identifier & 0x00FF0000) >> 16;
p_data[2] = (p_decoded->i_metadata_application_format_identifier & 0x0000FF00) >> 8;
p_data[3] = (p_decoded->i_metadata_application_format_identifier & 0x000000FF);
p_data += 4;
}
*p_data = ((p_decoded->b_content_reference_id_record_flag ? 1 : 0) << 7) |
((p_decoded->i_content_time_base_indicator & 0xf) << 6) |
0x07;
p_data++;
if(p_decoded->b_content_reference_id_record_flag)
{
*p_data = p_decoded->i_content_reference_id_record_length;
memcpy(p_data + 1, p_decoded->p_content_reference_id,
p_decoded->i_content_reference_id_record_length);
p_data += (p_decoded->i_content_reference_id_record_length + 1);
}
if(p_decoded->i_content_time_base_indicator == 1 ||
p_decoded->i_content_time_base_indicator == 2)
{
p_data[0] = 0xfe | ((p_decoded->i_content_time_base_value & 0x100000000) >> 32);
p_data[1] = (p_decoded->i_content_time_base_value & 0xFF000000) >> 24;
p_data[2] = (p_decoded->i_content_time_base_value & 0x00FF0000) >> 16;
p_data[3] = (p_decoded->i_content_time_base_value & 0x0000FF00) >> 8;
p_data[4] = (p_decoded->i_content_time_base_value & 0x000000FF);
p_data[5] = 0xfe | ((p_decoded->i_metadata_time_base_value & 0x100000000) >> 32);
p_data[6] = (p_decoded->i_metadata_time_base_value & 0xFF000000) >> 24;
p_data[7] = (p_decoded->i_metadata_time_base_value & 0x00FF0000) >> 16;
p_data[8] = (p_decoded->i_metadata_time_base_value & 0x0000FF00) >> 8;
p_data[9] = (p_decoded->i_metadata_time_base_value & 0x000000FF);
p_data += 10;
}
if(p_decoded->i_content_time_base_indicator == 2)
{
*p_data = 0x80 | (p_decoded->i_contentId & 0x7f);
p_data++;
}
if(p_decoded->i_content_time_base_indicator >= 3 &&
p_decoded->i_content_time_base_indicator <= 7)
{
*p_data = p_decoded->i_time_base_association_data_length;
memcpy(p_data + 1, p_decoded->p_time_base_association_data,
p_decoded->i_time_base_association_data_length);
p_data += (p_decoded->i_time_base_association_data_length + 1);
}
memcpy(p_data, p_decoded->p_private_data, p_decoded->i_private_data_len);
return p_descriptor;
}
/*
Copyright (C) 2015 Daniel Kamil Kozar
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*!
* \file <dr_24.h>
* \author Daniel Kamil Kozar <dkk089@gmail.com>
* \brief Application interface for the content labelling descriptor decoder and
* generator.
*
* Application interface for the content labelling descriptor decoder and
* generator. This descriptor's definition can be found in ISO/IEC 13818-1:2015
* section 2.6.56.
*/
#ifndef _DVBPSI_DR_24_H_
#define _DVBPSI_DR_24_H_
#ifdef __cplusplus
extern "C" {
#endif
/*!
* \struct dvbpsi_content_labelling_dr_s
* \brief Content labelling descriptor structure.
*
* This structure is used to store a decoded content labelling descriptor.
* (ISO/IEC 13818-1 section 2.6.56).
*/
/*!
* \typedef struct dvbpsi_content_labelling_dr_s dvbpsi_content_labelling_dr_t
* \brief dvbpsi_content_labelling_dr_t type definition.
*/
typedef struct dvbpsi_content_labelling_dr_s
{
uint16_t i_metadata_application_format; /*!< metadata_application_format */
/*! metadata_application_format_identifier
* \warning Valid only if \c i_metadata_application_format is \c 0xFFFF . */
uint32_t i_metadata_application_format_identifier;
/*! content_reference_id_record_flag */
bool b_content_reference_id_record_flag;
uint8_t i_content_time_base_indicator; /*!< content_time_base_indicator */
/*! content_reference_id_record_length
* \warning Valid only if \c b_content_reference_id_record_flag is true. */
uint8_t i_content_reference_id_record_length;
/*! content_reference_id_byte
* An array of \c i_content_reference_id_record_length bytes. Memory is
* allocated by the decoder when decoding, and by the caller when generating.
* \warning Valid only if \c b_content_reference_id_record_flag is true. */
uint8_t *p_content_reference_id;
/*! content_time_base_value
* \warning Valid only if \c i_content_time_base_indicator is 1 or 2. */
uint64_t i_content_time_base_value;
/*! metadata_time_base_value
* \warning Valid only if \c i_content_time_base_indicator is 1 or 2. */
uint64_t i_metadata_time_base_value;
/*! contentId
* \warning Valid only if \c i_content_time_base_indicator is 2. */
uint8_t i_contentId;
/*! time_base_association_data_length
* \warning Valid only if \c i_content_time_base_indicator is 3, 4, 5, 6,
* or 7. */
uint8_t i_time_base_association_data_length;
/*! time_base_association_data
* An array of \c i_time_base_association_data_length bytes. Memory is
* allocated by the decoder when decoding, and by the caller when generating.
* \note This field is marked as reserved, but access to it is nevertheless
* provided if applications want to use it.
* \warning Valid only if \c i_content_time_base_indicator is 3, 4, 5, 6,
* or 7. */
uint8_t *p_time_base_association_data;
/*! private_data_len */
uint8_t i_private_data_len;
/*! private_data
* \note An array of \c i_private_data_len bytes at the end of the
* descriptor. Memory is allocated by the decoder when decoding, and by the
* caller when generating. */
uint8_t *p_private_data;
} dvbpsi_content_labelling_dr_t;
/*!
* \brief Content labelling descriptor decoder.
* \param p_descriptor pointer to the descriptor structure
* \return A pointer to a new content labelling descriptor structure which
* contains the decoded data.
*/
dvbpsi_content_labelling_dr_t* dvbpsi_DecodeContentLabellingDr(
dvbpsi_descriptor_t * p_descriptor);
/*!
* \brief Content labelling descriptor generator.
* \param p_decoded pointer to a decoded content labelling descriptor structure.
* \return a pointer to a new descriptor structure which contains encoded data.
*/
dvbpsi_descriptor_t * dvbpsi_GenContentLabellingDr(
dvbpsi_content_labelling_dr_t * p_decoded);
#ifdef __cplusplus
}
#endif
#else
#error "Multiple inclusions of dr_24.h"
#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