diff --git a/src/lib_ccx/ccx_decoders_common.c b/src/lib_ccx/ccx_decoders_common.c index 649a3bcb..34a598b6 100644 --- a/src/lib_ccx/ccx_decoders_common.c +++ b/src/lib_ccx/ccx_decoders_common.c @@ -11,6 +11,7 @@ made to reuse, not duplicate, as many functions as possible */ #include "ccx_decoders_608.h" #include "ccx_decoders_708.h" #include "ccx_decoders_xds.h" +#include "ccx_decoders_vbi.h" #include "ccx_dtvcc.h" @@ -220,8 +221,8 @@ void dinit_cc_decode(struct lib_cc_decode **ctx) ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1); ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2); dinit_timing_ctx(&lctx->timing); - freep(&lctx->prev); - freep(&lctx->dec_sub.prev); + free_decoder_context(lctx->prev); + free_subtitle(lctx->dec_sub.prev); freep(ctx); } @@ -412,3 +413,154 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub) } } } +struct encoder_ctx* copy_encoder_context(struct encoder_ctx *ctx) +{ + struct encoder_ctx *ctx_copy = NULL; + ctx_copy = malloc(sizeof(struct encoder_ctx)); + memcpy(ctx_copy, ctx, sizeof(struct encoder_ctx)); + + if (ctx->buffer) + { + ctx_copy->buffer = malloc(ctx->capacity * sizeof(unsigned char)); + memcpy(ctx_copy->buffer, ctx->buffer, ctx->capacity * sizeof(unsigned char)); + } + if (ctx->first_input_file) + { + ctx_copy->first_input_file = malloc(strlen(ctx->first_input_file) * sizeof(char)); + memcpy(ctx_copy->first_input_file, ctx->first_input_file, strlen(ctx->first_input_file) * sizeof(char)); + } + if (ctx->out) + { + ctx_copy->out = malloc(sizeof(struct ccx_s_write)); + memcpy(ctx_copy->out, ctx->out, sizeof(struct ccx_s_write)); + } + if (ctx->timing) + { + ctx_copy->timing = malloc(sizeof(struct ccx_common_timing_ctx)); + memcpy(ctx_copy->timing, ctx->timing, sizeof(struct ccx_common_timing_ctx)); + } + if (ctx->transcript_settings) + { + ctx_copy->transcript_settings = malloc(sizeof(struct ccx_encoders_transcript_format)); + memcpy(ctx_copy->transcript_settings, ctx->transcript_settings, sizeof(struct ccx_encoders_transcript_format)); + } + if (ctx->subline) + { + ctx_copy->subline = malloc(SUBLINESIZE); + memcpy(ctx_copy->subline, ctx->subline, SUBLINESIZE); + } + if (ctx->start_credits_text) + { + ctx_copy->start_credits_text = malloc(strlen(ctx->start_credits_text) * sizeof(char)); + memcpy(ctx_copy->start_credits_text, ctx->start_credits_text, (strlen(ctx->start_credits_text) + 1) * sizeof(char)); + } + if (ctx->end_credits_text) + { + ctx_copy->end_credits_text = malloc(strlen(ctx->end_credits_text) * sizeof(char)); + memcpy(ctx_copy->end_credits_text, ctx->end_credits_text, (strlen(ctx->end_credits_text) + 1) * sizeof(char)); + } + if (ctx->sbs_buffer) + { + ctx_copy->sbs_buffer = malloc((strlen(ctx->sbs_buffer) + 2) * sizeof(unsigned char)); + memcpy(ctx_copy->sbs_buffer, ctx->sbs_buffer, (strlen(ctx->sbs_buffer) + 2) * sizeof(unsigned char)); + } + return ctx_copy; +} +struct lib_cc_decode* copy_decoder_context(struct lib_cc_decode *ctx) +{ + struct lib_cc_decode *ctx_copy = NULL; + ctx_copy = malloc(sizeof(struct lib_cc_decode)); + memcpy(ctx_copy, ctx, sizeof(struct lib_cc_decode)); + + if (ctx->context_cc608_field_1) + { + ctx_copy->context_cc608_field_1 = malloc(sizeof(struct ccx_decoder_608_context)); + memcpy(ctx_copy->context_cc608_field_1, ctx->context_cc608_field_1, sizeof(struct ccx_decoder_608_context)); + } + if (ctx->context_cc608_field_2) + { + ctx_copy->context_cc608_field_2 = malloc(sizeof(struct ccx_decoder_608_context)); + memcpy(ctx_copy->context_cc608_field_2, ctx->context_cc608_field_2, sizeof(struct ccx_decoder_608_context)); + } + if (ctx->timing) + { + ctx_copy->timing = malloc(sizeof(struct ccx_common_timing_ctx)); + memcpy(ctx_copy->timing, ctx->timing, sizeof(struct ccx_common_timing_ctx)); + } + if (ctx->avc_ctx) + { + ctx_copy->avc_ctx = malloc(sizeof(struct avc_ctx)); + memcpy(ctx_copy->avc_ctx, ctx->avc_ctx, sizeof(struct avc_ctx)); + } + ctx_copy->private_data = NULL; + if (ctx->dtvcc) + { + ctx_copy->dtvcc = malloc(sizeof(struct ccx_dtvcc_ctx)); + memcpy(ctx_copy->dtvcc, ctx->dtvcc, sizeof(struct ccx_dtvcc_ctx)); + } + if (ctx->xds_ctx) + { + ctx_copy->xds_ctx = malloc(sizeof(struct ccx_decoders_xds_context)); + memcpy(ctx_copy->xds_ctx, ctx->xds_ctx, sizeof(struct ccx_decoders_xds_context)); + } + if (ctx->vbi_decoder) + { + ctx_copy->vbi_decoder = malloc(sizeof(struct ccx_decoder_vbi_ctx)); + memcpy(ctx_copy->vbi_decoder, ctx->vbi_decoder, sizeof(struct ccx_decoder_vbi_ctx)); + } + return ctx_copy; +} +struct cc_subtitle* copy_subtitle(struct cc_subtitle *sub) +{ + struct cc_subtitle *sub_copy = NULL; + sub_copy = malloc(sizeof(struct cc_subtitle)); + memcpy(sub_copy, sub, sizeof(struct cc_subtitle)); + + if (sub->data) + { + sub_copy->data = malloc(sizeof(struct eia608_screen)); + sub_copy->data = malloc(sub->nb_data * sizeof(struct eia608_screen)); + memcpy(sub_copy->data, sub->data, sub->nb_data * sizeof(struct eia608_screen)); + } + return sub_copy; +} +void free_encoder_context(struct encoder_ctx *ctx) +{ + if (!ctx) + return; + + freep(&ctx->first_input_file); + freep(&ctx->buffer); + freep(&ctx->out); + freep(&ctx->timing); + freep(&ctx->transcript_settings); + freep(&ctx->subline); + freep(&ctx->start_credits_text); + freep(&ctx->end_credits_text); + freep(&ctx->sbs_buffer); + freep(&ctx->prev); + freep(&ctx); +} +void free_decoder_context(struct lib_cc_decode *ctx) +{ + if (!ctx) + return; + + freep(&ctx->context_cc608_field_1); + freep(&ctx->context_cc608_field_2); + freep(&ctx->timing); + freep(&ctx->avc_ctx); + freep(&ctx->private_data); + freep(&ctx->dtvcc); + freep(&ctx->xds_ctx); + freep(&ctx->vbi_decoder); + freep(&ctx); +} +void free_subtitle(struct cc_subtitle* sub) +{ + if (!sub) + return; + + freep(&sub->data); + freep(&sub); +} \ No newline at end of file diff --git a/src/lib_ccx/ccx_decoders_common.h b/src/lib_ccx/ccx_decoders_common.h index 18bfaf00..aa30a24b 100644 --- a/src/lib_ccx/ccx_decoders_common.h +++ b/src/lib_ccx/ccx_decoders_common.h @@ -25,4 +25,10 @@ void printdata (struct lib_cc_decode *ctx, const unsigned char *data1, int lengt struct lib_cc_decode* init_cc_decode (struct ccx_decoders_common_settings_t *setting); void dinit_cc_decode(struct lib_cc_decode **ctx); void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub); +struct encoder_ctx* copy_encoder_context(struct encoder_ctx *ctx); +struct lib_cc_decode* copy_decoder_context(struct lib_cc_decode *ctx); +struct cc_subtitle* copy_subtitle(struct cc_subtitle *sub); +void free_encoder_context(struct encoder_ctx *ctx); +void free_decoder_context(struct lib_cc_decode *ctx); +void free_subtitle(struct cc_subtitle* sub); #endif diff --git a/src/lib_ccx/ccx_decoders_vbi.h b/src/lib_ccx/ccx_decoders_vbi.h index 1dc721c4..17c04f55 100644 --- a/src/lib_ccx/ccx_decoders_vbi.h +++ b/src/lib_ccx/ccx_decoders_vbi.h @@ -5,6 +5,7 @@ #define VBI_DEBUG #include "ccx_decoders_structs.h" +#include "ccx_decoders_common.h" struct ccx_decoder_vbi_cfg { diff --git a/src/lib_ccx/ccx_decoders_xds.c b/src/lib_ccx/ccx_decoders_xds.c index c4e90e1b..7b900517 100644 --- a/src/lib_ccx/ccx_decoders_xds.c +++ b/src/lib_ccx/ccx_decoders_xds.c @@ -79,49 +79,6 @@ static const char *XDSProgramTypes[]= #define XDS_TYPE_TIME_OF_DAY 1 #define XDS_TYPE_LOCAL_TIME_ZONE 4 #define XDS_TYPE_OUT_OF_BAND_CHANNEL_NUMBER 0x40 -#define NUM_XDS_BUFFERS 9 // CEA recommends no more than one level of interleaving. Play it safe -#define NUM_BYTES_PER_PACKET 35 // Class + type (repeated for convenience) + data + zero - -struct xds_buffer -{ - unsigned in_use; - int xds_class; - int xds_type; - unsigned char bytes[NUM_BYTES_PER_PACKET]; // Class + type (repeated for convenience) + data + zero - unsigned char used_bytes; -} ; - -typedef struct ccx_decoders_xds_context -{ - // Program Identification Number (Start Time) for current program - int current_xds_min; - int current_xds_hour; - int current_xds_date; - int current_xds_month; - int current_program_type_reported; // No. - int xds_start_time_shown; - int xds_program_length_shown; - char xds_program_description[8][33]; - - char current_xds_network_name[33]; - char current_xds_program_name[33]; - char current_xds_call_letters[7]; - char current_xds_program_type[33]; - - struct xds_buffer xds_buffers[NUM_XDS_BUFFERS]; - int cur_xds_buffer_idx; - int cur_xds_packet_class; - unsigned char *cur_xds_payload; - int cur_xds_payload_length; - int cur_xds_packet_type; - struct ccx_common_timing_ctx *timing; - - unsigned current_ar_start; - unsigned current_ar_end; - - int xds_write_to_file; // Set to 1 if XDS data is to be written to file - -} ccx_decoders_xds_context_t; struct ccx_decoders_xds_context *ccx_decoders_xds_init_library(struct ccx_common_timing_ctx *timing, int xds_write_to_file) { diff --git a/src/lib_ccx/ccx_decoders_xds.h b/src/lib_ccx/ccx_decoders_xds.h index 775e6fbb..8f894ed7 100644 --- a/src/lib_ccx/ccx_decoders_xds.h +++ b/src/lib_ccx/ccx_decoders_xds.h @@ -3,6 +3,9 @@ #include "ccx_decoders_common.h" +#define NUM_BYTES_PER_PACKET 35 // Class + type (repeated for convenience) + data + zero +#define NUM_XDS_BUFFERS 9 // CEA recommends no more than one level of interleaving. Play it safe + struct ccx_decoders_xds_context; void process_xds_bytes (struct ccx_decoders_xds_context *ctx, const unsigned char hi, int lo); void do_end_of_xds (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned char expected_checksum); @@ -10,4 +13,46 @@ void do_end_of_xds (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ct struct ccx_decoders_xds_context *ccx_decoders_xds_init_library(struct ccx_common_timing_ctx *timing, int xds_write_to_file); void xds_cea608_test(); + +struct xds_buffer +{ + unsigned in_use; + int xds_class; + int xds_type; + unsigned char bytes[NUM_BYTES_PER_PACKET]; // Class + type (repeated for convenience) + data + zero + unsigned char used_bytes; +}; + +typedef struct ccx_decoders_xds_context +{ + // Program Identification Number (Start Time) for current program + int current_xds_min; + int current_xds_hour; + int current_xds_date; + int current_xds_month; + int current_program_type_reported; // No. + int xds_start_time_shown; + int xds_program_length_shown; + char xds_program_description[8][33]; + + char current_xds_network_name[33]; + char current_xds_program_name[33]; + char current_xds_call_letters[7]; + char current_xds_program_type[33]; + + struct xds_buffer xds_buffers[NUM_XDS_BUFFERS]; + int cur_xds_buffer_idx; + int cur_xds_packet_class; + unsigned char *cur_xds_payload; + int cur_xds_payload_length; + int cur_xds_packet_type; + struct ccx_common_timing_ctx *timing; + + unsigned current_ar_start; + unsigned current_ar_end; + + int xds_write_to_file; // Set to 1 if XDS data is to be written to file + +} ccx_decoders_xds_context_t; + #endif diff --git a/src/lib_ccx/ccx_demuxer.c b/src/lib_ccx/ccx_demuxer.c index d176ce16..25d192a1 100644 --- a/src/lib_ccx/ccx_demuxer.c +++ b/src/lib_ccx/ccx_demuxer.c @@ -9,9 +9,8 @@ static void ccx_demuxer_reset(struct ccx_demuxer *ctx) ctx->startbytes_pos=0; ctx->startbytes_avail=0; memset (ctx->PIDs_seen, 0, 65536*sizeof (int)); - memset(ctx->min_pts, UINT64_MAX, 65536 * sizeof(uint64_t)); - memset(ctx->found_stream_ids, 0, MAX_NUM_OF_STREAMIDS * sizeof(uint8_t)); - memset(ctx->got_important_streams_min_pts, UINT64_MAX, 3 * sizeof(uint64_t)); + memset(ctx->min_pts, UINT64_MAX, MAX_PID * sizeof(uint64_t)); + memset(ctx->stream_id_of_each_pid, 0, MAX_PID * sizeof(uint8_t)); memset (ctx->PIDs_programs, 0, 65536*sizeof (struct PMT_entry *)); } diff --git a/src/lib_ccx/ccx_demuxer.h b/src/lib_ccx/ccx_demuxer.h index a6ede59a..90804866 100644 --- a/src/lib_ccx/ccx_demuxer.h +++ b/src/lib_ccx/ccx_demuxer.h @@ -15,6 +15,14 @@ #define TS_PMT_MAP_SIZE 128 #define MAX_PROGRAM 128 #define MAX_PROGRAM_NAME_LEN 128 + +enum STREAM_TYPE +{ + PRIVATE_STREAM_1 = 0, + AUDIO, + VIDEO, + COUNT +}; struct ccx_demux_report { unsigned program_cnt; @@ -37,7 +45,7 @@ struct program_info * -1 pid represent that pcr_pid is not available */ int16_t pcr_pid; - LLONG min_pts; //global min_pts for a program (relative to all of its streams) + uint64_t got_important_streams_min_pts[COUNT]; }; struct cap_info @@ -69,13 +77,6 @@ struct cap_info struct list_head pg_stream; }; -enum STREAM_TYPE -{ - PRIVATE_STREAM_1 = 0, - AUDIO, - VIDEO, - COUNT -}; struct ccx_demuxer { int m2ts; @@ -116,13 +117,14 @@ struct ccx_demuxer struct PSI_buffer *PID_buffers[MAX_PSI_PID]; int PIDs_seen[MAX_PID]; - uint64_t min_pts[MAX_PID]; - uint64_t got_important_streams_min_pts[COUNT]; //0 is pvs1 (private stream 1), 1 is audio and 2 is video /*51 possible stream ids in total, 0xbd is private stream, 0xbe is padding stream, 0xbf private stream 2, 0xc0 - 0xdf audio, 0xe0 - 0xef video (stream ids range from 0xbd to 0xef so 0xef - 0xbd + 1 = 51)*/ - uint8_t found_stream_ids[MAX_NUM_OF_STREAMIDS]; + //uint8_t found_stream_ids[MAX_NUM_OF_STREAMIDS]; + + uint8_t stream_id_of_each_pid[MAX_PID]; + uint64_t min_pts[MAX_PID]; struct PMT_entry *PIDs_programs[MAX_PID]; struct ccx_demux_report freport; diff --git a/src/lib_ccx/ccx_encoders_common.c b/src/lib_ccx/ccx_encoders_common.c index 70027ada..6bfa3e28 100644 --- a/src/lib_ccx/ccx_encoders_common.c +++ b/src/lib_ccx/ccx_encoders_common.c @@ -910,11 +910,11 @@ void dinit_encoder(struct encoder_ctx **arg, LLONG current_fts) write_subtitle_file_footer(ctx, ctx->out + i); } + free_encoder_context(ctx->prev); dinit_output_ctx(ctx); freep(&ctx->subline); freep(&ctx->buffer); ctx->capacity = 0; - freep(&ctx->prev); freep(arg); } diff --git a/src/lib_ccx/dvb_subtitle_decoder.c b/src/lib_ccx/dvb_subtitle_decoder.c index 8bbfa3d1..e4f6d3a2 100644 --- a/src/lib_ccx/dvb_subtitle_decoder.c +++ b/src/lib_ccx/dvb_subtitle_decoder.c @@ -1654,10 +1654,23 @@ int dvbsub_decode(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, co enc_ctx->wrote_webvtt_header = 1; } } - memcpy(enc_ctx->prev, enc_ctx, sizeof(struct encoder_ctx)); //we save the current encoder context - memcpy(sub->prev, sub, sizeof(struct cc_subtitle)); //we save the current subtitle - memcpy(dec_ctx->prev, dec_ctx, sizeof(struct lib_cc_decode)); //we save the current decoder context + /* copy previous encoder context*/ + free_encoder_context(enc_ctx->prev); + enc_ctx->prev = NULL; + enc_ctx->prev = copy_encoder_context(enc_ctx); + /* copy previous decoder context */ + free_decoder_context(dec_ctx->prev); + dec_ctx->prev = NULL; + dec_ctx->prev = copy_decoder_context(dec_ctx); + freep(&dec_ctx->prev->private_data); + dec_ctx->prev->private_data = malloc(sizeof(struct DVBSubContext)); + memcpy(dec_ctx->prev->private_data, dec_ctx->private_data, sizeof(struct DVBSubContext)); + /* copy previous subtitle */ + free_subtitle(sub->prev); + sub->prev = NULL; + sub->prev = copy_subtitle(sub); sub->prev->start_time = (dec_ctx->timing->current_pts - dec_ctx->timing->min_pts) / (MPEG_CLOCK_FREQ / 1000); //we set the start time of the previous sub the current pts + write_dvb_sub(dec_ctx->prev, sub->prev); //we write the current dvb sub to update decoder context enc_ctx->write_previous = 1; //we update our boolean value so next time the program reaches this block of code, it encodes the previous sub got_segment |= 16; diff --git a/src/lib_ccx/general_loop.c b/src/lib_ccx/general_loop.c index 16db8a29..802f5497 100644 --- a/src/lib_ccx/general_loop.c +++ b/src/lib_ccx/general_loop.c @@ -809,8 +809,6 @@ int general_loop(struct lib_ccx_ctx *ctx) int caps = 0; uint64_t min_pts = UINT64_MAX; - int got_pts = 0; - int set_pts = 0; stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx); @@ -881,37 +879,45 @@ int general_loop(struct lib_ccx_ctx *ctx) dec_ctx = update_decoder_list_cinfo(ctx, cinfo); dec_ctx->dtvcc->encoder = (void *)enc_ctx; //WARN: otherwise cea-708 will not work - if (!set_pts && dec_ctx->codec == CCX_CODEC_TELETEXT) //even if there's no sub data, we still need to set the min_pts + if (dec_ctx->timing->min_pts == 0x01FFFFFFFFLL) //if we didn't set the min_pts of the program { - if (!got_pts && (ctx->demux_ctx->got_important_streams_min_pts[PRIVATE_STREAM_1] != UINT64_MAX || ctx->demux_ctx->got_important_streams_min_pts[AUDIO] != UINT64_MAX || ctx->demux_ctx->got_important_streams_min_pts[VIDEO] != UINT64_MAX)) //it means we got the first pts for either sub, audio or video :) + int p_index = 0; //program index + for (int i = 0; i < ctx->demux_ctx->nb_program; i++) { - /*we don't need to parse the entire min_pts array since - we are only interested in sub, audio and video stream pts - and we have got_important_streams_min_pts array for that*/ - for (int i = 0; i < COUNT; i++) + if (dec_ctx->program_number == ctx->demux_ctx->pinfo[i].program_number) { - if (ctx->demux_ctx->got_important_streams_min_pts[i] != UINT64_MAX) //PTS is 33 bit, array is 64 so we set the default value to UINT64_MAX instead of 0 because a PTS can also be 0 + p_index = i; + break; + } + } + + if (dec_ctx->codec == CCX_CODEC_TELETEXT) //even if there's no sub data, we still need to set the min_pts + { + if ((ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[PRIVATE_STREAM_1] != UINT64_MAX || ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[AUDIO] != UINT64_MAX || ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[VIDEO] != UINT64_MAX)) //it means we got the first pts for either sub, audio or video :) + { + /*we don't need to parse the entire min_pts array since + we are only interested in sub, audio and video stream pts + and we have got_important_streams_min_pts array for that*/ + for (int i = 0; i < COUNT; i++) { - //printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i); - if (ctx->demux_ctx->got_important_streams_min_pts[i] < min_pts) - min_pts = ctx->demux_ctx->got_important_streams_min_pts[i]; + if (ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[i] != UINT64_MAX) //PTS is 33 bit, array is 64 so we set the default value to UINT64_MAX instead of 0 because a PTS can also be 0 + { + //printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i); + if (ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[i] < min_pts) + min_pts = ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[i]; + } } } - ctx->demux_ctx->pinfo->min_pts = min_pts; //we set the program's min_pts (not exactly perfect since we would need to parse the entire min_pts array to get the real min_pts for the program, but for now it's a good approximation) - got_pts = 1; } - set_pts = 1; - } - if (!set_pts && dec_ctx->codec == CCX_CODEC_DVB) //DVB will always have to be in sync with video (no matter the min_pts of the other streams) - { - if (!got_pts && ctx->demux_ctx->got_important_streams_min_pts[AUDIO] != UINT64_MAX) //it means we got the first pts for video + if (dec_ctx->codec == CCX_CODEC_DVB) //DVB will always have to be in sync with video (no matter the min_pts of the other streams) { - min_pts = ctx->demux_ctx->got_important_streams_min_pts[AUDIO]; - set_current_pts(dec_ctx->timing, min_pts); - set_fts(dec_ctx->timing); - got_pts = 1; + if (ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[AUDIO] != UINT64_MAX) //it means we got the first pts for audio + { + min_pts = ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[AUDIO]; + set_current_pts(dec_ctx->timing, min_pts); + set_fts(dec_ctx->timing); + } } - set_pts = 1; } if (enc_ctx) @@ -979,38 +985,46 @@ int general_loop(struct lib_ccx_ctx *ctx) enc_ctx = update_encoder_list_cinfo(ctx, cinfo); dec_ctx = update_decoder_list_cinfo(ctx, cinfo); dec_ctx->dtvcc->encoder = (void *)enc_ctx; //WARN: otherwise cea-708 will not work - - if (!set_pts && dec_ctx->codec == CCX_CODEC_TELETEXT) //even if there's no sub data, we still need to set the min_pts + + if (dec_ctx->timing->min_pts == 0x01FFFFFFFFLL) //if we didn't set the min_pts of the program { - if (!got_pts && (ctx->demux_ctx->got_important_streams_min_pts[PRIVATE_STREAM_1] != UINT64_MAX || ctx->demux_ctx->got_important_streams_min_pts[AUDIO] != UINT64_MAX || ctx->demux_ctx->got_important_streams_min_pts[VIDEO] != UINT64_MAX)) //it means we got the first pts for either sub, audio or video :) + int p_index = 0; //program index + for (int i = 0; i < ctx->demux_ctx->nb_program; i++) { - /*we don't need to parse the entire min_pts array since - we are only interested in sub, audio and video stream pts - and we have got_important_streams_min_pts array for that*/ - for (int i = 0; i < COUNT; i++) + if (dec_ctx->program_number == ctx->demux_ctx->pinfo[i].program_number) { - if (ctx->demux_ctx->got_important_streams_min_pts[i] != UINT64_MAX) //PTS is 33 bit, array is 64 so we set the default value to UINT64_MAX instead of 0 because a PTS can also be 0 + p_index = i; + break; + } + } + + if (dec_ctx->codec == CCX_CODEC_TELETEXT) //even if there's no sub data, we still need to set the min_pts + { + if ((ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[PRIVATE_STREAM_1] != UINT64_MAX || ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[AUDIO] != UINT64_MAX || ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[VIDEO] != UINT64_MAX)) //it means we got the first pts for either sub, audio or video :) + { + /*we don't need to parse the entire min_pts array since + we are only interested in sub, audio and video stream pts + and we have got_important_streams_min_pts array for that*/ + for (int i = 0; i < COUNT; i++) { - //printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i); - if (ctx->demux_ctx->got_important_streams_min_pts[i] < min_pts) - min_pts = ctx->demux_ctx->got_important_streams_min_pts[i]; + if (ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[i] != UINT64_MAX) //PTS is 33 bit, array is 64 so we set the default value to UINT64_MAX instead of 0 because a PTS can also be 0 + { + //printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i); + if (ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[i] < min_pts) + min_pts = ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[i]; + } } } - ctx->demux_ctx->pinfo->min_pts = min_pts; //we set the program's min_pts (not exactly perfect since we would need to parse the entire min_pts array to get the real min_pts for the program, but for now it's a good approximation) - got_pts = 1; } - set_pts = 1; - } - if (!set_pts && dec_ctx->codec == CCX_CODEC_DVB) //DVB will always have to be in sync with video (no matter the min_pts of the other streams) - { - if (!got_pts && ctx->demux_ctx->got_important_streams_min_pts[AUDIO] != UINT64_MAX) //it means we got the first pts for video + if (dec_ctx->codec == CCX_CODEC_DVB) //DVB will always have to be in sync with video (no matter the min_pts of the other streams) { - min_pts = ctx->demux_ctx->got_important_streams_min_pts[AUDIO]; - set_current_pts(dec_ctx->timing, min_pts); - set_fts(dec_ctx->timing); - got_pts = 1; + if (ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[AUDIO] != UINT64_MAX) //it means we got the first pts for audio + { + min_pts = ctx->demux_ctx->pinfo[p_index].got_important_streams_min_pts[AUDIO]; + set_current_pts(dec_ctx->timing, min_pts); + set_fts(dec_ctx->timing); + } } - set_pts = 1; } if (enc_ctx) diff --git a/src/lib_ccx/lib_ccx.c b/src/lib_ccx/lib_ccx.c index 42c12f59..a7e8c680 100644 --- a/src/lib_ccx/lib_ccx.c +++ b/src/lib_ccx/lib_ccx.c @@ -335,11 +335,7 @@ struct lib_cc_decode *update_decoder_list_cinfo(struct lib_ccx_ctx *ctx, struct //DVB related dec_ctx->prev = NULL; dec_ctx->dec_sub.prev = NULL; - if (dec_ctx->codec == CCX_CODEC_DVB) - { - dec_ctx->prev = malloc(sizeof(struct lib_cc_decode)); - dec_ctx->dec_sub.prev = malloc(sizeof(struct cc_subtitle)); - } + return dec_ctx; } @@ -430,13 +426,8 @@ struct encoder_ctx *update_encoder_list_cinfo(struct lib_ccx_ctx *ctx, struct ca // DVB related enc_ctx->prev = NULL; if (cinfo) - { if (cinfo->codec == CCX_CODEC_DVB) - { enc_ctx->write_previous = 0; - enc_ctx->prev = malloc(sizeof(struct encoder_ctx)); - } - } freep(&extension); return enc_ctx; } diff --git a/src/lib_ccx/ts_functions.c b/src/lib_ccx/ts_functions.c index 11a8f2e8..2c0d2829 100644 --- a/src/lib_ccx/ts_functions.c +++ b/src/lib_ccx/ts_functions.c @@ -731,8 +731,8 @@ long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data) memset(&payload, 0, sizeof(payload)); - if (ctx->got_important_streams_min_pts[VIDEO] == UINT64_MAX) - ctx->got_important_streams_min_pts[VIDEO] = get_video_min_pts(ctx); + /*if (ctx->got_important_streams_min_pts[VIDEO] == UINT64_MAX) + ctx->got_important_streams_min_pts[VIDEO] = get_video_min_pts(ctx);*/ do { @@ -805,48 +805,33 @@ long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data) ctx->PIDs_seen[payload.pid]=2; ts_buffer_psi_packet(ctx); if(ctx->PID_buffers[payload.pid]!=NULL && ctx->PID_buffers[payload.pid]->buffer_length>0) - if(parse_PMT(ctx, ctx->PID_buffers[payload.pid]->buffer+1, ctx->PID_buffers[payload.pid]->buffer_length-1, pinfo)) + if(parse_PMT(ctx, ctx->PID_buffers[payload.pid]->buffer+1, ctx->PID_buffers[payload.pid]->buffer_length-1, pinfo)) gotpes=1; // Signals that something changed and that we must flush the buffer continue; } //PTS calculation - if (ctx->got_important_streams_min_pts[PRIVATE_STREAM_1] == UINT64_MAX || ctx->got_important_streams_min_pts[AUDIO] == UINT64_MAX || ctx->got_important_streams_min_pts[VIDEO] == UINT64_MAX) //if we didn't already get the first PTS of the important streams + if (payload.pesstart) //if there is PES Header data in the payload and we didn't get the first pts of that stream { - if (payload.pesstart) //if there is PES Header data in the payload and we didn't get the first pts of that stream + if (ctx->min_pts[payload.pid] == UINT64_MAX) //check if we don't have the min_pts of that packet's pid { - if (ctx->min_pts[payload.pid] == UINT64_MAX) //check if we don't have the min_pts of that packet's pid + // Packetized Elementary Stream (PES) 32-bit start code + uint64_t pes_prefix = (payload.start[0] << 16) | (payload.start[1] << 8) | payload.start[2]; + uint8_t pes_stream_id = payload.start[3]; + + uint64_t pts = 0; + + // check for PES header + if (pes_prefix == 0x000001) { - // Packetized Elementary Stream (PES) 32-bit start code - uint64_t pes_prefix = (payload.start[0] << 16) | (payload.start[1] << 8) | payload.start[2]; - uint8_t pes_stream_id = payload.start[3]; - - uint64_t pts = 0; - - // check for PES header - if (pes_prefix == 0x000001) - { - //if we didn't already have this stream id with its first pts then calculate - if (pes_stream_id != ctx->found_stream_ids[pes_stream_id - 0xbd]) - { - pts = get_pts(payload.start); - - //keep in mind we already checked if we have this stream id - ctx->found_stream_ids[pes_stream_id - 0xbd] = pes_stream_id; //add it - ctx->min_pts[payload.pid] = pts; //and add its packet pts (we still have this array in case someone wants the global PTS for all stream_id not only for pvs1, audio and video) - - /*we already checked if we got that packet's pts - but we still need to check if we got the min_pts of the stream type - because we might have multiple audio streams for example (audio and subs are sent in order)*/ - if (pes_stream_id == 0xbd && ctx->got_important_streams_min_pts[PRIVATE_STREAM_1] == UINT64_MAX) //private stream 1 - ctx->got_important_streams_min_pts[PRIVATE_STREAM_1] = pts; - if (pes_stream_id >= 0xC0 && pes_stream_id <= 0xDF && ctx->got_important_streams_min_pts[AUDIO] == UINT64_MAX) //audio - ctx->got_important_streams_min_pts[AUDIO] = pts; - } - } + pts = get_pts(payload.start); + //keep in mind we already checked if we have this stream id + ctx->stream_id_of_each_pid[payload.pid] = pes_stream_id; + ctx->min_pts[payload.pid] = pts; //and add its packet pts } } } + switch (ctx->PIDs_seen[payload.pid]) { case 0: // First time we see this PID @@ -996,6 +981,32 @@ long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data) } while( !gotpes ); // gotpes==1 never arrives here because of the breaks + for (int i = 0; i < ctx->nb_program; i++) + { + pinfo = &ctx->pinfo[i]; + for (int j = 0; j < MAX_PID; j++) + { + if (ctx->PIDs_programs[j]) + { + if (ctx->PIDs_programs[j]->program_number == pinfo->program_number) + { + if (ctx->min_pts[j] != UINT64_MAX) + { + if (ctx->stream_id_of_each_pid[j] == 0xbd) + if (ctx->min_pts[j] < pinfo->got_important_streams_min_pts[PRIVATE_STREAM_1]) + pinfo->got_important_streams_min_pts[PRIVATE_STREAM_1] = ctx->min_pts[j]; + if (ctx->stream_id_of_each_pid[j] >= 0xc0 && ctx->stream_id_of_each_pid[j] <= 0xdf) + if (ctx->min_pts[j] < pinfo->got_important_streams_min_pts[AUDIO]) + pinfo->got_important_streams_min_pts[AUDIO] = ctx->min_pts[j]; + if (ctx->stream_id_of_each_pid[j] >= 0xe0 && ctx->stream_id_of_each_pid[j] <= 0xef) + if (ctx->min_pts[j] < pinfo->got_important_streams_min_pts[VIDEO]) + pinfo->got_important_streams_min_pts[VIDEO] = ctx->min_pts[j]; + } + } + } + } + } + if (ret == CCX_EOF) { cinfo_cremation(ctx, data); diff --git a/src/lib_ccx/ts_tables.c b/src/lib_ccx/ts_tables.c index 8876c2a9..1bd83cd0 100644 --- a/src/lib_ccx/ts_tables.c +++ b/src/lib_ccx/ts_tables.c @@ -74,6 +74,7 @@ int update_pinfo(struct ccx_demuxer *ctx, int pid, int program_number) ctx->pinfo[ctx->nb_program].analysed_PMT_once = CCX_FALSE; ctx->pinfo[ctx->nb_program].name[0] = '\0'; ctx->pinfo[ctx->nb_program].pcr_pid = -1; + memset(ctx->pinfo[ctx->nb_program].got_important_streams_min_pts, UINT64_MAX, 3 * sizeof(uint64_t)); ctx->nb_program++; return CCX_OK; @@ -586,9 +587,6 @@ int parse_PAT (struct ccx_demuxer *ctx) dinit_cap(ctx); clear_PMT_array(ctx); memset (ctx->PIDs_seen,0,sizeof (int) *65536); // Forget all we saw - memset(ctx->min_pts, UINT64_MAX, 65536 * sizeof(uint64_t)); - memset(ctx->found_stream_ids, 0, MAX_NUM_OF_STREAMIDS * sizeof(uint8_t)); - memset(ctx->got_important_streams_min_pts, UINT64_MAX, 3 * sizeof(uint64_t)); if (!tlt_config.user_page) // If the user didn't select a page... tlt_config.page=0; // ..forget whatever we detected.