Browse Source

add SCT-35 support

master
Christophe Massiot 9 years ago
parent
commit
57197d858c
6 changed files with 1189 additions and 29 deletions
  1. +64
    -0
      examples/dvb_gen_si.c
  2. +63
    -2
      examples/dvb_print_si.c
  3. +16
    -13
      examples/dvb_print_si.output.txt
  4. +18
    -14
      examples/dvb_print_si.output.xml
  5. +732
    -0
      scte/35.h
  6. +296
    -0
      scte/35_print.h

+ 64
- 0
examples/dvb_gen_si.c View File

@ -2,9 +2,11 @@
* dvb_gen_si.c: Generate SI tables and descriptors
*****************************************************************************
* Copyright (c) 2011 Unix Solutions Ltd.
* Copyright (c) 2015 VideoLAN
*
* Authors:
* Georgi Chorbadzhiyski <gf@unixsol.org>
* Christophe Massiot <massiot@via.ecp.fr>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -38,6 +40,8 @@
#include <bitstream/mpeg/psi.h>
#include <bitstream/dvb/si.h>
#include <bitstream/dvb/si_print.h>
#include <bitstream/scte/35.h>
#include <bitstream/scte/35_print.h>
uint16_t tsid = 10000;
uint16_t sid = 20000;
@ -45,6 +49,7 @@ uint16_t event_id = 30000;
uint16_t onid = 40000;
uint16_t pmt_pid = 100;
uint16_t scte35_pid = 200;
time_t ts_0 = 1234567890;
time_t ts_1 = 1;
@ -2959,6 +2964,12 @@ static void generate_pmt(void) {
descs_set_length(desc_loop, desc - desc_loop - DESCS_HEADER_SIZE);
}
pmt_n = pmt_get_es(pmt, pmt_n_counter++);
pmtn_init(pmt_n);
pmtn_set_streamtype(pmt_n, PMT_STREAMTYPE_SCTE_35);
pmtn_set_pid(pmt_n, scte35_pid);
pmtn_set_desclength(pmt_n, 0);
// Set transport_stream_loop length
pmt_n = pmt_get_es(pmt, pmt_n_counter); // Get last service
pmt_set_length(pmt, pmt_n - pmt_get_es(pmt, 0) + pmt_get_desclength(pmt));
@ -3073,6 +3084,58 @@ static void generate_sit(void) {
free(sit);
}
/* SCTE 35 Splice Information Table */
static void generate_scte35(void) {
uint8_t *scte35 = psi_allocate();
// Generate empty section
scte35_init(scte35);
psi_set_length(scte35, PSI_MAX_SIZE);
scte35_set_pts_adjustment(scte35, 0);
scte35_null_init(scte35);
scte35_set_desclength(scte35, 0);
psi_set_length(scte35,
scte35_get_descl(scte35) + PSI_CRC_SIZE - scte35 - PSI_HEADER_SIZE);
psi_set_crc(scte35);
output_psi_section(scte35, scte35_pid, &cc);
// Generate insert section
scte35_init(scte35);
psi_set_length(scte35, PSI_MAX_SIZE);
scte35_set_pts_adjustment(scte35, 0);
scte35_insert_init(scte35,
SCTE35_INSERT_HEADER2_SIZE +
SCTE35_SPLICE_TIME_HEADER_SIZE + SCTE35_SPLICE_TIME_TIME_SIZE +
SCTE35_BREAK_DURATION_HEADER_SIZE + SCTE35_INSERT_FOOTER_SIZE);
scte35_insert_set_cancel(scte35, false);
scte35_insert_set_event_id(scte35, 4242);
scte35_insert_set_out_of_network(scte35, true);
scte35_insert_set_program_splice(scte35, true);
scte35_insert_set_duration(scte35, true);
scte35_insert_set_splice_immediate(scte35, false);
uint8_t *splice_time = scte35_insert_get_splice_time(scte35);
scte35_splice_time_init(splice_time);
scte35_splice_time_set_time_specified(splice_time, true);
scte35_splice_time_set_pts_time(splice_time, 270000000);
uint8_t *duration = scte35_insert_get_break_duration(scte35);
scte35_break_duration_init(duration);
scte35_break_duration_set_auto_return(duration, true);
scte35_break_duration_set_duration(duration, 27000000);
scte35_insert_set_unique_program_id(scte35, 2424);
scte35_insert_set_avail_num(scte35, 0);
scte35_insert_set_avails_expected(scte35, 0);
scte35_set_desclength(scte35, 0);
psi_set_length(scte35,
scte35_get_descl(scte35) + PSI_CRC_SIZE - scte35 - PSI_HEADER_SIZE);
psi_set_crc(scte35);
output_psi_section(scte35, scte35_pid, &cc);
free(scte35);
}
int main(void)
{
generate_pat();
@ -3088,6 +3151,7 @@ int main(void)
generate_pmt();
generate_dit();
generate_sit();
generate_scte35();
return EXIT_SUCCESS;
}

+ 63
- 2
examples/dvb_print_si.c View File

