kopia lustrzana https://github.com/kierank/libmpegts
Merge branch 'staging'
commit
2b7f128488
|
@ -38,3 +38,10 @@ void write_scte_adaptation_descriptor( bs_t *s )
|
|||
bs_write( s, 8, SCTE_ADAPTATION_FIELD_DESCRIPTOR_TAG ); // descriptor_tag
|
||||
bs_write( s, 8, 0 ); // descriptor_length
|
||||
}
|
||||
|
||||
void write_scte35_cue_identifier_descriptor( bs_t *s )
|
||||
{
|
||||
bs_write( s, 8, SCTE35_CUE_IDENTIFIER_DESCRIPTOR_TAG ); // descriptor_tag
|
||||
bs_write( s, 8, 1 ); // descriptor_length
|
||||
bs_write( s, 8, 0 ); // cue_stream_type
|
||||
}
|
|
@ -24,8 +24,10 @@
|
|||
/* Descriptors */
|
||||
#define SCTE_ADAPTATION_FIELD_DESCRIPTOR_TAG 0x97
|
||||
#define CABLELABS_3D_MPEG2_DESCRIPTOR_TAG 0xe8
|
||||
#define SCTE35_CUE_IDENTIFIER_DESCRIPTOR_TAG 0x8a
|
||||
|
||||
void write_cablelabs_3d_descriptor( bs_t *s );
|
||||
void write_scte_adaptation_descriptor( bs_t *s );
|
||||
void write_scte35_cue_identifier_descriptor( bs_t *s );
|
||||
|
||||
#endif
|
||||
|
|
10
common.h
10
common.h
|
@ -44,10 +44,13 @@
|
|||
#define PRIVATE_SECTION 0x05
|
||||
#define PRIVATE_DATA 0x06
|
||||
|
||||
#define DATA_SCTE35 0x86
|
||||
|
||||
#define TS_HEADER_SIZE 4
|
||||
#define TS_PACKET_SIZE 188
|
||||
#define TS_CLOCK 27000000LL
|
||||
#define TS_START 10
|
||||
#define TIMESTAMP_CLOCK 90000LL
|
||||
|
||||
// arbitrary
|
||||
#define MAX_PROGRAMS 100
|
||||
|
@ -97,7 +100,7 @@
|
|||
#define MIN(a,b) ( (a)<(b) ? (a) : (b) )
|
||||
#define MAX(a,b) ( (a)>(b) ? (a) : (b) )
|
||||
|
||||
#define IS_VIDEO(x) ( x->stream_format == LIBMPEGTS_VIDEO_MPEG2 || x->stream_format == LIBMPEGTS_VIDEO_AVC )
|
||||
#define IS_VIDEO(x) ( x->stream_format == LIBMPEGTS_VIDEO_MPEG2 || x->stream_format == LIBMPEGTS_VIDEO_AVC || x->stream_format == LIBMPEGTS_VIDEO_DIRAC )
|
||||
|
||||
/* Internal Program & Stream Structures */
|
||||
typedef struct
|
||||
|
@ -201,6 +204,9 @@ typedef struct
|
|||
int aac_profile;
|
||||
int aac_channel_map;
|
||||
|
||||
/* Opus */
|
||||
int opus_channel_map;
|
||||
|
||||
/* ATSC */
|
||||
|
||||
/* DVB */
|
||||
|
@ -284,12 +290,14 @@ struct ts_writer_t
|
|||
|
||||
uint64_t bytes_written;
|
||||
uint64_t packets_written;
|
||||
uint64_t pcr_start;
|
||||
|
||||
int ts_type;
|
||||
int ts_id;
|
||||
|
||||
int cbr;
|
||||
int ts_muxrate;
|
||||
int lowlatency;
|
||||
|
||||
int pat_cc;
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ void write_teletext_descriptor( bs_t *s, ts_int_stream_t *stream, int vbi )
|
|||
for( int j = 0; j < 3; j++ )
|
||||
bs_write( s, 8, teletext->lang_code[j] ); // ISO_639_language_code
|
||||
bs_write( s, 5, teletext->teletext_type ); // teletext_type
|
||||
bs_write( s, 3, teletext->teletext_magazine_number ); // teletext_magazine_number
|
||||
bs_write( s, 3, teletext->teletext_magazine_number == 8 ? 0 : teletext->teletext_magazine_number ); // teletext_magazine_number
|
||||
bs_write( s, 8, teletext->teletext_page_number ); // teletext_page_number
|
||||
}
|
||||
}
|
||||
|
@ -127,11 +127,11 @@ static void write_service_descriptor( bs_t *s, int service_type, char *provider_
|
|||
|
||||
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, (unsigned char)*provider_name++ );
|
||||
|
||||
bs_write( s, 8, service_name_length ); // service_name_length
|
||||
while( *service_name != '\0' )
|
||||
bs_write( s, 8, *service_name++ );
|
||||
bs_write( s, 8, (unsigned char)*service_name++ );
|
||||
}
|
||||
|
||||
/* DVB Service Information */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define DVB_ADAPTATION_FIELD_DATA_DESCRIPTOR 0x70
|
||||
#define DVB_EAC3_DESCRIPTOR_TAG 0x7a
|
||||
#define DVB_AAC_DESCRIPTOR_TAG 0x7c
|
||||
#define DVB_EXTENSION_DESCRIPTOR_TAG 0x7f
|
||||
|
||||
/* PIDs */
|
||||
#define SDT_PID 0x0011
|
||||
|
|
274
libmpegts.c
274
libmpegts.c
|
@ -29,10 +29,11 @@
|
|||
#include "crc/crc.h"
|
||||
#include <math.h>
|
||||
|
||||
static const int steam_type_table[27][2] =
|
||||
static const int stream_type_table[30][2] =
|
||||
{
|
||||
{ LIBMPEGTS_VIDEO_MPEG2, VIDEO_MPEG2 },
|
||||
{ LIBMPEGTS_VIDEO_AVC, VIDEO_AVC },
|
||||
{ LIBMPEGTS_VIDEO_DIRAC, 0xd1 },
|
||||
{ LIBMPEGTS_AUDIO_MPEG1, AUDIO_MPEG1 },
|
||||
{ LIBMPEGTS_AUDIO_MPEG2, AUDIO_MPEG2 },
|
||||
{ LIBMPEGTS_AUDIO_ADTS, AUDIO_ADTS },
|
||||
|
@ -57,6 +58,8 @@ static const int steam_type_table[27][2] =
|
|||
{ LIBMPEGTS_DVB_VBI, PRIVATE_DATA },
|
||||
{ LIBMPEGTS_ANCILLARY_RDD11, PRIVATE_DATA },
|
||||
{ LIBMPEGTS_ANCILLARY_2038, PRIVATE_DATA },
|
||||
{ LIBMPEGTS_AUDIO_OPUS, PRIVATE_DATA },
|
||||
{ LIBMPEGTS_DATA_SCTE35, DATA_SCTE35 },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
|
@ -186,30 +189,35 @@ static void write_iso_lang_descriptor( bs_t *s, ts_int_stream_t *stream )
|
|||
bs_write(s, 8, stream->audio_type ); // audio_type
|
||||
}
|
||||
|
||||
/**** PCR functions ****/
|
||||
static int check_pcr( ts_writer_t *w, ts_int_program_t *program )
|
||||
/** Misc descriptors **/
|
||||
static void write_opus_descriptor( bs_t *s, ts_int_stream_t *stream )
|
||||
{
|
||||
// if the next packet written goes over the max pcr retransmit boundary, write the pcr in the next packet
|
||||
double next_pkt_pcr = ((w->packets_written * TS_PACKET_SIZE) + (TS_PACKET_SIZE + 7)) * 8.0 / w->ts_muxrate -
|
||||
(double)program->last_pcr / TS_CLOCK;
|
||||
next_pkt_pcr += TS_START;
|
||||
|
||||
if( next_pkt_pcr >= (double)w->pcr_period / 1000 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
bs_write( s, 8, DVB_EXTENSION_DESCRIPTOR_TAG ); // descriptor_tag
|
||||
bs_write( s, 8, 0x2 ); // descriptor_length
|
||||
bs_write( s, 8, 0x80 ); // descriptor_tag_extension (User defined)
|
||||
bs_write( s, 8, stream->opus_channel_map ); // channel_config_code
|
||||
}
|
||||
|
||||
/**** PCR functions ****/
|
||||
static int64_t get_pcr_int( ts_writer_t *w, double offset )
|
||||
{
|
||||
return (int64_t)((8.0 * (w->packets_written * TS_PACKET_SIZE + offset) / w->ts_muxrate) * TS_CLOCK + 0.5) + TS_START * TS_CLOCK;
|
||||
return (int64_t)((8.0 * (w->packets_written * TS_PACKET_SIZE + offset) / w->ts_muxrate) * TS_CLOCK + 0.5) + w->pcr_start;
|
||||
}
|
||||
|
||||
static double get_pcr_double( ts_writer_t *w, double offset )
|
||||
{
|
||||
return (8.0 * (w->packets_written * TS_PACKET_SIZE + offset) / w->ts_muxrate) + TS_START;
|
||||
return (8.0 * (w->packets_written * TS_PACKET_SIZE + offset) / w->ts_muxrate) + (double)w->pcr_start / TS_CLOCK;
|
||||
}
|
||||
|
||||
static int check_pcr( ts_writer_t *w, ts_int_program_t *program )
|
||||
{
|
||||
// if the next packet written goes over the max pcr retransmit boundary, write the pcr in the next packet
|
||||
int64_t next_pkt_pcr = get_pcr_int( w, (TS_PACKET_SIZE + 7) * 8 ) - program->last_pcr;
|
||||
|
||||
if( next_pkt_pcr >= w->pcr_period * (TS_CLOCK/1000) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**** Buffer management ****/
|
||||
|
@ -404,11 +412,6 @@ static int eject_queued_pmt( ts_writer_t *w, ts_int_program_t *program, bs_t *s
|
|||
memmove( &program->pmt_packets[0], &program->pmt_packets[1], (program->num_queued_pmt-1) * sizeof(uint8_t*) );
|
||||
|
||||
temp = realloc( program->pmt_packets, (program->num_queued_pmt-1) * sizeof(uint8_t*) );
|
||||
if( !temp )
|
||||
{
|
||||
fprintf( stderr, "malloc failed\n" );
|
||||
return -1;
|
||||
}
|
||||
program->pmt_packets = temp;
|
||||
|
||||
program->num_queued_pmt--;
|
||||
|
@ -476,6 +479,14 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
|
|||
else if( w->ts_type == TS_TYPE_BLU_RAY )
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "HDMV" );
|
||||
|
||||
for( int i = 0; i < program->num_streams; i++ )
|
||||
{
|
||||
ts_int_stream_t *stream = program->streams[i];
|
||||
|
||||
if( stream->stream_format == LIBMPEGTS_DATA_SCTE35 )
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "CUEI" );
|
||||
}
|
||||
|
||||
/* Optional descriptor(s) here */
|
||||
|
||||
bs_flush( &q );
|
||||
|
@ -494,7 +505,7 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
|
|||
/* reset temporary bitstream context for streams loop */
|
||||
bs_init( &q, temp1, 512 );
|
||||
|
||||
if( stream->stream_format != LIBMPEGTS_ANCILLARY_RDD11 )
|
||||
if( stream->stream_format != LIBMPEGTS_ANCILLARY_RDD11 && stream->stream_format != LIBMPEGTS_DATA_SCTE35 )
|
||||
write_data_stream_alignment_descriptor( &q );
|
||||
|
||||
if( stream->dvb_au )
|
||||
|
@ -522,6 +533,8 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
|
|||
if( w->ts_type == TS_TYPE_BLU_RAY )
|
||||
write_hdmv_video_registration_descriptor( &q, stream );
|
||||
}
|
||||
else if( stream->stream_format == LIBMPEGTS_VIDEO_DIRAC )
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "BBCD" );
|
||||
else if( stream->stream_format == LIBMPEGTS_AUDIO_MPEG1 ||
|
||||
stream->stream_format == LIBMPEGTS_AUDIO_MPEG2 )
|
||||
{
|
||||
|
@ -550,7 +563,7 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
|
|||
// TODO
|
||||
}
|
||||
else if( stream->stream_format == LIBMPEGTS_AUDIO_302M )
|
||||
write_registration_descriptor( &q, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "BSSD" );
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "BSSD" );
|
||||
else if( stream->stream_format == LIBMPEGTS_DVB_SUB )
|
||||
write_dvb_subtitling_descriptor( &q, stream );
|
||||
else if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT )
|
||||
|
@ -562,12 +575,19 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
|
|||
write_teletext_descriptor( &q, stream, 1 );
|
||||
}
|
||||
else if( stream->stream_format == LIBMPEGTS_ANCILLARY_RDD11 )
|
||||
write_registration_descriptor( &q, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "LU-A" );
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "LU-A" );
|
||||
else if( stream->stream_format == LIBMPEGTS_ANCILLARY_2038 )
|
||||
{
|
||||
write_registration_descriptor( &q, PRIVATE_DATA_DESCRIPTOR_TAG, 4, "VANC" );
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "VANC" );
|
||||
write_anc_data_descriptor( &q );
|
||||
}
|
||||
else if( stream->stream_format == LIBMPEGTS_AUDIO_OPUS )
|
||||
{
|
||||
write_registration_descriptor( &q, REGISTRATION_DESCRIPTOR_TAG, 4, "Opus" );
|
||||
write_opus_descriptor( &q, stream );
|
||||
}
|
||||
else if( stream->stream_format == LIBMPEGTS_DATA_SCTE35 )
|
||||
write_scte35_cue_identifier_descriptor( &q );
|
||||
|
||||
// TODO other stream_type descriptors
|
||||
|
||||
|
@ -640,11 +660,11 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program )
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void retransmit_psi_and_si( ts_writer_t *w, ts_int_program_t *program, int first )
|
||||
static void retransmit_psi_and_si( ts_writer_t *w, ts_int_program_t *program )
|
||||
{
|
||||
// TODO make this work with multiple programs
|
||||
int64_t cur_pcr = get_pcr_int( w, 0 );
|
||||
if( cur_pcr - w->last_pat >= w->pat_period * 27000LL || first )
|
||||
if( cur_pcr - w->last_pat >= w->pat_period * 27000LL || !w->last_pat )
|
||||
{
|
||||
/* Although it is not in line with the mux strategy it is good practice to write PAT and PMT together */
|
||||
w->last_pat = cur_pcr;
|
||||
|
@ -654,7 +674,7 @@ static void retransmit_psi_and_si( ts_writer_t *w, ts_int_program_t *program, in
|
|||
|
||||
cur_pcr = get_pcr_int( w, 0 );
|
||||
|
||||
if( w->sdt && ( cur_pcr - w->last_sdt >= w->sdt_period * 27000LL || first ) )
|
||||
if( w->sdt && ( cur_pcr - w->last_sdt >= w->sdt_period * 27000LL || !w->last_sdt ) )
|
||||
{
|
||||
w->last_sdt = cur_pcr;
|
||||
write_sdt( w );
|
||||
|
@ -760,9 +780,11 @@ static int write_pes( ts_writer_t *w, ts_int_program_t *program, ts_frame_t *in_
|
|||
bs_write1( &q, 0 ); // DSM_trick_mode_flag
|
||||
bs_write1( &q, 0 ); // additional_copy_info_flag
|
||||
bs_write1( &q, 0 ); // PES_CRC_flag
|
||||
bs_write1( &q, 0 ); // PES_extension_flag
|
||||
bs_write1( &q, stream->stream_format == LIBMPEGTS_VIDEO_DIRAC ); // PES_extension_flag
|
||||
|
||||
if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT || stream->stream_format == LIBMPEGTS_DVB_VBI )
|
||||
if( stream->stream_format == LIBMPEGTS_VIDEO_DIRAC )
|
||||
bs_write( &q, 8, 0x08 ); // PES_header_data_length
|
||||
else if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT || stream->stream_format == LIBMPEGTS_DVB_VBI )
|
||||
bs_write( &q, 8, 0x24 ); // PES_header_data_length
|
||||
else if( same_timestamps )
|
||||
bs_write( &q, 8, 0x05 ); // PES_header_data_length (PTS only)
|
||||
|
@ -779,6 +801,21 @@ static int write_pes( ts_writer_t *w, ts_int_program_t *program, ts_frame_t *in_
|
|||
write_timestamp( &q, out_pes->dts % mod ); // DTS
|
||||
}
|
||||
|
||||
if( stream->stream_format == LIBMPEGTS_VIDEO_DIRAC )
|
||||
{
|
||||
bs_write1( &q, 0 ); // PES_private_data_flag
|
||||
bs_write1( &q, 0 ); // pack_header_field_flag
|
||||
bs_write1( &q, 0 ); // program_packet_sequence_counter_flag
|
||||
bs_write1( &q, 0 ); // P-STD_buffer_flag
|
||||
bs_write( &q, 3, 0x0a ); // reserved
|
||||
bs_write1( &q, 1 ); // PES_extension_flag_2
|
||||
|
||||
bs_write1( &q, 1 ); // marker_bit
|
||||
bs_write( &q, 7, 1 ); // PES_header_data_length
|
||||
bs_write1( &q, 0 ); // stream_id_extension_flag
|
||||
bs_write( &q, 7, 0x60 ); // stream_id_extension
|
||||
}
|
||||
|
||||
/* TTX and VBI require extra stuffing */
|
||||
if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT || stream->stream_format == LIBMPEGTS_DVB_VBI )
|
||||
{
|
||||
|
@ -791,7 +828,8 @@ static int write_pes( ts_writer_t *w, ts_int_program_t *program, ts_frame_t *in_
|
|||
bs_flush( &q );
|
||||
total_size = in_frame->size + (bs_pos( &q ) >> 3);
|
||||
|
||||
if( stream->stream_format == LIBMPEGTS_VIDEO_MPEG2 || stream->stream_format == LIBMPEGTS_VIDEO_AVC )
|
||||
if( stream->stream_format == LIBMPEGTS_VIDEO_MPEG2 || stream->stream_format == LIBMPEGTS_VIDEO_AVC ||
|
||||
stream->stream_format == LIBMPEGTS_VIDEO_DIRAC )
|
||||
bs_write( &s, 16, 0 ); // PES_packet_length
|
||||
else
|
||||
bs_write( &s, 16, total_size ); // PES_packet_length
|
||||
|
@ -852,6 +890,21 @@ static int check_bitstream( ts_writer_t *w )
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* set updatable ts parameters */
|
||||
static void update_ts_params( ts_writer_t *w, ts_main_t *params )
|
||||
{
|
||||
w->ts_muxrate = params->muxrate;
|
||||
w->cbr = params->cbr;
|
||||
w->legacy_constraints = params->legacy_constraints;
|
||||
w->lowlatency = params->lowlatency;
|
||||
|
||||
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->r_sys = MAX( R_SYS_DEFAULT, (double)w->ts_muxrate / 500 );
|
||||
}
|
||||
|
||||
ts_writer_t *ts_create_writer( void )
|
||||
{
|
||||
ts_writer_t *w = calloc( 1, sizeof(*w) );
|
||||
|
@ -968,16 +1021,16 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
|
|||
|
||||
cur_stream->pid = stream_in->pid;
|
||||
cur_stream->stream_format = stream_in->stream_format;
|
||||
for( int j = 0; steam_type_table[j][0] != 0; j++ )
|
||||
for( int j = 0; stream_type_table[j][0] != 0; j++ )
|
||||
{
|
||||
if( cur_stream->stream_format == steam_type_table[j][0] )
|
||||
if( cur_stream->stream_format == stream_type_table[j][0] )
|
||||
{
|
||||
/* DVB AC-3 and EAC-3 are different */
|
||||
if( w->ts_type == TS_TYPE_DVB &&
|
||||
( cur_stream->stream_format == LIBMPEGTS_AUDIO_AC3 || cur_stream->stream_format == LIBMPEGTS_AUDIO_EAC3 ) )
|
||||
j++;
|
||||
|
||||
cur_stream->stream_type = steam_type_table[j][1];
|
||||
cur_stream->stream_type = stream_type_table[j][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1023,7 +1076,8 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
|
|||
cur_stream->tb.buf_size = TB_SIZE;
|
||||
|
||||
/* setup T-STD buffers when audio buffers sizes are independent of number of channels */
|
||||
if( cur_stream->stream_format == LIBMPEGTS_AUDIO_MPEG1 || cur_stream->stream_format == LIBMPEGTS_AUDIO_MPEG2 )
|
||||
if( cur_stream->stream_format == LIBMPEGTS_AUDIO_MPEG1 || cur_stream->stream_format == LIBMPEGTS_AUDIO_MPEG2 ||
|
||||
cur_stream->stream_format == LIBMPEGTS_AUDIO_OPUS )
|
||||
{
|
||||
/* use the defaults */
|
||||
cur_stream->rx = MISC_AUDIO_RXN;
|
||||
|
@ -1034,6 +1088,30 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
|
|||
cur_stream->rx = MISC_AUDIO_RXN;
|
||||
cur_stream->mb.buf_size = w->ts_type == TS_TYPE_ATSC || w->ts_type == TS_TYPE_CABLELABS ? AC3_BS_ATSC : AC3_BS_DVB;
|
||||
}
|
||||
else if( cur_stream->stream_format == LIBMPEGTS_AUDIO_302M )
|
||||
{
|
||||
/* Use some made up value because (surprise surprise) SMPTE hasn't defined it properly
|
||||
* 7 bytes in 24-bit packing * 4 pairs * 48000 * 1.2 */
|
||||
cur_stream->rx = 7 * 4 * 48000 * 8 * 6 / 5;
|
||||
cur_stream->mb.buf_size = SMPTE_302M_AUDIO_BS;
|
||||
}
|
||||
else if( cur_stream->stream_format == LIBMPEGTS_VIDEO_DIRAC )
|
||||
{
|
||||
#define DIRAC_MAX_BITRATE 10000000
|
||||
int bitrate = DIRAC_MAX_BITRATE * 1.2;
|
||||
int bs_mux = 0.004 * bitrate;
|
||||
int bs_oh = 1.0 * bitrate / 50.0;
|
||||
|
||||
cur_stream->mb.buf_size = bs_mux + bs_oh;
|
||||
cur_stream->eb.buf_size = 10000000*8;
|
||||
|
||||
cur_stream->rx = bitrate;
|
||||
cur_stream->rbx = bitrate;
|
||||
}
|
||||
else if( cur_stream->stream_format == LIBMPEGTS_ANCILLARY_2038 )
|
||||
{
|
||||
cur_stream->rx = 1.2 * 2500000;
|
||||
}
|
||||
|
||||
cur_program->streams[cur_program->num_streams] = cur_stream;
|
||||
cur_program->num_streams++;
|
||||
|
@ -1049,21 +1127,15 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
|
|||
cur_program->pcr_stream = pcr_stream;
|
||||
}
|
||||
|
||||
w->ts_id = params->ts_id;
|
||||
w->ts_muxrate = params->muxrate;
|
||||
w->cbr = params->cbr;
|
||||
update_ts_params( w, params );
|
||||
|
||||
w->network_pid = params->network_pid;
|
||||
w->legacy_constraints = params->legacy_constraints;
|
||||
|
||||
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;
|
||||
|
||||
w->ts_id = params->ts_id;
|
||||
w->tb.buf_size = TB_SIZE;
|
||||
w->rx_sys = RX_SYS;
|
||||
w->r_sys = MAX( R_SYS_DEFAULT, (double)w->ts_muxrate / 500 );
|
||||
|
||||
w->pcr_start = TS_START * TS_CLOCK;
|
||||
|
||||
// FIXME realloc if necessary
|
||||
|
||||
|
@ -1081,6 +1153,17 @@ int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params )
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ts_update_transport_stream( ts_writer_t *w, ts_main_t *params )
|
||||
{
|
||||
int64_t cur_pcr = get_pcr_int( w, 0 );
|
||||
if( params->muxrate != w->ts_muxrate )
|
||||
{
|
||||
update_ts_params( w, params );
|
||||
w->packets_written = 0;
|
||||
w->pcr_start = cur_pcr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Codec-specific features */
|
||||
|
||||
int ts_setup_mpegvideo_stream( ts_writer_t *w, int pid, int level, int profile, int vbv_maxrate, int vbv_bufsize, int frame_rate )
|
||||
|
@ -1287,24 +1370,8 @@ int ts_setup_mpeg4_aac_stream( ts_writer_t *w, int pid, int profile_and_level, i
|
|||
return 0;
|
||||
};
|
||||
|
||||
int ts_setup_302m_stream( ts_writer_t *w, int pid, int bit_depth, int num_channels )
|
||||
int ts_setup_opus_stream( ts_writer_t *w, int pid, int channel_map )
|
||||
{
|
||||
if( w->ts_type == TS_TYPE_BLU_RAY )
|
||||
{
|
||||
fprintf( stderr, "SMPTE 302M not allowed in Blu-Ray\n" );
|
||||
return -1;
|
||||
}
|
||||
else if( !(bit_depth == 16 || bit_depth == 20 || bit_depth == 24) )
|
||||
{
|
||||
fprintf( stderr, "Invalid Bit Depth for SMPTE 302M\n" );
|
||||
return -1;
|
||||
}
|
||||
else if( (num_channels & 1) || num_channels <= 0 || num_channels > 8 )
|
||||
{
|
||||
fprintf( stderr, "Invalid number of channels for SMPTE 302M\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ts_int_stream_t *stream = find_stream( w, pid );
|
||||
|
||||
if( !stream )
|
||||
|
@ -1313,20 +1380,7 @@ int ts_setup_302m_stream( ts_writer_t *w, int pid, int bit_depth, int num_channe
|
|||
return -1;
|
||||
}
|
||||
|
||||
if( stream->lpcm_ctx )
|
||||
free( stream->lpcm_ctx );
|
||||
|
||||
stream->lpcm_ctx = calloc( 1, sizeof(lpcm_stream_ctx_t) );
|
||||
if( !stream->lpcm_ctx )
|
||||
return -1;
|
||||
|
||||
stream->lpcm_ctx->bits_per_sample = bit_depth;
|
||||
stream->lpcm_ctx->num_channels = num_channels;
|
||||
|
||||
stream->mb.buf_size = SMPTE_302M_AUDIO_BS;
|
||||
|
||||
/* 302M frame size is bit_depth / 4 + 1 */
|
||||
stream->rx = 1.2 * ((bit_depth >> 2) + 1) * SMPTE_302M_AUDIO_SR * 8;
|
||||
stream->opus_channel_map = channel_map;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1601,18 +1655,20 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
new_pes[i]->stream = stream;
|
||||
new_pes[i]->random_access = !!frames[i].random_access;
|
||||
new_pes[i]->priority = !!frames[i].priority;
|
||||
new_pes[i]->dts = frames[i].dts + TS_START * 90000LL;
|
||||
new_pes[i]->pts = frames[i].pts + TS_START * 90000LL;
|
||||
new_pes[i]->dts = frames[i].dts + TS_START * TIMESTAMP_CLOCK;
|
||||
new_pes[i]->pts = frames[i].pts + TS_START * TIMESTAMP_CLOCK;
|
||||
|
||||
if( IS_VIDEO( stream ) )
|
||||
{
|
||||
new_pes[i]->frame_type = frames[i].frame_type;
|
||||
new_pes[i]->initial_arrival_time = frames[i].cpb_initial_arrival_time + TS_START * 27000000LL;
|
||||
new_pes[i]->final_arrival_time = frames[i].cpb_final_arrival_time + TS_START * 27000000LL;
|
||||
new_pes[i]->initial_arrival_time = frames[i].cpb_initial_arrival_time + TS_START * TS_CLOCK;
|
||||
new_pes[i]->final_arrival_time = frames[i].cpb_final_arrival_time + TS_START * TS_CLOCK;
|
||||
new_pes[i]->ref_pic_idc = frames[i].ref_pic_idc;
|
||||
new_pes[i]->write_pulldown_info = frames[i].write_pulldown_info;
|
||||
new_pes[i]->pic_struct = frames[i].pic_struct;
|
||||
}
|
||||
else if( stream->stream_format == LIBMPEGTS_AUDIO_302M || stream->stream_format == LIBMPEGTS_DATA_SCTE35 || stream->stream_format == LIBMPEGTS_ANCILLARY_2038 )
|
||||
new_pes[i]->initial_arrival_time = (new_pes[i]->dts * 300) - frames[i].duration;
|
||||
else if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT )
|
||||
new_pes[i]->initial_arrival_time = (new_pes[i]->dts - 3600) * 300; /* Teletext is special because data can only stay in the buffer for 40ms */
|
||||
else if( stream->stream_format == LIBMPEGTS_DVB_SUB )
|
||||
|
@ -1649,10 +1705,22 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Not technically a PES but put it through the same codepath */
|
||||
if ( stream->stream_format == LIBMPEGTS_DATA_SCTE35 )
|
||||
{
|
||||
new_pes[i]->data[0] = 0; // pointer_field
|
||||
memcpy( new_pes[i]->data+1, frames[i].data, frames[i].size );
|
||||
new_pes[i]->size = new_pes[i]->bytes_left = frames[i].size + 1;
|
||||
new_pes[i]->cur_pos = new_pes[i]->data;
|
||||
new_pes[i]->header_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_pes[i]->header_size = write_pes( w, program, &frames[i], new_pes[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if( !initial_queued_pes )
|
||||
if( !w->lowlatency && !initial_queued_pes )
|
||||
{
|
||||
out = NULL;
|
||||
*len = 0;
|
||||
|
@ -1667,16 +1735,28 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
{
|
||||
if( write_pcr_empty( w, program, 1 ) < 0 )
|
||||
return -1;
|
||||
retransmit_psi_and_si( w, program, 1 );
|
||||
w->first_input = 1;
|
||||
}
|
||||
|
||||
/* loop through and find the time when the second video packet in the queue can arrive */
|
||||
int video_found = 0;
|
||||
|
||||
int video_found = 0, start = 0;
|
||||
int64_t pcr_stop = 0;
|
||||
|
||||
cur_pcr = get_pcr_int( w, 0 );
|
||||
|
||||
if( w->lowlatency )
|
||||
{
|
||||
/* Find the latest arrival time in the batch of packets delivered */
|
||||
for( int i = 0; i < w->num_buffered_frames; i++ )
|
||||
{
|
||||
stream = queued_pes[i]->stream;
|
||||
if( queued_pes[i]->final_arrival_time > pcr_stop )
|
||||
pcr_stop = queued_pes[i]->final_arrival_time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* loop through and find the time when the second video packet in the queue can arrive */
|
||||
for( int i = 0; i < w->num_buffered_frames; i++ )
|
||||
{
|
||||
stream = queued_pes[i]->stream;
|
||||
|
@ -1691,6 +1771,7 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
pcr_stop = queued_pes[i]->initial_arrival_time; /* earliest that a frame can arrive */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while( cur_pcr < pcr_stop )
|
||||
{
|
||||
|
@ -1717,6 +1798,8 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
/* Check all the non-video packets first */
|
||||
if( !need_pcr )
|
||||
{
|
||||
retransmit_psi_and_si( w, program );
|
||||
|
||||
for( int i = 0; i < w->num_buffered_frames; i++ )
|
||||
{
|
||||
stream = queued_pes[i]->stream;
|
||||
|
@ -1834,7 +1917,12 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
|
||||
/* special case where the adaptation_field_length byte is the stuffing */
|
||||
// FIXME except for cablelabs legacy
|
||||
if( stuffing == 1 && !adapt_field_len )
|
||||
|
||||
if( stream->stream_format == LIBMPEGTS_DATA_SCTE35 )
|
||||
{
|
||||
adapt_field_len = 0; /* Theoretically could be made PCR */
|
||||
}
|
||||
else if( stuffing == 1 && !adapt_field_len )
|
||||
{
|
||||
stuffing = flags = 0;
|
||||
adapt_field_len = 1;
|
||||
|
@ -1845,11 +1933,15 @@ 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 */
|
||||
}
|
||||
|
||||
start = bs_pos( s );
|
||||
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 );
|
||||
|
||||
write_bytes(s, pes->cur_pos, pes->bytes_left );
|
||||
write_bytes( s, pes->cur_pos, pes->bytes_left );
|
||||
if( stream->stream_format == LIBMPEGTS_DATA_SCTE35 )
|
||||
write_padding( s, start );
|
||||
|
||||
pes->bytes_left = 0;
|
||||
add_to_buffer( &stream->tb );
|
||||
if( increase_pcr( w, 1, 0 ) < 0 )
|
||||
|
@ -1872,8 +1964,6 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t
|
|||
free( pes->data );
|
||||
free( pes );
|
||||
}
|
||||
|
||||
retransmit_psi_and_si( w, program, 0 );
|
||||
}
|
||||
else /* no packets can be written */
|
||||
{
|
||||
|
@ -2026,11 +2116,15 @@ int increase_pcr( ts_writer_t *w, int num_packets, int imaginary )
|
|||
|
||||
// TODO do this for all programs
|
||||
ts_int_program_t *program = w->programs[0];
|
||||
double next_pcr = TS_START + (w->packets_written + num_packets) * 8.0 * TS_PACKET_SIZE / w->ts_muxrate;
|
||||
double next_pcr = get_pcr_double( w, num_packets * TS_PACKET_SIZE );
|
||||
/* buffer drip (TODO: all buffers?) */
|
||||
drip_buffer( w, program, w->rx_sys, &w->tb, next_pcr );
|
||||
for( int i = 0; i < program->num_streams; i++ )
|
||||
{
|
||||
/* SCTE35 is PSI so not part of T-STD */
|
||||
if( program->streams[i]->stream_format == LIBMPEGTS_DATA_SCTE35 )
|
||||
program->streams[i]->tb.cur_buf = 0;
|
||||
else
|
||||
drip_buffer( w, program, program->streams[i]->rx, &program->streams[i]->tb, next_pcr );
|
||||
}
|
||||
|
||||
|
|
27
libmpegts.h
27
libmpegts.h
|
@ -38,6 +38,7 @@
|
|||
/* Generic */
|
||||
#define LIBMPEGTS_VIDEO_MPEG2 1
|
||||
#define LIBMPEGTS_VIDEO_AVC 2
|
||||
#define LIBMPEGTS_VIDEO_DIRAC 3
|
||||
|
||||
#define LIBMPEGTS_AUDIO_MPEG1 32
|
||||
#define LIBMPEGTS_AUDIO_MPEG2 33
|
||||
|
@ -69,7 +70,8 @@
|
|||
#define LIBMPEGTS_DVB_VBI 130
|
||||
|
||||
/* Misc */
|
||||
|
||||
#define LIBMPEGTS_AUDIO_OPUS 160
|
||||
#define LIBMPEGTS_DATA_SCTE35 161
|
||||
|
||||
/**** Stream IDs ****/
|
||||
/* SMPTE 302M, AC3, DVB subtitles and Teletext use Private Stream 1 */
|
||||
|
@ -82,6 +84,9 @@
|
|||
/* MPEG Video (all types): 0xe0-0xef */
|
||||
#define LIBMPEGTS_STREAM_ID_MPEGVIDEO 0xe0
|
||||
|
||||
/* Extended Stream-id */
|
||||
#define LIBMPEGTS_STREAM_ID_EXTENDED 0xfd
|
||||
|
||||
/**** Blu-Ray Information ****/
|
||||
/* Blu-Ray Aspect Ratios */
|
||||
#define LIBMPEGTS_HDMV_AR_4_3 2
|
||||
|
@ -311,6 +316,7 @@ typedef struct ts_main_t
|
|||
int muxrate;
|
||||
int cbr;
|
||||
int ts_type;
|
||||
int lowlatency;
|
||||
|
||||
int network_pid;
|
||||
|
||||
|
@ -329,6 +335,15 @@ typedef struct ts_main_t
|
|||
|
||||
int ts_setup_transport_stream( ts_writer_t *w, ts_main_t *params );
|
||||
|
||||
/* update transport stream
|
||||
*
|
||||
* muxrate is the only tested parameter
|
||||
*
|
||||
* TODO: implement versioning so other parameters can be updated
|
||||
*
|
||||
*/
|
||||
void ts_update_transport_stream( ts_writer_t *w, ts_main_t *params );
|
||||
|
||||
/**** Additional Codec-Specific functions ****/
|
||||
/* Many formats require extra information. Setup the relevant information using the following functions */
|
||||
|
||||
|
@ -412,6 +427,15 @@ int ts_setup_mpeg4_aac_stream( ts_writer_t *w, int pid, int profile_and_level, i
|
|||
|
||||
int ts_setup_302m_stream( ts_writer_t *w, int pid, int bit_depth, int num_channels );
|
||||
|
||||
/* Opus */
|
||||
|
||||
#define LIBMPEGTS_CHANNEL_CONFIG_DUAL_MONO 0x00
|
||||
#define LIBMPEGTS_CHANNEL_CONFIG_MONO 0x01
|
||||
#define LIBMPEGTS_CHANNEL_CONFIG_STEREO 0x02
|
||||
|
||||
int ts_setup_opus_stream( ts_writer_t *w, int pid, int channel_map );
|
||||
|
||||
|
||||
/**** DVB Specific Information ****/
|
||||
|
||||
/* DVB Subtitles */
|
||||
|
@ -648,6 +672,7 @@ typedef struct
|
|||
int64_t cpb_final_arrival_time;
|
||||
int64_t dts;
|
||||
int64_t pts;
|
||||
int64_t duration; /* SMPTE 302M only */
|
||||
int random_access;
|
||||
int priority;
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue