// 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_data(struct bitstream *esstream) { dbg_print(DMT_VERBOSE, "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) { dbg_print(DMT_VERBOSE, "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 ) dbg_print(DMT_VERBOSE, "read_pic_data: syntax problem.\n"); else dbg_print(DMT_VERBOSE, "read_pic_data: reached end of bitstream.\n"); return 0; } slice_start = esstream->pos; // No need to come back if ( startcode >= 0x01 && startcode <= 0xAF ) { read_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; } dbg_print(DMT_VERBOSE, "Read Pic Data - processed\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 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; }
/*! * \param *media: A pointer to a MediaFile_t structure, containing every informations available about the current media file. * \param tid: Track ID. * \return A pointer to the newlee allocated DecodingContext. * * Initialize the DecodingContext and it's bitstream (with a MediaFile_t passed in parameters), * then NAL Unit structure, then init all pointer's (sps, pps, sei) to NULL. */ DecodingContext_t *initDecodingContext(MediaFile_t *media, unsigned tid) { TRACE_INFO(H264, BLD_GREEN "initDecodingContext()" CLR_RESET); DecodingContext_t *dc = NULL; if (media != NULL && tid < media->tracks_video_count && media->tracks_video[tid] != NULL) { // DecodingContext allocation dc = (DecodingContext_t*)calloc(1, sizeof(DecodingContext_t)); if (dc == NULL) { TRACE_ERROR(H264, "Unable to alloc new DecodingContext!"); } else { // Select media and track dc->MediaFile = media; dc->VideoStream = media->tracks_video[tid]; dc->active_tid = tid; // Init some quantization parameters computeNormAdjust(dc); // Init input bitstream dc->bitstr = init_bitstream(media, media->tracks_video[tid]); if (dc->bitstr == NULL) { free(dc); dc = NULL; } else { // Init NAL Unit dc->active_nalu = initNALU(); if (dc->active_nalu == NULL) { free(dc->bitstr); dc->bitstr = NULL; free(dc); dc = NULL; } } } } // Return the DecodingContext return dc; }
/* Process a mpeg-2 data stream with "lenght" bytes in buffer "data". * The number of processed bytes is returned. * Defined in ISO/IEC 13818-2 6.2 */ LLONG process_m2v (unsigned char *data, LLONG length) { if (length<8) // Need to look ahead 8 bytes return length; // Init bitstream struct bitstream esstream; init_bitstream(&esstream, data, data+length); // Process data. The return value is ignored as esstream.pos holds // the information how far the parsing progressed. es_video_sequence(&esstream); // This returns how many bytes were processed and can therefore // be discarded from "buffer". "esstream.pos" points to the next byte // where processing will continue. return (LLONG) (esstream.pos - data); }
// 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 bitstream *esstream, int udtype) { dbg_print(DMT_VERBOSE, "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 ) { read_u32(esstream); // Advance bitstream unsigned char *dstart = esstream->pos; // Advanve 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) { dbg_print(DMT_VERBOSE, "Extension and user data - syntax problem\n"); return 0; } if (esstream->bitsleft < 0) { dbg_print(DMT_VERBOSE, "Extension and user data - inclomplete\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(&ustream, udtype); } else { dbg_print(DMT_VERBOSE, "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) { dbg_print(DMT_VERBOSE, "Extension and user data - syntax problem\n"); return 0; } if (esstream->bitsleft < 0) { dbg_print(DMT_VERBOSE, "Extension and user data - inclomplete\n"); // Restore to where we need to continue init_bitstream(esstream, eau_start, esstream->end); esstream->bitsleft = -1; // Redundant return 0; } dbg_print(DMT_VERBOSE, "Extension and user data - processed\n"); // Read complete 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 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; }
/*! * \brief Parse a mp4 file. * \param *video A pointer to a VideoFile_t structure. * \return retcode 1 if succeed, 0 otherwise. * * This parser is based on the 'ISO/IEC 13818-1' international standard, part 1: * 'Transmission multiplexing and synchronization'. */ int ps_fileParse(VideoFile_t *video) { TRACE_INFO(MPS, BLD_GREEN "ps_fileParse()\n" CLR_RESET); int retcode = SUCCESS; int sid = 0; // Init bitstream to parse container infos Bitstream_t *bitstr = init_bitstream(video, NULL); if (bitstr != NULL) { // Init bitstream_map to store container infos retcode = init_bitstream_map(&video->tracks_audio[0], 999999); retcode = init_bitstream_map(&video->tracks_video[0], 999999); if (retcode == SUCCESS) { video->tracks_audio[0]->stream_type = stream_AUDIO; video->tracks_audio[0]->stream_level = stream_level_PES; video->tracks_audio[0]->stream_codec = CODEC_MPEG_L3; video->tracks_audio[0]->sample_alignment = false; video->tracks_video[0]->stream_type = stream_VIDEO; video->tracks_video[0]->stream_level = stream_level_PES; video->tracks_video[0]->stream_codec = CODEC_MPEG12; video->tracks_video[0]->sample_alignment = false; // Read bitstream while (retcode == SUCCESS && (bitstream_get_absolute_byte_offset(bitstr) + 4) < video->file_size && next_bits(bitstr, 32) != PES_PROGRAM_END) { PackHeader_t pack_header; SystemHeader_t system_header; if (read_bits(bitstr, 32) == PES_PACK_HEADER) { // Parse pack & system header retcode = parse_pack_header(bitstr, &pack_header, &system_header); // Then loop on PES while (retcode == SUCCESS && (bitstream_get_absolute_byte_offset(bitstr) + 4) < video->file_size && next_bits(bitstr, 32) != PES_PACK_HEADER && next_bits(bitstr, 32) != PES_PROGRAM_END) { // Init PesPacket_t pes_packet; ProgramStreamMap_t pes_streammap; ProgramStreamDirectory_t pes_streamdirectory; // Parse start code pes_packet.packet_start_offset = bitstream_get_absolute_byte_offset(bitstr); pes_packet.packet_start_code = read_bits(bitstr, 24); pes_packet.stream_id = (uint8_t)read_bits(bitstr, 8); if (pes_packet.packet_start_code == PES_PACKETSTARTCODE) { switch (pes_packet.stream_id) { case SID_PROGRAM_STREAM_MAP: retcode = parse_program_stream_map(bitstr, &pes_streammap); break; case SID_PROGRAM_STREAM_DIRECTORY: retcode = parse_program_stream_directory(bitstr, &pes_streamdirectory); break; case SID_PADDING: retcode = parse_pes_padding(bitstr, &pes_packet); break; case SID_PRIVATE_STREAM_1: TRACE_2(MPS, BLD_GREEN "Private Stream 1 PES" CLR_RESET " @ %i\n", pes_packet.packet_start_offset); retcode = skip_pes(bitstr, &pes_packet); break; case SID_PRIVATE_STREAM_2: TRACE_2(MPS, BLD_GREEN "Private Stream 2 PES" CLR_RESET " @ %i\n", pes_packet.packet_start_offset); retcode = skip_pes(bitstr, &pes_packet); break; case SID_VIDEO: TRACE_INFO(MPS, BLD_GREEN "parse_pes_video()" CLR_RESET " @ %i\n", pes_packet.packet_start_offset); retcode = parse_pes(bitstr, &pes_packet); //print_pes(&pes_packet); // Set sample into the bitstream_map video->tracks_video[0]->sample_count++; sid = video->tracks_video[0]->sample_count; if (sid < 999999) { video->tracks_video[0]->sample_type[sid] = sample_VIDEO; video->tracks_video[0]->sample_size[sid] = pes_packet.PES_packet_length + 6; video->tracks_video[0]->sample_offset[sid] = pes_packet.packet_start_offset; video->tracks_video[0]->sample_pts[sid] = pes_packet.PTS; video->tracks_video[0]->sample_dts[sid] = pes_packet.DTS; } break; case SID_AUDIO: TRACE_INFO(MPS, BLD_GREEN "parse_pes_audio()" CLR_RESET " @ %i\n", pes_packet.packet_start_offset); retcode = parse_pes(bitstr, &pes_packet); //print_pes(&pes_packet); // Set sample into the bitstream_map video->tracks_audio[0]->sample_count++; sid = video->tracks_audio[0]->sample_count; if (sid < 999999) { video->tracks_audio[0]->sample_type[sid] = sample_AUDIO; video->tracks_audio[0]->sample_size[sid] = pes_packet.PES_packet_length + 6; video->tracks_audio[0]->sample_offset[sid] = pes_packet.packet_start_offset; video->tracks_audio[0]->sample_pts[sid] = pes_packet.PTS; video->tracks_audio[0]->sample_dts[sid] = pes_packet.DTS; } break; default: TRACE_WARNING(MPS, "Unknown PES type (0x%06X%02X) @ %i\n", pes_packet.packet_start_code, pes_packet.stream_id, pes_packet.packet_start_offset); retcode = skip_pes(bitstr, &pes_packet); break; } } else { TRACE_ERROR(MPS, "No valid packet_start_code at %i\n", pes_packet.packet_start_offset); retcode = FAILURE; } } } else { TRACE_ERROR(MPS, "No pack header\n"); retcode = FAILURE; } } } // Free bitstream free_bitstream(&bitstr); } return retcode; }
/*! * \brief Free decoding context. * \param *video A pointer to a VideoFile_t structure, containing every informations available about the current video file. * \return A pointer to the newlee allocated DecodingContext. * * Initialize the DecodingContext and it's bitstream (with a VideoFile_t passed in parameters), * then NAL Unit structure, then init all pointer's (sps, pps, sei) to NULL. */ DecodingContext_t *initDecodingContext(VideoFile_t *video) { TRACE_INFO(H264, BLD_GREEN "initDecodingContext()\n" CLR_RESET); DecodingContext_t *dc = NULL; if (video != NULL) { // DecodingContext allocation dc = (DecodingContext_t*)calloc(1, sizeof(DecodingContext_t)); if (dc == NULL) { TRACE_ERROR(H264, "Unable to alloc new DecodingContext!\n"); } else { // Init output variables dc->output_format = 0; dc->picture_quality = 75; dc->picture_number = 1; dc->picture_extractionmode = 0; // Init input bitstream dc->VideoFile = video; dc->bitstr = init_bitstream(video, video->tracks_video[0]); if (dc->bitstr == NULL) { free(dc); dc = NULL; } else { // Init NAL Unit dc->active_nalu = initNALU(); if (dc->active_nalu == NULL) { free(dc->bitstr); dc->bitstr = NULL; free(dc); dc = NULL; } else { // Cleanup array of SPS and PPS int i = 0; for (i = 0; i < MAX_SPS; i++) { dc->sps_array[i] = NULL; } for (i = 0; i < MAX_PPS; i++) { dc->pps_array[i] = NULL; } dc->active_sei = NULL; dc->active_slice = NULL; dc->mb_array = NULL; TRACE_1(H264, "* DecodingContext allocation success\n"); } } } } // Return the DecodingContext return dc; }
int ps_fileParse(MediaFile_t *media) { int retcode = SUCCESS; TRACE_INFO(MPS, BLD_GREEN "ps_fileParse()" CLR_RESET); // Init bitstream to parse container infos Bitstream_t *bitstr = init_bitstream(media, NULL); if (bitstr != NULL) { // Init an MpegPs structure MpegPs_t mpg; memset(&mpg, 0, sizeof(MpegPs_t)); // A convenient way to stop the parser mpg.run = true; // stuff const int64_t min_packet_size = 4; // Loop on PES packets while (mpg.run == true && retcode == SUCCESS && bitstream_get_absolute_byte_offset(bitstr) < (media->file_size - min_packet_size)) { // Init PackHeader_t pack_header; memset(&pack_header, 0, sizeof(PackHeader_t)); SystemHeader_t system_header; memset(&system_header, 0, sizeof(SystemHeader_t)); PesHeader_t pes_header; memset(&pes_header, 0, sizeof(PesHeader_t)); PesPacket_t pes_packet; memset(&pes_packet, 0, sizeof(PesPacket_t)); ProgramStreamMap_t pes_streammap; memset(&pes_streammap, 0, sizeof(ProgramStreamMap_t)); ProgramStreamDirectory_t pes_streamdirectory; memset(&pes_streamdirectory, 0, sizeof(ProgramStreamDirectory_t)); // Parse packet header parse_pes_header(bitstr, &pes_header); switch (pes_header.stream_id) { case SID_PACK_HEADER: retcode = parse_pack_header(bitstr, &pes_header, &pack_header); mpg.stat_packheader++; break; case SID_SYSTEM_HEADER: retcode = parse_system_header(bitstr, &pes_header, &system_header); mpg.stat_systemheader++; break; case SID_PROGRAM_STREAM_MAP: retcode = parse_program_stream_map(bitstr, &pes_header, &pes_streammap); mpg.stat_packet_psm++; break; case SID_PROGRAM_STREAM_DIRECTORY: retcode = parse_program_stream_directory(bitstr, &pes_header, &pes_streamdirectory); mpg.stat_packet_psd++; break; case SID_PRIVATE_STREAM_2: TRACE_2(MPS, BLD_GREEN "Private Stream 2 PES" CLR_RESET " @ %lli", pes_header.offset_start); mpg.stat_packet_private++; break; case SID_PADDING: retcode = parse_pes_padding(bitstr, &pes_header, &pes_packet); mpg.stat_packet_other++; break; case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: case SID_PRIVATE_STREAM_1: case SID_AUDIO: { TRACE_INFO(MPS, BLD_GREEN "parse_pes_audio()" CLR_RESET " @ %lli", pes_header.offset_start); // Find a trackid unsigned track_id = pes_header.stream_id - 0xC0; if (pes_header.stream_id == SID_PRIVATE_STREAM_1) track_id = 0; // If a private stream is in the stream, the 'regular' trackid order is shifted //while (media->tracks_audio[track_id] == NULL) // track_id--; // Init bitstream_map (as needed) to store samples if (media->tracks_audio[track_id] == NULL) { retcode = init_bitstream_map(&media->tracks_audio[track_id], 0, 999999); media->tracks_audio_count++; media->tracks_audio[track_id]->stream_type = stream_AUDIO; } retcode = parse_pes(bitstr, &pes_header, &pes_packet); parse_pes_a(bitstr, &pes_header, &pes_packet, media->tracks_audio[track_id]); mpg.stat_packet_audio++; // Set sample into the bitstream_map unsigned sample_id = media->tracks_audio[track_id]->sample_count++; if (sample_id < 999999) { media->tracks_audio[track_id]->sample_type[sample_id] = sample_AUDIO; media->tracks_audio[track_id]->sample_size[sample_id] = pes_header.payload_length - pes_packet.PES_header_data_length; media->tracks_audio[track_id]->sample_offset[sample_id] = pes_header.offset_start + 6 + pes_packet.PES_header_data_length; media->tracks_audio[track_id]->sample_pts[sample_id] = pes_packet.PTS; media->tracks_audio[track_id]->sample_dts[sample_id] = pes_packet.DTS; } } break; case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF: case SID_VIDEO: { TRACE_INFO(MPS, BLD_GREEN "parse_pes_video()" CLR_RESET " @ %lli", pes_header.offset_start + 6); // Init bitstream_map (as needed) to store samples unsigned track_id = pes_header.stream_id - 0xE0; if (media->tracks_video[track_id] == NULL) { retcode = init_bitstream_map(&media->tracks_video[track_id], 0, 999999); media->tracks_video_count++; media->tracks_video[track_id]->stream_type = stream_VIDEO; } retcode = parse_pes(bitstr, &pes_header, &pes_packet); parse_pes_v(bitstr, &pes_header, &pes_packet, media->tracks_video[track_id]); mpg.stat_packet_video++; // Set sample into the bitstream_map unsigned sample_id = media->tracks_video[track_id]->sample_count++; if (sample_id < 999999) { media->tracks_video[track_id]->sample_type[sample_id] = sample_VIDEO; media->tracks_video[track_id]->sample_size[sample_id] = pes_header.payload_length - pes_packet.PES_header_data_length; media->tracks_video[track_id]->sample_offset[sample_id] = pes_header.offset_start + 6 + pes_packet.PES_header_data_length; media->tracks_video[track_id]->sample_pts[sample_id] = pes_packet.PTS; media->tracks_video[track_id]->sample_dts[sample_id] = pes_packet.DTS; } } break; case SID_PROGRAM_END: mpg.stat_packet_other++; mpg.run = false; break; default: TRACE_WARNING(MPS, "Unknown PES packet type (0x%02X) @ %lli", pes_header.stream_id, pes_header.offset_start); mpg.stat_packet_other++; break; } retcode = jumpy_pes(bitstr, &pes_header); } // Free bitstream free_bitstream(&bitstr); // Recap TRACE_INFO(MPS, "MPEG PS (version %u) stats", mpg.mpeg_version); TRACE_INFO(MPS, "- Pack Headers: %u", mpg.stat_packheader); TRACE_INFO(MPS, "- System Headers: %u", mpg.stat_systemheader); TRACE_INFO(MPS, "- PSM packets: %u", mpg.stat_packet_psm); TRACE_INFO(MPS, "- PSD packets: %u", mpg.stat_packet_psd); TRACE_INFO(MPS, "- Private packets: %u", mpg.stat_packet_private); TRACE_INFO(MPS, "- Audio packets: %u", mpg.stat_packet_audio); TRACE_INFO(MPS, "- Video packets: %u", mpg.stat_packet_video); TRACE_INFO(MPS, "- Unknown packets: %u", mpg.stat_packet_other); } else { retcode = FAILURE; } return retcode; }
int main(int argc, char* argv[]) { FILE *fd; fd = fopen("predictor_error.txt", "w+"); FILE *fd1,*fd2; fd1 = fopen("predictor1_error.txt", "w+"); fd2 = fopen("predictor2_error.txt", "w+"); parameters params; codingvars vars; image_data* pre_im_data = NULL;//n-1 frame image image_data* im_data = NULL;//n frame image // parsing command line parameters and/or JPEG-LS header params = coding_parameters(argc, argv); // encoding process //loading previous image data pre_im_data = load_image(params.input_file0); printf("%s**\n", params.input_file0); // loading image data im_data = load_image(params.input_file); printf("%s**\n", params.input_file); // bitstream initialization init_bitstream(params.output_file, 'w'); params.MAXVAL = im_data->maxval; write_header(params, im_data); // setting parameters if(params.specified_T == false) { /* C.2.4.1.1 Default threshold values */ if(params.MAXVAL>=128) { vars.FACTOR = floor((float64)(min(params.MAXVAL,4095)+128)/256); params.T1 = CLAMP(vars.FACTOR*(vars.BASIC_T1-2)+2+3*params.NEAR,params.NEAR+1,params.MAXVAL); params.T2 = CLAMP(vars.FACTOR*(vars.BASIC_T2-3)+3+5*params.NEAR,params.T1,params.MAXVAL); params.T3 = CLAMP(vars.FACTOR*(vars.BASIC_T3-4)+4+7*params.NEAR,params.T2,params.MAXVAL); } else { vars.FACTOR = floor( 256.0/(params.MAXVAL + 1) ); params.T1 = CLAMP(max(2,floor((float64)vars.BASIC_T1/vars.FACTOR)+3*params.NEAR),params.NEAR+1,params.MAXVAL); params.T2 = CLAMP(max(2,floor((float64)vars.BASIC_T2/vars.FACTOR)+5*params.NEAR),params.T1,params.MAXVAL); params.T3 = CLAMP(max(2,floor((float64)vars.BASIC_T3/vars.FACTOR)+7*params.NEAR),params.T2,params.MAXVAL); } } if(params.verbose) { fprintf(stdout, "Encoding %s...\n\n\twidth\t\t%d\n\theight\t\t%d\n\tcomponents\t%d\n", params.input_file, im_data->width, im_data->height, im_data->n_comp); fprintf(stdout, "\tMAXVAL\t\t%d\n\tNEAR\t\t%d\n\tT1\t\t%d\n\tT2\t\t%d\n\tT3\t\t%d\n\tRESET\t\t%d\n", params.MAXVAL, params.NEAR, params.T1, params.T2, params.T3, params.RESET); } /* A.2 Initializations and conventions */ init_codingvars(&vars, params); //for(vars.comp=0; vars.comp<im_data->n_comp; vars.comp++) for(vars.comp=0; vars.comp<1; vars.comp++) for(vars.row=0; vars.row<im_data->height; vars.row++) for(vars.col=0; vars.col<im_data->width; vars.col++) { /* A.3 Context determination */ context_determination(&vars, params, im_data); //printf("%s\n", "HERE IT IS!"); motion_vector(&vars, params, pre_im_data, im_data); if((vars.row == 100) && (vars.col >= 200) && (vars.col < 220)) printf("motion_vector is (%d,%d) and Dif_min is %d.\n", vars.m0,vars.n0,vars.temp); prev_context(&vars, params, pre_im_data); // regular mode /* A.4 Prediction*/ predict_sample_value(&vars, params); predictor1(&vars, params); predictor2(&vars, params); encode_prediction_error(&vars, params, im_data); fprintf(fd, "%d\n", vars.Errval_temp3); encode_prediction_error_intra(&vars, params); fprintf(fd1, "%d\n", vars.Errval_temp1); fprintf(fd2, "%d\n", vars.Errval_temp2); /* A.6 Update variables */ update_codingvars(&vars, params); } end_bitstream(); if(params.decoding_flag == true) write_image("lena_decoded.ppm", im_data); else print_bpp(im_data); return 0; }
// 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; }
int mp3_fileParse(MediaFile_t *media) { int retcode = SUCCESS; TRACE_INFO(MP3, BLD_GREEN "mp3_fileParse()" CLR_RESET); // Init bitstream to parse container infos Bitstream_t *bitstr = init_bitstream(media, NULL); if (bitstr != NULL) { // Init a MediaStream_t to store samples retcode = init_bitstream_map(&media->tracks_audio[0], 0, 999999); // Init an MP3 structure mp3_t mp3; memset(&mp3, 0, sizeof(mp3_t)); // A convenient way to stop the parser mp3.run = true; // stuff int64_t min_frame_size = 128; int64_t frame_offset = 0; uint32_t frame_header = 0; bool first_frame_parsed = false; // Loop on 1st level elements while (mp3.run == true && retcode == SUCCESS && bitstream_get_absolute_byte_offset(bitstr) < (media->file_size - min_frame_size)) { // Seek to the next frame offset // Assume the MP3 frames will not be bigger than 4Gib uint32_t jump_bits = (uint32_t)(frame_offset - bitstream_get_absolute_byte_offset(bitstr)) * 8; if (jump_bits > 0) skip_bits(bitstr, jump_bits); // Read the next frame header frame_header = read_bits(bitstr, 32); // note: check frame header against 11 bits long instead of 12, to be compatible with MPEG-1/2/2.5 if ((frame_header & 0xFFE00000) == 0xFFE00000) { TRACE_1(MP3, "> MP3 frame @ %lli", frame_offset); if (first_frame_parsed == false) { frame_offset = parse_frame_full(bitstr, frame_header, &mp3, media); if (frame_offset > 0) first_frame_parsed = true; else retcode = FAILURE; } else { frame_offset = parse_frame(bitstr, frame_header, &mp3, media); } } else if ((frame_header & 0xFFFFFF00) == 0x54414700) { TRACE_INFO(MP3, "> ID3v1 tag @ %lli", frame_offset); mp3.run = false; // Add the TAG to the track int sid = media->tracks_audio[0]->sample_count; if (sid < 999999) { media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG; media->tracks_audio[0]->sample_size[sid] = media->file_size - frame_offset; media->tracks_audio[0]->sample_offset[sid] = frame_offset; media->tracks_audio[0]->sample_pts[sid] = 0; media->tracks_audio[0]->sample_dts[sid] = 0; media->tracks_audio[0]->sample_count++; } } else if ((frame_header & 0xFFFFFF00) == 0x49443300) { int id3tag_version = ((frame_header & 0x000000FF) << 8) + read_bits(bitstr, 8); /*int id3tag_flag =*/ read_bits(bitstr, 8); TRACE_INFO(MP3, "> ID3v2.%i @ %lli", id3tag_version, frame_offset); uint32_t id3tag_size = read_bits(bitstr, 8) & 0x0000007F; id3tag_size <<= 7; id3tag_size += read_bits(bitstr, 8) & 0x0000007F; id3tag_size <<= 7; id3tag_size += read_bits(bitstr, 8) & 0x0000007F; id3tag_size <<= 7; id3tag_size += read_bits(bitstr, 8) & 0x0000007F; id3tag_size += 10; // bytes already read // Add the TAG to the track int sid = media->tracks_audio[0]->sample_count; if (sid < 999999) { media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG; media->tracks_audio[0]->sample_size[sid] = id3tag_size; media->tracks_audio[0]->sample_offset[sid] = frame_offset; media->tracks_audio[0]->sample_pts[sid] = 0; media->tracks_audio[0]->sample_dts[sid] = 0; media->tracks_audio[0]->sample_count++; } // Simulate TAG parsing frame_offset += id3tag_size; } else if (frame_header == 0x4C595249) { TRACE_INFO(MP3, "> Lyrics3 tag @ %lli", frame_offset); frame_offset += 32; // just restart MP3 frame detection 32 bytes later... // Add the TAG to the track int sid = media->tracks_audio[0]->sample_count; if (sid < 999999) { media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG; media->tracks_audio[0]->sample_size[sid] = 0; media->tracks_audio[0]->sample_offset[sid] = frame_offset; media->tracks_audio[0]->sample_pts[sid] = 0; media->tracks_audio[0]->sample_dts[sid] = 0; media->tracks_audio[0]->sample_count++; } } else if (frame_header == 0x58696E67) { TRACE_INFO(MP3, "> XING tag @ %lli", frame_offset); frame_offset += 32; // just restart MP3 frame detection 32 bytes later... // Add the TAG to the track int sid = media->tracks_audio[0]->sample_count; if (sid < 999999) { media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG; media->tracks_audio[0]->sample_size[sid] = 0; media->tracks_audio[0]->sample_offset[sid] = frame_offset; media->tracks_audio[0]->sample_pts[sid] = 0; media->tracks_audio[0]->sample_dts[sid] = 0; media->tracks_audio[0]->sample_count++; } } else if (frame_header == 0x56425249) { TRACE_INFO(MP3, "> VBRI tag @ %lli", frame_offset); frame_offset += 32; // just restart MP3 frame detection 32 bytes later... // Add the TAG to the track int sid = media->tracks_audio[0]->sample_count; if (sid < 999999) { media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG; media->tracks_audio[0]->sample_size[sid] = 0; media->tracks_audio[0]->sample_offset[sid] = frame_offset; media->tracks_audio[0]->sample_pts[sid] = 0; media->tracks_audio[0]->sample_dts[sid] = 0; media->tracks_audio[0]->sample_count++; } } else if (frame_header == 0x41504554) { TRACE_WARNING(MP3, "> APE tag @ %lli", frame_offset); /*uint32_t apetag_header =*/ read_bits(bitstr, 32); // 0x41474558, second part of the tag header /*uint32_t apetag_version =*/ read_bits(bitstr, 32); uint32_t apetag_size = 8 + read_bits(bitstr, 32); // APE header size (8 bytes) + tag content size // Add the TAG to the track int sid = media->tracks_audio[0]->sample_count; if (sid < 999999) { media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG; media->tracks_audio[0]->sample_size[sid] = apetag_size; media->tracks_audio[0]->sample_offset[sid] = frame_offset; media->tracks_audio[0]->sample_pts[sid] = 0; media->tracks_audio[0]->sample_dts[sid] = 0; media->tracks_audio[0]->sample_count++; } // Simulate TAG parsing frame_offset = frame_offset + apetag_size; } else { // Try to find a new startcode closeby... frame_offset += 1; TRACE_3(MP3, "Unknown frame header @ %lli (startcode: 0x%X)", frame_offset, frame_header); } } if (retcode == SUCCESS) { retcode = mp3_indexer_track(media, &mp3); if (retcode == SUCCESS) { retcode = mp3_indexer(media, &mp3); } } } else { retcode = FAILURE; } return retcode; }