Implemented various TS-related library functions.

This commit is contained in:
Thulinma 2014-06-11 15:47:20 +02:00
parent 910feb0a07
commit 0cf74425f9
5 changed files with 1325 additions and 426 deletions

View file

@ -8,6 +8,10 @@ namespace Utils{
append(input); append(input);
return *this; return *this;
}; };
bitstream& operator<< (char input){
append(std::string(input, 1));
return *this;
};
void append (char* input, size_t bytes); void append (char* input, size_t bytes);
void append (std::string input); void append (std::string input);
long long unsigned int size(); long long unsigned int size();

561
lib/nal.cpp Normal file → Executable file
View file

@ -1,82 +1,507 @@
#include "nal.h" #include "nal.h"
#include "bitstream.h"
#include "defines.h"
#include <iostream>
#include <iomanip>
#include <math.h>//for log
namespace h264 {
NAL_Unit::NAL_Unit(){ ///empty constructor of NAL
NAL::NAL() {
}
NAL_Unit::NAL_Unit(std::string & InputData){
ReadData(InputData);
}
bool NAL_Unit::ReadData(std::string & InputData){
std::string FullAnnexB;
FullAnnexB += (char)0x00;
FullAnnexB += (char)0x00;
FullAnnexB += (char)0x00;
FullAnnexB += (char)0x01;
std::string ShortAnnexB;
ShortAnnexB += (char)0x00;
ShortAnnexB += (char)0x00;
ShortAnnexB += (char)0x01;
if (InputData.size() < 3){
return false;
} }
bool AnnexB = false;
if (InputData.substr(0, 3) == ShortAnnexB){ ///Constructor capable of directly inputting NAL data from a string
AnnexB = true; ///\param InputData the nal input data, as a string
NAL::NAL(std::string & InputData) {
ReadData(InputData);
} }
if (InputData.substr(0, 4) == FullAnnexB){
InputData.erase(0, 1); ///Gets the raw NAL unit data, as a string
AnnexB = true; ///\return the raw NAL unit data
std::string NAL::getData() {
return MyData;
} }
if (AnnexB){
MyData = ""; ///Reads data from a string,either raw or annexed
InputData.erase(0, 3); //Intro Bytes ///\param InputData the h264 data, as string
int Location = std::min(InputData.find(ShortAnnexB), InputData.find(FullAnnexB)); ///\param raw a boolean that determines whether the string contains raw h264 data or not
MyData = InputData.substr(0, Location); bool NAL::ReadData(std::string & InputData, bool raw) {
InputData.erase(0, Location); if (raw) {
}else{ MyData = InputData;
if (InputData.size() < 4){ InputData.clear();
return true;
}
std::string FullAnnexB;
FullAnnexB += (char)0x00;
FullAnnexB += (char)0x00;
FullAnnexB += (char)0x00;
FullAnnexB += (char)0x01;
std::string ShortAnnexB;
ShortAnnexB += (char)0x00;
ShortAnnexB += (char)0x00;
ShortAnnexB += (char)0x01;
if (InputData.size() < 3) {
//DEBUG_MSG(DLVL_DEVEL, "fal1");
return false; return false;
} }
unsigned int UnitLen = (InputData[0] << 24) + (InputData[1] << 16) + (InputData[2] << 8) + InputData[3]; bool AnnexB = false;
if (InputData.size() < 4 + UnitLen){ if (InputData.substr(0, 3) == ShortAnnexB) {
return false;
}
InputData.erase(0, 4); //Remove Length
MyData = InputData.substr(0, UnitLen);
InputData.erase(0, UnitLen); //Remove this unit from the string
}
return true;
}
std::string NAL_Unit::AnnexB(bool LongIntro){ AnnexB = true;
std::string Result; }
if (MyData.size()){ if (InputData.substr(0, 4) == FullAnnexB) {
if (LongIntro){ InputData.erase(0, 1);
AnnexB = true;
}
if (AnnexB) {
MyData = "";
InputData.erase(0, 3); //Intro Bytes
int Location = std::min(InputData.find(ShortAnnexB), InputData.find(FullAnnexB));
MyData = InputData.substr(0, Location);
InputData.erase(0, Location);
} else {
if (InputData.size() < 4) {
DEBUG_MSG(DLVL_DEVEL, "fal2");
return false;
}
unsigned int UnitLen = (InputData[0] << 24) + (InputData[1] << 16) + (InputData[2] << 8) + InputData[3];
if (InputData.size() < 4 + UnitLen) {
DEBUG_MSG(DLVL_DEVEL, "fal3");
return false;
}
InputData.erase(0, 4); //Remove Length
MyData = InputData.substr(0, UnitLen);
InputData.erase(0, UnitLen); //Remove this unit from the string
}
//DEBUG_MSG(DLVL_DEVEL, "tru");
return true;
}
///Returns an annex B prefix
///\param LongIntro determines whether it is a short or long annex B
///\return the desired annex B prefix
std::string NAL::AnnexB(bool LongIntro) {
std::string Result;
if (MyData.size()) {
if (LongIntro) {
Result += (char)0x00;
}
Result += (char)0x00; Result += (char)0x00;
Result += (char)0x00;
Result += (char)0x01; //Annex B Lead-In
Result += MyData;
} }
Result += (char)0x00; return Result;
Result += (char)0x00;
Result += (char)0x01; //Annex B Lead-In
Result += MyData;
} }
return Result;
///Returns raw h264 data as Size Prepended
///\return the h264 data as Size prepended
std::string NAL::SizePrepended() {
std::string Result;
if (MyData.size()) {
int DataSize = MyData.size();
Result += (char)((DataSize & 0xFF000000) >> 24);
Result += (char)((DataSize & 0x00FF0000) >> 16);
Result += (char)((DataSize & 0x0000FF00) >> 8);
Result += (char)(DataSize & 0x000000FF); //Size Lead-In
Result += MyData;
}
return Result;
}
///returns the nal unit type
///\return the nal unit type
int NAL::Type() {
return (MyData[0] & 0x1F);
}
SPS::SPS(std::string & input, bool raw) : NAL() {
ReadData(input, raw);
}
///computes SPS data from an SPS nal unit, and saves them in a useful
///more human-readable format in the parameter spsmeta
///The function is based on the analyzeSPS() function. If more data needs to be stored in sps meta,
///refer to that function to determine which variable comes at which place (as all couts have been removed).
///\param spsmeta the sps metadata, in which data from the sps is stored
///\todo some h264 sps data types are not supported (due to them containing matrixes and have never been encountered in practice). If needed, these need to be implemented
SPSMeta SPS::getCharacteristics() {
SPSMeta result;
//For calculating width
unsigned int widthInMbs = 0;
unsigned int cropHorizontal = 0;
//For calculating height
bool mbsOnlyFlag = 0;
unsigned int heightInMapUnits = 0;
unsigned int cropVertical = 0;
Utils::bitstream bs;
for (unsigned int i = 1; i < MyData.size(); i++) {
if (i + 2 < MyData.size() && MyData.substr(i, 3) == std::string("\000\000\003", 3)) {
bs << MyData.substr(i, 2);
i += 2;
} else {
bs << MyData.substr(i, 1);
}
}
char profileIdc = bs.get(8);
//Start skipping unused data
bs.skip(16);
bs.getUExpGolomb();
if (profileIdc == 100 || profileIdc == 110 || profileIdc == 122 || profileIdc == 244 || profileIdc == 44 || profileIdc == 83 || profileIdc == 86 || profileIdc == 118 || profileIdc == 128) {
//chroma format idc
if (bs.getUExpGolomb() == 3) {
bs.skip(1);
}
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.skip(1);
if (bs.get(1)) {
DEBUG_MSG(DLVL_DEVEL, "Scaling matrix not implemented yet");
}
}
bs.getUExpGolomb();
unsigned int pic_order_cnt_type = bs.getUExpGolomb();
if (!pic_order_cnt_type) {
bs.getUExpGolomb();
} else if (pic_order_cnt_type == 1) {
DEBUG_MSG(DLVL_DEVEL, "This part of the implementation is incomplete(2), to be continued. If this message is shown, contact developers immediately.");
}
bs.getUExpGolomb();
bs.skip(1);
//Stop skipping data and start doing usefull stuff
widthInMbs = bs.getUExpGolomb() + 1;
heightInMapUnits = bs.getUExpGolomb() + 1;
mbsOnlyFlag = bs.get(1);//Gets used in height calculation
if (!mbsOnlyFlag) {
bs.skip(1);
}
bs.skip(1);
//cropping flag
if (bs.get(1)) {
cropHorizontal = bs.getUExpGolomb();//leftOffset
cropHorizontal += bs.getUExpGolomb();//rightOffset
cropVertical = bs.getUExpGolomb();//topOffset
cropVertical += bs.getUExpGolomb();//bottomOffset
}
//vuiParameters
if (bs.get(1)) {
//Skipping all the paramters we dont use
if (bs.get(1)){
if (bs.get(8) == 255) {
bs.skip(32);
}
}
if (bs.get(1)) {
bs.skip(1);
}
if (bs.get(1)) {
bs.skip(4);
if (bs.get(1)) {
bs.skip(24);
}
}
if (bs.get(1)) {
bs.getUExpGolomb();
bs.getUExpGolomb();
}
//Decode timing info
if (bs.get(1)) {
unsigned int unitsInTick = bs.get(32);
unsigned int timeScale = bs.get(32);
result.fps = (double)timeScale / (2 * unitsInTick);
bs.skip(1);
}
}
result.width = (widthInMbs * 16) - (cropHorizontal * 2);
result.height = ((mbsOnlyFlag ? 1 : 2) * heightInMapUnits * 16) - (cropVertical * 2);
return result;
}
///Analyzes an SPS nal unit, and prints the values of all existing fields
///\todo some h264 sps data types are not supported (due to them containing matrixes and have not yet been encountered in practice). If needed, these need to be implemented
void SPS::analyzeSPS() {
if (Type() != 7) {
DEBUG_MSG(DLVL_DEVEL, "This is not an SPS, but type %d", Type());
return;
}
Utils::bitstream bs;
//put rbsp bytes in mydata
for (unsigned int i = 1; i < MyData.size(); i++) {
//DEBUG_MSG(DLVL_DEVEL, "position %u out of %lu",i,MyData.size());
if (i + 2 < MyData.size() && MyData.substr(i, 3) == std::string("\000\000\003", 3)) {
bs << MyData.substr(i, 2);
//DEBUG_MSG(DLVL_DEVEL, "0x000003 encountered at i = %u",i);
i += 2;
} else {
bs << MyData.substr(i, 1);
}
}
//bs contains all rbsp bytes, now we can analyze them
std::cout << "seq_parameter_set_data()" << std::endl;
std::cout << std::hex << std::setfill('0') << std::setw(2);
char profileIdc = bs.get(8);
std::cout << "profile idc: " << (unsigned int) profileIdc << std::endl;
std::cout << "constraint_set0_flag: " << bs.get(1) << std::endl;
std::cout << "constraint_set1_flag: " << bs.get(1) << std::endl;
std::cout << "constraint_set2_flag: " << bs.get(1) << std::endl;
std::cout << "constraint_set3_flag: " << bs.get(1) << std::endl;
std::cout << "constraint_set4_flag: " << bs.get(1) << std::endl;
std::cout << "constraint_set5_flag: " << bs.get(1) << std::endl;
std::cout << "reserved_zero_2bits: " << bs.get(2) << std::endl;
std::cout << "level idc: " << bs.get(8) << std::endl;
std::cout << "seq_parameter_set_id: " << bs.getUExpGolomb() << std::endl;
if (profileIdc == 100 || profileIdc == 110 || profileIdc == 122 || profileIdc == 244 || profileIdc == 44 || profileIdc == 83 || profileIdc == 86 || profileIdc == 118 || profileIdc == 128) {
chroma_format_idc = bs.getUExpGolomb();
std::cout << "chroma_format_idc: " << chroma_format_idc << std::endl;
if (chroma_format_idc == 3) {
std::cout << "separate_colour_plane_flag" << bs.get(1) << std::endl;
}
std::cout << "bit_depth_luma_minus8: " << bs.getUExpGolomb() << std::endl;
std::cout << "bit_depth_chroma_minus8: " << bs.getUExpGolomb() << std::endl;
std::cout << "qpprime_y_zero_transform_bypass_flag: " << bs.get(1) << std::endl;
unsigned int seq_scaling_matrix_present_flag = bs.get(1);
std::cout << "seq_scaling_matrix_present_flag: " << seq_scaling_matrix_present_flag << std::endl;
if (seq_scaling_matrix_present_flag) {
for (unsigned int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12) ; i++) {
unsigned int seq_scaling_list_present_flag = bs.get(1);
std::cout << "seq_scaling_list_present_flag: " << seq_scaling_list_present_flag << std::endl;
DEBUG_MSG(DLVL_DEVEL, "not implemented, ending");
return;
if (seq_scaling_list_present_flag) {
//LevelScale4x4( m, i, j ) = weightScale4x4( i, j ) * normAdjust4x4( m, i, j )
//
if (i < 6) {
//scaling)list(ScalingList4x4[i],16,UseDefaultScalingMatrix4x4Flag[i]
} else {
//scaling)list(ScalingList4x4[i-6],64,UseDefaultScalingMatrix4x4Flag[i-6]
}
}
}
}
}
std::cout << "log2_max_frame_num_minus4: " << bs.getUExpGolomb() << std::endl;
unsigned int pic_order_cnt_type = bs.getUExpGolomb();
std::cout << "pic_order_cnt_type: " << pic_order_cnt_type << std::endl;
if (pic_order_cnt_type == 0) {
std::cout << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb() << std::endl;
} else if (pic_order_cnt_type == 1) {
DEBUG_MSG(DLVL_DEVEL, "This part of the implementation is incomplete(2), to be continued. If this message is shown, contact developers immediately.");
return;
}
std::cout << "max_num_ref_frames: " << bs.getUExpGolomb() << std::endl;
std::cout << "gaps_in_frame_num_allowed_flag: " << bs.get(1) << std::endl;
std::cout << "pic_width_in_mbs_minus1: " << bs.getUExpGolomb() << std::endl;
std::cout << "pic_height_in_map_units_minus1: " << bs.getUExpGolomb() << std::endl;
unsigned int frame_mbs_only_flag = bs.get(1);
std::cout << "frame_mbs_only_flag: " << frame_mbs_only_flag << std::endl;
if (frame_mbs_only_flag == 0) {
std::cout << "mb_adaptive_frame_field_flag: " << bs.get(1) << std::endl;
}
std::cout << "direct_8x8_inference_flag: " << bs.get(1) << std::endl;
unsigned int frame_cropping_flag = bs.get(1);
std::cout << "frame_cropping_flag: " << frame_cropping_flag << std::endl;
if (frame_cropping_flag != 0) {
std::cout << "frame_crop_left_offset: " << bs.getUExpGolomb() << std::endl;
std::cout << "frame_crop_right_offset: " << bs.getUExpGolomb() << std::endl;
std::cout << "frame_crop_top_offset: " << bs.getUExpGolomb() << std::endl;
std::cout << "frame_crop_bottom_offset: " << bs.getUExpGolomb() << std::endl;
}
unsigned int vui_parameters_present_flag = bs.get(1);
std::cout << "vui_parameters_present_flag: " << vui_parameters_present_flag << std::endl;
if (vui_parameters_present_flag != 0) {
//vuiParameters
unsigned int aspect_ratio_info_present_flag = bs.get(1);
std::cout << "aspect_ratio_info_present_flag: " << aspect_ratio_info_present_flag << std::endl;
if (aspect_ratio_info_present_flag != 0) {
unsigned int aspect_ratio_idc = bs.get(8);
std::cout << "aspect_ratio_idc: " << aspect_ratio_idc << std::endl;
if (aspect_ratio_idc == 255) {
std::cout << "sar_width: " << bs.get(16) << std::endl;
std::cout << "sar_height: " << bs.get(16) << std::endl;
}
}
unsigned int overscan_info_present_flag = bs.get(1);
std::cout << "overscan_info_present_flag: " << overscan_info_present_flag << std::endl;
if (overscan_info_present_flag) {
std::cout << "overscan_appropriate_flag: " << bs.get(1) << std::endl;
}
unsigned int video_signal_type_present_flag = bs.get(1);
std::cout << "video_signal_type_present_flag: " << video_signal_type_present_flag << std::endl;
if (video_signal_type_present_flag) {
std::cout << "video_format: " << bs.get(3) << std::endl;
std::cout << "video_full_range_flag: " << bs.get(1) << std::endl;
unsigned int colour_description_present_flag = bs.get(1);
std::cout << "colour_description_present_flag: " << colour_description_present_flag << std::endl;
if (colour_description_present_flag) {
std::cout << "colour_primaries: " << bs.get(8) << std::endl;
std::cout << "transfer_characteristics: " << bs.get(8) << std::endl;
std::cout << "matrix_coefficients: " << bs.get(8) << std::endl;
}
}
unsigned int chroma_loc_info_present_flag = bs.get(1);
std::cout << "chroma_loc_info_present_flag: " << chroma_loc_info_present_flag << std::endl;
if (chroma_loc_info_present_flag) {
std::cout << "chroma_sample_loc_type_top_field: " << bs.getUExpGolomb() << std::endl;
std::cout << "chroma_sample_loc_type_bottom_field: " << bs.getUExpGolomb() << std::endl;
}
unsigned int timing_info_present_flag = bs.get(1);
std::cout << "timing_info_present_flag: " << timing_info_present_flag << std::endl;
if (timing_info_present_flag) {
std::cout << "num_units_in_tick: " << bs.get(32) << std::endl;
std::cout << "time_scale: " << bs.get(32) << std::endl;
std::cout << "fixed_frame_rate_flag: " << bs.get(1) << std::endl;
}
unsigned int nal_hrd_parameters_present_flag = bs.get(1);
std::cout << "nal_hrd_parameters_present_flag: " << nal_hrd_parameters_present_flag << std::endl;
if (nal_hrd_parameters_present_flag) {
unsigned int cpb_cnt_minus1 = bs.getUExpGolomb();
std::cout << "cpb_cnt_minus1: " << cpb_cnt_minus1 << std::endl;
std::cout << "bit_rate_scale: " << bs.get(4) << std::endl;
std::cout << "cpb_rate_scale: " << bs.get(4) << std::endl;
for (unsigned int ssi = 0; ssi <= cpb_cnt_minus1 ; ssi++) {
std::cout << "bit_rate_value_minus1[" << ssi << "]: " << bs.getUExpGolomb() << std::endl;
std::cout << "cpb_size_value_minus1[" << ssi << "]: " << bs.getUExpGolomb() << std::endl;
std::cout << "cbr_flag[" << ssi << "]: " << bs.get(1) << std::endl;
}
std::cout << "initial_cpb_removal_delay_length_minus1: " << bs.get(5) << std::endl;
std::cout << "cpb_removal_delay_length_minus1: " << bs.get(5) << std::endl;
std::cout << "dpb_output_delay_length_minus1: " << bs.get(5) << std::endl;
std::cout << "time_offset_length: " << bs.get(5) << std::endl;
}
unsigned int vcl_hrd_parameters_present_flag = bs.get(1);
std::cout << "vcl_hrd_parameters_present_flag: " << vcl_hrd_parameters_present_flag << std::endl;
if (vcl_hrd_parameters_present_flag) {
unsigned int cpb_cnt_minus1 = bs.getUExpGolomb();
std::cout << "cpb_cnt_minus1: " << cpb_cnt_minus1 << std::endl;
std::cout << "bit_rate_scale: " << bs.get(4) << std::endl;
std::cout << "cpb_rate_scale: " << bs.get(4) << std::endl;
for (unsigned int ssi = 0; ssi <= cpb_cnt_minus1 ; ssi++) {
std::cout << "bit_rate_value_minus1[" << ssi << "]: " << bs.getUExpGolomb() << std::endl;
std::cout << "cpb_size_value_minus1[" << ssi << "]: " << bs.getUExpGolomb() << std::endl;
std::cout << "cbr_flag[" << ssi << "]: " << bs.get(1) << std::endl;
}
std::cout << "initial_cpb_removal_delay_length_minus1: " << bs.get(5) << std::endl;
std::cout << "cpb_removal_delay_length_minus1: " << bs.get(5) << std::endl;
std::cout << "dpb_output_delay_length_minus1: " << bs.get(5) << std::endl;
std::cout << "time_offset_length: " << bs.get(5) << std::endl;
}
if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
std::cout << "low_delay_hrd_flag: " << bs.get(1) << std::endl;
}
std::cout << "pic_struct_present_flag: " << bs.get(1) << std::endl;
unsigned int bitstream_restriction_flag = bs.get(1);
std::cout << "bitstream_restriction_flag: " << bitstream_restriction_flag << std::endl;
if (bitstream_restriction_flag) {
std::cout << "motion_vectors_over_pic_boundaries_flag: " << bs.get(1) << std::endl;
std::cout << "max_bytes_per_pic_denom: " << bs.getUExpGolomb() << std::endl;
std::cout << "max_bits_per_mb_denom: " << bs.getUExpGolomb() << std::endl;
std::cout << "log2_max_mv_length_horizontal: " << bs.getUExpGolomb() << std::endl;
std::cout << "log2_max_mv_length_vertical: " << bs.getUExpGolomb() << std::endl;
std::cout << "num_reorder_frames: " << bs.getUExpGolomb() << std::endl;
std::cout << "max_dec_frame_buffering: " << bs.getUExpGolomb() << std::endl;
}
}
std::cout << std::dec << std::endl;
//DEBUG_MSG(DLVL_DEVEL, "SPS analyser");
}
///Prints the values of all the fields of a PPS nal unit in a human readable format.
///\todo some features, including analyzable matrices, are not implemented. They were never encountered in practice, so far
void PPS::analyzePPS() {
if (Type() != 8) {
DEBUG_MSG(DLVL_DEVEL, "This is not a PPS, but type %d", Type());
return;
}
Utils::bitstream bs;
//put rbsp bytes in mydata
for (unsigned int i = 1; i < MyData.size(); i++) {
if (i + 2 < MyData.size() && MyData.substr(i, 3) == std::string("\000\000\003", 3)) {
bs << MyData.substr(i, 2);
i += 2;
} else {
bs << MyData.substr(i, 1);
}
}
//bs contains all rbsp bytes, now we can analyze them
std::cout << "pic_parameter_set_id: " << bs.getUExpGolomb() << std::endl;
std::cout << "seq_parameter_set_id: " << bs.getUExpGolomb() << std::endl;
std::cout << "entropy_coding_mode_flag: " << bs.get(1) << std::endl;
std::cout << "bottom_field_pic_order_in_frame_present_flag: " << bs.get(1) << std::endl;
unsigned int num_slice_groups_minus1 = bs.getUExpGolomb();
std::cout << "num_slice_groups_minus1: " << num_slice_groups_minus1 << std::endl;
if (num_slice_groups_minus1 > 0) {
unsigned int slice_group_map_type = bs.getUExpGolomb();
std::cout << "slice_group_map_type: " << slice_group_map_type << std::endl;
if (slice_group_map_type == 0) {
for (unsigned int ig = 0; ig <= num_slice_groups_minus1; ig++) {
std::cout << "runlengthminus1[" << ig << "]: " << bs.getUExpGolomb() << std::endl;
}
} else if (slice_group_map_type == 2) {
for (unsigned int ig = 0; ig <= num_slice_groups_minus1; ig++) {
std::cout << "top_left[" << ig << "]: " << bs.getUExpGolomb() << std::endl;
std::cout << "bottom_right[" << ig << "]: " << bs.getUExpGolomb() << std::endl;
}
} else if (slice_group_map_type == 3 || slice_group_map_type == 4 || slice_group_map_type == 5) {
std::cout << "slice_group_change_direction_flag: " << bs.get(1) << std::endl;
std::cout << "slice_group_change_rate_minus1: " << bs.getUExpGolomb() << std::endl;
} else if (slice_group_map_type == 6) {
unsigned int pic_size_in_map_units_minus1 = bs.getUExpGolomb();
std::cout << "pic_size_in_map_units_minus1: " << pic_size_in_map_units_minus1 << std::endl;
for (unsigned int i = 0; i <= pic_size_in_map_units_minus1; i++) {
std::cout << "slice_group_id[" << i << "]: " << bs.get((unsigned int)(ceil(log(num_slice_groups_minus1 + 1) / log(2)))) << std::endl;
}
}
}
std::cout << "num_ref_idx_l0_default_active_minus1: " << bs.getUExpGolomb() << std::endl;
std::cout << "num_ref_idx_l1_default_active_minus1: " << bs.getUExpGolomb() << std::endl;
std::cout << "weighted_pred_flag: " << bs.get(1) << std::endl;
std::cout << "weighted_bipred_idc: " << bs.get(2) << std::endl;
std::cout << "pic_init_qp_minus26: " << bs.getExpGolomb() << std::endl;
std::cout << "pic_init_qs_minus26: " << bs.getExpGolomb() << std::endl;
std::cout << "chroma_qp_index_offset: " << bs.getExpGolomb() << std::endl;
std::cout << "deblocking_filter_control_present_flag: " << bs.get(1) << std::endl;
std::cout << "constrained_intra_pred_flag: " << bs.get(1) << std::endl;
std::cout << "redundant_pic_cnt_present_flag: " << bs.get(1) << std::endl;
//check for more data
if (bs.size() == 0) {
return;
}
unsigned int transform_8x8_mode_flag = bs.get(1);
std::cout << "transform_8x8_mode_flag: " << transform_8x8_mode_flag << std::endl;
unsigned int pic_scaling_matrix_present_flag = bs.get(1);
std::cout << "pic_scaling_matrix_present_flag: " << pic_scaling_matrix_present_flag << std::endl;
if (pic_scaling_matrix_present_flag) {
for (unsigned int i = 0; i < 6 + ((chroma_format_idc != 3) ? 2 : 6)*transform_8x8_mode_flag ; i++) {
unsigned int pic_scaling_list_present_flag = bs.get(1);
std::cout << "pic_scaling_list_present_flag[" << i << "]: " << pic_scaling_list_present_flag << std::endl;
if (pic_scaling_list_present_flag) {
std::cout << "under development, pslpf" << std::endl;
return;
if (i < 6) {
//scaling list(ScalingList4x4[i],16,UseDefaultScalingMatrix4x4Flag[ i ])
} else {
//scaling_list(ScalingList4x4[i],64,UseDefaultScalingMatrix4x4Flag[ i-6 ])
}
}
}
}
std::cout << "second_chroma_qp_index_offset: " << bs.getExpGolomb() << std::endl;
}
} }
std::string NAL_Unit::SizePrepended(){
std::string Result;
if (MyData.size()){
int DataSize = MyData.size();
Result += (char)((DataSize & 0xFF000000) >> 24);
Result += (char)((DataSize & 0x00FF0000) >> 16);
Result += (char)((DataSize & 0x0000FF00) >> 8);
Result += (char)(DataSize & 0x000000FF); //Size Lead-In
Result += MyData;
}
return Result;
}
int NAL_Unit::Type(){
return (MyData[0] & 0x1F);
}

