Perfected DVB timing and cleaned up code

This commit is contained in:
AlexBratosin2001 2017-01-11 00:00:06 +02:00
parent 9f331b6a92
commit b633491b91
6 changed files with 367 additions and 294 deletions

View File

@ -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 *));
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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];

View File

@ -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.