From b28a619fc61a2f70531c1124f8975ec62f09ec50 Mon Sep 17 00:00:00 2001
From: Thulinma <jaron@vietors.com>
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<string>
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 <string>
#include "json.h"
+#include <signal.h>
/// 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 <cstdlib>
+#include <cstring>
+#include "bitfields.h"
+#include "bitstream.h"
+#include "defines.h"
+
+namespace h264 {
+ std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){
+ std::deque<nalu::nalData> 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 <deque>
+#include <string>
+
+#include "nal.h"
+
+namespace h264 {
+
+ std::deque<nalu::nalData> 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;///<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();
+ };
+
+
+ class sequenceParameterSet {
+ public:
+ sequenceParameterSet(const char * _data, unsigned long _dataLen);
+ SPSMeta getCharacteristics() const;
+ private:
+ const char * data;
+ unsigned long dataLen;
+ };
+
+}
diff --git a/lib/json.cpp b/lib/json.cpp
index 1b0f305b..fa2afa2f 100644
--- a/lib/json.cpp
+++ b/lib/json.cpp
@@ -657,12 +657,13 @@ JSON::Value & JSON::Value::operator[](const char * i) {
/// Retrieves or sets the JSON::Value at this position in the array.
/// Converts destructively to array if not already an array.
JSON::Value & JSON::Value::operator[](unsigned int i) {
+ static JSON::Value empty;
if (myType != ARRAY) {
null();
myType = ARRAY;
}
while (i >= 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 <cstdlib>
+#include <cstring>
+#include <math.h>//for log
+
#include "nal.h"
#include "bitstream.h"
+#include "bitfields.h"
#include "defines.h"
-#include <iostream>
-#include <iomanip>
-#include <math.h>//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<int> parseNalSizes(DTSC::Packet & pack){
+ std::deque<int> 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 <deque>
#include <string>
#include <cstdio>
+#include <deque>
+#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;///<the value of chroma_format_idc
- std::string MyData;///<The h264 nal unit data
- };
- //NAL class
+ std::deque<int> 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);