54
lib/nal.h Normal file → Executable file
View file

@ -1,15 +1,45 @@
#include <string> #include <string>
#include <cstdio> #include <cstdio>
class NAL_Unit{ namespace h264{
public:
NAL_Unit(); ///Struct containing pre-calculated metadata of an SPS nal unit. Width and height in pixels, fps in Hz
NAL_Unit(std::string & InputData); struct SPSMeta{
bool ReadData(std::string & InputData); unsigned int width;
std::string AnnexB(bool LongIntro = false); unsigned int height;
std::string SizePrepended(); double fps;
int Type(); };
private:
std::string MyData; ///Class for analyzing generic nal units
}; class NAL{
//NAL_Unit class public:
NAL();
NAL(std::string & InputData);
bool ReadData(std::string & InputData, bool raw = false);
std::string AnnexB(bool LongIntro = false);
std::string SizePrepended();
int Type();
std::string getData();
protected:
unsigned int chroma_format_idc;///<the value of chroma_format_idc
std::string MyData;///<The h264 nal unit data
};
//NAL class
///Special instance of NAL class for analyzing SPS nal units
class SPS: public NAL{
public:
SPS():NAL(){};
SPS(std::string & InputData, bool raw = false);
SPSMeta getCharacteristics();
void analyzeSPS();
};
///Special instance of NAL class for analyzing PPS nal units
class PPS: public NAL{
public:
PPS():NAL(){};
PPS(std::string & InputData):NAL(InputData){};
void analyzePPS();
};
}//ns h264

