// Return TRUE if all was read. FALSE if a problem occured: // If a bitstream syntax problem occured the bitstream will // point to after the problem, in case we run out of data the bitstream // will point to where we want to restart after getting more. static int read_gop_info(struct bitstream *esstream) { dbg_print(DMT_VERBOSE, "Read GOP Info\n"); // We only get here after seeing that start code if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8) fatal(EXIT_BUG_BUG, "Impossible!"); // 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(esstream); //extension_and_user_data(esstream); if (esstream->error) return 0; if (esstream->bitsleft < 0) { init_bitstream(esstream, gop_info_start, esstream->end); return 0; } dbg_print(DMT_VERBOSE, "Read GOP Info - processed\n\n"); return 1; }
// Return TRUE if all was read. FALSE if a problem occured: // If a bitstream syntax problem occured the bitstream will // point to after the problem, in case we run out of data the bitstream // will point to where we want to restart after getting more. static int read_seq_info(struct bitstream *esstream) { dbg_print(DMT_VERBOSE, "Read Sequence Info\n"); // We only get here after seeing that start code if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3) fatal(EXIT_BUG_BUG, "read_seq_info: Impossible!"); // 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(esstream); sequence_ext(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; } dbg_print(DMT_VERBOSE, "Read Sequence Info - processed\n\n"); return 1; }
// Return TRUE if all was read. FALSE if a problem occured: // If a bitstream syntax problem occured the bitstream will // point to after the problem, in case we run out of data the bitstream // will point to where we want to restart after getting more. static int read_gop_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *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, "read_gop_info: next_u32(esstream) != 0xB8010000. Please file a bug report in 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(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 all was read. FALSE if a problem occured: // If a bitstream syntax problem occured the bitstream will // point to after the problem, in case we run out of data the bitstream // will point to where we want to restart after getting more. static int read_seq_info(struct lib_cc_decode *ctx, struct bitstream *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, "read_seq_info: next_u32(esstream) != 0xB3010000. Please file a bug report in 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 the next startcode or sequence_error_code if not enough // data was left in the bitstream. Also set esstream->bitsleft. // The bitstream pointer shall be moved to the begin of the start // code if found, or to the position where a search would continue // would more data be made available. // Only NULL bytes before the start code are discarded, if a non // NULL byte is encountered esstream->error is set to TRUE and the // function returns sequence_error_code with the pointer set after // that byte. static uint8_t next_start_code(struct bitstream *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) { dbg_print(DMT_VERBOSE, "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) { dbg_print(DMT_VERBOSE, "next_start_code: Non zero stuffing\n"); esstream->error = 1; return 0xB4; } } if (esstream->bitsleft < 8) { esstream->bitsleft -= 8; dbg_print(DMT_VERBOSE, "next_start_code: bitsleft <= 0\n"); return 0xB4; } else { dbg_print(DMT_VERBOSE, "next_start_code: Found %02X\n", *(esstream->pos+3)); if ( *(esstream->pos+3) == 0xB4 ) { dbg_print(DMT_VERBOSE, "B4: assume bitstream syntax error!\n"); esstream->error = 1; } return *(esstream->pos+3); } }
// Return TRUE if all was read. FALSE if a problem occured: // If a bitstream syntax problem occured the bitstream will // point to after the problem, in case we run out of data the bitstream // will point to where we want to restart after getting more. static int read_pic_info(struct bitstream *esstream) { dbg_print(DMT_VERBOSE, "Read PIC Info\n"); // We only get here after seeing that start code if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100) fatal(EXIT_BUG_BUG, "Impossible!"); // 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(esstream); pic_coding_ext(esstream); if (esstream->error) return 0; if (esstream->bitsleft < 0) { init_bitstream(esstream, pic_info_start, esstream->end); return 0; } // Analyse/use the picture information static int maxtref; // Use to remember the temporal reference number // A new anchor frame - flush buffered caption data. Might be flushed // in GOP header already. if (picture_coding_type==I_FRAME || picture_coding_type==P_FRAME) { // if (((picture_structure != 0x1) && (picture_structure != 0x2)) || // (temporal_reference != current_tref)) // { // NOTE: process_hdcc() needs to be called before set_fts() as it // uses fts_now to re-create the timeline !!!!! if (has_ccdata_buffered) { process_hdcc(); } anchor_hdcc(temporal_reference); // } } current_tref = temporal_reference; current_picture_coding_type = picture_coding_type; // We mostly use PTS, but when the GOP mode is enabled do not set // the FTS time here. if (!use_gop_as_pts) { set_fts(); // Initialize fts } dbg_print(DMT_VIDES, "PTS: %s (%8u) - tref: %2d - %s since tref0/GOP: %2u/%2u", print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)), unsigned(current_pts), temporal_reference, pict_types[picture_coding_type], unsigned(frames_since_ref_time), unsigned(frames_since_last_gop)); dbg_print(DMT_VIDES, " t:%d r:%d p:%d", top_field_first, repeat_first_field, progressive_frame); dbg_print(DMT_VIDES, " FTS: %s\n", print_mstime(get_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(temporal_reference == 0) { last_gop_length = maxtref + 1; maxtref = temporal_reference; // frames_since_ref_time is used in set_fts() if( 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 = frames_since_last_gop; // Should this be 0? } else { // No GOP header, use the current values fts_at_gop_start=get_fts(); frames_since_ref_time = 0; } if (debug_mask & DMT_TIME) { dbg_print(DMT_TIME, "\nNew temporal reference:\n"); print_debug_timing(); } saw_gop_header = 0; // Reset the value } if ( !saw_gop_header && picture_coding_type==I_FRAME ) { // A new GOP beginns with an I-frame. Lets hope there are // never more than one per GOP frames_since_last_gop = 0; } // Set maxtref if( temporal_reference > maxtref ) { maxtref = temporal_reference; if (maxtref+1 > max_gop_length) max_gop_length = maxtref+1; } unsigned extraframe = 0; if (repeat_first_field) { pulldownfields++; total_pulldownfields++; if ( current_progressive_sequence || !(total_pulldownfields%2) ) extraframe = 1; if ( current_progressive_sequence && top_field_first ) extraframe = 2; dbg_print(DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n", total_pulldownfields, extraframe); } total_pulldownframes += extraframe; total_frames_count += 1+extraframe; frames_since_last_gop += 1+extraframe; frames_since_ref_time += 1+extraframe; dbg_print(DMT_VERBOSE, "Read PIC Info - processed\n\n"); return 1; }
// Return TRUE if all was read. FALSE if a problem occured: // If a bitstream syntax problem occured the bitstream will // point to after the problem, in case we run out of data the bitstream // will point to where we want to restart after getting more. static int read_pic_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *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 in 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(ctx, esstream); pic_coding_ext(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 (ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME || ctx->picture_coding_type==CCX_FRAME_TYPE_P_FRAME) { if (((ctx->picture_structure != 0x1) && (ctx->picture_structure != 0x2)) || (ctx->temporal_reference != 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 (ctx->has_ccdata_buffered) { process_hdcc(ctx, sub); } anchor_hdcc(ctx, ctx->temporal_reference); } } ctx->timing->current_tref = ctx->temporal_reference; ctx->timing->current_picture_coding_type = 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(ctx->timing); // Initialize fts } dbg_print(CCX_DMT_VIDES, " t:%d r:%d p:%d", ctx->top_field_first, ctx->repeat_first_field, ctx->progressive_frame); dbg_print(CCX_DMT_VIDES, " FTS: %s\n", print_mstime_static(get_fts(ctx->timing, ctx->current_field))); // 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(ctx->temporal_reference == 0) { ctx->last_gop_length = ctx->maxtref + 1; ctx->maxtref = ctx->temporal_reference; // frames_since_ref_time is used in set_fts() if( 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 = ctx->frames_since_last_gop; // Should this be 0? } else { // No GOP header, use the current values fts_at_gop_start = get_fts(ctx->timing, 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(ctx->timing); } ctx->saw_gop_header = 0; // Reset the value } if ( !ctx->saw_gop_header && ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME ) { // A new GOP beginns with an I-frame. Lets hope there are // never more than one per GOP ctx->frames_since_last_gop = 0; } // Set maxtref if( ctx->temporal_reference > ctx->maxtref ) { ctx->maxtref = ctx->temporal_reference; if (ctx->maxtref + 1 > ctx->max_gop_length) ctx->max_gop_length = ctx->maxtref + 1; } unsigned extraframe = 0; if (ctx->repeat_first_field) { ctx->pulldownfields++; ctx->total_pulldownfields++; if ( ctx->current_progressive_sequence || !(ctx->total_pulldownfields%2) ) extraframe = 1; if ( ctx->current_progressive_sequence && ctx->top_field_first ) extraframe = 2; dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n", ctx->total_pulldownfields, extraframe); } ctx->total_pulldownframes += extraframe; total_frames_count += 1+extraframe; ctx->frames_since_last_gop += 1+extraframe; frames_since_ref_time += 1+extraframe; debug("Read PIC Info - processed\n\n"); return 1; }