libmist backport from new metadata branch with improved typing and styling

This commit is contained in:
Erik Zandvliet 2018-11-28 12:16:00 +01:00 committed by Thulinma
parent 7a03d3e96c
commit 10fa4b7e7b
88 changed files with 5957 additions and 5757 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,15 +2,15 @@
/// Holds all headers for the AMF namespace. /// Holds all headers for the AMF namespace.
#pragma once #pragma once
#include <vector>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector>
/// Holds all AMF parsing and creation related functions and classes. /// Holds all AMF parsing and creation related functions and classes.
namespace AMF { namespace AMF{
/// Enumerates all possible AMF0 types, adding a special DDVTECH container type for ease of use. /// Enumerates all possible AMF0 types, adding a special DDVTECH container type for ease of use.
enum obj0type { enum obj0type{
AMF0_NUMBER = 0x00, AMF0_NUMBER = 0x00,
AMF0_BOOL = 0x01, AMF0_BOOL = 0x01,
AMF0_STRING = 0x02, AMF0_STRING = 0x02,
@ -33,7 +33,7 @@ namespace AMF {
}; };
/// Enumerates all possible AMF3 types, adding a special DDVTECH container type for ease of use. /// Enumerates all possible AMF3 types, adding a special DDVTECH container type for ease of use.
enum obj3type { enum obj3type{
AMF3_UNDEFINED = 0x00, AMF3_UNDEFINED = 0x00,
AMF3_NULL = 0x01, AMF3_NULL = 0x01,
AMF3_FALSE = 0x02, AMF3_FALSE = 0x02,
@ -51,26 +51,29 @@ namespace AMF {
}; };
/// Recursive class that holds AMF0 objects. /// Recursive class that holds AMF0 objects.
/// It supports all AMF0 types (defined in AMF::obj0type), adding support for a special DDVTECH container type. /// It supports all AMF0 types (defined in AMF::obj0type), adding support for a special DDVTECH
class Object { /// container type.
class Object{
public: public:
std::string Indice(); std::string Indice();
obj0type GetType(); obj0type GetType();
double NumValue(); double NumValue();
std::string StrValue(); std::string StrValue();
const char * Str(); const char *Str();
int hasContent(); int hasContent();
void addContent(AMF::Object c); void addContent(AMF::Object c);
Object * getContentP(unsigned int i); Object *getContentP(unsigned int i);
Object getContent(unsigned int i); Object getContent(unsigned int i);
Object * getContentP(std::string s); Object *getContentP(std::string s);
Object getContent(std::string s); Object getContent(std::string s);
Object(); Object();
Object(std::string indice, double val, obj0type setType = AMF0_NUMBER); Object(std::string indice, double val, obj0type setType = AMF0_NUMBER);
Object(std::string indice, std::string val, obj0type setType = AMF0_STRING); Object(std::string indice, std::string val, obj0type setType = AMF0_STRING);
Object(std::string indice, const char *val, obj0type setType = AMF0_STRING);
Object(std::string indice, obj0type setType = AMF0_OBJECT); Object(std::string indice, obj0type setType = AMF0_OBJECT);
std::string Print(std::string indent = ""); std::string Print(std::string indent = "");
std::string Pack(); std::string Pack();
protected: protected:
std::string myIndice; ///< Holds this objects indice, if any. std::string myIndice; ///< Holds this objects indice, if any.
obj0type myType; ///< Holds this objects AMF0 type. obj0type myType; ///< Holds this objects AMF0 type.
@ -78,30 +81,31 @@ namespace AMF {
double numval; ///< Holds this objects numeric value, if any. double numval; ///< Holds this objects numeric value, if any.
std::vector<Object> contents; ///< Holds this objects contents, if any (for container types). std::vector<Object> contents; ///< Holds this objects contents, if any (for container types).
}; };
//AMFType // AMFType
/// Parses a C-string to a valid AMF::Object. /// Parses a C-string to a valid AMF::Object.
Object parse(const unsigned char * data, unsigned int len); Object parse(const unsigned char *data, unsigned int len);
/// Parses a std::string to a valid AMF::Object. /// Parses a std::string to a valid AMF::Object.
Object parse(std::string data); Object parse(std::string data);
/// Parses a single AMF0 type - used recursively by the AMF::parse() functions. /// Parses a single AMF0 type - used recursively by the AMF::parse() functions.
Object parseOne(const unsigned char *& data, unsigned int & len, unsigned int & i, std::string name); Object parseOne(const unsigned char *&data, unsigned int &len, unsigned int &i, std::string name);
/// Recursive class that holds AMF3 objects. /// Recursive class that holds AMF3 objects.
/// It supports all AMF3 types (defined in AMF::obj3type), adding support for a special DDVTECH container type. /// It supports all AMF3 types (defined in AMF::obj3type), adding support for a special DDVTECH
class Object3 { /// container type.
class Object3{
public: public:
std::string Indice(); std::string Indice();
obj3type GetType(); obj3type GetType();
double DblValue(); double DblValue();
int IntValue(); int IntValue();
std::string StrValue(); std::string StrValue();
const char * Str(); const char *Str();
int hasContent(); int hasContent();
void addContent(AMF::Object3 c); void addContent(AMF::Object3 c);
Object3 * getContentP(int i); Object3 *getContentP(int i);
Object3 getContent(int i); Object3 getContent(int i);
Object3 * getContentP(std::string s); Object3 *getContentP(std::string s);
Object3 getContent(std::string s); Object3 getContent(std::string s);
Object3(); Object3();
Object3(std::string indice, int val, obj3type setType = AMF3_INTEGER); Object3(std::string indice, int val, obj3type setType = AMF3_INTEGER);
@ -110,6 +114,7 @@ namespace AMF {
Object3(std::string indice, obj3type setType = AMF3_OBJECT); Object3(std::string indice, obj3type setType = AMF3_OBJECT);
std::string Print(std::string indent = ""); std::string Print(std::string indent = "");
std::string Pack(); std::string Pack();
protected: protected:
std::string myIndice; ///< Holds this objects indice, if any. std::string myIndice; ///< Holds this objects indice, if any.
obj3type myType; ///< Holds this objects AMF0 type. obj3type myType; ///< Holds this objects AMF0 type.
@ -118,13 +123,15 @@ namespace AMF {
int intval; ///< Holds this objects int value, if any. int intval; ///< Holds this objects int value, if any.
std::vector<Object3> contents; ///< Holds this objects contents, if any (for container types). std::vector<Object3> contents; ///< Holds this objects contents, if any (for container types).
}; };
//AMFType // AMFType
/// Parses a C-string to a valid AMF::Object3. /// Parses a C-string to a valid AMF::Object3.
Object3 parse3(const unsigned char * data, unsigned int len); Object3 parse3(const unsigned char *data, unsigned int len);
/// Parses a std::string to a valid AMF::Object3. /// Parses a std::string to a valid AMF::Object3.
Object3 parse3(std::string data); Object3 parse3(std::string data);
/// Parses a single AMF3 type - used recursively by the AMF::parse3() functions. /// Parses a single AMF3 type - used recursively by the AMF::parse3() functions.
Object3 parseOne3(const unsigned char *& data, unsigned int & len, unsigned int & i, std::string name); Object3 parseOne3(const unsigned char *&data, unsigned int &len, unsigned int &i,
std::string name);
}// namespace AMF
} //AMF namespace

View file

@ -1,33 +1,32 @@
#include "bitfields.h" #include "bitfields.h"
#include <string.h> #include <string.h>
/// Takes a pointer, offset bitcount and data bitcount, returning the unsigned int read from the givens. /// Takes a pointer, offset bitcount and data bitcount, returning the unsigned int read from the
/// offsetBits may be > 7, in which case offsetBits / 8 is added to the pointer automatically. /// givens. offsetBits may be > 7, in which case offsetBits / 8 is added to the pointer
/// This function assumes Most Significant Bits first. /// automatically. This function assumes Most Significant Bits first. If dataBits > 64, only the
/// If dataBits > 64, only the last 64 bits are returned. /// last 64 bits are returned.
unsigned long long Bit::getMSB(char * pointer, unsigned int offsetBits, unsigned int dataBits){ unsigned long long Bit::getMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits){
//If the offset is a whole byte or more, add the whole bytes to the pointer instead. // If the offset is a whole byte or more, add the whole bytes to the pointer instead.
pointer += offsetBits >> 3; pointer += offsetBits >> 3;
//The offset is now guaranteed less than a whole byte. // The offset is now guaranteed less than a whole byte.
offsetBits &= 0x07; offsetBits &= 0x07;
unsigned long long retVal = 0; unsigned long long retVal = 0;
//Now we parse the remaining bytes // Now we parse the remaining bytes
while (dataBits){ while (dataBits){
//Calculate how many bits we're reading from this byte // Calculate how many bits we're reading from this byte
//We assume all except for the offset // We assume all except for the offset
unsigned int curBits = 8 - offsetBits; unsigned int curBits = 8 - offsetBits;
//If that is too much, we use the remainder instead // If that is too much, we use the remainder instead
if (curBits > dataBits){ if (curBits > dataBits){curBits = dataBits;}
curBits = dataBits; // First, shift the current return value by the amount of bits we're adding
}
//First, shift the current return value by the amount of bits we're adding
retVal <<= curBits; retVal <<= curBits;
//Next, add those bits from the current pointer position at the correct offset, increasing the pointer by one // Next, add those bits from the current pointer position at the correct offset, increasing the
// pointer by one
retVal |= ((int)(*(pointer++)) << offsetBits) >> (8 - curBits); retVal |= ((int)(*(pointer++)) << offsetBits) >> (8 - curBits);
//Finally, set the offset to zero and remove curBits from dataBits. // Finally, set the offset to zero and remove curBits from dataBits.
offsetBits = 0; offsetBits = 0;
dataBits -= curBits; dataBits -= curBits;
}//Loop until we run out of dataBits, then return the result }// Loop until we run out of dataBits, then return the result
return retVal; return retVal;
} }
@ -36,45 +35,42 @@ unsigned long long Bit::getMSB(char * pointer, unsigned int offsetBits, unsigned
/// This function assumes Most Significant Bits first. /// This function assumes Most Significant Bits first.
/// WARNING: UNFINISHED. DO NOT USE. /// WARNING: UNFINISHED. DO NOT USE.
/// \todo Finish writing this - untested atm. /// \todo Finish writing this - untested atm.
void Bit::setMSB(char * pointer, unsigned int offsetBits, unsigned int dataBits, unsigned long long value){ void Bit::setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits,
//Set the pointer to the last byte we need to be setting unsigned long long value){
// Set the pointer to the last byte we need to be setting
pointer += (offsetBits + dataBits) >> 3; pointer += (offsetBits + dataBits) >> 3;
//The offset is now guaranteed less than a whole byte. // The offset is now guaranteed less than a whole byte.
offsetBits = (offsetBits + dataBits) & 0x07; offsetBits = (offsetBits + dataBits) & 0x07;
unsigned long long retVal = 0; unsigned long long retVal = 0;
//Now we set the remaining bytes // Now we set the remaining bytes
while (dataBits){ while (dataBits){
//Calculate how many bits we're setting in this byte // Calculate how many bits we're setting in this byte
//We assume all that will fit in the current byte // We assume all that will fit in the current byte
unsigned int curBits = offsetBits; unsigned int curBits = offsetBits;
//If that is too much, we use the remainder instead // If that is too much, we use the remainder instead
if (curBits > dataBits){ if (curBits > dataBits){curBits = dataBits;}
curBits = dataBits; // Set the current pointer position at the correct offset, increasing the pointer by one
}
//Set the current pointer position at the correct offset, increasing the pointer by one
retVal |= ((int)(*(pointer++)) << offsetBits) >> (8 - curBits); retVal |= ((int)(*(pointer++)) << offsetBits) >> (8 - curBits);
*pointer = (((*pointer) << offsetBits) >> offsetBits) | ((value & 0xFF) << (8 - offsetBits)); *pointer = (((*pointer) << offsetBits) >> offsetBits) | ((value & 0xFF) << (8 - offsetBits));
--pointer; --pointer;
//Finally, shift the current value by the amount of bits we're adding // Finally, shift the current value by the amount of bits we're adding
value >>= offsetBits; value >>= offsetBits;
//... and set the offset to eight and remove curBits from dataBits. //... and set the offset to eight and remove curBits from dataBits.
offsetBits = 8; offsetBits = 8;
dataBits -= curBits; dataBits -= curBits;
}//Loop until we run out of dataBits, then return the result }// Loop until we run out of dataBits, then return the result
} }
/// Parses a string reference to a boolean. /// Parses a string reference to a boolean.
/// Returns true if the string, with whitespace removed and converted to lowercase, prefix-matches any of: "1", "yes", "true", "cont". /// Returns true if the string, with whitespace removed and converted to lowercase, prefix-matches
/// Returns false otherwise. /// any of: "1", "yes", "true", "cont". Returns false otherwise.
bool Util::stringToBool(std::string & str){ bool Util::stringToBool(std::string &str){
std::string tmp; std::string tmp;
tmp.reserve(4); tmp.reserve(4);
for (unsigned int i = 0; i < str.size() && tmp.size() < 4; ++i){ for (unsigned int i = 0; i < str.size() && tmp.size() < 4; ++i){
if (!::isspace(str[i])){ if (!::isspace(str[i])){tmp.push_back((char)tolower(str[i]));}
tmp.push_back((char)tolower(str[i]));
} }
} return (strncmp(tmp.c_str(), "1", 1) == 0 || strncmp(tmp.c_str(), "yes", 3) == 0 ||
return (strncmp(tmp.c_str(), "1", 1) == 0 || strncmp(tmp.c_str(), "yes", 3) == 0 || strncmp(tmp.c_str(), "true", 4) == 0 || strncmp(tmp.c_str(), "cont", 4) == 0); strncmp(tmp.c_str(), "true", 4) == 0 || strncmp(tmp.c_str(), "cont", 4) == 0);
} }

View file

@ -1,39 +1,38 @@
#pragma once #pragma once
#include "defines.h"
#include <string> #include <string>
#include <stdint.h>
namespace Util{ namespace Util{
bool stringToBool(std::string & str); bool stringToBool(std::string &str);
} }
namespace Bit{ namespace Bit{
//bitfield getters // bitfield getters
unsigned long long getMSB(char * pointer, unsigned int offsetBits, unsigned int dataBits); unsigned long long getMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits);
unsigned long long getByName(char * pointer); unsigned long long getByName(char *pointer);
//bitfield setters // bitfield setters
void setMSB(char * pointer, unsigned int offsetBits, unsigned int dataBits, unsigned long long value); void setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits,
void setByName(char * pointer); unsigned long long value);
void setByName(char *pointer);
//Host to binary/binary to host functions - similar to kernel ntoh/hton functions. // Host to binary/binary to host functions - similar to kernel ntoh/hton functions.
/// Retrieves a short in network order from the pointer p. /// Retrieves a short in network order from the pointer p.
inline unsigned short btohs(const char * p) { inline uint16_t btohs(const char *p){return ((uint16_t)p[0] << 8) | p[1];}
return ((unsigned short)p[0] << 8) | p[1];
}
/// Stores a short value of val in network order to the pointer p. /// Stores a short value of val in network order to the pointer p.
inline void htobs(char * p, unsigned short val) { inline void htobs(char *p, uint16_t val){
p[0] = (val >> 8) & 0xFF; p[0] = (val >> 8) & 0xFF;
p[1] = val & 0xFF; p[1] = val & 0xFF;
} }
/// Retrieves a long in network order from the pointer p. /// Retrieves a long in network order from the pointer p.
inline unsigned long btohl(const char * p) { inline uint32_t btohl(const char *p){
return ((unsigned long)p[0] << 24) | ((unsigned long)p[1] << 16) | ((unsigned long)p[2] << 8) | p[3]; return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
} }
/// Stores a long value of val in network order to the pointer p. /// Stores a long value of val in network order to the pointer p.
inline void htobl(char * p, unsigned long val) { inline void htobl(char *p, uint32_t val){
p[0] = (val >> 24) & 0xFF; p[0] = (val >> 24) & 0xFF;
p[1] = (val >> 16) & 0xFF; p[1] = (val >> 16) & 0xFF;
p[2] = (val >> 8) & 0xFF; p[2] = (val >> 8) & 0xFF;
@ -41,24 +40,25 @@ namespace Bit{
} }
/// Retrieves a long in network order from the pointer p. /// Retrieves a long in network order from the pointer p.
inline unsigned long btoh24(const char * p) { inline unsigned long btoh24(const char *p){
return ((unsigned long)p[0] << 16) | ((unsigned long)p[1] << 8) | p[2]; return ((unsigned long)p[0] << 16) | ((unsigned long)p[1] << 8) | p[2];
} }
/// Stores a long value of val in network order to the pointer p. /// Stores a long value of val in network order to the pointer p.
inline void htob24(char * p, unsigned long val) { inline void htob24(char *p, unsigned long val){
p[0] = (val >> 16) & 0xFF; p[0] = (val >> 16) & 0xFF;
p[1] = (val >> 8) & 0xFF; p[1] = (val >> 8) & 0xFF;
p[2] = val & 0xFF; p[2] = val & 0xFF;
} }
/// Retrieves a 40-bit uint in network order from the pointer p. /// Retrieves a 40-bit uint in network order from the pointer p.
inline uint64_t btoh40(const char * p) { inline uint64_t btoh40(const char *p){
return ((uint64_t)p[0] << 32) | ((uint64_t)p[1] << 24) | ((uint64_t)p[2] << 16) | ((uint64_t)p[3] << 8) | p[4]; return ((uint64_t)p[0] << 32) | ((uint64_t)p[1] << 24) | ((uint64_t)p[2] << 16) |
((uint64_t)p[3] << 8) | p[4];
} }
/// Stores a 40-bit uint value of val in network order to the pointer p. /// Stores a 40-bit uint value of val in network order to the pointer p.
inline void htob40(char * p, uint64_t val) { inline void htob40(char *p, uint64_t val){
p[0] = (val >> 32) & 0xFF; p[0] = (val >> 32) & 0xFF;
p[1] = (val >> 24) & 0xFF; p[1] = (val >> 24) & 0xFF;
p[2] = (val >> 16) & 0xFF; p[2] = (val >> 16) & 0xFF;
@ -67,12 +67,13 @@ namespace Bit{
} }
/// Retrieves a 48-bit uint in network order from the pointer p. /// Retrieves a 48-bit uint in network order from the pointer p.
inline uint64_t btoh48(const char * p) { inline uint64_t btoh48(const char *p){
return ((uint64_t)p[0] << 40) | ((uint64_t)p[1] << 32) | ((uint64_t)p[2] << 24) | ((uint64_t)p[3] << 16) | ((uint64_t)p[4] << 8) | p[5]; return ((uint64_t)p[0] << 40) | ((uint64_t)p[1] << 32) | ((uint64_t)p[2] << 24) |
((uint64_t)p[3] << 16) | ((uint64_t)p[4] << 8) | p[5];
} }
/// Stores a 48-bit uint value of val in network order to the pointer p. /// Stores a 48-bit uint value of val in network order to the pointer p.
inline void htob48(char * p, uint64_t val) { inline void htob48(char *p, uint64_t val){
p[0] = (val >> 40) & 0xFF; p[0] = (val >> 40) & 0xFF;
p[1] = (val >> 32) & 0xFF; p[1] = (val >> 32) & 0xFF;
p[2] = (val >> 24) & 0xFF; p[2] = (val >> 24) & 0xFF;
@ -82,12 +83,13 @@ namespace Bit{
} }
/// Retrieves a 56-bit uint in network order from the pointer p. /// Retrieves a 56-bit uint in network order from the pointer p.
inline uint64_t btoh56(const char * p) { inline uint64_t btoh56(const char *p){
return ((uint64_t)p[0] << 48) | ((uint64_t)p[1] << 40) | ((uint64_t)p[2] << 32) | ((uint64_t)p[3] << 24) | ((uint64_t)p[4] << 16) | ((uint64_t)p[5] << 8) | p[6]; return ((uint64_t)p[0] << 48) | ((uint64_t)p[1] << 40) | ((uint64_t)p[2] << 32) |
((uint64_t)p[3] << 24) | ((uint64_t)p[4] << 16) | ((uint64_t)p[5] << 8) | p[6];
} }
/// Stores a 56-bit uint value of val in network order to the pointer p. /// Stores a 56-bit uint value of val in network order to the pointer p.
inline void htob56(char * p, uint64_t val) { inline void htob56(char *p, uint64_t val){
p[0] = (val >> 48) & 0xFF; p[0] = (val >> 48) & 0xFF;
p[1] = (val >> 40) & 0xFF; p[1] = (val >> 40) & 0xFF;
p[2] = (val >> 32) & 0xFF; p[2] = (val >> 32) & 0xFF;
@ -98,12 +100,14 @@ namespace Bit{
} }
/// Retrieves a long long in network order from the pointer p. /// Retrieves a long long in network order from the pointer p.
inline unsigned long long btohll(const char * p) { inline uint64_t btohll(const char *p){
return ((unsigned long long)p[0] << 56) | ((unsigned long long)p[1] << 48) | ((unsigned long long)p[2] << 40) | ((unsigned long long)p[3] << 32) | ((unsigned long)p[4] << 24) | ((unsigned long)p[5] << 16) | ((unsigned long)p[6] << 8) | p[7]; return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) |
((uint64_t)p[3] << 32) | ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) |
((uint64_t)p[6] << 8) | p[7];
} }
/// Stores a long value of val in network order to the pointer p. /// Stores a long value of val in network order to the pointer p.
inline void htobll(char * p, unsigned long long val) { inline void htobll(char *p, unsigned long long val){
p[0] = (val >> 56) & 0xFF; p[0] = (val >> 56) & 0xFF;
p[1] = (val >> 48) & 0xFF; p[1] = (val >> 48) & 0xFF;
p[2] = (val >> 40) & 0xFF; p[2] = (val >> 40) & 0xFF;
@ -114,42 +118,37 @@ namespace Bit{
p[7] = val & 0xFF; p[7] = val & 0xFF;
} }
inline float btohf(const char * p){ inline float btohf(const char *p){
uint32_t tmp = btohl(p); uint32_t tmp = btohl(p);
return *reinterpret_cast<float*>(&tmp); return *reinterpret_cast<float *>(&tmp);
} }
inline void htobf(char * p, float val){ inline void htobf(char *p, float val){htobl(p, *reinterpret_cast<uint32_t *>(&val));}
htobl(p, *reinterpret_cast<unsigned long*>(&val));
}
inline double btohd(const char * p){ inline double btohd(const char *p){
uint64_t tmp = btohll(p); uint64_t tmp = btohll(p);
return *reinterpret_cast<double*>(&tmp); return *reinterpret_cast<double *>(&tmp);
} }
inline void htobd(char * p, double val){ inline void htobd(char *p, double val){htobll(p, *reinterpret_cast<uint32_t *>(&val));}
htobll(p, *reinterpret_cast<unsigned long*>(&val));
}
/// Retrieves a short in little endian from the pointer p. /// Retrieves a short in little endian from the pointer p.
inline unsigned short btohs_le(const char * p) { inline uint16_t btohs_le(const char *p){return ((uint16_t)p[1] << 8) | p[0];}
return ((unsigned short)p[1] << 8) | p[0];
}
/// Stores a short value of val in little endian to the pointer p. /// Stores a short value of val in little endian to the pointer p.
inline void htobs_le(char * p, unsigned short val) { inline void htobs_le(char *p, unsigned short val){
p[1] = (val >> 8) & 0xFF; p[1] = (val >> 8) & 0xFF;
p[0] = val & 0xFF; p[0] = val & 0xFF;
} }
/// Retrieves a long in network order from the pointer p. /// Retrieves a long in network order from the pointer p.
inline unsigned long btohl_le(const char * p) { inline unsigned long btohl_le(const char *p){
return ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0]; return ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) |
p[0];
} }
/// Stores a long value of val in little endian to the pointer p. /// Stores a long value of val in little endian to the pointer p.
inline void htobl_le(char * p, unsigned long val) { inline void htobl_le(char *p, unsigned long val){
p[3] = (val >> 24) & 0xFF; p[3] = (val >> 24) & 0xFF;
p[2] = (val >> 16) & 0xFF; p[2] = (val >> 16) & 0xFF;
p[1] = (val >> 8) & 0xFF; p[1] = (val >> 8) & 0xFF;
@ -157,24 +156,27 @@ namespace Bit{
} }
/// Retrieves a long in little endian from the pointer p. /// Retrieves a long in little endian from the pointer p.
inline unsigned long btoh24_le(const char * p) { inline unsigned long btoh24_le(const char *p){
return ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0]; return ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
} }
/// Stores a long value of val in network order to the pointer p. /// Stores a long value of val in network order to the pointer p.
inline void htob24_le(char * p, unsigned long val) { inline void htob24_le(char *p, unsigned long val){
p[2] = (val >> 16) & 0xFF; p[2] = (val >> 16) & 0xFF;
p[1] = (val >> 8) & 0xFF; p[1] = (val >> 8) & 0xFF;
p[0] = val & 0xFF; p[0] = val & 0xFF;
} }
/// Retrieves a long long in little endian from the pointer p. /// Retrieves a long long in little endian from the pointer p.
inline unsigned long long btohll_le(const char * p) { inline unsigned long long btohll_le(const char *p){
return ((unsigned long long)p[7] << 56) | ((unsigned long long)p[6] << 48) | ((unsigned long long)p[5] << 40) | ((unsigned long long)p[4] << 32) | ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0]; return ((unsigned long long)p[7] << 56) | ((unsigned long long)p[6] << 48) |
((unsigned long long)p[5] << 40) | ((unsigned long long)p[4] << 32) |
((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) |
p[0];
} }
/// Stores a long value of val in little endian to the pointer p. /// Stores a long value of val in little endian to the pointer p.
inline void htobll_le(char * p, unsigned long long val) { inline void htobll_le(char *p, unsigned long long val){
p[7] = (val >> 56) & 0xFF; p[7] = (val >> 56) & 0xFF;
p[6] = (val >> 48) & 0xFF; p[6] = (val >> 48) & 0xFF;
p[5] = (val >> 40) & 0xFF; p[5] = (val >> 40) & 0xFF;
@ -185,5 +187,5 @@ namespace Bit{
p[0] = val & 0xFF; p[0] = val & 0xFF;
} }
} }// namespace Bit

View file

@ -3,52 +3,55 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
namespace Utils { namespace Utils{
bitstream::bitstream() { bitstream::bitstream(){
data = NULL; data = NULL;
offset = 0; offset = 0;
dataSize = 0; dataSize = 0;
bufferSize = 0; bufferSize = 0;
} }
bool bitstream::checkBufferSize(unsigned int size) { bitstream::~bitstream(){
if (size > bufferSize) { if (!data){return;}
void * temp = realloc(data, size); free(data);
if (temp) { bufferSize = 0;
data = (char *) temp; dataSize = 0;
bufferSize = size; offset = 0;
return true;
} else {
return false;
}
} else {
return true;
}
} }
void bitstream::append(const char * input, size_t bytes) { bool bitstream::checkBufferSize(unsigned int size){
if (checkBufferSize(dataSize + bytes)) { if (size <= bufferSize){return true;}
void *temp = realloc(data, size);
if (!temp){return false;}
data = (char *)temp;
bufferSize = size;
return true;
}
void bitstream::append(const char *input, size_t bytes){
if (checkBufferSize(dataSize + bytes)){
memcpy(data + dataSize, input, bytes); memcpy(data + dataSize, input, bytes);
dataSize += bytes; dataSize += bytes;
} }
} }
void bitstream::append(const std::string & input) { void bitstream::append(const std::string &input){append((char *)input.c_str(), input.size());}
append((char *)input.c_str(), input.size());
}
bool bitstream::peekOffset(size_t peekOffset) { bool bitstream::peekOffset(size_t peekOffset){
peekOffset += offset; peekOffset += offset;
return ((data[peekOffset >> 3]) >> (7 - (peekOffset & 7))) & 1; return ((data[peekOffset >> 3]) >> (7 - (peekOffset & 7))) & 1;
} }
long long unsigned int bitstream::peek(size_t count) { long long unsigned int bitstream::peek(size_t count){
if (count > 64) { if (count > 64){
DEBUG_MSG(DLVL_WARN, "Can not read %d bits into a long long unsigned int!", (int)count); DEBUG_MSG(DLVL_WARN, "Can not read %d bits into a long long unsigned int!", (int)count);
//return 0; // return 0;
} }
if (count > size()) { if (count > size()){
DEBUG_MSG(DLVL_ERROR, "Not enough bits left in stream. Left: %d requested: %d", (int)size(), (int)count); DEBUG_MSG(DLVL_ERROR, "Not enough bits left in stream. Left: %d requested: %d", (int)size(),
(int)count);
return 0; return 0;
} }
long long unsigned int retval = 0; long long unsigned int retval = 0;
@ -56,21 +59,21 @@ namespace Utils {
size_t readSize; size_t readSize;
size_t readOff; size_t readOff;
char readBuff; char readBuff;
while (curPlace < count) { while (curPlace < count){
readBuff = data[(int)((offset + curPlace) / 8)]; readBuff = data[(int)((offset + curPlace) / 8)];
readSize = 8; readSize = 8;
readOff = (offset + curPlace) % 8; //the reading offset within the byte readOff = (offset + curPlace) % 8; // the reading offset within the byte
if (readOff != 0) { if (readOff != 0){
//if we start our read not on the start of a byte // if we start our read not on the start of a byte
//curplace and retval should both be 0 // curplace and retval should both be 0
//this should be the first read that aligns reading to bytes, if we read over the end of read byte // this should be the first read that aligns reading to bytes, if we read over the end of
//we cut the MSb off of the buffer by bit mask // read byte we cut the MSb off of the buffer by bit mask
readSize -= readOff;//defining starting bit readSize -= readOff; // defining starting bit
readBuff = readBuff & ((1 << readSize) - 1);//bitmasking readBuff = readBuff & ((1 << readSize) - 1); // bitmasking
} }
//up until here we assume we read to the end of the byte // up until here we assume we read to the end of the byte
if (count - curPlace < readSize) { //if we do not read to the end of the byte if (count - curPlace < readSize){// if we do not read to the end of the byte
//we cut off the LSb off of the read buffer by bitshift // we cut off the LSb off of the read buffer by bitshift
readSize = count - curPlace; readSize = count - curPlace;
readBuff = readBuff >> (8 - readSize - readOff); readBuff = readBuff >> (8 - readSize - readOff);
} }
@ -80,77 +83,67 @@ namespace Utils {
return retval; return retval;
} }
long long unsigned int bitstream::get(size_t count) { long long unsigned int bitstream::get(size_t count){
if (count <= size()) { if (count <= size()){
long long unsigned int retVal; long long unsigned int retVal;
retVal = peek(count); retVal = peek(count);
skip(count); skip(count);
return retVal; return retVal;
} else { }else{
return 0; return 0;
} }
} }
void bitstream::skip(size_t count) { void bitstream::skip(size_t count){
if (count <= size()) { if (count <= size()){
offset += count; offset += count;
} else { }else{
offset = dataSize * 8; offset = dataSize * 8;
} }
} }
long long unsigned int bitstream::size() { long long unsigned int bitstream::size(){return (dataSize * 8) - offset;}
return (dataSize * 8) - offset;
}
void bitstream::clear() { void bitstream::clear(){
dataSize = 0; dataSize = 0;
offset = 0; offset = 0;
} }
void bitstream::flush() { void bitstream::flush(){
memmove(data, data + (offset / 8), dataSize - (offset / 8)); memmove(data, data + (offset / 8), dataSize - (offset / 8));
dataSize -= offset / 8; dataSize -= offset / 8;
offset %= 8; offset %= 8;
} }
long long unsigned int bitstream::golombPeeker() { long long unsigned int bitstream::golombPeeker(){
for (size_t i = 0; i < 64 && i < size(); i++) { for (size_t i = 0; i < 64 && i < size(); i++){
if (peekOffset(i)) { if (peekOffset(i)){return peek((i * 2) + 1);}
return peek((i * 2) + 1);
}
} }
return 0; return 0;
} }
long long unsigned int bitstream::golombGetter() { long long unsigned int bitstream::golombGetter(){
for (size_t i = 0; i < 64 && i < size(); i++) { for (size_t i = 0; i < 64 && i < size(); i++){
if (peekOffset(i)) { if (peekOffset(i)){return get((i * 2) + 1);}
return get((i * 2) + 1);
}
} }
return 0; return 0;
} }
long long int bitstream::getExpGolomb() { long long int bitstream::getExpGolomb(){
long long unsigned int temp = golombGetter(); long long unsigned int temp = golombGetter();
return (temp >> 1) * (1 - ((temp & 1) << 1)); //Is actually return (temp / 2) * (1 - (temp & 1) * 2); return (temp >> 1) *
(1 - ((temp & 1) << 1)); // Is actually return (temp / 2) * (1 - (temp & 1) * 2);
} }
long long unsigned int bitstream::getUExpGolomb() { long long unsigned int bitstream::getUExpGolomb(){return golombGetter() - 1;}
return golombGetter() - 1;
}
long long int bitstream::peekExpGolomb() { long long int bitstream::peekExpGolomb(){
long long unsigned int temp = golombPeeker(); long long unsigned int temp = golombPeeker();
return (temp >> 1) * (1 - ((temp & 1) << 1)); //Is actually return (temp / 2) * (1 - (temp & 1) * 2); return (temp >> 1) *
} (1 - ((temp & 1) << 1)); // Is actually return (temp / 2) * (1 - (temp & 1) * 2);
long long unsigned int bitstream::peekUExpGolomb() {
return golombPeeker() - 1;
} }
long long unsigned int bitstream::peekUExpGolomb(){return golombPeeker() - 1;}
bitWriter::bitWriter(){ bitWriter::bitWriter(){
dataBuffer = NULL; dataBuffer = NULL;
@ -160,18 +153,16 @@ namespace Utils {
} }
bitWriter::~bitWriter(){ bitWriter::~bitWriter(){
if (dataBuffer != NULL){ if (dataBuffer != NULL){free(dataBuffer);}
free(dataBuffer);
}
} }
void bitWriter::reallocate(size_t newSize){ void bitWriter::reallocate(size_t newSize){
size_t sizeBefore = bufferSize / 8; size_t sizeBefore = bufferSize / 8;
char * tmp; char *tmp;
if (dataBuffer != NULL){ if (dataBuffer != NULL){
tmp = (char*)realloc(dataBuffer, (newSize / 8) + 1); tmp = (char *)realloc(dataBuffer, (newSize / 8) + 1);
}else{ }else{
tmp = (char*)malloc((newSize / 8) + 1); tmp = (char *)malloc((newSize / 8) + 1);
} }
if (tmp){ if (tmp){
dataBuffer = tmp; dataBuffer = tmp;
@ -182,20 +173,16 @@ namespace Utils {
} }
} }
size_t bitWriter::size() { size_t bitWriter::size(){return dataSize;}
return dataSize;
}
void bitWriter::append(uint64_t value, size_t bitLength){ void bitWriter::append(uint64_t value, size_t bitLength){
if (dataSize + bitLength > bufferSize){ if (dataSize + bitLength > bufferSize){reallocate(dataSize + bitLength);}
reallocate(dataSize + bitLength);
}
int64_t fullShift = (bitLength / 8) * 8; int64_t fullShift = (bitLength / 8) * 8;
uint64_t firstMask = ((0x01ull << (bitLength % 8)) - 1) << fullShift; uint64_t firstMask = ((0x01ull << (bitLength % 8)) - 1) << fullShift;
appendData( ((value & firstMask) >> fullShift), bitLength - fullShift); appendData(((value & firstMask) >> fullShift), bitLength - fullShift);
while (fullShift > 0) { while (fullShift > 0){
fullShift -= 8; fullShift -= 8;
uint64_t mask = (0xFFull) << fullShift; uint64_t mask = (0xFFull) << fullShift;
appendData((value & mask) >> fullShift, 8); appendData((value & mask) >> fullShift, 8);
@ -217,7 +204,7 @@ namespace Utils {
} }
size_t bitWriter::UExpGolombEncodedSize(uint64_t value){ size_t bitWriter::UExpGolombEncodedSize(uint64_t value){
value ++; value++;
size_t res = 1; size_t res = 1;
size_t maxVal = 1; size_t maxVal = 1;
while (value > maxVal){ while (value > maxVal){
@ -240,29 +227,26 @@ namespace Utils {
append(value + 1, UExpGolombEncodedSize(value)); append(value + 1, UExpGolombEncodedSize(value));
} }
// Note: other bitstream here
//Note: other bitstream here bitstreamLSBF::bitstreamLSBF(){
bitstreamLSBF::bitstreamLSBF() {
readBufferOffset = 0; readBufferOffset = 0;
readBuffer = 0; readBuffer = 0;
} }
void bitstreamLSBF::append(char * input, size_t bytes) { void bitstreamLSBF::append(char *input, size_t bytes){
data.append(input, bytes); data.append(input, bytes);
fixData(); fixData();
} }
void bitstreamLSBF::append(std::string & input) { void bitstreamLSBF::append(std::string &input){
data += input; data += input;
fixData(); fixData();
} }
long long unsigned int bitstreamLSBF::size() { long long unsigned int bitstreamLSBF::size(){return data.size() * 8 + readBufferOffset;}
return data.size() * 8 + readBufferOffset;
}
long long unsigned int bitstreamLSBF::get(size_t count) { long long unsigned int bitstreamLSBF::get(size_t count){
if (count <= 32 && count <= readBufferOffset) { if (count <= 32 && count <= readBufferOffset){
long long unsigned int retval = readBuffer & (((long long unsigned int)1 << count) - 1); long long unsigned int retval = readBuffer & (((long long unsigned int)1 << count) - 1);
readBuffer = readBuffer >> count; readBuffer = readBuffer >> count;
readBufferOffset -= count; readBufferOffset -= count;
@ -272,34 +256,33 @@ namespace Utils {
return 42; return 42;
} }
void bitstreamLSBF::skip(size_t count) { void bitstreamLSBF::skip(size_t count){
if (count <= 32 && count <= readBufferOffset) { if (count <= 32 && count <= readBufferOffset){
readBuffer = readBuffer >> count; readBuffer = readBuffer >> count;
readBufferOffset -= count; readBufferOffset -= count;
fixData(); fixData();
} }
} }
long long unsigned int bitstreamLSBF::peek(size_t count) { long long unsigned int bitstreamLSBF::peek(size_t count){
if (count <= 32 && count <= readBufferOffset) { if (count <= 32 && count <= readBufferOffset){return readBuffer & ((1 << count) - 1);}
return readBuffer & ((1 << count) - 1);
}
return 0; return 0;
} }
void bitstreamLSBF::clear() { void bitstreamLSBF::clear(){
data = ""; data = "";
readBufferOffset = 0; readBufferOffset = 0;
readBuffer = 0; readBuffer = 0;
} }
void bitstreamLSBF::fixData() { void bitstreamLSBF::fixData(){
unsigned int pos=0; unsigned int pos = 0;
while (readBufferOffset <= 32 && data.size() != 0) { while (readBufferOffset <= 32 && data.size() != 0){
readBuffer |= (((long long unsigned int)data[pos]) << readBufferOffset); readBuffer |= (((long long unsigned int)data[pos]) << readBufferOffset);
pos++; pos++;
readBufferOffset += 8; readBufferOffset += 8;
} }
data.erase(0, pos); data.erase(0, pos);
} }
} }// namespace Utils

View file

@ -1,21 +1,22 @@
#pragma once #pragma once
#include<string>
#include "defines.h" #include "defines.h"
#include <string>
namespace Utils { namespace Utils{
class bitstream { class bitstream{
public: public:
bitstream(); bitstream();
bitstream & operator<< (std::string input) { bitstream &operator<<(std::string input){
append(input); append(input);
return *this; return *this;
}; }
bitstream & operator<< (char input) { bitstream &operator<<(char input){
append(std::string(input, 1)); append(std::string(input, 1));
return *this; return *this;
}; }
void append(const char * input, size_t bytes); ~bitstream();
void append(const std::string & input); void append(const char *input, size_t bytes);
void append(const std::string &input);
long long unsigned int size(); long long unsigned int size();
void skip(size_t count); void skip(size_t count);
long long unsigned int get(size_t count); long long unsigned int get(size_t count);
@ -32,7 +33,7 @@ namespace Utils {
size_t i = 1; size_t i = 1;
size_t power = 2; size_t power = 2;
while (power - 2 < value){ while (power - 2 < value){
i+= 2; i += 2;
power *= 2; power *= 2;
} }
return i; return i;
@ -42,13 +43,13 @@ namespace Utils {
bool checkBufferSize(unsigned int size); bool checkBufferSize(unsigned int size);
long long unsigned int golombGetter(); long long unsigned int golombGetter();
long long unsigned int golombPeeker(); long long unsigned int golombPeeker();
char * data; char *data;
size_t offset; size_t offset;
size_t dataSize; size_t dataSize;
size_t bufferSize; size_t bufferSize;
}; };
class bitWriter { class bitWriter{
public: public:
bitWriter(); bitWriter();
~bitWriter(); ~bitWriter();
@ -57,38 +58,39 @@ namespace Utils {
void appendExpGolomb(int64_t value); void appendExpGolomb(int64_t value);
void appendUExpGolomb(uint64_t value); void appendUExpGolomb(uint64_t value);
static size_t UExpGolombEncodedSize(uint64_t value); static size_t UExpGolombEncodedSize(uint64_t value);
std::string str() { return std::string(dataBuffer, (dataSize / 8) + (dataSize % 8 ? 1 : 0)); } std::string str(){return std::string(dataBuffer, (dataSize / 8) + (dataSize % 8 ? 1 : 0));}
protected: protected:
void reallocate(size_t newSize); void reallocate(size_t newSize);
void appendData(uint8_t data, size_t len); void appendData(uint8_t data, size_t len);
char * dataBuffer; char *dataBuffer;
//NOTE: ALL SIZES IN BITS! // NOTE: ALL SIZES IN BITS!
size_t bufferSize; size_t bufferSize;
size_t dataSize; size_t dataSize;
}; };
class bitstreamLSBF { class bitstreamLSBF{
public: public:
bitstreamLSBF(); bitstreamLSBF();
bitstreamLSBF & operator<< (std::string input) { bitstreamLSBF &operator<<(std::string input){
append(input); append(input);
return *this; return *this;
}; }
void append(char * input, size_t bytes); void append(char *input, size_t bytes);
void append(std::string & input); void append(std::string &input);
long long unsigned int size(); long long unsigned int size();
void skip(size_t count); void skip(size_t count);
long long unsigned int get(size_t count); long long unsigned int get(size_t count);
long long unsigned int peek(size_t count); long long unsigned int peek(size_t count);
void clear(); void clear();
std::string data; std::string data;
private: private:
long long unsigned int readBuffer; long long unsigned int readBuffer;
unsigned int readBufferOffset; unsigned int readBufferOffset;
void fixData(); void fixData();
}; };
} }// namespace Utils

View file

@ -3,11 +3,11 @@
#include "config.h" #include "config.h"
#include "defines.h" #include "defines.h"
#include "stream.h"
#include "timing.h" #include "timing.h"
#include "tinythread.h" #include "tinythread.h"
#include "stream.h"
#include <string.h>
#include <signal.h> #include <signal.h>
#include <string.h>
#ifdef __CYGWIN__ #ifdef __CYGWIN__
#include <windows.h> #include <windows.h>
@ -21,35 +21,35 @@
#if defined(__APPLE__) #if defined(__APPLE__)
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#endif #endif
#include "procs.h"
#include <dirent.h> //for getMyExec
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <getopt.h>
#include <iostream> #include <iostream>
#include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <getopt.h>
#include <stdlib.h>
#include <fstream>
#include <dirent.h> //for getMyExec
#include "procs.h"
bool Util::Config::is_active = false; bool Util::Config::is_active = false;
static Socket::Server * serv_sock_pointer = 0; static Socket::Server *serv_sock_pointer = 0;
unsigned int Util::Config::printDebugLevel = DEBUG;// uint32_t Util::Config::printDebugLevel = DEBUG; //
std::string Util::Config::streamName; std::string Util::Config::streamName;
Util::Config::Config() { Util::Config::Config(){
//global options here // global options here
vals["debug"]["long"] = "debug"; vals["debug"]["long"] = "debug";
vals["debug"]["short"] = "g"; vals["debug"]["short"] = "g";
vals["debug"]["arg"] = "integer"; vals["debug"]["arg"] = "integer";
vals["debug"]["help"] = "The debug level at which messages need to be printed."; vals["debug"]["help"] = "The debug level at which messages need to be printed.";
vals["debug"]["value"].append((long long)DEBUG); vals["debug"]["value"].append((int64_t)DEBUG);
} }
/// Creates a new configuration manager. /// Creates a new configuration manager.
Util::Config::Config(std::string cmd) { Util::Config::Config(std::string cmd){
vals.null(); vals.null();
long_count = 2; long_count = 2;
vals["cmd"]["value"].append(cmd); vals["cmd"]["value"].append(cmd);
@ -63,194 +63,182 @@ Util::Config::Config(std::string cmd) {
vals["debug"]["short"] = "g"; vals["debug"]["short"] = "g";
vals["debug"]["arg"] = "integer"; vals["debug"]["arg"] = "integer";
vals["debug"]["help"] = "The debug level at which messages need to be printed."; vals["debug"]["help"] = "The debug level at which messages need to be printed.";
vals["debug"]["value"].append((long long)DEBUG); vals["debug"]["value"].append((int64_t)DEBUG);
} }
/// Adds an option to the configuration parser. /// Adds an option to the configuration parser.
/// The option needs an unique name (doubles will overwrite the previous) and can contain the following in the option itself: /// The option needs an unique name (doubles will overwrite the previous) and can contain the
/// following in the option itself:
///\code ///\code
/// { ///{
/// "short":"o", //The short option letter /// "short":"o", //The short option letter
/// "long":"onName", //The long option /// "long":"onName", //The long option
/// "arg":"integer", //The type of argument, if required. /// "arg":"integer", //The type of argument, if required.
/// "value":[], //The default value(s) for this option if it is not given on the commandline. /// "value":[], //The default value(s) for this option if it is not given on the
/// "arg_num":1, //The count this value has on the commandline, after all the options have been processed. /// commandline. "arg_num":1, //The count this value has on the commandline, after all
/// "help":"Blahblahblah" //The helptext for this option. /// the options have been processed. "help":"Blahblahblah" //The helptext for this option.
/// } ///}
///\endcode ///\endcode
void Util::Config::addOption(std::string optname, JSON::Value option) { void Util::Config::addOption(std::string optname, JSON::Value option){
vals[optname] = option; vals[optname] = option;
if (!vals[optname].isMember("value") && vals[optname].isMember("default")) { if (!vals[optname].isMember("value") && vals[optname].isMember("default")){
vals[optname]["value"].append(vals[optname]["default"]); vals[optname]["value"].append(vals[optname]["default"]);
vals[optname].removeMember("default"); vals[optname].removeMember("default");
} }
long_count = 0; long_count = 0;
jsonForEach(vals, it) { jsonForEach(vals, it){
if (it->isMember("long")) { if (it->isMember("long")){long_count++;}
long_count++;
}
} }
} }
/// Prints a usage message to the given output. /// Prints a usage message to the given output.
void Util::Config::printHelp(std::ostream & output) { void Util::Config::printHelp(std::ostream &output){
unsigned int longest = 0; unsigned int longest = 0;
std::map<long long int, std::string> args; std::map<long long int, std::string> args;
jsonForEach(vals, it) { jsonForEach(vals, it){
unsigned int current = 0; unsigned int current = 0;
if (it->isMember("long")) { if (it->isMember("long")){current += (*it)["long"].asString().size() + 4;}
current += (*it)["long"].asString().size() + 4; if (it->isMember("short")){current += (*it)["short"].asString().size() + 3;}
} if (current > longest){longest = current;}
if (it->isMember("short")) {
current += (*it)["short"].asString().size() + 3;
}
if (current > longest) {
longest = current;
}
current = 0; current = 0;
if (current > longest) { if (current > longest){longest = current;}
longest = current; if (it->isMember("arg_num")){
}
if (it->isMember("arg_num")) {
current = it.key().size() + 3; current = it.key().size() + 3;
if (current > longest) { if (current > longest){longest = current;}
longest = current;
}
args[(*it)["arg_num"].asInt()] = it.key(); args[(*it)["arg_num"].asInt()] = it.key();
} }
} }
output << "Usage: " << getString("cmd") << " [options]"; output << "Usage: " << getString("cmd") << " [options]";
for (std::map<long long int, std::string>::iterator i = args.begin(); i != args.end(); i++) { for (std::map<long long int, std::string>::iterator i = args.begin(); i != args.end(); i++){
if (vals[i->second].isMember("value") && vals[i->second]["value"].size()) { if (vals[i->second].isMember("value") && vals[i->second]["value"].size()){
output << " [" << i->second << "]"; output << " [" << i->second << "]";
} else { }else{
output << " " << i->second; output << " " << i->second;
} }
} }
output << std::endl << std::endl; output << std::endl << std::endl;
jsonForEach(vals, it) { jsonForEach(vals, it){
std::string f; std::string f;
if (it->isMember("long") || it->isMember("short")) { if (it->isMember("long") || it->isMember("short")){
if (it->isMember("long") && it->isMember("short")) { if (it->isMember("long") && it->isMember("short")){
f = "--" + (*it)["long"].asString() + ", -" + (*it)["short"].asString(); f = "--" + (*it)["long"].asString() + ", -" + (*it)["short"].asString();
} else { }else{
if (it->isMember("long")) { if (it->isMember("long")){f = "--" + (*it)["long"].asString();}
f = "--" + (*it)["long"].asString(); if (it->isMember("short")){f = "-" + (*it)["short"].asString();}
} }
if (it->isMember("short")) { while (f.size() < longest){f.append(" ");}
f = "-" + (*it)["short"].asString(); if (it->isMember("arg")){
} output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString()
} << std::endl;
while (f.size() < longest) { }else{
f.append(" ");
}
if (it->isMember("arg")) {
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() << std::endl;
} else {
output << f << (*it)["help"].asString() << std::endl; output << f << (*it)["help"].asString() << std::endl;
} }
} }
if (it->isMember("arg_num")) { if (it->isMember("arg_num")){
f = it.key(); f = it.key();
while (f.size() < longest) { while (f.size() < longest){f.append(" ");}
f.append(" "); output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString()
} << std::endl;
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() << std::endl;
} }
} }
} }
/// Parses commandline arguments. /// Parses commandline arguments.
/// Calls exit if an unknown option is encountered, printing a help message. /// Calls exit if an unknown option is encountered, printing a help message.
bool Util::Config::parseArgs(int & argc, char ** & argv) { bool Util::Config::parseArgs(int &argc, char **&argv){
int opt = 0; int opt = 0;
std::string shortopts; std::string shortopts;
struct option * longOpts = (struct option *)calloc(long_count + 1, sizeof(struct option)); struct option *longOpts = (struct option *)calloc(long_count + 1, sizeof(struct option));
int long_i = 0; int long_i = 0;
int arg_count = 0; int arg_count = 0;
if (vals.size()) { if (vals.size()){
jsonForEach(vals, it) { jsonForEach(vals, it){
if (it->isMember("short")) { if (it->isMember("short")){
shortopts += (*it)["short"].asString(); shortopts += (*it)["short"].asString();
if (it->isMember("arg")) { if (it->isMember("arg")){shortopts += ":";}
shortopts += ":";
} }
} if (it->isMember("long")){
if (it->isMember("long")) {
longOpts[long_i].name = (*it)["long"].asStringRef().c_str(); longOpts[long_i].name = (*it)["long"].asStringRef().c_str();
longOpts[long_i].val = (*it)["short"].asString()[0]; longOpts[long_i].val = (*it)["short"].asString()[0];
if (it->isMember("arg")) { if (it->isMember("arg")){longOpts[long_i].has_arg = 1;}
longOpts[long_i].has_arg = 1;
}
long_i++; long_i++;
} }
if (it->isMember("arg_num") && !(it->isMember("value") && (*it)["value"].size())) { if (it->isMember("arg_num") && !(it->isMember("value") && (*it)["value"].size())){
if ((*it)["arg_num"].asInt() > arg_count) { if ((*it)["arg_num"].asInt() > arg_count){arg_count = (*it)["arg_num"].asInt();}
arg_count = (*it)["arg_num"].asInt();
}
} }
} }
} }
while ((opt = getopt_long(argc, argv, shortopts.c_str(), longOpts, 0)) != -1) { while ((opt = getopt_long(argc, argv, shortopts.c_str(), longOpts, 0)) != -1){
switch (opt) { switch (opt){
case 'h': case 'h':
case '?': case '?': printHelp(std::cout);
printHelp(std::cout); case 'v': std::cout << "Version: " PACKAGE_VERSION ", release " RELEASE << std::endl;
case 'v': #ifdef NOCRASHCHECK
std::cout << "Version: " PACKAGE_VERSION ", release " RELEASE << std::endl; std::cout << "- Flag: No crash check. Will not attempt to detect and kill crashed processes."
#ifdef NOCRASHCHECK << std::endl;
std::cout << "- Flag: No crash check. Will not attempt to detect and kill crashed processes." << std::endl; #endif
#endif #ifndef SHM_ENABLED
#ifndef SHM_ENABLED std::cout << "- Flag: Shared memory disabled. Will use shared files in stead of shared "
std::cout << "- Flag: Shared memory disabled. Will use shared files in stead of shared memory as IPC method." << std::endl; "memory as IPC method."
#endif << std::endl;
#ifdef WITH_THREADNAMES #endif
std::cout << "- Flag: With threadnames. Debuggers will show sensible human-readable thread names." << std::endl; #ifdef WITH_THREADNAMES
#endif std::cout
/*LTS-START*/ << "- Flag: With threadnames. Debuggers will show sensible human-readable thread names."
#ifndef UPDATER << std::endl;
std::cout << "- Flag: Updater disabled. Server will not call back home and attempt to search for updates at regular intervals." << std::endl; #endif
#endif /*LTS-START*/
#ifdef NOAUTH #ifndef UPDATER
std::cout << "- Flag: No authentication. API calls do not require logging in with a valid account first. Make sure access to API port isn't public!" << std::endl; std::cout << "- Flag: Updater disabled. Server will not call back home and attempt to search "
#endif "for updates at regular intervals."
#ifdef KILLONEXIT << std::endl;
std::cout << "- Flag: Kill on exit. All binaries will forcibly shut down all their children on exit. This disabled rolling restart support." << std::endl; #endif
#endif #ifdef NOAUTH
#ifdef STATS_DELAY std::cout << "- Flag: No authentication. API calls do not require logging in with a valid "
"account first. Make sure access to API port isn't public!"
<< std::endl;
#endif
#ifdef KILLONEXIT
std::cout << "- Flag: Kill on exit. All binaries will forcibly shut down all their children "
"on exit. This disabled rolling restart support."
<< std::endl;
#endif
#ifdef STATS_DELAY
if (STATS_DELAY != 15){ if (STATS_DELAY != 15){
std::cout << "- Setting: Stats delay " << STATS_DELAY << ". Statistics of viewer counts are delayed by " << STATS_DELAY << " seconds as opposed to the default of 15 seconds. "; std::cout << "- Setting: Stats delay " << STATS_DELAY
<< ". Statistics of viewer counts are delayed by " << STATS_DELAY
<< " seconds as opposed to the default of 15 seconds. ";
if (STATS_DELAY > 15){ if (STATS_DELAY > 15){
std::cout << "This makes them more accurate." << std::endl; std::cout << "This makes them more accurate." << std::endl;
}else{ }else{
std::cout << "This makes them less accurate." << std::endl; std::cout << "This makes them less accurate." << std::endl;
} }
} }
#endif #endif
/*LTS-END*/ /*LTS-END*/
std::cout << "Built on " __DATE__ ", " __TIME__ << std::endl; std::cout << "Built on " __DATE__ ", " __TIME__ << std::endl;
exit(0); exit(0);
break; break;
default: default:
jsonForEach(vals, it) { jsonForEach(vals, it){
if (it->isMember("short") && (*it)["short"].asString()[0] == opt) { if (it->isMember("short") && (*it)["short"].asString()[0] == opt){
if (it->isMember("arg")) { if (it->isMember("arg")){
(*it)["value"].append((std::string)optarg); (*it)["value"].append(optarg);
} else { }else{
(*it)["value"].append((long long int)1); (*it)["value"].append((int64_t)1);
} }
break; break;
} }
} }
break; break;
} }
} //commandline options parser }// commandline options parser
free(longOpts); //free the long options array free(longOpts); // free the long options array
long_i = 1; //re-use long_i as an argument counter long_i = 1; // re-use long_i as an argument counter
while (optind < argc) { //parse all remaining options, ignoring anything unexpected. while (optind < argc){// parse all remaining options, ignoring anything unexpected.
jsonForEach(vals, it) { jsonForEach(vals, it){
if (it->isMember("arg_num") && (*it)["arg_num"].asInt() == long_i) { if (it->isMember("arg_num") && (*it)["arg_num"].asInt() == long_i){
(*it)["value"].append((std::string)argv[optind]); (*it)["value"].append((std::string)argv[optind]);
break; break;
} }
@ -258,89 +246,85 @@ bool Util::Config::parseArgs(int & argc, char ** & argv) {
optind++; optind++;
long_i++; long_i++;
} }
if (long_i <= arg_count) { if (long_i <= arg_count){return false;}
return false;
}
printDebugLevel = getInteger("debug"); printDebugLevel = getInteger("debug");
return true; return true;
} }
bool Util::Config::hasOption(const std::string & optname) { bool Util::Config::hasOption(const std::string &optname){
return vals.isMember(optname); return vals.isMember(optname);
} }
/// Returns a reference to the current value of an option or default if none was set. /// Returns a reference to the current value of an option or default if none was set.
/// If the option does not exist, this exits the application with a return code of 37. /// If the option does not exist, this exits the application with a return code of 37.
JSON::Value & Util::Config::getOption(std::string optname, bool asArray) { JSON::Value &Util::Config::getOption(std::string optname, bool asArray){
if (!vals.isMember(optname)) { if (!vals.isMember(optname)){
std::cout << "Fatal error: a non-existent option '" << optname << "' was accessed." << std::endl; std::cout << "Fatal error: a non-existent option '" << optname << "' was accessed."
<< std::endl;
exit(37); exit(37);
} }
if (!vals[optname].isMember("value") || !vals[optname]["value"].isArray()) { if (!vals[optname].isMember("value") || !vals[optname]["value"].isArray()){
vals[optname]["value"].append(JSON::Value()); vals[optname]["value"].append(JSON::Value());
vals[optname]["value"].shrink(0); vals[optname]["value"].shrink(0);
} }
if (asArray) { if (asArray){return vals[optname]["value"];}
return vals[optname]["value"];
} else {
int n = vals[optname]["value"].size(); int n = vals[optname]["value"].size();
if (!n){ if (!n){
static JSON::Value empty = ""; static JSON::Value empty = "";
return empty; return empty;
}else{ }
return vals[optname]["value"][n - 1]; return vals[optname]["value"][n - 1];
}
}
} }
/// Returns the current value of an option or default if none was set as a string. /// Returns the current value of an option or default if none was set as a string.
/// Calls getOption internally. /// Calls getOption internally.
std::string Util::Config::getString(std::string optname) { std::string Util::Config::getString(std::string optname){
return getOption(optname).asString(); return getOption(optname).asString();
} }
/// Returns the current value of an option or default if none was set as a long long int. /// Returns the current value of an option or default if none was set as a long long int.
/// Calls getOption internally. /// Calls getOption internally.
long long int Util::Config::getInteger(std::string optname) { int64_t Util::Config::getInteger(std::string optname){
return getOption(optname).asInt(); return getOption(optname).asInt();
} }
/// Returns the current value of an option or default if none was set as a bool. /// Returns the current value of an option or default if none was set as a bool.
/// Calls getOption internally. /// Calls getOption internally.
bool Util::Config::getBool(std::string optname) { bool Util::Config::getBool(std::string optname){
return getOption(optname).asBool(); return getOption(optname).asBool();
} }
struct callbackData { struct callbackData{
Socket::Connection * sock; Socket::Connection *sock;
int (*cb)(Socket::Connection &); int (*cb)(Socket::Connection &);
}; };
static void callThreadCallback(void * cDataArg) { static void callThreadCallback(void *cDataArg){
DEBUG_MSG(DLVL_INSANE, "Thread for %p started", cDataArg); INSANE_MSG("Thread for %p started", cDataArg);
callbackData * cData = (callbackData *)cDataArg; callbackData *cData = (callbackData *)cDataArg;
cData->cb(*(cData->sock)); cData->cb(*(cData->sock));
cData->sock->close(); cData->sock->close();
delete cData->sock; delete cData->sock;
delete cData; delete cData;
DEBUG_MSG(DLVL_INSANE, "Thread for %p ended", cDataArg); INSANE_MSG("Thread for %p ended", cDataArg);
} }
int Util::Config::threadServer(Socket::Server & server_socket, int (*callback)(Socket::Connection &)) { int Util::Config::threadServer(Socket::Server &server_socket,
int (*callback)(Socket::Connection &)){
Util::Procs::socketList.insert(server_socket.getSocket()); Util::Procs::socketList.insert(server_socket.getSocket());
while (is_active && server_socket.connected()) { while (is_active && server_socket.connected()){
Socket::Connection S = server_socket.accept(); Socket::Connection S = server_socket.accept();
if (S.connected()) { //check if the new connection is valid if (S.connected()){// check if the new connection is valid
callbackData * cData = new callbackData; callbackData *cData = new callbackData;
cData->sock = new Socket::Connection(S); cData->sock = new Socket::Connection(S);
cData->cb = callback; cData->cb = callback;
//spawn a new thread for this connection // spawn a new thread for this connection
tthread::thread T(callThreadCallback, (void *)cData); tthread::thread T(callThreadCallback, (void *)cData);
//detach it, no need to keep track of it anymore // detach it, no need to keep track of it anymore
T.detach(); T.detach();
DEBUG_MSG(DLVL_HIGH, "Spawned new thread for socket %i", S.getSocket()); HIGH_MSG("Spawned new thread for socket %i", S.getSocket());
} else { }else{
Util::sleep(10); //sleep 10ms Util::sleep(10); // sleep 10ms
} }
} }
Util::Procs::socketList.erase(server_socket.getSocket()); Util::Procs::socketList.erase(server_socket.getSocket());
@ -348,21 +332,21 @@ int Util::Config::threadServer(Socket::Server & server_socket, int (*callback)(S
return 0; return 0;
} }
int Util::Config::forkServer(Socket::Server & server_socket, int (*callback)(Socket::Connection &)) { int Util::Config::forkServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &)){
Util::Procs::socketList.insert(server_socket.getSocket()); Util::Procs::socketList.insert(server_socket.getSocket());
while (is_active && server_socket.connected()) { while (is_active && server_socket.connected()){
Socket::Connection S = server_socket.accept(); Socket::Connection S = server_socket.accept();
if (S.connected()) { //check if the new connection is valid if (S.connected()){// check if the new connection is valid
pid_t myid = fork(); pid_t myid = fork();
if (myid == 0) { //if new child, start MAINHANDLER if (myid == 0){// if new child, start MAINHANDLER
server_socket.drop(); server_socket.drop();
return callback(S); return callback(S);
} else { //otherwise, do nothing or output debugging text }else{// otherwise, do nothing or output debugging text
DEBUG_MSG(DLVL_HIGH, "Forked new process %i for socket %i", (int)myid, S.getSocket()); HIGH_MSG("Forked new process %i for socket %i", (int)myid, S.getSocket());
S.drop(); S.drop();
} }
} else { }else{
Util::sleep(10); //sleep 10ms Util::sleep(10); // sleep 10ms
} }
} }
Util::Procs::socketList.erase(server_socket.getSocket()); Util::Procs::socketList.erase(server_socket.getSocket());
@ -370,40 +354,40 @@ int Util::Config::forkServer(Socket::Server & server_socket, int (*callback)(Soc
return 0; return 0;
} }
int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)) { int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
Socket::Server server_socket; Socket::Server server_socket;
if (vals.isMember("socket")) { if (vals.isMember("socket")){
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
} }
if (vals.isMember("port") && vals.isMember("interface")) { if (vals.isMember("port") && vals.isMember("interface")){
server_socket = Socket::Server(getInteger("port"), getString("interface"), false); server_socket = Socket::Server(getInteger("port"), getString("interface"), false);
} }
if (!server_socket.connected()) { if (!server_socket.connected()){
DEBUG_MSG(DLVL_DEVEL, "Failure to open socket"); DEVEL_MSG("Failure to open socket");
return 1; return 1;
} }
serv_sock_pointer = &server_socket; serv_sock_pointer = &server_socket;
DEBUG_MSG(DLVL_DEVEL, "Activating threaded server: %s", getString("cmd").c_str()); DEVEL_MSG("Activating threaded server: %s", getString("cmd").c_str());
activate(); activate();
int r = threadServer(server_socket, callback); int r = threadServer(server_socket, callback);
serv_sock_pointer = 0; serv_sock_pointer = 0;
return r; return r;
} }
int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection & S)) { int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){
Socket::Server server_socket; Socket::Server server_socket;
if (vals.isMember("socket")) { if (vals.isMember("socket")){
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
} }
if (vals.isMember("port") && vals.isMember("interface")) { if (vals.isMember("port") && vals.isMember("interface")){
server_socket = Socket::Server(getInteger("port"), getString("interface"), false); server_socket = Socket::Server(getInteger("port"), getString("interface"), false);
} }
if (!server_socket.connected()) { if (!server_socket.connected()){
DEBUG_MSG(DLVL_DEVEL, "Failure to open socket"); DEVEL_MSG("Failure to open socket");
return 1; return 1;
} }
serv_sock_pointer = &server_socket; serv_sock_pointer = &server_socket;
DEBUG_MSG(DLVL_DEVEL, "Activating forked server: %s", getString("cmd").c_str()); DEVEL_MSG("Activating forked server: %s", getString("cmd").c_str());
activate(); activate();
int r = forkServer(server_socket, callback); int r = forkServer(server_socket, callback);
serv_sock_pointer = 0; serv_sock_pointer = 0;
@ -414,8 +398,8 @@ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection & S)) {
/// - Drop permissions to the stored "username", if any. /// - Drop permissions to the stored "username", if any.
/// - Set is_active to true. /// - Set is_active to true.
/// - Set up a signal handler to set is_active to false for the SIGINT, SIGHUP and SIGTERM signals. /// - Set up a signal handler to set is_active to false for the SIGINT, SIGHUP and SIGTERM signals.
void Util::Config::activate() { void Util::Config::activate(){
if (vals.isMember("username")) { if (vals.isMember("username")){
setUser(getString("username")); setUser(getString("username"));
vals.removeMember("username"); vals.removeMember("username");
} }
@ -428,9 +412,9 @@ void Util::Config::activate() {
sigaction(SIGHUP, &new_action, NULL); sigaction(SIGHUP, &new_action, NULL);
sigaction(SIGTERM, &new_action, NULL); sigaction(SIGTERM, &new_action, NULL);
sigaction(SIGPIPE, &new_action, NULL); sigaction(SIGPIPE, &new_action, NULL);
//check if a child signal handler isn't set already, if so, set it. // check if a child signal handler isn't set already, if so, set it.
sigaction(SIGCHLD, 0, &cur_action); sigaction(SIGCHLD, 0, &cur_action);
if (cur_action.sa_handler == SIG_DFL || cur_action.sa_handler == SIG_IGN) { if (cur_action.sa_handler == SIG_DFL || cur_action.sa_handler == SIG_IGN){
sigaction(SIGCHLD, &new_action, NULL); sigaction(SIGCHLD, &new_action, NULL);
} }
is_active = true; is_active = true;
@ -439,9 +423,9 @@ void Util::Config::activate() {
/// Basic signal handler. Sets is_active to false if it receives /// Basic signal handler. Sets is_active to false if it receives
/// a SIGINT, SIGHUP or SIGTERM signal, reaps children for the SIGCHLD /// a SIGINT, SIGHUP or SIGTERM signal, reaps children for the SIGCHLD
/// signal, and ignores all other signals. /// signal, and ignores all other signals.
void Util::Config::signal_handler(int signum, siginfo_t * sigInfo, void * ignore) { void Util::Config::signal_handler(int signum, siginfo_t *sigInfo, void *ignore){
switch (signum) { switch (signum){
case SIGINT: //these three signals will set is_active to false. case SIGINT: // these three signals will set is_active to false.
case SIGHUP: case SIGHUP:
case SIGTERM: case SIGTERM:
if (serv_sock_pointer){serv_sock_pointer->close();} if (serv_sock_pointer){serv_sock_pointer->close();}
@ -457,37 +441,33 @@ void Util::Config::signal_handler(int signum, siginfo_t * sigInfo, void * ignore
case SI_TIMER: case SI_TIMER:
case SI_ASYNCIO: case SI_ASYNCIO:
case SI_MESGQ: case SI_MESGQ:
INFO_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid); INFO_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum,
break; sigInfo->si_pid);
default:
INFO_MSG("Received signal %s (%d)", strsignal(signum), signum);
break; break;
default: INFO_MSG("Received signal %s (%d)", strsignal(signum), signum); break;
} }
break; break;
case SIGCHLD: { //when a child dies, reap it. case SIGCHLD:{// when a child dies, reap it.
int status; int status;
pid_t ret = -1; pid_t ret = -1;
while (ret != 0) { while (ret != 0){
ret = waitpid(-1, &status, WNOHANG); ret = waitpid(-1, &status, WNOHANG);
if (ret < 0 && errno != EINTR) { if (ret < 0 && errno != EINTR){break;}
break;
}
} }
HIGH_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid); HIGH_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid);
break; break;
} }
case SIGPIPE: case SIGPIPE:
//We ignore SIGPIPE to prevent messages triggering another SIGPIPE. // We ignore SIGPIPE to prevent messages triggering another SIGPIPE.
//Loops are bad, m'kay? // Loops are bad, m'kay?
break; break;
} }
} //signal_handler }// signal_handler
/// Adds the options from the given JSON capabilities structure. /// Adds the options from the given JSON capabilities structure.
/// Recurses into optional and required, added options as needed. /// Recurses into optional and required, added options as needed.
void Util::Config::addOptionsFromCapabilities(const JSON::Value & capa){ void Util::Config::addOptionsFromCapabilities(const JSON::Value &capa){
//First add the required options. // First add the required options.
if (capa.isMember("required") && capa["required"].size()){ if (capa.isMember("required") && capa["required"].size()){
jsonForEachConst(capa["required"], it){ jsonForEachConst(capa["required"], it){
if (!it->isMember("short") || !it->isMember("option") || !it->isMember("type")){ if (!it->isMember("short") || !it->isMember("option") || !it->isMember("type")){
@ -498,21 +478,19 @@ void Util::Config::addOptionsFromCapabilities(const JSON::Value & capa){
opt["short"] = (*it)["short"]; opt["short"] = (*it)["short"];
opt["long"] = (*it)["option"].asStringRef().substr(2); opt["long"] = (*it)["option"].asStringRef().substr(2);
if (it->isMember("type")){ if (it->isMember("type")){
//int, uint, debug, select, str // int, uint, debug, select, str
if ((*it)["type"].asStringRef() == "int" || (*it)["type"].asStringRef() == "uint"){ if ((*it)["type"].asStringRef() == "int" || (*it)["type"].asStringRef() == "uint"){
opt["arg"] = "integer"; opt["arg"] = "integer";
}else{ }else{
opt["arg"] = "string"; opt["arg"] = "string";
} }
} }
if (it->isMember("default")){ if (it->isMember("default")){opt["value"].append((*it)["default"]);}
opt["value"].append((*it)["default"]);
}
opt["help"] = (*it)["help"]; opt["help"] = (*it)["help"];
addOption(it.key(), opt); addOption(it.key(), opt);
} }
} }
//Then, the optionals. // Then, the optionals.
if (capa.isMember("optional") && capa["optional"].size()){ if (capa.isMember("optional") && capa["optional"].size()){
jsonForEachConst(capa["optional"], it){ jsonForEachConst(capa["optional"], it){
if (it.key() == "debug"){continue;} if (it.key() == "debug"){continue;}
@ -524,31 +502,30 @@ void Util::Config::addOptionsFromCapabilities(const JSON::Value & capa){
opt["short"] = (*it)["short"]; opt["short"] = (*it)["short"];
opt["long"] = (*it)["option"].asStringRef().substr(2); opt["long"] = (*it)["option"].asStringRef().substr(2);
if (it->isMember("type")){ if (it->isMember("type")){
//int, uint, debug, select, str // int, uint, debug, select, str
if ((*it)["type"].asStringRef() == "int" || (*it)["type"].asStringRef() == "uint"){ if ((*it)["type"].asStringRef() == "int" || (*it)["type"].asStringRef() == "uint"){
opt["arg"] = "integer"; opt["arg"] = "integer";
}else{ }else{
opt["arg"] = "string"; opt["arg"] = "string";
} }
} }
if (it->isMember("default")){ if (it->isMember("default")){opt["value"].append((*it)["default"]);}
opt["value"].append((*it)["default"]);
}
opt["help"] = (*it)["help"]; opt["help"] = (*it)["help"];
addOption(it.key(), opt); addOption(it.key(), opt);
} }
} }
} }
/// Adds the default connector options. Also updates the capabilities structure with the default options. /// Adds the default connector options. Also updates the capabilities structure with the default
/// Besides the options addBasicConnectorOptions adds, this function also adds port and interface options. /// options. Besides the options addBasicConnectorOptions adds, this function also adds port and
void Util::Config::addConnectorOptions(int port, JSON::Value & capabilities) { /// interface options.
void Util::Config::addConnectorOptions(int port, JSON::Value &capabilities){
capabilities["optional"]["port"]["name"] = "TCP port"; capabilities["optional"]["port"]["name"] = "TCP port";
capabilities["optional"]["port"]["help"] = "TCP port to listen on"; capabilities["optional"]["port"]["help"] = "TCP port to listen on";
capabilities["optional"]["port"]["type"] = "uint"; capabilities["optional"]["port"]["type"] = "uint";
capabilities["optional"]["port"]["short"] = "p"; capabilities["optional"]["port"]["short"] = "p";
capabilities["optional"]["port"]["option"] = "--port"; capabilities["optional"]["port"]["option"] = "--port";
capabilities["optional"]["port"]["default"] = (long long)port; capabilities["optional"]["port"]["default"] = (int64_t)port;
capabilities["optional"]["interface"]["name"] = "Interface"; capabilities["optional"]["interface"]["name"] = "Interface";
capabilities["optional"]["interface"]["help"] = "Address of the interface to listen on"; capabilities["optional"]["interface"]["help"] = "Address of the interface to listen on";
@ -558,12 +535,14 @@ void Util::Config::addConnectorOptions(int port, JSON::Value & capabilities) {
capabilities["optional"]["interface"]["type"] = "str"; capabilities["optional"]["interface"]["type"] = "str";
addBasicConnectorOptions(capabilities); addBasicConnectorOptions(capabilities);
} //addConnectorOptions }// addConnectorOptions
/// Adds the default connector options. Also updates the capabilities structure with the default options. /// Adds the default connector options. Also updates the capabilities structure with the default
void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities) { /// options.
void Util::Config::addBasicConnectorOptions(JSON::Value &capabilities){
capabilities["optional"]["username"]["name"] = "Username"; capabilities["optional"]["username"]["name"] = "Username";
capabilities["optional"]["username"]["help"] = "Username to drop privileges to - default if unprovided means do not drop privileges"; capabilities["optional"]["username"]["help"] =
"Username to drop privileges to - default if unprovided means do not drop privileges";
capabilities["optional"]["username"]["option"] = "--username"; capabilities["optional"]["username"]["option"] = "--username";
capabilities["optional"]["username"]["short"] = "u"; capabilities["optional"]["username"]["short"] = "u";
capabilities["optional"]["username"]["default"] = "root"; capabilities["optional"]["username"]["default"] = "root";
@ -575,14 +554,12 @@ void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities) {
option["long"] = "json"; option["long"] = "json";
option["short"] = "j"; option["short"] = "j";
option["help"] = "Output connector info in JSON format, then exit."; option["help"] = "Output connector info in JSON format, then exit.";
option["value"].append(0ll); option["value"].append((int64_t)0);
addOption("json", option); addOption("json", option);
} }
/// Gets directory the current executable is stored in. /// Gets directory the current executable is stored in.
std::string Util::getMyPath() { std::string Util::getMyPath(){
char mypath[500]; char mypath[500];
#ifdef __CYGWIN__ #ifdef __CYGWIN__
GetModuleFileName(0, mypath, 500); GetModuleFileName(0, mypath, 500);
@ -593,69 +570,63 @@ std::string Util::getMyPath() {
int ret = _NSGetExecutablePath(mypath, &refSize); int ret = _NSGetExecutablePath(mypath, &refSize);
#else #else
int ret = readlink("/proc/self/exe", mypath, 500); int ret = readlink("/proc/self/exe", mypath, 500);
if (ret != -1) { if (ret != -1){
mypath[ret] = 0; mypath[ret] = 0;
} else { }else{
mypath[0] = 0; mypath[0] = 0;
} }
#endif #endif
#endif #endif
std::string tPath = mypath; std::string tPath = mypath;
size_t slash = tPath.rfind('/'); size_t slash = tPath.rfind('/');
if (slash == std::string::npos) { if (slash == std::string::npos){
slash = tPath.rfind('\\'); slash = tPath.rfind('\\');
if (slash == std::string::npos) { if (slash == std::string::npos){return "";}
return "";
}
} }
tPath.resize(slash + 1); tPath.resize(slash + 1);
return tPath; return tPath;
} }
/// Gets all executables in getMyPath that start with "Mist". /// Gets all executables in getMyPath that start with "Mist".
void Util::getMyExec(std::deque<std::string> & execs) { void Util::getMyExec(std::deque<std::string> &execs){
std::string path = Util::getMyPath(); std::string path = Util::getMyPath();
#ifdef __CYGWIN__ #ifdef __CYGWIN__
path += "\\Mist*"; path += "\\Mist*";
WIN32_FIND_DATA FindFileData; WIN32_FIND_DATA FindFileData;
HANDLE hdl = FindFirstFile(path.c_str(), &FindFileData); HANDLE hdl = FindFirstFile(path.c_str(), &FindFileData);
while (hdl != INVALID_HANDLE_VALUE) { while (hdl != INVALID_HANDLE_VALUE){
execs.push_back(FindFileData.cFileName); execs.push_back(FindFileData.cFileName);
if (!FindNextFile(hdl, &FindFileData)) { if (!FindNextFile(hdl, &FindFileData)){
FindClose(hdl); FindClose(hdl);
hdl = INVALID_HANDLE_VALUE; hdl = INVALID_HANDLE_VALUE;
} }
} }
#else #else
DIR * d = opendir(path.c_str()); DIR *d = opendir(path.c_str());
if (!d) { if (!d){return;}
return; struct dirent *dp;
} do{
struct dirent * dp;
do {
errno = 0; errno = 0;
if ((dp = readdir(d))) { if ((dp = readdir(d))){
if (strncmp(dp->d_name, "Mist", 4) == 0) { if (strncmp(dp->d_name, "Mist", 4) == 0){execs.push_back(dp->d_name);}
execs.push_back(dp->d_name);
} }
} }while (dp != NULL);
} while (dp != NULL);
closedir(d); closedir(d);
#endif #endif
} }
/// Sets the current process' running user /// Sets the current process' running user
void Util::setUser(std::string username) { void Util::setUser(std::string username){
if (username != "root") { if (username != "root"){
struct passwd * user_info = getpwnam(username.c_str()); struct passwd *user_info = getpwnam(username.c_str());
if (!user_info) { if (!user_info){
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: could not get PID", username.c_str()); ERROR_MSG("Error: could not setuid %s: could not get PID", username.c_str());
return; return;
} else { }else{
if (setuid(user_info->pw_uid) != 0) { if (setuid(user_info->pw_uid) != 0){
DEBUG_MSG(DLVL_ERROR, "Error: could not setuid %s: not allowed", username.c_str()); ERROR_MSG("Error: could not setuid %s: not allowed", username.c_str());
} else { }else{
DEBUG_MSG(DLVL_DEVEL, "Change user to %s", username.c_str()); DEVEL_MSG("Change user to %s", username.c_str());
} }
} }
} }

View file

@ -7,53 +7,55 @@
#define PACKAGE_VERSION "unknown" #define PACKAGE_VERSION "unknown"
#endif #endif
#include <string>
#include "json.h" #include "json.h"
#include <signal.h> #include <signal.h>
#include <string>
/// Contains utility code, not directly related to streaming media /// Contains utility code, not directly related to streaming media
namespace Util { namespace Util{
/// Deals with parsing configuration from commandline options. /// Deals with parsing configuration from commandline options.
class Config { class Config{
private: private:
JSON::Value vals; ///< Holds all current config values JSON::Value vals; ///< Holds all current config values
int long_count; int long_count;
static void signal_handler(int signum, siginfo_t * sigInfo, void * ignore); static void signal_handler(int signum, siginfo_t *sigInfo, void *ignore);
public: public:
//variables // variables
static bool is_active; ///< Set to true by activate(), set to false by the signal handler. static bool is_active; ///< Set to true by activate(), set to false by the signal handler.
static unsigned int printDebugLevel; static uint32_t printDebugLevel;
static std::string streamName; ///< Used by debug messages to identify the stream name static std::string streamName; ///< Used by debug messages to identify the stream name
//functions // functions
Config(); Config();
Config(std::string cmd); Config(std::string cmd);
void addOption(std::string optname, JSON::Value option); void addOption(std::string optname, JSON::Value option);
void printHelp(std::ostream & output); void printHelp(std::ostream &output);
bool parseArgs(int & argc, char ** & argv); bool parseArgs(int &argc, char **&argv);
bool hasOption(const std::string & optname); bool hasOption(const std::string &optname);
JSON::Value & getOption(std::string optname, bool asArray = false); JSON::Value &getOption(std::string optname, bool asArray = false);
std::string getString(std::string optname); std::string getString(std::string optname);
long long int getInteger(std::string optname); int64_t getInteger(std::string optname);
bool getBool(std::string optname); bool getBool(std::string optname);
void activate(); void activate();
int threadServer(Socket::Server & server_socket, int (*callback)(Socket::Connection & S)); int threadServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &S));
int forkServer(Socket::Server & server_socket, int (*callback)(Socket::Connection & S)); int forkServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &S));
int serveThreadedSocket(int (*callback)(Socket::Connection & S)); int serveThreadedSocket(int (*callback)(Socket::Connection &S));
int serveForkedSocket(int (*callback)(Socket::Connection & S)); int serveForkedSocket(int (*callback)(Socket::Connection &S));
int servePlainSocket(int (*callback)(Socket::Connection & S)); int servePlainSocket(int (*callback)(Socket::Connection &S));
void addOptionsFromCapabilities(const JSON::Value & capabilities); void addOptionsFromCapabilities(const JSON::Value &capabilities);
void addBasicConnectorOptions(JSON::Value & capabilities); void addBasicConnectorOptions(JSON::Value &capabilities);
void addConnectorOptions(int port, JSON::Value & capabilities); void addConnectorOptions(int port, JSON::Value &capabilities);
}; };
/// Gets directory the current executable is stored in. /// Gets directory the current executable is stored in.
std::string getMyPath(); std::string getMyPath();
/// Gets all executables in getMyPath that start with "Mist". /// Gets all executables in getMyPath that start with "Mist".
void getMyExec(std::deque<std::string> & execs); void getMyExec(std::deque<std::string> &execs);
/// Will set the active user to the named username. /// Will set the active user to the named username.
void setUser(std::string user); void setUser(std::string user);
} }// namespace Util

View file

@ -18,7 +18,9 @@
#define PRETTY_ARG_TIME(t) (int)(t)/86400, ((int)(t)%86400)/3600, ((int)(t)%3600)/60, (int)(t)%60 #define PRETTY_ARG_TIME(t) (int)(t)/86400, ((int)(t)%86400)/3600, ((int)(t)%3600)/60, (int)(t)%60
#if DEBUG > -1 #if DEBUG > -1
#define __STDC_FORMAT_MACROS 1
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
#include "config.h" #include "config.h"

View file

@ -1,7 +1,7 @@
#include "downloader.h" #include "downloader.h"
#include "defines.h" #include "defines.h"
#include "timing.h"
#include "encode.h" #include "encode.h"
#include "timing.h"
namespace HTTP{ namespace HTTP{
@ -66,7 +66,8 @@ namespace HTTP{
} }
/// Sends a request for the given URL, does no waiting. /// Sends a request for the given URL, does no waiting.
void Downloader::doRequest(const HTTP::URL &link, const std::string &method, const std::string &body){ void Downloader::doRequest(const HTTP::URL &link, const std::string &method,
const std::string &body){
if (!canRequest(link)){return;} if (!canRequest(link)){return;}
bool needSSL = (link.protocol == "https"); bool needSSL = (link.protocol == "https");
H.Clean(); H.Clean();
@ -116,9 +117,7 @@ namespace HTTP{
H.SetHeader("Host", link.host); H.SetHeader("Host", link.host);
} }
} }
if (method.size()){ if (method.size()){H.method = method;}
H.method = method;
}
H.SetHeader("User-Agent", "MistServer " PACKAGE_VERSION); H.SetHeader("User-Agent", "MistServer " PACKAGE_VERSION);
H.SetHeader("X-Version", PACKAGE_VERSION); H.SetHeader("X-Version", PACKAGE_VERSION);
H.SetHeader("Accept", "*/*"); H.SetHeader("Accept", "*/*");
@ -142,9 +141,10 @@ namespace HTTP{
/// Makes at most 5 attempts, and will wait no longer than 5 seconds without receiving data. /// Makes at most 5 attempts, and will wait no longer than 5 seconds without receiving data.
bool Downloader::get(const HTTP::URL &link, uint8_t maxRecursiveDepth){ bool Downloader::get(const HTTP::URL &link, uint8_t maxRecursiveDepth){
if (!canRequest(link)){return false;} if (!canRequest(link)){return false;}
unsigned int loop = retryCount+1; // max 5 attempts size_t loop = retryCount + 1; // max 5 attempts
while (--loop){// loop while we are unsuccessful while (--loop){// loop while we are unsuccessful
MEDIUM_MSG("Retrieving %s (%lu/%lu)", link.getUrl().c_str(), retryCount-loop+1, retryCount); MEDIUM_MSG("Retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(), retryCount - loop + 1,
retryCount);
doRequest(link); doRequest(link);
uint64_t reqTime = Util::bootSecs(); uint64_t reqTime = Util::bootSecs();
while (getSocket() && Util::bootSecs() < reqTime + dataTimeout){ while (getSocket() && Util::bootSecs() < reqTime + dataTimeout){
@ -179,10 +179,12 @@ namespace HTTP{
reqTime = Util::bootSecs(); reqTime = Util::bootSecs();
} }
if (getSocket()){ if (getSocket()){
FAIL_MSG("Timeout while retrieving %s (%lu/%lu)", link.getUrl().c_str(), retryCount-loop+1, retryCount); FAIL_MSG("Timeout while retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(),
retryCount - loop + 1, retryCount);
getSocket().close(); getSocket().close();
}else{ }else{
FAIL_MSG("Lost connection while retrieving %s (%lu/%lu)", link.getUrl().c_str(), retryCount-loop+1, retryCount); FAIL_MSG("Lost connection while retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(),
retryCount - loop + 1, retryCount);
} }
Util::sleep(500); // wait a bit before retrying Util::sleep(500); // wait a bit before retrying
} }
@ -190,13 +192,15 @@ namespace HTTP{
return false; return false;
} }
bool Downloader::post(const HTTP::URL &link, const std::string &payload, bool sync, uint8_t maxRecursiveDepth){ bool Downloader::post(const HTTP::URL &link, const std::string &payload, bool sync,
uint8_t maxRecursiveDepth){
if (!canRequest(link)){return false;} if (!canRequest(link)){return false;}
unsigned int loop = retryCount; // max 5 attempts size_t loop = retryCount; // max 5 attempts
while (--loop){// loop while we are unsuccessful while (--loop){// loop while we are unsuccessful
MEDIUM_MSG("Posting to %s (%lu/%lu)", link.getUrl().c_str(), retryCount-loop+1, retryCount); MEDIUM_MSG("Posting to %s (%zu/%" PRIu32 ")", link.getUrl().c_str(), retryCount - loop + 1,
retryCount);
doRequest(link, "POST", payload); doRequest(link, "POST", payload);
//Not synced? Ignore the response and immediately return false. // Not synced? Ignore the response and immediately return false.
if (!sync){return false;} if (!sync){return false;}
uint64_t reqTime = Util::bootSecs(); uint64_t reqTime = Util::bootSecs();
while (getSocket() && Util::bootSecs() < reqTime + dataTimeout){ while (getSocket() && Util::bootSecs() < reqTime + dataTimeout){
@ -261,9 +265,7 @@ namespace HTTP{
setHeader("Cookie", cookie.substr(0, cookie.find(';'))); setHeader("Cookie", cookie.substr(0, cookie.find(';')));
} }
uint32_t sCode = getStatusCode(); uint32_t sCode = getStatusCode();
if (sCode == 401 || sCode == 407 || (sCode >= 300 && sCode < 400)){ if (sCode == 401 || sCode == 407 || (sCode >= 300 && sCode < 400)){return true;}
return true;
}
return false; return false;
} }
@ -285,9 +287,7 @@ namespace HTTP{
} }
if (getStatusCode() == 407){ if (getStatusCode() == 407){
// retry with authentication // retry with authentication
if (H.hasHeader("Proxy-Authenticate")){ if (H.hasHeader("Proxy-Authenticate")){proxyAuthStr = H.GetHeader("Proxy-Authenticate");}
proxyAuthStr = H.GetHeader("Proxy-Authenticate");
}
if (!proxyAuthStr.size()){ if (!proxyAuthStr.size()){
FAIL_MSG("Proxy authentication required but no Proxy-Authenticate header present"); FAIL_MSG("Proxy authentication required but no Proxy-Authenticate header present");
return false; return false;

View file

@ -7,16 +7,20 @@ namespace HTTP{
Downloader(); Downloader();
std::string &data(); std::string &data();
const std::string &const_data() const; const std::string &const_data() const;
void doRequest(const HTTP::URL &link, const std::string &method="", const std::string &body=""); void doRequest(const HTTP::URL &link, const std::string &method = "",
const std::string &body = "");
bool get(const std::string &link); bool get(const std::string &link);
bool get(const HTTP::URL &link, uint8_t maxRecursiveDepth = 6); bool get(const HTTP::URL &link, uint8_t maxRecursiveDepth = 6);
bool post(const HTTP::URL &link, const std::string &payload, bool sync = true, uint8_t maxRecursiveDepth = 6); bool post(const HTTP::URL &link, const std::string &payload, bool sync = true,
uint8_t maxRecursiveDepth = 6);
std::string getHeader(const std::string &headerName); std::string getHeader(const std::string &headerName);
std::string &getStatusText(); std::string &getStatusText();
uint32_t getStatusCode(); uint32_t getStatusCode();
bool isOk(); ///< True if the request was successful. bool isOk(); ///< True if the request was successful.
bool shouldContinue(); ///<True if the request should be followed-up with another. E.g. redirect or authenticate. bool shouldContinue(); ///< True if the request should be followed-up with another. E.g.
bool canContinue(const HTTP::URL &link);///<True if the request is able to continue, false if there is a state error or some such. ///< redirect or authenticate.
bool canContinue(const HTTP::URL &link); ///< True if the request is able to continue, false if
///< there is a state error or some such.
bool (*progressCallback)(); ///< Called every time the socket stalls, up to 4X per second. bool (*progressCallback)(); ///< Called every time the socket stalls, up to 4X per second.
void setHeader(const std::string &name, const std::string &val); void setHeader(const std::string &name, const std::string &val);
void clearHeaders(); void clearHeaders();

View file

@ -80,22 +80,22 @@ namespace DTSC {
Scan(); Scan();
Scan(char * pointer, size_t len); Scan(char * pointer, size_t len);
operator bool() const; operator bool() const;
std::string toPrettyString(unsigned int indent = 0); std::string toPrettyString(size_t indent = 0) const;
bool hasMember(std::string indice); bool hasMember(const std::string & indice) const;
bool hasMember(const char * indice, const unsigned int ind_len); bool hasMember(const char * indice, size_t ind_len) const;
Scan getMember(std::string indice); Scan getMember(const std::string & indice) const;
Scan getMember(const char * indice); Scan getMember(const char * indice) const;
Scan getMember(const char * indice, const unsigned int ind_len); Scan getMember(const char * indice, size_t ind_len) const;
Scan getIndice(unsigned int num); Scan getIndice(size_t num) const;
std::string getIndiceName(unsigned int num); std::string getIndiceName(size_t num) const;
unsigned int getSize(); size_t getSize() const;
char getType(); char getType() const;
bool asBool(); bool asBool() const;
long long asInt(); int64_t asInt() const;
std::string asString(); std::string asString() const;
void getString(char *& result, unsigned int & len); void getString(char *& result, size_t & len) const;
JSON::Value asJSON(); JSON::Value asJSON() const;
private: private:
char * p; char * p;
size_t len; size_t len;
@ -111,7 +111,7 @@ namespace DTSC {
Packet(); Packet();
Packet(const Packet & rhs); Packet(const Packet & rhs);
Packet(const char * data_, unsigned int len, bool noCopy = false); Packet(const char * data_, unsigned int len, bool noCopy = false);
~Packet(); virtual ~Packet();
void null(); void null();
void operator = (const Packet & rhs); void operator = (const Packet & rhs);
operator bool() const; operator bool() const;
@ -119,7 +119,8 @@ namespace DTSC {
void reInit(Socket::Connection & src); void reInit(Socket::Connection & src);
void reInit(const char * data_, unsigned int len, bool noCopy = false); void reInit(const char * data_, unsigned int len, bool noCopy = false);
void genericFill(long long packTime, long long packOffset, long long packTrack, const char * packData, long long packDataSize, uint64_t packBytePos, bool isKeyframe, int64_t bootMsOffset = 0); void genericFill(long long packTime, long long packOffset, long long packTrack, const char * packData, long long packDataSize, uint64_t packBytePos, bool isKeyframe, int64_t bootMsOffset = 0);
void getString(const char * identifier, char *& result, unsigned int & len) const; void appendData(const char * appendData, uint32_t appendLen);
void getString(const char * identifier, char *& result, size_t & len) const;
void getString(const char * identifier, std::string & result) const; void getString(const char * identifier, std::string & result) const;
void getInt(const char * identifier, uint64_t & result) const; void getInt(const char * identifier, uint64_t & result) const;
uint64_t getInt(const char * identifier) const; uint64_t getInt(const char * identifier) const;
@ -129,23 +130,24 @@ namespace DTSC {
void appendNal(const char * appendData, uint32_t appendLen); void appendNal(const char * appendData, uint32_t appendLen);
void upgradeNal(const char * appendData, uint32_t appendLen); void upgradeNal(const char * appendData, uint32_t appendLen);
void setKeyFrame(bool kf); void setKeyFrame(bool kf);
virtual long long unsigned int getTime() const; virtual uint64_t getTime() const;
long int getTrackId() const; void setTime(uint64_t _time);
size_t getTrackId() const;
char * getData() const; char * getData() const;
int getDataLen() const; size_t getDataLen() const;
int getPayloadLen() const; size_t getPayloadLen() const;
uint32_t getDataStringLen(); size_t getDataStringLen();
uint32_t getDataStringLenOffset(); size_t getDataStringLenOffset();
JSON::Value toJSON() const; JSON::Value toJSON() const;
std::string toSummary() const; std::string toSummary() const;
Scan getScan() const; Scan getScan() const;
protected: protected:
bool master; bool master;
packType version; packType version;
void resize(unsigned int size); void resize(size_t size);
char * data; char * data;
unsigned int bufferLen; size_t bufferLen;
unsigned int dataLen; size_t dataLen;
uint64_t prevNalSize; uint64_t prevNalSize;
}; };
@ -162,7 +164,7 @@ namespace DTSC {
RetimedPacket(uint64_t reTime, const char * data_, unsigned int len, bool noCopy = false) : Packet(data_, len, noCopy){ RetimedPacket(uint64_t reTime, const char * data_, unsigned int len, bool noCopy = false) : Packet(data_, len, noCopy){
timeOverride = reTime; timeOverride = reTime;
} }
virtual long long unsigned int getTime() const{return timeOverride;} virtual uint64_t getTime() const{return timeOverride;}
protected: protected:
uint64_t timeOverride; uint64_t timeOverride;
}; };

View file

@ -60,19 +60,19 @@ namespace DTSC {
/// Valid packets have a length of at least 8, known header type, and length equal to the length set in the header. /// Valid packets have a length of at least 8, known header type, and length equal to the length set in the header.
Packet::operator bool() const { Packet::operator bool() const {
if (!data) { if (!data) {
DEBUG_MSG(DLVL_DONTEVEN, "No data"); DONTEVEN_MSG("No data");
return false; return false;
} }
if (dataLen < 8) { if (dataLen < 8) {
DEBUG_MSG(DLVL_VERYHIGH, "Datalen < 8"); VERYHIGH_MSG("Datalen < 8");
return false; return false;
} }
if (version == DTSC_INVALID) { if (version == DTSC_INVALID) {
DEBUG_MSG(DLVL_VERYHIGH, "No valid version"); VERYHIGH_MSG("No valid version");
return false; return false;
} }
if (ntohl(((int *)data)[1]) + 8 > dataLen) { if (ntohl(((int *)data)[1]) + 8 > dataLen) {
DEBUG_MSG(DLVL_VERYHIGH, "Length mismatch"); VERYHIGH_MSG("Length mismatch");
return false; return false;
} }
return true; return true;
@ -100,14 +100,14 @@ namespace DTSC {
/// Internally used resize function for when operating in copy mode and the internal buffer is too small. /// Internally used resize function for when operating in copy mode and the internal buffer is too small.
/// It will only resize up, never down. /// It will only resize up, never down.
///\param len The length th scale the buffer up to if necessary ///\param len The length th scale the buffer up to if necessary
void Packet::resize(unsigned int len) { void Packet::resize(size_t len) {
if (master && len > bufferLen) { if (master && len > bufferLen) {
char * tmp = (char *)realloc(data, len); char * tmp = (char *)realloc(data, len);
if (tmp) { if (tmp) {
data = tmp; data = tmp;
bufferLen = len; bufferLen = len;
} else { } else {
DEBUG_MSG(DLVL_FAIL, "Out of memory on parsing a packet"); FAIL_MSG("Out of memory on parsing a packet");
} }
} }
} }
@ -156,7 +156,7 @@ namespace DTSC {
if (data_[0] != 'D' || data_[1] != 'T') { if (data_[0] != 'D' || data_[1] != 'T') {
unsigned int twlen = len; unsigned int twlen = len;
if (twlen > 20){twlen = 20;} if (twlen > 20){twlen = 20;}
DEBUG_MSG(DLVL_HIGH, "ReInit received a pointer that didn't start with 'DT' but with %s (%u) - data corruption?", JSON::Value(std::string(data_, twlen)).toString().c_str(), len); HIGH_MSG("ReInit received a pointer that didn't start with 'DT' but with %s (%u) - data corruption?", JSON::Value(std::string(data_, twlen)).toString().c_str(), len);
null(); null();
return; return;
} }
@ -179,28 +179,24 @@ namespace DTSC {
//check header type and store packet length //check header type and store packet length
dataLen = len; dataLen = len;
version = DTSC_INVALID; version = DTSC_INVALID;
if (len > 3) { if (len < 4) {
FAIL_MSG("ReInit received a packet with size < 4");
return;
}
if (!memcmp(data, Magic_Packet2, 4)) { if (!memcmp(data, Magic_Packet2, 4)) {
version = DTSC_V2; version = DTSC_V2;
} else { }
if (!memcmp(data, Magic_Packet, 4)) { if (!memcmp(data, Magic_Packet, 4)) {
version = DTSC_V1; version = DTSC_V1;
} else { }
if (!memcmp(data, Magic_Header, 4)) { if (!memcmp(data, Magic_Header, 4)) {
version = DTSC_HEAD; version = DTSC_HEAD;
} else { }
if (!memcmp(data, Magic_Command, 4)) { if (!memcmp(data, Magic_Command, 4)) {
version = DTCM; version = DTCM;
} else {
DEBUG_MSG(DLVL_FAIL, "ReInit received a packet with invalid header");
return;
} }
} if (version == DTSC_INVALID){
} FAIL_MSG("ReInit received a packet with invalid header");
}
} else {
DEBUG_MSG(DLVL_FAIL, "ReInit received a packet with size < 4");
return;
} }
} }
@ -298,12 +294,21 @@ namespace DTSC {
} }
} }
void Packet::appendData(const char * appendData, uint32_t appendLen){
resize(dataLen + appendLen);
memcpy(data + dataLen-3, appendData, appendLen);
memcpy(data + dataLen-3 + appendLen, "\000\000\356", 3); //end container
dataLen += appendLen;
Bit::htobl(data+4, Bit::btohl(data +4)+appendLen);
uint32_t offset = getDataStringLenOffset();
Bit::htobl(data+offset, Bit::btohl(data+offset)+appendLen);
}
void Packet::appendNal(const char * appendData, uint32_t appendLen){ void Packet::appendNal(const char * appendData, uint32_t appendLen){
if(appendLen ==0){ if(appendLen ==0){
return; return;
} }
// INFO_MSG("totallen: %d, appendLen: %d",totalLen,appendLen);
resize(dataLen + appendLen +4); resize(dataLen + appendLen +4);
Bit::htobl(data+dataLen -3, appendLen); Bit::htobl(data+dataLen -3, appendLen);
memcpy(data + dataLen-3+4, appendData, appendLen); memcpy(data + dataLen-3+4, appendData, appendLen);
@ -336,13 +341,13 @@ namespace DTSC {
Bit::htobl(data+offset, Bit::btohl(data+offset)+appendLen); Bit::htobl(data+offset, Bit::btohl(data+offset)+appendLen);
} }
uint32_t Packet::getDataStringLen(){ size_t Packet::getDataStringLen(){
return Bit::btohl(data+getDataStringLenOffset()); return Bit::btohl(data+getDataStringLenOffset());
} }
///Method can only be used when using internal functions to build the data. ///Method can only be used when using internal functions to build the data.
uint32_t Packet::getDataStringLenOffset(){ size_t Packet::getDataStringLenOffset(){
uint32_t offset = 23; size_t offset = 23;
while (data[offset] != 'd'){ while (data[offset] != 'd'){
switch (data[offset]){ switch (data[offset]){
case 'o': offset += 17; break; case 'o': offset += 17; break;
@ -408,7 +413,7 @@ namespace DTSC {
///\param identifier The name of the parameter ///\param identifier The name of the parameter
///\param result A location on which the string will be returned ///\param result A location on which the string will be returned
///\param len An integer in which the length of the string will be returned ///\param len An integer in which the length of the string will be returned
void Packet::getString(const char * identifier, char *& result, unsigned int & len) const { void Packet::getString(const char * identifier, char *& result, size_t & len) const {
getScan().getMember(identifier).getString(result, len); getScan().getMember(identifier).getString(result, len);
} }
@ -441,7 +446,7 @@ namespace DTSC {
void Packet::getFlag(const char * identifier, bool & result) const { void Packet::getFlag(const char * identifier, bool & result) const {
uint64_t result_; uint64_t result_;
getInt(identifier, result_); getInt(identifier, result_);
result = (bool)result_; result = result_;
} }
///\brief Retrieves a single parameter as a boolean ///\brief Retrieves a single parameter as a boolean
@ -462,7 +467,7 @@ namespace DTSC {
///\brief Returns the timestamp of the packet. ///\brief Returns the timestamp of the packet.
///\return The timestamp of this packet. ///\return The timestamp of this packet.
long long unsigned int Packet::getTime() const { uint64_t Packet::getTime() const {
if (version != DTSC_V2) { if (version != DTSC_V2) {
if (!data) { if (!data) {
return 0; return 0;
@ -472,9 +477,17 @@ namespace DTSC {
return Bit::btohll(data + 12); return Bit::btohll(data + 12);
} }
void Packet::setTime(uint64_t _time) {
if (!master){
INFO_MSG("Can't set the time for this packet, as it is not master.");
return;
}
Bit::htobll(data + 12, _time);
}
///\brief Returns the track id of the packet. ///\brief Returns the track id of the packet.
///\return The track id of this packet. ///\return The track id of this packet.
long int Packet::getTrackId() const { size_t Packet::getTrackId() const {
if (version != DTSC_V2) { if (version != DTSC_V2) {
return getInt("trackid"); return getInt("trackid");
} }
@ -489,13 +502,13 @@ namespace DTSC {
///\brief Returns the size of this packet. ///\brief Returns the size of this packet.
///\return The size of this packet. ///\return The size of this packet.
int Packet::getDataLen() const { uint64_t Packet::getDataLen() const {
return dataLen; return dataLen;
} }
///\brief Returns the size of the payload of this packet. ///\brief Returns the size of the payload of this packet.
///\return The size of the payload of this packet. ///\return The size of the payload of this packet.
int Packet::getPayloadLen() const { size_t Packet::getPayloadLen() const {
if (version == DTSC_V2) { if (version == DTSC_V2) {
return dataLen - 20; return dataLen - 20;
} else { } else {
@ -516,12 +529,12 @@ namespace DTSC {
///\return A JSON::Value representation of this packet. ///\return A JSON::Value representation of this packet.
JSON::Value Packet::toJSON() const { JSON::Value Packet::toJSON() const {
JSON::Value result; JSON::Value result;
unsigned int i = 8; uint32_t i = 8;
if (getVersion() == DTSC_V1) { if (getVersion() == DTSC_V1) {
JSON::fromDTMI((const unsigned char *)data, dataLen, i, result); JSON::fromDTMI(data, dataLen, i, result);
} }
if (getVersion() == DTSC_V2) { if (getVersion() == DTSC_V2) {
JSON::fromDTMI2((const unsigned char *)data, dataLen, i, result); JSON::fromDTMI2(data, dataLen, i, result);
} }
return result; return result;
} }
@ -529,7 +542,7 @@ namespace DTSC {
std::string Packet::toSummary() const { std::string Packet::toSummary() const {
std::stringstream out; std::stringstream out;
char * res = 0; char * res = 0;
unsigned int len = 0; size_t len = 0;
getString("data", res, len); getString("data", res, len);
out << getTrackId() << "@" << getTime() << ": " << len << " bytes"; out << getTrackId() << "@" << getTime() << ": " << len << " bytes";
if (hasMember("keyframe")){ if (hasMember("keyframe")){
@ -558,13 +571,13 @@ namespace DTSC {
/// Returns an object representing the named indice of this object. /// Returns an object representing the named indice of this object.
/// Returns an invalid object if this indice doesn't exist or this isn't an object type. /// Returns an invalid object if this indice doesn't exist or this isn't an object type.
Scan Scan::getMember(std::string indice) { Scan Scan::getMember(const std::string & indice) const {
return getMember(indice.data(), indice.size()); return getMember(indice.data(), indice.size());
} }
/// Returns an object representing the named indice of this object. /// Returns an object representing the named indice of this object.
/// Returns an invalid object if this indice doesn't exist or this isn't an object type. /// Returns an invalid object if this indice doesn't exist or this isn't an object type.
Scan Scan::getMember(const char * indice, const unsigned int ind_len) { Scan Scan::getMember(const char * indice, const size_t ind_len) const {
if (getType() != DTSC_OBJ && getType() != DTSC_CON) { if (getType() != DTSC_OBJ && getType() != DTSC_CON) {
return Scan(); return Scan();
} }
@ -574,79 +587,75 @@ namespace DTSC {
if (i + 2 >= p + len) { if (i + 2 >= p + len) {
return Scan();//out of packet! return Scan();//out of packet!
} }
unsigned int strlen = Bit::btohs(i); uint16_t strlen = Bit::btohs(i);
i += 2; i += 2;
if (ind_len == strlen && strncmp(indice, i, strlen) == 0) { if (ind_len == strlen && strncmp(indice, i, strlen) == 0) {
return Scan(i + strlen, len - (i - p)); return Scan(i + strlen, len - (i - p));
} else { }
i = skipDTSC(i + strlen, p + len); i = skipDTSC(i + strlen, p + len);
if (!i) { if (!i) {
return Scan(); return Scan();
} }
} }
}
return Scan(); return Scan();
} }
/// Returns an object representing the named indice of this object. /// Returns an object representing the named indice of this object.
/// Returns an invalid object if this indice doesn't exist or this isn't an object type. /// Returns an invalid object if this indice doesn't exist or this isn't an object type.
bool Scan::hasMember(std::string indice){ bool Scan::hasMember(const std::string & indice) const{
return getMember(indice.data(), indice.size()); return getMember(indice.data(), indice.size());
} }
/// Returns whether an object representing the named indice of this object exists. /// Returns whether an object representing the named indice of this object exists.
/// Returns false if this indice doesn't exist or this isn't an object type. /// Returns false if this indice doesn't exist or this isn't an object type.
bool Scan::hasMember(const char * indice, const unsigned int ind_len) { bool Scan::hasMember(const char * indice, const size_t ind_len) const {
return getMember(indice, ind_len); return getMember(indice, ind_len);
} }
/// Returns an object representing the named indice of this object. /// Returns an object representing the named indice of this object.
/// Returns an invalid object if this indice doesn't exist or this isn't an object type. /// Returns an invalid object if this indice doesn't exist or this isn't an object type.
Scan Scan::getMember(const char * indice) { Scan Scan::getMember(const char * indice) const {
return getMember(indice, strlen(indice)); return getMember(indice, strlen(indice));
} }
/// Returns the amount of indices if an array, the amount of members if an object, or zero otherwise. /// Returns the amount of indices if an array, the amount of members if an object, or zero otherwise.
unsigned int Scan::getSize() { size_t Scan::getSize() const {
uint32_t arr_indice = 0;
if (getType() == DTSC_ARR) { if (getType() == DTSC_ARR) {
char * i = p + 1; char * i = p + 1;
unsigned int arr_indice = 0;
//array, scan contents //array, scan contents
while (i[0] + i[1] != 0 && i < p + len) { //while not encountering 0x0000 (we assume 0x0000EE) while (i[0] + i[1] != 0 && i < p + len) { //while not encountering 0x0000 (we assume 0x0000EE)
//search through contents... //search through contents...
arr_indice++; arr_indice++;
i = skipDTSC(i, p + len); i = skipDTSC(i, p + len);
if (!i) { if (!i) {
return arr_indice; break;
} }
} }
return arr_indice;
} }
if (getType() == DTSC_OBJ || getType() == DTSC_CON) { if (getType() == DTSC_OBJ || getType() == DTSC_CON) {
char * i = p + 1; char * i = p + 1;
unsigned int arr_indice = 0;
//object, scan contents //object, scan contents
while (i[0] + i[1] != 0 && i < p + len) { //while not encountering 0x0000 (we assume 0x0000EE) while (i[0] + i[1] != 0 && i < p + len) { //while not encountering 0x0000 (we assume 0x0000EE)
if (i + 2 >= p + len) { if (i + 2 >= p + len) {
return Scan();//out of packet! return Scan();//out of packet!
} }
unsigned int strlen = Bit::btohs(i); uint16_t strlen = Bit::btohs(i);
i += 2; i += 2;
arr_indice++; arr_indice++;
i = skipDTSC(i + strlen, p + len); i = skipDTSC(i + strlen, p + len);
if (!i) { if (!i) {
return arr_indice; break;
}
} }
} }
return arr_indice; return arr_indice;
} }
return 0;
}
/// Returns an object representing the num-th indice of this array. /// Returns an object representing the num-th indice of this array.
/// If not an array but an object, it returns the num-th member, instead. /// If not an array but an object, it returns the num-th member, instead.
/// Returns an invalid object if this indice doesn't exist or this isn't an array or object type. /// Returns an invalid object if this indice doesn't exist or this isn't an array or object type.
Scan Scan::getIndice(unsigned int num) { Scan Scan::getIndice(size_t num) const {
if (getType() == DTSC_ARR) { if (getType() == DTSC_ARR) {
char * i = p + 1; char * i = p + 1;
unsigned int arr_indice = 0; unsigned int arr_indice = 0;
@ -690,7 +699,7 @@ namespace DTSC {
/// Returns the name of the num-th member of this object. /// Returns the name of the num-th member of this object.
/// Returns an empty string on error or when not an object. /// Returns an empty string on error or when not an object.
std::string Scan::getIndiceName(unsigned int num) { std::string Scan::getIndiceName(size_t num) const {
if (getType() == DTSC_OBJ || getType() == DTSC_CON) { if (getType() == DTSC_OBJ || getType() == DTSC_CON) {
char * i = p + 1; char * i = p + 1;
unsigned int arr_indice = 0; unsigned int arr_indice = 0;
@ -716,7 +725,7 @@ namespace DTSC {
} }
/// Returns the first byte of this DTSC value, or 0 on error. /// Returns the first byte of this DTSC value, or 0 on error.
char Scan::getType() { char Scan::getType() const {
if (!p) { if (!p) {
return 0; return 0;
} }
@ -728,7 +737,7 @@ namespace DTSC {
/// Strings are checked for non-zero length. /// Strings are checked for non-zero length.
/// Objects and arrays are checked for content. /// Objects and arrays are checked for content.
/// Returns false on error or in other cases. /// Returns false on error or in other cases.
bool Scan::asBool() { bool Scan::asBool() const {
switch (getType()) { switch (getType()) {
case DTSC_STR: case DTSC_STR:
return (p[1] | p[2] | p[3] | p[4]); return (p[1] | p[2] | p[3] | p[4]);
@ -746,13 +755,13 @@ namespace DTSC {
/// Returns the long long value of this DTSC number value. /// Returns the long long value of this DTSC number value.
/// Will convert string values to numbers, taking octal and hexadecimal types into account. /// Will convert string values to numbers, taking octal and hexadecimal types into account.
/// Illegal or invalid values return 0. /// Illegal or invalid values return 0.
long long Scan::asInt() { int64_t Scan::asInt() const {
switch (getType()) { switch (getType()) {
case DTSC_INT: case DTSC_INT:
return Bit::btohll(p+1); return Bit::btohll(p+1);
case DTSC_STR: case DTSC_STR:
char * str; char * str;
unsigned int strlen; size_t strlen;
getString(str, strlen); getString(str, strlen);
if (!strlen) { if (!strlen) {
return 0; return 0;
@ -767,7 +776,7 @@ namespace DTSC {
/// Uses getString internally, if a string. /// Uses getString internally, if a string.
/// Converts integer values to strings. /// Converts integer values to strings.
/// Returns an empty string on error. /// Returns an empty string on error.
std::string Scan::asString() { std::string Scan::asString() const {
switch (getType()) { switch (getType()) {
case DTSC_INT:{ case DTSC_INT:{
std::stringstream st; std::stringstream st;
@ -777,7 +786,7 @@ namespace DTSC {
break; break;
case DTSC_STR:{ case DTSC_STR:{
char * str; char * str;
unsigned int strlen; size_t strlen;
getString(str, strlen); getString(str, strlen);
return std::string(str, strlen); return std::string(str, strlen);
} }
@ -789,25 +798,22 @@ namespace DTSC {
/// Sets result to a pointer to the string, and strlen to the length of it. /// Sets result to a pointer to the string, and strlen to the length of it.
/// Sets both to zero if this isn't a DTSC string value. /// Sets both to zero if this isn't a DTSC string value.
/// Attempts absolutely no conversion. /// Attempts absolutely no conversion.
void Scan::getString(char *& result, unsigned int & strlen) { void Scan::getString(char *& result, size_t & strlen) const {
switch (getType()) { if (getType() == DTSC_STR){
case DTSC_STR:
result = p + 5; result = p + 5;
strlen = Bit::btohl(p+1); strlen = Bit::btohl(p+1);
return; return;
default: }
result = 0; result = 0;
strlen = 0; strlen = 0;
return;
}
} }
/// Returns the DTSC scan object as a JSON value /// Returns the DTSC scan object as a JSON value
/// Returns an empty object on error. /// Returns an empty object on error.
JSON::Value Scan::asJSON(){ JSON::Value Scan::asJSON() const {
JSON::Value result; JSON::Value result;
unsigned int i = 0; unsigned int i = 0;
JSON::fromDTMI((const unsigned char*)p, len, i, result); JSON::fromDTMI(p, len, i, result);
return result; return result;
} }
@ -826,7 +832,7 @@ namespace DTSC {
static std::string string_escape(const std::string val) { static std::string string_escape(const std::string val) {
std::stringstream out; std::stringstream out;
out << "\""; out << "\"";
for (unsigned int i = 0; i < val.size(); ++i) { for (size_t i = 0; i < val.size(); ++i) {
switch (val.data()[i]) { switch (val.data()[i]) {
case '"': case '"':
out << "\\\""; out << "\\\"";
@ -864,10 +870,10 @@ namespace DTSC {
return out.str(); return out.str();
} }
std::string Scan::toPrettyString(unsigned int indent) { std::string Scan::toPrettyString(size_t indent) const {
switch (getType()) { switch (getType()) {
case DTSC_STR: { case DTSC_STR: {
unsigned int strlen = Bit::btohl(p+1); uint32_t strlen = Bit::btohl(p+1);
if (strlen > 250) { if (strlen > 250) {
std::stringstream ret; std::stringstream ret;
ret << "\"" << strlen << " bytes of data\""; ret << "\"" << strlen << " bytes of data\"";
@ -891,25 +897,25 @@ namespace DTSC {
while (i[0] + i[1] != 0 && i < p + len) { //while not encountering 0x0000 (we assume 0x0000EE) while (i[0] + i[1] != 0 && i < p + len) { //while not encountering 0x0000 (we assume 0x0000EE)
if (i + 2 >= p + len) { if (i + 2 >= p + len) {
indent -= 2; indent -= 2;
ret << std::string((size_t)indent, ' ') << "} //walked out of object here"; ret << std::string(indent, ' ') << "} //walked out of object here";
return ret.str(); return ret.str();
} }
if (!first){ if (!first){
ret << "," << std::endl; ret << "," << std::endl;
} }
first = false; first = false;
unsigned int strlen = Bit::btohs(i); uint16_t strlen = Bit::btohs(i);
i += 2; i += 2;
ret << std::string((size_t)indent, ' ') << "\"" << std::string(i, strlen) << "\": " << Scan(i + strlen, len - (i - p)).toPrettyString(indent); ret << std::string(indent, ' ') << "\"" << std::string(i, strlen) << "\": " << Scan(i + strlen, len - (i - p)).toPrettyString(indent);
i = skipDTSC(i + strlen, p + len); i = skipDTSC(i + strlen, p + len);
if (!i) { if (!i) {
indent -= 2; indent -= 2;
ret << std::string((size_t)indent, ' ') << "} //could not locate next object"; ret << std::string(indent, ' ') << "} //could not locate next object";
return ret.str(); return ret.str();
} }
} }
indent -= 2; indent -= 2;
ret << std::endl << std::string((size_t)indent, ' ') << "}"; ret << std::endl << std::string(indent, ' ') << "}";
return ret.str(); return ret.str();
} }
case DTSC_ARR: { case DTSC_ARR: {
@ -926,11 +932,11 @@ namespace DTSC {
ret << "," << std::endl; ret << "," << std::endl;
} }
first = false; first = false;
ret << std::string((size_t)indent, ' ') << tmpScan.toPrettyString(indent); ret << std::string(indent, ' ') << tmpScan.toPrettyString(indent);
} }
} while (tmpScan.getType()); } while (tmpScan.getType());
indent -= 2; indent -= 2;
ret << std::endl << std::string((size_t)indent, ' ') << "]"; ret << std::endl << std::string(indent, ' ') << "]";
return ret.str(); return ret.str();
} }
default: default:
@ -1205,26 +1211,26 @@ namespace DTSC {
Track::Track(Scan & trackRef) { Track::Track(Scan & trackRef) {
if (trackRef.getMember("fragments").getType() == DTSC_STR) { if (trackRef.getMember("fragments").getType() == DTSC_STR) {
char * tmp = 0; char * tmp = 0;
unsigned int tmplen = 0; size_t tmplen = 0;
trackRef.getMember("fragments").getString(tmp, tmplen); trackRef.getMember("fragments").getString(tmp, tmplen);
fragments = std::deque<Fragment>((Fragment *)tmp, ((Fragment *)tmp) + (tmplen / PACKED_FRAGMENT_SIZE)); fragments = std::deque<Fragment>((Fragment *)tmp, ((Fragment *)tmp) + (tmplen / PACKED_FRAGMENT_SIZE));
} }
if (trackRef.getMember("keys").getType() == DTSC_STR) { if (trackRef.getMember("keys").getType() == DTSC_STR) {
char * tmp = 0; char * tmp = 0;
unsigned int tmplen = 0; size_t tmplen = 0;
trackRef.getMember("keys").getString(tmp, tmplen); trackRef.getMember("keys").getString(tmp, tmplen);
keys = std::deque<Key>((Key *)tmp, ((Key *)tmp) + (tmplen / PACKED_KEY_SIZE)); keys = std::deque<Key>((Key *)tmp, ((Key *)tmp) + (tmplen / PACKED_KEY_SIZE));
} }
if (trackRef.getMember("parts").getType() == DTSC_STR) { if (trackRef.getMember("parts").getType() == DTSC_STR) {
char * tmp = 0; char * tmp = 0;
unsigned int tmplen = 0; size_t tmplen = 0;
trackRef.getMember("parts").getString(tmp, tmplen); trackRef.getMember("parts").getString(tmp, tmplen);
parts = std::deque<Part>((Part *)tmp, ((Part *)tmp) + (tmplen / 9)); parts = std::deque<Part>((Part *)tmp, ((Part *)tmp) + (tmplen / 9));
} }
/*LTS-START*/ /*LTS-START*/
if (trackRef.getMember("ivecs").getType() == DTSC_STR) { if (trackRef.getMember("ivecs").getType() == DTSC_STR) {
char * tmp = 0; char * tmp = 0;
unsigned int tmplen = 0; size_t tmplen = 0;
trackRef.getMember("ivecs").getString(tmp, tmplen); trackRef.getMember("ivecs").getString(tmp, tmplen);
ivecs = std::deque<Ivec>((Ivec *)tmp, ((Ivec *)tmp) + (tmplen / 8)); ivecs = std::deque<Ivec>((Ivec *)tmp, ((Ivec *)tmp) + (tmplen / 8));
} }
@ -1253,7 +1259,7 @@ namespace DTSC {
} }
if (trackRef.getMember("keysizes").getType() == DTSC_STR) { if (trackRef.getMember("keysizes").getType() == DTSC_STR) {
char * tmp = 0; char * tmp = 0;
unsigned int tmplen = 0; size_t tmplen = 0;
trackRef.getMember("keysizes").getString(tmp, tmplen); trackRef.getMember("keysizes").getString(tmp, tmplen);
for (unsigned int i = 0; i < tmplen; i += 4){ for (unsigned int i = 0; i < tmplen; i += 4){
keySizes.push_back((((long unsigned)tmp[i]) << 24) | (((long unsigned)tmp[i+1]) << 16) | (((long unsigned int)tmp[i+2]) << 8) | tmp[i+3]); keySizes.push_back((((long unsigned)tmp[i]) << 24) | (((long unsigned)tmp[i+1]) << 16) | (((long unsigned int)tmp[i+2]) << 8) | tmp[i+3]);
@ -1547,10 +1553,10 @@ namespace DTSC {
///\brief Updates a meta object given a DTSC::Packet ///\brief Updates a meta object given a DTSC::Packet
void Meta::update(const DTSC::Packet & pack, unsigned long segment_size) { void Meta::update(const DTSC::Packet & pack, unsigned long segment_size) {
char * data; char * data;
unsigned int dataLen; size_t dataLen;
pack.getString("data", data, dataLen); pack.getString("data", data, dataLen);
char * ivec; char * ivec;
unsigned int ivecLen; size_t ivecLen;
pack.getString("ivec", ivec, ivecLen); pack.getString("ivec", ivec, ivecLen);
/*LTS /*LTS
update(pack.getTime(), pack.hasMember("offset")?pack.getInt("offset"):0, pack.getTrackId(), dataLen, pack.hasMember("bpos")?pack.getInt("bpos"):0, pack.hasMember("keyframe"), pack.getDataLen(), segment_size); update(pack.getTime(), pack.hasMember("offset")?pack.getInt("offset"):0, pack.getTrackId(), dataLen, pack.hasMember("bpos")?pack.getInt("bpos"):0, pack.hasMember("keyframe"), pack.getDataLen(), segment_size);
@ -1564,13 +1570,13 @@ namespace DTSC {
///\brief Updates a meta object given a DTSC::Packet with byte position override. ///\brief Updates a meta object given a DTSC::Packet with byte position override.
void Meta::updatePosOverride(DTSC::Packet & pack, uint64_t bpos) { void Meta::updatePosOverride(DTSC::Packet & pack, uint64_t bpos) {
char * data; char * data;
unsigned int dataLen; size_t dataLen;
pack.getString("data", data, dataLen); pack.getString("data", data, dataLen);
/*LTS /*LTS
update(pack.getTime(), pack.hasMember("offset")?pack.getInt("offset"):0, pack.getTrackId(), dataLen, bpos, pack.hasMember("keyframe"), pack.getDataLen()); update(pack.getTime(), pack.hasMember("offset")?pack.getInt("offset"):0, pack.getTrackId(), dataLen, bpos, pack.hasMember("keyframe"), pack.getDataLen());
LTS*/ LTS*/
char * ivec; char * ivec;
unsigned int ivecLen; size_t ivecLen;
pack.getString("ivec", ivec, ivecLen); pack.getString("ivec", ivec, ivecLen);
update(pack.getTime(), pack.hasMember("offset")?pack.getInt("offset"):0, pack.getTrackId(), dataLen, bpos, pack.hasMember("keyframe"), pack.getDataLen(), 5000, ivecLen?ivec:0); update(pack.getTime(), pack.hasMember("offset")?pack.getInt("offset"):0, pack.getTrackId(), dataLen, bpos, pack.hasMember("keyframe"), pack.getDataLen(), 5000, ivecLen?ivec:0);
} }

View file

@ -37,11 +37,8 @@ namespace EBML{
uint64_t UniInt::readInt(const char *p){ uint64_t UniInt::readInt(const char *p){
switch (readSize(p)){ switch (readSize(p)){
case 1: case 1:
if (p[0] == 0xFF){ if (p[0] == 0xFF){return 0xFFFFFFFFFFFFFFFFull;}
return 0xFFFFFFFFFFFFFFFFull;
}else{
return p[0] & 0x7F; return p[0] & 0x7F;
}
case 2: return Bit::btohs(p) & 0x3FFFull; case 2: return Bit::btohs(p) & 0x3FFFull;
case 3: return Bit::btoh24(p) & 0x1FFFFFull; case 3: return Bit::btoh24(p) & 0x1FFFFFull;
case 4: return Bit::btohl(p) & 0xFFFFFFFull; case 4: return Bit::btohl(p) & 0xFFFFFFFull;
@ -66,8 +63,8 @@ namespace EBML{
} }
} }
/// Reads an EBML-encoded singed integer from a pointer. Expects the whole number to be readable without /// Reads an EBML-encoded singed integer from a pointer. Expects the whole number to be readable
/// bounds checking. /// without bounds checking.
int64_t UniInt::readSInt(const char *p){ int64_t UniInt::readSInt(const char *p){
switch (readSize(p)){ switch (readSize(p)){
case 1: return ((int64_t)readInt(p)) - 0x3Fll; case 1: return ((int64_t)readInt(p)) - 0x3Fll;
@ -99,9 +96,7 @@ namespace EBML{
// ELEM_MASTER types do not contain payload if minimal is true // ELEM_MASTER types do not contain payload if minimal is true
if (minimal && Element(p, true).getType() == ELEM_MASTER){return needed;} if (minimal && Element(p, true).getType() == ELEM_MASTER){return needed;}
uint64_t pSize = UniInt::readInt(sizeOffset); uint64_t pSize = UniInt::readInt(sizeOffset);
if (pSize != 0xFFFFFFFFFFFFFFFFull){ if (pSize != 0xFFFFFFFFFFFFFFFFull){needed += pSize;}
needed += pSize;
}
return needed; return needed;
} }
@ -476,7 +471,7 @@ namespace EBML{
case 6: val = Bit::btoh48(payDat); break; case 6: val = Bit::btoh48(payDat); break;
case 7: val = Bit::btoh56(payDat); break; case 7: val = Bit::btoh56(payDat); break;
case 8: val = Bit::btohll(payDat); break; case 8: val = Bit::btohll(payDat); break;
default: WARN_MSG("UInt payload size %llu not implemented", getPayloadLen()); default: WARN_MSG("UInt payload size %" PRIu64 " not implemented", getPayloadLen());
} }
return val; return val;
} }
@ -493,7 +488,7 @@ namespace EBML{
case 6: val = (((int64_t)Bit::btoh48(payDat)) << 16) >> 16; break; case 6: val = (((int64_t)Bit::btoh48(payDat)) << 16) >> 16; break;
case 7: val = (((int64_t)Bit::btoh56(payDat)) << 8) >> 8; break; case 7: val = (((int64_t)Bit::btoh56(payDat)) << 8) >> 8; break;
case 8: val = Bit::btohll(payDat); break; case 8: val = Bit::btohll(payDat); break;
default: WARN_MSG("Int payload size %llu not implemented", getPayloadLen()); default: WARN_MSG("Int payload size %" PRIu64 " not implemented", getPayloadLen());
} }
return val; return val;
} }
@ -504,21 +499,21 @@ namespace EBML{
switch (getPayloadLen()){ switch (getPayloadLen()){
case 4: val = Bit::btohf(payDat); break; case 4: val = Bit::btohf(payDat); break;
case 8: val = Bit::btohd(payDat); break; case 8: val = Bit::btohd(payDat); break;
default: WARN_MSG("Float payload size %llu not implemented", getPayloadLen()); default: WARN_MSG("Float payload size %" PRIu64 " not implemented", getPayloadLen());
} }
return val; return val;
} }
std::string Element::getValString() const{ std::string Element::getValString() const{
uint64_t strLen = getPayloadLen(); uint64_t strLen = getPayloadLen();
const char * strPtr = getPayload(); const char *strPtr = getPayload();
while (strLen && strPtr[strLen-1] == 0){--strLen;} while (strLen && strPtr[strLen - 1] == 0){--strLen;}
return std::string(strPtr, strLen); return std::string(strPtr, strLen);
} }
std::string Element::getValStringUntrimmed() const{ std::string Element::getValStringUntrimmed() const{
uint64_t strLen = getPayloadLen(); uint64_t strLen = getPayloadLen();
const char * strPtr = getPayload(); const char *strPtr = getPayload();
return std::string(strPtr, strLen); return std::string(strPtr, strLen);
} }
@ -549,16 +544,16 @@ namespace EBML{
uint32_t Block::getFrameSize(uint8_t no) const{ uint32_t Block::getFrameSize(uint8_t no) const{
switch (getLacing()){ switch (getLacing()){
case 0://No lacing case 0: // No lacing
return getPayloadLen() - (UniInt::readSize(getPayload()) + 3); return getPayloadLen() - (UniInt::readSize(getPayload()) + 3);
case 1:{//Xiph lacing case 1:{// Xiph lacing
uint64_t offset = (UniInt::readSize(getPayload()) + 3) + 1; uint64_t offset = (UniInt::readSize(getPayload()) + 3) + 1;
uint8_t frames = getFrameCount(); uint8_t frames = getFrameCount();
if (no > frames - 1){return 0;}//out of bounds if (no > frames - 1){return 0;}// out of bounds
uint64_t laceNo = 0; uint64_t laceNo = 0;
uint32_t currSize = 0; uint32_t currSize = 0;
uint32_t totSize = 0; uint32_t totSize = 0;
while (laceNo <= no && (laceNo < frames-1) && offset < getPayloadLen()){ while (laceNo <= no && (laceNo < frames - 1) && offset < getPayloadLen()){
currSize += getPayload()[offset]; currSize += getPayload()[offset];
if (getPayload()[offset] != 255){ if (getPayload()[offset] != 255){
totSize += currSize; totSize += currSize;
@ -568,17 +563,17 @@ namespace EBML{
} }
++offset; ++offset;
} }
return getPayloadLen() - offset - totSize;//last frame is rest of the data return getPayloadLen() - offset - totSize; // last frame is rest of the data
} }
case 3:{//EBML lacing case 3:{// EBML lacing
const char * pl = getPayload(); const char *pl = getPayload();
uint64_t offset = (UniInt::readSize(pl) + 3) + 1; uint64_t offset = (UniInt::readSize(pl) + 3) + 1;
uint8_t frames = getFrameCount(); uint8_t frames = getFrameCount();
if (no > frames - 1){return 0;}//out of bounds if (no > frames - 1){return 0;}// out of bounds
uint64_t laceNo = 0; uint64_t laceNo = 0;
uint32_t currSize = 0; uint32_t currSize = 0;
uint32_t totSize = 0; uint32_t totSize = 0;
while (laceNo <= no && (laceNo < frames-1) && offset < getPayloadLen()){ while (laceNo <= no && (laceNo < frames - 1) && offset < getPayloadLen()){
if (laceNo == 0){ if (laceNo == 0){
currSize = UniInt::readInt(pl + offset); currSize = UniInt::readInt(pl + offset);
}else{ }else{
@ -589,9 +584,9 @@ namespace EBML{
++laceNo; ++laceNo;
offset += UniInt::readSize(pl + offset); offset += UniInt::readSize(pl + offset);
} }
return getPayloadLen() - offset - totSize;//last frame is rest of the data return getPayloadLen() - offset - totSize; // last frame is rest of the data
} }
case 2://Fixed lacing case 2: // Fixed lacing
return (getPayloadLen() - (UniInt::readSize(getPayload()) + 3)) / getFrameCount(); return (getPayloadLen() - (UniInt::readSize(getPayload()) + 3)) / getFrameCount();
} }
WARN_MSG("Lacing type not yet implemented!"); WARN_MSG("Lacing type not yet implemented!");
@ -600,48 +595,42 @@ namespace EBML{
const char *Block::getFrameData(uint8_t no) const{ const char *Block::getFrameData(uint8_t no) const{
switch (getLacing()){ switch (getLacing()){
case 0://No lacing case 0: // No lacing
return getPayload() + (UniInt::readSize(getPayload()) + 3); return getPayload() + (UniInt::readSize(getPayload()) + 3);
case 1:{//Xiph lacing case 1:{// Xiph lacing
uint64_t offset = (UniInt::readSize(getPayload()) + 3) + 1; uint64_t offset = (UniInt::readSize(getPayload()) + 3) + 1;
uint8_t frames = getFrameCount(); uint8_t frames = getFrameCount();
if (no > frames - 1){return 0;}//out of bounds if (no > frames - 1){return 0;}// out of bounds
uint64_t laceNo = 0; uint64_t laceNo = 0;
uint32_t currSize = 0; uint32_t currSize = 0;
while ((laceNo < frames-1) && offset < getPayloadLen()){ while ((laceNo < frames - 1) && offset < getPayloadLen()){
if (laceNo < no){ if (laceNo < no){currSize += getPayload()[offset];}
currSize += getPayload()[offset]; if (getPayload()[offset] != 255){++laceNo;}
}
if (getPayload()[offset] != 255){
++laceNo;
}
++offset; ++offset;
} }
return getPayload() + offset + currSize; return getPayload() + offset + currSize;
} }
case 3:{//EBML lacing case 3:{// EBML lacing
const char * pl = getPayload(); const char *pl = getPayload();
uint64_t offset = (UniInt::readSize(pl) + 3) + 1; uint64_t offset = (UniInt::readSize(pl) + 3) + 1;
uint8_t frames = getFrameCount(); uint8_t frames = getFrameCount();
if (no > frames - 1){return 0;}//out of bounds if (no > frames - 1){return 0;}// out of bounds
uint64_t laceNo = 0; uint64_t laceNo = 0;
uint32_t currSize = 0; uint32_t currSize = 0;
uint32_t totSize = 0; uint32_t totSize = 0;
while ((laceNo < frames-1) && offset < getPayloadLen()){ while ((laceNo < frames - 1) && offset < getPayloadLen()){
if (laceNo == 0){ if (laceNo == 0){
currSize = UniInt::readInt(pl + offset); currSize = UniInt::readInt(pl + offset);
}else{ }else{
currSize += UniInt::readSInt(pl + offset); currSize += UniInt::readSInt(pl + offset);
} }
if (laceNo < no){ if (laceNo < no){totSize += currSize;}
totSize += currSize;
}
++laceNo; ++laceNo;
offset += UniInt::readSize(pl + offset); offset += UniInt::readSize(pl + offset);
} }
return pl + offset + totSize; return pl + offset + totSize;
} }
case 2://Fixed lacing case 2: // Fixed lacing
return getPayload() + (UniInt::readSize(getPayload()) + 3) + 1 + no * getFrameSize(no); return getPayload() + (UniInt::readSize(getPayload()) + 3) + 1 + no * getFrameSize(no);
} }
WARN_MSG("Lacing type not yet implemented!"); WARN_MSG("Lacing type not yet implemented!");
@ -657,8 +646,7 @@ namespace EBML{
if (isInvisible()){ret << " [Invisible]";} if (isInvisible()){ret << " [Invisible]";}
if (isDiscardable()){ret << " [Discardable]";} if (isDiscardable()){ret << " [Discardable]";}
switch (getLacing()){ switch (getLacing()){
case 0: case 0: break; // No lacing
break; // No lacing
case 1: ret << " [Lacing: Xiph]"; break; case 1: ret << " [Lacing: Xiph]"; break;
case 3: ret << " [Lacing: EMBL]"; break; case 3: ret << " [Lacing: EMBL]"; break;
case 2: ret << " [Lacing: Fixed]"; break; case 2: ret << " [Lacing: Fixed]"; break;
@ -668,7 +656,8 @@ namespace EBML{
for (uint32_t frameNo = 0; frameNo < getFrameCount(); ++frameNo){ for (uint32_t frameNo = 0; frameNo < getFrameCount(); ++frameNo){
const char *payDat = getFrameData(frameNo); const char *payDat = getFrameData(frameNo);
const uint64_t payLen = getFrameSize(frameNo); const uint64_t payLen = getFrameSize(frameNo);
ret << std::dec << std::string(indent + 4, ' ') << "Frame " << (frameNo+1) << " (" << payLen << "b):"; ret << std::dec << std::string(indent + 4, ' ') << "Frame " << (frameNo + 1) << " ("
<< payLen << "b):";
if (!payDat || !payLen || detail < 6){ if (!payDat || !payLen || detail < 6){
ret << std::endl; ret << std::endl;
continue; continue;
@ -693,5 +682,5 @@ namespace EBML{
ret << std::endl; ret << std::endl;
return ret.str(); return ret.str();
} }
} }// namespace EBML

View file

@ -102,7 +102,7 @@ namespace EBML{
private: private:
const char *data; const char *data;
bool minimalMode; ///<If set, ELEM_MASTER elements will not access payload data when bool minimalMode; ///< If set, ELEM_MASTER elements will not access payload data when
/// pretty-printing. /// pretty-printing.
}; };
@ -120,5 +120,5 @@ namespace EBML{
const char *getFrameData(uint8_t no) const; const char *getFrameData(uint8_t no) const;
virtual std::string toPrettyString(const uint8_t indent = 0, const uint8_t detail = 3) const; virtual std::string toPrettyString(const uint8_t indent = 0, const uint8_t detail = 3) const;
}; };
} }// namespace EBML

View file

@ -33,9 +33,8 @@ namespace EBML{
return 3; return 3;
}else if (val >= 0x100ull){ }else if (val >= 0x100ull){
return 2; return 2;
}else{
return 1;
} }
return 1;
} }
uint32_t sizeElemUInt(uint32_t ID, const uint64_t val){ uint32_t sizeElemUInt(uint32_t ID, const uint64_t val){
@ -80,7 +79,6 @@ namespace EBML{
} }
void sendElemID(Socket::Connection &C, uint32_t ID, const uint64_t val){ void sendElemID(Socket::Connection &C, uint32_t ID, const uint64_t val){
char tmp[8];
uint8_t wSize = UniInt::writeSize(val); uint8_t wSize = UniInt::writeSize(val);
sendElemHead(C, ID, wSize); sendElemHead(C, ID, wSize);
sendUniInt(C, val); sendUniInt(C, val);
@ -119,11 +117,11 @@ namespace EBML{
} }
void sendElemInfo(Socket::Connection &C, const std::string &appName, double duration){ void sendElemInfo(Socket::Connection &C, const std::string &appName, double duration){
sendElemHead(C, EID_INFO, 13 + 2 * appName.size() + (duration>0?sizeElemDbl(EID_DURATION, duration):0)); sendElemHead(C, EID_INFO,
13 + 2 * appName.size() +
(duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
sendElemUInt(C, EID_TIMECODESCALE, 1000000); sendElemUInt(C, EID_TIMECODESCALE, 1000000);
if (duration > 0){ if (duration > 0){sendElemDbl(C, EID_DURATION, duration);}
sendElemDbl(C, EID_DURATION, duration);
}
sendElemStr(C, EID_MUXINGAPP, appName); sendElemStr(C, EID_MUXINGAPP, appName);
sendElemStr(C, EID_WRITINGAPP, appName); sendElemStr(C, EID_WRITINGAPP, appName);
} }
@ -133,24 +131,23 @@ namespace EBML{
} }
uint32_t sizeElemInfo(const std::string &appName, double duration){ uint32_t sizeElemInfo(const std::string &appName, double duration){
return 13 + 2 * appName.size() + (duration>0?sizeElemDbl(EID_DURATION, duration):0) + sizeElemHead(EID_INFO, 13 + 2 * appName.size() + (duration>0?sizeElemDbl(EID_DURATION, duration):0)); return 13 + 2 * appName.size() + (duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0) +
sizeElemHead(EID_INFO, 13 + 2 * appName.size() +
(duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
} }
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet & pkt, uint64_t clusterTime, bool forceKeyframe){ void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime,
unsigned int dataLen = 0; bool forceKeyframe){
char * dataPointer = 0; size_t dataLen = 0;
char *dataPointer = 0;
pkt.getString("data", dataPointer, dataLen); pkt.getString("data", dataPointer, dataLen);
uint32_t blockSize = UniInt::writeSize(pkt.getTrackId()) + 3 + dataLen; uint32_t blockSize = UniInt::writeSize(pkt.getTrackId()) + 3 + dataLen;
sendElemHead(C, EID_SIMPLEBLOCK, blockSize); sendElemHead(C, EID_SIMPLEBLOCK, blockSize);
sendUniInt(C, pkt.getTrackId()); sendUniInt(C, pkt.getTrackId());
char blockHead[3] = {0, 0, 0}; char blockHead[3] ={0, 0, 0};
if (pkt.hasMember("keyframe") || forceKeyframe){ if (pkt.hasMember("keyframe") || forceKeyframe){blockHead[2] = 0x80;}
blockHead[2] = 0x80;
}
int offset = 0; int offset = 0;
if (pkt.hasMember("offset")){ if (pkt.hasMember("offset")){offset = pkt.getInt("offset");}
offset = pkt.getInt("offset");
}
Bit::htobs(blockHead, (int16_t)(pkt.getTime() + offset - clusterTime)); Bit::htobs(blockHead, (int16_t)(pkt.getTime() + offset - clusterTime));
C.SendNow(blockHead, 3); C.SendNow(blockHead, 3);
C.SendNow(dataPointer, dataLen); C.SendNow(dataPointer, dataLen);
@ -173,7 +170,8 @@ namespace EBML{
return sizeElemHead(EID_SEEK, elems) + elems; return sizeElemHead(EID_SEEK, elems) + elems;
} }
void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos){ void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos,
uint64_t relaPos){
uint32_t elemsA = 0, elemsB = 0; uint32_t elemsA = 0, elemsB = 0;
elemsA += sizeElemUInt(EID_CUETRACK, track); elemsA += sizeElemUInt(EID_CUETRACK, track);
elemsA += sizeElemUInt(EID_CUECLUSTERPOSITION, clusterPos); elemsA += sizeElemUInt(EID_CUECLUSTERPOSITION, clusterPos);
@ -197,6 +195,5 @@ namespace EBML{
return sizeElemHead(EID_CUEPOINT, elems) + elems; return sizeElemHead(EID_CUEPOINT, elems) + elems;
} }
}// namespace EBML
}

View file

@ -1,10 +1,10 @@
#include "ebml.h"
#include "socket.h"
#include "bitfields.h" #include "bitfields.h"
#include "dtsc.h" #include "dtsc.h"
#include "ebml.h"
#include "socket.h"
namespace EBML{ namespace EBML{
static void sendUniInt(Socket::Connection &C, const uint64_t val); void sendUniInt(Socket::Connection &C, const uint64_t val);
void sendElemHead(Socket::Connection &C, uint32_t ID, const uint64_t size); void sendElemHead(Socket::Connection &C, uint32_t ID, const uint64_t size);
void sendElemUInt(Socket::Connection &C, uint32_t ID, const uint64_t val); void sendElemUInt(Socket::Connection &C, uint32_t ID, const uint64_t val);
void sendElemID(Socket::Connection &C, uint32_t ID, const uint64_t val); void sendElemID(Socket::Connection &C, uint32_t ID, const uint64_t val);
@ -17,7 +17,8 @@ namespace EBML{
void sendElemSeek(Socket::Connection &C, uint32_t ID, uint64_t bytePos); void sendElemSeek(Socket::Connection &C, uint32_t ID, uint64_t bytePos);
uint32_t sizeElemSeek(uint32_t ID, uint64_t bytePos); uint32_t sizeElemSeek(uint32_t ID, uint64_t bytePos);
void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos); void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos,
uint64_t relaPos);
uint32_t sizeElemCuePoint(uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos); uint32_t sizeElemCuePoint(uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos);
uint8_t sizeUInt(const uint64_t val); uint8_t sizeUInt(const uint64_t val);
@ -27,7 +28,8 @@ namespace EBML{
uint32_t sizeElemDbl(uint32_t ID, const double val); uint32_t sizeElemDbl(uint32_t ID, const double val);
uint32_t sizeElemStr(uint32_t ID, const std::string &val); uint32_t sizeElemStr(uint32_t ID, const std::string &val);
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet & pkt, uint64_t clusterTime, bool forceKeyframe = false); void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime,
bool forceKeyframe = false);
uint32_t sizeSimpleBlock(uint64_t trackId, uint32_t dataSize); uint32_t sizeSimpleBlock(uint64_t trackId, uint32_t dataSize);
} }// namespace EBML

View file

@ -80,6 +80,12 @@ namespace Encodings{
return r; return r;
} }
std::string Hex::encode(const std::string &in){
std::string res;
for (size_t i = 0; i < in.size(); i++){res += chr(in[i]);}
return res;
}
/// Decodes a hex-encoded std::string to a raw binary std::string. /// Decodes a hex-encoded std::string to a raw binary std::string.
std::string Hex::decode(const std::string &in){ std::string Hex::decode(const std::string &in){
std::string ret(in.size() / 2, '\000'); std::string ret(in.size() / 2, '\000');
@ -97,8 +103,10 @@ namespace Encodings{
for (int i = 0; i < max; i++){ for (int i = 0; i < max; i++){
if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') || if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') ||
('A' <= c[i] && c[i] <= 'Z') || ('A' <= c[i] && c[i] <= 'Z') ||
(c[i] == '$' || c[i] == '-' || c[i] == '_' || c[i] == '.' || c[i] == ',' || c[i] == '!' || c[i] == '~' || c[i] == ';' || (c[i] == '$' || c[i] == '-' || c[i] == '_' || c[i] == '.' || c[i] == ',' || c[i] == '!' ||
c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'') || (ign.size() && ign.find(c[i]) != std::string::npos)){ c[i] == '~' || c[i] == ';' || c[i] == '*' || c[i] == '(' || c[i] == ')' ||
c[i] == '\'') ||
(ign.size() && ign.find(c[i]) != std::string::npos)){
escaped.append(&c[i], 1); escaped.append(&c[i], 1);
}else{ }else{
if (c[i] == ' '){ if (c[i] == ' '){

View file

@ -2,41 +2,42 @@
#include <string> #include <string>
/// Namespace for character encoding functions and classes /// Namespace for character encoding functions and classes
namespace Encodings { namespace Encodings{
/// Holds base64 decoding and encoding functions. /// Holds base64 decoding and encoding functions.
class Base64 { class Base64{
private: private:
static const std::string chars; static const std::string chars;
static inline bool is_base64(unsigned char c); static inline bool is_base64(unsigned char c);
public: public:
static std::string encode(std::string const input); static std::string encode(std::string const input);
static std::string decode(std::string const & encoded_string); static std::string decode(std::string const &encoded_string);
}; };
/// urlencoding and urldecoding functions /// urlencoding and urldecoding functions
class URL { class URL{
public: public:
/// urldecodes std::string data, parsing out both %-encoded characters and +-encoded spaces. /// urldecodes std::string data, parsing out both %-encoded characters and +-encoded spaces.
static std::string decode(const std::string & in); static std::string decode(const std::string &in);
/// urlencodes std::string data, leaving only the characters A-Za-z0-9~!&()' alone. /// urlencodes std::string data, leaving only the characters A-Za-z0-9~!&()' alone.
static std::string encode(const std::string & c, const std::string &ign = ""); static std::string encode(const std::string &c, const std::string &ign = "");
}; };
/// Hexadecimal-related functions /// Hexadecimal-related functions
class Hex { class Hex{
public: public:
/// Decodes a single hexadecimal character to integer, case-insensitive. /// Decodes a single hexadecimal character to integer, case-insensitive.
static inline int ord(char c){ static inline int ord(char c){return ((c & 15) + (((c & 64) >> 6) | ((c & 64) >> 3)));}
return ((c&15) + (((c&64)>>6) | ((c&64)>>3)));
}
/// Encodes a single character as two hex digits in string form. /// Encodes a single character as two hex digits in string form.
static std::string chr(char dec); static std::string chr(char dec);
/// Decodes a hex-encoded std::string to a raw binary std::string. /// Decodes a hex-encoded std::string to a raw binary std::string.
static std::string decode(const std::string & in); static std::string decode(const std::string &in);
/// Encodes a raw binary std::string to its hex-encoded form
static std::string encode(const std::string &in);
}; };
} }// namespace Encodings

View file

@ -115,7 +115,7 @@ namespace Encryption {
void encryptPlayReady(DTSC::Packet & thisPack, std::string & codec, const char * iVec, const char * key) { void encryptPlayReady(DTSC::Packet & thisPack, std::string & codec, const char * iVec, const char * key) {
char * data; char * data;
unsigned int dataLen; size_t dataLen;
thisPack.getString("data", data, dataLen); thisPack.getString("data", data, dataLen);
if (codec == "H264") { if (codec == "H264") {

File diff suppressed because it is too large Load diff

View file

@ -2,73 +2,78 @@
/// Holds all headers for the FLV namespace. /// Holds all headers for the FLV namespace.
#pragma once #pragma once
#include "socket.h"
#include "dtsc.h"
#include "amf.h" #include "amf.h"
#include "dtsc.h"
#include "socket.h"
#include <string> #include <string>
// forward declaration of RTMPStream::Chunk to avoid circular dependencies.
//forward declaration of RTMPStream::Chunk to avoid circular dependencies. namespace RTMPStream{
namespace RTMPStream {
class Chunk; class Chunk;
} }
/// This namespace holds all FLV-parsing related functionality. /// This namespace holds all FLV-parsing related functionality.
namespace FLV { namespace FLV{
//variables // variables
extern char Header[13]; ///< Holds the last FLV header parsed. extern char Header[13]; ///< Holds the last FLV header parsed.
extern bool Parse_Error; ///< This variable is set to true if a problem is encountered while parsing the FLV. extern bool Parse_Error; ///< This variable is set to true if a problem is encountered while
extern std::string Error_Str; ///< This variable is set if a problem is encountered while parsing the FLV. ///< parsing the FLV.
extern std::string
Error_Str; ///< This variable is set if a problem is encountered while parsing the FLV.
//functions // functions
bool check_header(char * header); ///< Checks a FLV Header for validness. bool check_header(char *header); ///< Checks a FLV Header for validness.
bool is_header(char * header); ///< Checks the first 3 bytes for the string "FLV". bool is_header(char *header); ///< Checks the first 3 bytes for the string "FLV".
/// Helper function that can quickly skip through a file looking for a particular tag type /// Helper function that can quickly skip through a file looking for a particular tag type
bool seekToTagType(FILE * f, uint8_t type); bool seekToTagType(FILE *f, uint8_t type);
/// This class is used to hold, work with and get information about a single FLV tag. /// This class is used to hold, work with and get information about a single FLV tag.
class Tag { class Tag{
public: public:
int len; ///< Actual length of tag. int len; ///< Actual length of tag.
bool isKeyframe; ///< True if current tag is a video keyframe. bool isKeyframe; ///< True if current tag is a video keyframe.
char * data; ///< Pointer to tag buffer. char *data; ///< Pointer to tag buffer.
bool needsInitData(); ///< True if this media type requires init data. bool needsInitData(); ///< True if this media type requires init data.
bool isInitData(); ///< True if current tag is init data for this media type. bool isInitData(); ///< True if current tag is init data for this media type.
const char * getAudioCodec(); ///< Returns a c-string with the audio codec name. const char *getAudioCodec(); ///< Returns a c-string with the audio codec name.
const char * getVideoCodec(); ///< Returns a c-string with the video codec name. const char *getVideoCodec(); ///< Returns a c-string with the video codec name.
std::string tagType(); ///< Returns a std::string describing the tag in detail. std::string tagType(); ///< Returns a std::string describing the tag in detail.
unsigned int tagTime(); uint64_t tagTime();
void tagTime(unsigned int T); void tagTime(uint64_t T);
int offset(); int64_t offset();
void offset(int o); void offset(int64_t o);
Tag(); ///< Constructor for a new, empty, tag. Tag(); ///< Constructor for a new, empty, tag.
Tag(const Tag & O); ///< Copy constructor, copies the contents of an existing tag. Tag(const Tag &O); ///< Copy constructor, copies the contents of an existing tag.
Tag & operator=(const Tag & O); ///< Assignment operator - works exactly like the copy constructor. Tag &
Tag(const RTMPStream::Chunk & O); ///<Copy constructor from a RTMP chunk. operator=(const Tag &O); ///< Assignment operator - works exactly like the copy constructor.
Tag(const RTMPStream::Chunk &O); ///< Copy constructor from a RTMP chunk.
~Tag(); ///< Generic destructor. ~Tag(); ///< Generic destructor.
//loader functions // loader functions
bool ChunkLoader(const RTMPStream::Chunk & O); bool ChunkLoader(const RTMPStream::Chunk &O);
bool DTSCLoader(DTSC::Packet & packData, DTSC::Track & track); bool DTSCLoader(DTSC::Packet &packData, DTSC::Track &track);
bool DTSCVideoInit(DTSC::Track & video); bool DTSCVideoInit(DTSC::Track &video);
bool DTSCAudioInit(DTSC::Track & audio); bool DTSCAudioInit(DTSC::Track &audio);
bool DTSCMetaInit(DTSC::Meta & M, std::set<long unsigned int> & selTracks); bool DTSCMetaInit(DTSC::Meta &M, std::set<long unsigned int> &selTracks);
void toMeta(DTSC::Meta & metadata, AMF::Object & amf_storage, unsigned int reTrack = 0); void toMeta(DTSC::Meta &metadata, AMF::Object &amf_storage, unsigned int reTrack = 0);
bool MemLoader(char * D, unsigned int S, unsigned int & P); bool MemLoader(char *D, unsigned int S, unsigned int &P);
bool FileLoader(FILE * f); bool FileLoader(FILE *f);
unsigned int getTrackID(); unsigned int getTrackID();
char * getData(); char *getData();
unsigned int getDataLen(); unsigned int getDataLen();
protected: protected:
int buf; ///< Maximum length of buffer space. int buf; ///< Maximum length of buffer space.
bool done; ///< Body reading done? bool done; ///< Body reading done?
unsigned int sofar; ///< How many bytes are read sofar? unsigned int sofar; ///< How many bytes are read sofar?
void setLen(); void setLen();
bool checkBufferSize(); bool checkBufferSize();
//loader helper functions // loader helper functions
bool MemReadUntil(char * buffer, unsigned int count, unsigned int & sofar, char * D, unsigned int S, unsigned int & P); bool MemReadUntil(char *buffer, unsigned int count, unsigned int &sofar, char *D,
bool FileReadUntil(char * buffer, unsigned int count, unsigned int & sofar, FILE * f); unsigned int S, unsigned int &P);
bool FileReadUntil(char *buffer, unsigned int count, unsigned int &sofar, FILE *f);
}; };
//Tag // Tag
}// namespace FLV
}//FLV namespace

File diff suppressed because it is too large Load diff

View file

@ -1,116 +1,122 @@
#pragma once #pragma once
#include <cstdio>
#include <cstdlib>
#include <deque> #include <deque>
#include <string> #include <string>
#include <cstdlib>
#include <cstdio>
#include "nal.h"
#include "bitfields.h" #include "bitfields.h"
#include "bitstream.h" #include "bitstream.h"
#include "nal.h"
namespace h264 { namespace h264{
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len); std::deque<nalu::nalData> analysePackets(const char *data, size_t len);
///Struct containing pre-calculated metadata of an SPS nal unit. Width and height in pixels, fps in Hz /// Struct containing pre-calculated metadata of an SPS nal unit. Width and height in pixels, fps
struct SPSMeta { /// in Hz
unsigned int width; struct SPSMeta{
unsigned int height; uint32_t width;
uint32_t height;
double fps; double fps;
uint8_t profile; uint8_t profile;
uint8_t level; uint8_t level;
bool sep_col_plane; bool sep_col_plane;
uint8_t cnt_type; uint8_t cnt_type;
bool gaps;///< Gaps in frame num allowed flag bool gaps; ///< Gaps in frame num allowed flag
bool mbs_only;///<MBS only flag bool mbs_only; ///< MBS only flag
uint16_t log2_max_frame_num; uint16_t log2_max_frame_num;
uint16_t log2_max_order_cnt; uint16_t log2_max_order_cnt;
uint16_t max_ref_frames;///<Maximum number of reference frames uint16_t max_ref_frames; ///< Maximum number of reference frames
}; };
///Class for analyzing generic nal units /// Class for analyzing generic nal units
class NAL { class NAL{
public: public:
NAL(); NAL();
NAL(std::string & InputData); NAL(std::string &InputData);
bool ReadData(std::string & InputData, bool raw = false); bool ReadData(std::string &InputData, bool raw = false);
std::string AnnexB(bool LongIntro = false); std::string AnnexB(bool LongIntro = false);
std::string SizePrepended(); std::string SizePrepended();
int Type(); int Type();
std::string getData(); 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 protected:
class SPS: public NAL { uint32_t 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: public:
SPS(): NAL() {}; SPS() : NAL(){}
SPS(std::string & InputData, bool raw = false); SPS(std::string &InputData, bool raw = false);
SPSMeta getCharacteristics(); SPSMeta getCharacteristics();
void analyzeSPS(); void analyzeSPS();
}; };
///Special instance of NAL class for analyzing PPS nal units /// Special instance of NAL class for analyzing PPS nal units
class PPS: public NAL { class PPS : public NAL{
public: public:
PPS(): NAL() {}; PPS() : NAL(){}
PPS(std::string & InputData): NAL(InputData) {}; PPS(std::string &InputData) : NAL(InputData){}
void analyzePPS(); void analyzePPS();
}; };
class sequenceParameterSet{
class sequenceParameterSet {
public: public:
sequenceParameterSet(const char * _data = NULL, size_t _dataLen = 0); sequenceParameterSet(const char *_data = NULL, size_t _dataLen = 0);
void fromDTSCInit(const std::string & dtscInit); void fromDTSCInit(const std::string &dtscInit);
SPSMeta getCharacteristics() const; SPSMeta getCharacteristics() const;
private: private:
const char * data; const char *data;
size_t dataLen; size_t dataLen;
}; };
bool isKeyframe(const char * data, uint32_t len); bool isKeyframe(const char *data, uint32_t len);
class nalUnit { class nalUnit{
public: public:
nalUnit(const char * data, size_t len) : payload(data, len) {} nalUnit(const char *data, size_t len) : payload(data, len){}
uint8_t getType() { return payload[0] & 0x1F; } virtual ~nalUnit(){}
uint32_t getSize(){return payload.size();}
virtual void toPrettyString(std::ostream & out){ uint8_t getType(){return payload[0] & 0x1F;}
out << "Nal unit of type " << (((uint8_t)payload[0]) & 0x1F) << ", " << payload.size() << " bytes long" << std::endl; size_t getSize(){return payload.size();}
virtual void toPrettyString(std::ostream &out){
out << "Nal unit of type " << (((uint8_t)payload[0]) & 0x1F) << ", " << payload.size()
<< " bytes long" << std::endl;
} }
void write(std::ostream & out){ void write(std::ostream &out){
//always writes in annex_b style // always writes in annex_b style
out.write("\000\000\000\001", 4); out.write("\000\000\000\001", 4);
out.write(payload.data(), payload.size()); out.write(payload.data(), payload.size());
} }
virtual std::string generate() { return ""; } virtual std::string generate(){return "";}
virtual void setSPSNumber(size_t newNumber) {} virtual void setSPSNumber(size_t newNumber){}
virtual void setPPSNumber(size_t newNumber) {} virtual void setPPSNumber(size_t newNumber){}
protected: protected:
std::string payload; std::string payload;
}; };
class hrd_parameters { class hrd_parameters{
public: public:
hrd_parameters() {} hrd_parameters(){}
hrd_parameters(Utils::bitstream & bs); hrd_parameters(Utils::bitstream &bs);
void toPrettyString(std::ostream & out, size_t indent = 0); void toPrettyString(std::ostream &out, size_t indent = 0);
uint64_t cpbCntMinus1; uint64_t cpbCntMinus1;
uint8_t bitRateScale; uint8_t bitRateScale;
uint8_t cpbSizeScale; uint8_t cpbSizeScale;
}; };
class vui_parameters { class vui_parameters{
public: public:
vui_parameters() {}; vui_parameters(){}
vui_parameters(Utils::bitstream & bs); vui_parameters(Utils::bitstream &bs);
void generate(Utils::bitWriter & bw); void generate(Utils::bitWriter &bw);
void toPrettyString(std::ostream & out, size_t indent = 0); void toPrettyString(std::ostream &out, size_t indent = 0);
bool aspectRatioInfoPresentFlag; bool aspectRatioInfoPresentFlag;
uint8_t aspectRatioIdc; uint8_t aspectRatioIdc;
@ -148,17 +154,16 @@ namespace h264 {
uint64_t maxDecFrameBuffering; uint64_t maxDecFrameBuffering;
}; };
class spsUnit : public nalUnit { class spsUnit : public nalUnit{
public: public:
spsUnit(const char * data, size_t len); spsUnit(const char *data, size_t len);
~spsUnit(){ ~spsUnit(){
if (scalingListPresentFlags != NULL){ if (scalingListPresentFlags != NULL){free(scalingListPresentFlags);}
free(scalingListPresentFlags);
}
} }
std::string generate(); std::string generate();
void toPrettyString(std::ostream & out); void toPrettyString(std::ostream &out);
void scalingList(uint64_t * scalingList, size_t sizeOfScalingList, bool & useDefaultScalingMatrixFlag, Utils::bitstream & bs); void scalingList(uint64_t *scalingList, size_t sizeOfScalingList,
bool &useDefaultScalingMatrixFlag, Utils::bitstream &bs);
void setSPSNumber(size_t newNumber); void setSPSNumber(size_t newNumber);
uint8_t profileIdc; uint8_t profileIdc;
bool constraintSet0Flag; bool constraintSet0Flag;
@ -176,20 +181,19 @@ namespace h264 {
uint64_t bitDepthChromaMinus8; uint64_t bitDepthChromaMinus8;
bool qpprimeYZeroTransformBypassFlag; bool qpprimeYZeroTransformBypassFlag;
bool seqScalingMatrixPresentFlag; bool seqScalingMatrixPresentFlag;
//Here go scaling lists // Here go scaling lists
uint8_t * scalingListPresentFlags; uint8_t *scalingListPresentFlags;
uint64_t ** scalingList4x4;
bool * useDefaultScalingMatrix4x4Flag;
uint64_t ** scalingList8x8;
bool * useDefaultScalingMatrix8x8Flag;
uint64_t **scalingList4x4;
bool *useDefaultScalingMatrix4x4Flag;
uint64_t **scalingList8x8;
bool *useDefaultScalingMatrix8x8Flag;
uint64_t log2MaxFrameNumMinus4; uint64_t log2MaxFrameNumMinus4;
uint64_t picOrderCntType; uint64_t picOrderCntType;
uint64_t log2MaxPicOrderCntLsbMinus4; uint64_t log2MaxPicOrderCntLsbMinus4;
//Here go values for pic_order_cnt_type == 1 // Here go values for pic_order_cnt_type == 1
uint64_t maxNumRefFrames; uint64_t maxNumRefFrames;
bool gapsInFrameNumValueAllowedFlag; bool gapsInFrameNumValueAllowedFlag;
@ -207,7 +211,7 @@ namespace h264 {
vui_parameters vuiParams; vui_parameters vuiParams;
//DERIVATIVE VALUES // DERIVATIVE VALUES
uint8_t derived_subWidthC; uint8_t derived_subWidthC;
uint8_t derived_subHeightC; uint8_t derived_subHeightC;
uint8_t derived_mbWidthC; uint8_t derived_mbWidthC;
@ -229,18 +233,17 @@ namespace h264 {
size_t derived_scalingList4x4Amount; size_t derived_scalingList4x4Amount;
size_t derived_scalingList8x8Amount; size_t derived_scalingList8x8Amount;
}; };
class ppsUnit : public nalUnit { class ppsUnit : public nalUnit{
public: public:
ppsUnit(const char * data, size_t len, uint8_t chromaFormatIdc = 0); ppsUnit(const char *data, size_t len, uint8_t chromaFormatIdc = 0);
~ppsUnit(){ ~ppsUnit(){
if (picScalingMatrixPresentFlags != NULL){ if (picScalingMatrixPresentFlags != NULL){free(picScalingMatrixPresentFlags);}
free(picScalingMatrixPresentFlags);
} }
} void scalingList(uint64_t *scalingList, size_t sizeOfScalingList,
void scalingList(uint64_t * scalingList, size_t sizeOfScalingList, bool & useDefaultScalingMatrixFlag, Utils::bitstream & bs); bool &useDefaultScalingMatrixFlag, Utils::bitstream &bs);
void setPPSNumber(size_t newNumber); void setPPSNumber(size_t newNumber);
void setSPSNumber(size_t newNumber); void setSPSNumber(size_t newNumber);
void toPrettyString(std::ostream & out); void toPrettyString(std::ostream &out);
std::string generate(); std::string generate();
uint64_t picParameterSetId; uint64_t picParameterSetId;
@ -260,13 +263,13 @@ namespace h264 {
bool redundantPicCntPresentFlag; bool redundantPicCntPresentFlag;
bool transform8x8ModeFlag; bool transform8x8ModeFlag;
bool picScalingMatrixPresentFlag; bool picScalingMatrixPresentFlag;
//Here go scaling lists // Here go scaling lists
uint8_t * picScalingMatrixPresentFlags; uint8_t *picScalingMatrixPresentFlags;
uint64_t ** scalingList4x4; uint64_t **scalingList4x4;
bool * useDefaultScalingMatrix4x4Flag; bool *useDefaultScalingMatrix4x4Flag;
uint64_t ** scalingList8x8; uint64_t **scalingList8x8;
bool * useDefaultScalingMatrix8x8Flag; bool *useDefaultScalingMatrix8x8Flag;
int64_t secondChromaQpIndexOffset; int64_t secondChromaQpIndexOffset;
@ -276,29 +279,28 @@ namespace h264 {
bool status_moreRBSP; bool status_moreRBSP;
}; };
class codedSliceUnit : public nalUnit { class codedSliceUnit : public nalUnit{
public: public:
codedSliceUnit(const char * data, size_t len); codedSliceUnit(const char *data, size_t len);
void setPPSNumber(size_t newNumber); void setPPSNumber(size_t newNumber);
void toPrettyString(std::ostream & out); void toPrettyString(std::ostream &out);
uint64_t firstMbInSlice; uint64_t firstMbInSlice;
uint64_t sliceType; uint64_t sliceType;
uint64_t picParameterSetId; uint64_t picParameterSetId;
}; };
class seiUnit : public nalUnit { class seiUnit : public nalUnit{
public: public:
seiUnit(const char * data, size_t len); seiUnit(const char *data, size_t len);
void toPrettyString(std::ostream & out); void toPrettyString(std::ostream &out);
uint32_t payloadType; uint32_t payloadType;
uint32_t payloadSize; uint32_t payloadSize;
uint32_t payloadOffset; uint32_t payloadOffset;
}; };
nalUnit *nalFactory(FILE *in, bool annexb = true);
nalUnit *nalFactory(const char *data, size_t len, size_t &offset, bool annexb = true);
}// namespace h264
nalUnit * nalFactory(FILE * in, bool annexb = true);
nalUnit * nalFactory(const char * data, size_t len, size_t & offset, bool annexb = true);
}

View file

@ -2,8 +2,8 @@
#include "bitfields.h" #include "bitfields.h"
#include "defines.h" #include "defines.h"
namespace h265 { namespace h265{
const char * typeToStr(uint8_t type){ const char *typeToStr(uint8_t type){
switch (type){ switch (type){
case 0: case 0:
case 1: return "Trailing slice"; case 1: return "Trailing slice";
@ -37,13 +37,13 @@ namespace h265 {
} }
} }
bool isKeyframe(const char * data, uint32_t len){ bool isKeyframe(const char *data, uint32_t len){
if (!len){return false;} if (!len){return false;}
uint8_t nalType = (data[0] & 0x7E) >> 1; uint8_t nalType = (data[0] & 0x7E) >> 1;
return (nalType >= 16 && nalType <= 21); return (nalType >= 16 && nalType <= 21);
} }
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){ std::deque<nalu::nalData> analysePackets(const char *data, unsigned long len){
std::deque<nalu::nalData> res; std::deque<nalu::nalData> res;
int offset = 0; int offset = 0;
@ -57,66 +57,66 @@ namespace h265 {
return res; return res;
} }
initData::initData() {} initData::initData(){}
initData::initData(const std::string& hvccData) { initData::initData(const std::string &hvccData){
MP4::HVCC hvccBox; MP4::HVCC hvccBox;
hvccBox.setPayload(hvccData); hvccBox.setPayload(hvccData);
std::deque<MP4::HVCCArrayEntry> arrays = hvccBox.getArrays(); std::deque<MP4::HVCCArrayEntry> arrays = hvccBox.getArrays();
for (std::deque<MP4::HVCCArrayEntry>::iterator it = arrays.begin(); it != arrays.end(); it++){ for (std::deque<MP4::HVCCArrayEntry>::iterator it = arrays.begin(); it != arrays.end(); it++){
for (std::deque<std::string>::iterator nalIt = it->nalUnits.begin(); nalIt != it->nalUnits.end(); nalIt++){ for (std::deque<std::string>::iterator nalIt = it->nalUnits.begin();
nalIt != it->nalUnits.end(); nalIt++){
nalUnits[it->nalUnitType].insert(*nalIt); nalUnits[it->nalUnitType].insert(*nalIt);
} }
} }
} }
const std::set<std::string> & initData::getVPS() const{ const std::set<std::string> &initData::getVPS() const{
static std::set<std::string> empty; static std::set<std::string> empty;
if (!nalUnits.count(32)){return empty;} if (!nalUnits.count(32)){return empty;}
return nalUnits.at(32); return nalUnits.at(32);
} }
const std::set<std::string> & initData::getSPS() const{ const std::set<std::string> &initData::getSPS() const{
static std::set<std::string> empty; static std::set<std::string> empty;
if (!nalUnits.count(33)){return empty;} if (!nalUnits.count(33)){return empty;}
return nalUnits.at(33); return nalUnits.at(33);
} }
const std::set<std::string> & initData::getPPS() const{ const std::set<std::string> &initData::getPPS() const{
static std::set<std::string> empty; static std::set<std::string> empty;
if (!nalUnits.count(34)){return empty;} if (!nalUnits.count(34)){return empty;}
return nalUnits.at(34); return nalUnits.at(34);
} }
void initData::addUnit(const char *data){
void initData::addUnit(char * data) {
unsigned long nalSize = Bit::btohl(data); unsigned long nalSize = Bit::btohl(data);
unsigned long nalType = (data[4] & 0x7E) >> 1; unsigned long nalType = (data[4] & 0x7E) >> 1;
switch (nalType) { switch (nalType){
case 32: //vps case 32: // vps
case 33: //sps case 33: // sps
case 34: //pps case 34: // pps
nalUnits[nalType].insert(std::string(data + 4, nalSize)); nalUnits[nalType].insert(std::string(data + 4, nalSize));
} }
} }
void initData::addUnit(const std::string & data) { void initData::addUnit(const std::string &data){
if (data.size() <= 1){return;} if (data.size() <= 1){return;}
unsigned long nalType = (data[0] & 0x7E) >> 1; uint8_t nalType = (data[0] & 0x7E) >> 1;
switch (nalType) { switch (nalType){
case 32: //vps case 32: // vps
case 33: //sps case 33: // sps
case 34: //pps case 34: // pps
nalUnits[nalType].insert(data); nalUnits[nalType].insert(data);
} }
INFO_MSG("added nal of type %u" , nalType); INFO_MSG("added nal of type %" PRIu8, nalType);
if (nalType == 32){ if (nalType == 32){
vpsUnit vps(data); vpsUnit vps(data);
std::cout << vps.toPrettyString(0); std::cout << vps.toPrettyString(0);
} }
} }
bool initData::haveRequired() { bool initData::haveRequired(){
return (nalUnits.count(32) && nalUnits.count(33) && nalUnits.count(34)); return (nalUnits.count(32) && nalUnits.count(33) && nalUnits.count(34));
} }
@ -126,7 +126,7 @@ namespace h265 {
hvccBox.setParallelismType(0); hvccBox.setParallelismType(0);
std::set<std::string>::iterator nalIt; std::set<std::string>::iterator nalIt;
//We first loop over all VPS Units // We first loop over all VPS Units
for (nalIt = nalUnits[32].begin(); nalIt != nalUnits[32].end(); nalIt++){ for (nalIt = nalUnits[32].begin(); nalIt != nalUnits[32].end(); nalIt++){
vpsUnit vps(*nalIt); vpsUnit vps(*nalIt);
vps.updateHVCC(hvccBox); vps.updateHVCC(hvccBox);
@ -135,7 +135,8 @@ namespace h265 {
spsUnit sps(*nalIt); spsUnit sps(*nalIt);
sps.updateHVCC(hvccBox); sps.updateHVCC(hvccBox);
} }
//NOTE: We dont parse the ppsUnit, as the only information it contains is parallelism mode, which is set to 0 for 'unknown' // NOTE: We dont parse the ppsUnit, as the only information it contains is parallelism mode,
// which is set to 0 for 'unknown'
std::deque<MP4::HVCCArrayEntry> hvccArrays; std::deque<MP4::HVCCArrayEntry> hvccArrays;
hvccArrays.resize(3); hvccArrays.resize(3);
hvccArrays[0].arrayCompleteness = 0; hvccArrays[0].arrayCompleteness = 0;
@ -158,21 +159,19 @@ namespace h265 {
return std::string(hvccBox.payload(), hvccBox.payloadSize()); return std::string(hvccBox.payload(), hvccBox.payloadSize());
} }
metaInfo initData::getMeta() { metaInfo initData::getMeta(){
metaInfo res; metaInfo res;
if (!nalUnits.count(33)){ if (!nalUnits.count(33)){return res;}
return res;
}
spsUnit sps(*nalUnits[33].begin()); spsUnit sps(*nalUnits[33].begin());
sps.getMeta(res); sps.getMeta(res);
return res; return res;
} }
void skipProfileTierLevel(Utils::bitstream & bs, unsigned int maxSubLayersMinus1){ void skipProfileTierLevel(Utils::bitstream &bs, unsigned int maxSubLayersMinus1){
bs.skip(8); bs.skip(8);
bs.skip(32);//general_profile_flags bs.skip(32); // general_profile_flags
bs.skip(4); bs.skip(4);
bs.skip(44);//reserverd_zero bs.skip(44); // reserverd_zero
bs.skip(8); bs.skip(8);
std::deque<bool> profilePresent; std::deque<bool> profilePresent;
std::deque<bool> levelPresent; std::deque<bool> levelPresent;
@ -181,33 +180,33 @@ namespace h265 {
levelPresent.push_back(bs.get(1)); levelPresent.push_back(bs.get(1));
} }
if (maxSubLayersMinus1){ if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){ for (int i = maxSubLayersMinus1; i < 8; i++){bs.skip(2);}
bs.skip(2);
}
} }
for (int i = 0; i < maxSubLayersMinus1; i++){ for (int i = 0; i < maxSubLayersMinus1; i++){
if (profilePresent[i]){ if (profilePresent[i]){
bs.skip(8); bs.skip(8);
bs.skip(32);//sub_layer_profile_flags bs.skip(32); // sub_layer_profile_flags
bs.skip(4); bs.skip(4);
bs.skip(44);//reserved_zero bs.skip(44); // reserved_zero
}
if (levelPresent[i]){
bs.skip(8);
} }
if (levelPresent[i]){bs.skip(8);}
} }
} }
std::string printProfileTierLevel(Utils::bitstream & bs, unsigned int maxSubLayersMinus1, size_t indent){ std::string printProfileTierLevel(Utils::bitstream &bs, unsigned int maxSubLayersMinus1,
size_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "general_profile_space: " << bs.get(2) << std::endl; r << std::string(indent, ' ') << "general_profile_space: " << bs.get(2) << std::endl;
r << std::string(indent, ' ') << "general_tier_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "general_tier_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_profile_idc: " << bs.get(5) << std::endl; r << std::string(indent, ' ') << "general_profile_idc: " << bs.get(5) << std::endl;
r << std::string(indent, ' ') << "general_profile_compatibility_flags: 0x" << std::hex << bs.get(32) << std::dec << std::endl; r << std::string(indent, ' ') << "general_profile_compatibility_flags: 0x" << std::hex
<< bs.get(32) << std::dec << std::endl;
r << std::string(indent, ' ') << "general_progressive_source_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "general_progressive_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_interlaced_source_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "general_interlaced_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_non_packed_constraint_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "general_non_packed_constraint_flag: " << bs.get(1)
r << std::string(indent, ' ') << "general_frame_only_constraint_flag: " << bs.get(1) << std::endl; << std::endl;
r << std::string(indent, ' ') << "general_frame_only_constraint_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent, ' ') << "general_reserved_zero_44bits: " << bs.get(44) << std::endl; r << std::string(indent, ' ') << "general_reserved_zero_44bits: " << bs.get(44) << std::endl;
r << std::string(indent, ' ') << "general_level_idc: " << bs.get(8) << std::endl; r << std::string(indent, ' ') << "general_level_idc: " << bs.get(8) << std::endl;
std::deque<bool> profilePresent; std::deque<bool> profilePresent;
@ -217,13 +216,16 @@ namespace h265 {
bool level = bs.get(1); bool level = bs.get(1);
profilePresent.push_back(profile); profilePresent.push_back(profile);
levelPresent.push_back(level); levelPresent.push_back(level);
r << std::string(indent + 1, ' ') << "sub_layer_profile_present_flag[" << i << "]: " << (profile ? 1 : 0) << std::endl; r << std::string(indent + 1, ' ') << "sub_layer_profile_present_flag[" << i
r << std::string(indent + 1, ' ') << "sub_layer_level_present_flag[" << i << "]: " << (level ? 1 : 0) << std::endl; << "]: " << (profile ? 1 : 0) << std::endl;
r << std::string(indent + 1, ' ') << "sub_layer_level_present_flag[" << i
<< "]: " << (level ? 1 : 0) << std::endl;
} }
if (maxSubLayersMinus1){ if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){ for (int i = maxSubLayersMinus1; i < 8; i++){
r << std::string(indent + 1, ' ') << "reserver_zero_2_bits[" << i << "]: " << bs.get(2) << std::endl; r << std::string(indent + 1, ' ') << "reserver_zero_2_bits[" << i << "]: " << bs.get(2)
<< std::endl;
} }
} }
for (int i = 0; i < maxSubLayersMinus1; i++){ for (int i = 0; i < maxSubLayersMinus1; i++){
@ -232,12 +234,18 @@ namespace h265 {
r << std::string(indent + 2, ' ') << "sub_layer_profile_space: " << bs.get(2) << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_profile_space: " << bs.get(2) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_tier_flag: " << bs.get(1) << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_tier_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_profile_idc: " << bs.get(5) << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_profile_idc: " << bs.get(5) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_profile_compatibility_flags: " << std::hex << bs.get(32) << std::dec << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_profile_compatibility_flags: " << std::hex
r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1) << std::endl; << bs.get(32) << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_interlaced_source_flag: " << bs.get(1) << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1)
r << std::string(indent + 2, ' ') << "sub_layer_non_packed_constraint_flag: " << bs.get(1) << std::endl; << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_frame_only_constraint_flag: " << bs.get(1) << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_interlaced_source_flag: " << bs.get(1)
r << std::string(indent + 2, ' ') << "sub_layer_reserved_zero_44bits: " << bs.get(44) << std::endl; << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_non_packed_constraint_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_frame_only_constraint_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_reserved_zero_44bits: " << bs.get(44)
<< std::endl;
} }
if (levelPresent[i]){ if (levelPresent[i]){
r << std::string(indent + 2, ' ') << "sub_layer_level_idc: " << bs.get(8) << std::endl; r << std::string(indent + 2, ' ') << "sub_layer_level_idc: " << bs.get(8) << std::endl;
@ -246,24 +254,27 @@ namespace h265 {
return r.str(); return r.str();
} }
void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned int maxSubLayersMinus1){ void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox,
unsigned int maxSubLayersMinus1){
hvccBox.setGeneralProfileSpace(bs.get(2)); hvccBox.setGeneralProfileSpace(bs.get(2));
unsigned int tierFlag = bs.get(1); unsigned int tierFlag = bs.get(1);
hvccBox.setGeneralProfileIdc(std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5))); hvccBox.setGeneralProfileIdc(
hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() & bs.get(32)); std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5)));
hvccBox.setGeneralConstraintIndicatorFlags(hvccBox.getGeneralConstraintIndicatorFlags() & bs.get(48)); hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() &
bs.get(32));
hvccBox.setGeneralConstraintIndicatorFlags(hvccBox.getGeneralConstraintIndicatorFlags() &
bs.get(48));
unsigned int levelIdc = bs.get(8); unsigned int levelIdc = bs.get(8);
if (tierFlag && !hvccBox.getGeneralTierFlag()) { if (tierFlag && !hvccBox.getGeneralTierFlag()){
hvccBox.setGeneralLevelIdc(levelIdc); hvccBox.setGeneralLevelIdc(levelIdc);
}else { }else{
hvccBox.setGeneralLevelIdc(std::max((unsigned int)hvccBox.getGeneralLevelIdc(),levelIdc)); hvccBox.setGeneralLevelIdc(std::max((unsigned int)hvccBox.getGeneralLevelIdc(), levelIdc));
} }
hvccBox.setGeneralTierFlag(tierFlag || hvccBox.getGeneralTierFlag()); hvccBox.setGeneralTierFlag(tierFlag || hvccBox.getGeneralTierFlag());
// Remainder is for synchronsation of the parser
//Remainder is for synchronsation of the parser
std::deque<bool> profilePresent; std::deque<bool> profilePresent;
std::deque<bool> levelPresent; std::deque<bool> levelPresent;
@ -273,9 +284,7 @@ namespace h265 {
} }
if (maxSubLayersMinus1){ if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){ for (int i = maxSubLayersMinus1; i < 8; i++){bs.skip(2);}
bs.skip(2);
}
} }
for (int i = 0; i < maxSubLayersMinus1; i++){ for (int i = 0; i < maxSubLayersMinus1; i++){
@ -284,25 +293,22 @@ namespace h265 {
bs.skip(32); bs.skip(32);
bs.skip(24); bs.skip(24);
} }
if (levelPresent[i]){ if (levelPresent[i]){bs.skip(8);}
bs.skip(8);
}
} }
} }
vpsUnit::vpsUnit(const std::string & _data){ vpsUnit::vpsUnit(const std::string &_data){data = nalu::removeEmulationPrevention(_data);}
data = nalu::removeEmulationPrevention(_data);
}
void vpsUnit::updateHVCC(MP4::HVCC & hvccBox) { void vpsUnit::updateHVCC(MP4::HVCC &hvccBox){
Utils::bitstream bs; Utils::bitstream bs;
bs.append(data); bs.append(data);
bs.skip(16);//Nal Header bs.skip(16); // Nal Header
bs.skip(12); bs.skip(12);
unsigned int maxSubLayers = bs.get(3) + 1; unsigned int maxSubLayers = bs.get(3) + 1;
hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers)); hvccBox.setNumberOfTemporalLayers(
std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
bs.skip(17); bs.skip(17);
@ -312,67 +318,69 @@ namespace h265 {
std::string vpsUnit::toPrettyString(size_t indent){ std::string vpsUnit::toPrettyString(size_t indent){
Utils::bitstream bs; Utils::bitstream bs;
bs.append(data); bs.append(data);
bs.skip(16);//Nal Header bs.skip(16); // Nal Header
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "vps_video_parameter_set_id: " << bs.get(4) << std::endl; r << std::string(indent, ' ') << "vps_video_parameter_set_id: " << bs.get(4) << std::endl;
r << std::string(indent, ' ') << "vps_reserved_three_2bits: " << bs.get(2) << std::endl; r << std::string(indent, ' ') << "vps_reserved_three_2bits: " << bs.get(2) << std::endl;
r << std::string(indent, ' ') << "vps_max_layers_minus1: " << bs.get(6) << std::endl; r << std::string(indent, ' ') << "vps_max_layers_minus1: " << bs.get(6) << std::endl;
unsigned int maxSubLayersMinus1 = bs.get(3); unsigned int maxSubLayersMinus1 = bs.get(3);
r << std::string(indent, ' ') << "vps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl; r << std::string(indent, ' ') << "vps_max_sub_layers_minus1: " << maxSubLayersMinus1
<< std::endl;
r << std::string(indent, ' ') << "vps_temporal_id_nesting_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "vps_temporal_id_nesting_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "vps_reserved_0xffff_16bits: " << std::hex << bs.get(16) << std::dec << std::endl; r << std::string(indent, ' ') << "vps_reserved_0xffff_16bits: " << std::hex << bs.get(16)
r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl << printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1); << std::dec << std::endl;
r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl
<< printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1);
bool sub_layer_ordering_info = bs.get(1); bool sub_layer_ordering_info = bs.get(1);
r << std::string(indent, ' ') << "vps_sub_layer_ordering_info_present_flag: " << sub_layer_ordering_info << std::endl; r << std::string(indent, ' ')
<< "vps_sub_layer_ordering_info_present_flag: " << sub_layer_ordering_info << std::endl;
for (int i = (sub_layer_ordering_info ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){ for (int i = (sub_layer_ordering_info ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){
r << std::string(indent, ' ') << "vps_max_dec_pic_buffering_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "vps_max_dec_pic_buffering_minus1[" << i
r << std::string(indent, ' ') << "vps_max_num_reorder_pics[" << i << "]: " << bs.getUExpGolomb() << std::endl; << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "vps_max_latency_increase_plus1[" << i << "]: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "vps_max_num_reorder_pics[" << i
<< "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "vps_max_latency_increase_plus1[" << i
<< "]: " << bs.getUExpGolomb() << std::endl;
} }
unsigned int vps_max_layer_id = bs.get(6); unsigned int vps_max_layer_id = bs.get(6);
uint64_t vps_num_layer_sets_minus1 = bs.getUExpGolomb(); uint64_t vps_num_layer_sets_minus1 = bs.getUExpGolomb();
r << std::string(indent, ' ') << "vps_max_layer_id: " << vps_max_layer_id << std::endl; r << std::string(indent, ' ') << "vps_max_layer_id: " << vps_max_layer_id << std::endl;
r << std::string(indent, ' ') << "vps_num_layer_sets_minus1: " << vps_num_layer_sets_minus1 << std::endl; r << std::string(indent, ' ') << "vps_num_layer_sets_minus1: " << vps_num_layer_sets_minus1
<< std::endl;
for (int i = 1; i <= vps_num_layer_sets_minus1; i++){ for (int i = 1; i <= vps_num_layer_sets_minus1; i++){
for (int j = 0; j < vps_max_layer_id; j++){ for (int j = 0; j < vps_max_layer_id; j++){
r << std::string(indent, ' ') << "layer_id_included_flag[" << i << "][" << j << "]: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "layer_id_included_flag[" << i << "][" << j
<< "]: " << bs.get(1) << std::endl;
} }
} }
bool vps_timing_info = bs.get(1); bool vps_timing_info = bs.get(1);
r << std::string(indent, ' ') << "vps_timing_info_present_flag: " << (vps_timing_info ? 1 : 0) << std::endl; r << std::string(indent, ' ') << "vps_timing_info_present_flag: " << (vps_timing_info ? 1 : 0)
<< std::endl;
return r.str(); return r.str();
} }
spsUnit::spsUnit(const std::string & _data){ spsUnit::spsUnit(const std::string &_data){data = nalu::removeEmulationPrevention(_data);}
data = nalu::removeEmulationPrevention(_data);
}
void skipShortTermRefPicSet(Utils::bitstream & bs, unsigned int idx, size_t count){ void skipShortTermRefPicSet(Utils::bitstream &bs, unsigned int idx, size_t count){
static std::map<int,int> negativePics; static std::map<int, int> negativePics;
static std::map<int,int> positivePics; static std::map<int, int> positivePics;
if (idx == 0){ if (idx == 0){
negativePics.clear(); negativePics.clear();
positivePics.clear(); positivePics.clear();
} }
bool interPrediction = false; bool interPrediction = false;
if (idx != 0){ if (idx != 0){interPrediction = bs.get(1);}
interPrediction = bs.get(1);
}
if (interPrediction){ if (interPrediction){
uint64_t deltaIdxMinus1 = 0; uint64_t deltaIdxMinus1 = 0;
if (idx == count){ if (idx == count){deltaIdxMinus1 = bs.getUExpGolomb();}
deltaIdxMinus1 = bs.getUExpGolomb();
}
bs.skip(1); bs.skip(1);
bs.getUExpGolomb(); bs.getUExpGolomb();
uint64_t refRpsIdx = idx - deltaIdxMinus1 - 1; uint64_t refRpsIdx = idx - deltaIdxMinus1 - 1;
uint64_t deltaPocs = negativePics[refRpsIdx] + positivePics[refRpsIdx]; uint64_t deltaPocs = negativePics[refRpsIdx] + positivePics[refRpsIdx];
for (int j = 0; j < deltaPocs; j++){ for (int j = 0; j < deltaPocs; j++){
bool usedByCurrPicFlag = bs.get(1); bool usedByCurrPicFlag = bs.get(1);
if (!usedByCurrPicFlag){ if (!usedByCurrPicFlag){bs.skip(1);}
bs.skip(1);
}
} }
}else{ }else{
negativePics[idx] = bs.getUExpGolomb(); negativePics[idx] = bs.getUExpGolomb();
@ -388,12 +396,13 @@ namespace h265 {
} }
} }
std::string printShortTermRefPicSet(Utils::bitstream & bs, unsigned int idx, size_t indent){ std::string printShortTermRefPicSet(Utils::bitstream &bs, unsigned int idx, size_t indent){
std::stringstream r; std::stringstream r;
bool interPrediction = false; bool interPrediction = false;
if (idx != 0){ if (idx != 0){
interPrediction = bs.get(1); interPrediction = bs.get(1);
r << std::string(indent, ' ') << "inter_ref_pic_set_predicition_flag: " << (interPrediction ? 1 : 0) << std::endl; r << std::string(indent, ' ')
<< "inter_ref_pic_set_predicition_flag: " << (interPrediction ? 1 : 0) << std::endl;
} }
if (interPrediction){ if (interPrediction){
WARN_MSG("interprediciton not yet handled"); WARN_MSG("interprediciton not yet handled");
@ -403,36 +412,34 @@ namespace h265 {
r << std::string(indent, ' ') << "num_negative_pics: " << negativePics << std::endl; r << std::string(indent, ' ') << "num_negative_pics: " << negativePics << std::endl;
r << std::string(indent, ' ') << "num_positive_pics: " << positivePics << std::endl; r << std::string(indent, ' ') << "num_positive_pics: " << positivePics << std::endl;
for (int i = 0; i < negativePics; i++){ for (int i = 0; i < negativePics; i++){
r << std::string(indent + 1, ' ') << "delta_poc_s0_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl; r << std::string(indent + 1, ' ') << "delta_poc_s0_minus1[" << i
r << std::string(indent + 1, ' ') << "used_by_curr_pic_s0_flag[" << i << "]: " << bs.get(1) << std::endl; << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "used_by_curr_pic_s0_flag[" << i << "]: " << bs.get(1)
<< std::endl;
} }
for (int i = 0; i < positivePics; i++){ for (int i = 0; i < positivePics; i++){
r << std::string(indent + 1, ' ') << "delta_poc_s1_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl; r << std::string(indent + 1, ' ') << "delta_poc_s1_minus1[" << i
r << std::string(indent + 1, ' ') << "used_by_curr_pic_s1_flag[" << i << "]: " << bs.get(1) << std::endl; << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "used_by_curr_pic_s1_flag[" << i << "]: " << bs.get(1)
<< std::endl;
} }
} }
return r.str(); return r.str();
} }
void parseVuiParameters(Utils::bitstream & bs, metaInfo & res){ void parseVuiParameters(Utils::bitstream &bs, metaInfo &res){
bool aspectRatio = bs.get(1); bool aspectRatio = bs.get(1);
if (aspectRatio){ if (aspectRatio){
uint16_t aspectRatioIdc = bs.get(8); uint16_t aspectRatioIdc = bs.get(8);
if (aspectRatioIdc == 255){ if (aspectRatioIdc == 255){bs.skip(32);}
bs.skip(32);
}
} }
bool overscanInfo = bs.get(1); bool overscanInfo = bs.get(1);
if (overscanInfo){ if (overscanInfo){bs.skip(1);}
bs.skip(1);
}
bool videoSignalTypePresent = bs.get(1); bool videoSignalTypePresent = bs.get(1);
if (videoSignalTypePresent){ if (videoSignalTypePresent){
bs.skip(4); bs.skip(4);
bool colourDescription = bs.get(1); bool colourDescription = bs.get(1);
if (colourDescription){ if (colourDescription){bs.skip(24);}
bs.skip(24);
}
} }
bool chromaLocPresent = bs.get(1); bool chromaLocPresent = bs.get(1);
if (chromaLocPresent){ if (chromaLocPresent){
@ -455,10 +462,11 @@ namespace h265 {
} }
} }
std::string printVuiParameters(Utils::bitstream & bs, size_t indent){ std::string printVuiParameters(Utils::bitstream &bs, size_t indent){
std::stringstream r; std::stringstream r;
bool aspectRatio = bs.get(1); bool aspectRatio = bs.get(1);
r << std::string(indent, ' ') << "aspect_ratio_info_present_flag: " << (aspectRatio ? 1 : 0) << std::endl; r << std::string(indent, ' ') << "aspect_ratio_info_present_flag: " << (aspectRatio ? 1 : 0)
<< std::endl;
if (aspectRatio){ if (aspectRatio){
uint16_t aspectRatioIdc = bs.get(8); uint16_t aspectRatioIdc = bs.get(8);
r << std::string(indent, ' ') << "aspect_ratio_idc: " << aspectRatioIdc << std::endl; r << std::string(indent, ' ') << "aspect_ratio_idc: " << aspectRatioIdc << std::endl;
@ -470,7 +478,7 @@ namespace h265 {
return r.str(); return r.str();
} }
void skipScalingList(Utils::bitstream & bs){ void skipScalingList(Utils::bitstream &bs){
for (int sizeId = 0; sizeId < 4; sizeId++){ for (int sizeId = 0; sizeId < 4; sizeId++){
for (int matrixId = 0; matrixId < (sizeId == 3 ? 2 : 6); matrixId++){ for (int matrixId = 0; matrixId < (sizeId == 3 ? 2 : 6); matrixId++){
bool modeFlag = bs.get(1); bool modeFlag = bs.get(1);
@ -478,21 +486,17 @@ namespace h265 {
bs.getUExpGolomb(); bs.getUExpGolomb();
}else{ }else{
size_t coefNum = std::min(64, (1 << (4 + (sizeId << 1)))); size_t coefNum = std::min(64, (1 << (4 + (sizeId << 1))));
if (sizeId > 1){ if (sizeId > 1){bs.getExpGolomb();}
bs.getExpGolomb(); for (int i = 0; i < coefNum; i++){bs.getExpGolomb();}
}
for (int i = 0; i < coefNum; i++){
bs.getExpGolomb();
}
} }
} }
} }
} }
void spsUnit::getMeta(metaInfo & res) { void spsUnit::getMeta(metaInfo &res){
Utils::bitstream bs; Utils::bitstream bs;
bs.append(data); bs.append(data);
bs.skip(16);//Nal Header bs.skip(16); // Nal Header
bs.skip(4); bs.skip(4);
unsigned int maxSubLayersMinus1 = bs.get(3); unsigned int maxSubLayersMinus1 = bs.get(3);
bs.skip(1); bs.skip(1);
@ -500,18 +504,16 @@ namespace h265 {
bs.getUExpGolomb(); bs.getUExpGolomb();
uint64_t chromaFormatIdc = bs.getUExpGolomb(); uint64_t chromaFormatIdc = bs.getUExpGolomb();
bool separateColorPlane = false; bool separateColorPlane = false;
if (chromaFormatIdc == 3){ if (chromaFormatIdc == 3){separateColorPlane = bs.get(1);}
separateColorPlane = bs.get(1);
}
res.width = bs.getUExpGolomb(); res.width = bs.getUExpGolomb();
res.height = bs.getUExpGolomb(); res.height = bs.getUExpGolomb();
bool conformanceWindow = bs.get(1); bool conformanceWindow = bs.get(1);
if (conformanceWindow){ if (conformanceWindow){
uint8_t subWidthC = ((chromaFormatIdc == 1 || chromaFormatIdc == 2) ? 2 : 1); uint8_t subWidthC = ((chromaFormatIdc == 1 || chromaFormatIdc == 2) ? 2 : 1);
uint8_t subHeightC = (chromaFormatIdc == 1 ? 2 : 1); uint8_t subHeightC = (chromaFormatIdc == 1 ? 2 : 1);
uint64_t left = bs.getUExpGolomb(); bs.getUExpGolomb(); // Skip left
uint64_t right = bs.getUExpGolomb(); uint64_t right = bs.getUExpGolomb();
uint64_t top = bs.getUExpGolomb(); bs.getUExpGolomb(); // Skip top
uint64_t bottom = bs.getUExpGolomb(); uint64_t bottom = bs.getUExpGolomb();
res.width -= (subWidthC * right); res.width -= (subWidthC * right);
res.height -= (subHeightC * bottom); res.height -= (subHeightC * bottom);
@ -520,7 +522,7 @@ namespace h265 {
bs.getUExpGolomb(); bs.getUExpGolomb();
uint64_t log2MaxPicOrderCntLsbMinus4 = bs.getUExpGolomb(); uint64_t log2MaxPicOrderCntLsbMinus4 = bs.getUExpGolomb();
bool subLayerOrdering = bs.get(1); bool subLayerOrdering = bs.get(1);
for (int i= (subLayerOrdering ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){ for (int i = (subLayerOrdering ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
@ -534,9 +536,7 @@ namespace h265 {
bool scalingListEnabled = bs.get(1); bool scalingListEnabled = bs.get(1);
if (scalingListEnabled){ if (scalingListEnabled){
bool scalingListPresent = bs.get(1); bool scalingListPresent = bs.get(1);
if (scalingListPresent){ if (scalingListPresent){skipScalingList(bs);}
skipScalingList(bs);
}
} }
bs.skip(2); bs.skip(2);
bool pcmEnabled = bs.get(1); bool pcmEnabled = bs.get(1);
@ -547,9 +547,7 @@ namespace h265 {
bs.skip(1); bs.skip(1);
} }
uint64_t shortTermPicSets = bs.getUExpGolomb(); uint64_t shortTermPicSets = bs.getUExpGolomb();
for (int i= 0; i < shortTermPicSets; i++){ for (int i = 0; i < shortTermPicSets; i++){skipShortTermRefPicSet(bs, i, shortTermPicSets);}
skipShortTermRefPicSet(bs, i, shortTermPicSets);
}
bool longTermRefPics = bs.get(1); bool longTermRefPics = bs.get(1);
if (longTermRefPics){ if (longTermRefPics){
uint64_t numLongTermPics = bs.getUExpGolomb(); uint64_t numLongTermPics = bs.getUExpGolomb();
@ -560,97 +558,117 @@ namespace h265 {
} }
bs.skip(2); bs.skip(2);
bool vuiParams = bs.get(1); bool vuiParams = bs.get(1);
if (vuiParams){ if (vuiParams){parseVuiParameters(bs, res);}
parseVuiParameters(bs, res);
}
} }
std::string spsUnit::toPrettyString(size_t indent){ std::string spsUnit::toPrettyString(size_t indent){
Utils::bitstream bs; Utils::bitstream bs;
bs.append(data); bs.append(data);
bs.skip(16);//Nal Header bs.skip(16); // Nal Header
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "sps_video_parameter_set_id: " << bs.get(4) << std::endl; r << std::string(indent, ' ') << "sps_video_parameter_set_id: " << bs.get(4) << std::endl;
unsigned int maxSubLayersMinus1 = bs.get(3); unsigned int maxSubLayersMinus1 = bs.get(3);
r << std::string(indent, ' ') << "sps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl; r << std::string(indent, ' ') << "sps_max_sub_layers_minus1: " << maxSubLayersMinus1
<< std::endl;
r << std::string(indent, ' ') << "sps_temporal_id_nesting_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "sps_temporal_id_nesting_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl << printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1); r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl
r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb() << std::endl; << printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1);
r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb()
<< std::endl;
uint64_t chromaFormatIdc = bs.getUExpGolomb(); uint64_t chromaFormatIdc = bs.getUExpGolomb();
r << std::string(indent, ' ') << "chroma_format_idc: " << chromaFormatIdc << std::endl; r << std::string(indent, ' ') << "chroma_format_idc: " << chromaFormatIdc << std::endl;
if (chromaFormatIdc == 3){ if (chromaFormatIdc == 3){
r << std::string(indent, ' ') << "separate_colour_plane_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "separate_colour_plane_flag: " << bs.get(1) << std::endl;
} }
r << std::string(indent, ' ') << "pic_width_in_luma_samples: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "pic_width_in_luma_samples: " << bs.getUExpGolomb()
r << std::string(indent, ' ') << "pic_height_in_luma_samples: " << bs.getUExpGolomb() << std::endl; << std::endl;
r << std::string(indent, ' ') << "pic_height_in_luma_samples: " << bs.getUExpGolomb()
<< std::endl;
bool conformance_window_flag = bs.get(1); bool conformance_window_flag = bs.get(1);
r << std::string(indent, ' ') << "conformance_window_flag: " << conformance_window_flag << std::endl; r << std::string(indent, ' ') << "conformance_window_flag: " << conformance_window_flag
<< std::endl;
if (conformance_window_flag){ if (conformance_window_flag){
r << std::string(indent, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb()
r << std::string(indent, ' ') << "conf_window_right_offset: " << bs.getUExpGolomb() << std::endl; << std::endl;
r << std::string(indent, ' ') << "conf_window_top_offset: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "conf_window_right_offset: " << bs.getUExpGolomb()
r << std::string(indent, ' ') << "conf_window_bottom_offset: " << bs.getUExpGolomb() << std::endl; << std::endl;
r << std::string(indent, ' ') << "conf_window_top_offset: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "conf_window_bottom_offset: " << bs.getUExpGolomb()
<< std::endl;
} }
r << std::string(indent, ' ') << "bit_depth_luma_minus8: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "bit_depth_luma_minus8: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "bit_depth_chroma_minus8: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "bit_depth_chroma_minus8: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb()
<< std::endl;
bool subLayerOrdering = bs.get(1); bool subLayerOrdering = bs.get(1);
r << std::string(indent, ' ') << "sps_sub_layer_ordering_info_present_flag: " << subLayerOrdering << std::endl; r << std::string(indent, ' ')
for (int i= (subLayerOrdering ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){ << "sps_sub_layer_ordering_info_present_flag: " << subLayerOrdering << std::endl;
r << std::string(indent + 1, ' ') << "sps_max_dec_pic_buffering_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl; for (int i = (subLayerOrdering ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){
r << std::string(indent + 1, ' ') << "sps_max_num_reorder_pics[" << i << "]: " << bs.getUExpGolomb() << std::endl; r << std::string(indent + 1, ' ') << "sps_max_dec_pic_buffering_minus1[" << i
r << std::string(indent + 1, ' ') << "sps_max_latency_increase_plus1[" << i << "]: " << bs.getUExpGolomb() << std::endl; << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "sps_max_num_reorder_pics[" << i
<< "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "sps_max_latency_increase_plus1[" << i
<< "]: " << bs.getUExpGolomb() << std::endl;
} }
r << std::string(indent, ' ') << "log2_min_luma_coding_block_size_minus3: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ')
r << std::string(indent, ' ') << "log2_diff_max_min_luma_coding_block_size: " << bs.getUExpGolomb() << std::endl; << "log2_min_luma_coding_block_size_minus3: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_min_transform_block_size_minus2: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ')
r << std::string(indent, ' ') << "log2_diff_max_min_transform_block_size: " << bs.getUExpGolomb() << std::endl; << "log2_diff_max_min_luma_coding_block_size: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb() << std::endl; r << std::string(indent, ' ') << "log2_min_transform_block_size_minus2: " << bs.getUExpGolomb()
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_intra: " << bs.getUExpGolomb() << std::endl; << std::endl;
r << std::string(indent, ' ')
<< "log2_diff_max_min_transform_block_size: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_intra: " << bs.getUExpGolomb()
<< std::endl;
bool scalingListEnabled = bs.get(1); bool scalingListEnabled = bs.get(1);
r << std::string(indent, ' ') << "scaling_list_enabled_flag: " << scalingListEnabled << std::endl; r << std::string(indent, ' ') << "scaling_list_enabled_flag: " << scalingListEnabled
if (scalingListEnabled){ << std::endl;
WARN_MSG("Not implemented scaling list in HEVC sps"); if (scalingListEnabled){WARN_MSG("Not implemented scaling list in HEVC sps");}
}
r << std::string(indent, ' ') << "amp_enabled_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "amp_enabled_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "sample_adaptive_offset_enabled_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "sample_adaptive_offset_enabled_flag: " << bs.get(1)
<< std::endl;
bool pcmEnabled = bs.get(1); bool pcmEnabled = bs.get(1);
r << std::string(indent, ' ') << "pcm_enabled_flag: " << pcmEnabled << std::endl; r << std::string(indent, ' ') << "pcm_enabled_flag: " << pcmEnabled << std::endl;
if (pcmEnabled){ if (pcmEnabled){WARN_MSG("Not implemented pcm_enabled in HEVC sps");}
WARN_MSG("Not implemented pcm_enabled in HEVC sps");
}
uint64_t shortTermPicSets = bs.getUExpGolomb(); uint64_t shortTermPicSets = bs.getUExpGolomb();
r << std::string(indent, ' ') << "num_short_term_ref_pic_sets: " << shortTermPicSets << std::endl; r << std::string(indent, ' ') << "num_short_term_ref_pic_sets: " << shortTermPicSets
for (int i= 0; i < shortTermPicSets; i++){ << std::endl;
r << std::string(indent, ' ') << "short_term_ref_pic_set(" << i << "):" << std::endl << printShortTermRefPicSet(bs, i, indent + 1); for (int i = 0; i < shortTermPicSets; i++){
r << std::string(indent, ' ') << "short_term_ref_pic_set(" << i << "):" << std::endl
<< printShortTermRefPicSet(bs, i, indent + 1);
} }
bool longTermRefPics = bs.get(1); bool longTermRefPics = bs.get(1);
r << std::string(indent, ' ') << "long_term_ref_pics_present_flag: " << (longTermRefPics ? 1 : 0) << std::endl; r << std::string(indent, ' ')
if (longTermRefPics){ << "long_term_ref_pics_present_flag: " << (longTermRefPics ? 1 : 0) << std::endl;
WARN_MSG("Implement longTermRefPics"); if (longTermRefPics){WARN_MSG("Implement longTermRefPics");}
}
r << std::string(indent, ' ') << "sps_temporal_mvp_enabled_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "sps_temporal_mvp_enabled_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "strong_intra_smoothing_enabled_flag: " << bs.get(1) << std::endl; r << std::string(indent, ' ') << "strong_intra_smoothing_enabled_flag: " << bs.get(1)
<< std::endl;
bool vuiParams = bs.get(1); bool vuiParams = bs.get(1);
r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0) << std::endl; r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0)
<< std::endl;
if (vuiParams){ if (vuiParams){
r << std::string(indent, ' ') << "vui_parameters:" << std::endl << printVuiParameters(bs, indent + 1); r << std::string(indent, ' ') << "vui_parameters:" << std::endl
<< printVuiParameters(bs, indent + 1);
} }
return r.str(); return r.str();
} }
void spsUnit::updateHVCC(MP4::HVCC & hvccBox) { void spsUnit::updateHVCC(MP4::HVCC &hvccBox){
Utils::bitstream bs; Utils::bitstream bs;
bs.append(data); bs.append(data);
bs.skip(16);//Nal Header bs.skip(16); // Nal Header
bs.skip(4); bs.skip(4);
unsigned int maxSubLayers = bs.get(3) + 1; unsigned int maxSubLayers = bs.get(3) + 1;
hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers)); hvccBox.setNumberOfTemporalLayers(
std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
hvccBox.setTemporalIdNested(bs.get(1)); hvccBox.setTemporalIdNested(bs.get(1));
updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1); updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1);
@ -658,9 +676,7 @@ namespace h265 {
hvccBox.setChromaFormat(bs.getUExpGolomb()); hvccBox.setChromaFormat(bs.getUExpGolomb());
if (hvccBox.getChromaFormat() == 3){ if (hvccBox.getChromaFormat() == 3){bs.skip(1);}
bs.skip(1);
}
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
@ -697,13 +713,9 @@ namespace h265 {
bs.getUExpGolomb(); bs.getUExpGolomb();
}else{ }else{
int numCoeffs = std::min(64, 1 << (4 + (i << 1))); int numCoeffs = std::min(64, 1 << (4 + (i << 1)));
if (i > 1){ if (i > 1){bs.getExpGolomb();}
bs.getExpGolomb();
}
for (int k = 0; k < numCoeffs; k++){ for (int k = 0; k < numCoeffs; k++){bs.getExpGolomb();}
bs.getExpGolomb();
}
} }
} }
} }
@ -720,30 +732,26 @@ namespace h265 {
unsigned long long shortTermRefPicSets = bs.getUExpGolomb(); unsigned long long shortTermRefPicSets = bs.getUExpGolomb();
for (int i = 0; i < shortTermRefPicSets; i++){ for (int i = 0; i < shortTermRefPicSets; i++){
//parse rps, return if ret < 0 // parse rps, return if ret < 0
} }
if (bs.get(1)){ if (bs.get(1)){
if (log2MaxPicOrderCntLsb > 16){ if (log2MaxPicOrderCntLsb > 16){log2MaxPicOrderCntLsb = 16;}
log2MaxPicOrderCntLsb = 16;
}
int numLongTermRefPicsSps = bs.getUExpGolomb(); int numLongTermRefPicsSps = bs.getUExpGolomb();
for (int i = 0; i < numLongTermRefPicsSps; i++){ for (int i = 0; i < numLongTermRefPicsSps; i++){bs.skip(log2MaxPicOrderCntLsb + 1);}
bs.skip(log2MaxPicOrderCntLsb + 1);
}
} }
bs.skip(2); bs.skip(2);
if (bs.get(1)){ if (bs.get(1)){
//parse vui // parse vui
if (bs.get(1) && bs.get(8) == 255){ bs.skip(32); } if (bs.get(1) && bs.get(8) == 255){bs.skip(32);}
if (bs.get(1)){ bs.skip(1); } if (bs.get(1)){bs.skip(1);}
if (bs.get(1)){ if (bs.get(1)){
bs.skip(4); bs.skip(4);
if (bs.get(1)){ bs.skip(24); } if (bs.get(1)){bs.skip(24);}
} }
if (bs.get(1)){ if (bs.get(1)){
@ -763,22 +771,16 @@ namespace h265 {
if (bs.get(1)){ if (bs.get(1)){
bs.skip(32); bs.skip(32);
bs.skip(32); bs.skip(32);
if (bs.get(1)){ if (bs.get(1)){bs.getUExpGolomb();}
bs.getUExpGolomb();
}
if (bs.get(1)){ if (bs.get(1)){
int nalHrd = bs.get(1); int nalHrd = bs.get(1);
int vclHrd = bs.get(1); int vclHrd = bs.get(1);
int subPicPresent = 0; int subPicPresent = 0;
if (nalHrd || vclHrd){ if (nalHrd || vclHrd){
subPicPresent = bs.get(1); subPicPresent = bs.get(1);
if (subPicPresent){ if (subPicPresent){bs.skip(19);}
bs.skip(19);
}
bs.skip(8); bs.skip(8);
if (subPicPresent){ if (subPicPresent){bs.skip(4);}
bs.skip(4);
}
bs.skip(15); bs.skip(15);
} }
@ -789,9 +791,7 @@ namespace h265 {
int fixedRateCvs = 0; int fixedRateCvs = 0;
int fixedRateGeneral = bs.get(1); int fixedRateGeneral = bs.get(1);
if (fixedRateGeneral){ if (fixedRateGeneral){fixedRateCvs = bs.get(1);}
fixedRateCvs = bs.get(1);
}
if (fixedRateCvs){ if (fixedRateCvs){
bs.getUExpGolomb(); bs.getUExpGolomb();
@ -799,9 +799,7 @@ namespace h265 {
lowDelay = bs.get(1); lowDelay = bs.get(1);
} }
if (!lowDelay){ if (!lowDelay){cpbCnt = bs.getUExpGolomb() + 1;}
cpbCnt = bs.getUExpGolomb() + 1;
}
if (nalHrd){ if (nalHrd){
for (int i = 0; i < cpbCnt; i++){ for (int i = 0; i < cpbCnt; i++){
@ -826,7 +824,6 @@ namespace h265 {
bs.skip(1); bs.skip(1);
} }
} }
} }
} }
} }
@ -834,7 +831,8 @@ namespace h265 {
if (bs.get(1)){ if (bs.get(1)){
bs.skip(3); bs.skip(3);
int spatialSegmentIdc = bs.getUExpGolomb(); int spatialSegmentIdc = bs.getUExpGolomb();
hvccBox.setMinSpatialSegmentationIdc(std::min((int)hvccBox.getMinSpatialSegmentationIdc(),spatialSegmentIdc)); hvccBox.setMinSpatialSegmentationIdc(
std::min((int)hvccBox.getMinSpatialSegmentationIdc(), spatialSegmentIdc));
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
@ -842,4 +840,5 @@ namespace h265 {
} }
} }
} }
} }// namespace h265

View file

@ -3,59 +3,66 @@
#include <map> #include <map>
#include <set> #include <set>
#include "nal.h"
#include "mp4_generic.h"
#include "bitstream.h" #include "bitstream.h"
#include "mp4_generic.h"
#include "nal.h"
namespace h265 { namespace h265{
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len); std::deque<nalu::nalData> analysePackets(const char *data, unsigned long len);
const char * typeToStr(uint8_t type); const char *typeToStr(uint8_t type);
bool isKeyframe(const char * data, uint32_t len); bool isKeyframe(const char *data, uint32_t len);
void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned long maxSubLayersMinus1); void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox,
std::string printProfileTierLevel(Utils::bitstream & bs, unsigned long maxSubLayersMinus1, size_t indent); unsigned long maxSubLayersMinus1);
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned long maxSubLayersMinus1,
size_t indent);
struct metaInfo { struct metaInfo{
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
double fps; double fps;
}; };
class initData { class initData{
public: public:
initData(); initData();
initData(const std::string & hvccData); initData(const std::string &hvccData);
void addUnit(char * data); void addUnit(const char *data);
void addUnit(const std::string & data); void addUnit(const std::string &data);
bool haveRequired(); bool haveRequired();
std::string generateHVCC(); std::string generateHVCC();
metaInfo getMeta(); metaInfo getMeta();
const std::set<std::string> & getVPS() const; const std::set<std::string> &getVPS() const;
const std::set<std::string> & getSPS() const; const std::set<std::string> &getSPS() const;
const std::set<std::string> & getPPS() const; const std::set<std::string> &getPPS() const;
protected: protected:
std::map<unsigned int, std::set<std::string> > nalUnits; std::map<unsigned int, std::set<std::string> > nalUnits;
}; };
class vpsUnit { class vpsUnit{
public: public:
vpsUnit(const std::string & _data); vpsUnit(const std::string &_data);
void updateHVCC(MP4::HVCC & hvccBox); void updateHVCC(MP4::HVCC &hvccBox);
std::string toPrettyString(size_t indent); std::string toPrettyString(size_t indent);
private: private:
std::string data; std::string data;
}; };
class spsUnit { class spsUnit{
public: public:
spsUnit(const std::string & _data); spsUnit(const std::string &_data);
void updateHVCC(MP4::HVCC & hvccBox); void updateHVCC(MP4::HVCC &hvccBox);
std::string toPrettyString(size_t indent = 0); std::string toPrettyString(size_t indent = 0);
void getMeta(metaInfo & res); void getMeta(metaInfo &res);
private: private:
std::string data; std::string data;
}; };
//NOTE: no ppsUnit, as the only information it contains is parallelism mode, which can be set to 0 for 'unknown' // NOTE: no ppsUnit, as the only information it contains is parallelism mode, which can be set to
} // 0 for 'unknown'
}// namespace h265

File diff suppressed because it is too large Load diff

View file

@ -1,97 +1,104 @@
/// \file json.h Holds all JSON-related headers. /// \file json.h Holds all JSON-related headers.
#pragma once #pragma once
#include <string>
#include <deque>
#include <map>
#include <istream>
#include <vector>
#include <set>
#include "socket.h" #include "socket.h"
#include <deque>
#include <istream>
#include <map>
#include <set>
#include <stdint.h>
#include <string>
#include <vector>
/// JSON-related classes and functions /// JSON-related classes and functions
namespace JSON { namespace JSON{
/// Lists all types of JSON::Value. /// Lists all types of JSON::Value.
enum ValueType { enum ValueType{EMPTY, BOOL, INTEGER, DOUBLE, STRING, ARRAY, OBJECT};
EMPTY, BOOL, INTEGER, DOUBLE, STRING, ARRAY, OBJECT
};
/// JSON-string-escapes a value /// JSON-string-escapes a value
std::string string_escape(const std::string & val); std::string string_escape(const std::string &val);
/// A JSON::Value is either a string or an integer, but may also be an object, array or null. /// A JSON::Value is either a string or an integer, but may also be an object, array or null.
class Value { class Value{
friend class Iter; friend class Iter;
friend class ConstIter; friend class ConstIter;
private: private:
ValueType myType; ValueType myType;
long long int intVal; long long int intVal;
std::string strVal; std::string strVal;
double dblVal; double dblVal;
double dblDivider; double dblDivider;
std::deque<Value*> arrVal; std::deque<Value *> arrVal;
std::map<std::string, Value*> objVal; std::map<std::string, Value *> objVal;
public: public:
//constructors/destructors // constructors/destructors
Value(); Value();
~Value(); ~Value();
Value(const Value & rhs); Value(const Value &rhs);
Value(std::istream & fromstream); Value(std::istream &fromstream);
Value(const std::string & val); Value(const std::string &val);
Value(const char * val); Value(const char *val);
Value(long long int val); Value(long long int val);
Value(int32_t val);
Value(int64_t val);
Value(uint32_t val);
Value(uint64_t val);
Value(double val); Value(double val);
Value(bool val); Value(bool val);
//comparison operators // comparison operators
bool operator==(const Value & rhs) const; bool operator==(const Value &rhs) const;
bool operator!=(const Value & rhs) const; bool operator!=(const Value &rhs) const;
bool compareExcept(const Value & rhs, const std::set<std::string> & skip) const; bool compareExcept(const Value &rhs, const std::set<std::string> &skip) const;
bool compareOnly(const Value & rhs, const std::set<std::string> & check) const; bool compareOnly(const Value &rhs, const std::set<std::string> &check) const;
//assignment operators // assignment operators
Value & assignFrom(const Value & rhs, const std::set<std::string> & skip); Value &assignFrom(const Value &rhs, const std::set<std::string> &skip);
Value & operator=(const Value & rhs); Value &operator=(const Value &rhs);
Value & operator=(const std::string & rhs); Value &operator=(const std::string &rhs);
Value & operator=(const char * rhs); Value &operator=(const char *rhs);
Value & operator=(const long long int & rhs); Value &operator=(const long long int &rhs);
Value & operator=(const int & rhs); Value &operator=(const int64_t &rhs);
Value & operator=(const double & rhs); Value &operator=(const int32_t &rhs);
Value & operator=(const unsigned int & rhs); Value &operator=(const uint64_t &rhs);
Value & operator=(const bool & rhs); Value &operator=(const uint32_t &rhs);
//converts to basic types Value &operator=(const double &rhs);
operator long long int() const; Value &operator=(const bool &rhs);
// converts to basic types
operator int64_t() const;
operator std::string() const; operator std::string() const;
operator bool() const; operator bool() const;
operator double() const; operator double() const;
const std::string asString() const; std::string asString() const;
const long long int asInt() const; int64_t asInt() const;
bool asBool() const;
const double asDouble() const; const double asDouble() const;
const bool asBool() const; const std::string &asStringRef() const;
const std::string & asStringRef() const; const char *c_str() const;
const char * c_str() const; // array operator for maps and arrays
//array operator for maps and arrays Value &operator[](const std::string &i);
Value & operator[](const std::string i); Value &operator[](const char *i);
Value & operator[](const char * i); Value &operator[](uint32_t i);
Value & operator[](unsigned int i); const Value &operator[](const std::string &i) const;
const Value & operator[](const std::string i) const; const Value &operator[](const char *i) const;
const Value & operator[](const char * i) const; const Value &operator[](uint32_t i) const;
const Value & operator[](unsigned int i) const; // handy functions and others
//handy functions and others
std::string toPacked() const; std::string toPacked() const;
void sendTo(Socket::Connection & socket) const; void sendTo(Socket::Connection &socket) const;
unsigned int packedSize() const; uint64_t packedSize() const;
void netPrepare(); void netPrepare();
std::string & toNetPacked(); std::string &toNetPacked();
std::string toString() const; std::string toString() const;
std::string toPrettyString(int indentation = 0) const; std::string toPrettyString(size_t indent = 0) const;
void append(const Value & rhs); void append(const Value &rhs);
void prepend(const Value & rhs); void prepend(const Value &rhs);
void shrink(unsigned int size); void shrink(uint32_t size);
void removeMember(const std::string & name); void removeMember(const std::string &name);
void removeMember(const std::deque<Value*>::iterator & it); void removeMember(const std::deque<Value *>::iterator &it);
void removeMember(const std::map<std::string, Value*>::iterator & it); void removeMember(const std::map<std::string, Value *>::iterator &it);
void removeNullMembers(); void removeNullMembers();
bool isMember(const std::string & name) const; bool isMember(const std::string &name) const;
bool isInt() const; bool isInt() const;
bool isDouble() const; bool isDouble() const;
bool isString() const; bool isString() const;
@ -99,119 +106,56 @@ namespace JSON {
bool isObject() const; bool isObject() const;
bool isArray() const; bool isArray() const;
bool isNull() const; bool isNull() const;
unsigned int size() const; uint32_t size() const;
void null(); void null();
}; };
Value fromDTMI2(std::string & data); Value fromDTMI2(const std::string &data);
Value fromDTMI2(const unsigned char * data, unsigned int len, unsigned int & i); Value fromDTMI2(const char *data, uint64_t len, uint32_t &i);
Value fromDTMI(std::string & data); Value fromDTMI(const std::string &data);
Value fromDTMI(const unsigned char * data, unsigned int len, unsigned int & i); Value fromDTMI(const char *data, uint64_t len, uint32_t &i);
Value fromString(const std::string & json); Value fromString(const std::string &json);
Value fromString(const char * data, const uint32_t data_len); Value fromString(const char *data, uint32_t data_len);
Value fromFile(std::string filename); Value fromFile(const std::string &filename);
void fromDTMI2(std::string & data, Value & ret); void fromDTMI2(const std::string &data, Value &ret);
void fromDTMI2(const unsigned char * data, unsigned int len, unsigned int & i, Value & ret); void fromDTMI2(const char *data, uint64_t len, uint32_t &i, Value &ret);
void fromDTMI(std::string & data, Value & ret); void fromDTMI(const std::string &data, Value &ret);
void fromDTMI(const unsigned char * data, unsigned int len, unsigned int & i, Value & ret); void fromDTMI(const char *data, uint64_t len, uint32_t &i, Value &ret);
class Iter { class Iter{
public: public:
Iter(Value & root);///<Construct from a root Value to iterate over. Iter(Value &root); ///< Construct from a root Value to iterate over.
Value & operator*() const;///< Dereferences into a Value reference. Value &operator*() const; ///< Dereferences into a Value reference.
Value* operator->() const;///< Dereferences into a Value reference. Value *operator->() const; ///< Dereferences into a Value reference.
operator bool() const;///< True if not done iterating. operator bool() const; ///< True if not done iterating.
Iter & operator++();///<Go to next iteration. Iter &operator++(); ///< Go to next iteration.
const std::string & key() const;///<Return the name of the current indice. const std::string &key() const; ///< Return the name of the current indice.
unsigned int num() const;///<Return the number of the current indice. uint32_t num() const; ///< Return the number of the current indice.
void remove();///<Delete the current indice from the parent JSON::Value. void remove(); ///< Delete the current indice from the parent JSON::Value.
private: private:
ValueType myType; ValueType myType;
Value * r; Value *r;
unsigned int i; uint32_t i;
std::deque<Value*>::iterator aIt; std::deque<Value *>::iterator aIt;
std::map<std::string, Value*>::iterator oIt; std::map<std::string, Value *>::iterator oIt;
}; };
class ConstIter { class ConstIter{
public: public:
ConstIter(const Value & root);///<Construct from a root Value to iterate over. ConstIter(const Value &root); ///< Construct from a root Value to iterate over.
const Value & operator*() const;///< Dereferences into a Value reference. const Value &operator*() const; ///< Dereferences into a Value reference.
const Value* operator->() const;///< Dereferences into a Value reference. const Value *operator->() const; ///< Dereferences into a Value reference.
operator bool() const;///< True if not done iterating. operator bool() const; ///< True if not done iterating.
ConstIter & operator++();///<Go to next iteration. ConstIter &operator++(); ///< Go to next iteration.
const std::string & key() const;///<Return the name of the current indice. const std::string &key() const; ///< Return the name of the current indice.
unsigned int num() const;///<Return the number of the current indice. uint32_t num() const; ///< Return the number of the current indice.
private: private:
ValueType myType; ValueType myType;
const Value * r; const Value *r;
unsigned int i; uint32_t i;
std::deque<Value*>::const_iterator aIt; std::deque<Value *>::const_iterator aIt;
std::map<std::string, Value*>::const_iterator oIt; std::map<std::string, Value *>::const_iterator oIt;
}; };
#define jsonForEach(val, i) for(JSON::Iter i(val); i; ++i) #define jsonForEach(val, i) for (JSON::Iter i(val); i; ++i)
#define jsonForEachConst(val, i) for(JSON::ConstIter i(val); i; ++i) #define jsonForEachConst(val, i) for (JSON::ConstIter i(val); i; ++i)
}// namespace JSON
template <typename T>
std::string encodeVector(T begin, T end) {
std::string result;
for (T it = begin; it != end; it++) {
long long int tmp = (*it);
while (tmp >= 0xFFFF) {
result += (char)0xFF;
result += (char)0xFF;
tmp -= 0xFFFF;
}
result += (char)(tmp / 256);
result += (char)(tmp % 256);
}
return result;
}
template <typename T>
void decodeVector(std::string input, T & result) {
result.clear();
unsigned int tmp = 0;
for (int i = 0; i < input.size(); i += 2) {
unsigned int curLen = (input[i] << 8) + input[i + 1];
tmp += curLen;
if (curLen != 0xFFFF) {
result.push_back(tmp);
tmp = 0;
}
}
}
template <typename T>
std::string encodeVector4(T begin, T end) {
std::string result;
for (T it = begin; it != end; it++) {
long long int tmp = (*it);
while (tmp >= 0xFFFFFFFF) {
result += (char)0xFF;
result += (char)0xFF;
result += (char)0xFF;
result += (char)0xFF;
tmp -= 0xFFFFFFFF;
}
result += (char)((tmp & 0xFF000000) >> 24);
result += (char)((tmp & 0x00FF0000) >> 16);
result += (char)((tmp & 0x0000FF00) >> 8);
result += (char)((tmp & 0x000000FF));
}
return result;
}
template <typename T>
void decodeVector4(std::string input, T & result) {
result.clear();
unsigned int tmp = 0;
for (int i = 0; i < input.size(); i += 4) {
unsigned int curLen = (input[i] << 24) + (input[i + 1] << 16) + (input[i + 2] << 8) + (input[i + 3]);
tmp += curLen;
if (curLen != 0xFFFFFFFF) {
result.push_back(tmp);
tmp = 0;
}
}
}
}

View file

@ -10,6 +10,7 @@
#include "json.h" #include "json.h"
#include "defines.h" #include "defines.h"
#include "bitfields.h"
/// Contains all MP4 format related code. /// Contains all MP4 format related code.
namespace MP4 { namespace MP4 {
@ -80,7 +81,7 @@ namespace MP4 {
payloadOffset = rs.payloadOffset; payloadOffset = rs.payloadOffset;
} }
/// Returns the values at byte positions 4 through 7. /// Returns the values at byte positions 4 through 7.
std::string Box::getType() { std::string Box::getType() const {
return std::string(data + 4, 4); return std::string(data + 4, 4);
} }
@ -190,7 +191,7 @@ namespace MP4 {
} }
/// Returns the total boxed size of this box, including the header. /// Returns the total boxed size of this box, including the header.
uint64_t Box::boxedSize() { uint64_t Box::boxedSize() const {
if (payloadOffset == 16) { if (payloadOffset == 16) {
return ((uint64_t)ntohl(((int *)data)[2]) << 32) | ntohl(((int *)data)[3]); return ((uint64_t)ntohl(((int *)data)[2]) << 32) | ntohl(((int *)data)[3]);
} }
@ -199,7 +200,7 @@ namespace MP4 {
/// Retruns the size of the payload of thix box, excluding the header. /// Retruns the size of the payload of thix box, excluding the header.
/// This value is defined as boxedSize() - 8. /// This value is defined as boxedSize() - 8.
uint64_t Box::payloadSize() { uint64_t Box::payloadSize() const {
return boxedSize() - payloadOffset; return boxedSize() - payloadOffset;
} }
@ -232,7 +233,7 @@ namespace MP4 {
/// Attempts to typecast this Box to a more specific type and call the toPrettyString() function of that type. /// Attempts to typecast this Box to a more specific type and call the toPrettyString() function of that type.
/// If this failed, it will print out a message saying pretty-printing is not implemented for boxtype. /// If this failed, it will print out a message saying pretty-printing is not implemented for boxtype.
std::string Box::toPrettyString(uint32_t indent) { std::string Box::toPrettyString(uint32_t indent) const {
switch (ntohl(*((int *)(data + 4)))) { //type is at this address switch (ntohl(*((int *)(data + 4)))) { //type is at this address
case 0x6D666864: case 0x6D666864:
return ((MFHD *)this)->toPrettyString(indent); return ((MFHD *)this)->toPrettyString(indent);
@ -382,10 +383,10 @@ namespace MP4 {
return ((HEV1 *)this)->toPrettyString(indent); return ((HEV1 *)this)->toPrettyString(indent);
break; break;
case 0x61766331: case 0x61766331:
case 0x656E6376://encv
return ((AVC1 *)this)->toPrettyString(indent); return ((AVC1 *)this)->toPrettyString(indent);
break; break;
case 0x68323634://h264 case 0x68323634://h264
case 0x656E6376://encv
return ((H264 *)this)->toPrettyString(indent); return ((H264 *)this)->toPrettyString(indent);
break; break;
case 0x6669656C: case 0x6669656C:
@ -451,9 +452,24 @@ namespace MP4 {
INFO_MSG("FTAB box found!"); INFO_MSG("FTAB box found!");
return ((FontTableBox *)this)->toPrettyString(indent); return ((FontTableBox *)this)->toPrettyString(indent);
break; break;
case 0x70737368:
return ((PSSH *)this)->toPrettyString(indent);
break;
case 0x73656E63:
return ((SENC *)this)->toPrettyString(indent);
break;
case 0x74656E63:
return ((TENC *)this)->toPrettyString(indent);
break;
case 0x7361697A:
return ((SAIZ *)this)->toPrettyString(indent);
break;
case 0x7361696F:
return ((SAIO *)this)->toPrettyString(indent);
break;
/*LTS-END*/ /*LTS-END*/
default: default:
INFO_MSG("no code found: 0x%0.8x",ntohl(*((int *)(data + 4)))); INFO_MSG("no code found: 0x%.8x",Bit::btohl(data + 4));
break; break;
} }
std::stringstream retval; std::stringstream retval;
@ -489,6 +505,16 @@ namespace MP4 {
return data[index]; return data[index];
} }
/// Gets the 8 bits integer at the given index.
/// Returns zero if out of bounds.
char Box::getInt8(size_t index) const {
index += payloadOffset;
if (index >= boxedSize()) {
return 0;
}
return data[index];
}
/// Sets the 16 bits integer at the given index. /// Sets the 16 bits integer at the given index.
/// Attempts to resize the data pointer if the index is out of range. /// Attempts to resize the data pointer if the index is out of range.
/// Fails silently if resizing failed. /// Fails silently if resizing failed.
@ -499,8 +525,7 @@ namespace MP4 {
return; return;
} }
} }
newData = htons(newData); Bit::htobs(data + index, newData);
memcpy(data + index, (char *) &newData, 2);
} }
/// Gets the 16 bits integer at the given index. /// Gets the 16 bits integer at the given index.
@ -514,9 +539,18 @@ namespace MP4 {
} }
setInt16(0, index - payloadOffset); setInt16(0, index - payloadOffset);
} }
short result; return Bit::btohs(data + index);
memcpy((char *) &result, data + index, 2); }
return ntohs(result);
/// Gets the 16 bits integer at the given index.
/// Attempts to resize the data pointer if the index is out of range.
/// Returns zero if resizing failed.
short Box::getInt16(size_t index) const {
index += payloadOffset;
if (index + 1 >= boxedSize()) {
return 0;
}
return Bit::btohs(data + index);
} }
/// Sets the 24 bits integer at the given index. /// Sets the 24 bits integer at the given index.
@ -529,9 +563,7 @@ namespace MP4 {
return; return;
} }
} }
data[index] = (newData & 0x00FF0000) >> 16; Bit::htob24(data + index, newData);
data[index + 1] = (newData & 0x0000FF00) >> 8;
data[index + 2] = (newData & 0x000000FF);
} }
/// Gets the 24 bits integer at the given index. /// Gets the 24 bits integer at the given index.
@ -545,12 +577,18 @@ namespace MP4 {
} }
setInt24(0, index - payloadOffset); setInt24(0, index - payloadOffset);
} }
uint32_t result = data[index]; return Bit::btoh24(data + index);
result <<= 8; }
result += data[index + 1];
result <<= 8; /// Gets the 24 bits integer at the given index.
result += data[index + 2]; /// Attempts to resize the data pointer if the index is out of range.
return result; /// Returns zero if resizing failed.
uint32_t Box::getInt24(size_t index) const {
index += payloadOffset;
if (index + 2 >= boxedSize()) {
return 0;
}
return Bit::btoh24(data + index);
} }
/// Sets the 32 bits integer at the given index. /// Sets the 32 bits integer at the given index.
@ -563,7 +601,7 @@ namespace MP4 {
return; return;
} }
} }
((int *)(data + index))[0] = htonl(newData); Bit::htobl(data + index, newData);
} }
/// Gets the 32 bits integer at the given index. /// Gets the 32 bits integer at the given index.
@ -577,7 +615,18 @@ namespace MP4 {
} }
setInt32(0, index - payloadOffset); setInt32(0, index - payloadOffset);
} }
return ntohl(((int *)(data + index))[0]); return Bit::btohl(data + index);
}
/// Gets the 32 bits integer at the given index.
/// Attempts to resize the data pointer if the index is out of range.
/// Returns zero if resizing failed.
uint32_t Box::getInt32(size_t index) const {
index += payloadOffset;
if (index + 3 >= boxedSize()) {
return 0;
}
return Bit::btohl(data + index);
} }
/// Sets the 64 bits integer at the given index. /// Sets the 64 bits integer at the given index.
@ -590,8 +639,7 @@ namespace MP4 {
return; return;
} }
} }
((int *)(data + index))[0] = htonl((int)(newData >> 32)); Bit::htobll(data + index, newData);
((int *)(data + index))[1] = htonl((int)(newData & 0xFFFFFFFF));
} }
/// Gets the 64 bits integer at the given index. /// Gets the 64 bits integer at the given index.
@ -605,10 +653,18 @@ namespace MP4 {
} }
setInt64(0, index - payloadOffset); setInt64(0, index - payloadOffset);
} }
uint64_t result = ntohl(((int *)(data + index))[0]); return Bit::btohll(data + index);
result <<= 32; }
result += ntohl(((int *)(data + index))[1]);
return result; /// Gets the 64 bits integer at the given index.
/// Attempts to resize the data pointer if the index is out of range.
/// Returns zero if resizing failed.
uint64_t Box::getInt64(size_t index) const {
index += payloadOffset;
if (index + 7 >= boxedSize()) {
return 0;
}
return Bit::btohll(data + index);
} }
/// Sets the NULL-terminated string at the given index. /// Sets the NULL-terminated string at the given index.
@ -653,7 +709,7 @@ namespace MP4 {
/// Returns the length of the NULL-terminated string at the given index. /// Returns the length of the NULL-terminated string at the given index.
/// Returns 0 if out of range. /// Returns 0 if out of range.
size_t Box::getStringLen(size_t index) { size_t Box::getStringLen(size_t index) const {
index += payloadOffset; index += payloadOffset;
if (index >= boxedSize()) { if (index >= boxedSize()) {
return 0; return 0;
@ -682,8 +738,8 @@ namespace MP4 {
/// Returns the size of the box at the given position. /// Returns the size of the box at the given position.
/// Returns undefined values if there is no box at the given position. /// Returns undefined values if there is no box at the given position.
/// Returns 0 if out of range. /// Returns 0 if out of range.
size_t Box::getBoxLen(size_t index) { size_t Box::getBoxLen(size_t index) const {
if ((index + payloadOffset + 8) > boxedSize()) { if ((index + payloadOffset + 8) >= boxedSize()) {
return 0; return 0;
} }
return calcBoxSize(data + index + payloadOffset); return calcBoxSize(data + index + payloadOffset);
@ -746,7 +802,7 @@ namespace MP4 {
setInt8(newVersion, 0); setInt8(newVersion, 0);
} }
char fullBox::getVersion() { char fullBox::getVersion() const {
return getInt8(0); return getInt8(0);
} }
@ -754,11 +810,11 @@ namespace MP4 {
setInt24(newFlags, 1); setInt24(newFlags, 1);
} }
uint32_t fullBox::getFlags() { uint32_t fullBox::getFlags() const {
return getInt24(1); return getInt24(1);
} }
std::string fullBox::toPrettyString(uint32_t indent) { std::string fullBox::toPrettyString(uint32_t indent) const {
std::stringstream r; std::stringstream r;
r << std::string(indent + 1, ' ') << "Version: " << (int)getVersion() << std::endl; r << std::string(indent + 1, ' ') << "Version: " << (int)getVersion() << std::endl;
r << std::string(indent + 1, ' ') << "Flags: " << getFlags() << std::endl; r << std::string(indent + 1, ' ') << "Flags: " << getFlags() << std::endl;

View file

@ -31,40 +31,47 @@ namespace MP4 {
} }
void copyFrom(const Box & rs); void copyFrom(const Box & rs);
std::string getType(); std::string getType() const;
bool isType(const char * boxType) const; bool isType(const char * boxType) const;
bool read(FILE * newData); bool read(FILE * newData);
bool read(std::string & newData); bool read(std::string & newData);
uint64_t boxedSize(); uint64_t boxedSize() const;
uint64_t payloadSize(); uint64_t payloadSize() const;
char * asBox(); char * asBox();
char * payload(); char * payload();
void clear(); void clear();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0) const;
protected: protected:
//integer functions //integer functions
void setInt8(char newData, size_t index); void setInt8(char newData, size_t index);
char getInt8(size_t index); char getInt8(size_t index);
char getInt8(size_t index) const;
void setInt16(short newData, size_t index); void setInt16(short newData, size_t index);
short getInt16(size_t index); short getInt16(size_t index);
short getInt16(size_t index) const;
void setInt24(uint32_t newData, size_t index); void setInt24(uint32_t newData, size_t index);
uint32_t getInt24(size_t index); uint32_t getInt24(size_t index);
uint32_t getInt24(size_t index) const;
void setInt32(uint32_t newData, size_t index); void setInt32(uint32_t newData, size_t index);
uint32_t getInt32(size_t index); uint32_t getInt32(size_t index);
uint32_t getInt32(size_t index) const;
void setInt64(uint64_t newData, size_t index); void setInt64(uint64_t newData, size_t index);
uint64_t getInt64(size_t index); uint64_t getInt64(size_t index);
uint64_t getInt64(size_t index) const;
//string functions //string functions
void setString(std::string newData, size_t index); void setString(std::string newData, size_t index);
void setString(char * newData, size_t size, size_t index); void setString(char * newData, size_t size, size_t index);
char * getString(size_t index); char * getString(size_t index);
size_t getStringLen(size_t index); size_t getStringLen(size_t index) const;
//box functions //box functions
Box & getBox(size_t index); Box & getBox(size_t index);
size_t getBoxLen(size_t index); size_t getBoxLen(size_t index) const;
void setBox(Box & newEntry, size_t index); void setBox(Box & newEntry, size_t index);
//data functions //data functions
bool reserve(size_t position, size_t current, size_t wanted); bool reserve(size_t position, size_t current, size_t wanted);
bool reserve(size_t position, size_t current, size_t wanted) const {return false;}
//internal variables //internal variables
char * data; ///< Holds the data of this box char * data; ///< Holds the data of this box
unsigned int data_size; ///< Currently reserved size unsigned int data_size; ///< Currently reserved size
@ -77,10 +84,10 @@ namespace MP4 {
public: public:
fullBox(); fullBox();
void setVersion(char newVersion); void setVersion(char newVersion);
char getVersion(); char getVersion() const;
void setFlags(uint32_t newFlags); void setFlags(uint32_t newFlags);
uint32_t getFlags(); uint32_t getFlags() const;
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0) const ;
}; };
class containerBox: public Box { class containerBox: public Box {

View file

@ -69,14 +69,14 @@ namespace MP4 {
uint32_t tmp = (newRef.referenceType ? 0x80000000 : 0) | newRef.referencedSize; uint32_t tmp = (newRef.referenceType ? 0x80000000 : 0) | newRef.referencedSize;
setInt32(tmp, offset); setInt32(tmp, offset);
setInt32(newRef.subSegmentDuration, offset + 4); setInt32(newRef.subSegmentDuration, offset + 4);
tmp = (newRef.sapStart ? 0x80000000 : 0) | ((newRef.sapType & 0x7) << 24) | newRef.sapDeltaTime; tmp = (newRef.sapStart ? 0x80000000 : 0) | ((uint32_t)(newRef.sapType & 0x70) << 24) | newRef.sapDeltaTime;
setInt32(tmp, offset + 8); setInt32(tmp, offset + 8);
} }
sidxReference SIDX::getReference(size_t index) { sidxReference SIDX::getReference(size_t index) {
sidxReference result; sidxReference result;
if (index >= getReferenceCount()) { if (index >= getReferenceCount()) {
DEBUG_MSG(DLVL_DEVEL, "Warning, attempt to obtain reference out of bounds"); DEVEL_MSG("Warning, attempt to obtain reference out of bounds");
return result; return result;
} }
uint32_t offset = 24 + (index * 12) + (getVersion() == 0 ? 0 : 8); uint32_t offset = 24 + (index * 12) + (getVersion() == 0 ? 0 : 8);
@ -115,8 +115,9 @@ namespace MP4 {
TFDT::TFDT() { TFDT::TFDT() {
memcpy(data + 4, "tfdt", 4); memcpy(data + 4, "tfdt", 4);
setVersion(0); setVersion(1);
setFlags(0); setFlags(0);
setBaseMediaDecodeTime(0);
} }
void TFDT::setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime) { void TFDT::setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime) {

View file

@ -1,11 +1,309 @@
#include "mp4_encryption.h" #include "mp4_encryption.h"
#include "defines.h"
namespace MP4 { namespace MP4 {
PSSH::PSSH() {
memcpy(data + 4, "pssh", 4);
}
std::string PSSH::toPrettyString(uint32_t indent) {
std::stringstream r;
r << std::string(indent, ' ') << "[pssh] Protection System Specific Header Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "SystemID: " << getSystemIDHex() << std::endl;
if (getVersion()){
r << std::string(indent + 1, ' ') << "KID_count: " << getKIDCount() << std::endl;
}
r << std::string(indent + 1, ' ') << "DataSize: " << getDataSize() << std::endl;
r << std::string(indent + 1, ' ') << "Data: ";
size_t dataSize = getDataSize();
char * data = getData();
for (size_t i = 0; i < dataSize; ++i){
r << std::hex << std::setw(2) << std::setfill('0') << (int)data[i] << std::dec << "";
}
r << std::endl;
return r.str();
}
std::string PSSH::getSystemIDHex() {
char * systemID = getString(4);
std::stringstream res;
for (size_t i = 0; i < 16; ++i){
res << std::hex << std::setw(2) << std::setfill('0') << (int)systemID[i] << std::dec;
}
return "0x" + res.str();
}
void PSSH::setSystemIDHex(const std::string & systemID) {
setString(systemID, 4);
}
size_t PSSH::getKIDCount(){
return getVersion() ? getInt32(20) : 0;
}
size_t PSSH::getDataSize(){
if (getVersion()){
size_t kidCount = getInt32(20);
return getInt32(24 + (kidCount * 16));
}
return getInt32(20);
}
char * PSSH::getData(){
if (getVersion()){
size_t kidCount = getInt32(20);
return getString(24 + (kidCount * 16) + 4);
}
return getString(24);
}
void PSSH::setData(const std::string & data){
if (getVersion()){
WARN_MSG("Not implemented yet!");
return;
}
for (int i = 0; i < data.size(); i++){
setInt8(data[i], 24 + i);
}
setInt32(data.size(), 20);
}
std::string TENC::toPrettyString(uint32_t indent) {
std::stringstream r;
r << std::string(indent, ' ') << "[tenc] Track Encryption Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "default_isEncrypted: " << getDefaultIsEncrypted() << std::endl;
r << std::string(indent + 1, ' ') << "default_IV_size: " << getDefaultIVSize() << std::endl;
r << std::string(indent + 1, ' ') << "default_KID: ";
std::string defaultKID = getDefaultKID();
for (int i = 0; i < 16; i++){
r << std::hex << std::setw(2) << std::setfill('0') << (int)defaultKID[i] << std::dec << " ";
}
r << std::endl;
return r.str();
}
TENC::TENC() {
memcpy(data + 4, "tenc", 4);
setDefaultIsEncrypted(1);
setDefaultIVSize(8);
}
size_t TENC::getDefaultIsEncrypted(){
return getInt24(4);
}
void TENC::setDefaultIsEncrypted(size_t isEncrypted){
setInt24(isEncrypted, 4);
}
size_t TENC::getDefaultIVSize(){
return getInt8(7);
}
void TENC::setDefaultIVSize(uint8_t ivSize){
setInt8(ivSize, 7);
}
std::string TENC::getDefaultKID(){
std::string result;
for (int i = 8; i < 24; i++){
result += getInt8(i);
}
return result;
}
void TENC::setDefaultKID(const std::string & kid){
for (int i = 0; i < 16; i++){
if (i < kid.size()){
setInt8(kid[i], i + 8);
}else{
setInt8(0, i + 8);
}
}
}
SENC::SENC() {
memcpy(data + 4, "senc", 4);
setFlags(2);
}
uint32_t SENC::getSampleCount() const {
return getInt32(4);
}
#define IV_SIZE 8
void SENC::setSample(UUID_SampleEncryption_Sample newSample, size_t index) {
int myOffset = 8;
for (unsigned int i = 0; i < std::min(index, (size_t)getSampleCount()); i++) {
myOffset += IV_SIZE;
if (getFlags() & 0x02) {
int entryCount = getInt16(myOffset);
myOffset += 2 + (entryCount * 6);
}
}
if (index > getSampleCount()) {
ERROR_MSG("First fill intermediate entries!");
return;
/*
//we are now at the end of currently reserved space, reserve more and adapt offset accordingly.
int reserveSize = ((index - getSampleCount())) * (IV_SIZE + (getFlags() & 0x02));
reserveSize += IV_SIZE;
if (getFlags() & 0x02) {
reserveSize += 2 + newSample.Entries.size();
}
if (!reserve(myOffset, 0, reserveSize)) {
return;//Memory errors...
}
myOffset += (index - getSampleCount()) * (IV_SIZE + (getFlags() & 0x02));
*/
}
//write box.
for (int i = 0; i < IV_SIZE; i++) {
setInt8(newSample.InitializationVector[i], myOffset ++);//set and skip
}
if (getFlags() & 0x02) {
setInt16(newSample.Entries.size(), myOffset);
myOffset += 2;
for (std::vector<UUID_SampleEncryption_Sample_Entry>::iterator it = newSample.Entries.begin(); it != newSample.Entries.end(); it++) {
setInt16(it->BytesClear, myOffset);
myOffset += 2;
setInt32(it->BytesEncrypted, myOffset);
myOffset += 4;
}
}
if (index >= getSampleCount()) {
setInt32(index + 1, 4);
}
}
UUID_SampleEncryption_Sample SENC::getSample(size_t index) const {
if (index >= getSampleCount()) {
return UUID_SampleEncryption_Sample();
}
int myOffset = 8;
for (unsigned int i = 0; i < index; i++) {
myOffset += IV_SIZE;
if (getFlags() & 0x02) {
int entryCount = getInt16(myOffset);
myOffset += 2;//skip over entrycount
myOffset += entryCount * 6;//skip entryCount sample entries
}
}
UUID_SampleEncryption_Sample result;
for (int i = 0; i < IV_SIZE; i++) {
result.InitializationVector += (char)getInt8(myOffset++);//read and skip
}
if (getFlags() & 0x02) {
result.NumberOfEntries = getInt16(myOffset);
myOffset += 2;
for (unsigned int i = 0; i < result.NumberOfEntries; i++) {
result.Entries.push_back(UUID_SampleEncryption_Sample_Entry());
result.Entries[i].BytesClear = getInt16(myOffset);
myOffset += 2;
result.Entries[i].BytesEncrypted = getInt32(myOffset);
myOffset += 4;
}
}
return result;
}
std::string SENC::toPrettyString(uint32_t indent) const {
std::stringstream r;
r << std::string(indent, ' ') << "[senc] Sample Encryption Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "Sample Count: " << getSampleCount() << std::endl;
for (unsigned int i = 0; i < getSampleCount(); i++) {
UUID_SampleEncryption_Sample tmpSample = getSample(i);
r << std::string(indent + 1, ' ') << "[" << i << "]" << std::endl;
r << std::string(indent + 3, ' ') << "Initialization Vector: 0x";
for (unsigned int j = 0; j < tmpSample.InitializationVector.size(); j++) {
r << std::hex << std::setw(2) << std::setfill('0') << (int)tmpSample.InitializationVector[j] << std::dec;
}
r << std::endl;
if (getFlags() & 0x02) {
r << std::string(indent + 3, ' ') << "Number of entries: " << tmpSample.NumberOfEntries << std::endl;
for (unsigned int j = 0; j < tmpSample.NumberOfEntries; j++) {
r << std::string(indent + 3, ' ') << "[" << j << "]" << std::endl;
r << std::string(indent + 5, ' ') << "Bytes clear: " << tmpSample.Entries[j].BytesClear << std::endl;
r << std::string(indent + 5, ' ') << "Bytes encrypted: " << tmpSample.Entries[j].BytesEncrypted << std::endl;
}
}
}
return r.str();
}
SAIZ::SAIZ(size_t entryCount){
memcpy(data + 4, "saiz", 4);
setFlags(0);
setVersion(0);
setInt24(0, 4); //Default sample size
setInt16(entryCount, 7);//EntryCount Samples
for (int i = 0; i < entryCount; i++){
setInt8(16, i+9);//16 bytes IV's
}
}
size_t SAIZ::getDefaultSampleSize(){
return getInt24(4);
}
size_t SAIZ::getEntryCount(){
return getInt16(7);
}
size_t SAIZ::getEntrySize(size_t entryNo){
if (entryNo >= getEntryCount()){return -1;}
return getInt8(9 + entryNo);
}
std::string SAIZ::toPrettyString(uint32_t indent) {
std::stringstream r;
r << std::string(indent, ' ') << "[saiz] Sample Auxiliary Information Size Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "Default Sample Size: " << getDefaultSampleSize() << std::endl;
r << std::string(indent + 1, ' ') << "Entry Count: " << getEntryCount() << std::endl;
for (size_t i = 0; i < getEntryCount(); ++i){
r << std::string(indent + 2, ' ') << "[" << i << "]: " << getEntrySize(i) << std::endl;
}
return r.str();
}
SAIO::SAIO(size_t offset){
memcpy(data + 4, "saio", 4);
setInt32(1, 4);
setInt32(offset, 8);
}
size_t SAIO::getEntryCount(){
return getInt32(4);
}
size_t SAIO::getEntrySize(size_t entryNo){
if (entryNo >= getEntryCount()){return -1;}
return getInt32(8 + (entryNo * 4));
}
std::string SAIO::toPrettyString(uint32_t indent) {
std::stringstream r;
r << std::string(indent, ' ') << "[saio] Sample Auxiliary Information Offset Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "Entry Count: " << getEntryCount() << std::endl;
for (size_t i = 0; i < getEntryCount(); ++i){
r << std::string(indent + 2, ' ') << "[" << i << "]: " << getEntrySize(i) << std::endl;
}
return r.str();
}
UUID_SampleEncryption::UUID_SampleEncryption() { UUID_SampleEncryption::UUID_SampleEncryption() {
setUUID((std::string)"a2394f52-5a9b-4f14-a244-6c427c648df4"); setUUID((std::string)"a2394f52-5a9b-4f14-a244-6c427c648df4");
} }
UUID_SampleEncryption::UUID_SampleEncryption(const SENC & senc){
setUUID((std::string)"a2394f52-5a9b-4f14-a244-6c427c648df4");
setVersion(0);
setFlags(2);
size_t sampleCount = senc.getSampleCount();
for (size_t i = 0; i < sampleCount; ++i){
setSample(senc.getSample(i), i);
}
}
void UUID_SampleEncryption::setVersion(uint32_t newVersion) { void UUID_SampleEncryption::setVersion(uint32_t newVersion) {
setInt8(newVersion, 16); setInt8(newVersion, 16);
} }
@ -93,17 +391,9 @@ namespace MP4 {
myOffset += 2 + (entryCount * 6); myOffset += 2 + (entryCount * 6);
} }
} }
if (index >= getSampleCount()) { if (index > getSampleCount()) {
//we are now at the end of currently reserved space, reserve more and adapt offset accordingly. ERROR_MSG("First fill intermediate entries!");
int reserveSize = ((index - getSampleCount())) * (IV_SIZE + (getFlags() & 0x02)); return;
reserveSize += IV_SIZE;
if (getFlags() & 0x02) {
reserveSize += 2 + newSample.Entries.size();
}
if (!reserve(myOffset, 0, reserveSize)) {
return;//Memory errors...
}
myOffset += (index - getSampleCount()) * (IV_SIZE + (getFlags() & 0x02));
} }
//write box. //write box.
for (int i = 0; i < IV_SIZE; i++) { for (int i = 0; i < IV_SIZE; i++) {
@ -339,15 +629,13 @@ namespace MP4 {
Box & SINF::getEntry(uint32_t no) { Box & SINF::getEntry(uint32_t no) {
static Box ret = Box((char *)"\000\000\000\010erro", false); static Box ret = Box((char *)"\000\000\000\010erro", false);
if (no > 4) { if (no > 4) {
ret = Box((char *)"\000\000\000\010erro", false);
return ret; return ret;
} }
int tempLoc = 0; int tempLoc = 0;
for (unsigned int i = 0; i < no; i++) { for (unsigned int i = 0; i < no; i++) {
tempLoc += Box(getBox(tempLoc).asBox(), false).boxedSize(); tempLoc += getBoxLen(tempLoc);
} }
ret = Box(getBox(tempLoc).asBox(), false); return getBox(tempLoc);
return ret;
} }
std::string SINF::toPrettyString(uint32_t indent) { std::string SINF::toPrettyString(uint32_t indent) {
@ -363,11 +651,12 @@ namespace MP4 {
return r.str(); return r.str();
} }
FRMA::FRMA() { FRMA::FRMA(const std::string & originalFormat) {
memcpy(data + 4, "frma", 4); memcpy(data + 4, "frma", 4);
setOriginalFormat(originalFormat);
} }
void FRMA::setOriginalFormat(std::string newFormat) { void FRMA::setOriginalFormat(const std::string & newFormat) {
for (unsigned int i = 0; i < 4; i++) { for (unsigned int i = 0; i < 4; i++) {
if (i < newFormat.size()) { if (i < newFormat.size()) {
setInt8(newFormat[i], i); setInt8(newFormat[i], i);
@ -388,8 +677,10 @@ namespace MP4 {
return r.str(); return r.str();
} }
SCHM::SCHM() { SCHM::SCHM(uint32_t schemeType, uint32_t schemeVersion){
memcpy(data + 4, "schm", 4); memcpy(data + 4, "schm", 4);
setSchemeType(schemeType);
setSchemeVersion(schemeVersion);
} }
void SCHM::setSchemeType(uint32_t newType) { void SCHM::setSchemeType(uint32_t newType) {

View file

@ -14,9 +14,60 @@ namespace MP4 {
std::vector<UUID_SampleEncryption_Sample_Entry> Entries; std::vector<UUID_SampleEncryption_Sample_Entry> Entries;
}; };
class PSSH: public fullBox {
public:
PSSH();
std::string getSystemIDHex();
void setSystemIDHex(const std::string & systemID);
std::string toPrettyString(uint32_t indent = 0);
size_t getKIDCount();
size_t getDataSize();
char * getData();
void setData(const std::string & data);
};
class TENC: public fullBox {
public:
TENC();
std::string toPrettyString(uint32_t indent = 0);
size_t getDefaultIsEncrypted();
void setDefaultIsEncrypted(size_t isEncrypted);
size_t getDefaultIVSize();
void setDefaultIVSize(uint8_t ivSize);
std::string getDefaultKID();
void setDefaultKID(const std::string & kid);
};
class SENC: public fullBox {
public:
SENC();
uint32_t getSampleCount() const;
void setSample(UUID_SampleEncryption_Sample newSample, size_t index);
UUID_SampleEncryption_Sample getSample(size_t index) const;
std::string toPrettyString(uint32_t indent = 0) const;
};
class SAIZ : public fullBox {
public:
SAIZ(size_t entryCount = 0);
size_t getDefaultSampleSize();
size_t getEntryCount();
size_t getEntrySize(size_t entryNo);
std::string toPrettyString(uint32_t indent = 0);
};
class SAIO : public fullBox {
public:
SAIO(size_t offset = 0);
size_t getEntryCount();
size_t getEntrySize(size_t entryNo);
std::string toPrettyString(uint32_t indent = 0);
};
class UUID_SampleEncryption: public UUID { class UUID_SampleEncryption: public UUID {
public: public:
UUID_SampleEncryption(); UUID_SampleEncryption();
UUID_SampleEncryption(const SENC & senc);
void setVersion(uint32_t newVersion); void setVersion(uint32_t newVersion);
uint32_t getVersion(); uint32_t getVersion();
void setFlags(uint32_t newFlags); void setFlags(uint32_t newFlags);
@ -75,15 +126,15 @@ namespace MP4 {
class FRMA: public Box { class FRMA: public Box {
public: public:
FRMA(); FRMA(const std::string & originalFormat = "");
void setOriginalFormat(std::string newFormat); void setOriginalFormat(const std::string & newFormat);
std::string getOriginalFormat(); std::string getOriginalFormat();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class SCHM: public fullBox { class SCHM: public fullBox {
public: public:
SCHM(); SCHM(uint32_t schemeType = 0x636E6563, uint32_t schemeVersion = 0x00000100);//CENC defaults
void setSchemeType(uint32_t newType); void setSchemeType(uint32_t newType);
uint32_t getSchemeType(); uint32_t getSchemeType();
void setSchemeVersion(uint32_t newVersion); void setSchemeVersion(uint32_t newVersion);

View file

@ -474,6 +474,10 @@ namespace MP4 {
return getInt32(offset); return getInt32(offset);
} }
bool TFHD::getDefaultBaseIsMoof() {
return getFlags() & tfhdBaseIsMoof;
}
std::string TFHD::toPrettyString(uint32_t indent) { std::string TFHD::toPrettyString(uint32_t indent) {
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[tfhd] Track Fragment Header (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[tfhd] Track Fragment Header (" << boxedSize() << ")" << std::endl;
@ -499,6 +503,9 @@ namespace MP4 {
if (flags & tfhdNoDuration) { if (flags & tfhdNoDuration) {
r << " NoDuration"; r << " NoDuration";
} }
if (flags & tfhdBaseIsMoof) {
r << " BaseIsMoof";
}
r << std::endl; r << std::endl;
r << std::string(indent + 1, ' ') << "TrackID " << getTrackID() << std::endl; r << std::string(indent + 1, ' ') << "TrackID " << getTrackID() << std::endl;
@ -513,7 +520,7 @@ namespace MP4 {
r << std::string(indent + 1, ' ') << "Default Sample Duration " << getDefaultSampleDuration() << std::endl; r << std::string(indent + 1, ' ') << "Default Sample Duration " << getDefaultSampleDuration() << std::endl;
} }
if (flags & tfhdSampleSize) { if (flags & tfhdSampleSize) {
r << std::string(indent + 1, ' ') << "Default Same Size " << getDefaultSampleSize() << std::endl; r << std::string(indent + 1, ' ') << "Default Sample Size " << getDefaultSampleSize() << std::endl;
} }
if (flags & tfhdSampleFlag) { if (flags & tfhdSampleFlag) {
r << std::string(indent + 1, ' ') << "Default Sample Flags " << prettySampleFlags(getDefaultSampleFlags()) << std::endl; r << std::string(indent + 1, ' ') << "Default Sample Flags " << prettySampleFlags(getDefaultSampleFlags()) << std::endl;
@ -569,6 +576,10 @@ namespace MP4 {
} }
void AVCC::setSPS(std::string newSPS, size_t index) { void AVCC::setSPS(std::string newSPS, size_t index) {
setSPS(newSPS.data(), newSPS.size(), index);
}
void AVCC::setSPS(const char * data, size_t len, size_t index) {
if (index >= getSPSCount()){ if (index >= getSPSCount()){
WARN_MSG("Cannot set entry at position %zu/%u: Out of bounds", index, getSPSCount()); WARN_MSG("Cannot set entry at position %zu/%u: Out of bounds", index, getSPSCount());
} }
@ -576,9 +587,9 @@ namespace MP4 {
for (size_t i = 0; i < index; i++){ for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2; offset += getInt16(offset) + 2;
} }
setInt16(newSPS.size(), offset); setInt16(len, offset);
for (unsigned int i = 0; i < newSPS.size(); i++) { for (unsigned int i = 0; i < len; i++) {
setInt8(newSPS[i], offset + 2 + i); setInt8(data[i], offset + 2 + i);
} //not null-terminated } //not null-terminated
} }
@ -648,6 +659,9 @@ namespace MP4 {
} }
void AVCC::setPPS(std::string newPPS, size_t index) { void AVCC::setPPS(std::string newPPS, size_t index) {
setPPS(newPPS.data(), newPPS.size(), index);
}
void AVCC::setPPS(const char * data, size_t len, size_t index) {
if (index >= getPPSCount()){ if (index >= getPPSCount()){
WARN_MSG("Cannot set entry at position %zu/%u: Out of bounds", index, getPPSCount()); WARN_MSG("Cannot set entry at position %zu/%u: Out of bounds", index, getPPSCount());
} }
@ -655,9 +669,9 @@ namespace MP4 {
for (size_t i = 0; i < index; i++){ for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2; offset += getInt16(offset) + 2;
} }
setInt16(newPPS.size(), offset); setInt16(len, offset);
for (unsigned int i = 0; i < newPPS.size(); i++) { for (unsigned int i = 0; i < len; i++) {
setInt8(newPPS[i], offset + 2 + i); setInt8(data[i], offset + 2 + i);
} //not null-terminated } //not null-terminated
} }
@ -742,11 +756,90 @@ namespace MP4 {
} }
void AVCC::setPayload(std::string newPayload) { void AVCC::setPayload(std::string newPayload) {
if (!reserve(0, payloadSize(), newPayload.size())) { setPayload(newPayload.data(), newPayload.size());
}
void AVCC::setPayload(const char * data, size_t len){
if (!reserve(0, payloadSize(), len)){
ERROR_MSG("Cannot allocate enough memory for payload"); ERROR_MSG("Cannot allocate enough memory for payload");
return; return;
} }
memcpy((char *)payload(), (char *)newPayload.c_str(), newPayload.size()); memcpy((char *)payload(), (char *)data, len);
}
bool AVCC::sanitize(){
bool needSanitization = false;
size_t count = getSPSCount();
for (size_t i = 0; i < count; i++){
char * sps = getSPS(i);
if (memcmp("\000\000\000\001", sps, 4) == 0 || memcmp("\000\000\001", sps, 3)){
needSanitization = true;
break;
}
}
if (!needSanitization){
count = getPPSCount();
for (size_t i = 0; i < count; i++){
char * pps = getPPS(i);
if (memcmp("\000\000\000\001", pps, 4) == 0 || memcmp("\000\000\001", pps, 3)){
needSanitization = true;
break;
}
}
}
if (!needSanitization){return false;}
AVCC sanitized;
sanitized.setVersion(getVersion());
sanitized.setProfile(getProfile());
sanitized.setCompatibleProfiles(getCompatibleProfiles());
sanitized.setLevel(getLevel());
count = getSPSCount();
sanitized.setSPSCount(count);
for (size_t i = 0; i < count; i++){
char * sps = getSPS(i);
size_t len = getSPSLen(i);
bool modded = true;
while (modded){
modded = false;
if (memcmp("\000\000\001", sps, 3) == 0){
modded = true;
len -= 3;
sps += 3;
}
if (memcmp("\000\000\000\001", sps, 4) == 0){
modded = true;
len -= 4;
sps += 4;
}
}
sanitized.setSPS(sps, len, i);
}
count = getPPSCount();
sanitized.setPPSCount(count);
for (size_t i = 0; i < count; i++){
char * pps = getPPS(i);
size_t len = getPPSLen(i);
bool modded = true;
while (modded){
modded = false;
if (memcmp("\000\000\001", pps, 3) == 0){
modded = true;
len -= 3;
pps += 3;
}
if (memcmp("\000\000\000\001", pps, 4) == 0){
modded = true;
len -= 4;
pps += 4;
}
}
sanitized.setPPS(pps, len, i);
}
clear();
memcpy(data + 4, "avcC", 4);
setInt8(0xFF, 4); //reserved + 4-bytes NAL length
setPayload(sanitized.payload(), sanitized.payloadSize());
return true;
} }
HVCC::HVCC() { HVCC::HVCC() {
@ -2692,13 +2785,17 @@ namespace MP4 {
r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
r << std::string(indent + 2, ' ') << "[";
for (unsigned int i = 0; i < getEntryCount(); i++) { for (unsigned int i = 0; i < getEntryCount(); i++) {
static STTSEntry temp; static STTSEntry temp;
temp = getSTTSEntry(i); temp = getSTTSEntry(i);
r << std::string(indent + 1, ' ') << "Entry[" << i << "]: " << temp.sampleCount << " sample(s) of " << temp.sampleDelta << "ms each" << std::endl; r << "(" << temp.sampleCount << " x " << temp.sampleDelta << "ms)";
if (i < getEntryCount() - 1){
r << ", ";
} }
}
r << "]" << std::endl;
return r.str(); return r.str();
} }
CTTS::CTTS() { CTTS::CTTS() {
@ -2742,13 +2839,16 @@ namespace MP4 {
r << std::string(indent, ' ') << "[ctts] Composition Time To Sample Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[ctts] Composition Time To Sample Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
r << std::string(indent + 2, ' ') << "[";
for (unsigned int i = 0; i < getEntryCount(); i++) { for (unsigned int i = 0; i < getEntryCount(); i++) {
static CTTSEntry temp; static CTTSEntry temp;
temp = getCTTSEntry(i); temp = getCTTSEntry(i);
r << std::string(indent + 1, ' ') << "Entry[" << i << "]:" << std::endl; r << "(" << temp.sampleCount << " x " << temp.sampleOffset << ")";
r << std::string(indent + 2, ' ') << "SampleCount: " << temp.sampleCount << std::endl; if (i < getEntryCount() - 1){
r << std::string(indent + 2, ' ') << "SampleOffset: " << temp.sampleOffset << std::endl; r << ", ";
} }
}
r << "]" << std::endl;
return r.str(); return r.str();
} }
@ -3081,10 +3181,10 @@ namespace MP4 {
return r.str(); return r.str();
} }
PASP::PASP() { PASP::PASP(uint32_t hSpacing, uint32_t vSpacing) {
memcpy(data + 4, "pasp", 4); memcpy(data + 4, "pasp", 4);
setHSpacing(1); setHSpacing(hSpacing);
setVSpacing(1); setVSpacing(vSpacing);
} }
void PASP::setHSpacing(uint32_t newVal) { void PASP::setHSpacing(uint32_t newVal) {
@ -3134,6 +3234,8 @@ namespace MP4 {
setCLAP(hvccBox); setCLAP(hvccBox);
} }
/*LTS-END*/ /*LTS-END*/
MP4::PASP paspBox;
setPASP(paspBox);
} }
void VisualSampleEntry::initialize(){ void VisualSampleEntry::initialize(){
@ -3238,12 +3340,61 @@ namespace MP4 {
} }
if (payloadSize() < 78 + getBoxLen(78) + 8) { if (payloadSize() < 78 + getBoxLen(78) + 8) {
return ret; return ret;
} else { }
return getBox(78 + getBoxLen(78)); return getBox(78 + getBoxLen(78));
} }
size_t VisualSampleEntry::getBoxEntryCount() {
if (payloadSize() < 84) { //if the EntryBox is not big enough to hold any box
return 0;
}
size_t count = 0;
size_t offset = 78;
while (offset < payloadSize()){
offset +=getBoxLen(offset);
count++;
}
return count;
} }
Box & VisualSampleEntry::getBoxEntry(size_t index){
static Box ret = Box((char *)"\000\000\000\010erro", false);
if (index >= getBoxEntryCount()){
return ret;
}
size_t count = 0;
size_t offset = 78;
while (offset < payloadSize()){
if (count == index){
return getBox(offset);
}
offset +=getBoxLen(offset);
count++;
}
return ret;
}
void VisualSampleEntry::setBoxEntry(size_t index, Box & box){
if (index > getBoxEntryCount()){
index = getBoxEntryCount();
WARN_MSG("This function can not leave empty spaces, appending at index %zu nstead!", index);
}
size_t count = 0;
size_t offset = 78;
while (offset < payloadSize()){
if (count == index){
setBox(box, offset);
return;
}
offset +=getBoxLen(offset);
count++;
}
if (count == index){
setBox(box, offset);
}else{
INFO_MSG("Should not be here! Index is %zu, count is %zu, offset is %zu, payloadSize is %zu", index, count, offset, payloadSize());
}
}
@ -3258,12 +3409,20 @@ namespace MP4 {
r << std::string(indent + 1, ' ') << "FrameCount: " << getFrameCount() << std::endl; r << std::string(indent + 1, ' ') << "FrameCount: " << getFrameCount() << std::endl;
r << std::string(indent + 1, ' ') << "CompressorName: " << getCompressorName() << std::endl; r << std::string(indent + 1, ' ') << "CompressorName: " << getCompressorName() << std::endl;
r << std::string(indent + 1, ' ') << "Depth: " << getDepth() << std::endl; r << std::string(indent + 1, ' ') << "Depth: " << getDepth() << std::endl;
r << std::string(indent + 1, ' ') << "Box Count: " << getBoxEntryCount() << std::endl;
if (!getCLAP().isType("erro")) { if (!getCLAP().isType("erro")) {
r << getCLAP().toPrettyString(indent + 1); r << getCLAP().toPrettyString(indent + 1);
} }
if (!getPASP().isType("erro")) { if (!getPASP().isType("erro")) {
r << getPASP().toPrettyString(indent + 1); r << getPASP().toPrettyString(indent + 1);
} }
if (getBoxEntryCount() > 2){
for (size_t index = 2; index < getBoxEntryCount(); ++index){
MP4::Box tmpBox = getBoxEntry(index);
r << tmpBox.toPrettyString(indent + 1);
}
}
return r.str(); return r.str();
} }

View file

@ -2,7 +2,7 @@
#include "mp4.h" #include "mp4.h"
namespace h265 { namespace h265 {
class metaInfo; struct metaInfo;
} }
namespace MP4 { namespace MP4 {
@ -79,6 +79,7 @@ namespace MP4 {
tfhdSampleSize = 0x000010, tfhdSampleSize = 0x000010,
tfhdSampleFlag = 0x000020, tfhdSampleFlag = 0x000020,
tfhdNoDuration = 0x010000, tfhdNoDuration = 0x010000,
tfhdBaseIsMoof = 0x020000,
}; };
class TFHD: public Box { class TFHD: public Box {
public: public:
@ -97,6 +98,7 @@ namespace MP4 {
uint32_t getDefaultSampleSize(); uint32_t getDefaultSampleSize();
void setDefaultSampleFlags(uint32_t newFlags); void setDefaultSampleFlags(uint32_t newFlags);
uint32_t getDefaultSampleFlags(); uint32_t getDefaultSampleFlags();
bool getDefaultBaseIsMoof();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
@ -116,6 +118,7 @@ namespace MP4 {
void setSPSCount(uint32_t _count); void setSPSCount(uint32_t _count);
uint32_t getSPSCount(); uint32_t getSPSCount();
void setSPS(std::string newSPS, size_t index = 0); void setSPS(std::string newSPS, size_t index = 0);
void setSPS(const char * data, size_t len, size_t index = 0);
uint32_t getSPSLen(size_t index = 0); uint32_t getSPSLen(size_t index = 0);
char * getSPS(size_t index = 0); char * getSPS(size_t index = 0);
std::string hexSPS(size_t index = 0); std::string hexSPS(size_t index = 0);
@ -124,12 +127,17 @@ namespace MP4 {
void setPPSCount(uint32_t _count); void setPPSCount(uint32_t _count);
uint32_t getPPSCount(); uint32_t getPPSCount();
void setPPS(std::string newPPS, size_t index = 0); void setPPS(std::string newPPS, size_t index = 0);
void setPPS(const char * data, size_t len, size_t index = 0);
uint32_t getPPSLen(size_t index = 0); uint32_t getPPSLen(size_t index = 0);
char * getPPS(size_t index = 0); char * getPPS(size_t index = 0);
void multiplyPPS(size_t newAmount); void multiplyPPS(size_t newAmount);
std::string hexPPS(size_t index = 0); std::string hexPPS(size_t index = 0);
std::string asAnnexB(); std::string asAnnexB();
void setPayload(std::string newPayload); void setPayload(std::string newPayload);
void setPayload(const char * data, size_t len);
bool sanitize();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
@ -651,7 +659,7 @@ namespace MP4 {
class PASP: public Box { //PixelAspectRatioBox class PASP: public Box { //PixelAspectRatioBox
public: public:
PASP(); PASP(uint32_t hSpacing = 1, uint32_t vSpacing = 1);
void setHSpacing(uint32_t newVal); void setHSpacing(uint32_t newVal);
uint32_t getHSpacing(); uint32_t getHSpacing();
void setVSpacing(uint32_t newVal); void setVSpacing(uint32_t newVal);
@ -684,6 +692,11 @@ namespace MP4 {
void setCLAP(Box & clap); void setCLAP(Box & clap);
Box & getPASP(); Box & getPASP();
void setPASP(Box & pasp); void setPASP(Box & pasp);
size_t getBoxEntryCount();
Box & getBoxEntry(size_t index);
void setBoxEntry(size_t index, Box & box);
std::string toPrettyVisualString(uint32_t index = 0, std::string = ""); std::string toPrettyVisualString(uint32_t index = 0, std::string = "");
}; };

View file

@ -13,6 +13,7 @@ namespace Mpeg{
// samplerate is encoded in bits 0x0C of header[2]; // samplerate is encoded in bits 0x0C of header[2];
res.sampleRate = sampleRates[mpegVersion][((hdr[2] >> 2) & 0x03)] * 1000; res.sampleRate = sampleRates[mpegVersion][((hdr[2] >> 2) & 0x03)] * 1000;
res.channels = 2 - (hdr[3] >> 7); res.channels = 2 - (hdr[3] >> 7);
res.layer = 4 - (hdr[1] >> 1) & 0x03;
return res; return res;
} }
@ -44,7 +45,7 @@ namespace Mpeg{
return true; return true;
} }
if (hdr[3] == 0x00){// Picture header if (hdr[3] == 0x00){// Picture header
mpInfo.tempSeq = (((uint16_t)hdr[4]) << 2) || (hdr[5] >> 6); mpInfo.tempSeq = ((uint16_t)hdr[4] << 2) | (hdr[5] >> 6);
mpInfo.frameType = (hdr[5] & 0x38) >> 3; mpInfo.frameType = (hdr[5] & 0x38) >> 3;
return true; return true;
} }
@ -55,8 +56,8 @@ namespace Mpeg{
void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo){ void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo){
mpInfo.clear(); mpInfo.clear();
const char *offset = hdr; const char *offset = hdr;
char *maxData = (char*)hdr + len - 5; char *maxData = (char *)hdr + len - 5;
if (maxData - hdr > 250){maxData = (char*)hdr + 250;} if (maxData - hdr > 250){maxData = (char *)hdr + 250;}
while (offset < maxData){ while (offset < maxData){
if (offset[2] > 1){ if (offset[2] > 1){
// We have no zero in the third byte, so we need to skip at least 3 bytes forward // We have no zero in the third byte, so we need to skip at least 3 bytes forward

View file

@ -15,6 +15,7 @@ namespace Mpeg{
struct MP2Info{ struct MP2Info{
uint64_t sampleRate; uint64_t sampleRate;
uint8_t channels; uint8_t channels;
uint8_t layer;
}; };
MP2Info parseMP2Header(const std::string &hdr); MP2Info parseMP2Header(const std::string &hdr);
@ -40,5 +41,5 @@ namespace Mpeg{
bool parseMPEG2Header(const char *hdr, MPEG2Info &mpInfo); bool parseMPEG2Header(const char *hdr, MPEG2Info &mpInfo);
void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo); void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo);
MPEG2Info parseMPEG2Headers(const char *hdr, uint32_t len); MPEG2Info parseMPEG2Headers(const char *hdr, uint32_t len);
} }// namespace Mpeg

View file

@ -14,7 +14,7 @@ namespace nalu{
std::deque<int> parseNalSizes(DTSC::Packet &pack){ std::deque<int> parseNalSizes(DTSC::Packet &pack){
std::deque<int> result; std::deque<int> result;
char *data; char *data;
unsigned int dataLen; size_t dataLen;
pack.getString("data", data, dataLen); pack.getString("data", data, dataLen);
int offset = 0; int offset = 0;
while (offset < dataLen){ while (offset < dataLen){
@ -30,9 +30,9 @@ namespace nalu{
result.resize(data.size()); result.resize(data.size());
result[0] = data[0]; result[0] = data[0];
result[1] = data[1]; result[1] = data[1];
unsigned int dataPtr = 2; size_t dataPtr = 2;
unsigned int dataLen = data.size(); size_t dataLen = data.size();
unsigned int resPtr = 2; size_t resPtr = 2;
while (dataPtr + 2 < dataLen){ while (dataPtr + 2 < dataLen){
if (!data[dataPtr] && !data[dataPtr + 1] && if (!data[dataPtr] && !data[dataPtr + 1] &&
data[dataPtr + 2] == 3){// We have found an emulation prevention data[dataPtr + 2] == 3){// We have found an emulation prevention

View file

@ -1,21 +1,21 @@
#pragma once #pragma once
#include <deque> #include "dtsc.h"
#include <string>
#include <cstdio> #include <cstdio>
#include <deque> #include <deque>
#include "dtsc.h" #include <string>
namespace nalu { namespace nalu{
struct nalData { struct nalData{
unsigned char nalType; uint8_t nalType;
unsigned long nalSize; size_t nalSize;
}; };
std::deque<int> parseNalSizes(DTSC::Packet & pack); std::deque<int> parseNalSizes(DTSC::Packet &pack);
std::string removeEmulationPrevention(const std::string & data); std::string removeEmulationPrevention(const std::string &data);
unsigned long toAnnexB(const char *data, unsigned long dataSize, char *&result);
unsigned long fromAnnexB(const char *data, unsigned long dataSize, char *&result);
const char *scanAnnexB(const char *data, uint32_t dataSize);
const char *nalEndPosition(const char *data, uint32_t dataSize);
}// namespace nalu
unsigned long toAnnexB(const char * data, unsigned long dataSize, char *& result);
unsigned long fromAnnexB(const char * data, unsigned long dataSize, char *& result);
const char* scanAnnexB(const char * data, uint32_t dataSize);
const char* nalEndPosition(const char * data, uint32_t dataSize);
}

View file

@ -113,7 +113,7 @@ namespace OGG {
return false; return false;
} }
if (newData.substr(0, 4) != "OggS"){ if (newData.substr(0, 4) != "OggS"){
DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered (magic number wrong: %s) - cannot continue", newData.c_str()); FAIL_MSG("Invalid Ogg page encountered (magic number wrong: %s) - cannot continue", newData.c_str());
return false; return false;
} }
memcpy(data, newData.c_str(), 27);//copying the header, always 27 bytes memcpy(data, newData.c_str(), 27);//copying the header, always 27 bytes
@ -154,7 +154,7 @@ namespace OGG {
return false; return false;
} }
if (std::string(data, 4) != "OggS"){ if (std::string(data, 4) != "OggS"){
DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered (magic number wrong: %s) - cannot continue bytePos %d", data, oriPos); FAIL_MSG("Invalid Ogg page encountered (magic number wrong: %s) - cannot continue bytePos %d", data, oriPos);
return false; return false;
} }
if (!fread(data + 27, getPageSegments(), 1, inFile)){ if (!fread(data + 27, getPageSegments(), 1, inFile)){
@ -167,10 +167,10 @@ namespace OGG {
if (*it){ if (*it){
char * thisSeg = (char *)malloc(*it * sizeof(char)); char * thisSeg = (char *)malloc(*it * sizeof(char));
if (!thisSeg){ if (!thisSeg){
DEBUG_MSG(DLVL_WARN, "malloc failed"); WARN_MSG("malloc failed");
} }
if (!fread(thisSeg, *it, 1, inFile)){ if (!fread(thisSeg, *it, 1, inFile)){
DEBUG_MSG(DLVL_WARN, "Unable to read a segment @ pos %d segment size: %d getPageSegments: %d", oriPos, *it, getPageSegments()); WARN_MSG("Unable to read a segment @ pos %d segment size: %d getPageSegments: %d", oriPos, *it, getPageSegments());
fseek(inFile, oriPos, SEEK_SET); fseek(inFile, oriPos, SEEK_SET);
return false; return false;
} }
@ -536,7 +536,7 @@ namespace OGG {
///\todo Rewrite this ///\todo Rewrite this
void Page::sendTo(Socket::Connection & destination, int calcGranule){ //combines all data and sends it to socket void Page::sendTo(Socket::Connection & destination, int calcGranule){ //combines all data and sends it to socket
if (!oggSegments.size()){ if (!oggSegments.size()){
DEBUG_MSG(DLVL_HIGH, "!segments.size()"); HIGH_MSG("!segments.size()");
return; return;
} }
if (codec == OGG::VORBIS){ if (codec == OGG::VORBIS){
@ -599,7 +599,7 @@ namespace OGG {
checksum = crc32(checksum, &tableSize, 1); //calculating the checksum over the segment Table Size checksum = crc32(checksum, &tableSize, 1); //calculating the checksum over the segment Table Size
checksum = crc32(checksum, table, tableSize);//calculating the checksum over the segment Table checksum = crc32(checksum, table, tableSize);//calculating the checksum over the segment Table
DEBUG_MSG(DLVL_DONTEVEN, "numSegments: %d", numSegments); DONTEVEN_MSG("numSegments: %d", numSegments);
for (unsigned int i = 0; i < numSegments; i++){ for (unsigned int i = 0; i < numSegments; i++){
//INFO_MSG("checksum, i: %d", i); //INFO_MSG("checksum, i: %d", i);

View file

@ -1,4 +1,5 @@
#include <string> #include <string>
#include <stdint.h>
namespace Opus{ namespace Opus{
uint16_t getPreSkip(const char * initData); uint16_t getPreSkip(const char * initData);

View file

@ -130,7 +130,7 @@ void Util::Procs::exit_handler() {
//send sigkill to all remaining //send sigkill to all remaining
if (!listcopy.empty()) { if (!listcopy.empty()) {
for (it = listcopy.begin(); it != listcopy.end(); it++) { for (it = listcopy.begin(); it != listcopy.end(); it++) {
DEBUG_MSG(DLVL_DEVEL, "SIGKILL %d", *it); INFO_MSG("SIGKILL %d", *it);
kill(*it, SIGKILL); kill(*it, SIGKILL);
} }
} }
@ -272,14 +272,13 @@ pid_t Util::Procs::StartPiped(std::deque<std::string> & argDeq, int * fdin, int
pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout, int * fderr) { pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout, int * fderr) {
pid_t pid; pid_t pid;
int pipein[2], pipeout[2], pipeerr[2]; int pipein[2], pipeout[2], pipeerr[2];
//DEBUG_MSG(DLVL_DEVEL, "setHandler");
setHandler(); setHandler();
if (fdin && *fdin == -1 && pipe(pipein) < 0) { if (fdin && *fdin == -1 && pipe(pipein) < 0) {
DEBUG_MSG(DLVL_ERROR, "stdin pipe creation failed for process %s, reason: %s", argv[0], strerror(errno)); ERROR_MSG("stdin pipe creation failed for process %s, reason: %s", argv[0], strerror(errno));
return 0; return 0;
} }
if (fdout && *fdout == -1 && pipe(pipeout) < 0) { if (fdout && *fdout == -1 && pipe(pipeout) < 0) {
DEBUG_MSG(DLVL_ERROR, "stdout pipe creation failed for process %s, reason: %s", argv[0], strerror(errno)); ERROR_MSG("stdout pipe creation failed for process %s, reason: %s", argv[0], strerror(errno));
if (*fdin == -1) { if (*fdin == -1) {
close(pipein[0]); close(pipein[0]);
close(pipein[1]); close(pipein[1]);
@ -287,7 +286,7 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
return 0; return 0;
} }
if (fderr && *fderr == -1 && pipe(pipeerr) < 0) { if (fderr && *fderr == -1 && pipe(pipeerr) < 0) {
DEBUG_MSG(DLVL_ERROR, "stderr pipe creation failed for process %s, reason: %s", argv[0], strerror(errno)); ERROR_MSG("stderr pipe creation failed for process %s, reason: %s", argv[0], strerror(errno));
if (*fdin == -1) { if (*fdin == -1) {
close(pipein[0]); close(pipein[0]);
close(pipein[1]); close(pipein[1]);
@ -302,7 +301,7 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
if (!fdin || !fdout || !fderr) { if (!fdin || !fdout || !fderr) {
devnull = open("/dev/null", O_RDWR); devnull = open("/dev/null", O_RDWR);
if (devnull == -1) { if (devnull == -1) {
DEBUG_MSG(DLVL_ERROR, "Could not open /dev/null for process %s, reason: %s", argv[0], strerror(errno)); ERROR_MSG("Could not open /dev/null for process %s, reason: %s", argv[0], strerror(errno));
if (*fdin == -1) { if (*fdin == -1) {
close(pipein[0]); close(pipein[0]);
close(pipein[1]); close(pipein[1]);
@ -365,10 +364,10 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
} }
//Because execvp requires a char* const* and we have a const char* const* //Because execvp requires a char* const* and we have a const char* const*
execvp(argv[0], (char* const*)argv); execvp(argv[0], (char* const*)argv);
DEBUG_MSG(DLVL_ERROR, "execvp failed for process %s, reason: %s", argv[0], strerror(errno)); ERROR_MSG("execvp failed for process %s, reason: %s", argv[0], strerror(errno));
exit(42); exit(42);
} else if (pid == -1) { } else if (pid == -1) {
DEBUG_MSG(DLVL_ERROR, "fork failed for process %s, reason: %s", argv[0], strerror(errno)); ERROR_MSG("fork failed for process %s, reason: %s", argv[0], strerror(errno));
if (fdin && *fdin == -1) { if (fdin && *fdin == -1) {
close(pipein[0]); close(pipein[0]);
close(pipein[1]); close(pipein[1]);
@ -390,7 +389,7 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
plist.insert(pid); plist.insert(pid);
} }
DEBUG_MSG(DLVL_HIGH, "Piped process %s started, PID %d", argv[0], pid); HIGH_MSG("Piped process %s started, PID %d", argv[0], pid);
if (devnull != -1) { if (devnull != -1) {
close(devnull); close(devnull);
} }

View file

@ -5,7 +5,7 @@ namespace RIFF{
Chunk::Chunk(const void *_p, uint32_t len){ Chunk::Chunk(const void *_p, uint32_t len){
p = (const char *)_p; p = (const char *)_p;
if (len && len < getPayloadSize() + 8){ if (len && len < getPayloadSize() + 8){
FAIL_MSG("Chunk %s (%lub) does not fit in %lu bytes length!", getType().c_str(), FAIL_MSG("Chunk %s (%" PRIu32 "b) does not fit in %" PRIu32 " bytes length!", getType().c_str(),
getPayloadSize() + 8, len); getPayloadSize() + 8, len);
p = 0; p = 0;
} }

View file

@ -2,22 +2,22 @@
/// Holds all code for the RTMPStream namespace. /// Holds all code for the RTMPStream namespace.
#include "rtmpchunks.h" #include "rtmpchunks.h"
#include "auth.h"
#include "defines.h" #include "defines.h"
#include "flv_tag.h" #include "flv_tag.h"
#include "timing.h" #include "timing.h"
#include "auth.h"
std::string RTMPStream::handshake_in; ///< Input for the handshake. std::string RTMPStream::handshake_in; ///< Input for the handshake.
std::string RTMPStream::handshake_out; ///< Output for the handshake. std::string RTMPStream::handshake_out; ///< Output for the handshake.
unsigned int RTMPStream::chunk_rec_max = 128; size_t RTMPStream::chunk_rec_max = 128;
unsigned int RTMPStream::chunk_snd_max = 128; size_t RTMPStream::chunk_snd_max = 128;
unsigned int RTMPStream::rec_window_size = 2500000; size_t RTMPStream::rec_window_size = 2500000;
unsigned int RTMPStream::snd_window_size = 2500000; size_t RTMPStream::snd_window_size = 2500000;
unsigned int RTMPStream::rec_window_at = 0; size_t RTMPStream::rec_window_at = 0;
unsigned int RTMPStream::snd_window_at = 0; size_t RTMPStream::snd_window_at = 0;
unsigned int RTMPStream::rec_cnt = 0; size_t RTMPStream::rec_cnt = 0;
unsigned int RTMPStream::snd_cnt = 0; size_t RTMPStream::snd_cnt = 0;
timeval RTMPStream::lastrec; timeval RTMPStream::lastrec;
@ -27,93 +27,97 @@ std::map<unsigned int, RTMPStream::Chunk> RTMPStream::lastsend;
std::map<unsigned int, RTMPStream::Chunk> RTMPStream::lastrecv; std::map<unsigned int, RTMPStream::Chunk> RTMPStream::lastrecv;
#define P1024 \ #define P1024 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ "DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7" \
"ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
char genuineFMSKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, char genuineFMSKey[] ={
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46,
0x6c, 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72,
0x76, // Genuine Adobe Flash Media Server 001 0x76, // Genuine Adobe Flash Media Server 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e,
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
}; // 68 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68
char genuineFPKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, char genuineFPKey[] ={
0x50, 0x6c, 0x61, 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65,
0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x50, 0x6c, 0x61,
0x79, // Genuine Adobe Flash Player 001 0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe,
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d,
}; // 62 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62
inline uint32_t GetDigestOffset(uint8_t * pBuffer, uint8_t scheme) { inline uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){
if (scheme == 0) { if (scheme == 0){
return ((pBuffer[8] + pBuffer[9] + pBuffer[10] + pBuffer[11]) % 728) + 12; return ((pBuffer[8] + pBuffer[9] + pBuffer[10] + pBuffer[11]) % 728) + 12;
} else { }else{
return ((pBuffer[772] + pBuffer[773] + pBuffer[774] + pBuffer[775]) % 728) + 776; return ((pBuffer[772] + pBuffer[773] + pBuffer[774] + pBuffer[775]) % 728) + 776;
} }
} }
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) { bool ValidateClientScheme(uint8_t *pBuffer, uint8_t scheme){
uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme); uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);
uint8_t pTempBuffer[1536-32]; uint8_t pTempBuffer[1536 - 32];
memcpy(pTempBuffer, pBuffer, clientDigestOffset); memcpy(pTempBuffer, pBuffer, clientDigestOffset);
memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32); memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32,
1536 - clientDigestOffset - 32);
char pTempHash[32]; char pTempHash[32];
Secure::hmac_sha256bin((char*)pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); Secure::hmac_sha256bin((char *)pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0); bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result ? "success" : "failed"); MEDIUM_MSG("Client scheme validation %hhi %s", scheme, result ? "success" : "failed");
return result; return result;
} }
/// Packs up the chunk for sending over the network. /// Packs up the chunk for sending over the network.
/// \warning Do not call if you are not actually sending the resulting data! /// \warning Do not call if you are not actually sending the resulting data!
/// \returns A std::string ready to be sent. /// \returns A std::string ready to be sent.
std::string & RTMPStream::Chunk::Pack() { std::string &RTMPStream::Chunk::Pack(){
static std::string output; static std::string output;
output.clear(); output.clear();
bool allow_short = lastsend.count(cs_id); bool allow_short = lastsend.count(cs_id);
RTMPStream::Chunk prev = lastsend[cs_id]; RTMPStream::Chunk prev = lastsend[cs_id];
unsigned int tmpi; unsigned int tmpi;
unsigned char chtype = 0x00; unsigned char chtype = 0x00;
if (allow_short && (prev.cs_id == cs_id)) { if (allow_short && (prev.cs_id == cs_id)){
if (msg_stream_id == prev.msg_stream_id) { if (msg_stream_id == prev.msg_stream_id){
chtype = 0x40; //do not send msg_stream_id chtype = 0x40; // do not send msg_stream_id
if (len == prev.len) { if (len == prev.len){
if (msg_type_id == prev.msg_type_id) { if (msg_type_id == prev.msg_type_id){
chtype = 0x80; //do not send len and msg_type_id chtype = 0x80; // do not send len and msg_type_id
if (timestamp - prev.timestamp == prev.ts_delta) { if (timestamp - prev.timestamp == prev.ts_delta){
chtype = 0xC0; //do not send timestamp chtype = 0xC0; // do not send timestamp
} }
} }
} }
} }
//override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel // override - we always sent type 0x00 if the timestamp has decreased since last chunk in this
if (timestamp < prev.timestamp) { // channel
chtype = 0x00; if (timestamp < prev.timestamp){chtype = 0x00;}
} }
} if (cs_id <= 63){
if (cs_id <= 63) {
output += (unsigned char)(chtype | cs_id); output += (unsigned char)(chtype | cs_id);
} else { }else{
if (cs_id <= 255 + 64) { if (cs_id <= 255 + 64){
output += (unsigned char)(chtype | 0); output += (unsigned char)(chtype | 0);
output += (unsigned char)(cs_id - 64); output += (unsigned char)(cs_id - 64);
} else { }else{
output += (unsigned char)(chtype | 1); output += (unsigned char)(chtype | 1);
output += (unsigned char)((cs_id - 64) % 256); output += (unsigned char)((cs_id - 64) % 256);
output += (unsigned char)((cs_id - 64) / 256); output += (unsigned char)((cs_id - 64) / 256);
} }
} }
unsigned int ntime = 0; unsigned int ntime = 0;
if (chtype != 0xC0) { if (chtype != 0xC0){
//timestamp or timestamp diff // timestamp or timestamp diff
if (chtype == 0x00) { if (chtype == 0x00){
tmpi = timestamp; tmpi = timestamp;
} else { }else{
tmpi = timestamp - prev.timestamp; tmpi = timestamp - prev.timestamp;
} }
ts_delta = tmpi; ts_delta = tmpi;
if (tmpi >= 0x00ffffff) { if (tmpi >= 0x00ffffff){
ntime = tmpi; ntime = tmpi;
tmpi = 0x00ffffff; tmpi = 0x00ffffff;
} }
@ -121,16 +125,16 @@ std::string & RTMPStream::Chunk::Pack() {
output += (unsigned char)((tmpi >> 16) & 0xff); output += (unsigned char)((tmpi >> 16) & 0xff);
output += (unsigned char)((tmpi >> 8) & 0xff); output += (unsigned char)((tmpi >> 8) & 0xff);
output += (unsigned char)(tmpi & 0xff); output += (unsigned char)(tmpi & 0xff);
if (chtype != 0x80) { if (chtype != 0x80){
//len // len
tmpi = len; tmpi = len;
output += (unsigned char)((tmpi >> 16) & 0xff); output += (unsigned char)((tmpi >> 16) & 0xff);
output += (unsigned char)((tmpi >> 8) & 0xff); output += (unsigned char)((tmpi >> 8) & 0xff);
output += (unsigned char)(tmpi & 0xff); output += (unsigned char)(tmpi & 0xff);
//msg type id // msg type id
output += (unsigned char)msg_type_id; output += (unsigned char)msg_type_id;
if (chtype != 0x40) { if (chtype != 0x40){
//msg stream id // msg stream id
output += (unsigned char)(msg_stream_id % 256); output += (unsigned char)(msg_stream_id % 256);
output += (unsigned char)(msg_stream_id / 256); output += (unsigned char)(msg_stream_id / 256);
output += (unsigned char)(msg_stream_id / (256 * 256)); output += (unsigned char)(msg_stream_id / (256 * 256));
@ -139,39 +143,35 @@ std::string & RTMPStream::Chunk::Pack() {
} }
}else{ }else{
ts_header = prev.ts_header; ts_header = prev.ts_header;
if (ts_header == 0xffffff){ if (ts_header == 0xffffff){ntime = timestamp;}
ntime = timestamp;
} }
} // support for 0x00ffffff timestamps
//support for 0x00ffffff timestamps if (ntime){
if (ntime) {
output += (unsigned char)((ntime >> 24) & 0xff); output += (unsigned char)((ntime >> 24) & 0xff);
output += (unsigned char)((ntime >> 16) & 0xff); output += (unsigned char)((ntime >> 16) & 0xff);
output += (unsigned char)((ntime >> 8) & 0xff); output += (unsigned char)((ntime >> 8) & 0xff);
output += (unsigned char)(ntime & 0xff); output += (unsigned char)(ntime & 0xff);
} }
len_left = 0; len_left = 0;
while (len_left < len) { while (len_left < len){
tmpi = len - len_left; tmpi = len - len_left;
if (tmpi > RTMPStream::chunk_snd_max) { if (tmpi > RTMPStream::chunk_snd_max){tmpi = RTMPStream::chunk_snd_max;}
tmpi = RTMPStream::chunk_snd_max;
}
output.append(data, len_left, tmpi); output.append(data, len_left, tmpi);
len_left += tmpi; len_left += tmpi;
if (len_left < len) { if (len_left < len){
if (cs_id <= 63) { if (cs_id <= 63){
output += (unsigned char)(0xC0 + cs_id); output += (unsigned char)(0xC0 + cs_id);
} else { }else{
if (cs_id <= 255 + 64) { if (cs_id <= 255 + 64){
output += (unsigned char)(0xC0); output += (unsigned char)(0xC0);
output += (unsigned char)(cs_id - 64); output += (unsigned char)(cs_id - 64);
} else { }else{
output += (unsigned char)(0xC1); output += (unsigned char)(0xC1);
output += (unsigned char)((cs_id - 64) % 256); output += (unsigned char)((cs_id - 64) % 256);
output += (unsigned char)((cs_id - 64) / 256); output += (unsigned char)((cs_id - 64) / 256);
} }
} }
if (ntime) { if (ntime){
output += (unsigned char)((ntime >> 24) & 0xff); output += (unsigned char)((ntime >> 24) & 0xff);
output += (unsigned char)((ntime >> 16) & 0xff); output += (unsigned char)((ntime >> 16) & 0xff);
output += (unsigned char)((ntime >> 8) & 0xff); output += (unsigned char)((ntime >> 8) & 0xff);
@ -182,10 +182,10 @@ std::string & RTMPStream::Chunk::Pack() {
lastsend[cs_id] = *this; lastsend[cs_id] = *this;
RTMPStream::snd_cnt += output.size(); RTMPStream::snd_cnt += output.size();
return output; return output;
} //SendChunk }// SendChunk
/// Default constructor, creates an empty chunk with all values initialized to zero. /// Default constructor, creates an empty chunk with all values initialized to zero.
RTMPStream::Chunk::Chunk() { RTMPStream::Chunk::Chunk(){
headertype = 0; headertype = 0;
cs_id = 0; cs_id = 0;
timestamp = 0; timestamp = 0;
@ -195,10 +195,11 @@ RTMPStream::Chunk::Chunk() {
msg_type_id = 0; msg_type_id = 0;
msg_stream_id = 0; msg_stream_id = 0;
data = ""; data = "";
} //constructor }// constructor
/// Packs up a chunk with the given arguments as properties. /// Packs up a chunk with the given arguments as properties.
std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data) { std::string &RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id,
unsigned int msg_stream_id, std::string data){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
ch.cs_id = cs_id; ch.cs_id = cs_id;
ch.timestamp = 0; ch.timestamp = 0;
@ -209,14 +210,15 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i
ch.msg_stream_id = msg_stream_id; ch.msg_stream_id = msg_stream_id;
ch.data = data; ch.data = data;
return ch.Pack(); return ch.Pack();
} //constructor }// constructor
/// Packs up a chunk with media contents. /// Packs up a chunk with media contents.
/// \param msg_type_id Type number of the media, as per FLV standard. /// \param msg_type_id Type number of the media, as per FLV standard.
/// \param data Contents of the media data. /// \param data Contents of the media data.
/// \param len Length of the media data, in bytes. /// \param len Length of the media data, in bytes.
/// \param ts Timestamp of the media data, relative to current system time. /// \param ts Timestamp of the media data, relative to current system time.
std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts) { std::string &RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char *data, int len,
unsigned int ts){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
ch.cs_id = msg_type_id + 42; ch.cs_id = msg_type_id + 42;
ch.timestamp = ts; ch.timestamp = ts;
@ -227,16 +229,16 @@ std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * d
ch.msg_stream_id = 1; ch.msg_stream_id = 1;
ch.data = std::string((char *)data, (size_t)len); ch.data = std::string((char *)data, (size_t)len);
return ch.Pack(); return ch.Pack();
} //SendMedia }// SendMedia
/// Packs up a chunk with media contents. /// Packs up a chunk with media contents.
/// \param tag FLV::Tag with media to send. /// \param tag FLV::Tag with media to send.
std::string & RTMPStream::SendMedia(FLV::Tag & tag) { std::string &RTMPStream::SendMedia(FLV::Tag &tag){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
//Commented bit is more efficient and correct according to RTMP spec. // Commented bit is more efficient and correct according to RTMP spec.
//Simply passing "4" is the only thing that actually plays correctly, though. // Simply passing "4" is the only thing that actually plays correctly, though.
//Adobe, if you're ever reading this... wtf? Seriously. // Adobe, if you're ever reading this... wtf? Seriously.
ch.cs_id = 4;//((unsigned char)tag.data[0]); ch.cs_id = 4; //((unsigned char)tag.data[0]);
ch.timestamp = tag.tagTime(); ch.timestamp = tag.tagTime();
ch.len_left = 0; ch.len_left = 0;
ch.msg_type_id = (unsigned char)tag.data[0]; ch.msg_type_id = (unsigned char)tag.data[0];
@ -245,10 +247,10 @@ std::string & RTMPStream::SendMedia(FLV::Tag & tag) {
ch.len = ch.data.size(); ch.len = ch.data.size();
ch.real_len = ch.len; ch.real_len = ch.len;
return ch.Pack(); return ch.Pack();
} //SendMedia }// SendMedia
/// Packs up a chunk for a control message with 1 argument. /// Packs up a chunk for a control message with 1 argument.
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data) { std::string &RTMPStream::SendCTL(unsigned char type, unsigned int data){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
ch.cs_id = 2; ch.cs_id = 2;
ch.timestamp = Util::getMS(); ch.timestamp = Util::getMS();
@ -259,7 +261,7 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data) {
ch.len = 5; ch.len = 5;
ch.real_len = 5; ch.real_len = 5;
ch.data.resize(5); ch.data.resize(5);
((char*)ch.data.data())[4] = 0; ((char *)ch.data.data())[4] = 0;
}else{ }else{
ch.len = 4; ch.len = 4;
ch.real_len = 4; ch.real_len = 4;
@ -267,10 +269,10 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data) {
} }
*(int *)((char *)ch.data.data()) = htonl(data); *(int *)((char *)ch.data.data()) = htonl(data);
return ch.Pack(); return ch.Pack();
} //SendCTL }// SendCTL
/// Packs up a chunk for a control message with 2 arguments. /// Packs up a chunk for a control message with 2 arguments.
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2) { std::string &RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
ch.cs_id = 2; ch.cs_id = 2;
ch.timestamp = Util::getMS(); ch.timestamp = Util::getMS();
@ -283,10 +285,10 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigne
*(unsigned int *)((char *)ch.data.c_str()) = htonl(data); *(unsigned int *)((char *)ch.data.c_str()) = htonl(data);
ch.data[4] = data2; ch.data[4] = data2;
return ch.Pack(); return ch.Pack();
} //SendCTL }// SendCTL
/// Packs up a chunk for a user control message with 1 argument. /// Packs up a chunk for a user control message with 1 argument.
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data) { std::string &RTMPStream::SendUSR(unsigned char type, unsigned int data){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
ch.cs_id = 2; ch.cs_id = 2;
ch.timestamp = Util::getMS(); ch.timestamp = Util::getMS();
@ -300,10 +302,10 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data) {
ch.data[0] = 0; ch.data[0] = 0;
ch.data[1] = type; ch.data[1] = type;
return ch.Pack(); return ch.Pack();
} //SendUSR }// SendUSR
/// Packs up a chunk for a user control message with 2 arguments. /// Packs up a chunk for a user control message with 2 arguments.
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2) { std::string &RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2){
static RTMPStream::Chunk ch; static RTMPStream::Chunk ch;
ch.cs_id = 2; ch.cs_id = 2;
ch.timestamp = Util::getMS(); ch.timestamp = Util::getMS();
@ -318,7 +320,7 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
ch.data[0] = 0; ch.data[0] = 0;
ch.data[1] = type; ch.data[1] = type;
return ch.Pack(); return ch.Pack();
} //SendUSR }// SendUSR
/// Parses the argument Socket::Buffer into the current chunk. /// Parses the argument Socket::Buffer into the current chunk.
/// Tries to read a whole chunk, removing data from the Buffer as it reads. /// Tries to read a whole chunk, removing data from the Buffer as it reads.
@ -328,94 +330,79 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
/// \param buffer The input to parse and update. /// \param buffer The input to parse and update.
/// \warning This function will destroy the current data in this chunk! /// \warning This function will destroy the current data in this chunk!
/// \returns True if a whole chunk could be read, false otherwise. /// \returns True if a whole chunk could be read, false otherwise.
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer) { bool RTMPStream::Chunk::Parse(Socket::Buffer &buffer){
gettimeofday(&RTMPStream::lastrec, 0); gettimeofday(&RTMPStream::lastrec, 0);
unsigned int i = 0; unsigned int i = 0;
if (!buffer.available(3)) { if (!buffer.available(3)){return false;}// we want at least 3 bytes
return false;
} //we want at least 3 bytes
std::string indata = buffer.copy(3); std::string indata = buffer.copy(3);
unsigned char chunktype = indata[i++ ]; unsigned char chunktype = indata[i++];
//read the chunkstream ID properly // read the chunkstream ID properly
switch (chunktype & 0x3F) { switch (chunktype & 0x3F){
case 0: case 0: cs_id = indata[i++] + 64; break;
cs_id = indata[i++ ] + 64;
break;
case 1: case 1:
cs_id = indata[i++ ] + 64; cs_id = indata[i++] + 64;
cs_id += indata[i++ ] * 256; cs_id += indata[i++] * 256;
break;
default:
cs_id = chunktype & 0x3F;
break; break;
default: cs_id = chunktype & 0x3F; break;
} }
bool allow_short = lastrecv.count(cs_id); bool allow_short = lastrecv.count(cs_id);
RTMPStream::Chunk prev = lastrecv[cs_id]; RTMPStream::Chunk prev = lastrecv[cs_id];
//process the rest of the header, for each chunk type // process the rest of the header, for each chunk type
headertype = chunktype & 0xC0; headertype = chunktype & 0xC0;
DEBUG_MSG(DLVL_DONTEVEN, "Parsing RTMP chunk header (%#.2hhX) at offset %#X", chunktype, RTMPStream::rec_cnt); DONTEVEN_MSG("Parsing RTMP chunk header (%#.2hhX) at offset %#zx", chunktype,
RTMPStream::rec_cnt);
switch (headertype) { switch (headertype){
case 0x00: case 0x00:
if (!buffer.available(i + 11)) { if (!buffer.available(i + 11)){return false;}// can't read whole header
return false;
} //can't read whole header
indata = buffer.copy(i + 11); indata = buffer.copy(i + 11);
timestamp = indata[i++ ] * 256 * 256; timestamp = indata[i++] * 256 * 256;
timestamp += indata[i++ ] * 256; timestamp += indata[i++] * 256;
timestamp += indata[i++ ]; timestamp += indata[i++];
ts_delta = timestamp; ts_delta = timestamp;
ts_header = timestamp; ts_header = timestamp;
len = indata[i++ ] * 256 * 256; len = indata[i++] * 256 * 256;
len += indata[i++ ] * 256; len += indata[i++] * 256;
len += indata[i++ ]; len += indata[i++];
len_left = 0; len_left = 0;
msg_type_id = indata[i++ ]; msg_type_id = indata[i++];
msg_stream_id = indata[i++ ]; msg_stream_id = indata[i++];
msg_stream_id += indata[i++ ] * 256; msg_stream_id += indata[i++] * 256;
msg_stream_id += indata[i++ ] * 256 * 256; msg_stream_id += indata[i++] * 256 * 256;
msg_stream_id += indata[i++ ] * 256 * 256 * 256; msg_stream_id += indata[i++] * 256 * 256 * 256;
break; break;
case 0x40: case 0x40:
if (!buffer.available(i + 7)) { if (!buffer.available(i + 7)){return false;}// can't read whole header
return false;
} //can't read whole header
indata = buffer.copy(i + 7); indata = buffer.copy(i + 7);
if (!allow_short) { if (!allow_short){WARN_MSG("Warning: Header type 0x40 with no valid previous chunk!");}
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!"); timestamp = indata[i++] * 256 * 256;
} timestamp += indata[i++] * 256;
timestamp = indata[i++ ] * 256 * 256; timestamp += indata[i++];
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
ts_header = timestamp; ts_header = timestamp;
if (timestamp != 0x00ffffff) { if (timestamp != 0x00ffffff){
ts_delta = timestamp; ts_delta = timestamp;
timestamp = prev.timestamp + ts_delta; timestamp = prev.timestamp + ts_delta;
} }
len = indata[i++ ] * 256 * 256; len = indata[i++] * 256 * 256;
len += indata[i++ ] * 256; len += indata[i++] * 256;
len += indata[i++ ]; len += indata[i++];
len_left = 0; len_left = 0;
msg_type_id = indata[i++ ]; msg_type_id = indata[i++];
msg_stream_id = prev.msg_stream_id; msg_stream_id = prev.msg_stream_id;
break; break;
case 0x80: case 0x80:
if (!buffer.available(i + 3)) { if (!buffer.available(i + 3)){return false;}// can't read whole header
return false;
} //can't read whole header
indata = buffer.copy(i + 3); indata = buffer.copy(i + 3);
if (!allow_short) { if (!allow_short){WARN_MSG("Warning: Header type 0x80 with no valid previous chunk!");}
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!"); timestamp = indata[i++] * 256 * 256;
} timestamp += indata[i++] * 256;
timestamp = indata[i++ ] * 256 * 256; timestamp += indata[i++];
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
ts_header = timestamp; ts_header = timestamp;
if (timestamp != 0x00ffffff) { if (timestamp != 0x00ffffff){
ts_delta = timestamp; ts_delta = timestamp;
timestamp = prev.timestamp + ts_delta; timestamp = prev.timestamp + ts_delta;
} }
@ -425,128 +412,122 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer) {
msg_stream_id = prev.msg_stream_id; msg_stream_id = prev.msg_stream_id;
break; break;
case 0xC0: case 0xC0:
if (!allow_short) { if (!allow_short){WARN_MSG("Warning: Header type 0xC0 with no valid previous chunk!");}
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
}
timestamp = prev.timestamp + prev.ts_delta; timestamp = prev.timestamp + prev.ts_delta;
ts_header = prev.ts_header; ts_header = prev.ts_header;
ts_delta = prev.ts_delta; ts_delta = prev.ts_delta;
len = prev.len; len = prev.len;
len_left = prev.len_left; len_left = prev.len_left;
if (len_left > 0){ if (len_left > 0){timestamp = prev.timestamp;}
timestamp = prev.timestamp;
}
msg_type_id = prev.msg_type_id; msg_type_id = prev.msg_type_id;
msg_stream_id = prev.msg_stream_id; msg_stream_id = prev.msg_stream_id;
break; break;
} }
//calculate chunk length, real length, and length left till complete // calculate chunk length, real length, and length left till complete
if (len_left > 0) { if (len_left > 0){
real_len = len_left; real_len = len_left;
len_left -= real_len; len_left -= real_len;
} else { }else{
real_len = len; real_len = len;
} }
if (real_len > RTMPStream::chunk_rec_max) { if (real_len > RTMPStream::chunk_rec_max){
len_left += real_len - RTMPStream::chunk_rec_max; len_left += real_len - RTMPStream::chunk_rec_max;
real_len = RTMPStream::chunk_rec_max; real_len = RTMPStream::chunk_rec_max;
} }
DEBUG_MSG(DLVL_DONTEVEN, "Parsing RTMP chunk result: len_left=%d, real_len=%d", len_left, real_len); DONTEVEN_MSG("Parsing RTMP chunk result: len_left=%d, real_len=%d", len_left, real_len);
//read extended timestamp, if necessary // read extended timestamp, if necessary
if (ts_header == 0x00ffffff) { if (ts_header == 0x00ffffff){
if (!buffer.available(i + 4)) { if (!buffer.available(i + 4)){return false;}// can't read timestamp
return false;
} //can't read timestamp
indata = buffer.copy(i + 4); indata = buffer.copy(i + 4);
timestamp += indata[i++ ] * 256 * 256 * 256; timestamp += indata[i++] * 256 * 256 * 256;
timestamp += indata[i++ ] * 256 * 256; timestamp += indata[i++] * 256 * 256;
timestamp += indata[i++ ] * 256; timestamp += indata[i++] * 256;
timestamp = indata[i++ ]; timestamp = indata[i++];
ts_delta = timestamp; ts_delta = timestamp;
DEBUG_MSG(DLVL_DONTEVEN, "Extended timestamp: %u", timestamp); DONTEVEN_MSG("Extended timestamp: %u", timestamp);
} }
//read data if length > 0, and allocate it // read data if length > 0, and allocate it
if (real_len > 0) { if (real_len > 0){
if (!buffer.available(i + real_len)) { if (!buffer.available(i + real_len)){return false;}// can't read all data (yet)
return false; buffer.remove(i); // remove the header
} //can't read all data (yet) if (prev.len_left > 0){
buffer.remove(i); //remove the header data = prev.data + buffer.remove(real_len); // append the data and remove from buffer
if (prev.len_left > 0) { }else{
data = prev.data + buffer.remove(real_len); //append the data and remove from buffer data = buffer.remove(real_len); // append the data and remove from buffer
} else {
data = buffer.remove(real_len); //append the data and remove from buffer
} }
lastrecv[cs_id] = *this; lastrecv[cs_id] = *this;
RTMPStream::rec_cnt += i + real_len; RTMPStream::rec_cnt += i + real_len;
if (len_left == 0) { if (len_left == 0){
return true; return true;
} else { }else{
return Parse(buffer); return Parse(buffer);
} }
} else { }else{
buffer.remove(i); //remove the header buffer.remove(i); // remove the header
data = ""; data = "";
indata = indata.substr(i + real_len); indata = indata.substr(i + real_len);
lastrecv[cs_id] = *this; lastrecv[cs_id] = *this;
RTMPStream::rec_cnt += i + real_len; RTMPStream::rec_cnt += i + real_len;
return true; return true;
} }
} //Parse }// Parse
/// Does the handshake. Expects handshake_in to be filled, and fills handshake_out. /// Does the handshake. Expects handshake_in to be filled, and fills handshake_out.
/// After calling this function, don't forget to read and ignore 1536 extra bytes, /// After calling this function, don't forget to read and ignore 1536 extra bytes,
/// these are the handshake response and not interesting for us because we don't do client /// these are the handshake response and not interesting for us because we don't do client
/// verification. /// verification.
bool RTMPStream::doHandshake() { bool RTMPStream::doHandshake(){
char Version; char Version;
//Read C0 // Read C0
if (handshake_in.size() < 1537) { if (handshake_in.size() < 1537){
DEBUG_MSG(DLVL_FAIL, "Handshake wasn't filled properly (%lu/1537) - aborting!", handshake_in.size()); FAIL_MSG("Handshake wasn't filled properly (%lu/1537) - aborting!", handshake_in.size());
return false; return false;
} }
Version = RTMPStream::handshake_in[0]; Version = RTMPStream::handshake_in[0];
uint8_t * Client = (uint8_t *)RTMPStream::handshake_in.data() + 1; uint8_t *Client = (uint8_t *)RTMPStream::handshake_in.data() + 1;
RTMPStream::handshake_out.resize(3073); RTMPStream::handshake_out.resize(3073);
uint8_t * Server = (uint8_t *)RTMPStream::handshake_out.data() + 1; uint8_t *Server = (uint8_t *)RTMPStream::handshake_out.data() + 1;
RTMPStream::rec_cnt += 1537; RTMPStream::rec_cnt += 1537;
//Build S1 Packet // Build S1 Packet
*((uint32_t *)Server) = 0; //time zero *((uint32_t *)Server) = 0; // time zero
*(((uint32_t *)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4 *(((uint32_t *)(Server + 4))) = htonl(0x01020304); // version 1 2 3 4
for (int i = 8; i < 3072; ++i) { for (int i = 8; i < 3072; ++i){
Server[i] = FILLER_DATA[i % sizeof(FILLER_DATA)]; Server[i] = FILLER_DATA[i % sizeof(FILLER_DATA)];
} //"random" data }//"random" data
bool encrypted = (Version == 6); bool encrypted = (Version == 6);
DEBUG_MSG(DLVL_HIGH, "Handshake version is %hhi", Version); HIGH_MSG("Handshake version is %hhi", Version);
uint8_t _validationScheme = 5; uint8_t _validationScheme = 5;
if (ValidateClientScheme(Client, 0)) _validationScheme = 0; if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
if (ValidateClientScheme(Client, 1)) _validationScheme = 1; if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted ? "on" : "off"); HIGH_MSG("Handshake type is %hhi, encryption is %s", _validationScheme, encrypted ? "on" : "off");
uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme); uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme);
uint32_t keyChallengeIndex = GetDigestOffset(Client, _validationScheme); uint32_t keyChallengeIndex = GetDigestOffset(Client, _validationScheme);
//FIRST 1536 bytes for server response // FIRST 1536 bytes for server response
char pTempBuffer[1504]; char pTempBuffer[1504];
memcpy(pTempBuffer, Server, serverDigestOffset); memcpy(pTempBuffer, Server, serverDigestOffset);
memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1504 - serverDigestOffset); memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32,
Secure::hmac_sha256bin(pTempBuffer, 1504, genuineFMSKey, 36, (char*)Server + serverDigestOffset); 1504 - serverDigestOffset);
Secure::hmac_sha256bin(pTempBuffer, 1504, genuineFMSKey, 36, (char *)Server + serverDigestOffset);
//SECOND 1536 bytes for server response // SECOND 1536 bytes for server response
if (_validationScheme == 5 && Version == 3){ if (_validationScheme == 5 && Version == 3){
//copy exactly from client // copy exactly from client
memcpy(Server+1536, Client, 1536); memcpy(Server + 1536, Client, 1536);
}else{ }else{
char pTempHash[32]; char pTempHash[32];
Secure::hmac_sha256bin((char*)Client + keyChallengeIndex, 32, genuineFMSKey, 68, pTempHash); Secure::hmac_sha256bin((char *)Client + keyChallengeIndex, 32, genuineFMSKey, 68, pTempHash);
Secure::hmac_sha256bin((char*)Server + 1536, 1536 - 32, pTempHash, 32, (char*)Server + 1536 * 2 - 32); Secure::hmac_sha256bin((char *)Server + 1536, 1536 - 32, pTempHash, 32,
(char *)Server + 1536 * 2 - 32);
} }
Server[ -1] = Version; Server[-1] = Version;
RTMPStream::snd_cnt += 3073; RTMPStream::snd_cnt += 3073;
return true; return true;
} }

View file

@ -2,41 +2,54 @@
/// Holds all headers for the RTMPStream namespace. /// Holds all headers for the RTMPStream namespace.
#pragma once #pragma once
#include <map>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string>
#include <arpa/inet.h>
#include "socket.h" #include "socket.h"
#include <arpa/inet.h>
#include <map>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/time.h>
#ifndef FILLER_DATA #ifndef FILLER_DATA
#define FILLER_DATA "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo vulputate urna eu commodo. Cras tempor velit nec nulla placerat volutpat. Proin eleifend blandit quam sit amet suscipit. Pellentesque vitae tristique lorem. Maecenas facilisis consequat neque, vitae iaculis eros vulputate ut. Suspendisse ut arcu non eros vestibulum pulvinar id sed erat. Nam dictum tellus vel tellus rhoncus ut mollis tellus fermentum. Fusce volutpat consectetur ante, in mollis nisi euismod vulputate. Curabitur vitae facilisis ligula. Sed sed gravida dolor. Integer eu eros a dolor lobortis ullamcorper. Mauris interdum elit non neque interdum dictum. Suspendisse imperdiet eros sed sapien cursus pulvinar. Vestibulum ut dolor lectus, id commodo elit. Cras convallis varius leo eu porta. Duis luctus sapien nec dui adipiscing quis interdum nunc congue. Morbi pharetra aliquet mauris vitae tristique. Etiam feugiat sapien quis augue elementum id ultricies magna vulputate. Phasellus luctus, leo id egestas consequat, eros tortor commodo neque, vitae hendrerit nunc sem ut odio." #define FILLER_DATA \
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo vulputate urna eu " \
"commodo. Cras tempor velit nec nulla placerat volutpat. Proin eleifend blandit quam sit amet " \
"suscipit. Pellentesque vitae tristique lorem. Maecenas facilisis consequat neque, vitae " \
"iaculis eros vulputate ut. Suspendisse ut arcu non eros vestibulum pulvinar id sed erat. Nam " \
"dictum tellus vel tellus rhoncus ut mollis tellus fermentum. Fusce volutpat consectetur ante, " \
"in mollis nisi euismod vulputate. Curabitur vitae facilisis ligula. Sed sed gravida dolor. " \
"Integer eu eros a dolor lobortis ullamcorper. Mauris interdum elit non neque interdum dictum. " \
"Suspendisse imperdiet eros sed sapien cursus pulvinar. Vestibulum ut dolor lectus, id commodo " \
"elit. Cras convallis varius leo eu porta. Duis luctus sapien nec dui adipiscing quis interdum " \
"nunc congue. Morbi pharetra aliquet mauris vitae tristique. Etiam feugiat sapien quis augue " \
"elementum id ultricies magna vulputate. Phasellus luctus, leo id egestas consequat, eros " \
"tortor commodo neque, vitae hendrerit nunc sem ut odio."
#endif #endif
//forward declaration of FLV::Tag to avoid circular dependencies. // forward declaration of FLV::Tag to avoid circular dependencies.
namespace FLV { namespace FLV{
class Tag; class Tag;
} }
/// Contains all functions and classes needed for RTMP connections. /// Contains all functions and classes needed for RTMP connections.
namespace RTMPStream { namespace RTMPStream{
extern unsigned int chunk_rec_max; ///< Maximum size for a received chunk. extern size_t chunk_rec_max; ///< Maximum size for a received chunk.
extern unsigned int chunk_snd_max; ///< Maximum size for a sent chunk. extern size_t chunk_snd_max; ///< Maximum size for a sent chunk.
extern unsigned int rec_window_size; ///< Window size for receiving. extern size_t rec_window_size; ///< Window size for receiving.
extern unsigned int snd_window_size; ///< Window size for sending. extern size_t snd_window_size; ///< Window size for sending.
extern unsigned int rec_window_at; ///< Current position of the receiving window. extern size_t rec_window_at; ///< Current position of the receiving window.
extern unsigned int snd_window_at; ///< Current position of the sending window. extern size_t snd_window_at; ///< Current position of the sending window.
extern unsigned int rec_cnt; ///< Counter for total data received, in bytes. extern size_t rec_cnt; ///< Counter for total data received, in bytes.
extern unsigned int snd_cnt; ///< Counter for total data sent, in bytes. extern size_t snd_cnt; ///< Counter for total data sent, in bytes.
extern timeval lastrec; ///< Timestamp of last time data was received. extern timeval lastrec; ///< Timestamp of last time data was received.
/// Holds a single RTMP chunk, either send or receive direction. /// Holds a single RTMP chunk, either send or receive direction.
class Chunk { class Chunk{
public: public:
unsigned char headertype; ///< For input chunks, the type of header. This is calculated automatically for output chunks. unsigned char headertype; ///< For input chunks, the type of header. This is calculated
///< automatically for output chunks.
unsigned int cs_id; ///< ContentStream ID unsigned int cs_id; ///< ContentStream ID
unsigned int timestamp; ///< Timestamp of this chunk. unsigned int timestamp; ///< Timestamp of this chunk.
unsigned int ts_delta; ///< Last timestamp delta. unsigned int ts_delta; ///< Last timestamp delta.
@ -49,21 +62,22 @@ namespace RTMPStream {
std::string data; ///< Payload of chunk. std::string data; ///< Payload of chunk.
Chunk(); Chunk();
bool Parse(Socket::Buffer & data); bool Parse(Socket::Buffer &data);
std::string & Pack(); std::string &Pack();
}; };
//RTMPStream::Chunk // RTMPStream::Chunk
extern std::map<unsigned int, Chunk> lastsend; extern std::map<unsigned int, Chunk> lastsend;
extern std::map<unsigned int, Chunk> lastrecv; extern std::map<unsigned int, Chunk> lastrecv;
std::string & SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data); std::string &SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id,
std::string & SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts); std::string data);
std::string & SendMedia(FLV::Tag & tag); std::string &SendMedia(unsigned char msg_type_id, unsigned char *data, int len, unsigned int ts);
std::string & SendCTL(unsigned char type, unsigned int data); std::string &SendMedia(FLV::Tag &tag);
std::string & SendCTL(unsigned char type, unsigned int data, unsigned char data2); std::string &SendCTL(unsigned char type, unsigned int data);
std::string & SendUSR(unsigned char type, unsigned int data); std::string &SendCTL(unsigned char type, unsigned int data, unsigned char data2);
std::string & SendUSR(unsigned char type, unsigned int data, unsigned int data2); std::string &SendUSR(unsigned char type, unsigned int data);
std::string &SendUSR(unsigned char type, unsigned int data, unsigned int data2);
/// This value should be set to the first 1537 bytes received. /// This value should be set to the first 1537 bytes received.
extern std::string handshake_in; extern std::string handshake_in;
@ -71,4 +85,5 @@ namespace RTMPStream {
extern std::string handshake_out; extern std::string handshake_out;
/// Does the handshake. Expects handshake_in to be filled, and fills handshake_out. /// Does the handshake. Expects handshake_in to be filled, and fills handshake_out.
bool doHandshake(); bool doHandshake();
} //RTMPStream namespace }// namespace RTMPStream

View file

@ -40,53 +40,6 @@ namespace IPC {
} }
#endif #endif
/// Stores a long value of val in network order to the pointer p.
static void htobl(char * p, long val) {
p[0] = (val >> 24) & 0xFF;
p[1] = (val >> 16) & 0xFF;
p[2] = (val >> 8) & 0xFF;
p[3] = val & 0xFF;
}
/// Stores a short value of val in network order to the pointer p.
static void htobs(char * p, short val) {
p[0] = (val >> 8) & 0xFF;
p[1] = val & 0xFF;
}
/// Stores a long long value of val in network order to the pointer p.
static void htobll(char * p, long long val) {
p[0] = (val >> 56) & 0xFF;
p[1] = (val >> 48) & 0xFF;
p[2] = (val >> 40) & 0xFF;
p[3] = (val >> 32) & 0xFF;
p[4] = (val >> 24) & 0xFF;
p[5] = (val >> 16) & 0xFF;
p[6] = (val >> 8) & 0xFF;
p[7] = val & 0xFF;
}
/// Reads a long value of p in host order to val.
static void btohl(char * p, long & val) {
val = ((long)p[0] << 24) | ((long)p[1] << 16) | ((long)p[2] << 8) | p[3];
}
/// Reads a short value of p in host order to val.
static void btohs(char * p, unsigned short & val) {
val = ((short)p[0] << 8) | p[1];
}
/// Reads a long value of p in host order to val.
static void btohl(char * p, unsigned int & val) {
val = ((long)p[0] << 24) | ((long)p[1] << 16) | ((long)p[2] << 8) | p[3];
}
/// Reads a long long value of p in host order to val.
static void btohll(char * p, long long & val) {
val = ((long long)p[0] << 56) | ((long long)p[1] << 48) | ((long long)p[2] << 40) | ((long long)p[3] << 32) | ((long long)p[4] << 24) | ((long long)p[5] << 16) | ((long long)p[6] << 8) | p[7];
}
///\brief Empty semaphore constructor, clears all values ///\brief Empty semaphore constructor, clears all values
semaphore::semaphore() { semaphore::semaphore() {
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
@ -262,8 +215,8 @@ namespace IPC {
} }
#elif defined(__APPLE__) #elif defined(__APPLE__)
/// \todo (roxlu) test tryWaitOneSecond, shared_memory.cpp /// \todo (roxlu) test tryWaitOneSecond, shared_memory.cpp
long long unsigned int now = Util::getMicros(); uint64_t now = Util::getMicros();
long long unsigned int timeout = now + 1e6; uint64_t timeout = now + 1e6;
while (now < timeout) { while (now < timeout) {
if (0 == sem_trywait(mySem)) { if (0 == sem_trywait(mySem)) {
isLocked = true; isLocked = true;
@ -363,7 +316,7 @@ namespace IPC {
///\param len_ The size to make the page ///\param len_ The size to make the page
///\param master_ Whether to create or merely open the page ///\param master_ Whether to create or merely open the page
///\param autoBackoff When only opening the page, wait for it to appear or fail ///\param autoBackoff When only opening the page, wait for it to appear or fail
sharedPage::sharedPage(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { sharedPage::sharedPage(const std::string & name_, uint64_t len_, bool master_, bool autoBackoff) {
handle = 0; handle = 0;
len = 0; len = 0;
master = false; master = false;
@ -453,7 +406,7 @@ namespace IPC {
///\param len_ The size to make the page ///\param len_ The size to make the page
///\param master_ Whether to create or merely open the page ///\param master_ Whether to create or merely open the page
///\param autoBackoff When only opening the page, wait for it to appear or fail ///\param autoBackoff When only opening the page, wait for it to appear or fail
void sharedPage::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { void sharedPage::init(const std::string & name_, uint64_t len_, bool master_, bool autoBackoff) {
close(); close();
name = name_; name = name_;
len = len_; len = len_;
@ -486,9 +439,9 @@ namespace IPC {
} }
//Under cygwin, the extra 4 bytes contain the real size of the page. //Under cygwin, the extra 4 bytes contain the real size of the page.
if (master) { if (master) {
((unsigned int *)mapped)[0] = len_; Bit::htobl(mapped, len);
} else { } else {
len = ((unsigned int *)mapped)[0]; len = Bit::btohl(mapped);
} }
//Now shift by those 4 bytes. //Now shift by those 4 bytes.
mapped += 4; mapped += 4;
@ -496,7 +449,7 @@ namespace IPC {
handle = shm_open(name.c_str(), (master ? O_CREAT | O_EXCL : 0) | O_RDWR, ACCESSPERMS); handle = shm_open(name.c_str(), (master ? O_CREAT | O_EXCL : 0) | O_RDWR, ACCESSPERMS);
if (handle == -1) { if (handle == -1) {
if (master) { if (master) {
DEBUG_MSG(DLVL_HIGH, "Overwriting old page for %s", name.c_str()); ERROR_MSG("Overwriting old page for %s", name.c_str());
handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS); handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS);
} else { } else {
int i = 0; int i = 0;
@ -515,7 +468,7 @@ namespace IPC {
} }
if (master) { if (master) {
if (ftruncate(handle, len) < 0) { if (ftruncate(handle, len) < 0) {
FAIL_MSG("truncate to %lld for page %s failed: %s", len, name.c_str(), strerror(errno)); FAIL_MSG("truncate to %" PRIu64 " for page %s failed: %s", len, name.c_str(), strerror(errno));
return; return;
} }
} else { } else {
@ -547,7 +500,7 @@ namespace IPC {
///\param len_ The size to make the file ///\param len_ The size to make the file
///\param master_ Whether to create or merely open the file ///\param master_ Whether to create or merely open the file
///\param autoBackoff When only opening the file, wait for it to appear or fail ///\param autoBackoff When only opening the file, wait for it to appear or fail
sharedFile::sharedFile(std::string name_, unsigned int len_, bool master_, bool autoBackoff) : handle(0), name(name_), len(len_), master(master_), mapped(NULL) { sharedFile::sharedFile(const std::string & name_, uint64_t len_, bool master_, bool autoBackoff) : handle(0), name(name_), len(len_), master(master_), mapped(NULL) {
handle = 0; handle = 0;
name = name_; name = name_;
len = len_; len = len_;
@ -612,7 +565,7 @@ namespace IPC {
///\param len_ The size to make the page ///\param len_ The size to make the page
///\param master_ Whether to create or merely open the page ///\param master_ Whether to create or merely open the page
///\param autoBackoff When only opening the page, wait for it to appear or fail ///\param autoBackoff When only opening the page, wait for it to appear or fail
void sharedFile::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { void sharedFile::init(const std::string & name_, uint64_t len_, bool master_, bool autoBackoff) {
close(); close();
name = name_; name = name_;
len = len_; len = len_;
@ -623,7 +576,7 @@ namespace IPC {
handle = open(std::string(Util::getTmpFolder() + name).c_str(), (master ? O_CREAT | O_TRUNC | O_EXCL : 0) | O_RDWR, (mode_t)0600); handle = open(std::string(Util::getTmpFolder() + name).c_str(), (master ? O_CREAT | O_TRUNC | O_EXCL : 0) | O_RDWR, (mode_t)0600);
if (handle == -1) { if (handle == -1) {
if (master) { if (master) {
DEBUG_MSG(DLVL_HIGH, "Overwriting old file for %s", name.c_str()); HIGH_MSG("Overwriting old file for %s", name.c_str());
handle = open(std::string(Util::getTmpFolder() + name).c_str(), O_CREAT | O_TRUNC | O_RDWR, (mode_t)0600); handle = open(std::string(Util::getTmpFolder() + name).c_str(), O_CREAT | O_TRUNC | O_RDWR, (mode_t)0600);
} else { } else {
int i = 0; int i = 0;
@ -670,19 +623,18 @@ namespace IPC {
///\brief Sets timestamp of the current stats ///\brief Sets timestamp of the current stats
void statExchange::now(long long int time) { void statExchange::now(long long int time) {
htobll(data, time); Bit::htobll(data, time);
} }
///\brief Gets timestamp of the current stats ///\brief Gets timestamp of the current stats
long long int statExchange::now() { long long int statExchange::now() {
long long int result; long long int result;
btohll(data, result); return Bit::btohll(data);
return result;
} }
///\brief Sets time currently connected ///\brief Sets time currently connected
void statExchange::time(long time) { void statExchange::time(long time) {
htobl(data + 8, time); Bit::htobl(data + 8, time);
} }
/// Calculates session ID from CRC, stream name, connector and host. /// Calculates session ID from CRC, stream name, connector and host.
@ -692,45 +644,37 @@ namespace IPC {
///\brief Gets time currently connected ///\brief Gets time currently connected
long statExchange::time() { long statExchange::time() {
long result; return Bit::btohl(data + 8);
btohl(data + 8, result);
return result;
} }
///\brief Sets the last viewing second of this user ///\brief Sets the last viewing second of this user
void statExchange::lastSecond(long time) { void statExchange::lastSecond(long time) {
htobl(data + 12, time); Bit::htobl(data + 12, time);
} }
///\brief Gets the last viewing second of this user ///\brief Gets the last viewing second of this user
long statExchange::lastSecond() { long statExchange::lastSecond() {
long result; return Bit::btohl(data + 12);
btohl(data + 12, result);
return result;
} }
///\brief Sets the amount of bytes received ///\brief Sets the amount of bytes received
void statExchange::down(long long int bytes) { void statExchange::down(long long int bytes) {
htobll(data + 16, bytes); Bit::htobll(data + 16, bytes);
} }
///\brief Gets the amount of bytes received ///\brief Gets the amount of bytes received
long long int statExchange::down() { long long int statExchange::down() {
long long int result; return Bit::btohll(data + 16);
btohll(data + 16, result);
return result;
} }
///\brief Sets the amount of bytes sent ///\brief Sets the amount of bytes sent
void statExchange::up(long long int bytes) { void statExchange::up(long long int bytes) {
htobll(data + 24, bytes); Bit::htobll(data + 24, bytes);
} }
///\brief Gets the amount of bytes sent ///\brief Gets the amount of bytes sent
long long int statExchange::up() { long long int statExchange::up() {
long long int result; return Bit::btohll(data + 24);
btohll(data + 24, result);
return result;
} }
///\brief Sets the host of this connection ///\brief Sets the host of this connection
@ -772,14 +716,12 @@ namespace IPC {
///\brief Sets checksum field ///\brief Sets checksum field
void statExchange::crc(unsigned int sum) { void statExchange::crc(unsigned int sum) {
htobl(data + 168, sum); Bit::htobl(data + 168, sum);
} }
///\brief Gets checksum field ///\brief Gets checksum field
unsigned int statExchange::crc() { unsigned int statExchange::crc() {
unsigned int result; return Bit::btohl(data + 168);
btohl(data + 168, result);
return result;
} }
///\brief Sets checksum field ///\brief Sets checksum field

View file

@ -103,11 +103,11 @@ namespace IPC {
///\brief A class for managing shared files. ///\brief A class for managing shared files.
class sharedFile { class sharedFile {
public: public:
sharedFile(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true); sharedFile(const std::string & name_ = "", uint64_t len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedFile(const sharedFile & rhs); sharedFile(const sharedFile & rhs);
~sharedFile(); ~sharedFile();
operator bool() const; operator bool() const;
void init(std::string name_, unsigned int len_, bool master_ = false, bool autoBackoff = true); void init(const std::string & name_, uint64_t len_, bool master_ = false, bool autoBackoff = true);
void operator =(sharedFile & rhs); void operator =(sharedFile & rhs);
bool operator < (const sharedFile & rhs) const { bool operator < (const sharedFile & rhs) const {
return name < rhs.name; return name < rhs.name;
@ -120,7 +120,7 @@ namespace IPC {
///\brief The name of the opened shared file ///\brief The name of the opened shared file
std::string name; std::string name;
///\brief The size in bytes of the opened shared file ///\brief The size in bytes of the opened shared file
long long int len; uint64_t len;
///\brief Whether this class should unlink the shared file upon deletion or not ///\brief Whether this class should unlink the shared file upon deletion or not
bool master; bool master;
///\brief A pointer to the payload of the file file ///\brief A pointer to the payload of the file file
@ -136,11 +136,11 @@ namespace IPC {
///\brief A class for managing shared memory pages. ///\brief A class for managing shared memory pages.
class sharedPage { class sharedPage {
public: public:
sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true); sharedPage(const std::string & name_ = "", uint64_t len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedPage(const sharedPage & rhs); sharedPage(const sharedPage & rhs);
~sharedPage(); ~sharedPage();
operator bool() const; operator bool() const;
void init(std::string name_, unsigned int len_, bool master_ = false, bool autoBackoff = true); void init(const std::string & name_, uint64_t len_, bool master_ = false, bool autoBackoff = true);
void operator =(sharedPage & rhs); void operator =(sharedPage & rhs);
bool operator < (const sharedPage & rhs) const { bool operator < (const sharedPage & rhs) const {
return name < rhs.name; return name < rhs.name;
@ -169,7 +169,7 @@ namespace IPC {
///Uses shared files at its backbone, defined for portability ///Uses shared files at its backbone, defined for portability
class sharedPage: public sharedFile { class sharedPage: public sharedFile {
public: public:
sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true); sharedPage(const std::string & name_ = "", uint64_t len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedPage(const sharedPage & rhs); sharedPage(const sharedPage & rhs);
~sharedPage(); ~sharedPage();
}; };

View file

@ -6,13 +6,13 @@
#include "defines.h" #include "defines.h"
#include "timing.h" #include "timing.h"
#include <cstdlib> #include <cstdlib>
#include <ifaddrs.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <poll.h> #include <poll.h>
#include <sstream> #include <sstream>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <ifaddrs.h>
#define BUFFER_BLOCKSIZE 4096 // set buffer blocksize to 4KiB #define BUFFER_BLOCKSIZE 4096 // set buffer blocksize to 4KiB
@ -23,8 +23,8 @@
#endif #endif
/// Local-scope only helper function that prints address families /// Local-scope only helper function that prints address families
static const char* addrFam(int f){ static const char *addrFam(int f){
switch(f){ switch (f){
case AF_UNSPEC: return "Unspecified"; case AF_UNSPEC: return "Unspecified";
case AF_INET: return "IPv4"; case AF_INET: return "IPv4";
case AF_INET6: return "IPv6"; case AF_INET6: return "IPv6";
@ -33,23 +33,20 @@ static const char* addrFam(int f){
} }
} }
static std::string getIPv6BinAddr(const struct sockaddr_in6 & remoteaddr){ static std::string getIPv6BinAddr(const struct sockaddr_in6 &remoteaddr){
char tmpBuffer[17] = "\000\000\000\000\000\000\000\000\000\000\377\377\000\000\000\000"; char tmpBuffer[17] = "\000\000\000\000\000\000\000\000\000\000\377\377\000\000\000\000";
switch (remoteaddr.sin6_family){ switch (remoteaddr.sin6_family){
case AF_INET: case AF_INET:
memcpy(tmpBuffer + 12, &(reinterpret_cast<const sockaddr_in*>(&remoteaddr)->sin_addr.s_addr), 4); memcpy(tmpBuffer + 12, &(reinterpret_cast<const sockaddr_in *>(&remoteaddr)->sin_addr.s_addr),
break; 4);
case AF_INET6:
memcpy(tmpBuffer, &(remoteaddr.sin6_addr.s6_addr), 16);
break;
default:
return "";
break; break;
case AF_INET6: memcpy(tmpBuffer, &(remoteaddr.sin6_addr.s6_addr), 16); break;
default: return ""; break;
} }
return std::string(tmpBuffer, 16); return std::string(tmpBuffer, 16);
} }
bool Socket::isLocalhost(const std::string & remotehost){ bool Socket::isLocalhost(const std::string &remotehost){
std::string tmpInput = remotehost; std::string tmpInput = remotehost;
std::string bf = Socket::getBinForms(tmpInput); std::string bf = Socket::getBinForms(tmpInput);
std::string tmpAddr; std::string tmpAddr;
@ -61,33 +58,31 @@ bool Socket::isLocalhost(const std::string & remotehost){
return false; return false;
} }
bool Socket::isLocal(const std::string & remotehost){ bool Socket::isLocal(const std::string &remotehost){
struct ifaddrs * ifAddrStruct=NULL; struct ifaddrs *ifAddrStruct = NULL;
struct ifaddrs * ifa=NULL; struct ifaddrs *ifa = NULL;
void * tmpAddrPtr=NULL; void *tmpAddrPtr = NULL;
char addressBuffer[INET6_ADDRSTRLEN]; char addressBuffer[INET6_ADDRSTRLEN];
getifaddrs(&ifAddrStruct); getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next){ for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next){
if (!ifa->ifa_addr){ if (!ifa->ifa_addr){continue;}
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET){// check it is IP4 if (ifa->ifa_addr->sa_family == AF_INET){// check it is IP4
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
INSANE_MSG("Comparing '%s' to '%s'", remotehost.c_str(), addressBuffer); INSANE_MSG("Comparing '%s' to '%s'", remotehost.c_str(), addressBuffer);
if (remotehost == addressBuffer){return true;} if (remotehost == addressBuffer){return true;}
INSANE_MSG("Comparing '%s' to '::ffff:%s'", remotehost.c_str(), addressBuffer); INSANE_MSG("Comparing '%s' to '::ffff:%s'", remotehost.c_str(), addressBuffer);
if (remotehost == std::string("::ffff:") + addressBuffer){return true;} if (remotehost == std::string("::ffff:") + addressBuffer){return true;}
}else if (ifa->ifa_addr->sa_family == AF_INET6){// check it is IP6 }else if (ifa->ifa_addr->sa_family == AF_INET6){// check it is IP6
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
INSANE_MSG("Comparing '%s' to '%s'", remotehost.c_str(), addressBuffer); INSANE_MSG("Comparing '%s' to '%s'", remotehost.c_str(), addressBuffer);
if (remotehost == addressBuffer){return true;} if (remotehost == addressBuffer){return true;}
} }
} }
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct); if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
return false; return false;
} }
@ -111,13 +106,13 @@ bool Socket::matchIPv6Addr(const std::string &A, const std::string &B, uint8_t p
/// Attempts to match the given address with optional subnet to the given binary-form IPv6 address. /// Attempts to match the given address with optional subnet to the given binary-form IPv6 address.
/// Returns true if match could be made, false otherwise. /// Returns true if match could be made, false otherwise.
bool Socket::isBinAddress(const std::string &binAddr, std::string addr){ bool Socket::isBinAddress(const std::string &binAddr, std::string addr){
//Check if we need to do prefix matching // Check if we need to do prefix matching
uint8_t prefixLen = 0; uint8_t prefixLen = 0;
if (addr.find('/') != std::string::npos){ if (addr.find('/') != std::string::npos){
prefixLen = atoi(addr.c_str() + addr.find('/') + 1); prefixLen = atoi(addr.c_str() + addr.find('/') + 1);
addr.erase(addr.find('/'), std::string::npos); addr.erase(addr.find('/'), std::string::npos);
} }
//Loops over all IPs for the given address and matches them in IPv6 form. // Loops over all IPs for the given address and matches them in IPv6 form.
struct addrinfo *result, *rp, hints; struct addrinfo *result, *rp, hints;
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -145,13 +140,13 @@ bool Socket::isBinAddress(const std::string &binAddr, std::string addr){
/// Converts the given address with optional subnet to binary IPv6 form. /// Converts the given address with optional subnet to binary IPv6 form.
/// Returns 16 bytes of address, followed by 1 byte of subnet bits, zero or more times. /// Returns 16 bytes of address, followed by 1 byte of subnet bits, zero or more times.
std::string Socket::getBinForms(std::string addr){ std::string Socket::getBinForms(std::string addr){
//Check if we need to do prefix matching // Check if we need to do prefix matching
uint8_t prefixLen = 128; uint8_t prefixLen = 128;
if (addr.find('/') != std::string::npos){ if (addr.find('/') != std::string::npos){
prefixLen = atoi(addr.c_str() + addr.find('/') + 1); prefixLen = atoi(addr.c_str() + addr.find('/') + 1);
addr.erase(addr.find('/'), std::string::npos); addr.erase(addr.find('/'), std::string::npos);
} }
//Loops over all IPs for the given address and converts to IPv6 binary form. // Loops over all IPs for the given address and converts to IPv6 binary form.
struct addrinfo *result, *rp, hints; struct addrinfo *result, *rp, hints;
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -167,7 +162,7 @@ std::string Socket::getBinForms(std::string addr){
for (rp = result; rp != NULL; rp = rp->ai_next){ for (rp = result; rp != NULL; rp = rp->ai_next){
ret += getIPv6BinAddr(*((sockaddr_in6 *)rp->ai_addr)); ret += getIPv6BinAddr(*((sockaddr_in6 *)rp->ai_addr));
if (rp->ai_family == AF_INET){ if (rp->ai_family == AF_INET){
ret += (char)(prefixLen<=32 ? prefixLen + 96 : prefixLen); ret += (char)(prefixLen <= 32 ? prefixLen + 96 : prefixLen);
}else{ }else{
ret += (char)prefixLen; ret += (char)prefixLen;
} }
@ -176,8 +171,8 @@ std::string Socket::getBinForms(std::string addr){
return ret; return ret;
} }
/// Checks bytes (length len) containing a binary-encoded IPv4 or IPv6 IP address, and writes it in human-readable notation to target. /// Checks bytes (length len) containing a binary-encoded IPv4 or IPv6 IP address, and writes it in
/// Writes "unknown" if it cannot decode to a sensible value. /// human-readable notation to target. Writes "unknown" if it cannot decode to a sensible value.
void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){ void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){
switch (len){ switch (len){
case 4: case 4:
@ -192,7 +187,7 @@ void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){
target = tmpstr; target = tmpstr;
}else{ }else{
char tmpstr[40]; char tmpstr[40];
snprintf(tmpstr, 40, "%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x", bytes[0], bytes[1], snprintf(tmpstr, 40, "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", bytes[0], bytes[1],
bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13],
bytes[14], bytes[15]); bytes[14], bytes[15]);
target = tmpstr; target = tmpstr;
@ -235,7 +230,8 @@ unsigned int Socket::Buffer::bytesToSplit(){
unsigned int i = 0; unsigned int i = 0;
for (std::deque<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){ for (std::deque<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){
i += (*it).size(); i += (*it).size();
if ((*it).size() >= splitter.size() && (*it).substr((*it).size()-splitter.size()) == splitter){ if ((*it).size() >= splitter.size() &&
(*it).substr((*it).size() - splitter.size()) == splitter){
return i; return i;
} }
} }
@ -243,12 +239,13 @@ unsigned int Socket::Buffer::bytesToSplit(){
} }
/// Appends this string to the internal std::deque of std::string objects. /// Appends this string to the internal std::deque of std::string objects.
/// It is automatically split every BUFFER_BLOCKSIZE bytes and when the splitter string is encountered. /// It is automatically split every BUFFER_BLOCKSIZE bytes and when the splitter string is
/// encountered.
void Socket::Buffer::append(const std::string &newdata){ void Socket::Buffer::append(const std::string &newdata){
append(newdata.data(), newdata.size()); append(newdata.data(), newdata.size());
} }
///Helper function that does a short-circuiting string compare /// Helper function that does a short-circuiting string compare
inline bool string_compare(const char *a, const char *b, const size_t len){ inline bool string_compare(const char *a, const char *b, const size_t len){
for (size_t i = 0; i < len; ++i){ for (size_t i = 0; i < len; ++i){
if (a[i] != b[i]){return false;} if (a[i] != b[i]){return false;}
@ -257,7 +254,8 @@ inline bool string_compare(const char *a, const char *b, const size_t len){
} }
/// Appends this data block to the internal std::deque of std::string objects. /// Appends this data block to the internal std::deque of std::string objects.
/// It is automatically split every BUFFER_BLOCKSIZE bytes and when the splitter string is encountered. /// It is automatically split every BUFFER_BLOCKSIZE bytes and when the splitter string is
/// encountered.
void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize){ void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize){
uint32_t i = 0; uint32_t i = 0;
while (i < newdatasize){ while (i < newdatasize){
@ -269,10 +267,12 @@ void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize)
j = newdatasize - i; j = newdatasize - i;
} }
}else{ }else{
while (j+i < newdatasize && j < BUFFER_BLOCKSIZE){ while (j + i < newdatasize && j < BUFFER_BLOCKSIZE){
j++; j++;
if (j >= splitter.size()){ if (j >= splitter.size()){
if (string_compare(newdata+i+j-splitter.size(), splitter.data(), splitter.size())){break;} if (string_compare(newdata + i + j - splitter.size(), splitter.data(), splitter.size())){
break;
}
} }
} }
} }
@ -286,7 +286,7 @@ void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize)
} }
} }
if (data.size() > 5000){ if (data.size() > 5000){
DEBUG_MSG(DLVL_WARN, "Warning: After %d new bytes, buffer has %d parts containing over %u bytes!", newdatasize, (int)data.size(), WARN_MSG("Warning: After %d new bytes, buffer has %d parts containing over %u bytes!", newdatasize, (int)data.size(),
bytes(9000)); bytes(9000));
} }
} }
@ -372,8 +372,8 @@ void Socket::Buffer::clear(){
data.clear(); data.clear();
} }
/// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection. /// Create a new base socket. This is a basic constructor for converting any valid socket to a
/// \param sockNo Integer representing the socket to convert. /// Socket::Connection. \param sockNo Integer representing the socket to convert.
Socket::Connection::Connection(int sockNo){ Socket::Connection::Connection(int sockNo){
sSend = sockNo; sSend = sockNo;
sRecv = -1; sRecv = -1;
@ -509,7 +509,8 @@ int Socket::Connection::getPureSocket(){
} }
/// Returns a string describing the last error that occured. /// Returns a string describing the last error that occured.
/// Only reports errors if an error actually occured - returns the host address or empty string otherwise. /// Only reports errors if an error actually occured - returns the host address or empty string
/// otherwise.
std::string Socket::Connection::getError(){ std::string Socket::Connection::getError(){
return remotehost; return remotehost;
} }
@ -572,7 +573,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result); int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result);
if (s != 0){ if (s != 0){
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s:%i! Error: %s", host.c_str(), port, gai_strerror(s)); FAIL_MSG("Could not connect to %s:%i! Error: %s", host.c_str(), port, gai_strerror(s));
close(); close();
return; return;
} }
@ -588,7 +589,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
freeaddrinfo(result); freeaddrinfo(result);
if (rp == 0){ if (rp == 0){
DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", host.c_str(), remotehost.c_str()); FAIL_MSG("Could not connect to %s! Error: %s", host.c_str(), remotehost.c_str());
close(); close();
}else{ }else{
if (nonblock){ if (nonblock){
@ -629,7 +630,8 @@ uint64_t Socket::Connection::dataDown(){
/// Returns a std::string of stats, ended by a newline. /// Returns a std::string of stats, ended by a newline.
/// Requires the current connector name as an argument. /// Requires the current connector name as an argument.
std::string Socket::Connection::getStats(std::string C){ std::string Socket::Connection::getStats(std::string C){
return "S " + getHost() + " " + C + " " + uint2string(Util::epoch() - conntime) + " " + uint2string(up) + " " + uint2string(down) + "\n"; return "S " + getHost() + " " + C + " " + uint2string(Util::epoch() - conntime) + " " +
uint2string(up) + " " + uint2string(down) + "\n";
} }
/// Updates the downbuffer internal variable. /// Updates the downbuffer internal variable.
@ -660,7 +662,9 @@ void Socket::Connection::SendNow(const char *data, size_t len){
bool bing = isBlocking(); bool bing = isBlocking();
if (!bing){setBlocking(true);} if (!bing){setBlocking(true);}
unsigned int i = iwrite(data, std::min((long unsigned int)len, SOCKETSIZE)); unsigned int i = iwrite(data, std::min((long unsigned int)len, SOCKETSIZE));
while (i < len && connected()){i += iwrite(data + i, std::min((long unsigned int)(len - i), SOCKETSIZE));} while (i < len && connected()){
i += iwrite(data + i, std::min((long unsigned int)(len - i), SOCKETSIZE));
}
if (!bing){setBlocking(false);} if (!bing){setBlocking(false);}
} }
@ -678,7 +682,7 @@ void Socket::Connection::SendNow(const std::string &data){
} }
void Socket::Connection::skipBytes(uint32_t byteCount){ void Socket::Connection::skipBytes(uint32_t byteCount){
INFO_MSG("Skipping first %lu bytes going to socket", byteCount); INFO_MSG("Skipping first %" PRIu32 " bytes going to socket", byteCount);
skipCount = byteCount; skipCount = byteCount;
} }
@ -690,15 +694,15 @@ void Socket::Connection::skipBytes(uint32_t byteCount){
unsigned int Socket::Connection::iwrite(const void *buffer, int len){ unsigned int Socket::Connection::iwrite(const void *buffer, int len){
if (!connected() || len < 1){return 0;} if (!connected() || len < 1){return 0;}
if (skipCount){ if (skipCount){
//We have bytes to skip writing. // We have bytes to skip writing.
//Pretend we write them, but don't really. // Pretend we write them, but don't really.
if (len <= skipCount){ if (len <= skipCount){
skipCount -= len; skipCount -= len;
return len; return len;
}else{ }else{
unsigned int toSkip = skipCount; unsigned int toSkip = skipCount;
skipCount = 0; skipCount = 0;
return iwrite((((char*)buffer)+toSkip), len-toSkip) + toSkip; return iwrite((((char *)buffer) + toSkip), len - toSkip) + toSkip;
} }
} }
int r; int r;
@ -802,7 +806,7 @@ std::string Socket::Connection::getBinHost(){
/// Overwrites the detected host, thus possibily making it incorrect. /// Overwrites the detected host, thus possibily making it incorrect.
void Socket::Connection::setHost(std::string host){ void Socket::Connection::setHost(std::string host){
remotehost = host; remotehost = host;
struct addrinfo *result, *rp, hints; struct addrinfo *result, hints;
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
@ -813,9 +817,7 @@ void Socket::Connection::setHost(std::string host){
hints.ai_next = NULL; hints.ai_next = NULL;
int s = getaddrinfo(host.c_str(), 0, &hints, &result); int s = getaddrinfo(host.c_str(), 0, &hints, &result);
if (s != 0){return;} if (s != 0){return;}
if (result){ if (result){remoteaddr = *((sockaddr_in6 *)result->ai_addr);}
remoteaddr = *((sockaddr_in6 *)result->ai_addr);
}
freeaddrinfo(result); freeaddrinfo(result);
} }
@ -840,7 +842,7 @@ Socket::Connection::operator bool() const{
/// Returns true if the given address can be matched with the remote host. /// Returns true if the given address can be matched with the remote host.
/// Can no longer return true after any socket error have occurred. /// Can no longer return true after any socket error have occurred.
bool Socket::Connection::isAddress(const std::string &addr){ bool Socket::Connection::isAddress(const std::string &addr){
//Retrieve current socket binary address // Retrieve current socket binary address
std::string myBinAddr = getBinHost(); std::string myBinAddr = getBinHost();
return isBinAddress(myBinAddr, addr); return isBinAddress(myBinAddr, addr);
} }
@ -865,7 +867,8 @@ static void my_debug(void *ctx, int level, const char *file, int line, const cha
fflush((FILE *)ctx); fflush((FILE *)ctx);
} }
Socket::SSLConnection::SSLConnection(std::string hostname, int port, bool nonblock) : Socket::Connection(){ Socket::SSLConnection::SSLConnection(std::string hostname, int port, bool nonblock)
: Socket::Connection(){
mbedtls_debug_set_threshold(0); mbedtls_debug_set_threshold(0);
isConnected = true; isConnected = true;
server_fd = new mbedtls_net_context; server_fd = new mbedtls_net_context;
@ -879,14 +882,15 @@ Socket::SSLConnection::SSLConnection(std::string hostname, int port, bool nonblo
mbedtls_ctr_drbg_init(ctr_drbg); mbedtls_ctr_drbg_init(ctr_drbg);
mbedtls_entropy_init(entropy); mbedtls_entropy_init(entropy);
DONTEVEN_MSG("SSL init"); DONTEVEN_MSG("SSL init");
if (mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char*)"meow", 4) != 0){ if (mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char *)"meow",
4) != 0){
FAIL_MSG("SSL socket init failed"); FAIL_MSG("SSL socket init failed");
close(); close();
return; return;
} }
DONTEVEN_MSG("SSL connect"); DONTEVEN_MSG("SSL connect");
int ret = 0; int ret = 0;
if ((ret = mbedtls_net_connect(server_fd, hostname.c_str(), JSON::Value((long long)port).asString().c_str(), MBEDTLS_NET_PROTO_TCP)) != 0){ if ((ret = mbedtls_net_connect(server_fd, hostname.c_str(), JSON::Value(port).asString().c_str(), MBEDTLS_NET_PROTO_TCP)) != 0){
FAIL_MSG(" failed\n ! mbedtls_net_connect returned %d\n\n", ret); FAIL_MSG(" failed\n ! mbedtls_net_connect returned %d\n\n", ret);
close(); close();
return; return;
@ -899,7 +903,7 @@ Socket::SSLConnection::SSLConnection(std::string hostname, int port, bool nonblo
} }
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, ctr_drbg); mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, ctr_drbg);
mbedtls_ssl_conf_dbg(conf, my_debug, stderr ); mbedtls_ssl_conf_dbg(conf, my_debug, stderr);
if ((ret = mbedtls_ssl_setup(ssl, conf)) != 0){ if ((ret = mbedtls_ssl_setup(ssl, conf)) != 0){
char estr[200]; char estr[200];
mbedtls_strerror(ret, estr, 200); mbedtls_strerror(ret, estr, 200);
@ -923,9 +927,7 @@ Socket::SSLConnection::SSLConnection(std::string hostname, int port, bool nonblo
} }
} }
Blocking = true; Blocking = true;
if (nonblock){ if (nonblock){setBlocking(false);}
setBlocking(false);
}
} }
void Socket::SSLConnection::close(){ void Socket::SSLConnection::close(){
@ -969,7 +971,7 @@ int Socket::SSLConnection::iread(void *buffer, int len, int flags){
if (!connected() || len < 1){return 0;} if (!connected() || len < 1){return 0;}
int r; int r;
/// \TODO Flags ignored... Bad. /// \TODO Flags ignored... Bad.
r = mbedtls_ssl_read(ssl, (unsigned char*)buffer, len); r = mbedtls_ssl_read(ssl, (unsigned char *)buffer, len);
if (r < 0){ if (r < 0){
char estr[200]; char estr[200];
mbedtls_strerror(r, estr, 200); mbedtls_strerror(r, estr, 200);
@ -1006,7 +1008,7 @@ unsigned int Socket::SSLConnection::iwrite(const void *buffer, int len){
DONTEVEN_MSG("SSL iwrite"); DONTEVEN_MSG("SSL iwrite");
if (!connected() || len < 1){return 0;} if (!connected() || len < 1){return 0;}
int r; int r;
r = mbedtls_ssl_write(ssl, (const unsigned char*)buffer, len); r = mbedtls_ssl_write(ssl, (const unsigned char *)buffer, len);
if (r < 0){ if (r < 0){
char estr[200]; char estr[200];
mbedtls_strerror(r, estr, 200); mbedtls_strerror(r, estr, 200);
@ -1050,7 +1052,8 @@ void Socket::SSLConnection::setBlocking(bool blocking){
#endif #endif
/// Create a new base Server. The socket is never connected, and a placeholder for later connections. /// Create a new base Server. The socket is never connected, and a placeholder for later
/// connections.
Socket::Server::Server(){ Socket::Server::Server(){
sock = -1; sock = -1;
}// Socket::Server base Constructor }// Socket::Server base Constructor
@ -1060,10 +1063,11 @@ Socket::Server::Server(){
/// Any further connections coming in will be dropped. /// Any further connections coming in will be dropped.
/// \param port The TCP port to listen on /// \param port The TCP port to listen on
/// \param hostname (optional) The interface to bind to. The default is 0.0.0.0 (all interfaces). /// \param hostname (optional) The interface to bind to. The default is 0.0.0.0 (all interfaces).
/// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking). /// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false
/// (blocking).
Socket::Server::Server(int port, std::string hostname, bool nonblock){ Socket::Server::Server(int port, std::string hostname, bool nonblock){
if (!IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)){ if (!IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)){
DEBUG_MSG(DLVL_FAIL, "Could not create socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str()); FAIL_MSG("Could not create socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
sock = -1; sock = -1;
} }
}// Socket::Server TCP Constructor }// Socket::Server TCP Constructor
@ -1077,7 +1081,7 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){
sock = socket(AF_INET6, SOCK_STREAM, 0); sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock < 0){ if (sock < 0){
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "Could not create IPv6 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str()); ERROR_MSG("Could not create IPv6 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
return false; return false;
} }
int on = 1; int on = 1;
@ -1095,7 +1099,7 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port); // set port addr.sin6_port = htons(port); // set port
//set interface, 0.0.0.0 (default) is all // set interface, 0.0.0.0 (default) is all
if (hostname == "0.0.0.0" || hostname.length() == 0){ if (hostname == "0.0.0.0" || hostname.length() == 0){
addr.sin6_addr = in6addr_any; addr.sin6_addr = in6addr_any;
}else{ }else{
@ -1110,17 +1114,17 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){
if (ret == 0){ if (ret == 0){
ret = listen(sock, 100); // start listening, backlog of 100 allowed ret = listen(sock, 100); // start listening, backlog of 100 allowed
if (ret == 0){ if (ret == 0){
DEBUG_MSG(DLVL_DEVEL, "IPv6 socket success @ %s:%i", hostname.c_str(), port); DEVEL_MSG("IPv6 socket success @ %s:%i", hostname.c_str(), port);
return true; return true;
}else{ }else{
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "IPv6 listen failed! Error: %s", errors.c_str()); ERROR_MSG("IPv6 listen failed! Error: %s", errors.c_str());
close(); close();
return false; return false;
} }
}else{ }else{
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "IPv6 Binding %s:%i failed (%s)", hostname.c_str(), port, errors.c_str()); ERROR_MSG("IPv6 Binding %s:%i failed (%s)", hostname.c_str(), port, errors.c_str());
close(); close();
return false; return false;
} }
@ -1135,7 +1139,7 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
sock = socket(AF_INET, SOCK_STREAM, 0); sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0){ if (sock < 0){
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "Could not create IPv4 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str()); ERROR_MSG("Could not create IPv4 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str());
return false; return false;
} }
int on = 1; int on = 1;
@ -1149,7 +1153,7 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
memset(&addr4, 0, sizeof(addr4)); memset(&addr4, 0, sizeof(addr4));
addr4.sin_family = AF_INET; addr4.sin_family = AF_INET;
addr4.sin_port = htons(port); // set port addr4.sin_port = htons(port); // set port
//set interface, 0.0.0.0 (default) is all // set interface, 0.0.0.0 (default) is all
if (hostname == "0.0.0.0" || hostname.length() == 0){ if (hostname == "0.0.0.0" || hostname.length() == 0){
addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_addr.s_addr = INADDR_ANY;
}else{ }else{
@ -1164,17 +1168,17 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
if (ret == 0){ if (ret == 0){
ret = listen(sock, 100); // start listening, backlog of 100 allowed ret = listen(sock, 100); // start listening, backlog of 100 allowed
if (ret == 0){ if (ret == 0){
DEBUG_MSG(DLVL_DEVEL, "IPv4 socket success @ %s:%i", hostname.c_str(), port); DEVEL_MSG("IPv4 socket success @ %s:%i", hostname.c_str(), port);
return true; return true;
}else{ }else{
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "IPv4 listen failed! Error: %s", errors.c_str()); ERROR_MSG("IPv4 listen failed! Error: %s", errors.c_str());
close(); close();
return false; return false;
} }
}else{ }else{
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "IPv4 Binding %s:%i failed (%s)", hostname.c_str(), port, errors.c_str()); ERROR_MSG("IPv4 Binding %s:%i failed (%s)", hostname.c_str(), port, errors.c_str());
close(); close();
return false; return false;
} }
@ -1183,16 +1187,16 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){
/// Create a new Unix Server. The socket is immediately bound and set to listen. /// Create a new Unix Server. The socket is immediately bound and set to listen.
/// A maximum of 100 connections will be accepted between accept() calls. /// A maximum of 100 connections will be accepted between accept() calls.
/// Any further connections coming in will be dropped. /// Any further connections coming in will be dropped.
/// The address used will first be unlinked - so it succeeds if the Unix socket already existed. Watch out for this behaviour - it will delete /// The address used will first be unlinked - so it succeeds if the Unix socket already existed.
/// any file located at address! /// Watch out for this behaviour - it will delete any file located at address! \param address The
/// \param address The location of the Unix socket to bind to. /// location of the Unix socket to bind to. \param nonblock (optional) Whether accept() calls will
/// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking). /// be nonblocking. Default is false (blocking).
Socket::Server::Server(std::string address, bool nonblock){ Socket::Server::Server(std::string address, bool nonblock){
unlink(address.c_str()); unlink(address.c_str());
sock = socket(AF_UNIX, SOCK_STREAM, 0); sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0){ if (sock < 0){
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "Could not create unix socket %s! Error: %s", address.c_str(), errors.c_str()); ERROR_MSG("Could not create unix socket %s! Error: %s", address.c_str(), errors.c_str());
return; return;
} }
if (nonblock){ if (nonblock){
@ -1210,22 +1214,23 @@ Socket::Server::Server(std::string address, bool nonblock){
return; return;
}else{ }else{
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "Unix listen failed! Error: %s", errors.c_str()); ERROR_MSG("Unix listen failed! Error: %s", errors.c_str());
close(); close();
return; return;
} }
}else{ }else{
errors = strerror(errno); errors = strerror(errno);
DEBUG_MSG(DLVL_ERROR, "Unix Binding %s failed (%s)", address.c_str(), errors.c_str()); ERROR_MSG("Unix Binding %s failed (%s)", address.c_str(), errors.c_str());
close(); close();
return; return;
} }
}// Socket::Server Unix Constructor }// Socket::Server Unix Constructor
/// Accept any waiting connections. If the Socket::Server is blocking, this function will block until there is an incoming connection. /// Accept any waiting connections. If the Socket::Server is blocking, this function will block
/// If the Socket::Server is nonblocking, it might return a Socket::Connection that is not connected, so check for this. /// until there is an incoming connection. If the Socket::Server is nonblocking, it might return a
/// \param nonblock (optional) Whether the newly connected socket should be nonblocking. Default is false (blocking). /// Socket::Connection that is not connected, so check for this. \param nonblock (optional) Whether
/// \returns A Socket::Connection, which may or may not be connected, depending on settings and circumstances. /// the newly connected socket should be nonblocking. Default is false (blocking). \returns A
/// Socket::Connection, which may or may not be connected, depending on settings and circumstances.
Socket::Connection Socket::Server::accept(bool nonblock){ Socket::Connection Socket::Server::accept(bool nonblock){
if (sock < 0){return Socket::Connection(-1);} if (sock < 0){return Socket::Connection(-1);}
struct sockaddr_in6 tmpaddr; struct sockaddr_in6 tmpaddr;
@ -1254,14 +1259,15 @@ Socket::Connection Socket::Server::accept(bool nonblock){
tmp.remoteaddr = tmpaddr; tmp.remoteaddr = tmpaddr;
if (tmpaddr.sin6_family == AF_INET6){ if (tmpaddr.sin6_family == AF_INET6){
tmp.remotehost = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN); tmp.remotehost = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN);
DEBUG_MSG(DLVL_HIGH, "IPv6 addr [%s]", tmp.remotehost.c_str()); HIGH_MSG("IPv6 addr [%s]", tmp.remotehost.c_str());
} }
if (tmpaddr.sin6_family == AF_INET){ if (tmpaddr.sin6_family == AF_INET){
tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in *)&tmpaddr)->sin_addr), addrconv, INET6_ADDRSTRLEN); tmp.remotehost =
DEBUG_MSG(DLVL_HIGH, "IPv4 addr [%s]", tmp.remotehost.c_str()); inet_ntop(AF_INET, &(((sockaddr_in *)&tmpaddr)->sin_addr), addrconv, INET6_ADDRSTRLEN);
HIGH_MSG("IPv4 addr [%s]", tmp.remotehost.c_str());
} }
if (tmpaddr.sin6_family == AF_UNIX){ if (tmpaddr.sin6_family == AF_UNIX){
DEBUG_MSG(DLVL_HIGH, "Unix connection"); HIGH_MSG("Unix connection");
tmp.remotehost = "UNIX_SOCKET"; tmp.remotehost = "UNIX_SOCKET";
} }
return tmp; return tmp;
@ -1294,7 +1300,7 @@ void Socket::Server::close(){
void Socket::Server::drop(){ void Socket::Server::drop(){
if (connected()){ if (connected()){
if (sock != -1){ if (sock != -1){
DEBUG_MSG(DLVL_HIGH, "ServerSocket %d closed", sock); HIGH_MSG("ServerSocket %d closed", sock);
errno = EINTR; errno = EINTR;
while (::close(sock) != 0 && errno == EINTR){} while (::close(sock) != 0 && errno == EINTR){}
sock = -1; sock = -1;
@ -1327,7 +1333,7 @@ Socket::UDPConnection::UDPConnection(bool nonblock){
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
family = AF_INET; family = AF_INET;
} }
if (sock == -1){DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno));} if (sock == -1){FAIL_MSG("Could not create UDP socket: %s", strerror(errno));}
up = 0; up = 0;
down = 0; down = 0;
destAddr = 0; destAddr = 0;
@ -1347,7 +1353,7 @@ Socket::UDPConnection::UDPConnection(const UDPConnection &o){
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
family = AF_INET; family = AF_INET;
} }
if (sock == -1){DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno));} if (sock == -1){FAIL_MSG("Could not create UDP socket: %s", strerror(errno));}
up = 0; up = 0;
down = 0; down = 0;
if (o.destAddr && o.destAddr_size){ if (o.destAddr && o.destAddr_size){
@ -1392,11 +1398,9 @@ Socket::UDPConnection::~UDPConnection(){
/// Stores the properties of the receiving end of this UDP socket. /// Stores the properties of the receiving end of this UDP socket.
/// This will be the receiving end for all SendNow calls. /// This will be the receiving end for all SendNow calls.
void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
//UDP sockets can switch between IPv4 and IPv6 on demand. // UDP sockets can switch between IPv4 and IPv6 on demand.
//We change IPv4-mapped IPv6 addresses into IPv4 addresses for Windows-sillyness reasons. // We change IPv4-mapped IPv6 addresses into IPv4 addresses for Windows-sillyness reasons.
if (destIp.substr(0, 7) == "::ffff:"){ if (destIp.substr(0, 7) == "::ffff:"){destIp = destIp.substr(7);}
destIp = destIp.substr(7);
}
struct addrinfo *result, *rp, hints; struct addrinfo *result, *rp, hints;
std::stringstream ss; std::stringstream ss;
ss << port; ss << port;
@ -1411,7 +1415,7 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
hints.ai_next = NULL; hints.ai_next = NULL;
int s = getaddrinfo(destIp.c_str(), ss.str().c_str(), &hints, &result); int s = getaddrinfo(destIp.c_str(), ss.str().c_str(), &hints, &result);
if (s != 0){ if (s != 0){
DEBUG_MSG(DLVL_FAIL, "Could not connect UDP socket to %s:%i! Error: %s", destIp.c_str(), port, gai_strerror(s)); FAIL_MSG("Could not connect UDP socket to %s:%i! Error: %s", destIp.c_str(), port, gai_strerror(s));
return; return;
} }
@ -1426,7 +1430,8 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
if (!destAddr){return;} if (!destAddr){return;}
memcpy(destAddr, rp->ai_addr, rp->ai_addrlen); memcpy(destAddr, rp->ai_addr, rp->ai_addrlen);
if (family != rp->ai_family){ if (family != rp->ai_family){
INFO_MSG("Socket is wrong type (%s), re-opening as %s", addrFam(family), addrFam(rp->ai_family)); INFO_MSG("Socket is wrong type (%s), re-opening as %s", addrFam(family),
addrFam(rp->ai_family));
close(); close();
family = rp->ai_family; family = rp->ai_family;
sock = socket(family, SOCK_DGRAM, 0); sock = socket(family, SOCK_DGRAM, 0);
@ -1439,7 +1444,7 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
freeaddrinfo(result); freeaddrinfo(result);
free(destAddr); free(destAddr);
destAddr = 0; destAddr = 0;
DEBUG_MSG(DLVL_FAIL, "Could not set destination for UDP socket: %s:%d", destIp.c_str(), port); FAIL_MSG("Could not set destination for UDP socket: %s:%d", destIp.c_str(), port);
}// Socket::UDPConnection SetDestination }// Socket::UDPConnection SetDestination
/// Gets the properties of the receiving end of this UDP socket. /// Gets the properties of the receiving end of this UDP socket.
@ -1453,14 +1458,16 @@ void Socket::UDPConnection::GetDestination(std::string &destIp, uint32_t &port){
char addr_str[INET6_ADDRSTRLEN + 1]; char addr_str[INET6_ADDRSTRLEN + 1];
addr_str[INET6_ADDRSTRLEN] = 0; // set last byte to zero, to prevent walking out of the array addr_str[INET6_ADDRSTRLEN] = 0; // set last byte to zero, to prevent walking out of the array
if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6){ if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6){
if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)destAddr)->sin6_addr), addr_str, INET6_ADDRSTRLEN) != 0){ if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)destAddr)->sin6_addr), addr_str,
INET6_ADDRSTRLEN) != 0){
destIp = addr_str; destIp = addr_str;
port = ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port); port = ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port);
return; return;
} }
} }
if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET){ if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET){
if (inet_ntop(AF_INET, &(((struct sockaddr_in *)destAddr)->sin_addr), addr_str, INET6_ADDRSTRLEN) != 0){ if (inet_ntop(AF_INET, &(((struct sockaddr_in *)destAddr)->sin_addr), addr_str,
INET6_ADDRSTRLEN) != 0){
destIp = addr_str; destIp = addr_str;
port = ntohs(((struct sockaddr_in *)destAddr)->sin_port); port = ntohs(((struct sockaddr_in *)destAddr)->sin_port);
return; return;
@ -1468,15 +1475,19 @@ void Socket::UDPConnection::GetDestination(std::string &destIp, uint32_t &port){
} }
destIp = ""; destIp = "";
port = 0; port = 0;
DEBUG_MSG(DLVL_FAIL, "Could not get destination for UDP socket"); FAIL_MSG("Could not get destination for UDP socket");
}// Socket::UDPConnection GetDestination }// Socket::UDPConnection GetDestination
/// Returns the port number of the receiving end of this socket. /// Returns the port number of the receiving end of this socket.
/// Returns 0 on error. /// Returns 0 on error.
uint32_t Socket::UDPConnection::getDestPort() const{ uint32_t Socket::UDPConnection::getDestPort() const{
if (!destAddr || !destAddr_size){return 0;} if (!destAddr || !destAddr_size){return 0;}
if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6){return ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port);} if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6){
if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET){return ntohs(((struct sockaddr_in *)destAddr)->sin_port);} return ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port);
}
if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET){
return ntohs(((struct sockaddr_in *)destAddr)->sin_port);
}
return 0; return 0;
} }
@ -1509,7 +1520,7 @@ void Socket::UDPConnection::SendNow(const char *sdata, size_t len){
if (r > 0){ if (r > 0){
up += r; up += r;
}else{ }else{
DEBUG_MSG(DLVL_FAIL, "Could not send UDP data through %d: %s", sock, strerror(errno)); FAIL_MSG("Could not send UDP data through %d: %s", sock, strerror(errno));
} }
} }
@ -1517,12 +1528,12 @@ void Socket::UDPConnection::SendNow(const char *sdata, size_t len){
/// If that fails, returns zero. /// If that fails, returns zero.
/// \arg port Port to bind to, required. /// \arg port Port to bind to, required.
/// \arg iface Interface address to listen for packets on (may be multicast address) /// \arg iface Interface address to listen for packets on (may be multicast address)
/// \arg multicastInterfaces Comma-separated list of interfaces to listen on for multicast packets. Optional, left out means automatically chosen /// \arg multicastInterfaces Comma-separated list of interfaces to listen on for multicast packets.
/// by kernel. /// Optional, left out means automatically chosen by kernel. \return Actually bound port number, or
/// \return Actually bound port number, or zero on error. /// zero on error.
uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::string &multicastInterfaces){ uint16_t Socket::UDPConnection::bind(int port, std::string iface,
const std::string &multicastInterfaces){
close(); // we open a new socket for each attempt close(); // we open a new socket for each attempt
int result = 0;
int addr_ret; int addr_ret;
bool multicast = false; bool multicast = false;
struct addrinfo hints, *addr_result, *rp; struct addrinfo hints, *addr_result, *rp;
@ -1559,13 +1570,13 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str
if (sock == -1){continue;} if (sock == -1){continue;}
char human_addr[INET6_ADDRSTRLEN]; char human_addr[INET6_ADDRSTRLEN];
char human_port[16]; char human_port[16];
getnameinfo(rp->ai_addr, rp->ai_addrlen, human_addr, INET6_ADDRSTRLEN, human_port, 16, NI_NUMERICHOST | NI_NUMERICSERV); getnameinfo(rp->ai_addr, rp->ai_addrlen, human_addr, INET6_ADDRSTRLEN, human_port, 16,
NI_NUMERICHOST | NI_NUMERICSERV);
MEDIUM_MSG("Attempting bind to %s:%s (%s)", human_addr, human_port, addrFam(rp->ai_family)); MEDIUM_MSG("Attempting bind to %s:%s (%s)", human_addr, human_port, addrFam(rp->ai_family));
family = rp->ai_family; family = rp->ai_family;
hints.ai_family = family; hints.ai_family = family;
if (family == AF_INET6){ if (family == AF_INET6){
sockaddr_in6 *addr6 = (sockaddr_in6 *)(rp->ai_addr); sockaddr_in6 *addr6 = (sockaddr_in6 *)(rp->ai_addr);
result = ntohs(addr6->sin6_port);
if (memcmp((char *)&(addr6->sin6_addr), "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){ if (memcmp((char *)&(addr6->sin6_addr), "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){
// IPv6-mapped IPv4 address - 13th byte ([12]) holds the first IPv4 byte // IPv6-mapped IPv4 address - 13th byte ([12]) holds the first IPv4 byte
multicast = (((char *)&(addr6->sin6_addr))[12] & 0xF0) == 0xE0; multicast = (((char *)&(addr6->sin6_addr))[12] & 0xF0) == 0xE0;
@ -1575,7 +1586,6 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str
} }
}else{ }else{
sockaddr_in *addr4 = (sockaddr_in *)(rp->ai_addr); sockaddr_in *addr4 = (sockaddr_in *)(rp->ai_addr);
result = ntohs(addr4->sin_port);
// multicast has a "1110" bit prefix // multicast has a "1110" bit prefix
multicast = (((char *)&(addr4->sin_addr))[0] & 0xF0) == 0xE0; multicast = (((char *)&(addr4->sin_addr))[0] & 0xF0) == 0xE0;
} }
@ -1586,14 +1596,14 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str
} }
} }
if (::bind(sock, rp->ai_addr, rp->ai_addrlen) == 0){ if (::bind(sock, rp->ai_addr, rp->ai_addrlen) == 0){
//get port number // get port number
struct sockaddr_storage fin_addr; struct sockaddr_storage fin_addr;
socklen_t alen = sizeof(fin_addr); socklen_t alen = sizeof(fin_addr);
if (getsockname(sock, (struct sockaddr*)&fin_addr, &alen) == 0){ if (getsockname(sock, (struct sockaddr *)&fin_addr, &alen) == 0){
if (family == AF_INET6){ if (family == AF_INET6){
portNo = ntohs(((struct sockaddr_in6*)&fin_addr)->sin6_port); portNo = ntohs(((struct sockaddr_in6 *)&fin_addr)->sin6_port);
}else{ }else{
portNo = ntohs(((struct sockaddr_in*)&fin_addr)->sin_port); portNo = ntohs(((struct sockaddr_in *)&fin_addr)->sin_port);
} }
} }
INFO_MSG("UDP bind success on %s:%u (%s)", human_addr, portNo, addrFam(rp->ai_family)); INFO_MSG("UDP bind success on %s:%u (%s)", human_addr, portNo, addrFam(rp->ai_family));
@ -1626,11 +1636,11 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str
if (!multicastInterfaces.length()){ if (!multicastInterfaces.length()){
if (family == AF_INET6){ if (family == AF_INET6){
memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6 *)resmulti->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr)); memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6 *)resmulti->ai_addr)->sin6_addr,
sizeof(mreq6.ipv6mr_multiaddr));
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0){ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0){
FAIL_MSG("Unable to register for IPv6 multicast on all interfaces: %s", strerror(errno)); FAIL_MSG("Unable to register for IPv6 multicast on all interfaces: %s", strerror(errno));
close(); close();
result = -1;
} }
}else{ }else{
mreq4.imr_multiaddr = ((sockaddr_in *)resmulti->ai_addr)->sin_addr; mreq4.imr_multiaddr = ((sockaddr_in *)resmulti->ai_addr)->sin_addr;
@ -1638,15 +1648,16 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0){ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0){
FAIL_MSG("Unable to register for IPv4 multicast on all interfaces: %s", strerror(errno)); FAIL_MSG("Unable to register for IPv4 multicast on all interfaces: %s", strerror(errno));
close(); close();
result = -1;
} }
} }
}else{ }else{
size_t nxtPos = std::string::npos; size_t nxtPos = std::string::npos;
bool atLeastOne = false; bool atLeastOne = false;
for (size_t loc = 0; loc != std::string::npos; loc = (nxtPos == std::string::npos ? nxtPos : nxtPos + 1)){ for (size_t loc = 0; loc != std::string::npos;
loc = (nxtPos == std::string::npos ? nxtPos : nxtPos + 1)){
nxtPos = multicastInterfaces.find(',', loc); nxtPos = multicastInterfaces.find(',', loc);
std::string curIface = multicastInterfaces.substr(loc, (nxtPos == std::string::npos ? nxtPos : nxtPos - loc)); std::string curIface =
multicastInterfaces.substr(loc, (nxtPos == std::string::npos ? nxtPos : nxtPos - loc));
// do a bit of filtering for IPv6, removing the []-braces, if any // do a bit of filtering for IPv6, removing the []-braces, if any
if (curIface[0] == '['){ if (curIface[0] == '['){
if (curIface[curIface.size() - 1] == ']'){ if (curIface[curIface.size() - 1] == ']'){
@ -1658,34 +1669,38 @@ uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::str
if (family == AF_INET6){ if (family == AF_INET6){
INFO_MSG("Registering for IPv6 multicast on interface %s", curIface.c_str()); INFO_MSG("Registering for IPv6 multicast on interface %s", curIface.c_str());
if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){ if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){
WARN_MSG("Unable to resolve IPv6 interface address %s: %s", curIface.c_str(), gai_strerror(addr_ret)); WARN_MSG("Unable to resolve IPv6 interface address %s: %s", curIface.c_str(),
gai_strerror(addr_ret));
continue; continue;
} }
memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6 *)resmulti->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr)); memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6 *)resmulti->ai_addr)->sin6_addr,
sizeof(mreq6.ipv6mr_multiaddr));
mreq6.ipv6mr_interface = ((sockaddr_in6 *)reslocal->ai_addr)->sin6_scope_id; mreq6.ipv6mr_interface = ((sockaddr_in6 *)reslocal->ai_addr)->sin6_scope_id;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0){ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0){
FAIL_MSG("Unable to register for IPv6 multicast on interface %s (%u): %s", curIface.c_str(), FAIL_MSG("Unable to register for IPv6 multicast on interface %s (%u): %s",
((sockaddr_in6 *)reslocal->ai_addr)->sin6_scope_id, strerror(errno)); curIface.c_str(), ((sockaddr_in6 *)reslocal->ai_addr)->sin6_scope_id,
strerror(errno));
}else{ }else{
atLeastOne = true; atLeastOne = true;
} }
}else{ }else{
INFO_MSG("Registering for IPv4 multicast on interface %s", curIface.c_str()); INFO_MSG("Registering for IPv4 multicast on interface %s", curIface.c_str());
if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){ if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){
WARN_MSG("Unable to resolve IPv4 interface address %s: %s", curIface.c_str(), gai_strerror(addr_ret)); WARN_MSG("Unable to resolve IPv4 interface address %s: %s", curIface.c_str(),
gai_strerror(addr_ret));
continue; continue;
} }
mreq4.imr_multiaddr = ((sockaddr_in *)resmulti->ai_addr)->sin_addr; mreq4.imr_multiaddr = ((sockaddr_in *)resmulti->ai_addr)->sin_addr;
mreq4.imr_interface = ((sockaddr_in *)reslocal->ai_addr)->sin_addr; mreq4.imr_interface = ((sockaddr_in *)reslocal->ai_addr)->sin_addr;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0){ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0){
FAIL_MSG("Unable to register for IPv4 multicast on interface %s: %s", curIface.c_str(), strerror(errno)); FAIL_MSG("Unable to register for IPv4 multicast on interface %s: %s", curIface.c_str(),
strerror(errno));
}else{ }else{
atLeastOne = true; atLeastOne = true;
} }
} }
if (!atLeastOne){ if (!atLeastOne){
close(); close();
result = -1;
} }
freeaddrinfo(reslocal); // free resolved interface addr freeaddrinfo(reslocal); // free resolved interface addr
}// loop over all interfaces }// loop over all interfaces
@ -1728,10 +1743,9 @@ bool Socket::UDPConnection::Receive(){
down += r; down += r;
data_len = r; data_len = r;
return true; return true;
}else{ }
data_len = 0; data_len = 0;
return false; return false;
}
} }
int Socket::UDPConnection::getSock(){ int Socket::UDPConnection::getSock(){

View file

@ -1,44 +1,45 @@
/// \file stream.cpp /// \file stream.cpp
/// Utilities for handling streams. /// Utilities for handling streams.
#include "stream.h"
#include "config.h"
#include "defines.h"
#include "dtsc.h"
#include "json.h"
#include "procs.h"
#include "shared_memory.h"
#include "socket.h"
#include "triggers.h" //LTS
#include <semaphore.h>
#include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include "json.h"
#include "stream.h"
#include "procs.h"
#include "config.h"
#include "socket.h"
#include "defines.h"
#include "shared_memory.h"
#include "dtsc.h"
#include "triggers.h"//LTS
/// Calls strftime using the current local time, returning empty string on any error. /// Calls strftime using the current local time, returning empty string on any error.
static std::string strftime_now(const std::string& format) { static std::string strftime_now(const std::string &format){
time_t rawtime; time_t rawtime;
char buffer[80]; char buffer[80];
time(&rawtime); time(&rawtime);
struct tm timebuf; struct tm timebuf;
struct tm* timeinfo = localtime_r(&rawtime, &timebuf); struct tm *timeinfo = localtime_r(&rawtime, &timebuf);
if (!timeinfo || !strftime(buffer, 80, format.c_str(), timeinfo)){return "";} if (!timeinfo || !strftime(buffer, 80, format.c_str(), timeinfo)){return "";}
return buffer; return buffer;
} }
///Replaces any occurrences of 'from' with 'to' in 'str'. /// Replaces any occurrences of 'from' with 'to' in 'str'.
static void replace(std::string& str, const std::string& from, const std::string& to) { static void replace(std::string &str, const std::string &from, const std::string &to){
if (from.empty()){return;} if (from.empty()){return;}
size_t start_pos = 0; size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) { while ((start_pos = str.find(from, start_pos)) != std::string::npos){
str.replace(start_pos, from.length(), to); str.replace(start_pos, from.length(), to);
start_pos += to.length(); start_pos += to.length();
} }
} }
///Replaces all stream-related variables in the given 'str' with their values. /// Replaces all stream-related variables in the given 'str' with their values.
void Util::streamVariables(std::string &str, const std::string & streamname, const std::string & source) { void Util::streamVariables(std::string &str, const std::string &streamname,
const std::string &source){
replace(str, "$source", source); replace(str, "$source", source);
replace(str, "$datetime", "$year.$month.$day.$hour.$minute.$second"); replace(str, "$datetime", "$year.$month.$day.$hour.$minute.$second");
replace(str, "$day", strftime_now("%d")); replace(str, "$day", strftime_now("%d"));
@ -50,11 +51,11 @@ void Util::streamVariables(std::string &str, const std::string & streamname, con
replace(str, "$stream", streamname); replace(str, "$stream", streamname);
if (streamname.find('+') != std::string::npos){ if (streamname.find('+') != std::string::npos){
std::string strbase = streamname.substr(0, streamname.find('+')); std::string strbase = streamname.substr(0, streamname.find('+'));
std::string strext = streamname.substr(streamname.find('+')+1); std::string strext = streamname.substr(streamname.find('+') + 1);
replace(str, "$basename", strbase); replace(str, "$basename", strbase);
replace(str, "$wildcard", strext); replace(str, "$wildcard", strext);
if (strext.size()){ if (strext.size()){
replace(str, "$pluswildcard", "+"+strext); replace(str, "$pluswildcard", "+" + strext);
}else{ }else{
replace(str, "$pluswildcard", ""); replace(str, "$pluswildcard", "");
} }
@ -65,30 +66,25 @@ void Util::streamVariables(std::string &str, const std::string & streamname, con
} }
} }
std::string Util::getTmpFolder() { std::string Util::getTmpFolder(){
std::string dir; std::string dir;
char * tmp_char = 0; char *tmp_char = 0;
if (!tmp_char) { if (!tmp_char){tmp_char = getenv("TMP");}
tmp_char = getenv("TMP"); if (!tmp_char){tmp_char = getenv("TEMP");}
} if (!tmp_char){tmp_char = getenv("TMPDIR");}
if (!tmp_char) { if (tmp_char){
tmp_char = getenv("TEMP");
}
if (!tmp_char) {
tmp_char = getenv("TMPDIR");
}
if (tmp_char) {
dir = tmp_char; dir = tmp_char;
dir += "/mist"; dir += "/mist";
} else { }else{
#if defined(_WIN32) || defined(_CYGWIN_) #if defined(_WIN32) || defined(_CYGWIN_)
dir = "C:/tmp/mist"; dir = "C:/tmp/mist";
#else #else
dir = "/tmp/mist"; dir = "/tmp/mist";
#endif #endif
} }
if (access(dir.c_str(), 0) != 0) { if (access(dir.c_str(), 0) != 0){
mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); //attempt to create mist folder - ignore failures mkdir(dir.c_str(),
S_IRWXU | S_IRWXG | S_IRWXO); // attempt to create mist folder - ignore failures
} }
return dir + "/"; return dir + "/";
} }
@ -97,36 +93,37 @@ std::string Util::getTmpFolder() {
/// letters to lowercase. If a '?' character is found, everything following /// letters to lowercase. If a '?' character is found, everything following
/// that character is deleted. The original string is modified. If a '+' or space /// that character is deleted. The original string is modified. If a '+' or space
/// exists, then only the part before that is sanitized. /// exists, then only the part before that is sanitized.
void Util::sanitizeName(std::string & streamname) { void Util::sanitizeName(std::string &streamname){
//strip anything that isn't numbers, digits or underscores // strip anything that isn't numbers, digits or underscores
size_t index = streamname.find_first_of("+ "); size_t index = streamname.find_first_of("+ ");
if(index != std::string::npos){ if (index != std::string::npos){
std::string preplus = streamname.substr(0,index); std::string preplus = streamname.substr(0, index);
sanitizeName(preplus); sanitizeName(preplus);
std::string postplus = streamname.substr(index+1); std::string postplus = streamname.substr(index + 1);
if (postplus.find('?') != std::string::npos){ if (postplus.find('?') != std::string::npos){
postplus = postplus.substr(0, (postplus.find('?'))); postplus = postplus.substr(0, (postplus.find('?')));
} }
streamname = preplus+"+"+postplus; streamname = preplus + "+" + postplus;
return; return;
} }
for (std::string::iterator i = streamname.end() - 1; i >= streamname.begin(); --i) { for (std::string::iterator i = streamname.end() - 1; i >= streamname.begin(); --i){
if (*i == '?') { if (*i == '?'){
streamname.erase(i, streamname.end()); streamname.erase(i, streamname.end());
break; break;
} }
if ( !isalpha( *i) && !isdigit( *i) && *i != '_' && *i != '.'){ if (!isalpha(*i) && !isdigit(*i) && *i != '_' && *i != '.'){
streamname.erase(i); streamname.erase(i);
} else { }else{
*i = tolower(*i); *i = tolower(*i);
} }
} }
} }
JSON::Value Util::getStreamConfig(const std::string & streamname){ JSON::Value Util::getStreamConfig(const std::string &streamname){
JSON::Value result; JSON::Value result;
if (streamname.size() > 100){ if (streamname.size() > 100){
FAIL_MSG("Stream opening denied: %s is longer than 100 characters (%lu).", streamname.c_str(), streamname.size()); FAIL_MSG("Stream opening denied: %s is longer than 100 characters (%lu).", streamname.c_str(),
streamname.size());
return result; return result;
} }
std::string smp = streamname.substr(0, streamname.find_first_of("+ ")); std::string smp = streamname.substr(0, streamname.find_first_of("+ "));
@ -142,7 +139,7 @@ JSON::Value Util::getStreamConfig(const std::string & streamname){
return stream_cfg.asJSON(); return stream_cfg.asJSON();
} }
DTSC::Meta Util::getStreamMeta(const std::string & streamname){ DTSC::Meta Util::getStreamMeta(const std::string &streamname){
DTSC::Meta ret; DTSC::Meta ret;
char pageId[NAME_BUFFER_SIZE]; char pageId[NAME_BUFFER_SIZE];
snprintf(pageId, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, streamname.c_str()); snprintf(pageId, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, streamname.c_str());
@ -158,12 +155,12 @@ DTSC::Meta Util::getStreamMeta(const std::string & streamname){
/// Checks if the given streamname has an active input serving it. Returns true if this is the case. /// Checks if the given streamname has an active input serving it. Returns true if this is the case.
/// Assumes the streamname has already been through sanitizeName()! /// Assumes the streamname has already been through sanitizeName()!
bool Util::streamAlive(std::string & streamname){ bool Util::streamAlive(std::string &streamname){
char semName[NAME_BUFFER_SIZE]; char semName[NAME_BUFFER_SIZE];
snprintf(semName, NAME_BUFFER_SIZE, SEM_INPUT, streamname.c_str()); snprintf(semName, NAME_BUFFER_SIZE, SEM_INPUT, streamname.c_str());
IPC::semaphore playerLock(semName, O_RDWR, ACCESSPERMS, 1, true); IPC::semaphore playerLock(semName, O_RDWR, ACCESSPERMS, 1, true);
if (!playerLock){return false;} if (!playerLock){return false;}
if (!playerLock.tryWait()) { if (!playerLock.tryWait()){
playerLock.close(); playerLock.close();
return true; return true;
}else{ }else{
@ -176,31 +173,32 @@ bool Util::streamAlive(std::string & streamname){
/// Assures the input for the given stream name is active. /// Assures the input for the given stream name is active.
/// Does stream name sanitation first, followed by a stream name length check (<= 100 chars). /// Does stream name sanitation first, followed by a stream name length check (<= 100 chars).
/// Then, checks if an input is already active by running streamAlive(). If yes, return true. /// Then, checks if an input is already active by running streamAlive(). If yes, return true.
/// If no, loads up the server configuration and attempts to start the given stream according to current configuration. /// If no, loads up the server configuration and attempts to start the given stream according to
/// At this point, fails and aborts if MistController isn't running. /// current configuration. At this point, fails and aborts if MistController isn't running.
bool Util::startInput(std::string streamname, std::string filename, bool forkFirst, bool isProvider, const std::map<std::string, std::string> & overrides, pid_t * spawn_pid ) { bool Util::startInput(std::string streamname, std::string filename, bool forkFirst, bool isProvider,
const std::map<std::string, std::string> &overrides, pid_t *spawn_pid){
sanitizeName(streamname); sanitizeName(streamname);
if (streamname.size() > 100){ if (streamname.size() > 100){
FAIL_MSG("Stream opening denied: %s is longer than 100 characters (%lu).", streamname.c_str(), streamname.size()); FAIL_MSG("Stream opening denied: %s is longer than 100 characters (%lu).", streamname.c_str(),
streamname.size());
return false; return false;
} }
//Check if the stream is already active. // Check if the stream is already active.
//If yes, don't activate again to prevent duplicate inputs. // If yes, don't activate again to prevent duplicate inputs.
//It's still possible a duplicate starts anyway, this is caught in the inputs initializer. // It's still possible a duplicate starts anyway, this is caught in the inputs initializer.
//Note: this uses the _whole_ stream name, including + (if any). // Note: this uses the _whole_ stream name, including + (if any).
//This means "test+a" and "test+b" have separate locks and do not interact with each other. // This means "test+a" and "test+b" have separate locks and do not interact with each other.
uint8_t streamStat = getStreamStatus(streamname); uint8_t streamStat = getStreamStatus(streamname);
//Wait for a maximum of 240 x 250ms sleeps = 60 seconds // Wait for a maximum of 240 x 250ms sleeps = 60 seconds
size_t sleeps = 0; size_t sleeps = 0;
while (++sleeps < 240 && streamStat != STRMSTAT_OFF && streamStat != STRMSTAT_READY && (!isProvider || streamStat != STRMSTAT_WAIT)){ while (++sleeps < 240 && streamStat != STRMSTAT_OFF && streamStat != STRMSTAT_READY &&
if (streamStat == STRMSTAT_BOOT && overrides.count("throughboot")){ (!isProvider || streamStat != STRMSTAT_WAIT)){
break; if (streamStat == STRMSTAT_BOOT && overrides.count("throughboot")){break;}
}
Util::sleep(250); Util::sleep(250);
streamStat = getStreamStatus(streamname); streamStat = getStreamStatus(streamname);
} }
if (streamAlive(streamname) && !overrides.count("alwaysStart")){ if (streamAlive(streamname) && !overrides.count("alwaysStart")){
DEBUG_MSG(DLVL_MEDIUM, "Stream %s already active; continuing", streamname.c_str()); MEDIUM_MSG("Stream %s already active; continuing", streamname.c_str());
return true; return true;
} }
@ -219,34 +217,29 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
} }
*/ */
//Find stream base name // Find stream base name
std::string smp = streamname.substr(0, streamname.find_first_of("+ ")); std::string smp = streamname.substr(0, streamname.find_first_of("+ "));
//check if base name (everything before + or space) exists // check if base name (everything before + or space) exists
const JSON::Value stream_cfg = getStreamConfig(streamname); const JSON::Value stream_cfg = getStreamConfig(streamname);
if (!stream_cfg){ if (!stream_cfg){
DEBUG_MSG(DLVL_HIGH, "Stream %s not configured - attempting to ignore", streamname.c_str()); HIGH_MSG("Stream %s not configured - attempting to ignore", streamname.c_str());
} }
/*LTS-START*/ /*LTS-START*/
if (!filename.size()){ if (!filename.size()){
if (stream_cfg && stream_cfg.isMember("hardlimit_active")) { if (stream_cfg && stream_cfg.isMember("hardlimit_active")){return false;}
return false; if (Triggers::shouldTrigger("STREAM_LOAD", smp)){
if (!Triggers::doTrigger("STREAM_LOAD", streamname, smp)){return false;}
} }
if(Triggers::shouldTrigger("STREAM_LOAD", smp)){ if (Triggers::shouldTrigger("STREAM_SOURCE", smp)){
if (!Triggers::doTrigger("STREAM_LOAD", streamname, smp)){
return false;
}
}
if(Triggers::shouldTrigger("STREAM_SOURCE", smp)){
Triggers::doTrigger("STREAM_SOURCE", streamname, smp, false, filename); Triggers::doTrigger("STREAM_SOURCE", streamname, smp, false, filename);
} }
} }
/*LTS-END*/ /*LTS-END*/
// Only use configured source if not manually overridden. Abort if no config is available.
//Only use configured source if not manually overridden. Abort if no config is available.
if (!filename.size()){ if (!filename.size()){
if (!stream_cfg){ if (!stream_cfg){
DEBUG_MSG(DLVL_MEDIUM, "Stream %s not configured, no source manually given, cannot start", streamname.c_str()); MEDIUM_MSG("Stream %s not configured, no source manually given, cannot start", streamname.c_str());
return false; return false;
} }
filename = stream_cfg["source"].asStringRef(); filename = stream_cfg["source"].asStringRef();
@ -256,62 +249,59 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
const JSON::Value input = getInputBySource(filename, isProvider); const JSON::Value input = getInputBySource(filename, isProvider);
if (!input){return false;} if (!input){return false;}
//copy the necessary arguments to separate storage so we can unlock the config semaphore safely // copy the necessary arguments to separate storage so we can unlock the config semaphore safely
std::map<std::string, std::string> str_args; std::map<std::string, std::string> str_args;
//check required parameters // check required parameters
if (input.isMember("required")){ if (input.isMember("required")){
jsonForEachConst(input["required"], prm){ jsonForEachConst(input["required"], prm){
const std::string opt = (*prm)["option"].asStringRef(); const std::string opt = (*prm)["option"].asStringRef();
//check for overrides // check for overrides
if (overrides.count(opt)){ if (overrides.count(opt)){
str_args[opt] = overrides.at(opt); str_args[opt] = overrides.at(opt);
}else{ }else{
if (!stream_cfg.isMember(prm.key())){ if (!stream_cfg.isMember(prm.key())){
FAIL_MSG("Required parameter %s for stream %s missing", prm.key().c_str(), streamname.c_str()); FAIL_MSG("Required parameter %s for stream %s missing", prm.key().c_str(),
streamname.c_str());
return false; return false;
} }
str_args[opt] = stream_cfg[opt].asStringRef(); str_args[opt] = stream_cfg[opt].asStringRef();
} }
} }
} }
//check optional parameters // check optional parameters
if (input.isMember("optional")){ if (input.isMember("optional")){
jsonForEachConst(input["optional"], prm){ jsonForEachConst(input["optional"], prm){
const std::string opt = (*prm)["option"].asStringRef(); const std::string opt = (*prm)["option"].asStringRef();
//check for overrides // check for overrides
if (overrides.count(opt)){ if (overrides.count(opt)){
str_args[opt] = overrides.at(opt); str_args[opt] = overrides.at(opt);
}else{ }else{
if (stream_cfg.isMember(prm.key())){ if (stream_cfg.isMember(prm.key())){str_args[opt] = stream_cfg[prm.key()].asStringRef();}
str_args[opt] = stream_cfg[prm.key()].asStringRef();
}
}
if (!prm->isMember("type") && str_args.count(opt)){
str_args[opt] = "";
} }
if (!prm->isMember("type") && str_args.count(opt)){str_args[opt] = "";}
} }
} }
if (isProvider){ if (isProvider){
//Set environment variable so we can know if we have a provider when re-exec'ing. // Set environment variable so we can know if we have a provider when re-exec'ing.
setenv("MISTPROVIDER", "1", 1); setenv("MISTPROVIDER", "1", 1);
} }
std::string player_bin = Util::getMyPath() + "MistIn" + input["name"].asStringRef(); std::string player_bin = Util::getMyPath() + "MistIn" + input["name"].asStringRef();
INFO_MSG("Starting %s -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str()); INFO_MSG("Starting %s -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str());
char * argv[30] = {(char *)player_bin.c_str(), (char *)"-s", (char *)streamname.c_str(), (char *)filename.c_str()}; char *argv[30] ={(char *)player_bin.c_str(), (char *)"-s", (char *)streamname.c_str(),
(char *)filename.c_str()};
int argNum = 3; int argNum = 3;
std::string debugLvl; std::string debugLvl;
if (Util::Config::printDebugLevel != DEBUG && !str_args.count("--debug")){ if (Util::Config::printDebugLevel != DEBUG && !str_args.count("--debug")){
debugLvl = JSON::Value((long long)Util::Config::printDebugLevel).asString(); debugLvl = JSON::Value(Util::Config::printDebugLevel).asString();
argv[++argNum] = (char *)"--debug"; argv[++argNum] = (char *)"--debug";
argv[++argNum] = (char *)debugLvl.c_str(); argv[++argNum] = (char *)debugLvl.c_str();
} }
for (std::map<std::string, std::string>::iterator it = str_args.begin(); it != str_args.end(); ++it){ for (std::map<std::string, std::string>::iterator it = str_args.begin(); it != str_args.end();
++it){
argv[++argNum] = (char *)it->first.c_str(); argv[++argNum] = (char *)it->first.c_str();
if (it->second.size()){ if (it->second.size()){argv[++argNum] = (char *)it->second.c_str();}
argv[++argNum] = (char *)it->second.c_str();
}
} }
argv[++argNum] = (char *)0; argv[++argNum] = (char *)0;
@ -319,9 +309,9 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
int pid = 0; int pid = 0;
if (forkFirst){ if (forkFirst){
DEBUG_MSG(DLVL_DONTEVEN, "Forking"); DONTEVEN_MSG("Forking");
pid = fork(); pid = fork();
if (pid == -1) { if (pid == -1){
FAIL_MSG("Forking process for stream %s failed: %s", streamname.c_str(), strerror(errno)); FAIL_MSG("Forking process for stream %s failed: %s", streamname.c_str(), strerror(errno));
return false; return false;
} }
@ -330,15 +320,16 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
Util::Procs::remember(pid); Util::Procs::remember(pid);
} }
}else{ }else{
DEBUG_MSG(DLVL_DONTEVEN, "Not forking"); DONTEVEN_MSG("Not forking");
} }
if (pid == 0){ if (pid == 0){
Socket::Connection io(0, 1); Socket::Connection io(0, 1);
io.drop(); io.drop();
DEBUG_MSG(DLVL_DONTEVEN, "execvp"); DONTEVEN_MSG("execvp");
execvp(argv[0], argv); execvp(argv[0], argv);
FAIL_MSG("Starting process %s for stream %s failed: %s", argv[0], streamname.c_str(), strerror(errno)); FAIL_MSG("Starting process %s for stream %s failed: %s", argv[0], streamname.c_str(),
strerror(errno));
_exit(42); _exit(42);
}else if (spawn_pid != NULL){ }else if (spawn_pid != NULL){
*spawn_pid = pid; *spawn_pid = pid;
@ -359,16 +350,16 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider){ JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider){
JSON::Value ret; JSON::Value ret;
//Attempt to load up configuration and find this stream // Attempt to load up configuration and find this stream
Util::DTSCShmReader rCapa(SHM_CAPA); Util::DTSCShmReader rCapa(SHM_CAPA);
DTSC::Scan inputs = rCapa.getMember("inputs"); DTSC::Scan inputs = rCapa.getMember("inputs");
//Abort if not available // Abort if not available
if (!inputs){ if (!inputs){
FAIL_MSG("Capabilities not available, aborting! Is MistController running?"); FAIL_MSG("Capabilities not available, aborting! Is MistController running?");
return false; return false;
} }
//check in curConf for <naam>-priority/source_match // check in curConf for <naam>-priority/source_match
bool selected = false; bool selected = false;
long long int curPrio = -1; long long int curPrio = -1;
DTSC::Scan input; DTSC::Scan input;
@ -377,16 +368,18 @@ JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider)
for (unsigned int i = 0; i < input_size; ++i){ for (unsigned int i = 0; i < input_size; ++i){
DTSC::Scan tmp_input = inputs.getIndice(i); DTSC::Scan tmp_input = inputs.getIndice(i);
//if match voor current stream && priority is hoger dan wat we al hebben // if match voor current stream && priority is hoger dan wat we al hebben
if (tmp_input.getMember("source_match") && curPrio < tmp_input.getMember("priority").asInt()){ if (tmp_input.getMember("source_match") && curPrio < tmp_input.getMember("priority").asInt()){
if (tmp_input.getMember("source_match").getSize()){ if (tmp_input.getMember("source_match").getSize()){
for(unsigned int j = 0; j < tmp_input.getMember("source_match").getSize(); ++j){ for (unsigned int j = 0; j < tmp_input.getMember("source_match").getSize(); ++j){
std::string source = tmp_input.getMember("source_match").getIndice(j).asString(); std::string source = tmp_input.getMember("source_match").getIndice(j).asString();
std::string front = source.substr(0,source.find('*')); std::string front = source.substr(0, source.find('*'));
std::string back = source.substr(source.find('*')+1); std::string back = source.substr(source.find('*') + 1);
MEDIUM_MSG("Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(), tmp_input.getMember("name").asString().c_str(), source.c_str()); MEDIUM_MSG("Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(),
tmp_input.getMember("name").asString().c_str(), source.c_str());
if (filename.substr(0,front.size()) == front && filename.substr(filename.size()-back.size()) == back){ if (filename.substr(0, front.size()) == front &&
filename.substr(filename.size() - back.size()) == back){
if (tmp_input.getMember("non-provider") && !isProvider){ if (tmp_input.getMember("non-provider") && !isProvider){
noProviderNoPick = true; noProviderNoPick = true;
continue; continue;
@ -398,11 +391,13 @@ JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider)
} }
}else{ }else{
std::string source = tmp_input.getMember("source_match").asString(); std::string source = tmp_input.getMember("source_match").asString();
std::string front = source.substr(0,source.find('*')); std::string front = source.substr(0, source.find('*'));
std::string back = source.substr(source.find('*')+1); std::string back = source.substr(source.find('*') + 1);
MEDIUM_MSG("Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(), tmp_input.getMember("name").asString().c_str(), source.c_str()); MEDIUM_MSG("Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(),
tmp_input.getMember("name").asString().c_str(), source.c_str());
if (filename.substr(0,front.size()) == front && filename.substr(filename.size()-back.size()) == back){ if (filename.substr(0, front.size()) == front &&
filename.substr(filename.size() - back.size()) == back){
if (tmp_input.getMember("non-provider") && !isProvider){ if (tmp_input.getMember("non-provider") && !isProvider){
noProviderNoPick = true; noProviderNoPick = true;
continue; continue;
@ -412,7 +407,6 @@ JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider)
input = tmp_input; input = tmp_input;
} }
} }
} }
} }
if (!selected){ if (!selected){
@ -427,14 +421,13 @@ JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider)
return ret; return ret;
} }
/// Attempt to start a push for streamname to target. /// Attempt to start a push for streamname to target.
/// streamname MUST be pre-sanitized /// streamname MUST be pre-sanitized
/// target gets variables replaced and may be altered by the PUSH_OUT_START trigger response. /// target gets variables replaced and may be altered by the PUSH_OUT_START trigger response.
/// Attempts to match the altered target to an output that can push to it. /// Attempts to match the altered target to an output that can push to it.
pid_t Util::startPush(const std::string & streamname, std::string & target) { pid_t Util::startPush(const std::string &streamname, std::string &target){
if (Triggers::shouldTrigger("PUSH_OUT_START", streamname)) { if (Triggers::shouldTrigger("PUSH_OUT_START", streamname)){
std::string payload = streamname+"\n"+target; std::string payload = streamname + "\n" + target;
std::string filepath_response; std::string filepath_response;
Triggers::doTrigger("PUSH_OUT_START", payload, streamname.c_str(), false, filepath_response); Triggers::doTrigger("PUSH_OUT_START", payload, streamname.c_str(), false, filepath_response);
target = filepath_response; target = filepath_response;
@ -447,7 +440,7 @@ pid_t Util::startPush(const std::string & streamname, std::string & target) {
// The target can hold variables like current time etc // The target can hold variables like current time etc
streamVariables(target, streamname); streamVariables(target, streamname);
//Attempt to load up configuration and find this stream // Attempt to load up configuration and find this stream
std::string output_bin = ""; std::string output_bin = "";
{ {
Util::DTSCShmReader rCapa(SHM_CAPA); Util::DTSCShmReader rCapa(SHM_CAPA);
@ -458,17 +451,19 @@ pid_t Util::startPush(const std::string & streamname, std::string & target) {
} }
std::string checkTarget = target.substr(0, target.rfind('?')); std::string checkTarget = target.substr(0, target.rfind('?'));
unsigned int outputs_size = outputs.getSize(); unsigned int outputs_size = outputs.getSize();
for (unsigned int i = 0; i<outputs_size && !output_bin.size(); ++i){ for (unsigned int i = 0; i < outputs_size && !output_bin.size(); ++i){
DTSC::Scan output = outputs.getIndice(i); DTSC::Scan output = outputs.getIndice(i);
if (output.getMember("push_urls")){ if (output.getMember("push_urls")){
unsigned int push_count = output.getMember("push_urls").getSize(); unsigned int push_count = output.getMember("push_urls").getSize();
for (unsigned int j = 0; j < push_count; ++j){ for (unsigned int j = 0; j < push_count; ++j){
std::string tar_match = output.getMember("push_urls").getIndice(j).asString(); std::string tar_match = output.getMember("push_urls").getIndice(j).asString();
std::string front = tar_match.substr(0,tar_match.find('*')); std::string front = tar_match.substr(0, tar_match.find('*'));
std::string back = tar_match.substr(tar_match.find('*')+1); std::string back = tar_match.substr(tar_match.find('*') + 1);
MEDIUM_MSG("Checking output %s: %s (%s)", outputs.getIndiceName(i).c_str(), output.getMember("name").asString().c_str(), checkTarget.c_str()); MEDIUM_MSG("Checking output %s: %s (%s)", outputs.getIndiceName(i).c_str(),
output.getMember("name").asString().c_str(), checkTarget.c_str());
if (checkTarget.substr(0,front.size()) == front && checkTarget.substr(checkTarget.size()-back.size()) == back){ if (checkTarget.substr(0, front.size()) == front &&
checkTarget.substr(checkTarget.size() - back.size()) == back){
output_bin = Util::getMyPath() + "MistOut" + output.getMember("name").asString(); output_bin = Util::getMyPath() + "MistOut" + output.getMember("name").asString();
break; break;
} }
@ -483,19 +478,14 @@ pid_t Util::startPush(const std::string & streamname, std::string & target) {
} }
INFO_MSG("Pushing %s to %s through %s", streamname.c_str(), target.c_str(), output_bin.c_str()); INFO_MSG("Pushing %s to %s through %s", streamname.c_str(), target.c_str(), output_bin.c_str());
// Start output. // Start output.
char* argv[] = { char *argv[] ={(char *)output_bin.c_str(), (char *)"--stream", (char *)streamname.c_str(),
(char*)output_bin.c_str(), (char *)target.c_str(), (char *)NULL};
(char*)"--stream", (char*)streamname.c_str(),
(char*)target.c_str(),
(char*)NULL
};
int stdErr = 2; int stdErr = 2;
return Util::Procs::StartPiped(argv, 0, 0, &stdErr); return Util::Procs::StartPiped(argv, 0, 0, &stdErr);
} }
uint8_t Util::getStreamStatus(const std::string & streamname){ uint8_t Util::getStreamStatus(const std::string &streamname){
char pageName[NAME_BUFFER_SIZE]; char pageName[NAME_BUFFER_SIZE];
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamname.c_str()); snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamname.c_str());
IPC::sharedPage streamStatus(pageName, 1, false, false); IPC::sharedPage streamStatus(pageName, 1, false, false);

View file

@ -61,8 +61,8 @@ namespace theora {
if (length < 7){ if (length < 7){
return false; return false;
} }
if (! newData[0] & 0x80){ if (!(newData[0] & 0x80)){
DEBUG_MSG(DLVL_FAIL, "newdata != 0x80: %.2X", newData[0]); FAIL_MSG("newdata != 0x80: %.2X", newData[0]);
return false; return false;
} }
if (memcmp(newData + 1, "theora", 6) != 0){ if (memcmp(newData + 1, "theora", 6) != 0){

View file

@ -29,15 +29,15 @@ void clock_gettime(int ign, struct timespec * ts) {
/// Will not sleep for longer than 10 minutes (600000ms). /// Will not sleep for longer than 10 minutes (600000ms).
/// If interrupted by signal, resumes sleep until at least ms milliseconds have passed. /// If interrupted by signal, resumes sleep until at least ms milliseconds have passed.
/// Can be slightly off (in positive direction only) depending on OS accuracy. /// Can be slightly off (in positive direction only) depending on OS accuracy.
void Util::wait(int ms){ void Util::wait(int64_t ms){
if (ms < 0) { if (ms < 0) {
return; return;
} }
if (ms > 600000) { if (ms > 600000) {
ms = 600000; ms = 600000;
} }
long long int start = getMS(); uint64_t start = getMS();
long long int now = start; uint64_t now = start;
while (now < start+ms){ while (now < start+ms){
sleep(start+ms-now); sleep(start+ms-now);
now = getMS(); now = getMS();
@ -49,7 +49,7 @@ void Util::wait(int ms){
/// Will not sleep for longer than 100 seconds (100000ms). /// Will not sleep for longer than 100 seconds (100000ms).
/// Can be interrupted early by a signal, no guarantee of minimum sleep time. /// Can be interrupted early by a signal, no guarantee of minimum sleep time.
/// Can be slightly off depending on OS accuracy. /// Can be slightly off depending on OS accuracy.
void Util::sleep(int ms) { void Util::sleep(int64_t ms) {
if (ms < 0) { if (ms < 0) {
return; return;
} }
@ -62,20 +62,20 @@ void Util::sleep(int ms) {
nanosleep(&T, 0); nanosleep(&T, 0);
} }
long long Util::getNTP() { uint64_t Util::getNTP() {
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return ((((long long int)t.tv_sec) + 2208988800ll) << 32) + (t.tv_nsec * 4.2949); return ((uint64_t)(t.tv_sec + 2208988800ull) << 32) + (t.tv_nsec * 4.2949);
} }
/// Gets the current time in milliseconds. /// Gets the current time in milliseconds.
long long int Util::getMS() { uint64_t Util::getMS() {
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return ((long long int)t.tv_sec) * 1000 + t.tv_nsec / 1000000; return (uint64_t)t.tv_sec * 1000 + t.tv_nsec / 1000000;
} }
long long int Util::bootSecs() { uint64_t Util::bootSecs() {
struct timespec t; struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t); clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec; return t.tv_sec;
@ -88,30 +88,30 @@ uint64_t Util::bootMS() {
} }
/// Gets the current time in microseconds. /// Gets the current time in microseconds.
long long unsigned int Util::getMicros() { uint64_t Util::getMicros() {
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return ((long long unsigned int)t.tv_sec) * 1000000 + t.tv_nsec / 1000; return (uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000;
} }
/// Gets the time difference in microseconds. /// Gets the time difference in microseconds.
long long unsigned int Util::getMicros(long long unsigned int previous) { uint64_t Util::getMicros(uint64_t previous) {
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return ((long long unsigned int)t.tv_sec) * 1000000 + t.tv_nsec / 1000 - previous; return (uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000 - previous;
} }
/// Gets the amount of seconds since 01/01/1970. /// Gets the amount of seconds since 01/01/1970.
long long int Util::epoch() { uint64_t Util::epoch() {
return time(0); return time(0);
} }
std::string Util::getUTCString(long long int epoch){ std::string Util::getUTCString(uint64_t epoch){
if (!epoch){epoch = time(0);} if (!epoch){epoch = time(0);}
time_t rawtime = epoch; time_t rawtime = epoch;
struct tm * ptm; struct tm * ptm;
ptm = gmtime(&rawtime); ptm = gmtime(&rawtime);
char result[20]; char result[20];
snprintf(result, 20, "%0.4d-%0.2d-%0.2dT%0.2d:%0.2d:%0.2d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); snprintf(result, 20, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
return std::string(result); return std::string(result);
} }

View file

@ -2,18 +2,19 @@
/// Utilities for handling time and timestamps. /// Utilities for handling time and timestamps.
#pragma once #pragma once
#include <stdint.h>
#include <string> #include <string>
#include <stdint.h> #include <stdint.h>
namespace Util { namespace Util {
void wait(int ms); ///< Sleeps for the indicated amount of milliseconds or longer. void wait(int64_t ms); ///< Sleeps for the indicated amount of milliseconds or longer.
void sleep(int ms); ///< Sleeps for roughly the indicated amount of milliseconds. void sleep(int64_t ms); ///< Sleeps for roughly the indicated amount of milliseconds.
long long int getMS(); ///< Gets the current time in milliseconds. uint64_t getMS(); ///< Gets the current time in milliseconds.
long long int bootSecs(); ///< Gets the current system uptime in seconds. uint64_t bootSecs(); ///< Gets the current system uptime in seconds.
uint64_t bootMS(); ///< Gets the current system uptime in milliseconds. uint64_t bootMS(); ///< Gets the current system uptime in milliseconds.
long long unsigned int getMicros();///<Gets the current time in microseconds. uint64_t getMicros();///<Gets the current time in microseconds
long long unsigned int getMicros(long long unsigned int previous);///<Gets the time difference in microseconds. uint64_t getMicros(uint64_t previous);///<Gets the time difference in microseconds.
long long int getNTP(); uint64_t getNTP();
long long int epoch(); ///< Gets the amount of seconds since 01/01/1970. uint64_t epoch(); ///< Gets the amount of seconds since 01/01/1970.
std::string getUTCString(long long int epoch = 0); std::string getUTCString(uint64_t epoch = 0);
} }

View file

@ -63,7 +63,7 @@ namespace TS {
} }
INFO_MSG("Skipping invalid TS packet..."); INFO_MSG("Skipping invalid TS packet...");
} }
FAIL_MSG("Failed to read a good packet @ %lld bytes", bPos); FAIL_MSG("Failed to read a good packet @ %" PRIu64 " bytes", bPos);
return false; return false;
} }
@ -499,7 +499,7 @@ namespace TS {
/// \return A character pointer to the internal packet buffer data /// \return A character pointer to the internal packet buffer data
const char * Packet::checkAndGetBuffer() const{ const char * Packet::checkAndGetBuffer() const{
if (pos != 188) { if (pos != 188) {
DEBUG_MSG(DLVL_HIGH, "Size invalid (%d) - invalid data from this point on", pos); HIGH_MSG("Size invalid (%d) - invalid data from this point on", pos);
} }
return strBuf; return strBuf;
} }

View file

@ -11,8 +11,7 @@
namespace TS{ namespace TS{
void ADTSRemainder::setRemainder(const aac::adts &p, const void *source, const uint32_t avail, void ADTSRemainder::setRemainder(const aac::adts &p, const void *source, uint32_t avail, uint64_t bPos){
const uint64_t bPos){
if (!p.getCompleteSize()){return;} if (!p.getCompleteSize()){return;}
if (max < p.getCompleteSize()){ if (max < p.getCompleteSize()){
@ -62,11 +61,11 @@ namespace TS{
} }
} }
uint32_t ADTSRemainder::getLength(){return len;} uint64_t ADTSRemainder::getLength(){return len;}
uint64_t ADTSRemainder::getBpos(){return bpos;} uint64_t ADTSRemainder::getBpos(){return bpos;}
uint32_t ADTSRemainder::getTodo(){return len - now;} uint64_t ADTSRemainder::getTodo(){return len - now;}
char *ADTSRemainder::getData(){return data;} char *ADTSRemainder::getData(){return data;}
Stream::Stream(bool _threaded){ Stream::Stream(bool _threaded){
@ -76,7 +75,7 @@ namespace TS{
Stream::~Stream(){ Stream::~Stream(){
} }
void Stream::parse(char *newPack, unsigned long long bytePos){ void Stream::parse(char * newPack, uint64_t bytePos) {
Packet newPacket; Packet newPacket;
newPacket.FromPointer(newPack); newPacket.FromPointer(newPack);
parse(newPacket, bytePos); parse(newPacket, bytePos);
@ -115,21 +114,21 @@ namespace TS{
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
if (!pesStreams.size()){return;} if (!pesStreams.size()){return;}
for (std::map<unsigned long, std::deque<Packet> >::const_iterator i = pesStreams.begin(); for (std::map<size_t, std::deque<Packet> >::const_iterator i = pesStreams.begin();
i != pesStreams.end(); i++){ i != pesStreams.end(); i++){
parsePES(i->first, true); parsePES(i->first, true);
} }
} }
void Stream::add(char *newPack, unsigned long long bytePos){ void Stream::add(char * newPack, uint64_t bytePos) {
Packet newPacket; Packet newPacket;
newPacket.FromPointer(newPack); newPacket.FromPointer(newPack);
add(newPacket, bytePos); add(newPacket, bytePos);
} }
void Stream::add(Packet &newPack, unsigned long long bytePos){ void Stream::add(Packet & newPack, uint64_t bytePos) {
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
int tid = newPack.getPID(); uint32_t tid = newPack.getPID();
bool unitStart = newPack.getUnitStart(); bool unitStart = newPack.getUnitStart();
std::deque<Packet> & PS = pesStreams[tid]; std::deque<Packet> & PS = pesStreams[tid];
if ((unitStart || PS.size()) && if ((unitStart || PS.size()) &&
@ -142,7 +141,7 @@ namespace TS{
} }
} }
bool Stream::isDataTrack(unsigned long tid){ bool Stream::isDataTrack(size_t tid) const {
if (tid == 0){return false;} if (tid == 0){return false;}
{ {
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
@ -150,7 +149,7 @@ namespace TS{
} }
} }
void Stream::parse(unsigned long tid){ void Stream::parse(size_t tid){
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
if (!pesStreams.count(tid) || pesStreams[tid].size() == 0){ if (!pesStreams.count(tid) || pesStreams[tid].size() == 0){
return; return;
@ -165,8 +164,8 @@ namespace TS{
associationTable.parsePIDs(); associationTable.parsePIDs();
lastPAT = Util::bootSecs(); lastPAT = Util::bootSecs();
int pmtCount = associationTable.getProgramCount(); size_t pmtCount = associationTable.getProgramCount();
for (int i = 0; i < pmtCount; i++){pmtTracks.insert(associationTable.getProgramPID(i));} for (size_t i = 0; i < pmtCount; i++){pmtTracks.insert(associationTable.getProgramPID(i));}
pesStreams.erase(0); pesStreams.erase(0);
return; return;
@ -183,8 +182,8 @@ namespace TS{
lastPMT[tid] = Util::bootSecs(); lastPMT[tid] = Util::bootSecs();
ProgramMappingEntry entry = mappingTable[tid].getEntry(0); ProgramMappingEntry entry = mappingTable[tid].getEntry(0);
while (entry){ while (entry){
unsigned long pid = entry.getElementaryPid(); uint32_t pid = entry.getElementaryPid();
unsigned long sType = entry.getStreamType(); uint32_t sType = entry.getStreamType();
switch (sType){ switch (sType){
case H264: case H264:
case AAC: case AAC:
@ -198,8 +197,7 @@ namespace TS{
metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength()); metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength());
} }
break; break;
default: default: break;
break;
} }
entry.advance(); entry.advance();
} }
@ -213,7 +211,7 @@ namespace TS{
} }
} }
void Stream::parse(Packet &newPack, unsigned long long bytePos){ void Stream::parse(Packet & newPack, uint64_t bytePos) {
add(newPack, bytePos); add(newPack, bytePos);
if (newPack.getUnitStart()){ if (newPack.getUnitStart()){
parse(newPack.getPID()); parse(newPack.getPID());
@ -227,10 +225,9 @@ namespace TS{
// pidToCodec.size(), outPackets.size()); // pidToCodec.size(), outPackets.size());
return false; return false;
} }
size_t missing = 0;
unsigned int missing = 0;
uint64_t firstTime = 0xffffffffffffffffull, lastTime = 0; uint64_t firstTime = 0xffffffffffffffffull, lastTime = 0;
for (std::map<unsigned long, unsigned long>::const_iterator it = pidToCodec.begin(); for (std::map<size_t, uint32_t>::const_iterator it = pidToCodec.begin();
it != pidToCodec.end(); it++){ it != pidToCodec.end(); it++){
if (!hasPacket(it->first)){ if (!hasPacket(it->first)){
missing++; missing++;
@ -247,7 +244,7 @@ namespace TS{
return (!missing || (missing != pidToCodec.size() && lastTime - firstTime > 2000)); return (!missing || (missing != pidToCodec.size() && lastTime - firstTime > 2000));
} }
bool Stream::hasPacket(unsigned long tid) const{ bool Stream::hasPacket(size_t tid) const {
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
std::map<unsigned long, std::deque<Packet> >::const_iterator pesIt = pesStreams.find(tid); std::map<unsigned long, std::deque<Packet> >::const_iterator pesIt = pesStreams.find(tid);
if (pesIt == pesStreams.end()){ if (pesIt == pesStreams.end()){
@ -269,7 +266,7 @@ namespace TS{
} }
if (outPackets.size()){ if (outPackets.size()){
for (std::map<unsigned long, std::deque<DTSC::Packet> >::const_iterator i = for (std::map<size_t, std::deque<DTSC::Packet> >::const_iterator i =
outPackets.begin(); outPackets.begin();
i != outPackets.end(); i++){ i != outPackets.end(); i++){
if (i->second.size()){ if (i->second.size()){
@ -288,18 +285,18 @@ namespace TS{
return false; return false;
} }
unsigned long long decodePTS(const char *data){ uint64_t decodePTS(const char * data){
unsigned long long time; uint64_t time;
time = ((data[0] >> 1) & 0x07); time = ((data[0] >> 1) & 0x07);
time <<= 15; time <<= 15;
time |= ((int)data[1] << 7) | ((data[2] >> 1) & 0x7F); time |= ((uint32_t)data[1] << 7) | ((data[2] >> 1) & 0x7F);
time <<= 15; time <<= 15;
time |= ((int)data[3] << 7) | ((data[4] >> 1) & 0x7F); time |= ((uint32_t)data[3] << 7) | ((data[4] >> 1) & 0x7F);
time /= 90; time /= 90;
return time; return time;
} }
void Stream::parsePES(unsigned long tid, bool finished){ void Stream::parsePES(size_t tid, bool finished){
if (!pidToCodec.count(tid)){ if (!pidToCodec.count(tid)){
return; // skip unknown codecs return; // skip unknown codecs
} }
@ -309,8 +306,7 @@ namespace TS{
return; return;
} }
// Find number of packets before unit Start // Find number of packets before unit Start
int packNum = 1; size_t packNum = 1;
std::deque<Packet>::iterator curPack = inStream.begin(); std::deque<Packet>::iterator curPack = inStream.begin();
if (seenUnitStart[tid] == 2 && inStream.begin()->getUnitStart() && inStream.rbegin()->getUnitStart()){ if (seenUnitStart[tid] == 2 && inStream.begin()->getUnitStart() && inStream.rbegin()->getUnitStart()){
@ -325,23 +321,23 @@ namespace TS{
} }
} }
if (!finished && curPack == inStream.end()){ if (!finished && curPack == inStream.end()){
FAIL_MSG("No PES packets to parse (%lu)", seenUnitStart[tid]); FAIL_MSG("No PES packets to parse (%" PRIu32 ")", seenUnitStart[tid]);
return; return;
} }
// We now know we're deleting 1 UnitStart, so we can pop the pesPositions and lower the seenUnitStart counter. // We now know we're deleting 1 UnitStart, so we can pop the pesPositions and lower the seenUnitStart counter.
--(seenUnitStart[tid]); --(seenUnitStart[tid]);
std::deque<unsigned long long> &inPositions = pesPositions[tid]; std::deque<size_t> &inPositions = pesPositions[tid];
uint64_t bPos = inPositions.front(); uint64_t bPos = inPositions.front();
inPositions.pop_front(); inPositions.pop_front();
// Create a buffer for the current PES, and remove it from the pesStreams buffer. // Create a buffer for the current PES, and remove it from the pesStreams buffer.
int paySize = 0; uint32_t paySize = 0;
// Loop over the packets we need, and calculate the total payload size // Loop over the packets we need, and calculate the total payload size
curPack = inStream.begin(); curPack = inStream.begin();
int lastCtr = curPack->getContinuityCounter() - 1; int lastCtr = curPack->getContinuityCounter() - 1;
for (int i = 0; i < packNum; i++){ for (size_t i = 0; i < packNum; i++){
if (curPack->getContinuityCounter() == lastCtr){ if (curPack->getContinuityCounter() == lastCtr){
curPack++; curPack++;
continue; continue;
@ -350,7 +346,7 @@ namespace TS{
paySize += curPack->getPayloadLength(); paySize += curPack->getPayloadLength();
curPack++; curPack++;
} }
VERYHIGH_MSG("Parsing PES for track %lu, length %i", tid, paySize); VERYHIGH_MSG("Parsing PES for track %zu, length %" PRIu32, tid, paySize);
// allocate a buffer, do it all again, but this time also copy the data bytes over to char* // allocate a buffer, do it all again, but this time also copy the data bytes over to char*
// payload // payload
char *payload = (char *)malloc(paySize); char *payload = (char *)malloc(paySize);
@ -368,7 +364,7 @@ namespace TS{
continue; continue;
} }
if (curPack->getContinuityCounter() - lastCtr != 1 && curPack->getContinuityCounter()){ if (curPack->getContinuityCounter() - lastCtr != 1 && curPack->getContinuityCounter()){
INFO_MSG("Parsing PES on track %d, missed %d packets", tid, INFO_MSG("Parsing PES on track %zu, missed %d packets", tid,
curPack->getContinuityCounter() - lastCtr - 1); curPack->getContinuityCounter() - lastCtr - 1);
} }
lastCtr = curPack->getContinuityCounter(); lastCtr = curPack->getContinuityCounter();
@ -381,21 +377,21 @@ namespace TS{
// headers) // headers)
// Parse the PES header // Parse the PES header
int offset = 0; uint32_t offset = 0;
while (offset < paySize){ while (offset < paySize){
const char *pesHeader = payload + offset; const char *pesHeader = payload + offset;
// Check for large enough buffer // Check for large enough buffer
if ((paySize - offset) < 9 || (paySize - offset) < 9 + pesHeader[8]){ if ((paySize - offset) < 9 || (paySize - offset) < 9 + pesHeader[8]){
INFO_MSG("Not enough data on track %lu (%d / %d), discarding remainder of data", tid, INFO_MSG("Not enough data on track %zu (%d / %d), discarding remainder of data", tid,
paySize - offset, 9 + pesHeader[8]); paySize - offset, 9 + pesHeader[8]);
break; break;
} }
// Check for valid PES lead-in // Check for valid PES lead-in
if (pesHeader[0] != 0 || pesHeader[1] != 0x00 || pesHeader[2] != 0x01){ if (pesHeader[0] != 0 || pesHeader[1] != 0x00 || pesHeader[2] != 0x01){
INFO_MSG("Invalid PES Lead in on track %lu, discarding it", tid); INFO_MSG("Invalid PES Lead in on track %zu, discarding it", tid);
break; break;
} }
@ -403,7 +399,7 @@ namespace TS{
// Note: if the payload size is 0, then we assume the pes packet will cover the entire TS // Note: if the payload size is 0, then we assume the pes packet will cover the entire TS
// Unit. // Unit.
// Note: this is technically only allowed for video pes streams. // Note: this is technically only allowed for video pes streams.
unsigned long long realPayloadSize = (((int)pesHeader[4] << 8) | pesHeader[5]); uint64_t realPayloadSize = Bit::btohs(pesHeader + 4);
if (!realPayloadSize){ if (!realPayloadSize){
realPayloadSize = paySize; // PES header size already included here realPayloadSize = paySize; // PES header size already included here
}else{ }else{
@ -417,9 +413,8 @@ namespace TS{
// Read the metadata for this PES Packet // Read the metadata for this PES Packet
///\todo Determine keyframe-ness ///\todo Determine keyframe-ness
uint64_t timeStamp = 0; uint64_t timeStamp = 0;
int64_t timeOffset = 0; int64_t timeOffset = 0;
unsigned int pesOffset = 9; // mandatory headers uint64_t pesOffset = 9; // mandatory headers
if ((pesHeader[7] >> 6) & 0x02){// Check for PTS presence if ((pesHeader[7] >> 6) & 0x02){// Check for PTS presence
timeStamp = decodePTS(pesHeader + pesOffset); timeStamp = decodePTS(pesHeader + pesOffset);
pesOffset += 5; pesOffset += 5;
@ -457,7 +452,7 @@ namespace TS{
} }
if (paySize - offset - pesOffset < realPayloadSize){ if (paySize - offset - pesOffset < realPayloadSize){
WARN_MSG("Packet loss detected (%lu != %lu), glitches will occur", (uint32_t)(paySize-offset-pesOffset), (uint32_t)realPayloadSize); WARN_MSG("Packet loss detected (%" PRIu64 " != %" PRIu64 "), glitches will occur", paySize-offset-pesOffset, realPayloadSize);
realPayloadSize = paySize - offset - pesOffset; realPayloadSize = paySize - offset - pesOffset;
} }
@ -472,26 +467,24 @@ namespace TS{
free(payload); free(payload);
} }
void Stream::setLastms(unsigned long tid, uint64_t timestamp){ void Stream::setLastms(size_t tid, uint64_t timestamp){
lastms[tid] = timestamp; lastms[tid] = timestamp;
rolloverCount[tid] = timestamp / TS_PTS_ROLLOVER; rolloverCount[tid] = timestamp / TS_PTS_ROLLOVER;
} }
void Stream::parseBitstream(uint32_t tid, const char *pesPayload, uint32_t realPayloadSize, void Stream::parseBitstream(size_t tid, const char *pesPayload, uint64_t realPayloadSize,
uint64_t timeStamp, int64_t timeOffset, uint64_t bPos, bool alignment){ uint64_t timeStamp, int64_t timeOffset, uint64_t bPos, bool alignment){
//INFO_MSG("timestamp: %llu offset: %lld", timeStamp, timeOffset);
// Create a new (empty) DTSC Packet at the end of the buffer // Create a new (empty) DTSC Packet at the end of the buffer
unsigned long thisCodec = pidToCodec[tid]; unsigned long thisCodec = pidToCodec[tid];
std::deque<DTSC::Packet> & out = outPackets[tid]; std::deque<DTSC::Packet> & out = outPackets[tid];
if (thisCodec == AAC){ if (thisCodec == AAC){
// Parse all the ADTS packets // Parse all the ADTS packets
unsigned long offsetInPes = 0; uint64_t offsetInPes = 0;
uint64_t msRead = 0; uint64_t msRead = 0;
if (remainders.count(tid) && remainders[tid].getLength()){ if (remainders.count(tid) && remainders[tid].getLength()){
offsetInPes = offsetInPes = std::min(remainders[tid].getTodo(), realPayloadSize);
std::min((unsigned long)(remainders[tid].getTodo()), (unsigned long)realPayloadSize);
remainders[tid].append(pesPayload, offsetInPes); remainders[tid].append(pesPayload, offsetInPes);
if (remainders[tid].isComplete()){ if (remainders[tid].isComplete()){
@ -563,7 +556,7 @@ namespace TS{
nextPtr = pesEnd; nextPtr = pesEnd;
nalSize = realPayloadSize; nalSize = realPayloadSize;
if(!alignment && timeStamp && buildPacket.count(tid) && timeStamp != buildPacket[tid].getTime()){ if(!alignment && timeStamp && buildPacket.count(tid) && timeStamp != buildPacket[tid].getTime()){
FAIL_MSG("No startcode in packet @ %llu ms, and time is not equal to %llu ms so can't merge", timeStamp, buildPacket[tid].getTime()); FAIL_MSG("No startcode in packet @ %" PRIu64 " ms, and time is not equal to %" PRIu64 " ms so can't merge", timeStamp, buildPacket[tid].getTime());
return; return;
} }
if (alignment){ if (alignment){
@ -573,11 +566,11 @@ namespace TS{
// Add the finished DTSC packet to our output buffer // Add the finished DTSC packet to our output buffer
out.push_back(buildPacket[tid]); out.push_back(buildPacket[tid]);
uint32_t size; size_t size;
char * tmp ; char * tmp ;
buildPacket[tid].getString("data", tmp, size); buildPacket[tid].getString("data", tmp, size);
INFO_MSG("buildpacket: size: %d, timestamp: %llu", size, buildPacket[tid].getTime()) INFO_MSG("buildpacket: size: %zu, timestamp: %" PRIu64, size, buildPacket[tid].getTime())
// Create a new empty packet with the key frame bit set to true // Create a new empty packet with the key frame bit set to true
buildPacket[tid].null(); buildPacket[tid].null();
@ -630,7 +623,7 @@ namespace TS{
// Add the finished DTSC packet to our output buffer // Add the finished DTSC packet to our output buffer
out.push_back(buildPacket[tid]); out.push_back(buildPacket[tid]);
uint32_t size; size_t size;
char * tmp ; char * tmp ;
buildPacket[tid].getString("data", tmp, size); buildPacket[tid].getString("data", tmp, size);
@ -657,7 +650,6 @@ namespace TS{
size_t origSize = realPayloadSize; size_t origSize = realPayloadSize;
const char *nextPtr; const char *nextPtr;
const char *pesEnd = pesPayload+realPayloadSize; const char *pesEnd = pesPayload+realPayloadSize;
uint32_t nalSize = 0;
bool isKeyFrame = false; bool isKeyFrame = false;
@ -672,7 +664,7 @@ namespace TS{
while (nextPtr < pesEnd && nalno < 8){ while (nextPtr < pesEnd && nalno < 8){
if (!nextPtr){nextPtr = pesEnd;} if (!nextPtr){nextPtr = pesEnd;}
//Calculate size of NAL unit, removing null bytes from the end //Calculate size of NAL unit, removing null bytes from the end
nalSize = nalu::nalEndPosition(pesPayload, nextPtr - pesPayload) - pesPayload; nalu::nalEndPosition(pesPayload, nextPtr - pesPayload);
// Check if this is a keyframe // Check if this is a keyframe
parseNal(tid, pesPayload, nextPtr, isKeyFrame); parseNal(tid, pesPayload, nextPtr, isKeyFrame);
@ -688,11 +680,11 @@ namespace TS{
} }
} }
void Stream::getPacket(unsigned long tid, DTSC::Packet &pack){ void Stream::getPacket(size_t tid, DTSC::Packet & pack) {
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
pack.null(); pack.null();
if (!hasPacket(tid)){ if (!hasPacket(tid)){
ERROR_MSG("Trying to obtain a packet on track %lu, but no full packet is available", tid); ERROR_MSG("Trying to obtain a packet on track %zu, but no full packet is available", tid);
return; return;
} }
@ -715,8 +707,7 @@ namespace TS{
} }
void Stream::parseNal(uint32_t tid, const char *pesPayload, const char *nextPtr, void Stream::parseNal(size_t tid, const char *pesPayload, const char *nextPtr, bool &isKeyFrame){
bool &isKeyFrame){
bool firstSlice = true; bool firstSlice = true;
char typeNal; char typeNal;
@ -813,14 +804,31 @@ namespace TS{
} }
} }
uint32_t Stream::getEarliestPID(){
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
uint64_t packTime = 0xFFFFFFFFull;
uint32_t packTrack = 0;
for (std::map<size_t, std::deque<DTSC::Packet> >::iterator it = outPackets.begin();
it != outPackets.end(); it++){
if (it->second.front().getTime() < packTime){
packTrack = it->first;
packTime = it->second.front().getTime();
}
}
return packTrack;
}
void Stream::getEarliestPacket(DTSC::Packet &pack){ void Stream::getEarliestPacket(DTSC::Packet &pack){
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
pack.null(); pack.null();
unsigned long packTime = 0xFFFFFFFFull; uint64_t packTime = 0xFFFFFFFFull;
unsigned long packTrack = 0; uint64_t packTrack = 0;
for (std::map<unsigned long, std::deque<DTSC::Packet> >::iterator it = outPackets.begin(); for (std::map<size_t, std::deque<DTSC::Packet> >::iterator it = outPackets.begin();
it != outPackets.end(); it++){ it != outPackets.end(); it++){
if (it->second.size() && it->second.front().getTime() < packTime){ if (it->second.size() && it->second.front().getTime() < packTime){
packTrack = it->first; packTrack = it->first;
@ -831,16 +839,14 @@ namespace TS{
if (packTrack){getPacket(packTrack, pack);} if (packTrack){getPacket(packTrack, pack);}
} }
void Stream::initializeMetadata(DTSC::Meta &meta, unsigned long tid, unsigned long mappingId){ void Stream::initializeMetadata(DTSC::Meta &meta, size_t tid, size_t mappingId){
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
unsigned long mId = mappingId; for (std::map<size_t, uint32_t>::const_iterator it = pidToCodec.begin();
for (std::map<unsigned long, unsigned long>::const_iterator it = pidToCodec.begin();
it != pidToCodec.end(); it++){ it != pidToCodec.end(); it++){
if (tid && it->first != tid){continue;} if (tid && it->first != tid){continue;}
if (mId == 0){mId = it->first;} size_t mId = it->first;
if (meta.tracks.count(mId) && meta.tracks[mId].codec.size()){continue;} if (meta.tracks.count(mId) && meta.tracks[mId].codec.size()){continue;}
@ -946,9 +952,9 @@ namespace TS{
}break; }break;
} }
int pmtCount = associationTable.getProgramCount(); size_t pmtCount = associationTable.getProgramCount();
for (int i = 0; i < pmtCount; i++){ for (size_t i = 0; i < pmtCount; i++){
int pid = associationTable.getProgramPID(i); uint32_t pid = associationTable.getProgramPID(i);
ProgramMappingEntry entry = mappingTable[pid].getEntry(0); ProgramMappingEntry entry = mappingTable[pid].getEntry(0);
while (entry){ while (entry){
if (entry.getElementaryPid() == tid){ if (entry.getElementaryPid() == tid){
@ -965,15 +971,15 @@ namespace TS{
std::set<unsigned long> Stream::getActiveTracks(){ std::set<unsigned long> Stream::getActiveTracks(){
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
std::set<unsigned long> result; std::set<size_t> result;
// Track 0 is always active // Track 0 is always active
result.insert(0); result.insert(0);
// IF PAT updated in the last 5 seconds, check for contents // IF PAT updated in the last 5 seconds, check for contents
if (Util::bootSecs() - lastPAT < 5){ if (Util::bootSecs() - lastPAT < 5){
int pmtCount = associationTable.getProgramCount(); size_t pmtCount = associationTable.getProgramCount();
// For each PMT // For each PMT
for (int i = 0; i < pmtCount; i++){ for (size_t i = 0; i < pmtCount; i++){
int pid = associationTable.getProgramPID(i); size_t pid = associationTable.getProgramPID(i);
// Add PMT track // Add PMT track
result.insert(pid); result.insert(pid);
// IF PMT updated in last 5 seconds, check for contents // IF PMT updated in last 5 seconds, check for contents
@ -1000,7 +1006,7 @@ namespace TS{
return result; return result;
} }
void Stream::eraseTrack(unsigned long tid){ void Stream::eraseTrack(size_t tid){
tthread::lock_guard<tthread::recursive_mutex> guard(tMutex); tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
pesStreams.erase(tid); pesStreams.erase(tid);
pesPositions.erase(tid); pesPositions.erase(tid);

View file

@ -15,20 +15,19 @@ namespace TS{
class ADTSRemainder{ class ADTSRemainder{
private: private:
char *data; char *data;
uint32_t max; uint64_t max;
uint32_t now; uint64_t now;
uint32_t len; uint64_t len;
uint64_t bpos; uint64_t bpos;
public: public:
void setRemainder(const aac::adts &p, const void *source, const uint32_t avail, void setRemainder(const aac::adts & p, const void * source, uint32_t avail, uint64_t bPos);
const uint64_t bPos);
ADTSRemainder(); ADTSRemainder();
~ADTSRemainder(); ~ADTSRemainder();
uint32_t getLength(); uint64_t getLength();
uint64_t getBpos(); uint64_t getBpos();
uint32_t getTodo(); uint64_t getTodo();
char *getData(); char *getData();
void append(const char *p, uint32_t pLen); void append(const char *p, uint32_t pLen);
@ -40,62 +39,63 @@ namespace TS{
public: public:
Stream(bool _threaded = false); Stream(bool _threaded = false);
~Stream(); ~Stream();
void add(char *newPack, unsigned long long bytePos = 0); void add(char * newPack, uint64_t bytePos = 0);
void add(Packet &newPack, unsigned long long bytePos = 0); void add(Packet & newPack, uint64_t bytePos = 0);
void parse(Packet &newPack, unsigned long long bytePos); void parse(Packet & newPack, uint64_t bytePos);
void parse(char *newPack, unsigned long long bytePos); void parse(char * newPack, uint64_t bytePos);
void parse(unsigned long tid); void parse(size_t tid);
void parseNal(uint32_t tid, const char *pesPayload, const char *packetPtr, bool &isKeyFrame); void parseNal(size_t tid, const char * pesPayload, const char * packetPtr, bool & isKeyFrame);
bool hasPacketOnEachTrack() const; bool hasPacketOnEachTrack() const;
bool hasPacket(unsigned long tid) const; bool hasPacket(size_t tid) const;
bool hasPacket() const; bool hasPacket() const;
void getPacket(unsigned long tid, DTSC::Packet &pack); void getPacket(size_t tid, DTSC::Packet &pack);
uint32_t getEarliestPID();
void getEarliestPacket(DTSC::Packet &pack); void getEarliestPacket(DTSC::Packet &pack);
void initializeMetadata(DTSC::Meta &meta, unsigned long tid = 0, unsigned long mappingId = 0); void initializeMetadata(DTSC::Meta &meta, size_t tid = 0, size_t mappingId = 0);
void partialClear(); void partialClear();
void clear(); void clear();
void finish(); void finish();
void eraseTrack(unsigned long tid); void eraseTrack(size_t tid);
bool isDataTrack(unsigned long tid); bool isDataTrack(size_t tid) const;
void parseBitstream(uint32_t tid, const char *pesPayload, uint32_t realPayloadSize, void parseBitstream(size_t tid, const char * pesPayload, uint64_t realPayloadSize,
uint64_t timeStamp, int64_t timeOffset, uint64_t bPos, bool alignment); uint64_t timeStamp, int64_t timeOffset, uint64_t bPos, bool alignment);
std::set<unsigned long> getActiveTracks(); std::set<size_t> getActiveTracks();
void setLastms(unsigned long tid, uint64_t timestamp); void setLastms(size_t tid, uint64_t timestamp);
private: private:
unsigned long long lastPAT; uint64_t lastPAT;
ProgramAssociationTable associationTable; ProgramAssociationTable associationTable;
std::map<unsigned long, ADTSRemainder> remainders; std::map<size_t, ADTSRemainder> remainders;
std::map<unsigned long, unsigned long long> lastPMT; std::map<size_t, uint64_t> lastPMT;
std::map<unsigned long, ProgramMappingTable> mappingTable; std::map<size_t, ProgramMappingTable> mappingTable;
std::map<unsigned long, std::deque<Packet> > pesStreams; std::map<size_t, std::deque<Packet> > pesStreams;
std::map<unsigned long, std::deque<unsigned long long> > pesPositions; std::map<size_t, std::deque<uint64_t> > pesPositions;
std::map<unsigned long, std::deque<DTSC::Packet> > outPackets; std::map<size_t, std::deque<DTSC::Packet> > outPackets;
std::map<unsigned long, DTSC::Packet> buildPacket; std::map<size_t, DTSC::Packet> buildPacket;
std::map<unsigned long, unsigned long> pidToCodec; std::map<size_t, uint32_t> pidToCodec;
std::map<unsigned long, aac::adts> adtsInfo; std::map<size_t, aac::adts > adtsInfo;
std::map<unsigned long, std::string> spsInfo; std::map<size_t, std::string > spsInfo;
std::map<unsigned long, std::string> ppsInfo; std::map<size_t, std::string > ppsInfo;
std::map<unsigned long, h265::initData> hevcInfo; std::map<size_t, h265::initData > hevcInfo;
std::map<unsigned long, std::string> metaInit; std::map<size_t, std::string> metaInit;
std::map<unsigned long, std::string> descriptors; std::map<size_t, std::string> descriptors;
std::map<unsigned long, uint32_t> seenUnitStart; std::map<size_t, uint32_t> seenUnitStart;
std::map<unsigned long, std::string> mpeg2SeqHdr; std::map<size_t, std::string> mpeg2SeqHdr;
std::map<unsigned long, std::string> mpeg2SeqExt; std::map<size_t, std::string> mpeg2SeqExt;
std::map<unsigned long, std::string> mp2Hdr; std::map<size_t, std::string> mp2Hdr;
std::map<unsigned long, size_t> rolloverCount; std::map<size_t, size_t> rolloverCount;
std::map<unsigned long, unsigned long long> lastms; std::map<size_t, unsigned long long> lastms;
mutable tthread::recursive_mutex tMutex; mutable tthread::recursive_mutex tMutex;
bool threaded; bool threaded;
std::set<unsigned long> pmtTracks; std::set<size_t> pmtTracks;
void parsePES(unsigned long tid, bool finished = false); void parsePES(size_t tid, bool finished = false);
}; };
} }

View file

@ -369,14 +369,18 @@ namespace Util{
close(in); close(in);
} }
FieldAccX::FieldAccX(RelAccX * _src, RelAccXFieldData _field, char * _data) : src(_src), field(_field), data(_data) {} FieldAccX::FieldAccX(RelAccX * _src, RelAccXFieldData _field) : src(_src), field(_field) {}
uint64_t FieldAccX::uint(size_t recordNo) const { uint64_t FieldAccX::uint(size_t recordNo) const {
return src->getInt(field, recordNo); return src->getInt(field, recordNo);
} }
std::string FieldAccX::string(size_t recordNo) const { std::string FieldAccX::string(size_t recordNo) const {
return std::string(src->getPointer(field, recordNo), field.size) ; std::string res(src->getPointer(field, recordNo));
if (res.size() > field.size){
res.resize(field.size);
}
return res;
} }
void FieldAccX::set(uint64_t val, size_t recordNo){ void FieldAccX::set(uint64_t val, size_t recordNo){
@ -448,9 +452,15 @@ namespace Util{
/// Gets the size in bytes of a single record in the structure. /// Gets the size in bytes of a single record in the structure.
uint32_t RelAccX::getRSize() const{return RAXHDR_RECORDSIZE;} uint32_t RelAccX::getRSize() const{return RAXHDR_RECORDSIZE;}
/// Gets the position in the records where the entries start
uint32_t RelAccX::getStartPos() const{return RAXHDR_STARTPOS;}
/// Gets the number of deleted records /// Gets the number of deleted records
uint64_t RelAccX::getDeleted() const{return RAXHDR_DELETED;} uint64_t RelAccX::getDeleted() const{return RAXHDR_DELETED;}
///Gets the number of records present
size_t RelAccX::getPresent() const{return RAXHDR_PRESENT;}
/// Gets the number of the last valid index /// Gets the number of the last valid index
uint64_t RelAccX::getEndPos() const{return RAXHDR_ENDPOS;} uint64_t RelAccX::getEndPos() const{return RAXHDR_ENDPOS;}
@ -497,20 +507,22 @@ namespace Util{
/// For other types, returns the maximum size possible. /// For other types, returns the maximum size possible.
/// Returns 0 if the field does not exist. /// Returns 0 if the field does not exist.
uint32_t RelAccX::getSize(const std::string &name, uint64_t recordNo) const{ uint32_t RelAccX::getSize(const std::string &name, uint64_t recordNo) const{
const RelAccXFieldData &fd = fields.at(name); if (!isRecordAvailable(recordNo)){ return 0;}
std::map<std::string, RelAccXFieldData>::const_iterator it = fields.find(name);
if (it == fields.end()){return 0;}
const RelAccXFieldData &fd = it->second;
if ((fd.type & 0xF0) == RAX_STRING){ if ((fd.type & 0xF0) == RAX_STRING){
if (!fields.count(name) || !isRecordAvailable(recordNo)){return 0;}
return strnlen(RECORD_POINTER, fd.size); return strnlen(RECORD_POINTER, fd.size);
}else{
return fd.size;
} }
return fd.size;
} }
/// Returns a pointer to the given field in the given record number. /// Returns a pointer to the given field in the given record number.
/// Returns a null pointer if the field does not exist. /// Returns a null pointer if the field does not exist.
char *RelAccX::getPointer(const std::string &name, uint64_t recordNo) const{ char *RelAccX::getPointer(const std::string &name, uint64_t recordNo) const{
if (!fields.count(name)){return 0;} std::map<std::string, RelAccXFieldData>::const_iterator it = fields.find(name);
return getPointer(fields.at(name), recordNo); if (it == fields.end()){return 0;}
return getPointer(it->second, recordNo);
} }
char * RelAccX::getPointer(const RelAccXFieldData & fd, uint64_t recordNo) const{ char * RelAccX::getPointer(const RelAccXFieldData & fd, uint64_t recordNo) const{
@ -520,8 +532,9 @@ namespace Util{
/// Returns the value of the given integer-type field in the given record, as an uint64_t type. /// Returns the value of the given integer-type field in the given record, as an uint64_t type.
/// Returns 0 if the field does not exist or is not an integer type. /// Returns 0 if the field does not exist or is not an integer type.
uint64_t RelAccX::getInt(const std::string &name, uint64_t recordNo) const{ uint64_t RelAccX::getInt(const std::string &name, uint64_t recordNo) const{
if (!fields.count(name)){return 0;} std::map<std::string, RelAccXFieldData>::const_iterator it = fields.find(name);
return getInt(fields.at(name), recordNo); if (it == fields.end()){return 0;}
return getInt(it->second, recordNo);
} }
uint64_t RelAccX::getInt(const RelAccXFieldData & fd, uint64_t recordNo) const{ uint64_t RelAccX::getInt(const RelAccXFieldData & fd, uint64_t recordNo) const{
@ -703,9 +716,16 @@ namespace Util{
/// Sets the record counter to the given value. /// Sets the record counter to the given value.
void RelAccX::setRCount(uint32_t count){RAXHDR_RECORDCNT = count;} void RelAccX::setRCount(uint32_t count){RAXHDR_RECORDCNT = count;}
/// Sets the position in the records where the entries start
void RelAccX::setStartPos(uint32_t n){RAXHDR_STARTPOS = n;}
/// Sets the number of deleted records /// Sets the number of deleted records
void RelAccX::setDeleted(uint64_t n){RAXHDR_DELETED = n;} void RelAccX::setDeleted(uint64_t n){RAXHDR_DELETED = n;}
/// Sets the number of records present
/// Defaults to the record count if set to zero.
void RelAccX::setPresent(uint32_t n){RAXHDR_PRESENT = n;}
/// Sets the number of the last valid index /// Sets the number of the last valid index
void RelAccX::setEndPos(uint64_t n){RAXHDR_ENDPOS = n;} void RelAccX::setEndPos(uint64_t n){RAXHDR_ENDPOS = n;}
@ -732,13 +752,17 @@ namespace Util{
/// Fails if ready is not set. /// Fails if ready is not set.
/// Ensures the last byte is always a zero. /// Ensures the last byte is always a zero.
void RelAccX::setString(const std::string &name, const std::string &val, uint64_t recordNo){ void RelAccX::setString(const std::string &name, const std::string &val, uint64_t recordNo){
if (!fields.count(name)){ std::map<std::string, RelAccXFieldData>::const_iterator it = fields.find(name);
if (it == fields.end()){
WARN_MSG("Setting non-existent string %s", name.c_str()); WARN_MSG("Setting non-existent string %s", name.c_str());
return; return;
} }
const RelAccXFieldData &fd = fields.at(name); setString(it->second, val, recordNo);
}
void RelAccX::setString(const RelAccXFieldData & fd, const std::string &val, uint64_t recordNo){
if ((fd.type & 0xF0) != RAX_STRING){ if ((fd.type & 0xF0) != RAX_STRING){
WARN_MSG("Setting non-string %s", name.c_str()); WARN_MSG("Setting non-string");
return; return;
} }
char *ptr = RECORD_POINTER; char *ptr = RECORD_POINTER;
@ -749,11 +773,12 @@ namespace Util{
/// Writes the given int to the given field in the given record. /// Writes the given int to the given field in the given record.
/// Fails if ready is not set or the field is not an integer type. /// Fails if ready is not set or the field is not an integer type.
void RelAccX::setInt(const std::string &name, uint64_t val, uint64_t recordNo){ void RelAccX::setInt(const std::string &name, uint64_t val, uint64_t recordNo){
if (!fields.count(name)){ std::map<std::string, RelAccXFieldData>::const_iterator it = fields.find(name);
if (it == fields.end()){
WARN_MSG("Setting non-existent integer %s", name.c_str()); WARN_MSG("Setting non-existent integer %s", name.c_str());
return; return;
} }
return setInt(fields.at(name), val, recordNo); setInt(it->second, val, recordNo);
} }
void RelAccX::setInt(const RelAccXFieldData & fd, uint64_t val, uint64_t recordNo){ void RelAccX::setInt(const RelAccXFieldData & fd, uint64_t val, uint64_t recordNo){
@ -781,12 +806,15 @@ namespace Util{
WARN_MSG("Setting non-integer field (%u) to integer value!", fd.type); WARN_MSG("Setting non-integer field (%u) to integer value!", fd.type);
} }
///Writes the given int to the given field in the given record.
///Fails if ready is not set or the field is not an integer type.
void RelAccX::setInts(const std::string & name, uint64_t * values, size_t len){ void RelAccX::setInts(const std::string & name, uint64_t * values, size_t len){
if (!fields.count(name)){ std::map<std::string, RelAccXFieldData>::const_iterator it = fields.find(name);
if (it == fields.end()){
WARN_MSG("Setting non-existent integer %s", name.c_str()); WARN_MSG("Setting non-existent integer %s", name.c_str());
return; return;
} }
const RelAccXFieldData & fd = fields.at(name); const RelAccXFieldData & fd = it->second;
for (uint64_t recordNo = 0; recordNo < len; recordNo++){ for (uint64_t recordNo = 0; recordNo < len; recordNo++){
setInt(fd, values[recordNo], recordNo); setInt(fd, values[recordNo], recordNo);
} }
@ -795,17 +823,124 @@ namespace Util{
/// Updates the deleted record counter, the start position and the present record counter, /// Updates the deleted record counter, the start position and the present record counter,
/// shifting the ring buffer start position forward without moving the ring buffer end position. /// shifting the ring buffer start position forward without moving the ring buffer end position.
void RelAccX::deleteRecords(uint32_t amount){ void RelAccX::deleteRecords(uint32_t amount){
RAXHDR_DELETED += amount; // update deleted record counter uint32_t &startPos = RAXHDR_STARTPOS;
uint64_t &deletedRecs = RAXHDR_DELETED;
uint32_t &recsPresent = RAXHDR_PRESENT;
startPos += amount; // update start position
deletedRecs += amount; // update deleted record counter
if (recsPresent >= amount){
recsPresent -= amount; // decrease records present
}else{
WARN_MSG("Depleting recordCount!");
recsPresent = 0;
}
} }
/// Updates the present record counter, shifting the ring buffer end position forward without /// Updates the present record counter, shifting the ring buffer end position forward without
/// moving the ring buffer start position. /// moving the ring buffer start position.
void RelAccX::addRecords(uint32_t amount){ void RelAccX::addRecords(uint32_t amount){
RAXHDR_ENDPOS += amount; uint32_t & recsPresent = RAXHDR_PRESENT;
uint32_t & recordsCount = RAXHDR_RECORDCNT;
uint64_t & recordEndPos = RAXHDR_ENDPOS;
if (recsPresent+amount > recordsCount){
WARN_MSG("Exceeding recordCount (%d [%d + %d] > %d)", recsPresent + amount, recsPresent, amount, recordsCount);
recsPresent = 0;
}else{
recsPresent += amount;
}
recordEndPos += amount;
}
void RelAccX::minimalFrom(const RelAccX & src){
copyFieldsFrom(src, true);
uint64_t rCount = src.getPresent();
setRCount(rCount);
setReady();
addRecords(rCount);
flowFrom(src);
}
void RelAccX::copyFieldsFrom(const RelAccX & src, bool minimal){
fields.clear();
if (!minimal){
for (std::map<std::string, RelAccXFieldData>::const_iterator it = src.fields.begin(); it != src.fields.end(); it++){
addField(it->first, it->second.type, it->second.size);
}
return;
}
for (std::map<std::string, RelAccXFieldData>::const_iterator it = src.fields.begin(); it != src.fields.end(); it++){
switch(it->second.type & 0xF0){
case 0x00: //nested RelAccX
{
uint64_t maxSize = 0;
for (int i = 0; i < src.getPresent(); i++){
Util::RelAccX child(src.getPointer(it->first, i), false);
char * tmpBuf = (char*)malloc(src.getOffset() + (src.getRCount() * src.getRSize()));
Util::RelAccX minChild(tmpBuf, false);
minChild.minimalFrom(child);
uint64_t thisSize = minChild.getOffset() + (minChild.getRSize() * minChild.getPresent());
maxSize = std::max(thisSize, maxSize);
free(tmpBuf);
}
addField(it->first, it->second.type, maxSize);
}
break;
default:
addField(it->first, it->second.type, it->second.size);
break;
}
}
}
void RelAccX::flowFrom(const RelAccX & src){
uint64_t rCount = src.getPresent();
if (getRCount() == 0){
setRCount(rCount);
}
if (rCount > getRCount()){
FAIL_MSG("Abandoning reflow, target does not have enough records available (%" PRIu64 " records, %d available)", rCount, getRCount());
return;
}
addRecords(rCount - getPresent());
for (int i = 0; i < rCount; i++){
for (std::map<std::string, RelAccXFieldData>::const_iterator it = src.fields.begin(); it != src.fields.end(); it++){
if (!fields.count(it->first)){
INFO_MSG("Field %s in source but not in target", it->first.c_str());
continue;
}
switch(it->second.type & 0xF0){
case RAX_RAW:
memcpy(getPointer(it->first, i), src.getPointer(it->first, i), std::min(it->second.size, fields.at(it->first).size));
break;
case RAX_INT:
case RAX_UINT:
setInt(it->first, src.getInt(it->first, i), i);
break;
case RAX_STRING:
setString(it->first, src.getPointer(it->first, i), i);
break;
case 0x00: //nested RelAccX
{
Util::RelAccX srcChild(src.getPointer(it->first, i), false);
Util::RelAccX child(getPointer(it->first, i), false);
child.flowFrom(srcChild);
}
break;
default:
break;
}
}
}
} }
FieldAccX RelAccX::getFieldAccX(const std::string & fName){ FieldAccX RelAccX::getFieldAccX(const std::string & fName){
return FieldAccX(this, fields.at(fName), p + getOffset()); return FieldAccX(this, fields.at(fName));
}
RelAccXFieldData RelAccX::getFieldData(const std::string & fName) const {
return fields.at(fName);
} }
} }

View file

@ -26,7 +26,7 @@ namespace Util{
public: public:
ResizeablePointer(); ResizeablePointer();
~ResizeablePointer(); ~ResizeablePointer();
inline uint32_t& size(){return currSize;} inline size_t& size(){return currSize;}
bool assign(const void * p, uint32_t l); bool assign(const void * p, uint32_t l);
bool append(const void * p, uint32_t l); bool append(const void * p, uint32_t l);
bool allocate(uint32_t l); bool allocate(uint32_t l);
@ -34,8 +34,8 @@ namespace Util{
inline operator void*(){return ptr;} inline operator void*(){return ptr;}
private: private:
void * ptr; void * ptr;
uint32_t currSize; size_t currSize;
uint32_t maxSize; size_t maxSize;
}; };
@ -117,8 +117,10 @@ namespace Util{
uint32_t getRCount() const; uint32_t getRCount() const;
uint32_t getRSize() const; uint32_t getRSize() const;
uint16_t getOffset() const; uint16_t getOffset() const;
uint32_t getStartPos() const;
uint64_t getDeleted() const; uint64_t getDeleted() const;
uint64_t getEndPos() const; uint64_t getEndPos() const;
size_t getPresent() const;
uint32_t getFieldCount() const; uint32_t getFieldCount() const;
bool isReady() const; bool isReady() const;
bool isExit() const; bool isExit() const;
@ -138,12 +140,15 @@ namespace Util{
//Read-write functions: //Read-write functions:
void addField(const std::string & name, uint8_t fType, uint32_t fLen=0); void addField(const std::string & name, uint8_t fType, uint32_t fLen=0);
void setRCount(uint32_t count); void setRCount(uint32_t count);
void setStartPos(uint32_t n);
void setDeleted(uint64_t n); void setDeleted(uint64_t n);
void setEndPos(uint64_t n); void setEndPos(uint64_t n);
void setPresent(uint32_t n);
void setReady(); void setReady();
void setExit(); void setExit();
void setReload(); void setReload();
void setString(const std::string & name, const std::string & val, uint64_t recordNo=0); void setString(const std::string & name, const std::string & val, uint64_t recordNo=0);
void setString(const RelAccXFieldData & fd, const std::string & val, uint64_t recordNo=0);
void setInt(const std::string & name, uint64_t val, uint64_t recordNo=0); void setInt(const std::string & name, uint64_t val, uint64_t recordNo=0);
void setInt(const RelAccXFieldData & fd, uint64_t val, uint64_t recordNo=0); void setInt(const RelAccXFieldData & fd, uint64_t val, uint64_t recordNo=0);
void setInts(const std::string & name, uint64_t * values, size_t len); void setInts(const std::string & name, uint64_t * values, size_t len);
@ -155,6 +160,7 @@ namespace Util{
void flowFrom(const RelAccX & src); void flowFrom(const RelAccX & src);
FieldAccX getFieldAccX(const std::string & fName); FieldAccX getFieldAccX(const std::string & fName);
RelAccXFieldData getFieldData(const std::string & fName) const;
protected: protected:
static uint32_t getDefaultSize(uint8_t fType); static uint32_t getDefaultSize(uint8_t fType);
std::map<std::string, RelAccXFieldData> fields; std::map<std::string, RelAccXFieldData> fields;
@ -164,7 +170,7 @@ namespace Util{
class FieldAccX { class FieldAccX {
public: public:
FieldAccX(RelAccX * _src = NULL, RelAccXFieldData _field = RelAccXFieldData(), char * _data = NULL); FieldAccX(RelAccX * _src = NULL, RelAccXFieldData _field = RelAccXFieldData());
uint64_t uint(size_t recordNo) const; uint64_t uint(size_t recordNo) const;
std::string string(size_t recordNo) const; std::string string(size_t recordNo) const;
void set(uint64_t val, size_t recordNo = 0); void set(uint64_t val, size_t recordNo = 0);
@ -172,6 +178,5 @@ namespace Util{
private: private:
RelAccX * src; RelAccX * src;
RelAccXFieldData field; RelAccXFieldData field;
char * data;
}; };
} }

View file

@ -198,7 +198,7 @@ namespace vorbis{
for (int i = 0; i < codebook_count; i++){ for (int i = 0; i < codebook_count; i++){
long long unsigned int CMN = stream.get(24); long long unsigned int CMN = stream.get(24);
if (CMN != 0x564342){ if (CMN != 0x564342){
DEBUG_MSG(DLVL_WARN,"Is dit het? VCB != %c%c%c", (char)(CMN >> 16), (char)(CMN >> 8), (char)CMN); WARN_MSG("Is dit het? VCB != %c%c%c", (char)(CMN >> 16), (char)(CMN >> 8), (char)CMN);
exit(1); exit(1);
} }
unsigned short codebook_dimensions = stream.get(16); unsigned short codebook_dimensions = stream.get(16);
@ -256,7 +256,7 @@ namespace vorbis{
long long unsigned int floorType = stream.get(16); long long unsigned int floorType = stream.get(16);
switch(floorType){ switch(floorType){
case 0:{ case 0:{
DEBUG_MSG(DLVL_WARN, "FloorType 0 in vorbis setup header not tested!"); WARN_MSG("FloorType 0 in vorbis setup header not tested!");
stream.skip(8);//order stream.skip(8);//order
stream.skip(16);//rate stream.skip(16);//rate
stream.skip(16);//bark_map_size stream.skip(16);//bark_map_size
@ -359,7 +359,7 @@ namespace vorbis{
} }
char meh = stream.get(2); char meh = stream.get(2);
if (meh != 0){ if (meh != 0){
DEBUG_MSG(DLVL_ERROR, "Sanity check ==0 : %i", (int)meh); ERROR_MSG("Sanity check ==0 : %i", (int)meh);
exit(0); exit(0);
} }
if (mappingSubmaps > 1){ if (mappingSubmaps > 1){

View file

@ -53,7 +53,7 @@ bool AnalyserDTSC::parsePacket(){
} }
if (detail >= 8){ if (detail >= 8){
char * payDat; char * payDat;
unsigned int payLen; size_t payLen;
P.getString("data", payDat, payLen); P.getString("data", payDat, payLen);
for (uint64_t i = 0; i < payLen; ++i){ for (uint64_t i = 0; i < payLen; ++i){
if ((i % 32) == 0){std::cout << std::endl;} if ((i % 32) == 0){std::cout << std::endl;}

View file

@ -12,7 +12,7 @@ void AnalyserRTSP::init(Util::Config &conf){
void AnalyserRTSP::incoming(const DTSC::Packet &pkt){ void AnalyserRTSP::incoming(const DTSC::Packet &pkt){
char *dataPtr; char *dataPtr;
uint32_t dataSize; size_t dataSize;
pkt.getString("data", dataPtr, dataSize); pkt.getString("data", dataPtr, dataSize);
DETAIL_MED("Received %ub %sfor track %lu (%s) @ %llums", dataSize, pkt.getFlag("keyframe")?"keyframe ":"", pkt.getTrackId(), DETAIL_MED("Received %ub %sfor track %lu (%s) @ %llums", dataSize, pkt.getFlag("keyframe")?"keyframe ":"", pkt.getTrackId(),
myMeta.tracks[pkt.getTrackId()].getIdentifier().c_str(), pkt.getTime()); myMeta.tracks[pkt.getTrackId()].getIdentifier().c_str(), pkt.getTime());

View file

@ -385,7 +385,7 @@ int main_loop(int argc, char **argv){
// Check if we have a usable server, if not, print messages with helpful hints // Check if we have a usable server, if not, print messages with helpful hints
{ {
std::string web_port = JSON::Value((long long)Controller::conf.getInteger("port")).asString(); std::string web_port = JSON::Value(Controller::conf.getInteger("port")).asString();
// check for username // check for username
if (!Controller::Storage.isMember("account") || Controller::Storage["account"].size() < 1){ if (!Controller::Storage.isMember("account") || Controller::Storage["account"].size() < 1){
Controller::Log("CONF", Controller::Log("CONF",
@ -530,7 +530,6 @@ int main(int argc, char **argv){
Util::Procs::setHandler(); // set child handler Util::Procs::setHandler(); // set child handler
{ {
struct sigaction new_action; struct sigaction new_action;
struct sigaction cur_action;
new_action.sa_sigaction = handleUSR1; new_action.sa_sigaction = handleUSR1;
sigemptyset(&new_action.sa_mask); sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0; new_action.sa_flags = 0;
@ -547,7 +546,6 @@ int main(int argc, char **argv){
Util::Procs::reaper_thread = 0; Util::Procs::reaper_thread = 0;
{ {
struct sigaction new_action; struct sigaction new_action;
struct sigaction cur_action;
new_action.sa_sigaction = handleUSR1; new_action.sa_sigaction = handleUSR1;
sigemptyset(&new_action.sa_mask); sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0; new_action.sa_flags = 0;
@ -584,7 +582,7 @@ int main(int argc, char **argv){
execvp(myFile.c_str(), argv); execvp(myFile.c_str(), argv);
FAIL_MSG("Error restarting: %s", strerror(errno)); FAIL_MSG("Error restarting: %s", strerror(errno));
} }
INFO_MSG("Controller uncleanly shut down! Restarting in %llu...", reTimer); INFO_MSG("Controller uncleanly shut down! Restarting in %" PRIu64 "...", reTimer);
Util::wait(reTimer); Util::wait(reTimer);
reTimer += 1000; reTimer += 1000;
} }

View file

@ -7,6 +7,7 @@
#include <mist/defines.h> #include <mist/defines.h>
#include <mist/timing.h> #include <mist/timing.h>
#include <mist/procs.h> #include <mist/procs.h>
#include <mist/bitfields.h>
#include "controller_api.h" #include "controller_api.h"
#include "controller_storage.h" #include "controller_storage.h"
#include "controller_streams.h" #include "controller_streams.h"
@ -190,7 +191,7 @@ void Controller::handleWebSocket(HTTP::Parser & H, Socket::Connection & C){
sent = true; sent = true;
JSON::Value tmp; JSON::Value tmp;
tmp[0u] = "log"; tmp[0u] = "log";
tmp[1u].append((long long)rlxLog.getInt("time", logPos)); tmp[1u].append(rlxLog.getInt("time", logPos));
tmp[1u].append(rlxLog.getPointer("kind", logPos)); tmp[1u].append(rlxLog.getPointer("kind", logPos));
tmp[1u].append(rlxLog.getPointer("msg", logPos)); tmp[1u].append(rlxLog.getPointer("msg", logPos));
W.sendFrame(tmp.toString()); W.sendFrame(tmp.toString());
@ -200,14 +201,14 @@ void Controller::handleWebSocket(HTTP::Parser & H, Socket::Connection & C){
sent = true; sent = true;
JSON::Value tmp; JSON::Value tmp;
tmp[0u] = "access"; tmp[0u] = "access";
tmp[1u].append((long long)rlxAccs.getInt("time", accsPos)); tmp[1u].append(rlxAccs.getInt("time", accsPos));
tmp[1u].append(rlxAccs.getPointer("session", accsPos)); tmp[1u].append(rlxAccs.getPointer("session", accsPos));
tmp[1u].append(rlxAccs.getPointer("stream", accsPos)); tmp[1u].append(rlxAccs.getPointer("stream", accsPos));
tmp[1u].append(rlxAccs.getPointer("connector", accsPos)); tmp[1u].append(rlxAccs.getPointer("connector", accsPos));
tmp[1u].append(rlxAccs.getPointer("host", accsPos)); tmp[1u].append(rlxAccs.getPointer("host", accsPos));
tmp[1u].append((long long)rlxAccs.getInt("duration", accsPos)); tmp[1u].append(rlxAccs.getInt("duration", accsPos));
tmp[1u].append((long long)rlxAccs.getInt("up", accsPos)); tmp[1u].append(rlxAccs.getInt("up", accsPos));
tmp[1u].append((long long)rlxAccs.getInt("down", accsPos)); tmp[1u].append(rlxAccs.getInt("down", accsPos));
tmp[1u].append(rlxAccs.getPointer("tags", accsPos)); tmp[1u].append(rlxAccs.getPointer("tags", accsPos));
W.sendFrame(tmp.toString()); W.sendFrame(tmp.toString());
accsPos++; accsPos++;
@ -228,10 +229,10 @@ void Controller::handleWebSocket(HTTP::Parser & H, Socket::Connection & C){
JSON::Value tmp; JSON::Value tmp;
tmp[0u] = "stream"; tmp[0u] = "stream";
tmp[1u].append(strm); tmp[1u].append(strm);
tmp[1u].append((long long)tmpStat.status); tmp[1u].append(tmpStat.status);
tmp[1u].append((long long)tmpStat.viewers); tmp[1u].append(tmpStat.viewers);
tmp[1u].append((long long)tmpStat.inputs); tmp[1u].append(tmpStat.inputs);
tmp[1u].append((long long)tmpStat.outputs); tmp[1u].append(tmpStat.outputs);
W.sendFrame(tmp.toString()); W.sendFrame(tmp.toString());
} }
} }
@ -241,10 +242,10 @@ void Controller::handleWebSocket(HTTP::Parser & H, Socket::Connection & C){
JSON::Value tmp; JSON::Value tmp;
tmp[0u] = "stream"; tmp[0u] = "stream";
tmp[1u].append(strm); tmp[1u].append(strm);
tmp[1u].append((long long)0); tmp[1u].append(0u);
tmp[1u].append((long long)0); tmp[1u].append(0u);
tmp[1u].append((long long)0); tmp[1u].append(0u);
tmp[1u].append((long long)0); tmp[1u].append(0u);
W.sendFrame(tmp.toString()); W.sendFrame(tmp.toString());
strmRemove.erase(strm); strmRemove.erase(strm);
lastStrmStat.erase(strm); lastStrmStat.erase(strm);
@ -710,7 +711,7 @@ void Controller::handleAPICommands(JSON::Value & Request, JSON::Value & Response
/*LTS-END*/ /*LTS-END*/
if (!Request.isMember("minimal") || Request.isMember("streams") || Request.isMember("addstream") || Request.isMember("deletestream")){ if (!Request.isMember("minimal") || Request.isMember("streams") || Request.isMember("addstream") || Request.isMember("deletestream")){
if (!Request.isMember("streams") && (Request.isMember("addstream") || Request.isMember("deletestream"))){ if (!Request.isMember("streams") && (Request.isMember("addstream") || Request.isMember("deletestream"))){
Response["streams"]["incomplete list"] = 1ll; Response["streams"]["incomplete list"] = 1u;
if (Request.isMember("addstream")){ if (Request.isMember("addstream")){
jsonForEach(Request["addstream"], jit){ jsonForEach(Request["addstream"], jit){
if (Controller::Storage["streams"].isMember(jit.key())){ if (Controller::Storage["streams"].isMember(jit.key())){

View file

@ -2,6 +2,7 @@
#include <string.h> #include <string.h>
#include <fstream> #include <fstream>
#include <set> #include <set>
#include <mist/defines.h>
#include <mist/config.h> #include <mist/config.h>
#include <mist/procs.h> #include <mist/procs.h>
#include "controller_capabilities.h" #include "controller_capabilities.h"
@ -381,23 +382,23 @@ namespace Controller {
} }
continue; continue;
} }
long long int i; uint64_t i;
if (sscanf(line, "MemTotal : %lli kB", &i) == 1){ if (sscanf(line, "MemTotal : %" PRIu64 " kB", &i) == 1){
capa["mem"]["total"] = i / 1024; capa["mem"]["total"] = i / 1024;
} }
if (sscanf(line, "MemFree : %lli kB", &i) == 1){ if (sscanf(line, "MemFree : %" PRIu64 " kB", &i) == 1){
capa["mem"]["free"] = i / 1024; capa["mem"]["free"] = i / 1024;
} }
if (sscanf(line, "SwapTotal : %lli kB", &i) == 1){ if (sscanf(line, "SwapTotal : %" PRIu64 " kB", &i) == 1){
capa["mem"]["swaptotal"] = i / 1024; capa["mem"]["swaptotal"] = i / 1024;
} }
if (sscanf(line, "SwapFree : %lli kB", &i) == 1){ if (sscanf(line, "SwapFree : %" PRIu64 " kB", &i) == 1){
capa["mem"]["swapfree"] = i / 1024; capa["mem"]["swapfree"] = i / 1024;
} }
if (sscanf(line, "Buffers : %lli kB", &i) == 1){ if (sscanf(line, "Buffers : %" PRIu64 " kB", &i) == 1){
bufcache += i / 1024; bufcache += i / 1024;
} }
if (sscanf(line, "Cached : %lli kB", &i) == 1){ if (sscanf(line, "Cached : %" PRIu64 " kB", &i) == 1){
bufcache += i / 1024; bufcache += i / 1024;
} }
} }
@ -413,23 +414,23 @@ namespace Controller {
//parse lines here //parse lines here
float onemin, fivemin, fifteenmin; float onemin, fivemin, fifteenmin;
if (sscanf(line, "%f %f %f", &onemin, &fivemin, &fifteenmin) == 3){ if (sscanf(line, "%f %f %f", &onemin, &fivemin, &fifteenmin) == 3){
capa["load"]["one"] = (long long int)(onemin * 100); capa["load"]["one"] = uint64_t(onemin * 100);
capa["load"]["five"] = (long long int)(fivemin * 100); capa["load"]["five"] = uint64_t(fivemin * 100);
capa["load"]["fifteen"] = (long long int)(fifteenmin * 100); capa["load"]["fifteen"] = uint64_t(fifteenmin * 100);
} }
} }
std::ifstream cpustat("/proc/stat"); std::ifstream cpustat("/proc/stat");
if (cpustat){ if (cpustat){
char line[300]; char line[300];
while (cpustat.getline(line, 300)){ while (cpustat.getline(line, 300)){
static unsigned long long cl_total = 0, cl_idle = 0; static uint64_t cl_total = 0, cl_idle = 0;
unsigned long long c_user, c_nice, c_syst, c_idle, c_total; uint64_t c_user, c_nice, c_syst, c_idle, c_total;
if (sscanf(line, "cpu %Lu %Lu %Lu %Lu", &c_user, &c_nice, &c_syst, &c_idle) == 4){ if (sscanf(line, "cpu %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &c_user, &c_nice, &c_syst, &c_idle) == 4){
c_total = c_user + c_nice + c_syst + c_idle; c_total = c_user + c_nice + c_syst + c_idle;
if (c_total - cl_total > 0){ if (c_total - cl_total > 0){
capa["cpu_use"] = (long long int)(1000 - ((c_idle - cl_idle) * 1000) / (c_total - cl_total)); capa["cpu_use"] = (1000 - ((c_idle - cl_idle) * 1000) / (c_total - cl_total));
}else{ }else{
capa["cpu_use"] = 0ll; capa["cpu_use"] = 0u;
} }
cl_total = c_total; cl_total = c_total;
cl_idle = c_idle; cl_idle = c_idle;

View file

@ -64,7 +64,10 @@ namespace Controller {
/// Deletes the shared memory page with connector information /// Deletes the shared memory page with connector information
/// in preparation of shutdown. /// in preparation of shutdown.
void prepareActiveConnectorsForShutdown(){ void prepareActiveConnectorsForShutdown(){
IPC::sharedPage f("MstCnns", 4096, true, false); IPC::sharedPage f("MstCnns", 4096, false, false);
if (f){
f.master = true;
}
} }
/// Forgets all active connectors, preventing them from being killed, /// Forgets all active connectors, preventing them from being killed,
@ -104,7 +107,7 @@ namespace Controller {
}else{ }else{
if (it.key() == "debug"){ if (it.key() == "debug"){
static std::string debugLvlStr; static std::string debugLvlStr;
debugLvlStr = JSON::Value((long long)Util::Config::printDebugLevel).asString(); debugLvlStr = JSON::Value(Util::Config::printDebugLevel).asString();
argarr[argnum++] = (char*)((*it)["option"].asStringRef().c_str()); argarr[argnum++] = (char*)((*it)["option"].asStringRef().c_str());
argarr[argnum++] = (char*)debugLvlStr.c_str(); argarr[argnum++] = (char*)debugLvlStr.c_str();
} }

View file

@ -35,7 +35,7 @@ namespace Controller{
updateLicense("&boot=1"); updateLicense("&boot=1");
checkLicense(); checkLicense();
}else{ }else{
lastCheck = std::min(Util::epoch(), currentLicense["valid_from"].asInt()); lastCheck = std::min(Util::epoch(), (uint64_t)currentLicense["valid_from"].asInt());
} }
}else{ }else{
updateLicense("&boot=1"); updateLicense("&boot=1");
@ -46,7 +46,7 @@ namespace Controller{
bool isLicensed(){ bool isLicensed(){
uint64_t now = Util::epoch() + timeOffset; uint64_t now = Util::epoch() + timeOffset;
#if DEBUG >= DLVL_DEVEL #if DEBUG >= DLVL_DEVEL
INFO_MSG("Verifying license against %llu: %s", now, currentLicense.toString().c_str()); INFO_MSG("Verifying license against %" PRIu64 ": %s", now, currentLicense.toString().c_str());
#endif #endif
//Print messages for user, if any //Print messages for user, if any
if (currentLicense.isMember("user_msg") && currentLicense["user_msg"].asStringRef().size()){ if (currentLicense.isMember("user_msg") && currentLicense["user_msg"].asStringRef().size()){
@ -104,7 +104,7 @@ namespace Controller{
if (currID){ if (currID){
char aesKey[16]; char aesKey[16];
if (strlen(SUPER_SECRET) >= 32){ if (strlen(SUPER_SECRET) >= 32){
parseKey(SUPER_SECRET SUPER_SECRET + 7,aesKey,16); parseKey((SUPER_SECRET SUPER_SECRET)+7,aesKey,16);
}else{ }else{
parseKey("4E56721C67306E1F473156F755FF5570",aesKey,16); parseKey("4E56721C67306E1F473156F755FF5570",aesKey,16);
} }
@ -128,7 +128,7 @@ namespace Controller{
void readLicense(uint64_t licID, const std::string & input, bool fromServer){ void readLicense(uint64_t licID, const std::string & input, bool fromServer){
char aesKey[16]; char aesKey[16];
if (strlen(SUPER_SECRET) >= 32){ if (strlen(SUPER_SECRET) >= 32){
parseKey(SUPER_SECRET SUPER_SECRET + 7,aesKey,16); parseKey((SUPER_SECRET SUPER_SECRET)+ 7,aesKey,16);
}else{ }else{
parseKey("4E56721C67306E1F473156F755FF5570",aesKey,16); parseKey("4E56721C67306E1F473156F755FF5570",aesKey,16);
} }
@ -158,10 +158,10 @@ namespace Controller{
uint64_t localTime = Util::epoch(); uint64_t localTime = Util::epoch();
uint64_t remoteTime = newLicense["time"].asInt(); uint64_t remoteTime = newLicense["time"].asInt();
if (localTime > remoteTime + 60){ if (localTime > remoteTime + 60){
WARN_MSG("Your computer clock is %u seconds ahead! Please ensure your computer clock is set correctly.", localTime - remoteTime); WARN_MSG("Your computer clock is %" PRIu64 " seconds ahead! Please ensure your computer clock is set correctly.", localTime - remoteTime);
} }
if (localTime < remoteTime - 60){ if (localTime < remoteTime - 60){
WARN_MSG("Your computer clock is %u seconds late! Please ensure your computer clock is set correctly.", remoteTime - localTime); WARN_MSG("Your computer clock is %" PRIu64 " seconds late! Please ensure your computer clock is set correctly.", remoteTime - localTime);
} }
timeOffset = remoteTime - localTime; timeOffset = remoteTime - localTime;
@ -177,7 +177,7 @@ namespace Controller{
if (currentLicense["store"].asBool()){ if (currentLicense["store"].asBool()){
if (Storage["license"].asStringRef() != input){ if (Storage["license"].asStringRef() != input){
Storage["license"] = input; Storage["license"] = input;
Storage["license_id"] = (long long)licID; Storage["license_id"] = licID;
INFO_MSG("Stored license for offline use"); INFO_MSG("Stored license for offline use");
} }
} }

View file

@ -29,7 +29,7 @@ namespace Controller{
pid_t ret = Util::startPush(stream, target); pid_t ret = Util::startPush(stream, target);
if (ret){ if (ret){
JSON::Value push; JSON::Value push;
push.append((long long)ret); push.append(ret);
push.append(stream); push.append(stream);
push.append(originalTarget); push.append(originalTarget);
push.append(target); push.append(target);
@ -114,10 +114,10 @@ namespace Controller{
static void readPushList(char * pwo){ static void readPushList(char * pwo){
activePushes.clear(); activePushes.clear();
pid_t p = Bit::btohl(pwo); pid_t p = Bit::btohl(pwo);
HIGH_MSG("Recovering pushes: %lu", (uint32_t)p); HIGH_MSG("Recovering pushes: %" PRIu32, (uint32_t)p);
while (p > 1){ while (p > 1){
JSON::Value push; JSON::Value push;
push.append((long long)p); push.append(p);
pwo += 4; pwo += 4;
for (uint8_t i = 0; i < 3; ++i){ for (uint8_t i = 0; i < 3; ++i){
uint16_t l = Bit::btohs(pwo); uint16_t l = Bit::btohs(pwo);
@ -244,13 +244,13 @@ namespace Controller{
startTime = true; startTime = true;
} }
if (request.isMember("completetime") && request["completetime"].isInt()){ if (request.isMember("completetime") && request["completetime"].isInt()){
if (!startTime){newPush.append(0ll);} if (!startTime){newPush.append(0u);}
newPush.append(request["completetime"]); newPush.append(request["completetime"]);
} }
} }
long long epo = Util::epoch(); long long epo = Util::epoch();
if (newPush.size() > 3 && newPush[3u].asInt() <= epo){ if (newPush.size() > 3 && newPush[3u].asInt() <= epo){
WARN_MSG("Automatic push not added: removal time is in the past! (%lld <= %lld)", newPush[3u].asInt(), Util::epoch()); WARN_MSG("Automatic push not added: removal time is in the past! (%" PRId64 " <= %" PRIu64 ")", newPush[3u].asInt(), Util::epoch());
return; return;
} }
bool edited = false; bool edited = false;

View file

@ -7,6 +7,7 @@
#include <mist/dtsc.h> #include <mist/dtsc.h>
#include <mist/procs.h> #include <mist/procs.h>
#include <mist/stream.h> #include <mist/stream.h>
#include <mist/bitfields.h>
#include "controller_statistics.h" #include "controller_statistics.h"
#include "controller_limits.h" #include "controller_limits.h"
#include "controller_push.h" #include "controller_push.h"
@ -76,24 +77,24 @@ void Controller::updateBandwidthConfig(){
//For server-wide totals. Local to this file only. //For server-wide totals. Local to this file only.
struct streamTotals { struct streamTotals {
unsigned long long upBytes; uint64_t upBytes;
unsigned long long downBytes; uint64_t downBytes;
unsigned long long inputs; uint64_t inputs;
unsigned long long outputs; uint64_t outputs;
unsigned long long viewers; uint64_t viewers;
unsigned long long currIns; uint64_t currIns;
unsigned long long currOuts; uint64_t currOuts;
unsigned long long currViews; uint64_t currViews;
uint8_t status; uint8_t status;
}; };
static std::map<std::string, struct streamTotals> streamStats; static std::map<std::string, struct streamTotals> streamStats;
static unsigned long long servUpBytes = 0; static uint64_t servUpBytes = 0;
static unsigned long long servDownBytes = 0; static uint64_t servDownBytes = 0;
static unsigned long long servUpOtherBytes = 0; static uint64_t servUpOtherBytes = 0;
static unsigned long long servDownOtherBytes = 0; static uint64_t servDownOtherBytes = 0;
static unsigned long long servInputs = 0; static uint64_t servInputs = 0;
static unsigned long long servOutputs = 0; static uint64_t servOutputs = 0;
static unsigned long long servViewers = 0; static uint64_t servViewers = 0;
Controller::sessIndex::sessIndex(std::string dhost, unsigned int dcrc, std::string dstreamName, std::string dconnector){ Controller::sessIndex::sessIndex(std::string dhost, unsigned int dcrc, std::string dstreamName, std::string dconnector){
ID = "UNSET"; ID = "UNSET";
@ -317,7 +318,7 @@ void Controller::writeSessionCache(){
/// statistics from all connected clients, as well as wipes /// statistics from all connected clients, as well as wipes
/// old statistics that have disconnected over 10 minutes ago. /// old statistics that have disconnected over 10 minutes ago.
void Controller::SharedMemStats(void * config){ void Controller::SharedMemStats(void * config){
DEBUG_MSG(DLVL_HIGH, "Starting stats thread"); HIGH_MSG("Starting stats thread");
IPC::sharedServer statServer(SHM_STATISTICS, STAT_EX_SIZE, true); IPC::sharedServer statServer(SHM_STATISTICS, STAT_EX_SIZE, true);
statPointer = &statServer; statPointer = &statServer;
shmSessions = new IPC::sharedPage(SHM_SESSIONS, SHM_SESSIONS_SIZE, true); shmSessions = new IPC::sharedPage(SHM_SESSIONS, SHM_SESSIONS_SIZE, true);
@ -435,7 +436,7 @@ void Controller::SharedMemStats(void * config){
shmSessions->master = false; shmSessions->master = false;
}else{/*LTS-START*/ }else{/*LTS-START*/
if (Controller::killOnExit){ if (Controller::killOnExit){
DEBUG_MSG(DLVL_WARN, "Killing all connected clients to force full shutdown"); WARN_MSG("Killing all connected clients to force full shutdown");
statServer.finishEach(); statServer.finishEach();
} }
/*LTS-END*/ /*LTS-END*/
@ -637,7 +638,7 @@ Controller::sessType Controller::statSession::getSessType(){
} }
/// Archives the given connection. /// Archives the given connection.
void Controller::statSession::wipeOld(unsigned long long cutOff){ void Controller::statSession::wipeOld(uint64_t cutOff){
if (firstSec > cutOff){ if (firstSec > cutOff){
return; return;
} }
@ -675,7 +676,7 @@ void Controller::statSession::wipeOld(unsigned long long cutOff){
} }
} }
void Controller::statSession::ping(const Controller::sessIndex & index, unsigned long long disconnectPoint){ void Controller::statSession::ping(const Controller::sessIndex & index, uint64_t disconnectPoint){
if (!tracked){return;} if (!tracked){return;}
if (lastSec < disconnectPoint){ if (lastSec < disconnectPoint){
switch (sessionType){ switch (sessionType){
@ -688,6 +689,8 @@ void Controller::statSession::ping(const Controller::sessIndex & index, unsigned
case SESS_VIEWER: case SESS_VIEWER:
if (streamStats[index.streamName].currViews){streamStats[index.streamName].currViews--;} if (streamStats[index.streamName].currViews){streamStats[index.streamName].currViews--;}
break; break;
default:
break;
} }
uint64_t duration = lastSec - firstActive; uint64_t duration = lastSec - firstActive;
if (duration < 1){duration = 1;} if (duration < 1){duration = 1;}
@ -807,17 +810,17 @@ void Controller::statSession::switchOverTo(statSession & newSess, unsigned long
} }
/// Returns the first measured timestamp in this session. /// Returns the first measured timestamp in this session.
unsigned long long Controller::statSession::getStart(){ uint64_t Controller::statSession::getStart(){
return firstSec; return firstSec;
} }
/// Returns the last measured timestamp in this session. /// Returns the last measured timestamp in this session.
unsigned long long Controller::statSession::getEnd(){ uint64_t Controller::statSession::getEnd(){
return lastSec; return lastSec;
} }
/// Returns true if there is data for this session at timestamp t. /// Returns true if there is data for this session at timestamp t.
bool Controller::statSession::hasDataFor(unsigned long long t){ bool Controller::statSession::hasDataFor(uint64_t t){
if (lastSec < t){return false;} if (lastSec < t){return false;}
if (firstSec > t){return false;} if (firstSec > t){return false;}
if (oldConns.size()){ if (oldConns.size()){
@ -826,7 +829,7 @@ bool Controller::statSession::hasDataFor(unsigned long long t){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.hasDataFor(t)){return true;} if (it->second.hasDataFor(t)){return true;}
} }
} }
@ -842,7 +845,7 @@ bool Controller::statSession::hasData(){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.log.size()){return true;} if (it->second.log.size()){return true;}
} }
} }
@ -850,7 +853,7 @@ bool Controller::statSession::hasData(){
} }
/// Returns true if this session should count as a viewer on the given timestamp. /// Returns true if this session should count as a viewer on the given timestamp.
bool Controller::statSession::isViewerOn(unsigned long long t){ bool Controller::statSession::isViewerOn(uint64_t t){
return getUp(t) + getDown(t) > COUNTABLE_BYTES; return getUp(t) + getDown(t) > COUNTABLE_BYTES;
} }
@ -877,8 +880,8 @@ bool Controller::statSession::isViewer(){
} }
/// Returns the cumulative connected time for this session at timestamp t. /// Returns the cumulative connected time for this session at timestamp t.
long long Controller::statSession::getConnTime(unsigned long long t){ uint64_t Controller::statSession::getConnTime(uint64_t t){
long long retVal = 0; uint64_t retVal = 0;
if (oldConns.size()){ if (oldConns.size()){
for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){ for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){
if (it->hasDataFor(t)){ if (it->hasDataFor(t)){
@ -887,7 +890,7 @@ long long Controller::statSession::getConnTime(unsigned long long t){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.hasDataFor(t)){ if (it->second.hasDataFor(t)){
retVal += it->second.getDataFor(t).time; retVal += it->second.getDataFor(t).time;
} }
@ -897,9 +900,9 @@ long long Controller::statSession::getConnTime(unsigned long long t){
} }
/// Returns the last requested media timestamp for this session at timestamp t. /// Returns the last requested media timestamp for this session at timestamp t.
long long Controller::statSession::getLastSecond(unsigned long long t){ uint64_t Controller::statSession::getLastSecond(uint64_t t){
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.hasDataFor(t)){ if (it->second.hasDataFor(t)){
return it->second.getDataFor(t).lastSecond; return it->second.getDataFor(t).lastSecond;
} }
@ -916,8 +919,8 @@ long long Controller::statSession::getLastSecond(unsigned long long t){
} }
/// Returns the cumulative downloaded bytes for this session at timestamp t. /// Returns the cumulative downloaded bytes for this session at timestamp t.
long long Controller::statSession::getDown(unsigned long long t){ uint64_t Controller::statSession::getDown(uint64_t t){
long long retVal = wipedDown; uint64_t retVal = wipedDown;
if (oldConns.size()){ if (oldConns.size()){
for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){ for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){
if (it->hasDataFor(t)){ if (it->hasDataFor(t)){
@ -926,7 +929,7 @@ long long Controller::statSession::getDown(unsigned long long t){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.hasDataFor(t)){ if (it->second.hasDataFor(t)){
retVal += it->second.getDataFor(t).down; retVal += it->second.getDataFor(t).down;
} }
@ -936,8 +939,8 @@ long long Controller::statSession::getDown(unsigned long long t){
} }
/// Returns the cumulative uploaded bytes for this session at timestamp t. /// Returns the cumulative uploaded bytes for this session at timestamp t.
long long Controller::statSession::getUp(unsigned long long t){ uint64_t Controller::statSession::getUp(uint64_t t){
long long retVal = wipedUp; uint64_t retVal = wipedUp;
if (oldConns.size()){ if (oldConns.size()){
for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){ for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){
if (it->hasDataFor(t)){ if (it->hasDataFor(t)){
@ -946,7 +949,7 @@ long long Controller::statSession::getUp(unsigned long long t){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.hasDataFor(t)){ if (it->second.hasDataFor(t)){
retVal += it->second.getDataFor(t).up; retVal += it->second.getDataFor(t).up;
} }
@ -956,8 +959,8 @@ long long Controller::statSession::getUp(unsigned long long t){
} }
/// Returns the cumulative downloaded bytes for this session at timestamp t. /// Returns the cumulative downloaded bytes for this session at timestamp t.
long long Controller::statSession::getDown(){ uint64_t Controller::statSession::getDown(){
long long retVal = wipedDown; uint64_t retVal = wipedDown;
if (oldConns.size()){ if (oldConns.size()){
for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){ for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){
if (it->log.size()){ if (it->log.size()){
@ -966,7 +969,7 @@ long long Controller::statSession::getDown(){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.log.size()){ if (it->second.log.size()){
retVal += it->second.log.rbegin()->second.down; retVal += it->second.log.rbegin()->second.down;
} }
@ -976,8 +979,8 @@ long long Controller::statSession::getDown(){
} }
/// Returns the cumulative uploaded bytes for this session at timestamp t. /// Returns the cumulative uploaded bytes for this session at timestamp t.
long long Controller::statSession::getUp(){ uint64_t Controller::statSession::getUp(){
long long retVal = wipedUp; uint64_t retVal = wipedUp;
if (oldConns.size()){ if (oldConns.size()){
for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){ for (std::deque<statStorage>::iterator it = oldConns.begin(); it != oldConns.end(); ++it){
if (it->log.size()){ if (it->log.size()){
@ -986,7 +989,7 @@ long long Controller::statSession::getUp(){
} }
} }
if (curConns.size()){ if (curConns.size()){
for (std::map<unsigned long, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){ for (std::map<uint64_t, statStorage>::iterator it = curConns.begin(); it != curConns.end(); ++it){
if (it->second.log.size()){ if (it->second.log.size()){
retVal += it->second.log.rbegin()->second.up; retVal += it->second.log.rbegin()->second.up;
} }
@ -996,35 +999,31 @@ long long Controller::statSession::getUp(){
} }
/// Returns the cumulative downloaded bytes per second for this session at timestamp t. /// Returns the cumulative downloaded bytes per second for this session at timestamp t.
long long Controller::statSession::getBpsDown(unsigned long long t){ uint64_t Controller::statSession::getBpsDown(uint64_t t){
unsigned long long aTime = t - 5; uint64_t aTime = t - 5;
if (aTime < firstSec){ if (aTime < firstSec){
aTime = firstSec; aTime = firstSec;
} }
long long valA = getDown(aTime); if (t <= aTime){
long long valB = getDown(t);
if (t > aTime){
//INFO_MSG("Saying the speed from time %lli to %lli (being %lli - %lli) is %lli.", aTime, t, valB, valA, (valB - valA) / (t - aTime));
return (valB - valA) / (t - aTime);
}else{
//INFO_MSG("Saying the speed from time %lli to %lli (being %lli - %lli) is %lli.", aTime, t, valB, valA, 0);
return 0; return 0;
} }
uint64_t valA = getDown(aTime);
uint64_t valB = getDown(t);
return (valB - valA) / (t - aTime);
} }
/// Returns the cumulative uploaded bytes per second for this session at timestamp t. /// Returns the cumulative uploaded bytes per second for this session at timestamp t.
long long Controller::statSession::getBpsUp(unsigned long long t){ uint64_t Controller::statSession::getBpsUp(uint64_t t){
unsigned long long aTime = t - 5; uint64_t aTime = t - 5;
if (aTime < firstSec){ if (aTime < firstSec){
aTime = firstSec; aTime = firstSec;
} }
long long valA = getUp(aTime); if (t <= aTime){
long long valB = getUp(t);
if (t > aTime){
return (valB - valA) / (t - aTime);
}else{
return 0; return 0;
} }
uint64_t valA = getUp(aTime);
uint64_t valB = getUp(t);
return (valB - valA) / (t - aTime);
} }
/// Returns true if there is data available for timestamp t. /// Returns true if there is data available for timestamp t.
@ -1068,7 +1067,7 @@ void Controller::statStorage::update(IPC::statExchange & data) {
/// This function is called by the shared memory page that holds statistics. /// This function is called by the shared memory page that holds statistics.
/// It updates the internally saved statistics data, moving across sessions or archiving when necessary. /// It updates the internally saved statistics data, moving across sessions or archiving when necessary.
void Controller::parseStatistics(char * data, size_t len, unsigned int id){ void Controller::parseStatistics(char * data, size_t len, uint32_t id){
//retrieve stats data //retrieve stats data
IPC::statExchange tmpEx(data); IPC::statExchange tmpEx(data);
//calculate the current session index, store as idx. //calculate the current session index, store as idx.
@ -1076,9 +1075,9 @@ void Controller::parseStatistics(char * data, size_t len, unsigned int id){
//if the connection was already indexed and it has changed, move it //if the connection was already indexed and it has changed, move it
if (connToSession.count(id) && connToSession[id] != idx){ if (connToSession.count(id) && connToSession[id] != idx){
if (sessions[connToSession[id]].getSessType() != SESS_UNSET){ if (sessions[connToSession[id]].getSessType() != SESS_UNSET){
INFO_MSG("Switching connection %lu from active session %s over to %s", id, connToSession[id].toStr().c_str(), idx.toStr().c_str()); INFO_MSG("Switching connection %" PRIu32 " from active session %s over to %s", id, connToSession[id].toStr().c_str(), idx.toStr().c_str());
}else{ }else{
INFO_MSG("Switching connection %lu from inactive session %s over to %s", id, connToSession[id].toStr().c_str(), idx.toStr().c_str()); INFO_MSG("Switching connection %" PRIu32 " from inactive session %s over to %s", id, connToSession[id].toStr().c_str(), idx.toStr().c_str());
} }
sessions[connToSession[id]].switchOverTo(sessions[idx], id); sessions[connToSession[id]].switchOverTo(sessions[idx], id);
if (!sessions[connToSession[id]].hasData()){ if (!sessions[connToSession[id]].hasData()){
@ -1086,7 +1085,7 @@ void Controller::parseStatistics(char * data, size_t len, unsigned int id){
} }
} }
if (!connToSession.count(id)){ if (!connToSession.count(id)){
INSANE_MSG("New connection: %lu as %s", id, idx.toStr().c_str()); INSANE_MSG("New connection: %" PRIu32 " as %s", id, idx.toStr().c_str());
} }
//store the index for later comparison //store the index for later comparison
connToSession[id] = idx; connToSession[id] = idx;
@ -1096,7 +1095,7 @@ void Controller::parseStatistics(char * data, size_t len, unsigned int id){
char counter = (*(data - 1)) & 0x7F; char counter = (*(data - 1)) & 0x7F;
if (counter == 126 || counter == 127){ if (counter == 126 || counter == 127){
//the data is no longer valid - connection has gone away, store for later //the data is no longer valid - connection has gone away, store for later
INSANE_MSG("Ended connection: %lu as %s", id, idx.toStr().c_str()); INSANE_MSG("Ended connection: %" PRIu32 " as %s", id, idx.toStr().c_str());
sessions[idx].finish(id); sessions[idx].finish(id);
connToSession.erase(id); connToSession.erase(id);
}else{ }else{
@ -1157,7 +1156,7 @@ bool Controller::hasViewers(std::string streamName){
void Controller::fillClients(JSON::Value & req, JSON::Value & rep){ void Controller::fillClients(JSON::Value & req, JSON::Value & rep){
tthread::lock_guard<tthread::mutex> guard(statsMutex); tthread::lock_guard<tthread::mutex> guard(statsMutex);
//first, figure out the timestamp wanted //first, figure out the timestamp wanted
long long int reqTime = 0; uint64_t reqTime = 0;
if (req.isMember("time")){ if (req.isMember("time")){
reqTime = req["time"].asInt(); reqTime = req["time"].asInt();
} }
@ -1233,7 +1232,7 @@ void Controller::fillClients(JSON::Value & req, JSON::Value & rep){
if (fields & STAT_CLI_UP){d.append(it->second.getUp(time));} if (fields & STAT_CLI_UP){d.append(it->second.getUp(time));}
if (fields & STAT_CLI_BPS_DOWN){d.append(it->second.getBpsDown(time));} if (fields & STAT_CLI_BPS_DOWN){d.append(it->second.getBpsDown(time));}
if (fields & STAT_CLI_BPS_UP){d.append(it->second.getBpsUp(time));} if (fields & STAT_CLI_BPS_UP){d.append(it->second.getBpsUp(time));}
if (fields & STAT_CLI_CRC){d.append((long long)it->first.crc);} if (fields & STAT_CLI_CRC){d.append(it->first.crc);}
rep["data"].append(d); rep["data"].append(d);
} }
} }
@ -1311,7 +1310,7 @@ void Controller::fillActive(JSON::Value & req, JSON::Value & rep, bool onlyNow){
rep[*it].null(); rep[*it].null();
jsonForEach(req, j){ jsonForEach(req, j){
if (j->asStringRef() == "clients"){ if (j->asStringRef() == "clients"){
rep[*it].append((long long)clients[*it]); rep[*it].append(clients[*it]);
} }
if (j->asStringRef() == "lastms"){ if (j->asStringRef() == "lastms"){
char pageId[NAME_BUFFER_SIZE]; char pageId[NAME_BUFFER_SIZE];
@ -1335,7 +1334,7 @@ void Controller::fillActive(JSON::Value & req, JSON::Value & rep, bool onlyNow){
rep[*it].append(lms); rep[*it].append(lms);
metaLocker.post(); metaLocker.post();
}else{ }else{
rep[*it].append(-1ll); rep[*it].append(-1);
} }
} }
} }
@ -1355,20 +1354,21 @@ class totalsData {
downbps = 0; downbps = 0;
upbps = 0; upbps = 0;
} }
void add(unsigned int down, unsigned int up, Controller::sessType sT){ void add(uint64_t down, uint64_t up, Controller::sessType sT){
switch (sT){ switch (sT){
case Controller::SESS_VIEWER: clients++; break; case Controller::SESS_VIEWER: clients++; break;
case Controller::SESS_INPUT: inputs++; break; case Controller::SESS_INPUT: inputs++; break;
case Controller::SESS_OUTPUT: outputs++; break; case Controller::SESS_OUTPUT: outputs++; break;
default: break;
} }
downbps += down; downbps += down;
upbps += up; upbps += up;
} }
long long clients; uint64_t clients;
long long inputs; uint64_t inputs;
long long outputs; uint64_t outputs;
long long downbps; uint64_t downbps;
long long upbps; uint64_t upbps;
}; };
/// This takes a "totals" request, and fills in the response data. /// This takes a "totals" request, and fills in the response data.
@ -1430,7 +1430,7 @@ void Controller::fillTotals(JSON::Value & req, JSON::Value & rep){
if (fields & STAT_TOT_BPS_DOWN){rep["fields"].append("downbps");} if (fields & STAT_TOT_BPS_DOWN){rep["fields"].append("downbps");}
if (fields & STAT_TOT_BPS_UP){rep["fields"].append("upbps");} if (fields & STAT_TOT_BPS_UP){rep["fields"].append("upbps");}
//start data collection //start data collection
std::map<long long unsigned int, totalsData> totalsCount; std::map<uint64_t, totalsData> totalsCount;
//loop over all sessions //loop over all sessions
/// \todo Make the interval configurable instead of 1 second /// \todo Make the interval configurable instead of 1 second
if (sessions.size()){ if (sessions.size()){
@ -1455,13 +1455,13 @@ void Controller::fillTotals(JSON::Value & req, JSON::Value & rep){
return; return;
} }
//yay! We have data! //yay! We have data!
rep["start"] = (long long)totalsCount.begin()->first; rep["start"] = totalsCount.begin()->first;
rep["end"] = (long long)totalsCount.rbegin()->first; rep["end"] = totalsCount.rbegin()->first;
rep["data"].null(); rep["data"].null();
rep["interval"].null(); rep["interval"].null();
long long prevT = 0; uint64_t prevT = 0;
JSON::Value i; JSON::Value i;
for (std::map<long long unsigned int, totalsData>::iterator it = totalsCount.begin(); it != totalsCount.end(); it++){ for (std::map<uint64_t, totalsData>::iterator it = totalsCount.begin(); it != totalsCount.end(); it++){
JSON::Value d; JSON::Value d;
if (fields & STAT_TOT_CLIENTS){d.append(it->second.clients);} if (fields & STAT_TOT_CLIENTS){d.append(it->second.clients);}
if (fields & STAT_TOT_INPUTS){d.append(it->second.inputs);} if (fields & STAT_TOT_INPUTS){d.append(it->second.inputs);}
@ -1471,13 +1471,13 @@ void Controller::fillTotals(JSON::Value & req, JSON::Value & rep){
rep["data"].append(d); rep["data"].append(d);
if (prevT){ if (prevT){
if (i.size() < 2){ if (i.size() < 2){
i.append(1ll); i.append(1u);
i.append((long long)(it->first - prevT)); i.append(it->first - prevT);
}else{ }else{
if (i[1u].asInt() != (long long)(it->first - prevT)){ if (i[1u].asInt() != it->first - prevT){
rep["interval"].append(i); rep["interval"].append(i);
i[0u] = 1ll; i[0u] = 1u;
i[1u] = (long long)(it->first - prevT); i[1u] = it->first - prevT;
}else{ }else{
i[0u] = i[0u].asInt() + 1; i[0u] = i[0u].asInt() + 1;
} }
@ -1510,9 +1510,9 @@ void Controller::handlePrometheus(HTTP::Parser & H, Socket::Connection & conn, i
//Collect core server stats //Collect core server stats
long long int cpu_use = 0; uint64_t cpu_use = 0;
long long int mem_total = 0, mem_free = 0, mem_bufcache = 0; uint64_t mem_total = 0, mem_free = 0, mem_bufcache = 0;
long long int bw_up_total = 0, bw_down_total = 0; uint64_t bw_up_total = 0, bw_down_total = 0;
{ {
std::ifstream cpustat("/proc/stat"); std::ifstream cpustat("/proc/stat");
if (cpustat){ if (cpustat){
@ -1576,7 +1576,7 @@ void Controller::handlePrometheus(HTTP::Parser & H, Socket::Connection & conn, i
} }
} }
} }
long long shm_total = 0, shm_free = 0; uint64_t shm_total = 0, shm_free = 0;
#if !defined(__CYGWIN__) && !defined(_WIN32) #if !defined(__CYGWIN__) && !defined(_WIN32)
{ {
struct statvfs shmd; struct statvfs shmd;
@ -1698,7 +1698,7 @@ void Controller::handlePrometheus(HTTP::Parser & H, Socket::Connection & conn, i
resp["mem_used"] = (mem_total - mem_free - mem_bufcache); resp["mem_used"] = (mem_total - mem_free - mem_bufcache);
resp["shm_total"] = shm_total; resp["shm_total"] = shm_total;
resp["shm_used"] = (shm_total - shm_free); resp["shm_used"] = (shm_total - shm_free);
resp["logs"] = (long long)Controller::logCounter; resp["logs"] = Controller::logCounter;
{//Scope for shortest possible blocking of statsMutex {//Scope for shortest possible blocking of statsMutex
tthread::lock_guard<tthread::mutex> guard(statsMutex); tthread::lock_guard<tthread::mutex> guard(statsMutex);
//collect the data first //collect the data first
@ -1732,34 +1732,34 @@ void Controller::handlePrometheus(HTTP::Parser & H, Socket::Connection & conn, i
} }
} }
resp["curr"].append((long long)totViewers); resp["curr"].append(totViewers);
resp["curr"].append((long long)totInputs); resp["curr"].append(totInputs);
resp["curr"].append((long long)totOutputs); resp["curr"].append(totOutputs);
resp["curr"].append((long long)sessions.size()); resp["curr"].append(sessions.size());
resp["tot"].append((long long)servViewers); resp["tot"].append(servViewers);
resp["tot"].append((long long)servInputs); resp["tot"].append(servInputs);
resp["tot"].append((long long)servOutputs); resp["tot"].append(servOutputs);
resp["st"].append((long long)bw_up_total); resp["st"].append(bw_up_total);
resp["st"].append((long long)bw_down_total); resp["st"].append(bw_down_total);
resp["bw"].append((long long)servUpBytes); resp["bw"].append(servUpBytes);
resp["bw"].append((long long)servDownBytes); resp["bw"].append(servDownBytes);
resp["bwlimit"] = (long long)bwLimit; resp["bwlimit"] = bwLimit;
resp["obw"].append((long long)servUpOtherBytes); resp["obw"].append(servUpOtherBytes);
resp["obw"].append((long long)servDownOtherBytes); resp["obw"].append(servDownOtherBytes);
for (std::map<std::string, struct streamTotals>::iterator it = streamStats.begin(); it != streamStats.end(); ++it){ for (std::map<std::string, struct streamTotals>::iterator it = streamStats.begin(); it != streamStats.end(); ++it){
resp["streams"][it->first]["tot"].append((long long)it->second.viewers); resp["streams"][it->first]["tot"].append(it->second.viewers);
resp["streams"][it->first]["tot"].append((long long)it->second.inputs); resp["streams"][it->first]["tot"].append(it->second.inputs);
resp["streams"][it->first]["tot"].append((long long)it->second.outputs); resp["streams"][it->first]["tot"].append(it->second.outputs);
resp["streams"][it->first]["bw"].append((long long)it->second.upBytes); resp["streams"][it->first]["bw"].append(it->second.upBytes);
resp["streams"][it->first]["bw"].append((long long)it->second.downBytes); resp["streams"][it->first]["bw"].append(it->second.downBytes);
resp["streams"][it->first]["curr"].append((long long)it->second.currViews); resp["streams"][it->first]["curr"].append(it->second.currViews);
resp["streams"][it->first]["curr"].append((long long)it->second.currIns); resp["streams"][it->first]["curr"].append(it->second.currIns);
resp["streams"][it->first]["curr"].append((long long)it->second.currOuts); resp["streams"][it->first]["curr"].append(it->second.currOuts);
} }
for (std::map<std::string, uint32_t>::iterator it = outputs.begin(); it != outputs.end(); ++it){ for (std::map<std::string, uint32_t>::iterator it = outputs.begin(); it != outputs.end(); ++it){
resp["outputs"][it->first] = (long long)it->second; resp["outputs"][it->first] = it->second;
} }
} }

View file

@ -26,10 +26,10 @@ namespace Controller {
void updateBandwidthConfig(); void updateBandwidthConfig();
struct statLog { struct statLog {
long time; uint64_t time;
long lastSecond; uint64_t lastSecond;
long long down; uint64_t down;
long long up; uint64_t up;
}; };
enum sessType { enum sessType {
@ -75,10 +75,10 @@ namespace Controller {
class statSession { class statSession {
private: private:
uint64_t firstActive; uint64_t firstActive;
unsigned long long firstSec; uint64_t firstSec;
unsigned long long lastSec; uint64_t lastSec;
unsigned long long wipedUp; uint64_t wipedUp;
unsigned long long wipedDown; uint64_t wipedDown;
std::deque<statStorage> oldConns; std::deque<statStorage> oldConns;
sessType sessionType; sessType sessionType;
bool tracked; bool tracked;
@ -88,30 +88,30 @@ namespace Controller {
uint32_t invalidate(); uint32_t invalidate();
uint32_t kill(); uint32_t kill();
char sync; char sync;
std::map<unsigned long, statStorage> curConns; std::map<uint64_t, statStorage> curConns;
std::set<std::string> tags; std::set<std::string> tags;
sessType getSessType(); sessType getSessType();
void wipeOld(unsigned long long); void wipeOld(uint64_t);
void finish(unsigned long index); void finish(uint64_t index);
void switchOverTo(statSession & newSess, unsigned long index); void switchOverTo(statSession & newSess, uint64_t index);
void update(unsigned long index, IPC::statExchange & data); void update(uint64_t index, IPC::statExchange & data);
void ping(const sessIndex & index, unsigned long long disconnectPoint); void ping(const sessIndex & index, uint64_t disconnectPoint);
unsigned long long getStart(); uint64_t getStart();
unsigned long long getEnd(); uint64_t getEnd();
bool isViewerOn(unsigned long long time); bool isViewerOn(uint64_t time);
bool isViewer(); bool isViewer();
bool hasDataFor(unsigned long long time); bool hasDataFor(uint64_t time);
bool hasData(); bool hasData();
long long getConnTime(unsigned long long time); uint64_t getConnTime(uint64_t time);
long long getLastSecond(unsigned long long time); uint64_t getLastSecond(uint64_t time);
long long getDown(unsigned long long time); uint64_t getDown(uint64_t time);
long long getUp(); uint64_t getUp();
long long getDown(); uint64_t getDown();
long long getUp(unsigned long long time); uint64_t getUp(uint64_t time);
long long getBpsDown(unsigned long long time); uint64_t getBpsDown(uint64_t time);
long long getBpsUp(unsigned long long time); uint64_t getBpsUp(uint64_t time);
long long getBpsDown(unsigned long long start, unsigned long long end); uint64_t getBpsDown(uint64_t start, uint64_t end);
long long getBpsUp(unsigned long long start, unsigned long long end); uint64_t getBpsUp(uint64_t start, uint64_t end);
}; };

View file

@ -19,7 +19,7 @@ namespace Controller{
JSON::Value Storage; ///< Global storage of data. JSON::Value Storage; ///< Global storage of data.
tthread::mutex configMutex; tthread::mutex configMutex;
tthread::mutex logMutex; tthread::mutex logMutex;
unsigned long long logCounter = 0; uint64_t logCounter = 0;
bool configChanged = false; bool configChanged = false;
bool restarting = false; bool restarting = false;
bool isTerminal = false; bool isTerminal = false;
@ -54,7 +54,7 @@ namespace Controller{
tthread::lock_guard<tthread::mutex> guard(logMutex); tthread::lock_guard<tthread::mutex> guard(logMutex);
JSON::Value m; JSON::Value m;
uint64_t logTime = Util::epoch(); uint64_t logTime = Util::epoch();
m.append((long long)logTime); m.append(logTime);
m.append(kind); m.append(kind);
m.append(message); m.append(message);
Storage["log"].append(m); Storage["log"].append(m);

View file

@ -16,7 +16,7 @@ namespace Controller {
extern bool restarting;///< Signals if the controller is shutting down (false) or restarting (true). extern bool restarting;///< Signals if the controller is shutting down (false) or restarting (true).
extern bool isTerminal;///< True if connected to a terminal and not a log file. extern bool isTerminal;///< True if connected to a terminal and not a log file.
extern bool isColorized;///< True if we colorize the output extern bool isColorized;///< True if we colorize the output
extern unsigned long long logCounter; ///<Count of logged messages since boot extern uint64_t logCounter; ///<Count of logged messages since boot
Util::RelAccX * logAccessor(); Util::RelAccX * logAccessor();
Util::RelAccX * accesslogAccessor(); Util::RelAccX * accesslogAccessor();

View file

@ -138,7 +138,6 @@ namespace Controller {
///\param data The stream configuration for the server. ///\param data The stream configuration for the server.
///\returns True if the server status changed ///\returns True if the server status changed
bool CheckAllStreams(JSON::Value & data){ bool CheckAllStreams(JSON::Value & data){
long long int currTime = Util::epoch();
jsonForEach(data, jit) { jsonForEach(data, jit) {
checkStream(jit.key(), (*jit)); checkStream(jit.key(), (*jit));
} }

View file

@ -87,7 +87,7 @@ namespace Controller{
void insertUpdateInfo(JSON::Value &ret){ void insertUpdateInfo(JSON::Value &ret){
tthread::lock_guard<tthread::mutex> guard(updaterMutex); tthread::lock_guard<tthread::mutex> guard(updaterMutex);
ret = updates; ret = updates;
if (updatePerc){ret["progress"] = (long long)updatePerc;} if (updatePerc){ret["progress"] = (uint16_t)updatePerc;}
} }
/// Downloads the latest details on updates /// Downloads the latest details on updates

View file

@ -34,7 +34,7 @@ void Controller::uplinkConnection(void * np) {
return; return;
} }
unsigned long long lastSend = Util::epoch() - 5; uint64_t lastSend = Util::epoch() - 5;
Socket::Connection uplink; Socket::Connection uplink;
while (Controller::conf.is_active) { while (Controller::conf.is_active) {
if (!uplink) { if (!uplink) {
@ -98,7 +98,7 @@ void Controller::uplinkConnection(void * np) {
} }
JSON::Value totalsRequest; JSON::Value totalsRequest;
Controller::fillClients(totalsRequest, data["clients"]); Controller::fillClients(totalsRequest, data["clients"]);
totalsRequest["start"] = (long long)lastSend; totalsRequest["start"] = lastSend;
Controller::fillTotals(totalsRequest, data["totals"]); Controller::fillTotals(totalsRequest, data["totals"]);
data["streams"] = Controller::Storage["streams"]; data["streams"] = Controller::Storage["streams"];
jsonForEach(data["streams"], it){ jsonForEach(data["streams"], it){

View file

@ -677,7 +677,7 @@ namespace Mist {
//Read in the metadata through a temporary JSON object //Read in the metadata through a temporary JSON object
///\todo Optimize this part. Find a way to not have to store the metadata in JSON first, but read it from the page immediately ///\todo Optimize this part. Find a way to not have to store the metadata in JSON first, but read it from the page immediately
JSON::Value tempJSONForMeta; JSON::Value tempJSONForMeta;
JSON::fromDTMI((const unsigned char *)tMeta.mapped + 8, len, tempForReadingMeta, tempJSONForMeta); JSON::fromDTMI((const char *)tMeta.mapped + 8, len, tempForReadingMeta, tempJSONForMeta);
tMeta.master = true; tMeta.master = true;
@ -743,7 +743,7 @@ namespace Mist {
//Read in the metadata through a temporary JSON object //Read in the metadata through a temporary JSON object
///\todo Optimize this part. Find a way to not have to store the metadata in JSON first, but read it from the page immediately ///\todo Optimize this part. Find a way to not have to store the metadata in JSON first, but read it from the page immediately
JSON::Value tempJSONForMeta; JSON::Value tempJSONForMeta;
JSON::fromDTMI((const unsigned char *)nProxy.metaPages[value].mapped + 8, len, tempForReadingMeta, tempJSONForMeta); JSON::fromDTMI((const char *)nProxy.metaPages[value].mapped + 8, len, tempForReadingMeta, tempJSONForMeta);
//Construct a metadata object for the current track //Construct a metadata object for the current track
DTSC::Meta trackMeta(tempJSONForMeta); DTSC::Meta trackMeta(tempJSONForMeta);
//If the track metadata does not contain the negotiated track, assume the metadata is currently being written, and skip the element for now. It will be instantiated in the next call. //If the track metadata does not contain the negotiated track, assume the metadata is currently being written, and skip the element for now. It will be instantiated in the next call.

View file

@ -118,7 +118,7 @@ namespace Mist {
//Do encryption/decryption here //Do encryption/decryption here
int tid = thisPacket.getTrackId(); int tid = thisPacket.getTrackId();
char * ivec; char * ivec;
unsigned int ivecLen; size_t ivecLen;
thisPacket.getString("ivec", ivec, ivecLen); thisPacket.getString("ivec", ivec, ivecLen);
char iVec[16]; char iVec[16];
if (ivecLen){ if (ivecLen){

View file

@ -141,7 +141,7 @@ namespace Mist {
DTSC::Track & trk = myMeta.tracks[tmpTag.getTrackID()]; DTSC::Track & trk = myMeta.tracks[tmpTag.getTrackID()];
if (trk.codec == "PCM" && trk.size == 16){ if (trk.codec == "PCM" && trk.size == 16){
char * ptr = 0; char * ptr = 0;
uint32_t ptrSize = 0; size_t ptrSize = 0;
thisPacket.getString("data", ptr, ptrSize); thisPacket.getString("data", ptr, ptrSize);
for (uint32_t i = 0; i < ptrSize; i+=2){ for (uint32_t i = 0; i < ptrSize; i+=2){
char tmpchar = ptr[i]; char tmpchar = ptr[i];

View file

@ -414,7 +414,7 @@ namespace Mist{
int packetId = 0; int packetId = 0;
char *data; char *data;
unsigned int dataLen; size_t dataLen;
for (std::vector<Playlist>::iterator pListIt = playlists.begin(); pListIt != playlists.end(); for (std::vector<Playlist>::iterator pListIt = playlists.begin(); pListIt != playlists.end();
pListIt++){ pListIt++){

View file

@ -217,7 +217,7 @@ namespace Mist{
trunBox.setSampleInformation(trunEntry, j); trunBox.setSampleInformation(trunEntry, j);
++j; ++j;
} }
trunBox.setDataOffset(88 + (12 * j) + 8); trunBox.setDataOffset(92 + (12 * j) + 8);
} }
if (Trk.type == "audio"){ if (Trk.type == "audio"){
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration); trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration);
@ -230,7 +230,7 @@ namespace Mist{
trunBox.setSampleInformation(trunEntry, j); trunBox.setSampleInformation(trunEntry, j);
++j; ++j;
} }
trunBox.setDataOffset(88 + (8 * j) + 8); trunBox.setDataOffset(92 + (8 * j) + 8);
} }
trafBox.setContent(trunBox, 2); trafBox.setContent(trunBox, 2);
moofBox.setContent(trafBox, 1); moofBox.setContent(trafBox, 1);
@ -316,7 +316,7 @@ namespace Mist{
return; return;
} }
char * data; char * data;
unsigned int dataLen; size_t dataLen;
thisPacket.getString("data", data, dataLen); thisPacket.getString("data", data, dataLen);
H.Chunkify(data, dataLen, myConn); H.Chunkify(data, dataLen, myConn);
} }

View file

@ -50,7 +50,7 @@ namespace Mist{
void OutH264::sendNext(){ void OutH264::sendNext(){
if (keysOnly && !thisPacket.getFlag("keyframe")){return;} if (keysOnly && !thisPacket.getFlag("keyframe")){return;}
char *dataPointer = 0; char *dataPointer = 0;
unsigned int len = 0; size_t len = 0;
thisPacket.getString("data", dataPointer, len); thisPacket.getString("data", dataPointer, len);
unsigned int i = 0; unsigned int i = 0;

View file

@ -74,7 +74,7 @@ namespace Mist {
return; return;
} }
char * dataPointer = 0; char * dataPointer = 0;
unsigned int len = 0; size_t len = 0;
thisPacket.getString("data", dataPointer, len); thisPacket.getString("data", dataPointer, len);
H.Chunkify(dataPointer, len, myConn); H.Chunkify(dataPointer, len, myConn);
} }

View file

@ -37,7 +37,7 @@ namespace Mist {
JSON::Value jPack; JSON::Value jPack;
if (myMeta.tracks[thisPacket.getTrackId()].codec == "JSON"){ if (myMeta.tracks[thisPacket.getTrackId()].codec == "JSON"){
char * dPtr; char * dPtr;
unsigned int dLen; size_t dLen;
thisPacket.getString("data", dPtr, dLen); thisPacket.getString("data", dPtr, dLen);
jPack["data"] = JSON::fromString(dPtr, dLen); jPack["data"] = JSON::fromString(dPtr, dLen);
jPack["time"] = (long long)thisPacket.getTime(); jPack["time"] = (long long)thisPacket.getTime();

View file

@ -28,7 +28,7 @@ namespace Mist {
void OutProgressiveMP3::sendNext(){ void OutProgressiveMP3::sendNext(){
char * dataPointer = 0; char * dataPointer = 0;
unsigned int len = 0; size_t len = 0;
thisPacket.getString("data", dataPointer, len); thisPacket.getString("data", dataPointer, len);
myConn.SendNow(dataPointer, len); myConn.SendNow(dataPointer, len);
} }

View file

@ -66,7 +66,7 @@ namespace Mist{
+ 32 //MDHD Box + 32 //MDHD Box
+ 33 + thisTrack.getIdentifier().size() // HDLR Box + 33 + thisTrack.getIdentifier().size() // HDLR Box
+ 8 //MINF Box + 8 //MINF Box
+ 36 //DINF Box + 44 //DINF Box
+ 8; // STBL Box + 8; // STBL Box
if (myMeta.vod && thisTrack.firstms != firstms){ if (myMeta.vod && thisTrack.firstms != firstms){
tmpRes += 12;// EDTS entry extra tmpRes += 12;// EDTS entry extra
@ -82,6 +82,7 @@ namespace Mist{
tmpRes += 20//VMHD Box tmpRes += 20//VMHD Box
+ 16 //STSD + 16 //STSD
+ 86 //AVC1 + 86 //AVC1
+ 16 //PASP
+ 8 + thisTrack.init.size();//avcC + 8 + thisTrack.init.size();//avcC
if (!fragmented){ if (!fragmented){
tmpRes += 16 + (thisTrack.keys.size() * 4);//STSS tmpRes += 16 + (thisTrack.keys.size() * 4);//STSS
@ -917,7 +918,7 @@ namespace Mist{
//Obtain a pointer to the data of this packet //Obtain a pointer to the data of this packet
char * dataPointer = 0; char * dataPointer = 0;
unsigned int len = 0; size_t len = 0;
thisPacket.getString("data", dataPointer, len); thisPacket.getString("data", dataPointer, len);
std::string subtitle; std::string subtitle;

View file

@ -264,7 +264,7 @@ namespace Mist{
unsigned int dheader_len = 1; unsigned int dheader_len = 1;
static Util::ResizeablePointer swappy; static Util::ResizeablePointer swappy;
char * tmpData = 0;//pointer to raw media data char * tmpData = 0;//pointer to raw media data
unsigned int data_len = 0;//length of processed media data size_t data_len = 0;//length of processed media data
thisPacket.getString("data", tmpData, data_len); thisPacket.getString("data", tmpData, data_len);
DTSC::Track & track = myMeta.tracks[thisPacket.getTrackId()]; DTSC::Track & track = myMeta.tracks[thisPacket.getTrackId()];

View file

@ -32,7 +32,7 @@ namespace Mist{
/// \TODO Make this less inefficient. Seriously. Maybe use DTSC::RetimedPacket by extending with bmo functionality...? /// \TODO Make this less inefficient. Seriously. Maybe use DTSC::RetimedPacket by extending with bmo functionality...?
static DTSC::Packet newPkt; static DTSC::Packet newPkt;
char * pktData; char * pktData;
unsigned int pktDataLen; size_t pktDataLen;
pkt.getString("data", pktData, pktDataLen); pkt.getString("data", pktData, pktDataLen);
newPkt.genericFill(pkt.getTime() + packetOffset, pkt.getInt("offset"), pkt.getTrackId(), pktData, pktDataLen, 0, pkt.getFlag("keyframe"), bootMsOffset); newPkt.genericFill(pkt.getTime() + packetOffset, pkt.getInt("offset"), pkt.getTrackId(), pktData, pktDataLen, 0, pkt.getFlag("keyframe"), bootMsOffset);
bufferLivePacket(newPkt); bufferLivePacket(newPkt);
@ -122,7 +122,7 @@ namespace Mist{
void OutRTSP::sendNext(){ void OutRTSP::sendNext(){
char *dataPointer = 0; char *dataPointer = 0;
unsigned int dataLen = 0; size_t dataLen = 0;
thisPacket.getString("data", dataPointer, dataLen); thisPacket.getString("data", dataPointer, dataLen);
uint32_t tid = thisPacket.getTrackId(); uint32_t tid = thisPacket.getTrackId();
uint64_t timestamp = thisPacket.getTime(); uint64_t timestamp = thisPacket.getTime();

View file

@ -27,7 +27,7 @@ namespace Mist {
void OutProgressiveSRT::sendNext(){ void OutProgressiveSRT::sendNext(){
char * dataPointer = 0; char * dataPointer = 0;
unsigned int len = 0; size_t len = 0;
thisPacket.getString("data", dataPointer, len); thisPacket.getString("data", dataPointer, len);
// INFO_MSG("getting sub: %s", dataPointer); // INFO_MSG("getting sub: %s", dataPointer);
//ignore empty subs //ignore empty subs

View file

@ -67,7 +67,7 @@ namespace Mist {
firstPack = true; firstPack = true;
char * dataPointer = 0; char * dataPointer = 0;
unsigned int tmpDataLen = 0; size_t tmpDataLen = 0;
thisPacket.getString("data", dataPointer, tmpDataLen); //data thisPacket.getString("data", dataPointer, tmpDataLen); //data
uint64_t dataLen = tmpDataLen; uint64_t dataLen = tmpDataLen;
//apple compatibility timestamp correction //apple compatibility timestamp correction

View file

@ -33,7 +33,7 @@ namespace Mist{
void OutWAV::sendNext(){ void OutWAV::sendNext(){
char *dataPointer = 0; char *dataPointer = 0;
unsigned int len = 0; size_t len = 0;
thisPacket.getString("data", dataPointer, len); thisPacket.getString("data", dataPointer, len);
//PCM must be converted to little-endian if > 8 bits per sample //PCM must be converted to little-endian if > 8 bits per sample