Summary
In src/lib_ccx/ts_tables_epg.c, the last EIT section in any stream is silently
discarded because EPG_free() frees epg_buffers without first flushing
accumulated data.
Root Cause
parse_EPG_packet() accumulates TS packets into epg_buffers[] and only calls
EPG_parse_table() when a new section starts (payload_start_indicator=1).
This means the last accumulated section is never parsed — there is no
following packet to trigger the flush.
EPG_free() then frees the buffers without processing them:
void EPG_free(struct lib_ccx_ctx *ctx)
{
// ... output logic ...
free(ctx->epg_buffers); // ← pending data discarded here!
free(ctx->eit_programs);
}
Impact
- The last EIT table section in every stream is lost
- For short streams or streams with few EIT sections, this can mean entire
programs are missing from XMLTV output
- There is a related
XXX hack comment in EPG_DVB_decode_EIT() at line 1420
that was added to prevent a segfault caused by this same issue
Fix
In EPG_free(), before freeing, iterate over all epg_buffers slots and
flush any with ccounter > 0:
// Flush any pending EIT sections before freeing
for (int i = 0; i <= 0xfff; i++) {
if (ctx->epg_buffers[i].buffer != NULL && ctx->epg_buffers[i].ccounter > 0) {
EPG_parse_table(ctx, ctx->epg_buffers[i].buffer,
ctx->epg_buffers[i].buffer_length);
free(ctx->epg_buffers[i].buffer);
ctx->epg_buffers[i].buffer = NULL;
}
}
Summary
In
src/lib_ccx/ts_tables_epg.c, the last EIT section in any stream is silentlydiscarded because
EPG_free()freesepg_bufferswithout first flushingaccumulated data.
Root Cause
parse_EPG_packet()accumulates TS packets intoepg_buffers[]and only callsEPG_parse_table()when a new section starts (payload_start_indicator=1).This means the last accumulated section is never parsed — there is no
following packet to trigger the flush.
EPG_free()then frees the buffers without processing them:Impact
programs are missing from XMLTV output
XXX hackcomment inEPG_DVB_decode_EIT()at line 1420that was added to prevent a segfault caused by this same issue
Fix
In
EPG_free(), before freeing, iterate over allepg_buffersslots andflush any with
ccounter > 0: