Add initial support for SDT

sdt
Kieran Kunhya 2013-06-04 20:18:22 +01:00
rodzic 8a793d749c
commit 11b87d850c
5 zmienionych plików z 196 dodań i 64 usunięć

Wyświetl plik

@ -266,7 +266,7 @@ typedef struct
int64_t video_dts;
//sdt_program_ctx_t *sdt_ctx;
sdt_program_ctx_t sdt_ctx;
int is_3dtv;
int sb_leak_rate;
@ -298,6 +298,7 @@ struct ts_writer_t
int pat_period;
int pcr_period;
int sdt_period;
int first_input;
int pat_version;

173
dvb/dvb.c
Wyświetl plik

@ -115,24 +115,24 @@ void write_vbi_descriptor( bs_t *s, ts_int_stream_t *stream )
write_bytes( s, temp, bs_pos( &q ) >> 3 );
}
/*
static void write_service_descriptor( bs_t *s )
{
bs_write( s, 8, DVB_SERVICE_DESCRIPTOR_TAG ); // descriptor_tag
bs_write( s, 8, 0 ); // descriptor_length
bs_write( s, 8, 0 ); // service_type
bs_write( s, 8, 0 ); // service_provider_name_length
// TODO support more character codes
static void write_service_descriptor( bs_t *s, int service_type, char *provider_name, char *service_name )
{
int provider_name_length = strlen( provider_name );
int service_name_length = strlen( service_name );
bs_write( s, 8, DVB_SERVICE_DESCRIPTOR_TAG ); // descriptor_tag
bs_write( s, 8, provider_name_length + service_name_length + 3 ); // descriptor_length
bs_write( s, 8, service_type ); // service_type
bs_write( s, 8, provider_name_length ); // service_provider_name_length
while( *provider_name != '\0' )
bs_write( s, 8, *provider_name++ );
bs_write( s, 8, name_len ); // service_name_length
while( *name != '\0' )
bs_write( s, 8, *name++ );
bs_write( s, 8, service_name_length ); // service_name_length
while( *service_name != '\0' )
bs_write( s, 8, *service_name++ );
}
*/
/* DVB Service Information */
int write_nit( ts_writer_t *w )
@ -182,68 +182,135 @@ int write_nit( ts_writer_t *w )
return 0;
}
#if 0
/* "The SDT contains data describing the services in the system e.g. names of services, the service provider, etc" */
void write_sdt( ts_writer_t *w )
int write_sdt( ts_writer_t *w )
{
uint64_t start;
int i;
int start;
uint8_t *sdt_buf = NULL, *sdt_buf2 = NULL;
int buf_size = 0;
int ret = 0;
int section_length;
bs_t *s = &w->out.bs;
bs_t q, r;
/* Estimate size of buffer */
for( int i = 0; i < w->num_programs; i++ )
{
buf_size += strlen( w->programs[i]->sdt_ctx.provider_name );
buf_size += strlen( w->programs[i]->sdt_ctx.service_name );
}
buf_size <<= 1;
sdt_buf = malloc( buf_size );
if( !sdt_buf )
{
fprintf( stderr, "malloc failed" );
goto end;
}
sdt_buf2 = malloc( buf_size );
if( !sdt_buf2 )
{
fprintf( stderr, "malloc failed" );
goto end;
}
start = bs_pos( s );
write_packet_header( w, s, 1, SDT_PID, PAYLOAD_ONLY, &w->sdt->cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );
bs_write( s, 8, SDT_TID ); // table_id
bs_write1( s, 1 ); // section_syntax_indicator
bs_write1( s, 1 ); // reserved_future_use
bs_write1( s, 1 ); // reserved
bs_init( &q, sdt_buf, buf_size );
bs_write( &q, 8, SDT_TID ); // table_id
bs_write1( &q, 1 ); // section_syntax_indicator
bs_write1( &q, 1 ); // reserved_future_use
bs_write( &q, 2, 0x3 ); // reserved
// TODO temp
bs_init( &r, sdt_buf2, buf_size );
bs_write( &r, 16, w->ts_id ); // transport_stream_id
bs_write( &r, 2, 0x3 ); // reserved
bs_write( &r, 5, 0 ); // version_number
bs_write1( &r, 1 ); // current_next_indicator
bs_write( &r, 8, 0 ); // section_number
bs_write( &r, 8, 0 ); // last_section_number
bs_write( &r, 16, w->network_id ); // original_network_id
bs_write( &r, 8, 0xff ); // reserved_future_use
bs_write( s, 12, len ); // section_length
bs_write( s, 16, w->ts_id ); // transport_stream_id
bs_write( s, 2, 0x03 ); // reserved
bs_write( s, 5, 0 ); // version_number
bs_write1( s, 1 ); // current_next_indicator
bs_write( s, 8, 0 ); // section_number
bs_write( s, 8, 0 ); // last_section_number
bs_write( s, 8, w->nid ); // original_network_id
bs_write( s, 8, 0xff ); // reserved_future_use
for( i = 0; i < w->num_programs; i++ )
for( int i = 0; i < w->num_programs; i++ )
{
bs_write( s, 16, w->programs[i]->program_num & 0xffff ); // service_id (equivalent to program_number)
bs_write( s, 6, 0x7f ); // reserved_future_use
bs_write1( s, 0 ); // EIT_schedule_flag
bs_write1( s, 1 ); // EIT_present_following_flag
bs_write( s, 3, 0 ); // running_status
bs_write1( s, 1 ); // free_CA_mode
sdt_program_ctx_t *sdt_ctx = &w->programs[i]->sdt_ctx;
int provider_name_len = strlen( w->programs[i]->sdt_ctx->provider_name );
int name_len = strlen( w->programs[i]->sdt_ctx->service_name );
bs_write( &r, 16, w->programs[i]->program_num & 0xffff ); // service_id (equivalent to program_number)
bs_write( &r, 6, 0x3f ); // reserved_future_use
bs_write1( &r, 0 ); // EIT_schedule_flag
bs_write1( &r, 0 ); // EIT_present_following_flag
bs_write( &r, 3, 4 ); // running_status
bs_write1( &r, 0 ); // free_CA_mode
char *provider_name = w->programs[i]->sdt_ctx->provider_name;
char *name = w->programs[i]->sdt_ctx->service_name;
int provider_name_len = strlen( sdt_ctx->provider_name );
int service_name_len = strlen( sdt_ctx->service_name );
int descriptors_len = 5 + provider_name_len + name_len;
bs_write( s, 12, descriptors_len ); // descriptors_loop_length
char *provider_name = sdt_ctx->provider_name;
char *service_name = sdt_ctx->service_name;
int descriptors_len = 5 + provider_name_len + service_name_len;
bs_write( &r, 12, descriptors_len ); // descriptors_loop_length
// service descriptor (mandatory for DVB)
write_service_descriptor( &r, sdt_ctx->service_type, provider_name, service_name );
// other descriptor(s) here
}
bs_flush( s );
write_crc( s, start );
/* section length includes crc */
section_length = (bs_pos( &r ) >> 3) + 4;
bs_write( &q, 12, section_length & 0x3ff ); // section_length
// -40 to include header and pointer field
write_padding( s, start - 40 );
increase_pcr( w, 1 );
/* write main chunk into sdt array */
bs_flush( &r );
write_bytes( &q, sdt_buf2, bs_pos( &r ) >> 3 );
/* take crc of the whole service description section */
bs_flush( &q );
write_crc( &q, 0 );
int length = bs_pos( &q ) >> 3;
int bytes_left = TS_PACKET_SIZE - (( bs_pos( s ) - start ) >> 3);
bs_flush( &q );
write_bytes( s, sdt_buf, MIN( bytes_left, length ) );
bs_flush( s );
write_padding( s, start );
if( increase_pcr( w, 1, 0 ) < 0 )
goto end;
int pos = MIN( bytes_left, length );
length -= pos;
bytes_left = 184;
/* keep writing SDT packets */
while( length > bytes_left )
{
start = bs_pos( s );
write_packet_header( w, s, 1, SDT_PID, PAYLOAD_ONLY, &w->sdt->cc );
write_bytes( s, &sdt_buf[pos], MIN( bytes_left, length ) );
write_padding( s, start );
pos += MIN( bytes_left, length );
length -= MIN( bytes_left, length );
if( increase_pcr( w, 1, 0 ) < 0 )
goto end;
}
end:
free( sdt_buf );
free( sdt_buf2 );
return ret;
}
#endif
#if 0
// FIXME
// "the EIT contains data concerning events or programmes such as event name, start time, duration, etc.; "

