Add support for queued PMTs if they are large.

sdt
Kieran Kunhya 2011-01-26 20:26:53 +00:00
rodzic 8c2fed1daa
commit 097953cadf
3 zmienionych plików z 166 dodań i 92 usunięć

Wyświetl plik

@ -241,6 +241,9 @@ typedef struct
ts_int_stream_t pmt;
int program_num;
int num_queued_pmt;
uint8_t **pmt_packets;
int num_streams;
ts_int_stream_t *streams[MAX_STREAMS];
ts_int_stream_t *pcr_stream;
@ -325,7 +328,7 @@ enum adaptation_field_control_e
};
void write_bytes( bs_t *s, uint8_t *bytes, int length );
void write_packet_header( ts_writer_t *w, int start, int pid, int adapt_field, int *cc );
void write_packet_header( ts_writer_t *w, bs_t *s, int start, int pid, int adapt_field, int *cc );
void write_registration_descriptor( bs_t *s, int descriptor_tag, int descriptor_length, char *format_id );
void write_crc( bs_t *s, int start );
int write_padding( bs_t *s, int start );

Wyświetl plik

@ -95,7 +95,7 @@ void write_nit( ts_writer_t *w )
bs_t *s = &w->out.bs;
write_packet_header( w, 1, w->network_pid, PAYLOAD_ONLY, &w->nit->cc );
write_packet_header( w, s, 1, w->network_pid, PAYLOAD_ONLY, &w->nit->cc );
bs_write( s, 8, 0 ); // pointer field
@ -142,7 +142,7 @@ void write_sdt( ts_writer_t *w )
bs_t *s = &w->out.bs;
write_packet_header( w, 1, SDT_PID, PAYLOAD_ONLY, &w->sdt->cc );
write_packet_header( w, s, 1, SDT_PID, PAYLOAD_ONLY, &w->sdt->cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );
@ -204,7 +204,7 @@ void write_eit( ts_writer_t *w )
bs_t *s = &w->out.bs;
write_packet_header( w, 1, EIT_PID, PAYLOAD_ONLY, &w->eit->cc );
write_packet_header( w, s, 1, EIT_PID, PAYLOAD_ONLY, &w->eit->cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );
@ -225,7 +225,7 @@ void write_tdt( ts_writer_t *w )
bs_t *s = &w->out.bs;
write_packet_header( w, 1, TDT_PID, PAYLOAD_ONLY, &w->tdt->cc );
write_packet_header( w, s, 1, TDT_PID, PAYLOAD_ONLY, &w->tdt->cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );

Wyświetl plik