@ -1,7 +1,7 @@
/*****************************************************************************
* dvb_print_si.c: Prints tables from a TS file
*****************************************************************************
* Copyright (C) 2010-2011 VideoLAN
* Copyright (C) 2010-2015 VideoLAN
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
@ -41,6 +41,8 @@
#include <bitstream/dvb/si.h>
#include <bitstream/dvb/si_print.h>
#include <bitstream/mpeg/psi_print.h>
#include <bitstream/scte/35.h>
#include <bitstream/scte/35_print.h>
/*****************************************************************************
* Local declarations
@ -108,14 +110,17 @@ enum tables_t {
TABLE_DIT,
TABLE_SIT,
TABLE_PMT,
TABLE_SCTE35,
TABLE_END
};
static const char * const ppsz_all_tables[TABLE_END] = {
"pat", "cat", "tsdt", "nit", "bat", "sdt", "eit", "tot", "tdt", "rst",
"dit", "sit", "pmt"
"dit", "sit", "pmt", "scte35"
};
static bool pb_print_table[TABLE_END];
static void handle_pmt_es(uint8_t *p_pmt, bool b_select);
/*****************************************************************************
* print_wrapper
*****************************************************************************/
@ -288,6 +293,7 @@ static void handle_pat(void)
for (i_pmt = 0; i_pmt < i_nb_sids; i_pmt++)
if (pp_sids[i_pmt]->i_sid == i_sid) {
pp_sids[i_pmt]->i_sid = 0;
handle_pmt_es(pp_sids[i_pmt]->p_current_pmt, false);
free(pp_sids[i_pmt]->p_current_pmt);
pp_sids[i_pmt]->p_current_pmt = NULL;
psi_table_free(pp_sids[i]->pp_eit_sections);
@ -451,6 +457,28 @@ static void handle_tsdt_section(uint16_t i_pid, uint8_t *p_section)
/*****************************************************************************
* handle_pmt
*****************************************************************************/
static void handle_pmt_es(uint8_t *p_pmt, bool b_select)
{
int j = 0;
uint8_t *p_es;
while ((p_es = pmt_get_es(p_pmt, j)) != NULL) {
uint16_t i_pid = pmtn_get_pid(p_es);
uint8_t i_type = pmtn_get_streamtype(p_es);
j++;
switch (i_type) {
case PMT_STREAMTYPE_SCTE_35:
if (b_select)
p_pids[i_pid].i_psi_refcount++;
else
p_pids[i_pid].i_psi_refcount--;
break;
default:
break;
}
}
}
static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
{
uint16_t i_sid = pmt_get_program(p_pmt);
@ -514,8 +542,12 @@ static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
return;
}
if (p_sid->p_current_pmt)
handle_pmt_es(p_sid->p_current_pmt, false);
free(p_sid->p_current_pmt);
p_sid->p_current_pmt = p_pmt;
handle_pmt_es(p_pmt, true);
if (pb_print_table[TABLE_PMT])
pmt_print(p_pmt, print_wrapper, NULL, iconv_wrapper, NULL,
@ -902,6 +934,31 @@ static void handle_sit_section(uint16_t i_pid, uint8_t *p_sit)
free(p_sit);
}
/*****************************************************************************
* handle_scte35
*****************************************************************************/
static void handle_scte35_section(uint16_t i_pid, uint8_t *p_scte35)
{
if (!scte35_validate(p_scte35)) {
switch (i_print_type) {
case PRINT_XML:
printf("<ERROR type=\"invalid_scte35_section\" pid=\"%hu\"/>\n",
i_pid);
break;
default:
printf("invalid SCTE35 section received on PID %hu\n", i_pid);
}
free(p_scte35);
return;
}
if (pb_print_table[TABLE_SCTE35] &&
scte35_get_command_type(p_scte35) != SCTE35_NULL_COMMAND)
scte35_print(p_scte35, print_wrapper, NULL, i_print_type);
free(p_scte35);
}
/*****************************************************************************
* handle_section
*****************************************************************************/
@ -974,6 +1031,10 @@ static void handle_section(uint16_t i_pid, uint8_t *p_section)
handle_eit_section(i_pid, p_section);
break;
case SCTE35_TABLE_ID:
handle_scte35_section(i_pid, p_section);
break;
default:
free( p_section );
break;

+ 16
- 13
examples/dvb_print_si.output.txt View File

@ -70,9 +70,9 @@ new NIT actual networkid=40000 version=1
- mobile_handover handover_type=1 origin_type=0 nid=41000 initial_sid=21000
* ts tsid=10300 onid=40300
end NIT
new BAT networkid=40000 version=0
new BAT bouquetid=40000 version=0
end BAT
new BAT networkid=40000 version=1
new BAT bouquetid=40000 version=1
- desc 47 bouquetname="Test Bouquet Name"
- desc 5c multilingual_bouquet_name code="eng" bouquetname="M Bouquet"
- desc 5c multilingual_bouquet_name code="fre" bouquetname="M Bouquet"
@ -141,12 +141,12 @@ new SDT actual tsid=10000 version=1 onid=40000
- desc 4b nvod_reference tsid=10200 onid=40200 sid=20200
- desc 5f private_data specifier=0xaabbccdd
end SDT
new EIT tableid=0x4e type=actual_pf service_id=20000 version=0 tsid=10000 onid=40000 seg_last_sec_number=0 last_table_id=0x00
new EIT tableid=0x4e type=actual_pf service_id=20000 version=0 section=0/0 tsid=10000 onid=40000
end EIT
new EIT tableid=0x4e type=actual_pf service_id=20000 version=1 tsid=10000 onid=40000 seg_last_sec_number=0 last_table_id=0x00
* EVENT id=30000 start_time=1234567890 start_time_dec="2009-02-13 23:31:30 UTC" duration=86399 duration_dec=23:59:59 running_status=2 free_CA_mode=0
new EIT tableid=0x4e type=actual_pf service_id=20000 version=1 section=0/0 tsid=10000 onid=40000
* EVENT id=30000 start_time=1234567890 start_time_dec="2009-02-13 23:31:30 UTC" duration=86399 duration_dec=23:59:59 running=2 free_CA=0
- desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
* EVENT id=30100 start_time=1 start_time_dec="1970-01-01 00:00:01 UTC" duration=3600 duration_dec=01:00:00 running_status=1 free_CA_mode=0
* EVENT id=30100 start_time=1 start_time_dec="1970-01-01 00:00:01 UTC" duration=3600 duration_dec=01:00:00 running=1 free_CA=0
- desc 4a linkage tsid=10700 onid=40700 sid=20700 linkage=0x0d linkage_txt="event linkage"
- event_linkage target_event_id=31000 target_listed=1 event_simulcast=1
- desc 4e extended_event desc_number=0 last_desc_number=0 lang=eng text="Wow, what an event!"
@ -155,7 +155,7 @@ new EIT tableid=0x4e type=actual_pf service_id=20000 version=1 tsid=10000 onid=4
- extended_event_item description="Rating" text="***++"
- desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
- desc 61 short_smoothing_buffer sb_size=1 sb_leak_rate=10
* EVENT id=30200 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running_status=0 free_CA_mode=0
* EVENT id=30200 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running=0 free_CA=0
- desc 4a linkage tsid=10800 onid=40800 sid=20800 linkage=0x0e linkage_txt="extended event linkage"
- extended_event_linkage target_event_id=31000 target_listed=0 event_simulcast=1 link_type=1 link_type_txt="HD" target_id_type=3 target_id_type_txt="use user_defined_id" onid_id_flag=1 service_id_flag=1 user_defined_id=7878 target_tsid=0 target_onid=0 target_service_id=0
- extended_event_linkage target_event_id=32000 target_listed=1 event_simulcast=1 link_type=0 link_type_txt="SD" target_id_type=0 target_id_type_txt="use tsid" onid_id_flag=1 service_id_flag=1 user_defined_id=0 target_tsid=0 target_onid=42000 target_service_id=22000
@ -172,7 +172,7 @@ new EIT tableid=0x4e type=actual_pf service_id=20000 version=1 tsid=10000 onid=4
- desc 55 parental_rating country_code=BUL rating=24 rating_txt="unknown"
- desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
- desc 4f time_shifted_service reference_sid=22000 reference_event_id=32000
* EVENT id=30300 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running_status=4 free_CA_mode=1
* EVENT id=30300 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running=4 free_CA=1
- desc 54 content content_l1=2 content_l2=4 user=78
- desc 54 content content_l1=6 content_l2=8 user=177
- desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
@ -205,9 +205,9 @@ end TOT
new RST
end RST
new RST
* status tsid="10000" onid="40000" service_id="20000" event_id="30000" running_status="1"
* status tsid="10100" onid="40100" service_id="20100" event_id="30100" running_status="2"
* status tsid="10200" onid="40200" service_id="20200" event_id="30200" running_status="3"
* status tsid="10000" onid="40000" service_id="20000" event_id="30000" running="1"
* status tsid="10100" onid="40100" service_id="20100" event_id="30100" running="2"
* status tsid="10200" onid="40200" service_id="20200" event_id="30200" running="3"
end RST
new PMT program=20000 version=0 pcrpid=110
end PMT
@ -332,6 +332,7 @@ new PMT program=20000 version=1 pcrpid=110
- desc 42 stuffing length=4
- desc 2b mpeg2_aac_audio profile=0x12 channel_config=0x05 additional_info=0x00
- desc 7c aac profile_and_level="0x14" aac_type_flag="1" aac_type="0x1f"
* ES pid=200 streamtype=0x86 streamtype_txt="SCTE 35 Splice Information Table"
end PMT
new DIT transition_flag=1
end DIT
@ -341,9 +342,11 @@ new SIT version=0
end SIT
new SIT version=1
- desc 63 partial_transport_stream peak_rate=5000 min_overall_smoothing_rate=7000 max_overall_smoothing_buffer=1000
* SERVICE sid=20000 running_status=1
* SERVICE sid=20000 running=1
- desc 05 registration identifier=TEST
- desc 05 registration identifier=TEST
- desc 05 registration identifier=TEST
* SERVICE sid=21000 running_status=3
* SERVICE sid=21000 running=3
end SIT
new SCTE35 command=5 command_str=insert pts_adjustment=0 event_id=4242 cancel=false out_of_network=true program_splice=true splice_time=270000000 auto_return=true duration=27000000 unique_program_id=2424
end SCTE35

+ 18
- 14
examples/dvb_print_si.output.xml View File

@ -120,9 +120,9 @@
<TS tsid="10300" onid="40300">
</TS>
</NIT>
<BAT tid="74" networkid="40000" version="0" current_next="1">
<BAT tid="74" bouquetid="40000" version="0" current_next="1">
</BAT>
<BAT tid="74" networkid="40000" version="1" current_next="1">
<BAT tid="74" bouquetid="40000" version="1" current_next="1">
<DESC id="0x47" length="17" value="5465737420426f7571756574204e616d65">
<BOUQUET_NAME_DESC bouquetname="Test Bouquet Name"/>
</DESC>
@ -248,15 +248,15 @@
</DESC>
</SERVICE>
</SDT>
<EIT tableid="0x4e" type="actual_pf" service_id="20000" version="0" current_next="1" tsid="10000" onid="40000" seg_last_sec_number="0" last_table_id="0x00">
<EIT tableid="0x4e" type="actual_pf" service_id="20000" version="0" current_next="1" tsid="10000" onid="40000">
</EIT>
<EIT tableid="0x4e" type="actual_pf" service_id="20000" version="1" current_next="1" tsid="10000" onid="40000" seg_last_sec_number="0" last_table_id="0x00">
<EVENT id="30000" start_time="1234567890" start_time_dec="2009-02-13 23:31:30 UTC" duration="86399" duration_dec="23:59:59" running_status="2" free_CA_mode="0">
<EIT tableid="0x4e" type="actual_pf" service_id="20000" version="1" current_next="1" tsid="10000" onid="40000">
<EVENT id="30000" start_time="1234567890" start_time_dec="2009-02-13 23:31:30 UTC" duration="86399" duration_dec="23:59:59" running="2" free_CA="0">
<DESC id="0x4d" length="44" value="656e670e4d616a6f72205456206576656e7419546865206576656e74206f66207468652063656e7475727921">
<SHORT_EVENT_DESC lang="eng" event_name="Major TV event" text="The event of the century!"/>
</DESC>
</EVENT>
<EVENT id="30100" start_time="1" start_time_dec="1970-01-01 00:00:01 UTC" duration="3600" duration_dec="01:00:00" running_status="1" free_CA_mode="0">
<EVENT id="30100" start_time="1" start_time_dec="1970-01-01 00:00:01 UTC" duration="3600" duration_dec="01:00:00" running="1" free_CA="0">
<DESC id="0x4a" length="10" value="29cc9efc50dc0d7918ff">
<LINKAGE_DESC tsid="10700" onid="40700" sid="20700" linkage="0x0d" linkage_txt="event linkage">
<EVENT_LINKAGE target_event_id="31000" target_listed="1" event_simulcast="1"/>
@ -276,7 +276,7 @@
<SHORT_SMOOTHING_BUFFER_DESC sb_size="1" sb_leak_rate="10"/>
</DESC>
</EVENT>
<EVENT id="30200" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running_status="0" free_CA_mode="0">
<EVENT id="30200" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running="0" free_CA="0">
<DESC id="0x4a" length="31" value="2a309f6051400e79185f1ec67d00c3a41055f080e8e732c8a7f859d884d000">
<LINKAGE_DESC tsid="10800" onid="40800" sid="20800" linkage="0x0e" linkage_txt="extended event linkage">
<EXTENDED_EVENT_LINKAGE target_event_id="31000" target_listed="0" event_simulcast="1" link_type="1" link_type_txt="HD" target_id_type="3" target_id_type_txt="use user_defined_id" onid_id_flag="1" service_id_flag="1" user_defined_id="7878" target_tsid="0" target_onid="0" target_service_id="0"/>
@ -307,7 +307,7 @@
<TIME_SHIFTED_EVENT_DESC reference_sid="22000" reference_event_id="32000"/>
</DESC>
</EVENT>
<EVENT id="30300" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running_status="4" free_CA_mode="1">
<EVENT id="30300" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running="4" free_CA="1">
<DESC id="0x54" length="4" value="244e68b1">
<CONTENT_DESC content_l1="2" content_l2="4" user="78"/>
<CONTENT_DESC content_l1="6" content_l2="8" user="177"/>
@ -350,9 +350,9 @@
<RST>
</RST>
<RST>
<STATUS tsid="10000" onid="40000" service_id="20000" event_id="30000" running_status="1"/>
<STATUS tsid="10100" onid="40100" service_id="20100" event_id="30100" running_status="2"/>
<STATUS tsid="10200" onid="40200" service_id="20200" event_id="30200" running_status="3"/>
<STATUS tsid="10000" onid="40000" service_id="20000" event_id="30000" running="1"/>
<STATUS tsid="10100" onid="40100" service_id="20100" event_id="30100" running="2"/>
<STATUS tsid="10200" onid="40200" service_id="20200" event_id="30200" running="3"/>
</RST>
<PMT program="20000" version="0" current_next="1" pcrpid="110">
</PMT>
@ -603,10 +603,12 @@
<DESC id="0x2b" length="3" value="120500">
<MPEG2_AAC_AUDIO_DESC profile="0x12" channel_config="0x05" additional_info="0x00"/>
</DESC>
<DESC id="0x7c" length="3" value="14ff1f">
<DESC id="0x7c" length="3" value="14801f">
<AAC_DESC profile_and_level="0x14" aac_type_flag="1" aac_type="0x1f"/>
</DESC>
</ES>
<ES pid="200" streamtype="0x86" streamtype_txt="SCTE 35 Splice Information Table">
</ES>
</PMT>
<DIT transition_flag="1"/>
<DIT transition_flag="0"/>
@ -616,7 +618,7 @@
<DESC id="0x63" length="8" value="c01388c01b58c3e8">
<PARTIAL_TRANSPORT_STREAM_DESC peak_rate="5000" min_overall_smoothing_rate="7000" max_overall_smoothing_buffer="1000"/>
</DESC>
<SERVICE sid="20000" running_status="1">
<SERVICE sid="20000" running="1">
<DESC id="0x05" length="4" value="54455354">
<REGISTRATION_DESC identifier="TEST"/>
</DESC>
@ -627,7 +629,9 @@
<REGISTRATION_DESC identifier="TEST"/>
</DESC>
</SERVICE>
<SERVICE sid="21000" running_status="3">
<SERVICE sid="21000" running="3">
</SERVICE>
</SIT>
<SCTE35 command="5" command_str="insert" pts_adjustment="0" event_id="4242" cancel="0" out_of_network="1" program_splice="1" splice_time="270000000" auto_return="1" duration="27000000" unique_program_id="2424">
</SCTE35>
</TS>

+ 732
- 0
scte/35.h View File

@ -0,0 +1,732 @@
/*****************************************************************************
* 35.h: SCTE 35 Digital Program Insertion Cueing Message for Cable
*****************************************************************************
* Copyright (C) 2015 VideoLAN
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*****************************************************************************/
/*
* Normative references:
* - SCTE 35 2013 (Digital Program Insertion Cueing Message for Cable)
*/
#ifndef __BITSTREAM_SCTE_35_H__
#define __BITSTREAM_SCTE_35_H__
#include <bitstream/common.h>
#include <bitstream/mpeg/psi/psi.h>
#include <bitstream/mpeg/psi/descriptors.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* Splice Information Table
*****************************************************************************/
#define SCTE35_TABLE_ID 0xfc
#define SCTE35_HEADER_SIZE (PSI_HEADER_SIZE + 11)
#define SCTE35_HEADER2_SIZE 2
static inline void scte35_init(uint8_t *p_scte35)
{
psi_set_tableid(p_scte35, SCTE35_TABLE_ID);
psi_init(p_scte35, false);
p_scte35[1] &= ~0x40; /* private indicator */
p_scte35[3] = 0;
p_scte35[4] = 0;
p_scte35[9] = 0;
p_scte35[10] = 0xff;
p_scte35[11] = 0xf0;
}
static inline uint8_t scte35_get_protocol(const uint8_t *p_scte35)
{
return p_scte35[3];
}
static inline void scte35_set_protocol(uint8_t *p_scte35, uint8_t i_version)
{
p_scte35[3] = i_version;
}
static inline bool scte35_is_encrypted(const uint8_t *p_scte35)
{
return !!(p_scte35[4] & 0x80);
}
static inline void scte35_set_encrypted(uint8_t *p_scte35, bool b_encrypted)
{
if (b_encrypted)
p_scte35[4] |= 0x80;
else
p_scte35[4] &= ~0x80;
}
static inline uint64_t scte35_get_pts_adjustment(const uint8_t *p_scte35)
{
return ((uint64_t)(p_scte35[4] & 0x1) << 32) |
(p_scte35[5] << 24) | (p_scte35[6] << 16) |
(p_scte35[7] << 8) | p_scte35[8];
}
static inline void scte35_set_pts_adjustment(uint8_t *p_scte35,
uint64_t i_adjustment)
{
p_scte35[4] &= ~0x1;
p_scte35[4] |= (i_adjustment >> 32) & 0x1;
p_scte35[5] = (i_adjustment >> 24) & 0xff;
p_scte35[6] = (i_adjustment >> 16) & 0xff;
p_scte35[7] = (i_adjustment >> 8) & 0xff;
p_scte35[8] = i_adjustment & 0xff;
}
static inline uint16_t scte35_get_command_length(const uint8_t *p_scte35)
{
return ((p_scte35[11] & 0xf) << 8) | p_scte35[12];
}
static inline void scte35_set_command_length(uint8_t *p_scte35,
uint16_t i_length)
{
p_scte35[11] &= ~0xf;
p_scte35[11] |= (i_length >> 8) & 0xf;
p_scte35[12] = i_length & 0xff;
}
static inline uint8_t scte35_get_command_type(const uint8_t *p_scte35)
{
return p_scte35[13];
}
static inline void scte35_set_command_type(uint8_t *p_scte35, uint8_t i_type)
{
p_scte35[13] = i_type;
}
static inline uint8_t *scte35_get_command(const uint8_t *p_scte35)
{
return (uint8_t *)p_scte35 + SCTE35_HEADER_SIZE;
}
static inline uint16_t scte35_get_desclength(const uint8_t *p_scte35)
{
uint16_t i_command_length = scte35_get_command_length(p_scte35);
if (i_command_length == 0xfff)
return 0;
const uint8_t *pi_desclength = scte35_get_command(p_scte35) +
i_command_length;
return (pi_desclength[0] << 8) | pi_desclength[1];
}
static inline void scte35_set_desclength(uint8_t *p_scte35, uint16_t i_length)
{
uint8_t *pi_desclength = scte35_get_command(p_scte35) +
scte35_get_command_length(p_scte35);
pi_desclength[0] = (i_length >> 8) & 0xff;
pi_desclength[1] = i_length & 0xff;
}
static inline uint8_t *scte35_get_descl(const uint8_t *p_scte35)
{
uint16_t i_command_length = scte35_get_command_length(p_scte35);
if (i_command_length == 0xfff)
return NULL;
return scte35_get_command(p_scte35) + i_command_length +
SCTE35_HEADER2_SIZE;
}
/*****************************************************************************
* Splice Information Table - splice_time structure
*****************************************************************************/
#define SCTE35_SPLICE_TIME_HEADER_SIZE 1
#define SCTE35_SPLICE_TIME_TIME_SIZE 4
static inline void scte35_splice_time_init(uint8_t *p_splice_time)
{
p_splice_time[0] = 0x7f;
}
static inline bool scte35_splice_time_has_time_specified(const uint8_t *p_splice_time)
{
return !!(p_splice_time[0] & 0x80);
}
static inline void scte35_splice_time_set_time_specified(uint8_t *p_splice_time,
bool b_time_specified)
{
if (b_time_specified)
p_splice_time[0] |= 0x80;
else
p_splice_time[0] &= ~0x80;
}
static inline uint64_t scte35_splice_time_get_pts_time(const uint8_t *p_splice_time)
{
return ((uint64_t)(p_splice_time[0] & 0x1) << 32) |
((uint64_t)p_splice_time[1] << 24) |
((uint64_t)p_splice_time[2] << 16) |
((uint64_t)p_splice_time[3] << 8) |
(uint64_t)p_splice_time[4];
}
static inline void scte35_splice_time_set_pts_time(uint8_t *p_splice_time,
uint64_t i_pts_time)
{
p_splice_time[0] &= ~0x1;
p_splice_time[0] |= (i_pts_time >> 32) & 0x1;
p_splice_time[1] = (i_pts_time >> 24) & 0xff;
p_splice_time[2] = (i_pts_time >> 16) & 0xff;
p_splice_time[3] = (i_pts_time >> 8) & 0xff;
p_splice_time[4] = i_pts_time & 0xff;
}
static inline uint8_t scte35_splice_time_size(const uint8_t *p_splice_time)
{
return SCTE35_SPLICE_TIME_HEADER_SIZE +
(scte35_splice_time_has_time_specified(p_splice_time) ?
SCTE35_SPLICE_TIME_TIME_SIZE : 0);
}
/*****************************************************************************
* Splice Information Table - break_duration structure
*****************************************************************************/
#define SCTE35_BREAK_DURATION_HEADER_SIZE 5
static inline void scte35_break_duration_init(uint8_t *p_break_duration)
{
p_break_duration[0] = 0xff;
}
static inline bool scte35_break_duration_has_auto_return(const uint8_t *p_break_duration)
{
return !!(p_break_duration[0] & 0x80);
}
static inline void scte35_break_duration_set_auto_return(uint8_t *p_break_duration, bool b_auto_return)
{
if (b_auto_return)
p_break_duration[0] |= 0x80;
else
p_break_duration[0] &= ~0x80;
}
static inline uint64_t scte35_break_duration_get_duration(const uint8_t *p_break_duration)
{
return ((uint64_t)(p_break_duration[0] & 0x1) << 32) |
((uint64_t)p_break_duration[1] << 24) |
((uint64_t)p_break_duration[2] << 16) |
((uint64_t)p_break_duration[3] << 8) |
(uint64_t)p_break_duration[4];
}
static inline void scte35_break_duration_set_duration(uint8_t *p_break_duration,
uint64_t i_duration)
{
p_break_duration[0] &= ~0x1;
p_break_duration[0] |= (i_duration >> 32) & 0x1;
p_break_duration[1] = (i_duration >> 24) & 0xff;
p_break_duration[2] = (i_duration >> 16) & 0xff;
p_break_duration[3] = (i_duration >> 8) & 0xff;
p_break_duration[4] = i_duration & 0xff;
}
/*****************************************************************************
* Splice Information Table - null command
*****************************************************************************/
#define SCTE35_NULL_COMMAND 0
#define SCTE35_NULL_HEADER_SIZE 0
static inline void scte35_null_init(uint8_t *p_scte35)
{
scte35_init(p_scte35);
scte35_set_command_type(p_scte35, SCTE35_NULL_COMMAND);
scte35_set_command_length(p_scte35, SCTE35_NULL_HEADER_SIZE);
scte35_set_desclength(p_scte35, 0);
}
static inline bool scte35_null_validate(const uint8_t *p_scte35)
{
return true;
}
/*****************************************************************************
* Splice Information Table - schedule command
*****************************************************************************/
#define SCTE35_SCHEDULE_COMMAND 4
/* TODO Not implemented (useless) */
/*****************************************************************************
* Splice Information Table - insert command
*****************************************************************************/
#define SCTE35_INSERT_COMMAND 5
#define SCTE35_INSERT_HEADER_SIZE 5
#define SCTE35_INSERT_HEADER2_SIZE 1
#define SCTE35_INSERT_COMPONENT_COUNT_SIZE 1
#define SCTE35_INSERT_COMPONENT_HEADER_SIZE 1
#define SCTE35_INSERT_FOOTER_SIZE 4
static inline void scte35_insert_init(uint8_t *p_scte35, uint16_t i_length)
{
scte35_init(p_scte35);
scte35_set_command_type(p_scte35, SCTE35_INSERT_COMMAND);
scte35_set_command_length(p_scte35,
SCTE35_INSERT_HEADER_SIZE + i_length);
scte35_set_desclength(p_scte35, 0);
uint8_t *p_command = scte35_get_command(p_scte35);
p_command[4] = 0xff;
}
static inline uint32_t scte35_insert_get_event_id(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return (p_command[0] << 24) | (p_command[1] << 16) |
(p_command[2] << 8) | p_command[3];
}
static inline void scte35_insert_set_event_id(uint8_t *p_scte35,
uint32_t i_event_id)
{
uint8_t *p_command = scte35_get_command(p_scte35);
p_command[0] = (i_event_id >> 24) & 0xff;
p_command[1] = (i_event_id >> 16) & 0xff;
p_command[2] = (i_event_id >> 8) & 0xff;
p_command[3] = i_event_id & 0xff;
}
static inline bool scte35_insert_has_cancel(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return !!(p_command[4] & 0x80);
}
static inline void scte35_insert_set_cancel(const uint8_t *p_scte35,
bool b_cancel)
{
uint8_t *p_command = scte35_get_command(p_scte35);
if (b_cancel)
p_command[4] |= 0x80;
else {
p_command[4] &= ~0x80;
p_command[5] = 0xff;
}
}
static inline bool scte35_insert_has_out_of_network(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return !!(p_command[5] & 0x80);
}
static inline void scte35_insert_set_out_of_network(const uint8_t *p_scte35,
bool b_out_of_network)
{
uint8_t *p_command = scte35_get_command(p_scte35);
if (b_out_of_network)
p_command[5] |= 0x80;
else
p_command[5] &= ~0x80;
}
static inline bool scte35_insert_has_program_splice(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return !!(p_command[5] & 0x40);
}
static inline void scte35_insert_set_program_splice(const uint8_t *p_scte35,
bool b_program_splice)
{
uint8_t *p_command = scte35_get_command(p_scte35);
if (b_program_splice)
p_command[5] |= 0x40;
else
p_command[5] &= ~0x40;
}
static inline bool scte35_insert_has_duration(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return !!(p_command[5] & 0x20);
}
static inline void scte35_insert_set_duration(const uint8_t *p_scte35,
bool b_duration)
{
uint8_t *p_command = scte35_get_command(p_scte35);
if (b_duration)
p_command[5] |= 0x20;
else
p_command[5] &= ~0x20;
}
static inline bool scte35_insert_has_splice_immediate(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return !!(p_command[5] & 0x10);
}
static inline void scte35_insert_set_splice_immediate(const uint8_t *p_scte35,
bool b_splice_immediate)
{
uint8_t *p_command = scte35_get_command(p_scte35);
if (b_splice_immediate)
p_command[5] |= 0x10;
else
p_command[5] &= ~0x10;
}
static inline uint8_t *scte35_insert_get_splice_time(const uint8_t *p_scte35)
{
uint8_t *p_command = scte35_get_command(p_scte35);
return p_command + SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE;
}
static inline uint8_t scte35_insert_get_component_count(const uint8_t *p_scte35)
{
uint8_t *p_command = scte35_get_command(p_scte35);
return p_command[SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE];
}
static inline void scte35_insert_set_component_count(uint8_t *p_scte35,
uint8_t i_component_count)
{
uint8_t *p_command = scte35_get_command(p_scte35);
p_command[SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE] =
i_component_count;
}
static inline uint8_t scte35_insert_component_get_component_tag(const uint8_t *p_component)
{
return p_component[0];
}
static inline void scte35_insert_component_set_component_tag(uint8_t *p_component, uint8_t i_component_tag)
{
p_component[0] = i_component_tag;
}
static inline uint8_t *scte35_insert_component_get_splice_time(const uint8_t *p_component)
{
return (uint8_t *)p_component + SCTE35_INSERT_COMPONENT_HEADER_SIZE;
}
static inline uint8_t *scte35_insert_get_component(const uint8_t *p_scte35,
uint8_t n)
{
uint16_t i_section_size = psi_get_length(p_scte35) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
bool b_splice_immediate = scte35_insert_has_splice_immediate(p_scte35);
uint8_t *p_scte35_n = scte35_get_command(p_scte35) +
SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
SCTE35_INSERT_COMPONENT_COUNT_SIZE;
if (p_scte35_n - p_scte35 > i_section_size)
return NULL;
while (n) {
if (p_scte35_n + SCTE35_INSERT_COMPONENT_HEADER_SIZE - p_scte35 >
i_section_size)
return NULL;
p_scte35_n += SCTE35_INSERT_COMPONENT_HEADER_SIZE +
(b_splice_immediate ?
scte35_splice_time_size(
scte35_insert_component_get_splice_time(p_scte35_n)) :
0);
n--;
}
if (p_scte35_n - p_scte35 >= i_section_size) return NULL;
return p_scte35_n;
}
static inline uint8_t *scte35_insert_get_break_duration(const uint8_t *p_scte35)
{
if (!scte35_insert_has_program_splice(p_scte35))
return scte35_insert_get_component(p_scte35,
scte35_insert_get_component_count(p_scte35) + 1);
if (scte35_insert_has_splice_immediate(p_scte35))
return scte35_get_command(p_scte35) + SCTE35_INSERT_HEADER_SIZE +
SCTE35_INSERT_HEADER2_SIZE;
uint8_t *p_splice_time = scte35_insert_get_splice_time(p_scte35);
return p_splice_time + scte35_splice_time_size(p_splice_time);
}
static inline uint8_t *scte35_insert_get_footer(const uint8_t *p_scte35)
{
return scte35_insert_get_break_duration(p_scte35) +
(scte35_insert_has_duration(p_scte35) ?
SCTE35_BREAK_DURATION_HEADER_SIZE : 0);
}
static inline uint16_t scte35_insert_get_unique_program_id(const uint8_t *p_scte35)
{
uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
return (p_footer[0] << 8) | p_footer[1];
}
static inline void scte35_insert_set_unique_program_id(uint8_t *p_scte35,
uint16_t i_unique_program_id)
{
uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
p_footer[0] = (i_unique_program_id >> 8) & 0xff;
p_footer[1] = i_unique_program_id & 0xff;
}
static inline uint8_t scte35_insert_get_avail_num(const uint8_t *p_scte35)
{
uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
return p_footer[2];
}
static inline void scte35_insert_set_avail_num(uint8_t *p_scte35,
uint8_t i_avail_num)
{
uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
p_footer[2] = i_avail_num;
}
static inline uint8_t scte35_insert_get_avails_expected(const uint8_t *p_scte35)
{
uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
return p_footer[3];
}
static inline void scte35_insert_set_avails_expected(uint8_t *p_scte35,
uint8_t i_avails_expected)
{
uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
p_footer[3] = i_avails_expected;
}
static inline bool scte35_insert_validate(const uint8_t *p_scte35)
{
size_t i_length = scte35_get_command_length(p_scte35);
if (i_length < SCTE35_INSERT_HEADER_SIZE)
return false;
if (scte35_insert_has_cancel(p_scte35))
return i_length <= SCTE35_INSERT_HEADER_SIZE;
if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE)
return false;
if (scte35_insert_has_program_splice(p_scte35)) {
if (scte35_insert_has_splice_immediate(p_scte35)) {
if (scte35_insert_has_duration(p_scte35))
return i_length >= SCTE35_INSERT_HEADER_SIZE +
SCTE35_INSERT_HEADER2_SIZE +
SCTE35_BREAK_DURATION_HEADER_SIZE +
SCTE35_INSERT_FOOTER_SIZE;
return i_length >= SCTE35_INSERT_HEADER_SIZE +
SCTE35_INSERT_HEADER2_SIZE +
SCTE35_INSERT_FOOTER_SIZE;
}
if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
SCTE35_SPLICE_TIME_HEADER_SIZE ||
i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
scte35_splice_time_size(
scte35_insert_get_splice_time(p_scte35)))
return false;
if (scte35_insert_has_duration(p_scte35))
return i_length >= SCTE35_INSERT_HEADER_SIZE +
SCTE35_INSERT_HEADER2_SIZE +
scte35_splice_time_size(scte35_insert_get_splice_time(p_scte35))
+ SCTE35_BREAK_DURATION_HEADER_SIZE +
SCTE35_INSERT_FOOTER_SIZE;
return i_length >= SCTE35_INSERT_HEADER_SIZE +
SCTE35_INSERT_HEADER2_SIZE +
scte35_splice_time_size(scte35_insert_get_splice_time(p_scte35))
+ SCTE35_INSERT_FOOTER_SIZE;
}
if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
SCTE35_INSERT_COMPONENT_COUNT_SIZE)
return false;
const uint8_t *p_command = scte35_get_command(p_scte35);
const uint8_t *p_end = scte35_insert_get_component(p_scte35,
scte35_insert_get_component_count(p_scte35) + 1);
if (p_end == NULL)
return false;
if (scte35_insert_has_duration(p_scte35))
return i_length >= p_end + SCTE35_BREAK_DURATION_HEADER_SIZE +
SCTE35_INSERT_FOOTER_SIZE - p_command;
return i_length >= p_end + SCTE35_INSERT_FOOTER_SIZE - p_command;
}
/*****************************************************************************
* Splice Information Table - time_signal command
*****************************************************************************/
#define SCTE35_TIME_SIGNAL_COMMAND 6
#define SCTE35_TIME_SIGNAL_HEADER_SIZE SCTE35_SPLICE_TIME_HEADER_SIZE
#define SCTE35_TIME_SIGNAL_TIME_SIZE SCTE35_SPLICE_TIME_TIME_SIZE
static inline void scte35_time_signal_init(uint8_t *p_scte35, uint16_t i_length)
{
scte35_init(p_scte35);
scte35_set_command_type(p_scte35, SCTE35_TIME_SIGNAL_COMMAND);
scte35_set_command_length(p_scte35,
SCTE35_TIME_SIGNAL_HEADER_SIZE + i_length);
scte35_set_desclength(p_scte35, 0);
}
static inline uint8_t *scte35_time_signal_get_splice_time(const uint8_t *p_scte35)
{
return scte35_get_command(p_scte35);
}
static inline bool scte35_time_signal_validate(const uint8_t *p_scte35)
{
return scte35_get_command_length(p_scte35) >=
scte35_splice_time_size(scte35_time_signal_get_splice_time(p_scte35));
}
/*****************************************************************************
* Splice Information Table - bandwidth_reservation command
*****************************************************************************/
#define SCTE35_BANDWIDTH_RESERVATION_COMMAND 7
#define SCTE35_BANDWIDTH_RESERVATION_HEADER_SIZE 0
static inline void scte35_bandwidth_reservation_init(uint8_t *p_scte35)
{
scte35_init(p_scte35);
scte35_set_command_type(p_scte35, SCTE35_BANDWIDTH_RESERVATION_COMMAND);
scte35_set_command_length(p_scte35,
SCTE35_BANDWIDTH_RESERVATION_HEADER_SIZE);
scte35_set_desclength(p_scte35, 0);
}
static inline bool scte35_bandwidth_reservation_validate(const uint8_t *p_scte35)
{
return true;
}
/*****************************************************************************
* Splice Information Table - private command
*****************************************************************************/
#define SCTE35_PRIVATE_COMMAND 0xff
#define SCTE35_PRIVATE_HEADER_SIZE 4
static inline void scte35_private_init(uint8_t *p_scte35, uint16_t i_length)
{
scte35_init(p_scte35);
scte35_set_command_type(p_scte35, SCTE35_PRIVATE_COMMAND);
scte35_set_command_length(p_scte35,
SCTE35_PRIVATE_HEADER_SIZE + i_length);
scte35_set_desclength(p_scte35, 0);
}
static inline uint32_t scte35_private_get_identifier(const uint8_t *p_scte35)
{
const uint8_t *p_command = scte35_get_command(p_scte35);
return (p_command[0] << 24) | (p_command[1] << 16) |
(p_command[2] << 8) | p_command[3];
}
static inline void scte35_private_set_identifier(uint8_t *p_scte35,
uint32_t i_identifier)
{
uint8_t *p_command = scte35_get_command(p_scte35);
p_command[0] = (i_identifier >> 24) & 0xff;
p_command[1] = (i_identifier >> 16) & 0xff;
p_command[2] = (i_identifier >> 8) & 0xff;
p_command[3] = i_identifier & 0xff;
}
static inline bool scte35_private_validate(const uint8_t *p_scte35)
{
return scte35_get_command_length(p_scte35) >= SCTE35_PRIVATE_HEADER_SIZE;
}
/*****************************************************************************
* Splice Information Table validation
*****************************************************************************/
static inline bool scte35_validate(const uint8_t *p_scte35)
{
if (psi_get_syntax(p_scte35) ||
psi_get_tableid(p_scte35) != SCTE35_TABLE_ID)
return false;
if (!psi_check_crc(p_scte35))
return false;
if (scte35_get_protocol(p_scte35))
return false;
uint16_t i_section_size = psi_get_length(p_scte35) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
if (i_section_size < SCTE35_HEADER_SIZE)
return false;
uint16_t i_command_length = scte35_get_command_length(p_scte35);
if (i_command_length != 0xfff &&
(i_section_size < SCTE35_HEADER_SIZE + i_command_length +
SCTE35_HEADER2_SIZE ||
i_section_size < SCTE35_HEADER_SIZE + i_command_length +
SCTE35_HEADER2_SIZE +
scte35_get_desclength(p_scte35)))
return false;
switch (scte35_get_command_type(p_scte35)) {
case SCTE35_NULL_COMMAND:
if (!scte35_null_validate(p_scte35))
return false;
break;
case SCTE35_INSERT_COMMAND:
if (!scte35_insert_validate(p_scte35))
return false;
break;
case SCTE35_TIME_SIGNAL_COMMAND:
if (!scte35_time_signal_validate(p_scte35))
return false;
break;
case SCTE35_BANDWIDTH_RESERVATION_COMMAND:
if (!scte35_bandwidth_reservation_validate(p_scte35))
return false;
break;
case SCTE35_PRIVATE_COMMAND:
if (!scte35_private_validate(p_scte35))
return false;
break;
default:
break;
}
if (i_command_length != 0xfff &&
!descl_validate(scte35_get_descl(p_scte35),
scte35_get_desclength(p_scte35)))
return false;
return true;
}
#ifdef __cplusplus
}
#endif
#endif