1034
lib/ts_packet.cpp Normal file → Executable file

File diff suppressed because it is too large Load diff

94
lib/ts_packet.h Normal file → Executable file
View file

@ -3,30 +3,46 @@
#pragma once #pragma once
#include <string> #include <string>
#include <map>
#include <cmath> #include <cmath>
#include <stdint.h>//for uint64_t #include <stdint.h>//for uint64_t
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
#include "dtsc.h" #include "dtsc.h"
/// Holds all TS processing related code. /// Holds all TS processing related code.
namespace TS { namespace TS {
/// Class for reading and writing TS Streams
class Packet{
///stores all the data of a pmt table. It must be mapped to a PID, and this is done in the function TS::getPMTTable(TS::Packet& packet)
///\todo Add more necessary variables, or find a more efficient way to store metadata
struct pmtinfo {
unsigned short streamtype;//the streamtype, 0x1b is h264, 0x0f is aac. These are used in aac, there may be (undiscovered) others
unsigned int trackid;//track id
std::string curPayload;//payload without PES/TS headers
long long int lastPEStime;//the pes time of the packet that was last seen
};
///Class for reading and writing TS Streams. The class is capable of analyzing a packet of 188 bytes
///and calculating key values
class Packet {
public: public:
Packet(); Packet();
~Packet(); ~Packet();
bool FromString(std::string & Data); bool FromString(std::string & Data);
bool FromPointer(char * Data);
bool FromFile(FILE * data);
void PID(int NewPID); void PID(int NewPID);
int PID(); unsigned int PID();
void ContinuityCounter(int NewContinuity); void ContinuityCounter(int NewContinuity);
int ContinuityCounter(); int ContinuityCounter();
void Clear(); void Clear();
void PCR(int64_t NewVal); void PCR(int64_t NewVal);
int64_t PCR(); int64_t PCR();
int64_t OPCR();
void AdaptationField(int NewVal); void AdaptationField(int NewVal);
int AdaptationField(); int AdaptationField();
int AdaptationFieldLen(); int AdaptationFieldLen();
@ -36,10 +52,29 @@ namespace TS {
void UnitStart(int NewVal); void UnitStart(int NewVal);
int RandomAccess(); int RandomAccess();
void RandomAccess(int NewVal); void RandomAccess(int NewVal);
int DiscontinuityIndicator();
int elementaryStreamPriorityIndicator();
int PCRFlag();
int OPCRFlag();
int splicingPointFlag();
//int transportPrivateDataFlag();
//int adaptationFieldExtensionFlag();
int BytesFree(); int BytesFree();
unsigned int getSyncByte();
unsigned int getTransportErrorIndicator();
unsigned int getPayloadUnitStartIndicator();
unsigned int getTransportPriority();
unsigned int getTransportScramblingControl();
std::string toPrettyString(size_t indent = 0); std::string toPrettyString(size_t indent = 0);
const char* ToString(); std::string getStrBuf();
const char * getBuffer();
const char * getPayload();
int getPayloadLength();
const char * ToString();
void PESVideoLeadIn(unsigned int NewLen, long long unsigned int PTS = 1); void PESVideoLeadIn(unsigned int NewLen, long long unsigned int PTS = 1);
void PESAudioLeadIn(unsigned int NewLen, uint64_t PTS = 0); void PESAudioLeadIn(unsigned int NewLen, uint64_t PTS = 0);
static void PESAudioLeadIn(std::string & toSend, long long unsigned int PTS); static void PESAudioLeadIn(std::string & toSend, long long unsigned int PTS);
@ -48,21 +83,56 @@ namespace TS {
static std::string & getPESVideoLeadIn(unsigned int NewLen, long long unsigned int PTS); static std::string & getPESVideoLeadIn(unsigned int NewLen, long long unsigned int PTS);
void FillFree(std::string & PackageData); void FillFree(std::string & PackageData);
int FillFree(const char* PackageData, int maxLen); int FillFree(const char * PackageData, int maxLen);
unsigned int AddStuffing(int NumBytes); unsigned int AddStuffing(int NumBytes);
private: protected:
//int Free; std::string strBuf;///<The actual data
std::string strBuf;
//char Buffer[188];///< The actual data //char Buffer[188];///< The actual data
}; };
//TS::Packet class
class ProgramAssociationTable : public Packet {
public:
char getOffset();
char getTableId();
short getSectionLength();
short getTransportStreamId();
char getVersionNumber();
bool getCurrentNextIndicator();
char getSectionNumber();
char getLastSectionNumber();
short getProgramCount();
short getProgramNumber(short index);
short getProgramPID(short index);
int getCRC();
std::string toPrettyString(size_t indent);
};
class ProgramMappingTable : public Packet {
public:
char getOffset();
char getTableId();
short getSectionLength();
short getProgramNumber();
char getVersionNumber();
bool getCurrentNextIndicator();
char getSectionNumber();
char getLastSectionNumber();
short getPCRPID();
short getProgramInfoLength();
short getProgramCount();
char getStreamType(short index);
short getElementaryPID(short index);
short getESInfoLength(short index);
int getCRC();
std::string toPrettyString(size_t indent);
};
/// Constructs an audio header to be used on each audio frame. /// Constructs an audio header to be used on each audio frame.
/// The length of this header will ALWAYS be 7 bytes, and has to be /// The length of this header will ALWAYS be 7 bytes, and has to be
/// prepended on each audio frame. /// prepended on each audio frame.
/// \param FrameLen the length of the current audio frame. /// \param FrameLen the length of the current audio frame.
/// \param initData A string containing the initalization data for this track's codec. /// \param initData A string containing the initalization data for this track's codec.
static inline std::string GetAudioHeader(int FrameLen, std::string initData){ static inline std::string GetAudioHeader(int FrameLen, std::string initData) {
char StandardHeader[7] = {0xFF, 0xF1, 0x00, 0x00, 0x00, 0x1F, 0xFC}; char StandardHeader[7] = {0xFF, 0xF1, 0x00, 0x00, 0x00, 0x1F, 0xFC};
FrameLen += 7; FrameLen += 7;
StandardHeader[2] = ((((initData[0] >> 3) - 1) << 6) & 0xC0); //AAC Profile - 1 ( First two bits ) StandardHeader[2] = ((((initData[0] >> 3) - 1) << 6) & 0xC0); //AAC Profile - 1 ( First two bits )
@ -75,6 +145,7 @@ namespace TS {
return std::string(StandardHeader, 7); return std::string(StandardHeader, 7);
} }
/// A standard Program Association Table, as generated by FFMPEG. /// A standard Program Association Table, as generated by FFMPEG.
/// Seems to be independent of the stream. /// Seems to be independent of the stream.
//0x47 = sync byte //0x47 = sync byte
@ -130,3 +201,4 @@ namespace TS {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
} //TS namespace } //TS namespace