From b28a619fc61a2f70531c1124f8975ec62f09ec50 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 5 Nov 2015 17:05:21 +0100 Subject: [PATCH] Various fixes and improvements, backported from Pro version. Code by Erik Zandvliet. --- lib/bitfields.h | 2 +- lib/bitstream.cpp | 4 +- lib/bitstream.h | 5 +- lib/config.cpp | 5 +- lib/config.h | 3 +- lib/h264.cpp | 190 ++++++++++++++ lib/h264.h | 60 +++++ lib/json.cpp | 3 +- lib/nal.cpp | 574 +++++++----------------------------------- lib/nal.h | 52 +--- lib/shared_memory.cpp | 18 +- lib/socket.cpp | 7 + lib/ts_packet.cpp | 10 +- 13 files changed, 383 insertions(+), 550 deletions(-) create mode 100644 lib/h264.cpp create mode 100644 lib/h264.h diff --git a/lib/bitfields.h b/lib/bitfields.h index bf57770b..0ca119a4 100644 --- a/lib/bitfields.h +++ b/lib/bitfields.h @@ -26,7 +26,7 @@ namespace Bit{ } /// Retrieves a long in network order from the pointer p. - inline unsigned long btohl(char * p) { + inline unsigned long btohl(const char * p) { return ((unsigned long)p[0] << 24) | ((unsigned long)p[1] << 16) | ((unsigned long)p[2] << 8) | p[3]; } diff --git a/lib/bitstream.cpp b/lib/bitstream.cpp index ef513913..b7617814 100644 --- a/lib/bitstream.cpp +++ b/lib/bitstream.cpp @@ -26,14 +26,14 @@ namespace Utils { } } - void bitstream::append(char * input, size_t bytes) { + void bitstream::append(const char * input, size_t bytes) { if (checkBufferSize(dataSize + bytes)) { memcpy(data + dataSize, input, bytes); dataSize += bytes; } } - void bitstream::append(std::string input) { + void bitstream::append(const std::string & input) { append((char *)input.c_str(), input.size()); } diff --git a/lib/bitstream.h b/lib/bitstream.h index d34d6424..bd623480 100644 --- a/lib/bitstream.h +++ b/lib/bitstream.h @@ -1,3 +1,4 @@ +#pragma once #include namespace Utils { @@ -12,8 +13,8 @@ namespace Utils { append(std::string(input, 1)); return *this; }; - void append(char * input, size_t bytes); - void append(std::string input); + void append(const char * input, size_t bytes); + void append(const std::string & input); long long unsigned int size(); void skip(size_t count); long long unsigned int get(size_t count); diff --git a/lib/config.cpp b/lib/config.cpp index a0abfc9d..660c07d5 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -434,7 +434,7 @@ void Util::Config::activate() { } struct sigaction new_action; struct sigaction cur_action; - new_action.sa_handler = signal_handler; + new_action.sa_sigaction = signal_handler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGINT, &new_action, NULL); @@ -452,7 +452,8 @@ void Util::Config::activate() { /// Basic signal handler. Sets is_active to false if it receives /// a SIGINT, SIGHUP or SIGTERM signal, reaps children for the SIGCHLD /// signal, and ignores all other signals. -void Util::Config::signal_handler(int signum) { +void Util::Config::signal_handler(int signum, siginfo_t * sigInfo, void * ignore) { + HIGH_MSG("Received signal %d from process %d", signum, sigInfo->si_pid); switch (signum) { case SIGINT: //these three signals will set is_active to false. case SIGHUP: diff --git a/lib/config.h b/lib/config.h index a070e6b6..af3d2c26 100644 --- a/lib/config.h +++ b/lib/config.h @@ -9,6 +9,7 @@ #include #include "json.h" +#include /// Contains utility code, not directly related to streaming media namespace Util { @@ -18,7 +19,7 @@ namespace Util { private: JSON::Value vals; ///< Holds all current config values int long_count; - static void signal_handler(int signum); + static void signal_handler(int signum, siginfo_t * sigInfo, void * ignore); public: //variables static bool is_active; ///< Set to true by activate(), set to false by the signal handler. diff --git a/lib/h264.cpp b/lib/h264.cpp new file mode 100644 index 00000000..6d6efd3b --- /dev/null +++ b/lib/h264.cpp @@ -0,0 +1,190 @@ +#include "h264.h" +#include +#include +#include "bitfields.h" +#include "bitstream.h" +#include "defines.h" + +namespace h264 { + std::deque analysePackets(const char * data, unsigned long len){ + std::deque res; + + int offset = 0; + while (offset < len){ + nalu::nalData entry; + entry.nalSize = Bit::btohl(data + offset); + entry.nalType = (data + offset)[4] & 0x1F; + res.push_back(entry); + offset += entry.nalSize + 4; + } + return res; + } + + unsigned long toAnnexB(const char * data, unsigned long dataSize, char *& result){ + //toAnnexB keeps the same size. + if (!result){ + result = (char *)malloc(dataSize); + } + int offset = 0; + while (offset < dataSize){ + //Read unit size + unsigned long unitSize = Bit::btohl(data + offset); + //Write annex b header + memset(result + offset, 0x00, 3); + result[offset + 3] = 0x01; + //Copy the nal unit + memcpy(result + offset + 4, data + offset + 4, unitSize); + //Update the offset + offset += 4 + unitSize; + } + return dataSize; + } + + unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result){ + const char * lastCheck = data + dataSize - 3; + if (!result){ + FAIL_MSG("No output buffer given to FromAnnexB"); + return 0; + } + int offset = 0; + int newOffset = 0; + while (offset < dataSize){ + const char * begin = data + offset; + while ( begin < lastCheck && !(!begin[0] && !begin[1] && begin[2] == 0x01)){ + begin++; + if (begin < lastCheck && begin[0]){ + begin++; + } + } + begin += 3;//Initialize begin after the first 0x000001 pattern. + if (begin > data + dataSize){ + offset = dataSize; + continue; + } + const char * end = (const char*)memmem(begin, dataSize - (begin - data), "\000\000\001", 3); + if (!end) { + end = data + dataSize; + } + //Check for 4-byte lead in's. Yes, we access -1 here + if (end > begin && end[-1] == 0x00){ + end--; + } + unsigned int nalSize = end - begin; + Bit::htobl(result + newOffset, nalSize); + memcpy(result + newOffset + 4, begin, nalSize); + + newOffset += 4 + nalSize; + offset = end - data; + } + return newOffset; + } + + sequenceParameterSet::sequenceParameterSet(const char * _data, unsigned long _dataLen) : data(_data), dataLen(_dataLen) {} + + SPSMeta sequenceParameterSet::getCharacteristics() const { + 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; + + //Fill the bitstream + Utils::bitstream bs; + for (unsigned int i = 1; i < dataLen; i++) { + if (i + 2 < dataLen && (memcmp(data + i, "\000\000\003", 3) == 0)){//Emulation prevention bytes + //Yes, we increase i here + bs.append(data + i, 2); + i += 2; + } else { + //No we don't increase i here + bs.append(data + 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; + } + +} + diff --git a/lib/h264.h b/lib/h264.h new file mode 100644 index 00000000..28cc693b --- /dev/null +++ b/lib/h264.h @@ -0,0 +1,60 @@ +#include +#include + +#include "nal.h" + +namespace h264 { + + std::deque analysePackets(const char * data, unsigned long len); + + ///Struct containing pre-calculated metadata of an SPS nal unit. Width and height in pixels, fps in Hz + struct SPSMeta { + unsigned int width; + unsigned int height; + double fps; + }; + + ///Class for analyzing generic nal units + class NAL { + 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;///= arrVal.size()) { - append(new JSON::Value()); + append(empty); } return *arrVal[i]; } diff --git a/lib/nal.cpp b/lib/nal.cpp index a7c430f7..3ba793b8 100644 --- a/lib/nal.cpp +++ b/lib/nal.cpp @@ -1,507 +1,107 @@ +#include +#include +#include //for log + #include "nal.h" #include "bitstream.h" +#include "bitfields.h" #include "defines.h" -#include -#include -#include //for log -namespace h264 { - ///empty constructor of NAL - NAL::NAL() { - - } - - ///Constructor capable of directly inputting NAL data from a string - ///\param InputData the nal input data, as a string - NAL::NAL(std::string & InputData) { - ReadData(InputData); - } - - ///Gets the raw NAL unit data, as a string - ///\return the raw NAL unit data - std::string NAL::getData() { - return MyData; - } - - ///Reads data from a string,either raw or annexed - ///\param InputData the h264 data, as string - ///\param raw a boolean that determines whether the string contains raw h264 data or not - bool NAL::ReadData(std::string & InputData, bool raw) { - if (raw) { - MyData = InputData; - InputData.clear(); - return true; +namespace nalu { + std::deque parseNalSizes(DTSC::Packet & pack){ + std::deque result; + char * data; + unsigned int dataLen; + pack.getString("data", data, dataLen); + int offset = 0; + while (offset < dataLen){ + int nalSize = Bit::btohl(data + offset); + result.push_back(nalSize + 4); + offset += nalSize + 4; } - 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; - } - bool AnnexB = false; - if (InputData.substr(0, 3) == ShortAnnexB) { - - AnnexB = true; - } - if (InputData.substr(0, 4) == FullAnnexB) { - 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)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; + std::string removeEmulationPrevention(const std::string & data) { + std::string result; + result.resize(data.size()); + result[0] = data[0]; + result[1] = data[1]; + unsigned int dataPtr = 2; + unsigned int dataLen = data.size(); + unsigned int resPtr = 2; + while (dataPtr + 2 < dataLen) { + if (!data[dataPtr] && !data[dataPtr + 1] && data[dataPtr + 2] == 3){ //We have found an emulation prevention + result[resPtr++] = data[dataPtr++]; + result[resPtr++] = data[dataPtr++]; + dataPtr++; //Skip the emulation prevention byte } else { - bs << MyData.substr(i, 1); + result[resPtr++] = data[dataPtr++]; } } - //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] - } - } - } - } + while (dataPtr < dataLen){ + result[resPtr++] = data[dataPtr++]; } - 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"); + return result.substr(0, resPtr); } - ///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; + unsigned long toAnnexB(const char * data, unsigned long dataSize, char *& result){ + //toAnnexB keeps the same size. + if (!result){ + result = (char *)malloc(dataSize); } - 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); - } + int offset = 0; + while (offset < dataSize){ + //Read unit size + unsigned long unitSize = Bit::btohl(data + offset); + //Write annex b header + memset(result + offset, 0x00, 3); + result[offset + 3] = 0x01; + //Copy the nal unit + memcpy(result + offset + 4, data + offset + 4, unitSize); + //Update the offset + offset += 4 + unitSize; } - //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; + return dataSize; } + unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result){ + const char * lastCheck = data + dataSize - 3; + if (!result){ + FAIL_MSG("No output buffer given to FromAnnexB"); + return 0; + } + int offset = 0; + int newOffset = 0; + while (offset < dataSize){ + const char * begin = data + offset; + while ( begin < lastCheck && !(!begin[0] && !begin[1] && begin[2] == 0x01)){ + begin++; + if (begin < lastCheck && begin[0]){ + begin++; + } + } + begin += 3;//Initialize begin after the first 0x000001 pattern. + if (begin > data + dataSize){ + offset = dataSize; + continue; + } + const char * end = (const char*)memmem(begin, dataSize - (begin - data), "\000\000\001", 3); + if (!end) { + end = data + dataSize; + } + //Check for 4-byte lead in's. Yes, we access -1 here + if (end > begin && (end - data) != dataSize && end[-1] == 0x00){ + end--; + } + unsigned int nalSize = end - begin; + Bit::htobl(result + newOffset, nalSize); + memcpy(result + newOffset + 4, begin, nalSize); + + newOffset += 4 + nalSize; + offset = end - data; + } + return newOffset; + } } - diff --git a/lib/nal.h b/lib/nal.h index 16403ce0..e1ad63ff 100644 --- a/lib/nal.h +++ b/lib/nal.h @@ -1,45 +1,19 @@ +#pragma once +#include #include #include +#include +#include "dtsc.h" -namespace h264 { - - ///Struct containing pre-calculated metadata of an SPS nal unit. Width and height in pixels, fps in Hz - struct SPSMeta { - unsigned int width; - unsigned int height; - double fps; +namespace nalu { + struct nalData { + unsigned char nalType; + unsigned long nalSize; }; - ///Class for analyzing generic nal units - class NAL { - 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;/// parseNalSizes(DTSC::Packet & pack); + std::string removeEmulationPrevention(const std::string & data); - ///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 + unsigned long toAnnexB(const char * data, unsigned long dataSize, char *& result); + unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result); +} diff --git a/lib/shared_memory.cpp b/lib/shared_memory.cpp index fa641992..c4fc6751 100644 --- a/lib/shared_memory.cpp +++ b/lib/shared_memory.cpp @@ -808,15 +808,17 @@ namespace IPC { break; default: #ifndef NOCRASHCHECK - if(*counter > 10 && *counter < 126 ){ - if(*counter < 30){ - if (*counter > 15){ - WARN_MSG("Process %d is unresponsive",tmpPID); + if (tmpPID){ + if(*counter > 10 && *counter < 126 ){ + if(*counter < 30){ + if (*counter > 15){ + WARN_MSG("Process %d is unresponsive",tmpPID); + } + Util::Procs::Stop(tmpPID); //soft kill + } else { + ERROR_MSG("Killing unresponsive process %d", tmpPID); + Util::Procs::Murder(tmpPID); //improved kill } - Util::Procs::Stop(tmpPID); //soft kill - } else { - ERROR_MSG("Killing unresponsive process %d", tmpPID); - Util::Procs::Murder(tmpPID); //improved kill } } #endif diff --git a/lib/socket.cpp b/lib/socket.cpp index c40b0614..f197bd36 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -1167,6 +1167,13 @@ int Socket::UDPConnection::bind(int port) { /// \return True if a packet was received, false otherwise. bool Socket::UDPConnection::Receive() { int r = recvfrom(sock, data, data_size, MSG_PEEK | MSG_TRUNC, 0, 0); + if (r == -1){ + if (errno != EAGAIN){ + INFO_MSG("Found an error: %d (%s)", errno, strerror(errno)); + } + data_len = 0; + return false; + } if (data_size < (unsigned int)r) { data = (char *)realloc(data, r); if (data) { diff --git a/lib/ts_packet.cpp b/lib/ts_packet.cpp index b943445b..ac41247c 100644 --- a/lib/ts_packet.cpp +++ b/lib/ts_packet.cpp @@ -30,13 +30,13 @@ namespace TS { /// \param Data The data to be read into the packet. /// \return true if it was possible to read in a full packet, false otherwise. bool Packet::FromFile(FILE * data) { - long long int pos = ftell(data); + long long int bPos = ftell(data); if (!fread((void *)strBuf, 188, 1, data)) { return false; } pos=188; if (strBuf[0] != 0x47){ - INFO_MSG("Failed to read a good packet on pos %lld", pos); + HIGH_MSG("Failed to read a good packet on pos %lld", bPos); return false; } return true; @@ -285,7 +285,7 @@ namespace TS { if (!(i % 32)){ output << std::endl << std::string(indent + 4, ' '); } - output << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)(strBuf+pos)[i] << " "; + output << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)(strBuf+188-size)[i] << " "; if ((i % 4) == 3){ output << " "; } @@ -295,10 +295,6 @@ namespace TS { return output.str(); } - /* - char * Packet::dataPointer(){ - return (char*)strBuf+pos;//.data() + 188 - dataSize(); - }*/ unsigned int Packet::getDataSize() const{ return 184 - ((getAdaptationField() > 1) ? getAdaptationFieldLen() + 1 : 0);