@ -68,6 +68,7 @@ static void write_ac3_descriptor( ts_writer_t *w, bs_t *s, int e_ac3 );
static int check_pcr( 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 );
static int eject_queued_pmt( ts_int_program_t *program, bs_t *s );
static int write_adaptation_field( ts_writer_t *w, bs_t *s, ts_int_program_t *program, ts_int_pes_t *pes,
int write_pcr, int flags, int stuffing, int discontinuity );
static void write_pcr_empty( ts_writer_t *w, ts_int_program_t *program, int first );
@ -78,7 +79,7 @@ static void drip_buffer( ts_int_program_t *program, int rx, buffer_t *buffer, do
/* Tables */
static void write_pat( ts_writer_t *w );
static void write_pmt( ts_writer_t *w, ts_int_program_t *program );
static int write_pmt( ts_writer_t *w, ts_int_program_t *program );
static void write_timestamp( bs_t *s, uint64_t timestamp );
static int write_pes( ts_writer_t *w, ts_int_program_t *program, ts_frame_t *in_frame, ts_int_pes_t *out_pes );
@ -100,7 +101,7 @@ ts_writer_t *ts_create_writer( void )
int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
{
// TODO check for PID collisions, add MPTS support
if( params->ts_type < TS_TYPE_DVB || params->ts_type > TS_TYPE_BLU_RAY )
if( params->ts_type < TS_TYPE_GENERIC || params->ts_type > TS_TYPE_BLU_RAY )
{
fprintf( stderr, "Invalid Transport Stream type.\n" );
return -1;
@ -702,8 +703,11 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
w->out.i_bitstream += 100000;
w->out.p_bitstream = realloc( w->out.p_bitstream, w->out.i_bitstream );
if( !w->out.p_bitstream )
if( w->out.p_bitstream < 0 )
{
fprintf( stderr, "malloc failed\n" );
return -1;
}
intptr_t delta = w->out.p_bitstream - bs_bak;
@ -713,7 +717,12 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
bs_realign( s );
}
/* check for any queued PMT packets */
/* write any queued PMT packets */
if( program->num_queued_pmt )
{
eject_queued_pmt( program, s );
continue;
}
// FIXME at low bitrates this might need tweaking
@ -787,7 +796,7 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
if( pes->bytes_left >= pkt_bytes_left )
{
write_packet_header( w, pes_start, stream->pid, PAYLOAD_ONLY + ((!!adapt_field_len)<<1), &stream->cc );
write_packet_header( w, s, pes_start, stream->pid, PAYLOAD_ONLY + ((!!adapt_field_len)<<1), &stream->cc );
if( adapt_field_len )
write_adaptation_field( w, s, program, pes, write_pcr, 1, 0, 0 );
@ -816,7 +825,7 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
stuffing -= 2; /* 2 bytes for adaptation field in this case. NOTE: needs fixing if more private data added */
}
write_packet_header( w, pes_start, stream->pid, PAYLOAD_ONLY + ((!!adapt_field_len)<<1), &stream->cc );
write_packet_header( w, s, pes_start, stream->pid, PAYLOAD_ONLY + ((!!adapt_field_len)<<1), &stream->cc );
if( adapt_field_len )
write_adaptation_field( w, s, program, pes, write_pcr, flags, stuffing, 0 );
@ -910,7 +919,6 @@ int ts_close_writer( ts_writer_t *w )
for( int j = 0; j < w->programs[i]->num_streams; j++ )
{
// TODO free other stuff
free( w->programs[i]->streams[j] );
if( w->programs[i]->streams[j]->mpegvideo_ctx )
free( w->programs[i]->streams[j]->mpegvideo_ctx );
if( w->programs[i]->streams[j]->lpcm_ctx )
@ -919,6 +927,7 @@ int ts_close_writer( ts_writer_t *w )
free( w->programs[i]->streams[j]->atsc_ac3_ctx );
if( w->programs[i]->streams[j]->dvb_sub_ctx )
free( w->programs[i]->streams[j]->dvb_sub_ctx );
free( w->programs[i]->streams[j] );
}
}
@ -929,10 +938,8 @@ int ts_close_writer( ts_writer_t *w )
return 0;
}
void write_packet_header( ts_writer_t *w, int start, int pid, int adapt_field, int *cc )
void write_packet_header( ts_writer_t *w, bs_t *s, int start, int pid, int adapt_field, int *cc )
{
bs_t *s = &w->out.bs;
if( w->ts_type == TS_TYPE_BLU_RAY )
{
// tp_extra_header
@ -1154,11 +1161,29 @@ static void retransmit_psi_and_si( ts_writer_t *w, ts_int_program_t *program, in
{
w->last_pat = (uint64_t)(program->cur_pcr * 27000000LL);
write_pat( w );
write_pmt( w, program );
write_pmt( w, program ); // FIXME handle failure
}
}
static int eject_queued_pmt( ts_int_program_t *program, bs_t *s )
{
write_bytes( s, program->pmt_packets[0], TS_PACKET_SIZE );
if( program->num_queued_pmt > 1 )
memmove( &program->pmt_packets[0], &program->pmt_packets[1], (program->num_queued_pmt-1) * sizeof(uint8_t*) );
program->pmt_packets = realloc( program->pmt_packets, (program->num_queued_pmt-1) * sizeof(uint8_t*) );
if( program->pmt_packets < 0 )
{
fprintf( stderr, "malloc failed\n" );
return -1;
}
program->num_queued_pmt--;
return 0;
};
static int write_adaptation_field( ts_writer_t *w, bs_t *s, ts_int_program_t *program, ts_int_pes_t *pes,
int write_pcr, int flags, int stuffing, int discontinuity )
{
@ -1242,7 +1267,7 @@ static void write_pcr_empty( ts_writer_t *w, ts_int_program_t *program, int firs
{
bs_t *s = &w->out.bs;
write_packet_header( w, 0, program->pcr_stream->pid, ADAPT_FIELD_ONLY, &program->pcr_stream->cc );
write_packet_header( w, s, 0, program->pcr_stream->pid, ADAPT_FIELD_ONLY, &program->pcr_stream->cc );
int stuffing = 184 - 6 - 2; /* pcr, flags and length */
int discontinuity = first && w->ts_type == TS_TYPE_CABLELABS;
write_adaptation_field( w, s, program, NULL, 1, 1, stuffing, discontinuity );
@ -1257,7 +1282,7 @@ static void write_pat( ts_writer_t *w )
int start;
bs_t *s = &w->out.bs;
write_packet_header( w, 1, PAT_PID, PAYLOAD_ONLY, &w->pat_cc );
write_packet_header( w, s, 1, PAT_PID, PAYLOAD_ONLY, &w->pat_cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );
@ -1300,99 +1325,109 @@ static void write_pat( ts_writer_t *w )
increase_pcr( w, 1 );
}
static void write_pmt( ts_writer_t *w, ts_int_program_t *program )
static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
{
int start;
bs_t *s = &w->out.bs;
uint8_t temp[4096], temp2[1024];
bs_t q, r;
uint8_t pmt_buf[2048], temp[2048], temp1[2048];
bs_t o, p, q;
int section_length;
write_packet_header( w, 1, program->pmt.pid, PAYLOAD_ONLY, &program->pmt.cc );
/* this should never happen */
if( program->num_queued_pmt )
{
if( eject_queued_pmt( program, s ) < 0 )
return -1;
return 0;
}
start = bs_pos( s );
write_packet_header( w, s, 1, program->pmt.pid, PAYLOAD_ONLY, &program->pmt.cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );
bs_write( s, 8, PMT_TID ); // table_id = program_map_section
bs_write1( s, 1 ); // section_syntax_indicator
bs_write1( s, 0 ); // '0'
bs_write( s, 2, 0x3 ); // reserved
bs_init( &o, pmt_buf, 2048 );
bs_init( &q, temp, 4096 );
bs_write( &o, 8, PMT_TID ); // table_id = program_map_section
bs_write1( &o, 1 ); // section_syntax_indicator
bs_write1( &o, 0 ); // '0'
bs_write( &o, 2, 0x3 ); // reserved
bs_write( &q, 16, program->program_num & 0xffff ); // program_number
bs_write( &q, 2, 0x3 ); // reserved
bs_write( &q, 5, 0 ); // version_number
bs_write1( &q, 1 ); // current_next_indicator
bs_write( &q, 8, 0 ); // section_number
bs_write( &q, 8, 0 ); // last_section_number
bs_write( &q, 3, 0x7 ); // reserved
bs_init( &p, temp, 2048 );
bs_write( &q, 13, program->pcr_stream[0].pid & 0x1fff ); // PCR PID
bs_write( &q, 4, 0xf ); // reserved
bs_write( &p, 16, program->program_num & 0xffff ); // program_number
bs_write( &p, 2, 0x3 ); // reserved
bs_write( &p, 5, 0 ); // version_number
bs_write1( &p, 1 ); // current_next_indicator
bs_write( &p, 8, 0 ); // section_number
bs_write( &p, 8, 0 ); // last_section_number
bs_write( &p, 3, 0x7 ); // reserved
bs_write( &p, 13, program->pcr_stream[0].pid & 0x1fff ); // PCR PID
bs_write( &p, 4, 0xf ); // reserved
/* setup temporary bitstream context */
bs_init( &r, temp2, 1024 );
bs_init( &q, temp1, 2048 );
if( w->ts_type == TS_TYPE_ATSC )
{
write_registration_descriptor( &r, REGISTRATION_DESCRIPTOR_TAG, 4, "GA94" );
write_smoothing_buffer_descriptor( &r, program );
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "GA94" );
write_smoothing_buffer_descriptor( &q, program );
}
else if( w->ts_type == TS_TYPE_CABLELABS )
write_registration_descriptor( &r, REGISTRATION_DESCRIPTOR_TAG, 4, "SCTE" );
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "SCTE" );
else if( w->ts_type == TS_TYPE_BLU_RAY )
write_registration_descriptor( &r, REGISTRATION_DESCRIPTOR_TAG, 4, "HDMV" );
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "HDMV" );
if( program->cablelabs_is_3d )
write_cablelabs_3d_descriptor( &r );
write_cablelabs_3d_descriptor( &q );
/* Optional descriptor(s) here */
bs_flush( &r );
bs_write( &q, 12, bs_pos( &r ) >> 3 ); // program_info_length
write_bytes( &q, temp2, bs_pos( &r ) >> 3 );
bs_flush( &q );
bs_write( &p, 12, bs_pos( &q ) >> 3 ); // program_info_length
write_bytes( &p, temp1, bs_pos( &q ) >> 3 );
for( int i = 0; i < program->num_streams; i++ )
{
ts_int_stream_t *stream = program->streams[i];
bs_write( &q, 8, stream->stream_type & 0xff ); // stream_type
bs_write( &q, 3, 0x7 ); // reserved
bs_write( &q, 13, stream->pid & 0x1fff ); // elementary_PID
bs_write( &q, 4, 0xf ); // reserved
bs_write( &p, 8, stream->stream_type & 0xff ); // stream_type
bs_write( &p, 3, 0x7 ); // reserved
bs_write( &p, 13, stream->pid & 0x1fff ); // elementary_PID
bs_write( &p, 4, 0xf ); // reserved
/* setup temporary bitstream context */
bs_init( &r, temp2, 1024 );
/* reset temporary bitstream context for streams loop */
bs_init( &q, temp1, 512 );
// FIXME not in certain cases
write_data_stream_alignment_descriptor( &r );
write_data_stream_alignment_descriptor( &q );
if( stream->dvb_au )
{
if( w->ts_type == TS_TYPE_DVB )
write_adaptation_field_data_descriptor( &r, AU_INFORMATION_DATA_FIELD );
write_adaptation_field_data_descriptor( &q, AU_INFORMATION_DATA_FIELD );
else if( w->ts_type == TS_TYPE_CABLELABS )
write_scte_adaptation_descriptor( &r );
write_scte_adaptation_descriptor( &q );
}
if( stream->write_lang_code )
write_iso_lang_descriptor( &r, stream );
write_iso_lang_descriptor( &q, stream );
if( stream->has_stream_identifier )
write_stream_identifier_descriptor( &r, stream->stream_identifier );
write_stream_identifier_descriptor( &q, stream->stream_identifier );
if( stream->stream_format == LIBMPEGTS_VIDEO_MPEG2 )
{
if( w->ts_type == TS_TYPE_BLU_RAY )
write_hdmv_video_registration_descriptor( &r, stream );
write_hdmv_video_registration_descriptor( &q, stream );
}
else if( stream->stream_format == LIBMPEGTS_VIDEO_AVC )
{
write_avc_descriptor( &r, stream );
write_avc_descriptor( &q, stream );
if( w->ts_type == TS_TYPE_BLU_RAY )
write_hdmv_video_registration_descriptor( &r, stream );
write_hdmv_video_registration_descriptor( &q, stream );
}
else if( stream->stream_format == LIBMPEGTS_AUDIO_MPEG1 ||
stream->stream_format == LIBMPEGTS_AUDIO_MPEG2 )
@ -1402,28 +1437,28 @@ static void write_pmt( ts_writer_t *w, ts_int_program_t *program )
else if( stream->stream_format == LIBMPEGTS_AUDIO_ADTS || stream->stream_format == LIBMPEGTS_AUDIO_LATM )
{
if( w->ts_type == TS_TYPE_DVB )
write_aac_descriptor( &r, stream );
write_aac_descriptor( &q, stream );
}
else if( stream->stream_format == LIBMPEGTS_AUDIO_AC3 )
{
write_registration_descriptor( &r, REGISTRATION_DESCRIPTOR_TAG, 4, "AC-3" );
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "AC-3" );
if( stream->atsc_ac3_ctx && ( w->ts_type == TS_TYPE_ATSC || w->ts_type == TS_TYPE_CABLELABS ) )
write_atsc_ac3_descriptor( &r, stream->atsc_ac3_ctx );
write_atsc_ac3_descriptor( &q, stream->atsc_ac3_ctx );
else
write_ac3_descriptor( w, &r, 0 );
write_ac3_descriptor( w, &q, 0 );
}
else if( stream->stream_format == LIBMPEGTS_AUDIO_EAC3 ||
stream->stream_format == LIBMPEGTS_AUDIO_EAC3_SECONDARY )
{
write_registration_descriptor( &r, REGISTRATION_DESCRIPTOR_TAG, 4, "AC-3" );
write_ac3_descriptor( w, &r, 1 );
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "AC-3" );
write_ac3_descriptor( w, &q, 1 );
}
else if( stream->stream_format == LIBMPEGTS_AUDIO_DTS )
{
// TODO
}
else if( stream->stream_format == LIBMPEGTS_AUDIO_302M )
write_registration_descriptor( &r, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "BSSD" );
write_registration_descriptor( &q, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "BSSD" );
else if( stream->stream_format == LIBMPEGTS_DVB_SUB )
{
}
@ -1431,45 +1466,81 @@ static void write_pmt( ts_writer_t *w, ts_int_program_t *program )
{
}
else if( stream->stream_format == LIBMPEGTS_ANCILLARY_RDD11 )
write_registration_descriptor( &r, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "LU-A" );
write_registration_descriptor( &q, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "LU-A" );
else if( stream->stream_format == LIBMPEGTS_ANCILLARY_2038 )
{
write_registration_descriptor( &r, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "VANC" );
write_anc_data_descriptor( &r );
write_registration_descriptor( &q, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "VANC" );
write_anc_data_descriptor( &q );
}
// TODO other stream_type descriptors
/* Optional descriptor(s) here */
bs_flush( &r );
bs_write( &q, 12, bs_pos( &r ) >> 3 ); // ES_info_length
write_bytes( &q, temp2, bs_pos( &r ) >> 3 );
bs_flush( &q );
bs_write( &p, 12, bs_pos( &q ) >> 3 ); // ES_info_length
write_bytes( &p, temp1, bs_pos( &q ) >> 3 );
}
// FIXME this will fail with a lot of streams
bs_flush( &q );
if( 0 )
{
// TODO 21 bytes length of packet
}
else
section_length = bs_pos( &q ) >> 3;
/* section length includes crc */
section_length += 4;
bs_write( s, 12, section_length & 0x3ff );
write_bytes( s, temp, bs_pos( &q ) >> 3 );
section_length = (bs_pos( &p ) >> 3) + 4;
bs_write( &o, 12, section_length & 0x3ff );
/* write main chunk into pmt array */
bs_flush( &p );
write_bytes( &o, temp, bs_pos( &p ) >> 3 );
/* take crc of the whole program map section */
bs_flush( &o );
write_crc( &o, 0 );
int length = bs_pos( &o ) >> 3;
int bytes_left = TS_PACKET_SIZE - ((bs_pos( s ) - start) >> 3);
bs_flush( &o );
write_bytes( s, pmt_buf, MIN( bytes_left, length ) );
bs_flush( s );
write_crc( s, start );
/* -40 to include header and pointer field */
write_padding( s, start - 40 );
write_padding( s, start );
// TODO buffer management
increase_pcr( w, 1 );
int pos = MIN( bytes_left, length );
length -= MIN( bytes_left, length );
bytes_left = 184;
/* queue up pmt packets for spaced output */
while( length > bytes_left )
{
bs_t z;
program->pmt_packets = realloc( program->pmt_packets, (program->num_queued_pmt + 1) * sizeof(uint8_t*));
if( program->pmt_packets < 0 )
{
fprintf( stderr, "malloc failed" );
return -1;
}
program->pmt_packets[program->num_queued_pmt] = malloc( TS_PACKET_SIZE );
if( !program->pmt_packets[program->num_queued_pmt] )
{
fprintf( stderr, "malloc failed" );
return -1;
}
bs_init( &z, program->pmt_packets[program->num_queued_pmt], 188 );
write_packet_header( w, &z, 0, program->pmt.pid, PAYLOAD_ONLY, &program->pmt.cc );
write_bytes( &z, &temp[pos], MIN( bytes_left, length ) );
bs_flush( &z );
write_padding( &z, 0 );
pos += MIN( bytes_left, length );
length -= MIN( bytes_left, length );
program->num_queued_pmt++;
}
return 0;
}
/* DVB / Blu-Ray Service Information */
@ -1479,7 +1550,7 @@ static void write_sit( ts_writer_t *w )
int len = 0; // FIXME
bs_t *s = &w->out.bs;
write_packet_header( w, 1, SIT_PID, PAYLOAD_ONLY, &w->sit->cc );
write_packet_header( w, s, 1, SIT_PID, PAYLOAD_ONLY, &w->sit->cc );
bs_write( s, 8, 0 ); // pointer field
start = bs_pos( s );
@ -1640,7 +1711,7 @@ static void write_null_packet( ts_writer_t *w )
bs_t *s = &w->out.bs;
start = bs_pos( s );
write_packet_header( w, 0, NULL_PID, PAYLOAD_ONLY, &cc );
write_packet_header( w, s, 0, NULL_PID, PAYLOAD_ONLY, &cc );
write_padding( s, start );
increase_pcr( w, 1 );