mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2024-12-25 04:11:38 +00:00
Fixed DVB multiprogram.
This commit is contained in:
parent
ade11eb80f
commit
462f63a294
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -5,6 +5,7 @@
|
||||
#define VBI_DEBUG
|
||||
|
||||
#include "ccx_decoders_structs.h"
|
||||
#include "ccx_decoders_common.h"
|
||||
|
||||
struct ccx_decoder_vbi_cfg
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 *));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user