+ 296
- 0
scte/35_print.h View File

@ -0,0 +1,296 @@
/*****************************************************************************
* 35_print.h: SCTE 35 Digital Program Insertion Cueing Message for Cable
* (printing)
*****************************************************************************
* Copyright (C) 2015 VideoLAN
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#ifndef __BITSTREAM_SCTE_35_PRINT_H__
#define __BITSTREAM_SCTE_35_PRINT_H__
#include <bitstream/common.h>
#include <bitstream/mpeg/psi/psi.h>
#include <bitstream/mpeg/psi/descs_print.h>
#include <bitstream/scte/35.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* Splice Information Table
*****************************************************************************/
static inline const char *scte35_get_command_type_txt(uint8_t i_type) {
switch (i_type) {
case SCTE35_NULL_COMMAND: return "null";
case SCTE35_SCHEDULE_COMMAND: return "schedule";
case SCTE35_INSERT_COMMAND: return "insert";
case SCTE35_TIME_SIGNAL_COMMAND: return "time_signal";
case SCTE35_BANDWIDTH_RESERVATION_COMMAND: return "bandwidth_reservation";
case SCTE35_PRIVATE_COMMAND: return "private";
default: return "reserved";
}
}
static inline void scte35_null_print(const uint8_t *p_scte35,
f_print pf_print, void *print_opaque, print_type_t i_print_type)
{
uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
switch (i_print_type) {
case PRINT_XML:
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"null\" pts_adjustment=\"%"PRIu64"\">",
SCTE35_NULL_COMMAND, i_pts_adjustment);
break;
default:
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=null pts_adjustment=%"PRIu64,
SCTE35_NULL_COMMAND, i_pts_adjustment);
}
}
static inline void scte35_insert_print(const uint8_t *p_scte35,
f_print pf_print, void *print_opaque, print_type_t i_print_type)
{
uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
uint32_t i_event_id = scte35_insert_get_event_id(p_scte35);
if (scte35_insert_has_cancel(p_scte35)) {
switch (i_print_type) {
case PRINT_XML:
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"insert\" pts_adjustment=\"%"PRIu64"\" event_id=\"%"PRIu32"\" cancel=\"1\">",
SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id);
break;
default:
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=insert pts_adjustment=%"PRIu64" event_id=%"PRIu32" cancel=true",
SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id);
}
return;
}
bool b_out_of_network = scte35_insert_has_out_of_network(p_scte35);
bool b_program_splice = scte35_insert_has_program_splice(p_scte35);
bool b_duration = scte35_insert_has_duration(p_scte35);
bool b_splice_immediate = scte35_insert_has_splice_immediate(p_scte35);
uint16_t i_unique_program_id = scte35_insert_get_unique_program_id(p_scte35);
char psz_duration[256];
psz_duration[0] = '\0';
psz_duration[255] = '\0';
if (b_duration) {
const uint8_t *p_break_duration =
scte35_insert_get_break_duration(p_scte35);
bool b_auto_return =
scte35_break_duration_has_auto_return(p_break_duration);
uint64_t i_duration =
scte35_break_duration_get_duration(p_break_duration);
switch (i_print_type) {
case PRINT_XML:
snprintf(psz_duration, 255,
" auto_return=\"%d\" duration=\"%"PRIu64"\"",
b_auto_return ? 1 : 0, i_duration);
break;
default:
snprintf(psz_duration, 255,
" auto_return=%s duration=%"PRIu64"",
b_auto_return ? "true" : "false", i_duration);
}
}
char psz_splice_time[256];
psz_splice_time[0] = '\0';
psz_splice_time[255] = '\0';
if (b_splice_immediate) {
switch (i_print_type) {
case PRINT_XML:
snprintf(psz_splice_time, 255, " splice_time=\"immediate\"");
break;
default:
snprintf(psz_splice_time, 255, " splice_time=immediate");
}
} else {
const uint8_t *p_splice_time = NULL;
if (b_program_splice)
p_splice_time = scte35_insert_get_splice_time(p_scte35);
else if (scte35_insert_get_component_count(p_scte35))
p_splice_time = scte35_insert_component_get_splice_time(
scte35_insert_get_component(p_scte35, 0));
if (p_splice_time == NULL ||
!scte35_splice_time_has_time_specified(p_splice_time)) {
switch (i_print_type) {
case PRINT_XML:
snprintf(psz_splice_time, 255, " splice_time=\"undefined\"");
break;
default:
snprintf(psz_splice_time, 255, " splice_time=undefined");
}
} else {
uint64_t i_pts_time =
scte35_splice_time_get_pts_time(p_splice_time);
switch (i_print_type) {
case PRINT_XML:
snprintf(psz_splice_time, 255, " splice_time=\"%"PRIu64"\"",
i_pts_time);
break;
default:
snprintf(psz_splice_time, 255, " splice_time=%"PRIu64"",
i_pts_time);
}
}
}
switch (i_print_type) {
case PRINT_XML:
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"insert\" pts_adjustment=\"%"PRIu64"\" event_id=\"%"PRIu32"\" cancel=\"0\" out_of_network=\"%d\" program_splice=\"%d\"%s%s unique_program_id=\"%"PRIu16"\">",
SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id,
b_out_of_network ? 1 : 0, b_program_splice ? 1 : 0,
psz_splice_time, psz_duration, i_unique_program_id);
break;
default:
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=insert pts_adjustment=%"PRIu64" event_id=%"PRIu32" cancel=false out_of_network=%s program_splice=%s%s%s unique_program_id=%"PRIu16,
SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id,
b_out_of_network ? "true" : "false",
b_program_splice ? "true" : "false",
psz_splice_time, psz_duration, i_unique_program_id);
}
}
static inline void scte35_time_signal_print(const uint8_t *p_scte35,
f_print pf_print, void *print_opaque, print_type_t i_print_type)
{
uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
const uint8_t *p_splice_time = scte35_time_signal_get_splice_time(p_scte35);
switch (i_print_type) {
case PRINT_XML:
if (scte35_splice_time_has_time_specified(p_splice_time))
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"time_signal\" pts_adjustment=\"%"PRIu64"\" splice_time=\"%"PRIu64"\">",
SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment,
scte35_splice_time_get_pts_time(p_splice_time));
else
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"time_signal\" pts_adjustment=\"%"PRIu64"\" splice_time=\"undefined\">",
SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment);
break;
default:
if (scte35_splice_time_has_time_specified(p_splice_time))
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=time_signal pts_adjustment=%"PRIu64" splice_time=%"PRIu64,
SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment,
scte35_splice_time_get_pts_time(p_splice_time));
else
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=time_signal pts_adjustment=%"PRIu64" splice_time=undefined",
SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment);
}
}
static inline void scte35_private_print(const uint8_t *p_scte35,
f_print pf_print, void *print_opaque, print_type_t i_print_type)
{
uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
uint32_t i_identifier = scte35_private_get_identifier(p_scte35);
switch (i_print_type) {
case PRINT_XML:
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"private\" pts_adjustment=\"%"PRIu64"\" identifier=\"%"PRIu32"\" />",
SCTE35_PRIVATE_COMMAND, i_pts_adjustment, i_identifier);
break;
default:
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=private pts_adjustment=%"PRIu64" identifier=%"PRIu32,
SCTE35_PRIVATE_COMMAND, i_pts_adjustment, i_identifier);
}
}
static inline void scte35_print(const uint8_t *p_scte35,
f_print pf_print, void *print_opaque, print_type_t i_print_type)
{
uint8_t i_type = scte35_get_command_type(p_scte35);
bool done = false;
switch (i_type) {
case SCTE35_NULL_COMMAND:
scte35_null_print(p_scte35, pf_print, print_opaque, i_print_type);
done = true;
break;
case SCTE35_INSERT_COMMAND:
scte35_insert_print(p_scte35, pf_print, print_opaque, i_print_type);
done = true;
break;
case SCTE35_TIME_SIGNAL_COMMAND:
scte35_time_signal_print(p_scte35, pf_print, print_opaque, i_print_type);
done = true;
break;
case SCTE35_PRIVATE_COMMAND:
scte35_private_print(p_scte35, pf_print, print_opaque, i_print_type);
done = true;
break;
default:
break;
}
if (!done) {
uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
switch (i_print_type) {
case PRINT_XML:
pf_print(print_opaque,
"<SCTE35 command=\"%"PRIu8"\" command_str=\"%s\" pts_adjustment=\"%"PRIu64"\">",
i_type, scte35_get_command_type_txt(i_type), i_pts_adjustment);
break;
default:
pf_print(print_opaque,
"new SCTE35 command=%"PRIu8" command_str=%s pts_adjustment=%"PRIu64,
i_type, scte35_get_command_type_txt(i_type), i_pts_adjustment);
}
}
/* TODO: print descriptors */
switch (i_print_type) {
case PRINT_XML:
pf_print(print_opaque, "</SCTE35>");
break;
default:
pf_print(print_opaque, "end SCTE35");
}
}
#ifdef __cplusplus
}
#endif
#endif

Loading…
Cancel
Save