Wyświetl plik

@ -44,6 +44,7 @@
#define TDT_TID 0x70
/* Default Retransmit times (ms) */
#define SDT_MAX_RETRANS_TIME 2000
#define EIT_MAX_RETRANS_TIME 2000
#define EIT_OTHER_TS_MAX_RETRANS_TIME 10000
#define TDT_MAX_RETRANS_TIME 25000
@ -62,7 +63,7 @@ void write_teletext_descriptor( bs_t *s, ts_int_stream_t *stream, int vbi );
void write_vbi_descriptor( bs_t *s, ts_int_stream_t *stream );
int write_nit( ts_writer_t *w );
//void write_sdt( ts_writer_t *w );
int write_sdt( ts_writer_t *w );
//void write_eit( ts_writer_t *w );
int write_tdt( ts_writer_t *w );

Wyświetl plik

@ -644,15 +644,22 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
static void retransmit_psi_and_si( ts_writer_t *w, ts_int_program_t *program, int first )
{
// TODO make this work with multiple programs
double cur_pcr = get_pcr_double( w, 0 );
if( (uint64_t)(cur_pcr * TS_CLOCK) - w->last_pat >= w->pat_period * 27000LL || first )
int64_t cur_pcr = get_pcr_int( w, 0 );
if( cur_pcr - w->last_pat >= w->pat_period * 27000LL || first )
{
/* Although it is not in line with the mux strategy it is good practice to write PAT and PMT together */
w->last_pat = (uint64_t)(cur_pcr * 27000000LL);
w->last_pat = cur_pcr;
write_pat( w ); // FIXME handle failure
write_pmt( w, program ); // FIXME handle failure
}
cur_pcr = get_pcr_int( w, 0 );
if( w->sdt && ( cur_pcr - w->last_sdt >= w->sdt_period * 27000LL || first ) )
{
w->last_sdt = cur_pcr;
write_sdt( w );
}
}
/* DVB / Blu-Ray Service Information */
@ -915,6 +922,28 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
cur_program->sb_size = params->programs[0].sb_size;
cur_program->video_dts = -1;
cur_program->sdt_ctx.service_type = params->programs[0].sdt.service_type;
if( params->programs[0].sdt.service_name )
{
cur_program->sdt_ctx.service_name = malloc( strlen( params->programs[0].sdt.service_name ) + 1 );
if( !cur_program->sdt_ctx.service_name )
{
fprintf( stderr, "Malloc failed\n" );
return -1;
}
strcpy( cur_program->sdt_ctx.service_name, params->programs[0].sdt.service_name );
}
if( params->programs[0].sdt.provider_name )
{
cur_program->sdt_ctx.provider_name = malloc( strlen( params->programs[0].sdt.provider_name ) + 1 );
if( !cur_program->sdt_ctx.provider_name )
{
fprintf( stderr, "Malloc failed\n" );
return -1;
}
strcpy( cur_program->sdt_ctx.provider_name, params->programs[0].sdt.provider_name );
}
for( int i = 0; i < params->programs[0].num_streams; i++ )
{
ts_stream_t *stream_in = &params->programs[0].streams[i];
@ -1028,6 +1057,7 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
w->pcr_period = params->pcr_period ? params->pcr_period : PCR_MAX_RETRANS_TIME;
w->pat_period = params->pat_period ? params->pat_period : PAT_MAX_RETRANS_TIME;
w->sdt_period = params->sdt_period ? params->sdt_period : SDT_MAX_RETRANS_TIME;
w->network_id = params->network_id ? params->network_id : DEFAULT_NID;
@ -1456,6 +1486,24 @@ int ts_setup_dvb_vbi( ts_writer_t *w, int pid, int num_vbis, ts_dvb_vbi_t *vbis
return 0;
}
int ts_setup_sdt( ts_writer_t *w )
{
w->sdt = calloc( 1, sizeof(*w->sdt) );
if( !w->sdt )
{
fprintf( stderr, "malloc failed\n" );
return -1;
}
return 0;
}
void ts_remove_sdt( ts_writer_t *w )
{
free( w->sdt );
w->sdt = NULL;
}
int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t **out, int *len, int64_t **pcr_list )
{
ts_int_program_t *program = w->programs[0];
@ -1863,9 +1911,19 @@ int ts_close_writer( ts_writer_t *w )
free( w->programs[i]->streams[j]->dvb_ttx_ctx );
if( w->programs[i]->streams[j]->dvb_vbi_ctx )
free( w->programs[i]->streams[j]->dvb_vbi_ctx );
free( w->programs[i]->streams[j] );
}
for( int j = 0; j < w->programs[i]->num_queued_pmt; j++ )
free( w->programs[i]->pmt_packets[j] );
if( w->programs[i]->pmt_packets )
free( w->programs[i]->pmt_packets );
if( w->programs[i]->sdt_ctx.service_name )
free( w->programs[i]->sdt_ctx.service_name );
if( w->programs[i]->sdt_ctx.provider_name )
free( w->programs[i]->sdt_ctx.provider_name );
free( w->programs[i] );
}

Wyświetl plik

@ -271,8 +271,12 @@ typedef struct
int is_3dtv;
/* ATSC */
int sb_leak_rate;
int sb_size;
/* DVB */
sdt_program_ctx_t sdt;
} ts_program_t;
/**** Functions ****/
@ -317,6 +321,7 @@ typedef struct ts_main_t
// FIXME dvb land
int network_id;
int sdt_period;
int nit_period;
int tdt_period;
int tot_period;
@ -508,16 +513,16 @@ typedef struct
int ts_setup_dvb_vbi( ts_writer_t *w, int pid, int num_vbis, ts_dvb_vbi_t *vbis );
/* SDT
* */
/* Service Description Table
*
* ts_setup_sdt enables SDT
* ts_remove_sdt disables SDT
*
*/
int ts_setup_sdt( ts_writer_t *w );
void ts_update_sdt( ts_writer_t *w );
void ts_remove_sdt( ts_writer_t *w );
int ts_program_setup_sdt( ts_writer_t *w );
void ts_program_update_sdt( ts_writer_t *w );
/* Network Information Table */
typedef struct