Merge branch 'development' into LTS_development

# Conflicts:
#	lib/bitstream.h
#	lib/h264.cpp
#	lib/h264.h
#	lib/nal.cpp
#	lib/nal.h
This commit is contained in:
Thulinma 2015-11-05 17:07:17 +01:00
commit 8bcda5e57b
12 changed files with 307 additions and 705 deletions

View file

@ -33,7 +33,7 @@ namespace Utils {
}
}
void bitstream::append(std::string input) {
void bitstream::append(const std::string & input) {
append((char *)input.c_str(), input.size());
}

View file

@ -1,3 +1,4 @@
#pragma once
#include<string>
namespace Utils {
@ -13,7 +14,7 @@ namespace Utils {
return *this;
};
void append(const char * input, size_t bytes);
void append(std::string input);
void append(const std::string & input);
long long unsigned int size();
void skip(size_t count);
long long unsigned int get(size_t count);

View file

@ -448,7 +448,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);
@ -466,7 +466,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:

View file

@ -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.

View file

@ -2,9 +2,24 @@
#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){
@ -26,36 +41,32 @@ namespace h264 {
}
unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result){
const char * lastCheck = data + dataSize - 3;
if (!result){
//first compute the new size. This might be the same as the annex b version, but this is not guaranteed
int offset = 0;
int newSize = 0;
while (offset < dataSize){
const char * begin = (const char*)memmem(data + offset, dataSize - offset, "\000\000\001", 3);
begin += 3;//Initialize begin after the first 0x000001 pattern.
const char * end = (const char*)memmem(begin, dataSize - (begin - data), "\000\000\001", 3);
if (end - data > dataSize){
end = data + dataSize;
}
//Check for 4-byte lead in's. Yes, we access -1 here
if (end[-1] == 0x00){
end--;
}
newSize += 4 + (end - begin);//end - begin = nalSize
offset = end - data;
}
result = (char *)malloc(newSize);
FAIL_MSG("No output buffer given to FromAnnexB");
return 0;
}
int offset = 0;
int newOffset = 0;
while (offset < dataSize){
const char * begin = ((const char*)memmem(data + offset, dataSize - offset, "\000\000\001", 3)) + 3;//Initialize begin after the first 0x000001 pattern.
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 - data > dataSize){
if (!end) {
end = data + dataSize;
}
//Check for 4-byte lead in's. Yes, we access -1 here
if (end[-1] == 0x00){
if (end > begin && end[-1] == 0x00){
end--;
}
unsigned int nalSize = end - begin;
@ -67,5 +78,113 @@ namespace h264 {
}
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;
}
}

View file

@ -1,4 +1,60 @@
#include <deque>
#include <string>
#include "nal.h"
namespace h264 {
unsigned long toAnnexB(const char * data, unsigned long dataSize, char *& result);
unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result);
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;
};
}

View file

@ -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];
}

View file

@ -1,12 +1,13 @@
#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 {
///Returns the nal sizes + 4 for size-prepend
namespace nalu {
std::deque<int> parseNalSizes(DTSC::Packet & pack){
std::deque<int> result;
char * data;
@ -21,622 +22,86 @@ namespace h264 {
return result;
}
std::deque<nalData> analyseH264Packet(const char * data, unsigned long len){
std::deque<nalData> res;
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 {
result[resPtr++] = data[dataPtr++];
}
}
while (dataPtr < dataLen){
result[resPtr++] = data[dataPtr++];
}
return result.substr(0, resPtr);
}
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 < len){
nalData entry;
entry.nalSize = Bit::btohl(data + offset);
entry.nalType = (data + offset)[4] & 0x1F;
res.push_back(entry);
offset += entry.nalSize + 4;
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 res;
return dataSize;
}
///empty constructor of NAL
NAL::NAL() {
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;
}
///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);
return newOffset;
}
///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;
}
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;
} 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;
}
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;
}
}

View file

@ -5,62 +5,15 @@
#include <deque>
#include "dtsc.h"
namespace h264 {
namespace nalu {
struct nalData {
unsigned char nalType;
unsigned long nalSize;
};
std::deque<nalData> analyseH264Packet(const char * data, unsigned long len);
std::deque<int> parseNalSizes(DTSC::Packet & pack);
std::string removeEmulationPrevention(const std::string & data);
///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;
};
}//ns h264
unsigned long toAnnexB(const char * data, unsigned long dataSize, char *& result);
unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result);
}

View file

@ -809,6 +809,7 @@ namespace IPC {
break;
default:
#ifndef NOCRASHCHECK
if (tmpPID){
if(*counter > 10 && *counter < 126 ){
if(*counter < 30){
if (*counter > 15){
@ -820,6 +821,7 @@ namespace IPC {
Util::Procs::Murder(tmpPID); //improved kill
}
}
}
#endif
break;
}

View file

@ -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) {

View file

@ -35,12 +35,12 @@ 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;
}
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;
}
pos=188;
@ -290,7 +290,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 << " ";
}
@ -300,10 +300,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);