mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2026-09-23 07:14:45 +00:00
Remove unreachable post-return C bodies and their orphaned helpers in es_functions.c (#2327)
This commit is contained in:
committed by
GitHub
parent
2ad84df33e
commit
3875e84351
@@ -7,15 +7,9 @@ static uint8_t search_start_code(struct bitstream *esstream);
|
||||
static uint8_t next_start_code(struct bitstream *esstream);
|
||||
static int es_video_sequence(struct encoder_ctx *enc_ctx, struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int sequence_header(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int read_gop_info(struct encoder_ctx *enc_ctx, struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int gop_header(struct encoder_ctx *enc_ctx, struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int read_pic_info(struct encoder_ctx *enc_ctx, struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub);
|
||||
static int pic_header(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream);
|
||||
static int read_eau_info(struct encoder_ctx *enc_ctx, struct lib_cc_decode *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int extension_and_user_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub);
|
||||
static int read_pic_data(struct bitstream *esstream);
|
||||
|
||||
#define debug(...) ccx_common_logging.debug_ftn(CCX_DMT_VERBOSE, __VA_ARGS__)
|
||||
@@ -60,58 +54,6 @@ size_t process_m2v(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, u
|
||||
static uint8_t search_start_code(struct bitstream *esstream)
|
||||
{
|
||||
return ccxr_search_start_code(esstream);
|
||||
make_byte_aligned(esstream);
|
||||
|
||||
// Keep a negative esstream->bitsleft, but correct it.
|
||||
if (esstream->bitsleft <= 0)
|
||||
{
|
||||
debug("search_start_code: bitsleft <= 0\n");
|
||||
esstream->bitsleft -= 8 * 4;
|
||||
return 0xB4;
|
||||
}
|
||||
|
||||
unsigned char *tstr = esstream->pos;
|
||||
|
||||
// Scan for 0x000001xx in header
|
||||
while (1)
|
||||
{
|
||||
// The loop is exited by break only, and if tstr+3 is less than
|
||||
// esstream->end we found the start code prefix
|
||||
tstr = (unsigned char *)memchr(tstr, 0x00,
|
||||
esstream->end - tstr);
|
||||
if (tstr == NULL)
|
||||
{
|
||||
// We don't even have the starting 0x00
|
||||
tstr = esstream->end;
|
||||
esstream->bitsleft = -8 * 4;
|
||||
break;
|
||||
}
|
||||
else if (tstr + 3 >= esstream->end)
|
||||
{
|
||||
// Not enough bytes left to check for 0x000001??
|
||||
esstream->bitsleft = 8 * (esstream->end - (tstr + 4));
|
||||
break;
|
||||
}
|
||||
else if (tstr[1] == 0x00 && tstr[2] == 0x01)
|
||||
{
|
||||
// Found 0x000001??
|
||||
esstream->bitsleft = 8 * (esstream->end - (tstr + 4));
|
||||
break;
|
||||
}
|
||||
// Keep searching
|
||||
tstr++;
|
||||
}
|
||||
esstream->pos = tstr;
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
debug("search_start_code: bitsleft <= 0\n");
|
||||
return 0xB4;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("search_start_code: Found %02X\n", tstr[3]);
|
||||
return tstr[3];
|
||||
}
|
||||
}
|
||||
|
||||
// Return the next startcode or sequence_error_code if not enough
|
||||
@@ -126,52 +68,6 @@ static uint8_t search_start_code(struct bitstream *esstream)
|
||||
static uint8_t next_start_code(struct bitstream *esstream)
|
||||
{
|
||||
return ccxr_next_start_code(esstream);
|
||||
if (esstream->error || esstream->bitsleft < 0)
|
||||
{
|
||||
return 0xB4;
|
||||
}
|
||||
|
||||
make_byte_aligned(esstream);
|
||||
|
||||
// Only start looking if there is enough data. Adjust bitsleft.
|
||||
if (esstream->bitsleft < 4 * 8)
|
||||
{
|
||||
debug("next_start_code: bitsleft %lld < 32\n", esstream->bitsleft);
|
||||
esstream->bitsleft -= 8 * 4;
|
||||
return 0xB4;
|
||||
}
|
||||
|
||||
uint8_t tmp;
|
||||
while ((next_u32(esstream) & 0x00FFFFFF) != 0x00010000 // LSB 0x000001??
|
||||
&& esstream->bitsleft > 0)
|
||||
{
|
||||
tmp = read_u8(esstream);
|
||||
if (tmp)
|
||||
{
|
||||
debug("next_start_code: Non zero stuffing\n");
|
||||
esstream->error = 1;
|
||||
return 0xB4;
|
||||
}
|
||||
}
|
||||
|
||||
if (esstream->bitsleft < 8)
|
||||
{
|
||||
esstream->bitsleft -= 8;
|
||||
debug("next_start_code: bitsleft <= 0\n");
|
||||
return 0xB4;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("next_start_code: Found %02X\n", *(esstream->pos + 3));
|
||||
|
||||
if (*(esstream->pos + 3) == 0xB4)
|
||||
{
|
||||
debug("B4: assume bitstream syntax error!\n");
|
||||
esstream->error = 1;
|
||||
}
|
||||
|
||||
return *(esstream->pos + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Return TRUE if the video sequence was finished, FALSE
|
||||
@@ -339,176 +235,14 @@ static int es_video_sequence(struct encoder_ctx *enc_ctx, struct lib_cc_decode *
|
||||
static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
return ccxr_read_seq_info(ctx, esstream);
|
||||
debug("Read Sequence Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In read_seq_info: next_u32(esstream) != 0xB3010000. Please file a bug report on GitHub.\n");
|
||||
|
||||
// If we get here esstream points to the start of a sequence_header_code
|
||||
// should we run out of data in esstream this is where we want to restart
|
||||
// after getting more.
|
||||
unsigned char *video_seq_start = esstream->pos;
|
||||
|
||||
sequence_header(ctx, esstream);
|
||||
sequence_ext(ctx, esstream);
|
||||
// FIXME: if sequence extension is missing this is not MPEG-2,
|
||||
// or broken. Set bitstream error.
|
||||
// extension_and_user_data(esstream);
|
||||
|
||||
if (esstream->error)
|
||||
return 0;
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
init_bitstream(esstream, video_seq_start, esstream->end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Read Sequence Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int sequence_header(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
debug("Sequence header\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (read_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In sequence_header: read_u32(esstream) != 0xB3010000. Please file a bug report on GitHub.\n");
|
||||
|
||||
unsigned hor_size = (unsigned)read_bits(esstream, 12);
|
||||
unsigned vert_size = (unsigned)read_bits(esstream, 12);
|
||||
unsigned aspect_ratio = (unsigned)read_bits(esstream, 4);
|
||||
unsigned frame_rate = (unsigned)read_bits(esstream, 4);
|
||||
|
||||
#if 0
|
||||
ctx->freport.width = hor_size;
|
||||
ctx->freport.height = vert_size;
|
||||
ctx->freport.aspect_ratio = aspect_ratio;
|
||||
ctx->freport.frame_rate = frame_rate;
|
||||
#endif
|
||||
|
||||
// Discard some information
|
||||
read_bits(esstream, 18 + 1 + 10 + 1);
|
||||
|
||||
// load_intra_quantiser_matrix
|
||||
if (read_bits(esstream, 1))
|
||||
skip_bits(esstream, 8 * 64);
|
||||
// load_non_intra_quantiser_matrix
|
||||
if (read_bits(esstream, 1))
|
||||
skip_bits(esstream, 8 * 64);
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// If we got the whole sequence, process
|
||||
if (hor_size != ctx->current_hor_size ||
|
||||
vert_size != ctx->current_vert_size ||
|
||||
aspect_ratio != ctx->current_aspect_ratio ||
|
||||
frame_rate != ctx->current_frame_rate)
|
||||
{
|
||||
// If horizontal/vertical size, framerate and/or aspect
|
||||
// ratio are illegal, we discard the
|
||||
// whole sequence info.
|
||||
if (vert_size >= 288 && vert_size <= 1088 &&
|
||||
hor_size >= 352 && hor_size <= 1920 &&
|
||||
(hor_size * 100) / vert_size >= (352 * 100) / 576 && // The weird *100 is to avoid using floats
|
||||
hor_size / vert_size <= 2 &&
|
||||
frame_rate > 0 && frame_rate < 9 &&
|
||||
aspect_ratio > 0 && aspect_ratio < 5)
|
||||
{
|
||||
mprint("\n\nNew video information found");
|
||||
mprint("\n");
|
||||
mprint("[%u * %u] [AR: %s] [FR: %s]",
|
||||
hor_size, vert_size,
|
||||
aspect_ratio_types[aspect_ratio],
|
||||
framerates_types[frame_rate]);
|
||||
// No newline, force the output of progressive info in picture
|
||||
// info part.
|
||||
ctx->current_progressive_sequence = 2;
|
||||
|
||||
ctx->current_hor_size = hor_size;
|
||||
ctx->current_vert_size = vert_size;
|
||||
ctx->current_aspect_ratio = aspect_ratio;
|
||||
ctx->current_frame_rate = frame_rate;
|
||||
current_fps = framerates_values[ctx->current_frame_rate];
|
||||
activity_video_info(hor_size, vert_size,
|
||||
aspect_ratio_types[aspect_ratio],
|
||||
framerates_types[frame_rate]);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("\nInvalid sequence header:\n");
|
||||
debug("V: %u H: %u FR: %u AS: %u\n",
|
||||
vert_size, hor_size, frame_rate, aspect_ratio);
|
||||
esstream->error = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
debug("Sequence extension\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
|
||||
// Syntax check
|
||||
if (next_start_code(esstream) != 0xB5)
|
||||
{
|
||||
debug("sequence_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
skip_u32(esstream); // Advance
|
||||
|
||||
// Read extension_start_code_identifier
|
||||
unsigned extension_id = (unsigned)read_bits(esstream, 4);
|
||||
if (extension_id != 0x1) // Sequence Extension ID
|
||||
{
|
||||
if (esstream->bitsleft >= 0) // When bits left, this is wrong
|
||||
esstream->error = 1;
|
||||
|
||||
if (esstream->error)
|
||||
debug("sequence_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Discard some information
|
||||
skip_bits(esstream, 8);
|
||||
unsigned progressive_sequence = (unsigned)read_bits(esstream, 1);
|
||||
|
||||
if (progressive_sequence != ctx->current_progressive_sequence)
|
||||
{
|
||||
ctx->current_progressive_sequence = progressive_sequence;
|
||||
mprint(" [progressive: %s]\n\n",
|
||||
(progressive_sequence ? "yes" : "no"));
|
||||
}
|
||||
|
||||
skip_bits(esstream, 2 + 2 + 2 + 12 + 1 + 8 + 1 + 2 + 5);
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if all was read. FALSE if a problem occurred:
|
||||
// If a bitstream syntax problem occurred the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
@@ -516,163 +250,11 @@ static int sequence_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
static int read_gop_info(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
return ccxr_read_gop_info(enc_ctx, dec_ctx, esstream, sub);
|
||||
debug("Read GOP Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In read_gop_info: next_u32(esstream) != 0xB8010000. Please file a bug report on GitHub.\n");
|
||||
|
||||
// If we get here esstream points to the start of a group_start_code
|
||||
// should we run out of data in esstream this is where we want to restart
|
||||
// after getting more.
|
||||
unsigned char *gop_info_start = esstream->pos;
|
||||
|
||||
gop_header(enc_ctx, dec_ctx, esstream, sub);
|
||||
// extension_and_user_data(esstream);
|
||||
|
||||
if (esstream->error)
|
||||
return 0;
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
init_bitstream(esstream, gop_info_start, esstream->end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Read GOP Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int gop_header(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
debug("GOP header\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (read_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In gop_header: read_u32(esstream) != 0xB8010000. Please file a bug report on GitHub.\n");
|
||||
|
||||
unsigned drop_frame_flag = (unsigned)read_bits(esstream, 1);
|
||||
struct gop_time_code gtc;
|
||||
gtc.time_code_hours = (int)read_bits(esstream, 5);
|
||||
gtc.time_code_minutes = (int)read_bits(esstream, 6);
|
||||
skip_bits(esstream, 1); // Marker bit
|
||||
gtc.time_code_seconds = (int)read_bits(esstream, 6);
|
||||
gtc.time_code_pictures = (int)read_bits(esstream, 6);
|
||||
gtc.inited = 1;
|
||||
calculate_ms_gop_time(>c);
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
if (gop_accepted(>c))
|
||||
{
|
||||
// Do GOP padding during GOP header. The previous GOP and all
|
||||
// included captions are written. Use the current GOP time to
|
||||
// do the padding.
|
||||
|
||||
// Flush buffered cc blocks before doing the housekeeping
|
||||
if (dec_ctx->has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(enc_ctx, dec_ctx, sub);
|
||||
}
|
||||
|
||||
// Last GOPs pulldown frames
|
||||
if ((dec_ctx->current_pulldownfields > 0) != (dec_ctx->pulldownfields > 0))
|
||||
{
|
||||
dec_ctx->current_pulldownfields = dec_ctx->pulldownfields;
|
||||
debug("Pulldown: %s", (dec_ctx->pulldownfields ? "on" : "off"));
|
||||
if (dec_ctx->pulldownfields)
|
||||
debug(" - %u fields in last GOP", dec_ctx->pulldownfields);
|
||||
debug("\n");
|
||||
}
|
||||
dec_ctx->pulldownfields = 0;
|
||||
|
||||
// Report synchronization jumps between GOPs. Warn if there
|
||||
// are 20% or more deviation.
|
||||
if ((ccx_options.debug_mask & CCX_DMT_TIME) && ((gtc.ms - gop_time.ms // more than 20% longer
|
||||
> dec_ctx->frames_since_last_gop * 1000.0 / current_fps * 1.2) ||
|
||||
(gtc.ms - gop_time.ms // or 20% shorter
|
||||
< dec_ctx->frames_since_last_gop * 1000.0 / current_fps * 0.8)) &&
|
||||
first_gop_time.inited)
|
||||
{
|
||||
mprint("\rWarning: Jump in GOP timing.\n");
|
||||
mprint(" (old) %s",
|
||||
print_mstime_static(gop_time.ms));
|
||||
mprint(" + %s (%uF)",
|
||||
print_mstime_static((LLONG)(dec_ctx->frames_since_last_gop * 1000.0 / current_fps)),
|
||||
dec_ctx->frames_since_last_gop);
|
||||
mprint(" != (new) %s\n",
|
||||
print_mstime_static(gtc.ms));
|
||||
}
|
||||
|
||||
if (first_gop_time.inited == 0)
|
||||
{
|
||||
first_gop_time = gtc;
|
||||
|
||||
// It needs to be "+1" because the frame count starts at 0 and we
|
||||
// need the length of all frames.
|
||||
if (total_frames_count == 0)
|
||||
{ // If this is the first frame there cannot be an offset
|
||||
dec_ctx->timing->fts_fc_offset = 0;
|
||||
// first_gop_time.ms stays unchanged
|
||||
}
|
||||
else
|
||||
{
|
||||
dec_ctx->timing->fts_fc_offset = (LLONG)((total_frames_count + 1) * 1000.0 / current_fps);
|
||||
// Compensate for those written before
|
||||
first_gop_time.ms -= dec_ctx->timing->fts_fc_offset;
|
||||
}
|
||||
|
||||
dbg_print(CCX_DMT_TIME, "\nFirst GOP time: %02u:%02u:%02u:%03u %+lldms\n",
|
||||
gtc.time_code_hours,
|
||||
gtc.time_code_minutes, gtc.time_code_seconds,
|
||||
(unsigned)(1000.0 * gtc.time_code_pictures / current_fps),
|
||||
dec_ctx->timing->fts_fc_offset);
|
||||
}
|
||||
|
||||
gop_time = gtc;
|
||||
|
||||
dec_ctx->frames_since_last_gop = 0;
|
||||
// Indicate that we read a gop header (since last frame number 0)
|
||||
dec_ctx->saw_gop_header = 1;
|
||||
|
||||
// If we use GOP timing, reconstruct the PTS from the GOP
|
||||
if (ccx_options.use_gop_as_pts == 1)
|
||||
{
|
||||
set_current_pts(dec_ctx->timing, gtc.ms * (MPEG_CLOCK_FREQ / 1000));
|
||||
dec_ctx->timing->current_tref = 0;
|
||||
frames_since_ref_time = 0;
|
||||
set_fts(dec_ctx->timing);
|
||||
fts_at_gop_start = get_fts_max(dec_ctx->timing);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Wrong when PTS are not increasing but are identical
|
||||
// throughout the GOP and then jump to the next time for the
|
||||
// next GOP.
|
||||
// This effect will also lead to captions being one GOP early
|
||||
// for DVD captions.
|
||||
fts_at_gop_start = get_fts_max(dec_ctx->timing) + (LLONG)(1000.0 / current_fps);
|
||||
}
|
||||
|
||||
if (ccx_options.debug_mask & CCX_DMT_TIME)
|
||||
{
|
||||
dbg_print(CCX_DMT_TIME, "\nNew GOP:\n");
|
||||
dbg_print(CCX_DMT_TIME, "\nDrop frame flag: %u:\n", drop_frame_flag);
|
||||
print_debug_timing(dec_ctx->timing);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if all was read. FALSE if a problem occurred:
|
||||
// If a bitstream syntax problem occurred the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
@@ -680,236 +262,14 @@ static int gop_header(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx
|
||||
static int read_pic_info(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct bitstream *esstream, struct cc_subtitle *sub)
|
||||
{
|
||||
return ccxr_read_pic_info(enc_ctx, dec_ctx, esstream, sub);
|
||||
debug("Read PIC Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In read_pic_info: next_u32(esstream) != 0x00010000. Please file a bug report on GitHub.\n");
|
||||
|
||||
// If we get here esstream points to the start of a group_start_code
|
||||
// should we run out of data in esstream this is where we want to restart
|
||||
// after getting more.
|
||||
unsigned char *pic_info_start = esstream->pos;
|
||||
|
||||
pic_header(dec_ctx, esstream);
|
||||
pic_coding_ext(dec_ctx, esstream);
|
||||
|
||||
if (esstream->error)
|
||||
return 0;
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
init_bitstream(esstream, pic_info_start, esstream->end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// A new anchor frame - flush buffered caption data. Might be flushed
|
||||
// in GOP header already.
|
||||
if (dec_ctx->picture_coding_type == CCX_FRAME_TYPE_I_FRAME || dec_ctx->picture_coding_type == CCX_FRAME_TYPE_P_FRAME)
|
||||
{
|
||||
if (((dec_ctx->picture_structure != 0x1) && (dec_ctx->picture_structure != 0x2)) ||
|
||||
(dec_ctx->temporal_reference != dec_ctx->timing->current_tref))
|
||||
{
|
||||
// NOTE: process_hdcc() needs to be called before set_fts() as it
|
||||
// uses fts_now to re-create the timeline !!!!!
|
||||
if (dec_ctx->has_ccdata_buffered)
|
||||
{
|
||||
process_hdcc(enc_ctx, dec_ctx, sub);
|
||||
}
|
||||
anchor_hdcc(dec_ctx, dec_ctx->temporal_reference);
|
||||
}
|
||||
}
|
||||
|
||||
dec_ctx->timing->current_tref = dec_ctx->temporal_reference;
|
||||
dec_ctx->timing->current_picture_coding_type = dec_ctx->picture_coding_type;
|
||||
|
||||
// We mostly use PTS, but when the GOP mode is enabled do not set
|
||||
// the FTS time here.
|
||||
if (ccx_options.use_gop_as_pts != 1)
|
||||
{
|
||||
set_fts(dec_ctx->timing); // Initialize fts
|
||||
}
|
||||
|
||||
// Set min_pts/sync_pts according to the current time stamp.
|
||||
// Use fts_at_gop_start as reference when a GOP header was seen
|
||||
// since the last frame 0. If not this is most probably a
|
||||
// TS without GOP headers but with USER DATA after each picture
|
||||
// header. Use the current FTS values as reference.
|
||||
// Note: If a GOP header was present the reference time is from
|
||||
// the beginning of the GOP, otherwise it is now.
|
||||
if (dec_ctx->temporal_reference == 0)
|
||||
{
|
||||
dec_ctx->last_gop_length = dec_ctx->maxtref + 1;
|
||||
dec_ctx->maxtref = dec_ctx->temporal_reference;
|
||||
|
||||
// frames_since_ref_time is used in set_fts()
|
||||
|
||||
if (dec_ctx->saw_gop_header)
|
||||
{
|
||||
// This time (fts_at_gop_start) that was set in the
|
||||
// GOP header and it might be off by one GOP. See the comment there.
|
||||
frames_since_ref_time = dec_ctx->frames_since_last_gop; // Should this be 0?
|
||||
}
|
||||
else
|
||||
{
|
||||
// No GOP header, use the current values
|
||||
fts_at_gop_start = get_fts(dec_ctx->timing, dec_ctx->current_field);
|
||||
frames_since_ref_time = 0;
|
||||
}
|
||||
|
||||
if (ccx_options.debug_mask & CCX_DMT_TIME)
|
||||
{
|
||||
dbg_print(CCX_DMT_TIME, "\nNew temporal reference:\n");
|
||||
print_debug_timing(dec_ctx->timing);
|
||||
}
|
||||
|
||||
dec_ctx->saw_gop_header = 0; // Reset the value
|
||||
}
|
||||
|
||||
if (!dec_ctx->saw_gop_header && dec_ctx->picture_coding_type == CCX_FRAME_TYPE_I_FRAME)
|
||||
{
|
||||
// A new GOP begins with an I-frame. Lets hope there are
|
||||
// never more than one per GOP
|
||||
dec_ctx->frames_since_last_gop = 0;
|
||||
}
|
||||
|
||||
// Set maxtref
|
||||
if (dec_ctx->temporal_reference > dec_ctx->maxtref)
|
||||
{
|
||||
dec_ctx->maxtref = dec_ctx->temporal_reference;
|
||||
if (dec_ctx->maxtref + 1 > dec_ctx->max_gop_length)
|
||||
dec_ctx->max_gop_length = dec_ctx->maxtref + 1;
|
||||
}
|
||||
|
||||
unsigned extraframe = 0;
|
||||
if (dec_ctx->repeat_first_field)
|
||||
{
|
||||
dec_ctx->pulldownfields++;
|
||||
dec_ctx->total_pulldownfields++;
|
||||
if (dec_ctx->current_progressive_sequence || !(dec_ctx->total_pulldownfields % 2))
|
||||
extraframe = 1;
|
||||
if (dec_ctx->current_progressive_sequence && dec_ctx->top_field_first)
|
||||
extraframe = 2;
|
||||
dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
|
||||
dec_ctx->total_pulldownfields, extraframe);
|
||||
}
|
||||
|
||||
dec_ctx->total_pulldownframes += extraframe;
|
||||
total_frames_count += 1 + extraframe;
|
||||
dec_ctx->frames_since_last_gop += 1 + extraframe;
|
||||
frames_since_ref_time += 1 + extraframe;
|
||||
|
||||
debug("Read PIC Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int pic_header(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
debug("PIC header\n");
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (read_u32(esstream) != 0x00010000) // LSB first (0x00000100)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In pic_header: read_u32(esstream) != 0x00010000. Please file a bug report on GitHub.\n");
|
||||
|
||||
ctx->temporal_reference = (int)read_bits(esstream, 10);
|
||||
ctx->picture_coding_type = (enum ccx_frame_type)read_bits(esstream, 3);
|
||||
|
||||
if (ctx->picture_coding_type == 1) // Write I-Frame in ffprobe format for easy comparison
|
||||
{
|
||||
ctx->num_key_frames++;
|
||||
dbg_print(CCX_DMT_VIDES, "key_frame=1|pkt_pts=%lld|pict_type=I\n", ctx->timing->current_pts);
|
||||
}
|
||||
|
||||
// Discard vbv_delay
|
||||
skip_bits(esstream, 16);
|
||||
|
||||
// Discard some information
|
||||
if (ctx->picture_coding_type == 2 || ctx->picture_coding_type == 3)
|
||||
skip_bits(esstream, 4);
|
||||
if (ctx->picture_coding_type == 3)
|
||||
skip_bits(esstream, 4);
|
||||
|
||||
// extra_information
|
||||
while (read_bits(esstream, 1) == 1)
|
||||
{
|
||||
skip_bits(esstream, 8);
|
||||
}
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
if (!(ctx->picture_coding_type == CCX_FRAME_TYPE_I_FRAME || ctx->picture_coding_type == CCX_FRAME_TYPE_P_FRAME || ctx->picture_coding_type == CCX_FRAME_TYPE_B_FRAME))
|
||||
{
|
||||
if (esstream->bitsleft >= 0) // When bits left, this is wrong
|
||||
esstream->error = 1;
|
||||
|
||||
if (esstream->error)
|
||||
debug("pic_header: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
{
|
||||
debug("Picture coding extension %lld\n", esstream->bitsleft);
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
|
||||
// Syntax check
|
||||
if (next_start_code(esstream) != 0xB5)
|
||||
{
|
||||
debug("pic_coding_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
skip_u32(esstream); // Advance
|
||||
|
||||
// Read extension_start_code_identifier
|
||||
unsigned extension_id = (unsigned int)read_bits(esstream, 4);
|
||||
if (extension_id != 0x8) // Picture Coding Extension ID
|
||||
{
|
||||
if (esstream->bitsleft >= 0) // When bits left, this is wrong
|
||||
esstream->error = 1;
|
||||
|
||||
if (esstream->error)
|
||||
debug("pic_coding_ext: syntax problem.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Discard some information
|
||||
skip_bits(esstream, 4 * 4 + 2);
|
||||
ctx->picture_structure = (unsigned int)read_bits(esstream, 2);
|
||||
ctx->top_field_first = (unsigned int)read_bits(esstream, 1);
|
||||
skip_bits(esstream, 5 * 1);
|
||||
ctx->repeat_first_field = (unsigned int)read_bits(esstream, 1);
|
||||
skip_bits(esstream, 1); // chroma
|
||||
ctx->progressive_frame = (unsigned int)read_bits(esstream, 1);
|
||||
unsigned composite_display = (unsigned int)read_bits(esstream, 1);
|
||||
if (composite_display)
|
||||
skip_bits(esstream, 1 + 3 + 1 + 7 + 8);
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
return 0;
|
||||
|
||||
debug("Picture coding extension - processed\n");
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if all was read. FALSE if a problem occurred:
|
||||
// If a bitstream syntax problem occurred the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
@@ -917,121 +277,11 @@ static int pic_coding_ext(struct lib_cc_decode *ctx, struct bitstream *esstream)
|
||||
static int read_eau_info(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
return ccxr_read_eau_info(enc_ctx, dec_ctx, esstream, udtype, sub);
|
||||
debug("Read Extension and User Info\n");
|
||||
|
||||
// We only get here after seeing that start code
|
||||
unsigned char *tst = next_bytes(esstream, 4);
|
||||
if (!tst || tst[0] != 0x00 || tst[1] != 0x00 || tst[2] != 0x01 || (tst[3] != 0xB2 && tst[3] != 0xB5)) // (0x000001 B2||B5)
|
||||
fatal(CCX_COMMON_EXIT_BUG_BUG, "In read_eau_info: Impossible values for tst. Please file a bug report on GitHub.\n");
|
||||
|
||||
// The following extension_and_user_data() function makes sure that
|
||||
// user data is not evaluated twice. Should the function run out of
|
||||
// data it will make sure that esstream points to where we want to
|
||||
// continue after getting more.
|
||||
if (!extension_and_user_data(enc_ctx, dec_ctx, esstream, udtype, sub))
|
||||
{
|
||||
if (esstream->error)
|
||||
debug("\nWarning: Retry while reading Extension and User Data!\n");
|
||||
else
|
||||
debug("\nBitstream problem while reading Extension and User Data!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Read Extension and User Info - processed\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if the data parsing finished, FALSE otherwise.
|
||||
// estream->pos is advanced. Data is only processed if esstream->error
|
||||
// is FALSE, parsing can set esstream->error to TRUE.
|
||||
static int extension_and_user_data(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, struct bitstream *esstream, int udtype, struct cc_subtitle *sub)
|
||||
{
|
||||
debug("Extension and user data(%d)\n", udtype);
|
||||
|
||||
if (esstream->error || esstream->bitsleft <= 0)
|
||||
return 0;
|
||||
|
||||
// Remember where to continue
|
||||
unsigned char *eau_start = esstream->pos;
|
||||
|
||||
uint8_t startcode;
|
||||
|
||||
do
|
||||
{
|
||||
startcode = next_start_code(esstream);
|
||||
|
||||
if (startcode == 0xB2 || startcode == 0xB5)
|
||||
{
|
||||
skip_u32(esstream); // Advance bitstream
|
||||
unsigned char *dstart = esstream->pos;
|
||||
|
||||
// Advance esstream to the next startcode. Verify that
|
||||
// the whole extension was available and discard blocks
|
||||
// followed by PACK headers. The latter usually indicates
|
||||
// a PS treated as an ES.
|
||||
uint8_t nextstartcode = search_start_code(esstream);
|
||||
if (nextstartcode == 0xBA)
|
||||
{
|
||||
mprint("\nFound PACK header in ES data. Probably wrong stream mode!\n");
|
||||
esstream->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (esstream->error)
|
||||
{
|
||||
debug("Extension and user data - syntax problem\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
debug("Extension and user data - incomplete\n");
|
||||
// Restore to where we need to continue
|
||||
init_bitstream(esstream, eau_start, esstream->end);
|
||||
esstream->bitsleft = -1; // Redundant
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (startcode == 0xB2)
|
||||
{
|
||||
struct bitstream ustream;
|
||||
init_bitstream(&ustream, dstart, esstream->pos);
|
||||
user_data(enc_ctx, dec_ctx, &ustream, udtype, sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Skip %d bytes extension data.\n",
|
||||
esstream->pos - dstart);
|
||||
}
|
||||
// If we get here esstream points to the end of a block
|
||||
// of extension or user data. Should we run out of data in
|
||||
// this loop this is where we want to restart after getting more.
|
||||
eau_start = esstream->pos;
|
||||
}
|
||||
} while (startcode == 0xB2 || startcode == 0xB5);
|
||||
|
||||
if (esstream->error)
|
||||
{
|
||||
debug("Extension and user data - syntax problem\n");
|
||||
return 0;
|
||||
}
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
debug("Extension and user data - incomplete\n");
|
||||
// Restore to where we need to continue
|
||||
init_bitstream(esstream, eau_start, esstream->end);
|
||||
esstream->bitsleft = -1; // Redundant
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Extension and user data - processed\n");
|
||||
|
||||
// Read complete
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return TRUE if all was read. FALSE if a problem occurred:
|
||||
// If a bitstream syntax problem occurred the bitstream will
|
||||
// point to after the problem, in case we run out of data the bitstream
|
||||
@@ -1039,60 +289,4 @@ static int extension_and_user_data(struct encoder_ctx *enc_ctx, struct lib_cc_de
|
||||
static int read_pic_data(struct bitstream *esstream)
|
||||
{
|
||||
return ccxr_read_pic_data(esstream);
|
||||
debug("Read PIC Data\n");
|
||||
|
||||
uint8_t startcode = next_start_code(esstream);
|
||||
|
||||
// Possibly the last call to this function ended with the last
|
||||
// bit of the slice? I.e. in_pic_data is still true, but we are
|
||||
// seeing the next start code.
|
||||
|
||||
// We only get here after seeing that start code
|
||||
if (startcode < 0x01 || startcode > 0xAF)
|
||||
{
|
||||
debug("Read Pic Data - processed0\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we get here esstream points to the start of a slice_start_code
|
||||
// should we run out of data in esstream this is where we want to restart
|
||||
// after getting more.
|
||||
unsigned char *slice_start = esstream->pos;
|
||||
|
||||
do
|
||||
{
|
||||
startcode = next_start_code(esstream);
|
||||
// Syntax check
|
||||
if (startcode == 0xB4)
|
||||
{
|
||||
if (esstream->bitsleft < 0)
|
||||
init_bitstream(esstream, slice_start, esstream->end);
|
||||
|
||||
if (esstream->error)
|
||||
debug("read_pic_data: syntax problem.\n");
|
||||
else
|
||||
debug("read_pic_data: reached end of bitstream.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
slice_start = esstream->pos; // No need to come back
|
||||
|
||||
if (startcode >= 0x01 && startcode <= 0xAF)
|
||||
{
|
||||
skip_u32(esstream); // Advance bitstream
|
||||
search_start_code(esstream); // Skip this slice
|
||||
}
|
||||
} while (startcode >= 0x01 && startcode <= 0xAF);
|
||||
|
||||
if (esstream->bitsleft < 0)
|
||||
{
|
||||
init_bitstream(esstream, slice_start, esstream->end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Read Pic Data - processed\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user