diff --git a/common.h b/common.h index c03636a..fe8ad6d 100644 --- a/common.h +++ b/common.h @@ -174,6 +174,9 @@ typedef struct int num_dvb_ttx; ts_dvb_ttx_t *dvb_ttx_ctx; + int num_dvb_vbi; + ts_dvb_vbi_t *dvb_vbi_ctx; + int num_channels; int max_frame_size; diff --git a/dvb/dvb.c b/dvb/dvb.c index ca27437..74e8ce8 100644 --- a/dvb/dvb.c +++ b/dvb/dvb.c @@ -62,11 +62,15 @@ void write_stream_identifier_descriptor( bs_t *s, uint8_t stream_identifier ) bs_write( s, 8, stream_identifier ); // component_tag } -void write_teletext_descriptor( bs_t *s, ts_int_stream_t *stream ) +void write_teletext_descriptor( bs_t *s, ts_int_stream_t *stream, int vbi ) { ts_dvb_ttx_t *teletext; - bs_write( s, 8, DVB_TELETEXT_DESCRIPTOR_TAG ); // descriptor_tag + if( vbi ) + bs_write( s, 8, DVB_VBI_TELETEXT_DESCRIPTOR_TAG ); // descriptor_tag + else + bs_write( s, 8, DVB_TELETEXT_DESCRIPTOR_TAG ); // descriptor_tag + bs_write( s, 8, stream->num_dvb_ttx * 5 ); // descriptor_length for( int i = 0; i < stream->num_dvb_ttx; i++ ) { @@ -79,6 +83,36 @@ void write_teletext_descriptor( bs_t *s, ts_int_stream_t *stream ) } } +void write_vbi_descriptor( bs_t *s, ts_int_stream_t *stream ) +{ + bs_t q; + uint8_t temp[1024]; + ts_dvb_vbi_t *vbi; + + bs_init( &q, temp, 1024 ); + + bs_write( s, 8, DVB_VBI_DESCRIPTOR_TAG ); // descriptor_tag + + for( int i = 0; i < stream->num_dvb_ttx; i++ ) + { + vbi = &stream->dvb_vbi_ctx[i]; + + bs_write( &q, 8, vbi->data_service_id ); // data_service_id + bs_write( &q, 8, vbi->num_lines ); // data_service_descriptor_length + + for( int j = 0; j < vbi->num_lines; j++ ) + { + bs_write( &q, 2, 0x3 ); // reserved + bs_write( &q, 1, vbi->lines[j].field_parity ); // field_parity + bs_write( &q, 5, vbi->lines[j].line_offset ); // line_offset + } + } + + bs_flush( &q ); + bs_write( s, 8, bs_pos( &q ) >> 3 ); // descriptor_length + write_bytes( s, temp, bs_pos( &q ) >> 3 ); +} + /* static void write_service_descriptor( bs_t *s ) { diff --git a/dvb/dvb.h b/dvb/dvb.h index 08243f1..d33fed8 100644 --- a/dvb/dvb.h +++ b/dvb/dvb.h @@ -22,6 +22,8 @@ #define LIBMPEGTS_DVB_H /* Descriptor Tags */ +#define DVB_VBI_DESCRIPTOR_TAG 0x45 +#define DVB_VBI_TELETEXT_DESCRIPTOR_TAG 0x46 #define DVB_SERVICE_DESCRIPTOR_TAG 0x48 #define DVB_STREAM_IDENTIFIER_DESCRIPTOR_TAG 0x52 #define DVB_TELETEXT_DESCRIPTOR_TAG 0x56 @@ -56,7 +58,8 @@ void write_aac_descriptor( bs_t *s, ts_int_stream_t *stream ); void write_adaptation_field_data_descriptor( bs_t *s, uint8_t identifier ); void write_dvb_subtitling_descriptor( bs_t *s, ts_int_stream_t *stream ); void write_stream_identifier_descriptor( bs_t *s, uint8_t stream_identifier ); -void write_teletext_descriptor( bs_t *s, ts_int_stream_t *stream ); +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 ); diff --git a/libmpegts.c b/libmpegts.c index 4d79993..2eda85b 100644 --- a/libmpegts.c +++ b/libmpegts.c @@ -29,7 +29,7 @@ #include "crc/crc.h" #include -static int steam_type_table[26][2] = +static const int steam_type_table[27][2] = { { LIBMPEGTS_VIDEO_MPEG2, VIDEO_MPEG2 }, { LIBMPEGTS_VIDEO_AVC, VIDEO_AVC }, @@ -54,6 +54,7 @@ static int steam_type_table[26][2] = { LIBMPEGTS_AUDIO_302M, PRIVATE_DATA }, { LIBMPEGTS_DVB_SUB, PRIVATE_DATA }, { LIBMPEGTS_DVB_TELETEXT, PRIVATE_DATA }, + { LIBMPEGTS_DVB_VBI, PRIVATE_DATA }, { LIBMPEGTS_ANCILLARY_RDD11, PRIVATE_DATA }, { LIBMPEGTS_ANCILLARY_2038, PRIVATE_DATA }, { 0 }, @@ -627,6 +628,66 @@ int ts_setup_dvb_teletext( ts_writer_t *w, int pid, int num_teletexts, ts_dvb_tt return 0; } +int ts_setup_dvb_vbi( ts_writer_t *w, int pid, int num_vbis, ts_dvb_vbi_t *vbis ) +{ + if( w->ts_type == TS_TYPE_BLU_RAY ) + { + fprintf( stderr, "VBI not allowed in Blu-Ray\n" ); + return -1; + } + + ts_int_stream_t *stream = find_stream( w, pid ); + + if( !stream ) + { + fprintf( stderr, "Invalid PID\n" ); + return -1; + } + + if( !vbis || !num_vbis ) + { + fprintf( stderr, "Invalid Number of VBI services\n" ); + return -1; + } + + if( stream->dvb_vbi_ctx ) + free( stream->dvb_vbi_ctx ); + + stream->dvb_vbi_ctx = calloc( 1, num_vbis * sizeof(ts_dvb_vbi_t) ); + if( !stream->dvb_vbi_ctx ) + return -1; + + stream->num_dvb_vbi = num_vbis; + memcpy( stream->dvb_vbi_ctx, vbis, num_vbis * sizeof(ts_dvb_vbi_t) ); + + for( int i = 0; i < stream->num_dvb_vbi; i++ ) + { + stream->dvb_vbi_ctx[i].lines = calloc( 1, vbis[i].num_lines * sizeof(ts_dvb_vbi_line_t) ); + if( !stream->dvb_vbi_ctx[i].lines ) + goto fail; + memcpy( stream->dvb_vbi_ctx[i].lines, vbis[i].lines, vbis[i].num_lines * sizeof(ts_dvb_vbi_line_t) ); + } + + /* VBI uses teletext T-STD */ + stream->tb.buf_size = TELETEXT_T_BS; + stream->rx = TELETEXT_RXN; + stream->mb.buf_size = TELETEXT_BTTX; + + return 0; + +fail: + + for( int i = 0; i < stream->num_dvb_vbi; i++ ) + { + if( stream->dvb_vbi_ctx[i].lines ) + free( stream->dvb_vbi_ctx[i].lines ); + } + + free( stream->dvb_vbi_ctx ); + + return 0; +} + 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]; @@ -700,6 +761,14 @@ int ts_write_frames( ts_writer_t *w, ts_frame_t *frames, int num_frames, uint8_t return -1; } } + else if( stream->stream_format == LIBMPEGTS_DVB_VBI ) + { + if( !stream->dvb_vbi_ctx ) + { + fprintf( stderr, "DVB VBI stream needs additional information. Call ts_setup_dvb_vbi \n" ); + return -1; + } + } // TODO more w->buffered_frames[i] = calloc( 1, sizeof(ts_int_pes_t) ); @@ -1618,7 +1687,13 @@ static int write_pmt( ts_writer_t *w, ts_int_program_t *program ) else if( stream->stream_format == LIBMPEGTS_DVB_SUB ) write_dvb_subtitling_descriptor( &q, stream ); else if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT ) - write_teletext_descriptor( &q, stream ); + write_teletext_descriptor( &q, stream, 0 ); + else if( stream->stream_format == LIBMPEGTS_DVB_VBI ) + { + write_vbi_descriptor( &q, stream ); + if( stream->num_dvb_ttx ) + 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" ); else if( stream->stream_format == LIBMPEGTS_ANCILLARY_2038 ) @@ -1812,7 +1887,7 @@ static int write_pes( ts_writer_t *w, ts_int_program_t *program, ts_frame_t *in_ bs_write1( &q, 0 ); // PES_CRC_flag bs_write1( &q, 0 ); // PES_extension_flag - if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT ) + 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) @@ -1829,8 +1904,8 @@ 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 } - /* TTX requires extra stuffing */ - if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT ) + /* TTX and VBI require extra stuffing */ + if( stream->stream_format == LIBMPEGTS_DVB_TELETEXT || stream->stream_format == LIBMPEGTS_DVB_VBI ) { int num_stuffing = 45 - (bs_pos( &q ) >> 3); for( int i = 0; i < num_stuffing; i++ ) diff --git a/libmpegts.h b/libmpegts.h index fe747eb..9269c10 100644 --- a/libmpegts.h +++ b/libmpegts.h @@ -66,6 +66,7 @@ /* DVB Stream Formats */ #define LIBMPEGTS_DVB_SUB 128 #define LIBMPEGTS_DVB_TELETEXT 129 +#define LIBMPEGTS_DVB_VBI 130 /* Misc */ @@ -464,6 +465,37 @@ typedef struct int ts_setup_dvb_teletext( ts_writer_t *w, int pid, int num_teletexts, ts_dvb_ttx_t *teletexts ); +/* ts_dvb_vbi_t + * field_parity - 1 for first field (odd), 0 for second field (even) + * line_offset - line number on which data is presented if it is transcoded into the VBI + */ +typedef struct +{ + int field_parity; + int line_offset; +} ts_dvb_vbi_line_t; + +#define LIBMPEGTS_DVB_VBI_DATA_SERVICE_ID_TTX 0x01 /* Requires call to ts_setup_dvb_teletext */ +#define LIBMPEGTS_DVB_VBI_DATA_SERVICE_ID_INVERTED_TTX 0x02 +#define LIBMPEGTS_DVB_VBI_DATA_SERVICE_ID_VPS 0x04 +#define LIBMPEGTS_DVB_VBI_DATA_SERVICE_ID_WSS 0x05 +#define LIBMPEGTS_DVB_VBI_DATA_SERVICE_ID_CC 0x06 +#define LIBMPEGTS_DVB_VBI_DATA_SERVICE_ID_MONO_SAMPLES 0x07 + +/* ts_dvb_vbi_t + * data_service_id - see above #defines + * lines - one ts_dvb_vbi_line_t per line + */ + +typedef struct +{ + int data_service_id; + int num_lines; + ts_dvb_vbi_line_t *lines; +} ts_dvb_vbi_t; + +int ts_setup_dvb_vbi( ts_writer_t *w, int pid, int num_vbis, ts_dvb_vbi_t *vbis ); + /* SDT * */