mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2024-12-25 12:23:59 +00:00
Perfected DVB timing and cleaned up code
This commit is contained in:
parent
9f331b6a92
commit
b633491b91
@ -11,7 +11,7 @@ static void ccx_demuxer_reset(struct ccx_demuxer *ctx)
|
||||
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_first_pts, UINT64_MAX, 3 * sizeof(uint64_t));
|
||||
memset(ctx->got_important_streams_min_pts, UINT64_MAX, 3 * sizeof(uint64_t));
|
||||
memset (ctx->PIDs_programs, 0, 65536*sizeof (struct PMT_entry *));
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,13 @@ struct cap_info
|
||||
struct list_head pg_stream;
|
||||
|
||||
};
|
||||
|
||||
enum STREAM_TYPE
|
||||
{
|
||||
PRIVATE_STREAM_1 = 0,
|
||||
AUDIO,
|
||||
VIDEO,
|
||||
COUNT
|
||||
};
|
||||
struct ccx_demuxer
|
||||
{
|
||||
int m2ts;
|
||||
@ -111,7 +117,7 @@ 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_first_pts[3]; //0 is pvs1 (private stream 1), 1 is audio and 2 is video
|
||||
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
|
||||
|
@ -858,21 +858,6 @@ int general_loop(struct lib_ccx_ctx *ctx)
|
||||
if(!datalist)
|
||||
break;
|
||||
}
|
||||
//this part is for getting the min_pts of every possible stream ID (optional)
|
||||
/*if (!got_pts && (ctx->demux_ctx->got_first_pts[0] || ctx->demux_ctx->got_first_pts[1] || ctx->demux_ctx->got_first_pts[2])) //it means we got the first pts for video, audio and sub :)
|
||||
{
|
||||
for (int i = 0; i < 65536; i++) // we parse the array with the min_pts for each stream
|
||||
{
|
||||
if (ctx->demux_ctx->min_pts[i] != UINT64_MAX) //PTS is 33 bit, array is 64 so we set the default value tu UINT64_MAX instead of 0 because PTS can also be 0
|
||||
{
|
||||
//printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i);
|
||||
if (ctx->demux_ctx->min_pts[i] < min_pts)
|
||||
min_pts = ctx->demux_ctx->min_pts[i];
|
||||
}
|
||||
}
|
||||
ctx->demux_ctx->pinfo->min_pts = min_pts;
|
||||
got_pts = 1;
|
||||
}*/
|
||||
if (!datalist)
|
||||
continue;
|
||||
position_sanity_check(ctx->demux_ctx);
|
||||
@ -898,18 +883,18 @@ int general_loop(struct lib_ccx_ctx *ctx)
|
||||
|
||||
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 (!got_pts && (ctx->demux_ctx->got_first_pts[0] != UINT64_MAX || ctx->demux_ctx->got_first_pts[1] != UINT64_MAX || ctx->demux_ctx->got_first_pts[2] != UINT64_MAX)) //it means we got the first pts for either sub, audio or video :)
|
||||
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 :)
|
||||
{
|
||||
/*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_first_pts array for that*/
|
||||
for (int i = 0; i < 3; i++)
|
||||
and we have got_important_streams_min_pts array for that*/
|
||||
for (int i = 0; i < COUNT; i++)
|
||||
{
|
||||
if (ctx->demux_ctx->got_first_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
|
||||
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
|
||||
{
|
||||
//printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i);
|
||||
if (ctx->demux_ctx->got_first_pts[i] < min_pts)
|
||||
min_pts = ctx->demux_ctx->got_first_pts[i];
|
||||
if (ctx->demux_ctx->got_important_streams_min_pts[i] < min_pts)
|
||||
min_pts = ctx->demux_ctx->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)
|
||||
@ -919,9 +904,9 @@ int general_loop(struct lib_ccx_ctx *ctx)
|
||||
}
|
||||
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_first_pts[2] != UINT64_MAX) //it means we got the first pts for video
|
||||
if (!got_pts && ctx->demux_ctx->got_important_streams_min_pts[AUDIO] != UINT64_MAX) //it means we got the first pts for video
|
||||
{
|
||||
min_pts = ctx->demux_ctx->got_first_pts[2];
|
||||
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;
|
||||
@ -993,18 +978,18 @@ int general_loop(struct lib_ccx_ctx *ctx)
|
||||
|
||||
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 (!got_pts && (ctx->demux_ctx->got_first_pts[0] != UINT64_MAX || ctx->demux_ctx->got_first_pts[1] != UINT64_MAX || ctx->demux_ctx->got_first_pts[2] != UINT64_MAX)) //it means we got the first pts for either sub, audio or video :)
|
||||
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 :)
|
||||
{
|
||||
/*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_first_pts array for that*/
|
||||
for (int i = 0; i < 3; i++)
|
||||
and we have got_important_streams_min_pts array for that*/
|
||||
for (int i = 0; i < COUNT; i++)
|
||||
{
|
||||
if (ctx->demux_ctx->got_first_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
|
||||
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
|
||||
{
|
||||
//printf("Got pts: %" PRId64 " for PID %d\n", ctx->demux_ctx->min_pts[i], i);
|
||||
if (ctx->demux_ctx->got_first_pts[i] < min_pts)
|
||||
min_pts = ctx->demux_ctx->got_first_pts[i];
|
||||
if (ctx->demux_ctx->got_important_streams_min_pts[i] < min_pts)
|
||||
min_pts = ctx->demux_ctx->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)
|
||||
@ -1014,9 +999,9 @@ int general_loop(struct lib_ccx_ctx *ctx)
|
||||
}
|
||||
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_first_pts[2] != UINT64_MAX) //it means we got the first pts for video
|
||||
if (!got_pts && ctx->demux_ctx->got_important_streams_min_pts[AUDIO] != UINT64_MAX) //it means we got the first pts for video
|
||||
{
|
||||
min_pts = ctx->demux_ctx->got_first_pts[2];
|
||||
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;
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "ccx_decoders_isdb.h"
|
||||
#include "file_buffer.h"
|
||||
|
||||
#define RAI_MASK 0x40 //byte mask to check if RAI bit is set (random access indicator)
|
||||
|
||||
unsigned char tspacket[188]; // Current packet
|
||||
|
||||
//struct ts_payload payload;
|
||||
@ -275,7 +277,7 @@ int ts_readpacket(struct ccx_demuxer* ctx, struct ts_payload *payload)
|
||||
|
||||
payload->start = tspacket + 4;
|
||||
payload->length = 188 - 4;
|
||||
if ( adaptation_field_control & 2 )
|
||||
if (adaptation_field_control & 2)
|
||||
{
|
||||
// Take the PCR (Program Clock Reference) from here, in case PTS is not available (copied from telxcc).
|
||||
adaptation_field_length = tspacket[4];
|
||||
@ -294,9 +296,11 @@ int ts_readpacket(struct ccx_demuxer* ctx, struct ts_payload *payload)
|
||||
// payload->pcr |= tspacket[11];
|
||||
}
|
||||
|
||||
payload->has_random_access_indicator = (tspacket[5] & RAI_MASK) != 0;
|
||||
|
||||
// Catch bad packages with adaptation_field_length > 184 and
|
||||
// the unsigned nature of payload_length leading to huge numbers.
|
||||
if(adaptation_field_length < payload->length)
|
||||
if (adaptation_field_length < payload->length)
|
||||
{
|
||||
payload->start += adaptation_field_length + 1;
|
||||
payload->length -= adaptation_field_length + 1;
|
||||
@ -308,6 +312,8 @@ int ts_readpacket(struct ccx_demuxer* ctx, struct ts_payload *payload)
|
||||
dbg_print(CCX_DMT_PARSE, " Reject package - set length to zero.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
payload->has_random_access_indicator = 0;
|
||||
|
||||
dbg_print(CCX_DMT_PARSE, "TS pid: %d PES start: %d counter: %u payload length: %u adapt length: %d\n",
|
||||
payload->pid, payload->start, payload->counter, payload->length,
|
||||
@ -607,6 +613,110 @@ int copy_payload_to_capbuf(struct cap_info *cinfo, struct ts_payload *payload)
|
||||
// Read ts packets until a complete video PES element can be returned.
|
||||
// The data is read into capbuf and the function returns the number of
|
||||
// bytes read.
|
||||
|
||||
uint64_t get_pts(uint8_t* buffer)
|
||||
{
|
||||
uint64_t pes_prefix;
|
||||
uint8_t pes_stream_id;
|
||||
uint16_t pes_packet_length;
|
||||
uint8_t optional_pes_header_included = NO;
|
||||
uint16_t optional_pes_header_length = 0;
|
||||
uint64_t pts = 0;
|
||||
|
||||
// Packetized Elementary Stream (PES) 32-bit start code
|
||||
pes_prefix = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
||||
pes_stream_id = buffer[3];
|
||||
|
||||
// check for PES header
|
||||
if (pes_prefix == 0x000001)
|
||||
{
|
||||
pes_packet_length = 6 + ((buffer[4] << 8) | buffer[5]); // 5th and 6th byte of the header define the length of the rest of the packet (+6 is for the prefix, stream ID and packet length)
|
||||
|
||||
printf("Packet start code prefix: %04x # ", pes_prefix);
|
||||
printf("Stream ID: %04x # ", pes_stream_id);
|
||||
printf("Packet length: %d ", pes_packet_length);
|
||||
|
||||
// optional PES header marker bits (10.. ....)
|
||||
if ((buffer[6] & 0xc0) == 0x80)
|
||||
{
|
||||
optional_pes_header_included = YES;
|
||||
optional_pes_header_length = buffer[8];
|
||||
}
|
||||
|
||||
if (optional_pes_header_included == YES && optional_pes_header_length > 0 && (buffer[7] & 0x80) > 0)
|
||||
{
|
||||
//get associated PTS as it exists
|
||||
pts = (buffer[9] & 0x0e);
|
||||
pts <<= 29;
|
||||
pts |= (buffer[10] << 22);
|
||||
pts |= ((buffer[11] & 0xfe) << 14);
|
||||
pts |= (buffer[12] << 7);
|
||||
pts |= ((buffer[13] & 0xfe) >> 1);
|
||||
return pts;
|
||||
}
|
||||
}
|
||||
return UINT64_MAX;
|
||||
}
|
||||
uint64_t get_video_min_pts(struct ccx_demuxer *context)
|
||||
{
|
||||
struct ccx_demuxer *ctx = malloc(sizeof(struct ccx_demuxer));
|
||||
memcpy(ctx, context, sizeof(struct ccx_demuxer));
|
||||
|
||||
int ret = CCX_EAGAIN;
|
||||
|
||||
struct ts_payload payload;
|
||||
|
||||
int got_pts = 0;
|
||||
|
||||
uint64_t min_pts = UINT64_MAX;
|
||||
uint64_t *pts_array = NULL;
|
||||
int num_of_remembered_pts = 0;
|
||||
int pcount = 0;
|
||||
uint64_t pts = UINT64_MAX;
|
||||
do
|
||||
{
|
||||
pcount++;
|
||||
// Exit the loop at EOF
|
||||
ret = ts_readpacket(ctx, &payload);
|
||||
if (ret != CCX_OK)
|
||||
break;
|
||||
|
||||
if (payload.pesstart)
|
||||
{
|
||||
// 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];
|
||||
|
||||
if (pes_prefix == 0x000001)
|
||||
if(pes_stream_id >= 0xe0 && pes_stream_id <= 0xef)
|
||||
pts = get_pts(payload.start);
|
||||
}
|
||||
|
||||
if (pts != UINT64_MAX)
|
||||
{
|
||||
num_of_remembered_pts++;
|
||||
pts_array = realloc(pts_array, num_of_remembered_pts * sizeof(uint64_t));
|
||||
((uint64_t*)pts_array)[num_of_remembered_pts - 1] = pts;
|
||||
}
|
||||
if (num_of_remembered_pts >= 1 && payload.has_random_access_indicator)
|
||||
got_pts = 1;
|
||||
|
||||
} while (!got_pts);
|
||||
|
||||
//search for smallest pts
|
||||
uint64_t* p = pts_array;
|
||||
for (int i = 0; i < num_of_remembered_pts; i++)
|
||||
{
|
||||
if (*p < min_pts)
|
||||
min_pts = *p;
|
||||
p++;
|
||||
}
|
||||
|
||||
freep(ctx);
|
||||
freep(&pts_array);
|
||||
|
||||
return min_pts;
|
||||
}
|
||||
long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data)
|
||||
{
|
||||
int gotpes = 0;
|
||||
@ -621,6 +731,9 @@ 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);
|
||||
|
||||
do
|
||||
{
|
||||
pcount++;
|
||||
@ -630,288 +743,256 @@ long ts_readstream(struct ccx_demuxer *ctx, struct demuxer_data **data)
|
||||
if ( ret != CCX_OK)
|
||||
break;
|
||||
|
||||
//// Skip damaged packets, they could do more harm than good
|
||||
//if (payload.transport_error)
|
||||
//{
|
||||
// dbg_print(CCX_DMT_VERBOSE, "Packet (pid %u) skipped - transport error.\n",
|
||||
// payload.pid);
|
||||
// continue;
|
||||
//}
|
||||
// Skip damaged packets, they could do more harm than good
|
||||
if (payload.transport_error)
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Packet (pid %u) skipped - transport error.\n",
|
||||
payload.pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
//// Check for PAT
|
||||
//if( payload.pid == 0) // This is a PAT
|
||||
//{
|
||||
// ts_buffer_psi_packet(ctx);
|
||||
// if(ctx->PID_buffers[payload.pid]!=NULL && ctx->PID_buffers[payload.pid]->buffer_length>0)
|
||||
// parse_PAT(ctx); // Returns 1 if there was some data in the buffer already
|
||||
// continue;
|
||||
//}
|
||||
// Check for PAT
|
||||
if( payload.pid == 0) // This is a PAT
|
||||
{
|
||||
ts_buffer_psi_packet(ctx);
|
||||
if(ctx->PID_buffers[payload.pid]!=NULL && ctx->PID_buffers[payload.pid]->buffer_length>0)
|
||||
parse_PAT(ctx); // Returns 1 if there was some data in the buffer already
|
||||
continue;
|
||||
}
|
||||
|
||||
//if( ccx_options.xmltv >= 1 && payload.pid == 0x11) {// This is SDT (or BAT)
|
||||
// ts_buffer_psi_packet(ctx);
|
||||
// if(ctx->PID_buffers[payload.pid]!=NULL && ctx->PID_buffers[payload.pid]->buffer_length>0)
|
||||
// parse_SDT(ctx);
|
||||
//}
|
||||
if( ccx_options.xmltv >= 1 && payload.pid == 0x11) {// This is SDT (or BAT)
|
||||
ts_buffer_psi_packet(ctx);
|
||||
if(ctx->PID_buffers[payload.pid]!=NULL && ctx->PID_buffers[payload.pid]->buffer_length>0)
|
||||
parse_SDT(ctx);
|
||||
}
|
||||
|
||||
//if( ccx_options.xmltv >= 1 && payload.pid == 0x12) // This is DVB EIT
|
||||
// parse_EPG_packet(ctx->parent);
|
||||
//if( ccx_options.xmltv >= 1 && payload.pid >= 0x1000) // This may be ATSC EPG packet
|
||||
// parse_EPG_packet(ctx->parent);
|
||||
if( ccx_options.xmltv >= 1 && payload.pid == 0x12) // This is DVB EIT
|
||||
parse_EPG_packet(ctx->parent);
|
||||
if( ccx_options.xmltv >= 1 && payload.pid >= 0x1000) // This may be ATSC EPG packet
|
||||
parse_EPG_packet(ctx->parent);
|
||||
|
||||
|
||||
//for (j = 0; j < ctx->nb_program; j++)
|
||||
//{
|
||||
// if (ctx->pinfo[j].analysed_PMT_once == CCX_TRUE &&
|
||||
// ctx->pinfo[j].pcr_pid == payload.pid &&
|
||||
// payload.have_pcr)
|
||||
// {
|
||||
// ctx->last_global_timestamp = ctx->global_timestamp;
|
||||
// ctx->global_timestamp = (uint32_t) payload.pcr / 90;
|
||||
// if (!ctx->global_timestamp_inited)
|
||||
// {
|
||||
// ctx->min_global_timestamp = ctx->global_timestamp;
|
||||
// ctx->global_timestamp_inited = 1;
|
||||
// }
|
||||
// if (ctx->min_global_timestamp > ctx->global_timestamp)
|
||||
// {
|
||||
// ctx->offset_global_timestamp = ctx->last_global_timestamp - ctx->min_global_timestamp;
|
||||
// ctx->min_global_timestamp = ctx->global_timestamp;
|
||||
// }
|
||||
for (j = 0; j < ctx->nb_program; j++)
|
||||
{
|
||||
if (ctx->pinfo[j].analysed_PMT_once == CCX_TRUE &&
|
||||
ctx->pinfo[j].pcr_pid == payload.pid &&
|
||||
payload.have_pcr)
|
||||
{
|
||||
ctx->last_global_timestamp = ctx->global_timestamp;
|
||||
ctx->global_timestamp = (uint32_t) payload.pcr / 90;
|
||||
if (!ctx->global_timestamp_inited)
|
||||
{
|
||||
ctx->min_global_timestamp = ctx->global_timestamp;
|
||||
ctx->global_timestamp_inited = 1;
|
||||
}
|
||||
if (ctx->min_global_timestamp > ctx->global_timestamp)
|
||||
{
|
||||
ctx->offset_global_timestamp = ctx->last_global_timestamp - ctx->min_global_timestamp;
|
||||
ctx->min_global_timestamp = ctx->global_timestamp;
|
||||
}
|
||||
|
||||
// }
|
||||
// if (ctx->pinfo[j].pid == payload.pid)
|
||||
// {
|
||||
// if (!ctx->PIDs_seen[payload.pid])
|
||||
// dbg_print(CCX_DMT_PAT, "This PID (%u) is a PMT for program %u.\n",payload.pid, ctx->pinfo[j].program_number);
|
||||
// pinfo = ctx->pinfo + j;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
//if (j != ctx->nb_program)
|
||||
//{
|
||||
// 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))
|
||||
// gotpes=1; // Signals that something changed and that we must flush the buffer
|
||||
// continue;
|
||||
//}
|
||||
}
|
||||
if (ctx->pinfo[j].pid == payload.pid)
|
||||
{
|
||||
if (!ctx->PIDs_seen[payload.pid])
|
||||
dbg_print(CCX_DMT_PAT, "This PID (%u) is a PMT for program %u.\n",payload.pid, ctx->pinfo[j].program_number);
|
||||
pinfo = ctx->pinfo + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j != ctx->nb_program)
|
||||
{
|
||||
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))
|
||||
gotpes=1; // Signals that something changed and that we must flush the buffer
|
||||
continue;
|
||||
}
|
||||
|
||||
////PTS calculation
|
||||
//if (ctx->got_first_pts[0] == UINT64_MAX || ctx->got_first_pts[1] == UINT64_MAX || ctx->got_first_pts[2] == 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 (ctx->min_pts[payload.pid] == UINT64_MAX) //check if we don't have the min_pts of that packet's pid
|
||||
// {
|
||||
// //Write the PES Header to console
|
||||
// uint64_t pes_prefix;
|
||||
// uint8_t pes_stream_id;
|
||||
// uint16_t pes_packet_length;
|
||||
// uint8_t optional_pes_header_included = NO;
|
||||
// uint16_t optional_pes_header_length = 0;
|
||||
// uint64_t pts = 0;
|
||||
//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 (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];
|
||||
|
||||
// // Packetized Elementary Stream (PES) 32-bit start code
|
||||
// pes_prefix = (payload.start[0] << 16) | (payload.start[1] << 8) | payload.start[2];
|
||||
// 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])
|
||||
// {
|
||||
// pes_packet_length = 6 + ((payload.start[4] << 8) | payload.start[5]); // 5th and 6th byte of the header define the length of the rest of the packet (+6 is for the prefix, stream ID and packet length)
|
||||
// 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);
|
||||
|
||||
// /*if (pes_packet_length == 6)
|
||||
// {
|
||||
// // great, there is only a header and no extension + payload
|
||||
// return;
|
||||
// }*/
|
||||
//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)
|
||||
|
||||
// // optional PES header marker bits (10.. ....)
|
||||
// if ((payload.start[6] & 0xc0) == 0x80)
|
||||
// {
|
||||
// optional_pes_header_included = YES;
|
||||
// optional_pes_header_length = payload.start[8];
|
||||
// }
|
||||
/*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (ctx->PIDs_seen[payload.pid])
|
||||
{
|
||||
case 0: // First time we see this PID
|
||||
if (ctx->PIDs_programs[payload.pid])
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "\nNew PID found: %u (%s), belongs to program: %u\n", payload.pid,
|
||||
desc[ctx->PIDs_programs[payload.pid]->printable_stream_type],
|
||||
ctx->PIDs_programs[payload.pid]->program_number);
|
||||
ctx->PIDs_seen[payload.pid]=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "\nNew PID found: %u, program number still unknown\n", payload.pid);
|
||||
ctx->PIDs_seen[payload.pid]=1;
|
||||
}
|
||||
break;
|
||||
case 1: // Saw it before but we didn't know what program it belonged to. Luckier now?
|
||||
if (ctx->PIDs_programs[payload.pid])
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "\nProgram for PID: %u (previously unknown) is: %u (%s)\n", payload.pid,
|
||||
ctx->PIDs_programs[payload.pid]->program_number,
|
||||
desc[ctx->PIDs_programs[payload.pid]->printable_stream_type]
|
||||
);
|
||||
ctx->PIDs_seen[payload.pid]=2;
|
||||
}
|
||||
break;
|
||||
case 2: // Already seen and reported with correct program
|
||||
break;
|
||||
case 3: // Already seen, reported, and inspected for CC data (and found some)
|
||||
break;
|
||||
}
|
||||
|
||||
// if (optional_pes_header_included == YES && optional_pes_header_length > 0 && (payload.start[7] & 0x80) > 0)
|
||||
// {
|
||||
// //get associated PTS as it exists
|
||||
// pts = (payload.start[9] & 0x0e);
|
||||
// pts <<= 29;
|
||||
// pts |= (payload.start[10] << 22);
|
||||
// pts |= ((payload.start[11] & 0xfe) << 14);
|
||||
// pts |= (payload.start[12] << 7);
|
||||
// pts |= ((payload.start[13] & 0xfe) >> 1);
|
||||
if (payload.pid==1003 && !ctx->hauppauge_warning_shown && !ccx_options.hauppauge_mode)
|
||||
{
|
||||
// TODO: Change this very weak test for something more decent such as size.
|
||||
mprint ("\n\nNote: This TS could be a recording from a Hauppage card. If no captions are detected, try --hauppauge\n\n");
|
||||
ctx->hauppauge_warning_shown=1;
|
||||
}
|
||||
|
||||
// //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)
|
||||
if (ccx_options.hauppauge_mode && payload.pid==HAUPPAGE_CCPID)
|
||||
{
|
||||
// Haup packets processed separately, because we can't mix payloads. So they go in their own buffer
|
||||
// copy payload to capbuf
|
||||
int haup_newcapbuflen = haup_capbuflen + payload.length;
|
||||
if ( haup_newcapbuflen > haup_capbufsize) {
|
||||
haup_capbuf = (unsigned char*)realloc(haup_capbuf, haup_newcapbuflen);
|
||||
if (!haup_capbuf)
|
||||
fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
haup_capbufsize = haup_newcapbuflen;
|
||||
}
|
||||
memcpy(haup_capbuf+haup_capbuflen, payload.start, payload.length);
|
||||
haup_capbuflen = haup_newcapbuflen;
|
||||
|
||||
// /*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*/
|
||||
// if (pes_stream_id == 0xbd && ctx->got_first_pts[0] == UINT64_MAX) //private stream 1
|
||||
// ctx->got_first_pts[0] = pts;
|
||||
// if (pes_stream_id >= 0xC0 && pes_stream_id <= 0xDF && ctx->got_first_pts[1] == UINT64_MAX) //audio
|
||||
// ctx->got_first_pts[1] = pts;
|
||||
// if (pes_stream_id >= 0xE0 && pes_stream_id <= 0xEF && ctx->got_first_pts[2] == UINT64_MAX) //video
|
||||
// ctx->got_first_pts[2] = pts;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//switch (ctx->PIDs_seen[payload.pid])
|
||||
//{
|
||||
// case 0: // First time we see this PID
|
||||
// if (ctx->PIDs_programs[payload.pid])
|
||||
// {
|
||||
// dbg_print(CCX_DMT_PARSE, "\nNew PID found: %u (%s), belongs to program: %u\n", payload.pid,
|
||||
// desc[ctx->PIDs_programs[payload.pid]->printable_stream_type],
|
||||
// ctx->PIDs_programs[payload.pid]->program_number);
|
||||
// ctx->PIDs_seen[payload.pid]=2;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// dbg_print(CCX_DMT_PARSE, "\nNew PID found: %u, program number still unknown\n", payload.pid);
|
||||
// ctx->PIDs_seen[payload.pid]=1;
|
||||
// }
|
||||
// break;
|
||||
// case 1: // Saw it before but we didn't know what program it belonged to. Luckier now?
|
||||
// if (ctx->PIDs_programs[payload.pid])
|
||||
// {
|
||||
// dbg_print(CCX_DMT_PARSE, "\nProgram for PID: %u (previously unknown) is: %u (%s)\n", payload.pid,
|
||||
// ctx->PIDs_programs[payload.pid]->program_number,
|
||||
// desc[ctx->PIDs_programs[payload.pid]->printable_stream_type]
|
||||
// );
|
||||
// ctx->PIDs_seen[payload.pid]=2;
|
||||
// }
|
||||
// break;
|
||||
// case 2: // Already seen and reported with correct program
|
||||
// break;
|
||||
// case 3: // Already seen, reported, and inspected for CC data (and found some)
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
//if (payload.pid==1003 && !ctx->hauppauge_warning_shown && !ccx_options.hauppauge_mode)
|
||||
//{
|
||||
// // TODO: Change this very weak test for something more decent such as size.
|
||||
// mprint ("\n\nNote: This TS could be a recording from a Hauppage card. If no captions are detected, try --hauppauge\n\n");
|
||||
// ctx->hauppauge_warning_shown=1;
|
||||
//}
|
||||
// Skip packets with no payload. This also fixes the problems
|
||||
// with the continuity counter not being incremented in empty
|
||||
// packets.
|
||||
if ( !payload.length )
|
||||
{
|
||||
dbg_print(CCX_DMT_VERBOSE, "Packet (pid %u) skipped - no payload.\n",
|
||||
payload.pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (ccx_options.hauppauge_mode && payload.pid==HAUPPAGE_CCPID)
|
||||
//{
|
||||
// // Haup packets processed separately, because we can't mix payloads. So they go in their own buffer
|
||||
// // copy payload to capbuf
|
||||
// int haup_newcapbuflen = haup_capbuflen + payload.length;
|
||||
// if ( haup_newcapbuflen > haup_capbufsize) {
|
||||
// haup_capbuf = (unsigned char*)realloc(haup_capbuf, haup_newcapbuflen);
|
||||
// if (!haup_capbuf)
|
||||
// fatal(EXIT_NOT_ENOUGH_MEMORY, "Out of memory");
|
||||
// haup_capbufsize = haup_newcapbuflen;
|
||||
// }
|
||||
// memcpy(haup_capbuf+haup_capbuflen, payload.start, payload.length);
|
||||
// haup_capbuflen = haup_newcapbuflen;
|
||||
cinfo = get_cinfo(ctx, payload.pid);
|
||||
if(cinfo == NULL)
|
||||
{
|
||||
if (!packet_analysis_mode)
|
||||
dbg_print(CCX_DMT_PARSE, "Packet (pid %u) skipped - no stream with captions identified yet.\n",
|
||||
payload.pid);
|
||||
else
|
||||
look_for_caption_data (ctx, &payload);
|
||||
continue;
|
||||
}
|
||||
else if (cinfo->ignore)
|
||||
{
|
||||
if(cinfo->codec_private_data)
|
||||
{
|
||||
switch(cinfo->codec)
|
||||
{
|
||||
case CCX_CODEC_TELETEXT:
|
||||
telxcc_close(&cinfo->codec_private_data, NULL);
|
||||
break;
|
||||
case CCX_CODEC_DVB:
|
||||
dvbsub_close_decoder(&cinfo->codec_private_data);
|
||||
break;
|
||||
case CCX_CODEC_ISDB_CC:
|
||||
delete_isdb_decoder(&cinfo->codec_private_data);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cinfo->codec_private_data = NULL;
|
||||
}
|
||||
|
||||
//}
|
||||
if (cinfo->capbuflen > 0)
|
||||
{
|
||||
freep(&cinfo->capbuf);
|
||||
cinfo->capbufsize = 0;
|
||||
cinfo->capbuflen = 0;
|
||||
delete_demuxer_data_node_by_pid(data, cinfo->pid);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//// Skip packets with no payload. This also fixes the problems
|
||||
//// with the continuity counter not being incremented in empty
|
||||
//// packets.
|
||||
//if ( !payload.length )
|
||||
//{
|
||||
// dbg_print(CCX_DMT_VERBOSE, "Packet (pid %u) skipped - no payload.\n",
|
||||
// payload.pid);
|
||||
// continue;
|
||||
//}
|
||||
// Video PES start
|
||||
if (payload.pesstart)
|
||||
{
|
||||
cinfo->saw_pesstart = 1;
|
||||
cinfo->prev_counter = payload.counter - 1;
|
||||
}
|
||||
|
||||
//cinfo = get_cinfo(ctx, payload.pid);
|
||||
//if(cinfo == NULL)
|
||||
//{
|
||||
// if (!packet_analysis_mode)
|
||||
// dbg_print(CCX_DMT_PARSE, "Packet (pid %u) skipped - no stream with captions identified yet.\n",
|
||||
// payload.pid);
|
||||
// else
|
||||
// look_for_caption_data (ctx, &payload);
|
||||
// continue;
|
||||
//}
|
||||
//else if (cinfo->ignore)
|
||||
//{
|
||||
// if(cinfo->codec_private_data)
|
||||
// {
|
||||
// switch(cinfo->codec)
|
||||
// {
|
||||
// case CCX_CODEC_TELETEXT:
|
||||
// telxcc_close(&cinfo->codec_private_data, NULL);
|
||||
// break;
|
||||
// case CCX_CODEC_DVB:
|
||||
// dvbsub_close_decoder(&cinfo->codec_private_data);
|
||||
// break;
|
||||
// case CCX_CODEC_ISDB_CC:
|
||||
// delete_isdb_decoder(&cinfo->codec_private_data);
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// cinfo->codec_private_data = NULL;
|
||||
// }
|
||||
|
||||
// if (cinfo->capbuflen > 0)
|
||||
// {
|
||||
// freep(&cinfo->capbuf);
|
||||
// cinfo->capbufsize = 0;
|
||||
// cinfo->capbuflen = 0;
|
||||
// delete_demuxer_data_node_by_pid(data, cinfo->pid);
|
||||
// }
|
||||
// continue;
|
||||
//}
|
||||
|
||||
//// Video PES start
|
||||
//if (payload.pesstart)
|
||||
//{
|
||||
// cinfo->saw_pesstart = 1;
|
||||
// cinfo->prev_counter = payload.counter - 1;
|
||||
//}
|
||||
|
||||
//// Discard packets when no pesstart was found.
|
||||
//if ( !cinfo->saw_pesstart )
|
||||
// continue;
|
||||
// Discard packets when no pesstart was found.
|
||||
if ( !cinfo->saw_pesstart )
|
||||
continue;
|
||||
|
||||
|
||||
//if ( (cinfo->prev_counter == 15 ? 0 : cinfo->prev_counter + 1) != payload.counter )
|
||||
//{
|
||||
// mprint("TS continuity counter not incremented prev/curr %u/%u\n",
|
||||
// cinfo->prev_counter, payload.counter);
|
||||
//}
|
||||
//cinfo->prev_counter = payload.counter;
|
||||
if ( (cinfo->prev_counter == 15 ? 0 : cinfo->prev_counter + 1) != payload.counter )
|
||||
{
|
||||
mprint("TS continuity counter not incremented prev/curr %u/%u\n",
|
||||
cinfo->prev_counter, payload.counter);
|
||||
}
|
||||
cinfo->prev_counter = payload.counter;
|
||||
|
||||
//// If the buffer is empty we just started this function
|
||||
//if (payload.pesstart && cinfo->capbuflen > 0)
|
||||
//{
|
||||
// dbg_print(CCX_DMT_PARSE, "\nPES finished (%ld bytes/%ld PES packets/%ld total packets)\n",
|
||||
// cinfo->capbuflen, pespcount, pcount);
|
||||
// If the buffer is empty we just started this function
|
||||
if (payload.pesstart && cinfo->capbuflen > 0)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "\nPES finished (%ld bytes/%ld PES packets/%ld total packets)\n",
|
||||
cinfo->capbuflen, pespcount, pcount);
|
||||
|
||||
// // Keep the data from capbuf to be worked on
|
||||
// ret = copy_capbuf_demux_data(ctx, data, cinfo);
|
||||
// cinfo->capbuflen = 0;
|
||||
// gotpes = 1;
|
||||
//}
|
||||
// Keep the data from capbuf to be worked on
|
||||
ret = copy_capbuf_demux_data(ctx, data, cinfo);
|
||||
cinfo->capbuflen = 0;
|
||||
gotpes = 1;
|
||||
}
|
||||
|
||||
//copy_payload_to_capbuf(cinfo, &payload);
|
||||
//if(ret < 0)
|
||||
//{
|
||||
// if(errno == EINVAL)
|
||||
// continue;
|
||||
// else
|
||||
// break;
|
||||
//}
|
||||
copy_payload_to_capbuf(cinfo, &payload);
|
||||
if(ret < 0)
|
||||
{
|
||||
if(errno == EINVAL)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
//pespcount++;
|
||||
pespcount++;
|
||||
}
|
||||
while( !gotpes ); // gotpes==1 never arrives here because of the breaks
|
||||
|
||||
|
@ -9,6 +9,7 @@ struct ts_payload
|
||||
unsigned pid; // Stream PID
|
||||
int counter; // continuity counter
|
||||
int transport_error; // 0 = packet OK, non-zero damaged
|
||||
int has_random_access_indicator; //1 = start of new GOP (Set when the stream may be decoded without errors from this point)
|
||||
int have_pcr;
|
||||
int64_t pcr;
|
||||
unsigned char section_buf[4098];
|
||||
|
@ -588,7 +588,7 @@ int parse_PAT (struct ccx_demuxer *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_first_pts, UINT64_MAX, 3 * sizeof(uint64_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