/*! * \brief Parse PES packet. * \param *bitstr: The bitstream to use. * \param *header: A pointer to a PES header structure. * \param *packet: A pointer to a PES packet structure. * \return 1 if succeed, 0 otherwise. * * From 'ISO/IEC 13818-1' specification: * 2.4.3.6 PES packet. * Table 2-17 – PES packet. * * Parse both MPEG-1 (ISO/IEC 11172-1) and MPEG-2 (ISO/IEC 13818-1) PES packets. */ int parse_pes(Bitstream_t *bitstr, PesHeader_t *header, PesPacket_t *packet) { TRACE_2(MPS, "> parse_pes()"); int retcode = SUCCESS; TRACE_INFO(MPS, "parse_pes() 0x%X @ %lli", header->start_code, bitstream_get_absolute_byte_offset(bitstr)); // "regular" PES packet? if ((header->stream_id != SID_PROGRAM_STREAM_MAP) && (header->stream_id != SID_PADDING) && (header->stream_id != SID_PRIVATE_STREAM_2) && (header->stream_id != SID_ECM_STREAM) && (header->stream_id != SID_EMM_STREAM) && (header->stream_id != SID_PROGRAM_STREAM_DIRECTORY) && (header->stream_id != SID_DSMCC_STREAM) && (header->stream_id != SID_2221E)) { unsigned checkversion = next_bits(bitstr, 2); // Parse MPEG-2 PES header if ((checkversion & 0x02) == 0x02) { packet->mpeg_version = 2; if (read_bits(bitstr, 2) != 2) { TRACE_ERROR(MPS, "wrong 'marker_bits'"); return FAILURE; } packet->PES_scrambling_control = read_bits(bitstr, 2); packet->PES_priority = read_bit(bitstr); packet->data_alignment_indicator = read_bit(bitstr); packet->copyright = read_bit(bitstr); packet->original_or_copy = read_bit(bitstr); packet->PTS_DTS_flag = read_bits(bitstr, 2); packet->ESCR_flag = read_bit(bitstr); packet->ES_rate_flag = read_bit(bitstr); packet->DSM_trick_mode_flag = read_bit(bitstr); packet->additional_copy_info_flag = read_bit(bitstr); packet->PES_CRC_flag = read_bit(bitstr); packet->PES_extension_flag = read_bit(bitstr); packet->PES_header_data_length = read_bits(bitstr, 8); if (packet->PTS_DTS_flag == 2) { if (read_bits(bitstr, 4) != 2) { TRACE_ERROR(MPS, "wrong 'marker_bit'"); return FAILURE; } packet->PTS = read_bits(bitstr, 3) << 30; MARKER_BIT packet->PTS += read_bits(bitstr, 15) << 15; MARKER_BIT packet->PTS += read_bits(bitstr, 15); MARKER_BIT } else if (packet->PTS_DTS_flag == 3)
static int __split_next_bits(struct sw842_param *p, u64 *d, u8 n, u8 s) { u64 tmp = 0; int ret; if (n <= s) { pr_debug("split_next_bits invalid n %u s %u\n", n, s); return -EINVAL; } ret = next_bits(p, &tmp, n - s); if (ret) return ret; ret = next_bits(p, d, s); if (ret) return ret; *d |= tmp << s; return 0; }
// Read bnum bits from bitstream bstr with the most significant // bit read first. A 64 bit unsigned integer is returned. uint64_t read_bits(struct bitstream *bstr, unsigned bnum) { uint64_t res = next_bits(bstr, bnum); // Special case for reading zero bits. Also abort when not enough // bits are left. Return zero if(bnum == 0 || bstr->bitsleft < 0) return 0; // Advance the bitstream bstr->bpos = bstr->_i_bpos; bstr->pos = bstr->_i_pos; return res; }
/*! * \brief Parse a pack header structure. * \param *bitstr The bitstream to use. * \param *pack_header A pointer to a pack_header structure. * \param *system_header A pointer to a system_header 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'. */ static int parse_pack_header(Bitstream_t *bitstr, PackHeader_t *pack_header, SystemHeader_t *system_header) { TRACE_INFO(MPS, BLD_GREEN "parse_pack_header()" CLR_RESET " @ %i\n", bitstream_get_absolute_byte_offset(bitstr) - 4); int retcode = SUCCESS; int i = 0; pack_header->pack_start_code = PES_PACK_HEADER; if (read_bits(bitstr, 2) != 1) { TRACE_ERROR(MPS, "wrong 'marker_bit'\n"); return FAILURE; } pack_header->system_clock_reference_base = read_bits(bitstr, 3) << 30; MARKER_BIT pack_header->system_clock_reference_base += read_bits(bitstr, 15) << 15; MARKER_BIT pack_header->system_clock_reference_base += read_bits(bitstr, 15); MARKER_BIT pack_header->system_clock_reference_extension = read_bits(bitstr, 9); MARKER_BIT pack_header->program_mux_rate = read_bits(bitstr, 22); MARKER_BIT MARKER_BIT int reserved = read_bits(bitstr, 5); pack_header->pack_stuffing_length = read_bits(bitstr, 3); // Stuffing for (i = 0; i < pack_header->pack_stuffing_length; i++) { if (read_bits(bitstr, 8) != 0xFF) { TRACE_ERROR(MPS, "Wrong 'stuffing_byte'\n"); return FAILURE; } } // System header if (next_bits(bitstr, 32) == PES_SYSTEM_HEADER) { TRACE_INFO(MPS, BLD_GREEN "parse_system_header()" CLR_RESET " @ %i\n", bitstream_get_absolute_byte_offset(bitstr) - 4); skip_bits(bitstr, 32); system_header->header_length = read_bits(bitstr, 16); MARKER_BIT system_header->rate_bound = read_bits(bitstr, 22); MARKER_BIT system_header->audio_bound = read_bits(bitstr, 6); system_header->fixed_flag = read_bits(bitstr, 1); system_header->CSPS_flag = read_bits(bitstr, 1); system_header->system_audio_lock_flag = read_bits(bitstr, 1); system_header->system_video_lock_flag = read_bits(bitstr, 1); MARKER_BIT system_header->video_bound = read_bits(bitstr, 5); system_header->packet_rate_restriction_flag = read_bits(bitstr, 1); int reserved_bits = read_bits(bitstr, 7); // stack it? while (next_bit(bitstr) == 1) { system_header->stream_id = read_bits(bitstr, 8); MARKER_BIT MARKER_BIT system_header->PSTD_buffer_bound_scale = read_bits(bitstr, 1); system_header->PSTD_buffer_size_bound = read_bits(bitstr, 13); } } else { TRACE_2(MPS, " > No system_header()\n"); } return retcode; }
/*! * \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 Parse a pack header structure. * \param *bitstr The bitstream to use. * \param *pack_header A pointer to a pack_header structure. * \return 1 if succeed, 0 otherwise. * * From 'ISO/IEC 13818-1' specification: * 2.5.3.3 Pack layer of Program Stream. * Table 2-33 – Program Stream pack header */ static int parse_pack_header(Bitstream_t *bitstr, PesHeader_t *header, PackHeader_t *packet) { TRACE_INFO(MPS, BLD_GREEN "parse_pack_header()" CLR_RESET " @ %lli", header->offset_start); int retcode = SUCCESS; // Pack Headers do not have lengh field, rewind 2 bytes rewind_bits(bitstr, 16); if (read_bits(bitstr, 2) != 1) { TRACE_ERROR(MPS, "wrong 'marker_bits'"); return FAILURE; } packet->system_clock_reference_base = read_bits(bitstr, 3) << 30; MARKER_BIT packet->system_clock_reference_base += read_bits(bitstr, 15) << 15; MARKER_BIT packet->system_clock_reference_base += read_bits(bitstr, 15); MARKER_BIT packet->system_clock_reference_extension = read_bits(bitstr, 9); MARKER_BIT packet->program_mux_rate = read_bits(bitstr, 22); MARKER_BIT MARKER_BIT /*unsigned reserved =*/ read_bits(bitstr, 5); packet->pack_stuffing_length = read_bits(bitstr, 3); // Stuffing for (uint8_t i = 0; i < packet->pack_stuffing_length; i++) { if (read_bits(bitstr, 8) != 0xFF) { TRACE_ERROR(MPS, "Wrong 'stuffing_byte'"); return FAILURE; } } // System header // TODO split into its own function? if (next_bits(bitstr, 32) == 0x000001BB) { TRACE_INFO(MPS, BLD_GREEN "parse_system_header()" CLR_RESET " @ %lli", bitstream_get_absolute_byte_offset(bitstr) - 4); skip_bits(bitstr, 48); // start code + size SystemHeader_t system_header; MARKER_BIT system_header.rate_bound = read_bits(bitstr, 22); MARKER_BIT system_header.audio_bound = read_bits(bitstr, 6); system_header.fixed_flag = read_bits(bitstr, 1); system_header.CSPS_flag = read_bits(bitstr, 1); system_header.system_audio_lock_flag = read_bits(bitstr, 1); system_header.system_video_lock_flag = read_bits(bitstr, 1); MARKER_BIT system_header.video_bound = read_bits(bitstr, 5); system_header.packet_rate_restriction_flag = read_bits(bitstr, 1); /*unsigned reserved_bits =*/ read_bits(bitstr, 7); // stack it? while (next_bit(bitstr) == 1) { system_header.stream_id = read_bits(bitstr, 8); MARKER_BIT MARKER_BIT system_header.PSTD_buffer_bound_scale = read_bits(bitstr, 1); system_header.PSTD_buffer_size_bound = read_bits(bitstr, 13); } } else { TRACE_2(MPS, " > No system_header()"); } // Pack header have no length field, so we just have to parse them correctly header->offset_end = bitstream_get_absolute_byte_offset(bitstr); header->payload_length = header->offset_end - header->offset_start - 4; return retcode; }