This commit is contained in:
DDVTech 2021-09-10 23:44:31 +02:00 committed by Thulinma
parent 5b79f296d6
commit fccf66fba2
280 changed files with 56975 additions and 71885 deletions

View file

@ -6,133 +6,110 @@
#include "defines.h" #include "defines.h"
namespace aac { namespace aac{
adts::adts(){ adts::adts(){
data = NULL; data = NULL;
len = 0; len = 0;
} }
adts::adts(const char * _data, unsigned long _len){ adts::adts(const char *_data, unsigned long _len){
len = _len; len = _len;
data = (char*)malloc(len); data = (char *)malloc(len);
memcpy(data, _data, len); memcpy(data, _data, len);
} }
bool adts::sameHeader(const adts &rhs) const{
bool adts::sameHeader(const adts & rhs) const {
if (!rhs || !*this){return false;} if (!rhs || !*this){return false;}
return (getAACProfile() == rhs.getAACProfile() && getFrequencyIndex() == rhs.getFrequencyIndex() && getChannelConfig() == rhs.getChannelConfig()); return (getAACProfile() == rhs.getAACProfile() && getFrequencyIndex() == rhs.getFrequencyIndex() &&
getChannelConfig() == rhs.getChannelConfig());
} }
adts::adts(const adts & rhs){ adts::adts(const adts &rhs){
data = NULL; data = NULL;
len = 0; len = 0;
*this = rhs; *this = rhs;
} }
adts& adts::operator = (const adts & rhs){ adts &adts::operator=(const adts &rhs){
if (data){ if (data){free(data);}
free(data);
}
len = rhs.len; len = rhs.len;
data = (char*)malloc(len); data = (char *)malloc(len);
memcpy(data, rhs.data, len); memcpy(data, rhs.data, len);
return * this; return *this;
} }
adts::~adts(){ adts::~adts(){
if (data){ if (data){free(data);}
free(data);
}
} }
unsigned long adts::getAACProfile() const{ unsigned long adts::getAACProfile() const{
if (!data || !len){ if (!data || !len){return 0;}
return 0;
}
return ((data[2] >> 6) & 0x03) + 1; return ((data[2] >> 6) & 0x03) + 1;
} }
unsigned long adts::getFrequencyIndex() const{ unsigned long adts::getFrequencyIndex() const{
if (!data || !len){ if (!data || !len){return 0;}
return 0;
}
return ((data[2] >> 2) & 0x0F); return ((data[2] >> 2) & 0x0F);
} }
unsigned long adts::getFrequency() const{ unsigned long adts::getFrequency() const{
if (!data || len < 3){ if (!data || len < 3){return 0;}
return 0; switch (getFrequencyIndex()){
} case 0: return 96000; break;
switch(getFrequencyIndex()){ case 1: return 88200; break;
case 0: return 96000; break; case 2: return 64000; break;
case 1: return 88200; break; case 3: return 48000; break;
case 2: return 64000; break; case 4: return 44100; break;
case 3: return 48000; break; case 5: return 32000; break;
case 4: return 44100; break; case 6: return 24000; break;
case 5: return 32000; break; case 7: return 22050; break;
case 6: return 24000; break; case 8: return 16000; break;
case 7: return 22050; break; case 9: return 12000; break;
case 8: return 16000; break; case 10: return 11025; break;
case 9: return 12000; break; case 11: return 8000; break;
case 10: return 11025; break; case 12: return 7350; break;
case 11: return 8000; break; default: return 0; break;
case 12: return 7350; break;
default: return 0; break;
} }
} }
unsigned long adts::getChannelConfig() const{ unsigned long adts::getChannelConfig() const{
if (!data || !len){ if (!data || !len){return 0;}
return 0;
}
return ((data[2] & 0x01) << 2) | ((data[3] >> 6) & 0x03); return ((data[2] & 0x01) << 2) | ((data[3] >> 6) & 0x03);
} }
unsigned long adts::getChannelCount() const{ unsigned long adts::getChannelCount() const{
if (!data || !len){ if (!data || !len){return 0;}
return 0;
}
return (getChannelConfig() == 7 ? 8 : getChannelConfig()); return (getChannelConfig() == 7 ? 8 : getChannelConfig());
} }
unsigned long adts::getHeaderSize() const{ unsigned long adts::getHeaderSize() const{
if (!data || !len){ if (!data || !len){return 0;}
return 0;
}
return (data[1] & 0x01 ? 7 : 9); return (data[1] & 0x01 ? 7 : 9);
} }
unsigned long adts::getCompleteSize() const{ unsigned long adts::getCompleteSize() const{
if (!data || len < 6){ if (!data || len < 6){return 0;}
return 0;
}
return (((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] >> 5) & 0x07)); return (((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] >> 5) & 0x07));
} }
unsigned long adts::getPayloadSize() const{ unsigned long adts::getPayloadSize() const{
unsigned long ret = getCompleteSize(); unsigned long ret = getCompleteSize();
if (!ret){return ret;}//catch zero length if (!ret){return ret;}// catch zero length
if (ret >= getHeaderSize()){ if (ret >= getHeaderSize()){
ret -= getHeaderSize(); ret -= getHeaderSize();
}else{ }else{
return 0;//catch size less than header size (corrupt data) return 0; // catch size less than header size (corrupt data)
} }
return ret; return ret;
} }
unsigned long adts::getSampleCount() const{ unsigned long adts::getSampleCount() const{
if (!data || len < 7){ if (!data || len < 7){return 0;}
return 0; return ((data[6] & 0x03) + 1) * 1024; // Number of samples in this frame * 1024
}
return ((data[6] & 0x03) + 1) * 1024;//Number of samples in this frame * 1024
} }
char * adts::getPayload() { char *adts::getPayload(){
if (!data || !len){ if (!data || !len){return 0;}
return 0;
}
return data + getHeaderSize(); return data + getHeaderSize();
} }
std::string adts::toPrettyString() const{ std::string adts::toPrettyString() const{
@ -147,12 +124,8 @@ namespace aac {
}else{ }else{
res << " MPEG-4" << std::endl; res << " MPEG-4" << std::endl;
} }
if ((data[1] & 0x6) != 0){ if ((data[1] & 0x6) != 0){res << " Non-zero layer!" << std::endl;}
res << " Non-zero layer!" << std::endl; if ((data[1] & 0x1) == 0x0){res << " CRC present" << std::endl;}
}
if ((data[1] & 0x1) == 0x0){
res << " CRC present" << std::endl;
}
res << " MPEG-4 audio object type: " << getAACProfile() << std::endl; res << " MPEG-4 audio object type: " << getAACProfile() << std::endl;
res << " Frequency: " << getFrequency() << "Hz" << std::endl; res << " Frequency: " << getFrequency() << "Hz" << std::endl;
res << " Channels: " << getChannelCount() << std::endl; res << " Channels: " << getChannelCount() << std::endl;
@ -161,9 +134,10 @@ namespace aac {
return res.str(); return res.str();
} }
adts::operator bool() const{ adts::operator bool() const{
return hasSync() && len && len >= getHeaderSize() && getFrequency() && getChannelCount() && getSampleCount(); return hasSync() && len && len >= getHeaderSize() && getFrequency() && getChannelCount() &&
getSampleCount();
} }
bool adts::hasSync() const{ bool adts::hasSync() const{
return len && (((int)data[0] << 4) | ((data[1] >> 4) & 0x0F)) == 0xfff; return len && (((int)data[0] << 4) | ((data[1] >> 4) & 0x0F)) == 0xfff;
} }
} }// namespace aac

View file

@ -1,96 +1,95 @@
#include "bitstream.h"
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include "bitstream.h"
namespace aac { namespace aac{
class adts { class adts{
public: public:
adts(); adts();
adts(const char * _data, unsigned long _len); adts(const char *_data, unsigned long _len);
adts(const adts & rhs); adts(const adts &rhs);
~adts(); ~adts();
adts& operator = (const adts & rhs); adts &operator=(const adts &rhs);
bool sameHeader(const adts & rhs) const; bool sameHeader(const adts &rhs) const;
unsigned long getAACProfile() const; unsigned long getAACProfile() const;
unsigned long getFrequencyIndex() const; unsigned long getFrequencyIndex() const;
unsigned long getFrequency() const; unsigned long getFrequency() const;
unsigned long getChannelConfig() const; unsigned long getChannelConfig() const;
unsigned long getChannelCount() const; unsigned long getChannelCount() const;
unsigned long getHeaderSize() const; unsigned long getHeaderSize() const;
unsigned long getPayloadSize() const; unsigned long getPayloadSize() const;
unsigned long getCompleteSize() const; unsigned long getCompleteSize() const;
unsigned long getSampleCount() const; unsigned long getSampleCount() const;
bool hasSync() const; bool hasSync() const;
char * getPayload(); char *getPayload();
std::string toPrettyString() const; std::string toPrettyString() const;
operator bool() const; operator bool() const;
private:
char * data; private:
unsigned long len; char *data;
unsigned long len;
}; };
class AudSpecConf{ class AudSpecConf{
public: public:
static inline uint32_t rate(const std::string & conf){ static inline uint32_t rate(const std::string &conf){
Utils::bitstream bs; Utils::bitstream bs;
bs.append(conf.data(), conf.size()); bs.append(conf.data(), conf.size());
if (bs.get(5) == 31){bs.skip(6);}//skip object type if (bs.get(5) == 31){bs.skip(6);}// skip object type
switch (bs.get(4)){//frequency index switch (bs.get(4)){// frequency index
case 0: return 96000; case 0: return 96000;
case 1: return 88200; case 1: return 88200;
case 2: return 64000; case 2: return 64000;
case 3: return 48000; case 3: return 48000;
case 4: return 44100; case 4: return 44100;
case 5: return 32000; case 5: return 32000;
case 6: return 24000; case 6: return 24000;
case 7: return 22050; case 7: return 22050;
case 8: return 16000; case 8: return 16000;
case 9: return 12000; case 9: return 12000;
case 10: return 11025; case 10: return 11025;
case 11: return 8000; case 11: return 8000;
case 12: return 7350; case 12: return 7350;
case 15: return bs.get(24); case 15: return bs.get(24);
default: return 0; default: return 0;
}
} }
static inline uint16_t channels(const std::string &conf){ }
Utils::bitstream bs; static inline uint16_t channels(const std::string &conf){
bs.append(conf.data(), conf.size()); Utils::bitstream bs;
if (bs.get(5) == 31){bs.skip(6);}// skip object type bs.append(conf.data(), conf.size());
if (bs.get(4) == 15){bs.skip(24);}// frequency index if (bs.get(5) == 31){bs.skip(6);}// skip object type
uint8_t chanConfig = bs.get(4); if (bs.get(4) == 15){bs.skip(24);}// frequency index
if (chanConfig == 0){ uint8_t chanConfig = bs.get(4);
WARN_MSG("Unimplemented AAC AOT Specific Config parsing"); if (chanConfig == 0){
return 8; WARN_MSG("Unimplemented AAC AOT Specific Config parsing");
} return 8;
if (chanConfig > 7){
WARN_MSG("Unimplemented AAC channel configuration %" PRIu8, chanConfig);
return 8;
}
if (chanConfig == 7){return 8;}
return chanConfig;
} }
static inline uint8_t objtype(const std::string &conf){ if (chanConfig > 7){
Utils::bitstream bs; WARN_MSG("Unimplemented AAC channel configuration %" PRIu8, chanConfig);
bs.append(conf.data(), conf.size()); return 8;
uint8_t ot = bs.get(5);
if (ot == 31){return bs.get(6) + 32;}
return ot;
} }
static inline uint16_t samples(const std::string &conf){ if (chanConfig == 7){return 8;}
Utils::bitstream bs; return chanConfig;
bs.append(conf.data(), conf.size()); }
if (bs.get(5) == 31){bs.skip(6);}// skip object type static inline uint8_t objtype(const std::string &conf){
if (bs.get(4) == 15){bs.skip(24);}// frequency index Utils::bitstream bs;
bs.skip(4); // channel configuration bs.append(conf.data(), conf.size());
if (bs.get(1)){ uint8_t ot = bs.get(5);
return 960; if (ot == 31){return bs.get(6) + 32;}
}else{ return ot;
return 1024; }
} static inline uint16_t samples(const std::string &conf){
Utils::bitstream bs;
bs.append(conf.data(), conf.size());
if (bs.get(5) == 31){bs.skip(6);}// skip object type
if (bs.get(4) == 15){bs.skip(24);}// frequency index
bs.skip(4); // channel configuration
if (bs.get(1)){
return 960;
}else{
return 1024;
} }
}
}; };
}// namespace aac
}

View file

@ -328,8 +328,7 @@ std::string AMF::Object::Pack(){
/// \param i Current parsing position in the raw data. /// \param i Current parsing position in the raw data.
/// \param name Indice name for any new object created. /// \param name Indice name for any new object created.
/// \returns A single AMF::Object, parsed from the raw data. /// \returns A single AMF::Object, parsed from the raw data.
AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigned int &i, AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigned int &i, std::string name){
std::string name){
std::string tmpstr; std::string tmpstr;
unsigned int tmpi = 0; unsigned int tmpi = 0;
unsigned char tmpdbl[8]; unsigned char tmpdbl[8];
@ -375,16 +374,14 @@ AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigne
return AMF::Object(name, (double)tmpi, AMF::AMF0_REFERENCE); return AMF::Object(name, (double)tmpi, AMF::AMF0_REFERENCE);
break; break;
case AMF::AMF0_XMLDOC: case AMF::AMF0_XMLDOC:
tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; // set tmpi to UTF-8-long length
data[i + 4]; // set tmpi to UTF-8-long length
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i + 5, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i + 5, (size_t)tmpi); // add the string data
i += tmpi + 5; // skip length+size+1 forwards i += tmpi + 5; // skip length+size+1 forwards
return AMF::Object(name, tmpstr, AMF::AMF0_XMLDOC); return AMF::Object(name, tmpstr, AMF::AMF0_XMLDOC);
break; break;
case AMF::AMF0_LONGSTRING: case AMF::AMF0_LONGSTRING:
tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; // set tmpi to UTF-8-long length
data[i + 4]; // set tmpi to UTF-8-long length
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i + 5, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i + 5, (size_t)tmpi); // add the string data
i += tmpi + 5; // skip length+size+1 forwards i += tmpi + 5; // skip length+size+1 forwards
@ -411,9 +408,8 @@ AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigne
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i + 2, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i + 2, (size_t)tmpi); // add the string data
i += tmpi + 2; // skip length+size forwards i += tmpi + 2; // skip length+size forwards
ret.addContent(AMF::parseOne( ret.addContent(AMF::parseOne(data, len, i,
data, len, i, tmpstr)); // add content, recursively parsed, updating i, setting indice to tmpstr
tmpstr)); // add content, recursively parsed, updating i, setting indice to tmpstr
} }
i += 3; // skip 0x000009 i += 3; // skip 0x000009
return ret; return ret;
@ -429,9 +425,8 @@ AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigne
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i + 2, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i + 2, (size_t)tmpi); // add the string data
i += tmpi + 2; // skip length+size forwards i += tmpi + 2; // skip length+size forwards
ret.addContent(AMF::parseOne( ret.addContent(AMF::parseOne(data, len, i,
data, len, i, tmpstr)); // add content, recursively parsed, updating i, setting indice to tmpstr
tmpstr)); // add content, recursively parsed, updating i, setting indice to tmpstr
} }
i += 3; // skip 0x000009 i += 3; // skip 0x000009
return ret; return ret;
@ -445,21 +440,18 @@ AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigne
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i + 2, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i + 2, (size_t)tmpi); // add the string data
i += tmpi + 2; // skip length+size forwards i += tmpi + 2; // skip length+size forwards
ret.addContent(AMF::parseOne( ret.addContent(AMF::parseOne(data, len, i,
data, len, i, tmpstr)); // add content, recursively parsed, updating i, setting indice to tmpstr
tmpstr)); // add content, recursively parsed, updating i, setting indice to tmpstr
} }
i += 3; // skip 0x000009 i += 3; // skip 0x000009
return ret; return ret;
}break; }break;
case AMF::AMF0_STRICT_ARRAY:{ case AMF::AMF0_STRICT_ARRAY:{
AMF::Object ret(name, AMF::AMF0_STRICT_ARRAY); AMF::Object ret(name, AMF::AMF0_STRICT_ARRAY);
tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; // set tmpi to array length
data[i + 4]; // set tmpi to array length i += 5; // skip size+1 forwards
i += 5; // skip size+1 forwards
while (tmpi > 0){// while not done parsing array while (tmpi > 0){// while not done parsing array
ret.addContent( ret.addContent(AMF::parseOne(data, len, i, "arrVal")); // add content, recursively parsed, updating i
AMF::parseOne(data, len, i, "arrVal")); // add content, recursively parsed, updating i
--tmpi; --tmpi;
} }
return ret; return ret;
@ -712,8 +704,7 @@ std::string AMF::Object3::Pack(){
/// \param i Current parsing position in the raw data. /// \param i Current parsing position in the raw data.
/// \param name Indice name for any new object created. /// \param name Indice name for any new object created.
/// \returns A single AMF::Object3, parsed from the raw data. /// \returns A single AMF::Object3, parsed from the raw data.
AMF::Object3 AMF::parseOne3(const unsigned char *&data, unsigned int &len, unsigned int &i, AMF::Object3 AMF::parseOne3(const unsigned char *&data, unsigned int &len, unsigned int &i, std::string name){
std::string name){
std::string tmpstr; std::string tmpstr;
unsigned int tmpi = 0; unsigned int tmpi = 0;
unsigned int arrsize = 0; unsigned int arrsize = 0;
@ -974,13 +965,11 @@ AMF::Object3 AMF::parseOne3(const unsigned char *&data, unsigned int &len, unsig
if (tmpi > 0){ if (tmpi > 0){
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i, (size_t)tmpi); // add the string data
ret.addContent( ret.addContent(AMF::parseOne3(data, len, i, tmpstr)); // add content, recursively parsed, updating i
AMF::parseOne3(data, len, i, tmpstr)); // add content, recursively parsed, updating i
} }
}while (tmpi > 0); }while (tmpi > 0);
while (arrsize > 0){// while not done parsing array while (arrsize > 0){// while not done parsing array
ret.addContent( ret.addContent(AMF::parseOne3(data, len, i, "arrVal")); // add content, recursively parsed, updating i
AMF::parseOne3(data, len, i, "arrVal")); // add content, recursively parsed, updating i
--arrsize; --arrsize;
} }
return ret; return ret;
@ -1046,8 +1035,7 @@ AMF::Object3 AMF::parseOne3(const unsigned char *&data, unsigned int &len, unsig
if (tmpi > 0){ if (tmpi > 0){
tmpstr.clear(); // clean tmpstr, just to be sure tmpstr.clear(); // clean tmpstr, just to be sure
tmpstr.append((const char *)data + i, (size_t)tmpi); // add the string data tmpstr.append((const char *)data + i, (size_t)tmpi); // add the string data
ret.addContent( ret.addContent(AMF::parseOne3(data, len, i, tmpstr)); // add content, recursively parsed, updating i
AMF::parseOne3(data, len, i, tmpstr)); // add content, recursively parsed, updating i
} }
}while (tmpi > 0); // keep reading dynamic values until empty string }while (tmpi > 0); // keep reading dynamic values until empty string
}// dynamic types }// dynamic types
@ -1081,4 +1069,3 @@ AMF::Object3 AMF::parse3(const unsigned char *data, unsigned int len){
AMF::Object3 AMF::parse3(std::string data){ AMF::Object3 AMF::parse3(std::string data){
return AMF::parse3((const unsigned char *)data.c_str(), data.size()); return AMF::parse3((const unsigned char *)data.c_str(), data.size());
}// parse }// parse

View file

@ -130,8 +130,6 @@ namespace AMF{
/// 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, Object3 parseOne3(const unsigned char *&data, unsigned int &len, unsigned int &i, std::string name);
std::string name);
}// namespace AMF }// namespace AMF

View file

@ -1,19 +1,17 @@
#include "auth.h" #include "auth.h"
#include <string.h>
#include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <sstream>
#include <iomanip> #include <iomanip>
#include <sstream>
#include <stdio.h>
#include <string.h>
namespace Secure { namespace Secure{
/// Calculates a MD5 digest as per rfc1321, returning it as a hexadecimal alphanumeric string. /// Calculates a MD5 digest as per rfc1321, returning it as a hexadecimal alphanumeric string.
std::string md5(std::string input) { std::string md5(std::string input){return md5(input.data(), input.size());}
return md5(input.data(), input.size());
}
/// Calculates a MD5 digest as per rfc1321, returning it as a hexadecimal alphanumeric string. /// Calculates a MD5 digest as per rfc1321, returning it as a hexadecimal alphanumeric string.
std::string md5(const char * input, const unsigned int in_len){ std::string md5(const char *input, const unsigned int in_len){
char output[16]; char output[16];
md5bin(input, in_len, output); md5bin(input, in_len, output);
std::stringstream outStr; std::stringstream outStr;
@ -24,12 +22,10 @@ namespace Secure {
} }
/// Calculates a SHA256 digest as per NSAs SHA-2, returning it as a hexadecimal alphanumeric string. /// Calculates a SHA256 digest as per NSAs SHA-2, returning it as a hexadecimal alphanumeric string.
std::string sha256(std::string input) { std::string sha256(std::string input){return sha256(input.data(), input.size());}
return sha256(input.data(), input.size());
}
/// Calculates a SHA256 digest as per NSAs SHA-2, returning it as a hexadecimal alphanumeric string. /// Calculates a SHA256 digest as per NSAs SHA-2, returning it as a hexadecimal alphanumeric string.
std::string sha256(const char * input, const unsigned int in_len){ std::string sha256(const char *input, const unsigned int in_len){
char output[32]; char output[32];
sha256bin(input, in_len, output); sha256bin(input, in_len, output);
std::stringstream outStr; std::stringstream outStr;
@ -42,14 +38,28 @@ namespace Secure {
/// Adds 64 bytes of data to the current MD5 hash. /// Adds 64 bytes of data to the current MD5 hash.
/// hash is the current hash, represented by 4 unsigned longs. /// hash is the current hash, represented by 4 unsigned longs.
/// data is the 64 bytes of data that need to be added. /// data is the 64 bytes of data that need to be added.
static inline void md5_add64(uint32_t * hash, const char * data){ static inline void md5_add64(uint32_t *hash, const char *data){
//Inspired by the pseudocode as available on Wikipedia on March 2nd, 2015. // Inspired by the pseudocode as available on Wikipedia on March 2nd, 2015.
uint32_t M[16]; uint32_t M[16];
for (unsigned int i = 0; i < 16; ++i){ for (unsigned int i = 0; i < 16; ++i){
M[i] = data[i << 2] | (data[(i<<2)+1] << 8) | (data[(i<<2)+2] << 16) | (data[(i<<2)+3] << 24); M[i] = data[i << 2] | (data[(i << 2) + 1] << 8) | (data[(i << 2) + 2] << 16) |
(data[(i << 2) + 3] << 24);
} }
static unsigned char shift[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; static unsigned char shift[] ={7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
static uint32_t K[] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
static uint32_t K[] ={0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
uint32_t A = hash[0]; uint32_t A = hash[0];
uint32_t B = hash[1]; uint32_t B = hash[1];
uint32_t C = hash[2]; uint32_t C = hash[2];
@ -61,19 +71,19 @@ namespace Secure {
g = i; g = i;
}else if (i < 32){ }else if (i < 32){
F = (D & B) | ((~D) & C); F = (D & B) | ((~D) & C);
g = (5*i + 1) % 16; g = (5 * i + 1) % 16;
}else if (i < 48){ }else if (i < 48){
F = B ^ C ^ D; F = B ^ C ^ D;
g = (3*i + 5) % 16; g = (3 * i + 5) % 16;
}else{ }else{
F = C ^ (B | (~D)); F = C ^ (B | (~D));
g = (7*i) % 16; g = (7 * i) % 16;
} }
uint32_t dTemp = D; uint32_t dTemp = D;
D = C; D = C;
C = B; C = B;
uint32_t x = A + F + K[i] + M[g]; uint32_t x = A + F + K[i] + M[g];
B += (x << shift[i] | (x >> (32-shift[i]))); B += (x << shift[i] | (x >> (32 - shift[i])));
A = dTemp; A = dTemp;
} }
hash[0] += A; hash[0] += A;
@ -84,31 +94,31 @@ namespace Secure {
/// Calculates a MD5 digest as per rfc1321, returning it as binary. /// Calculates a MD5 digest as per rfc1321, returning it as binary.
/// Assumes output is big enough to contain 16 bytes of data. /// Assumes output is big enough to contain 16 bytes of data.
void md5bin(const char * input, const unsigned int in_len, char * output){ void md5bin(const char *input, const unsigned int in_len, char *output){
//Initialize the hash, according to MD5 spec. // Initialize the hash, according to MD5 spec.
uint32_t hash[] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476}; uint32_t hash[] ={0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
//Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left. // Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left.
unsigned int offset = 0; unsigned int offset = 0;
while (offset+64 <= in_len){ while (offset + 64 <= in_len){
md5_add64(hash, input+offset); md5_add64(hash, input + offset);
offset += 64; offset += 64;
} }
//now, copy the remainder to a 64 byte buffer. // now, copy the remainder to a 64 byte buffer.
char buffer[64]; char buffer[64];
memcpy(buffer, input+offset, in_len-offset); memcpy(buffer, input + offset, in_len - offset);
//Calculate how much we've filled in that buffer // Calculate how much we've filled in that buffer
offset = in_len - offset; offset = in_len - offset;
//We know at least 1 byte must be empty, so we can safely do this // We know at least 1 byte must be empty, so we can safely do this
buffer[offset] = 0x80;//append 0x80 buffer[offset] = 0x80; // append 0x80
//fill to the end of the buffer with zeroes // fill to the end of the buffer with zeroes
memset(buffer+offset+1, 0, 64-offset-1); memset(buffer + offset + 1, 0, 64 - offset - 1);
if (offset > 55){ if (offset > 55){
//There's no space for the length, add what we have and zero it // There's no space for the length, add what we have and zero it
md5_add64(hash, buffer); md5_add64(hash, buffer);
memset(buffer, 0, 64); memset(buffer, 0, 64);
} }
unsigned long long bit_len = in_len << 3; unsigned long long bit_len = in_len << 3;
//Write the length into the last 8 bytes // Write the length into the last 8 bytes
buffer[56] = (bit_len >> 0) & 0xff; buffer[56] = (bit_len >> 0) & 0xff;
buffer[57] = (bit_len >> 8) & 0xff; buffer[57] = (bit_len >> 8) & 0xff;
buffer[58] = (bit_len >> 16) & 0xff; buffer[58] = (bit_len >> 16) & 0xff;
@ -117,24 +127,24 @@ namespace Secure {
buffer[61] = (bit_len >> 40) & 0xff; buffer[61] = (bit_len >> 40) & 0xff;
buffer[62] = (bit_len >> 48) & 0xff; buffer[62] = (bit_len >> 48) & 0xff;
buffer[63] = (bit_len >> 54) & 0xff; buffer[63] = (bit_len >> 54) & 0xff;
//Add the last bit of buffer // Add the last bit of buffer
md5_add64(hash, buffer); md5_add64(hash, buffer);
//Write to output // Write to output
//convert hash to hexadecimal string // convert hash to hexadecimal string
output[0 ] = (hash[0] >> 0 ) & 0xff; output[0] = (hash[0] >> 0) & 0xff;
output[1 ] = (hash[0] >> 8 ) & 0xff; output[1] = (hash[0] >> 8) & 0xff;
output[2 ] = (hash[0] >> 16) & 0xff; output[2] = (hash[0] >> 16) & 0xff;
output[3 ] = (hash[0] >> 24) & 0xff; output[3] = (hash[0] >> 24) & 0xff;
output[4 ] = (hash[1] >> 0 ) & 0xff; output[4] = (hash[1] >> 0) & 0xff;
output[5 ] = (hash[1] >> 8 ) & 0xff; output[5] = (hash[1] >> 8) & 0xff;
output[6 ] = (hash[1] >> 16) & 0xff; output[6] = (hash[1] >> 16) & 0xff;
output[7 ] = (hash[1] >> 24) & 0xff; output[7] = (hash[1] >> 24) & 0xff;
output[8 ] = (hash[2] >> 0 ) & 0xff; output[8] = (hash[2] >> 0) & 0xff;
output[9 ] = (hash[2] >> 8 ) & 0xff; output[9] = (hash[2] >> 8) & 0xff;
output[10] = (hash[2] >> 16) & 0xff; output[10] = (hash[2] >> 16) & 0xff;
output[11] = (hash[2] >> 24) & 0xff; output[11] = (hash[2] >> 24) & 0xff;
output[12] = (hash[3] >> 0 ) & 0xff; output[12] = (hash[3] >> 0) & 0xff;
output[13] = (hash[3] >> 8 ) & 0xff; output[13] = (hash[3] >> 8) & 0xff;
output[14] = (hash[3] >> 16) & 0xff; output[14] = (hash[3] >> 16) & 0xff;
output[15] = (hash[3] >> 24) & 0xff; output[15] = (hash[3] >> 24) & 0xff;
} }
@ -147,20 +157,31 @@ namespace Secure {
/// Adds 64 bytes of data to the current SHA256 hash. /// Adds 64 bytes of data to the current SHA256 hash.
/// hash is the current hash, represented by 8 unsigned longs. /// hash is the current hash, represented by 8 unsigned longs.
/// data is the 64 bytes of data that need to be added. /// data is the 64 bytes of data that need to be added.
static inline void sha256_add64(uint32_t * hash, const char * data){ static inline void sha256_add64(uint32_t *hash, const char *data){
//Inspired by the pseudocode as available on Wikipedia on March 3rd, 2015. // Inspired by the pseudocode as available on Wikipedia on March 3rd, 2015.
uint32_t w[64]; uint32_t w[64];
for (unsigned int i = 0; i < 16; ++i){ for (unsigned int i = 0; i < 16; ++i){
w[i] = (uint32_t)data[(i<<2)+3] | ((uint32_t)data[(i<<2)+2] << 8) | ((uint32_t)data[(i<<2)+1] << 16) | ((uint32_t)data[(i<<2)+0] << 24); w[i] = (uint32_t)data[(i << 2) + 3] | ((uint32_t)data[(i << 2) + 2] << 8) |
((uint32_t)data[(i << 2) + 1] << 16) | ((uint32_t)data[(i << 2) + 0] << 24);
} }
for (unsigned int i = 16; i < 64; ++i){ for (unsigned int i = 16; i < 64; ++i){
uint32_t s0 = rr(w[i-15], 7) ^ rr(w[i-15], 18) ^ ((w[i-15] & 0xFFFFFFFF ) >> 3); uint32_t s0 = rr(w[i - 15], 7) ^ rr(w[i - 15], 18) ^ ((w[i - 15] & 0xFFFFFFFF) >> 3);
uint32_t s1 = rr(w[i-2], 17) ^ rr(w[i-2], 19) ^ ((w[i-2] & 0xFFFFFFFF) >> 10); uint32_t s1 = rr(w[i - 2], 17) ^ rr(w[i - 2], 19) ^ ((w[i - 2] & 0xFFFFFFFF) >> 10);
w[i] = w[i-16] + s0 + w[i-7] + s1; w[i] = w[i - 16] + s0 + w[i - 7] + s1;
} }
static uint32_t k[] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; static uint32_t k[] ={0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
uint32_t a = hash[0]; uint32_t a = hash[0];
uint32_t b = hash[1]; uint32_t b = hash[1];
uint32_t c = hash[2]; uint32_t c = hash[2];
@ -170,8 +191,8 @@ namespace Secure {
uint32_t g = hash[6]; uint32_t g = hash[6];
uint32_t h = hash[7]; uint32_t h = hash[7];
for (unsigned int i = 0; i < 64; ++i){ for (unsigned int i = 0; i < 64; ++i){
uint32_t temp1 = h + (rr(e, 6) ^ rr(e, 11) ^ rr(e, 25)) + (g^(e&(f^g))) + k[i] + w[i]; uint32_t temp1 = h + (rr(e, 6) ^ rr(e, 11) ^ rr(e, 25)) + (g ^ (e & (f ^ g))) + k[i] + w[i];
uint32_t temp2 = (rr(a, 2) ^ rr(a, 13) ^ rr(a, 22)) + ((a&b)|(c&(a|b))); uint32_t temp2 = (rr(a, 2) ^ rr(a, 13) ^ rr(a, 22)) + ((a & b) | (c & (a | b)));
h = g; h = g;
g = f; g = f;
f = e; f = e;
@ -193,31 +214,32 @@ namespace Secure {
/// Calculates a SHA256 digest as per NSAs SHA-2, returning it as binary. /// Calculates a SHA256 digest as per NSAs SHA-2, returning it as binary.
/// Assumes output is big enough to contain 16 bytes of data. /// Assumes output is big enough to contain 16 bytes of data.
void sha256bin(const char * input, const unsigned int in_len, char * output){ void sha256bin(const char *input, const unsigned int in_len, char *output){
//Initialize the hash, according to MD5 spec. // Initialize the hash, according to MD5 spec.
uint32_t hash[] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; uint32_t hash[] ={0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
//Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left. 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
// Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left.
unsigned int offset = 0; unsigned int offset = 0;
while (offset+64 <= in_len){ while (offset + 64 <= in_len){
sha256_add64(hash, input+offset); sha256_add64(hash, input + offset);
offset += 64; offset += 64;
} }
//now, copy the remainder to a 64 byte buffer. // now, copy the remainder to a 64 byte buffer.
char buffer[64]; char buffer[64];
memcpy(buffer, input+offset, in_len-offset); memcpy(buffer, input + offset, in_len - offset);
//Calculate how much we've filled in that buffer // Calculate how much we've filled in that buffer
offset = in_len - offset; offset = in_len - offset;
//We know at least 1 byte must be empty, so we can safely do this // We know at least 1 byte must be empty, so we can safely do this
buffer[offset] = 0x80;//append 0x80 buffer[offset] = 0x80; // append 0x80
//fill to the end of the buffer with zeroes // fill to the end of the buffer with zeroes
memset(buffer+offset+1, 0, 64-offset-1); memset(buffer + offset + 1, 0, 64 - offset - 1);
if (offset > 55){ if (offset > 55){
//There's no space for the length, add what we have and zero it // There's no space for the length, add what we have and zero it
sha256_add64(hash, buffer); sha256_add64(hash, buffer);
memset(buffer, 0, 64); memset(buffer, 0, 64);
} }
unsigned long long bit_len = in_len << 3; unsigned long long bit_len = in_len << 3;
//Write the length into the last 8 bytes // Write the length into the last 8 bytes
buffer[56] = (bit_len >> 54) & 0xff; buffer[56] = (bit_len >> 54) & 0xff;
buffer[57] = (bit_len >> 48) & 0xff; buffer[57] = (bit_len >> 48) & 0xff;
buffer[58] = (bit_len >> 40) & 0xff; buffer[58] = (bit_len >> 40) & 0xff;
@ -226,9 +248,9 @@ namespace Secure {
buffer[61] = (bit_len >> 16) & 0xff; buffer[61] = (bit_len >> 16) & 0xff;
buffer[62] = (bit_len >> 8) & 0xff; buffer[62] = (bit_len >> 8) & 0xff;
buffer[63] = (bit_len >> 0) & 0xff; buffer[63] = (bit_len >> 0) & 0xff;
//Add the last bit of buffer // Add the last bit of buffer
sha256_add64(hash, buffer); sha256_add64(hash, buffer);
//Write result to output // Write result to output
output[3] = hash[0] & 0xff; output[3] = hash[0] & 0xff;
output[2] = (hash[0] >> 8) & 0xff; output[2] = (hash[0] >> 8) & 0xff;
output[1] = (hash[0] >> 16) & 0xff; output[1] = (hash[0] >> 16) & 0xff;
@ -263,13 +285,12 @@ namespace Secure {
output[28] = (hash[7] >> 24) & 0xff; output[28] = (hash[7] >> 24) & 0xff;
} }
/// Performs HMAC on msg with given key. /// Performs HMAC on msg with given key.
/// Uses given hasher function, requires hashSize to be set accordingly. /// Uses given hasher function, requires hashSize to be set accordingly.
/// Output is returned as hexadecimal alphanumeric string. /// Output is returned as hexadecimal alphanumeric string.
/// The hasher function must be the "bin" version of the hasher to have a compatible function signature. /// The hasher function must be the "bin" version of the hasher to have a compatible function signature.
std::string hmac(std::string msg, std::string key, unsigned int hashSize, void hasher(const char *, const unsigned int, char*), unsigned int blockSize){ std::string hmac(std::string msg, std::string key, unsigned int hashSize,
void hasher(const char *, const unsigned int, char *), unsigned int blockSize){
return hmac(msg.data(), msg.size(), key.data(), key.size(), hashSize, hasher, blockSize); return hmac(msg.data(), msg.size(), key.data(), key.size(), hashSize, hasher, blockSize);
} }
@ -277,7 +298,9 @@ namespace Secure {
/// Uses given hasher function, requires hashSize to be set accordingly. /// Uses given hasher function, requires hashSize to be set accordingly.
/// Output is returned as hexadecimal alphanumeric string. /// Output is returned as hexadecimal alphanumeric string.
/// The hasher function must be the "bin" version of the hasher to have a compatible function signature. /// The hasher function must be the "bin" version of the hasher to have a compatible function signature.
std::string hmac(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len, unsigned int hashSize, void hasher(const char *, const unsigned int, char*), unsigned int blockSize){ std::string hmac(const char *msg, const unsigned int msg_len, const char *key,
const unsigned int key_len, unsigned int hashSize,
void hasher(const char *, const unsigned int, char *), unsigned int blockSize){
char output[hashSize]; char output[hashSize];
hmacbin(msg, msg_len, key, key_len, hashSize, hasher, blockSize, output); hmacbin(msg, msg_len, key, key_len, hashSize, hasher, blockSize, output);
std::stringstream outStr; std::stringstream outStr;
@ -291,30 +314,32 @@ namespace Secure {
/// Uses given hasher function, requires hashSize to be set accordingly. /// Uses given hasher function, requires hashSize to be set accordingly.
/// Output is written in binary form to output, and assumes hashSize bytes are available to be written to. /// Output is written in binary form to output, and assumes hashSize bytes are available to be written to.
/// The hasher function must be the "bin" version of the hasher to have a compatible function signature. /// The hasher function must be the "bin" version of the hasher to have a compatible function signature.
void hmacbin(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len, unsigned int hashSize, void hasher(const char*, const unsigned int, char*), unsigned int blockSize, char * output){ void hmacbin(const char *msg, const unsigned int msg_len, const char *key, const unsigned int key_len,
char key_data[blockSize];//holds key as used in HMAC algorithm unsigned int hashSize, void hasher(const char *, const unsigned int, char *),
unsigned int blockSize, char *output){
char key_data[blockSize]; // holds key as used in HMAC algorithm
if (key_len > blockSize){ if (key_len > blockSize){
//If the key given is too big, hash it. // If the key given is too big, hash it.
hasher(key, key_len, key_data); hasher(key, key_len, key_data);
memset(key_data+hashSize, 0, blockSize-hashSize); memset(key_data + hashSize, 0, blockSize - hashSize);
}else{ }else{
//Otherwise, use as-is, zero-padded if too small. // Otherwise, use as-is, zero-padded if too small.
memcpy(key_data, key, key_len); memcpy(key_data, key, key_len);
memset(key_data+key_len, 0, blockSize-key_len); memset(key_data + key_len, 0, blockSize - key_len);
} }
//key_data now contains hashSize bytes of key data, treated as per spec. // key_data now contains hashSize bytes of key data, treated as per spec.
char inner[blockSize+msg_len];//holds data for inner hash char inner[blockSize + msg_len]; // holds data for inner hash
char outer[blockSize+hashSize];//holds data for outer hash char outer[blockSize + hashSize]; // holds data for outer hash
for (unsigned int i = 0; i < blockSize; ++i){ for (unsigned int i = 0; i < blockSize; ++i){
inner[i] = key_data[i] ^ 0x36; inner[i] = key_data[i] ^ 0x36;
outer[i] = key_data[i] ^ 0x5c; outer[i] = key_data[i] ^ 0x5c;
} }
//Copy the message to the inner hash data buffer // Copy the message to the inner hash data buffer
memcpy(inner+blockSize, msg, msg_len); memcpy(inner + blockSize, msg, msg_len);
//Calculate the inner hash // Calculate the inner hash
hasher(inner, blockSize+msg_len, outer+blockSize); hasher(inner, blockSize + msg_len, outer + blockSize);
//Calculate the outer hash // Calculate the outer hash
hasher(outer, blockSize+hashSize, output); hasher(outer, blockSize + hashSize, output);
} }
/// Convenience function that returns the hexadecimal alphanumeric HMAC-SHA256 of msg and key /// Convenience function that returns the hexadecimal alphanumeric HMAC-SHA256 of msg and key
@ -323,15 +348,15 @@ namespace Secure {
} }
/// Convenience function that returns the hexadecimal alphanumeric HMAC-SHA256 of msg and key /// Convenience function that returns the hexadecimal alphanumeric HMAC-SHA256 of msg and key
std::string hmac_sha256(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len){ std::string hmac_sha256(const char *msg, const unsigned int msg_len, const char *key, const unsigned int key_len){
return hmac(msg, msg_len, key, key_len, 32, sha256bin, 64); return hmac(msg, msg_len, key, key_len, 32, sha256bin, 64);
} }
/// Convenience function that sets output to the HMAC-SHA256 of msg and key in binary format. /// Convenience function that sets output to the HMAC-SHA256 of msg and key in binary format.
/// Assumes at least 32 bytes are available for writing in output. /// Assumes at least 32 bytes are available for writing in output.
void hmac_sha256bin(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len, char * output){ void hmac_sha256bin(const char *msg, const unsigned int msg_len, const char *key,
const unsigned int key_len, char *output){
return hmacbin(msg, msg_len, key, key_len, 32, sha256bin, 64, output); return hmacbin(msg, msg_len, key, key_len, 32, sha256bin, 64, output);
} }
} }// namespace Secure

View file

@ -1,25 +1,30 @@
#pragma once #pragma once
#include <string> #include <string>
namespace Secure { namespace Secure{
//MD5 hashing functions // MD5 hashing functions
std::string md5(std::string input); std::string md5(std::string input);
std::string md5(const char * input, const unsigned int in_len); std::string md5(const char *input, const unsigned int in_len);
void md5bin(const char * input, const unsigned int in_len, char * output); void md5bin(const char *input, const unsigned int in_len, char *output);
//SHA256 hashing functions // SHA256 hashing functions
std::string sha256(std::string input); std::string sha256(std::string input);
std::string sha256(const char * input, const unsigned int in_len); std::string sha256(const char *input, const unsigned int in_len);
void sha256bin(const char * input, const unsigned int in_len, char * output); void sha256bin(const char *input, const unsigned int in_len, char *output);
//Generic HMAC functions // Generic HMAC functions
std::string hmac(std::string msg, std::string key, unsigned int hashSize, void hasher(const char *, const unsigned int, char*), unsigned int blockSize); std::string hmac(std::string msg, std::string key, unsigned int hashSize,
std::string hmac(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len, unsigned int hashSize, void hasher(const char *, const unsigned int, char*), unsigned int blockSize); void hasher(const char *, const unsigned int, char *), unsigned int blockSize);
void hmacbin(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len, unsigned int hashSize, void hasher(const char*, const unsigned int, char*), unsigned int blockSize, char * output); std::string hmac(const char *msg, const unsigned int msg_len, const char *key,
//Specific HMAC functions const unsigned int key_len, unsigned int hashSize,
void hasher(const char *, const unsigned int, char *), unsigned int blockSize);
void hmacbin(const char *msg, const unsigned int msg_len, const char *key, const unsigned int key_len,
unsigned int hashSize, void hasher(const char *, const unsigned int, char *),
unsigned int blockSize, char *output);
// Specific HMAC functions
std::string hmac_sha256(std::string msg, std::string key); std::string hmac_sha256(std::string msg, std::string key);
std::string hmac_sha256(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len); std::string hmac_sha256(const char *msg, const unsigned int msg_len, const char *key, const unsigned int key_len);
void hmac_sha256bin(const char * msg, const unsigned int msg_len, const char * key, const unsigned int key_len, char * output); void hmac_sha256bin(const char *msg, const unsigned int msg_len, const char *key,
const unsigned int key_len, char *output);
}
}// namespace Secure

View file

@ -35,8 +35,7 @@ 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, void Bit::setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits, unsigned long long value){
unsigned long long value){
// Set the pointer to the last byte we need to be setting // 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.
@ -73,4 +72,3 @@ bool Util::stringToBool(std::string &str){
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

@ -11,8 +11,7 @@ namespace Bit{
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, void setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits, unsigned long long value);
unsigned long long value);
void setByName(char *pointer); 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.
@ -143,8 +142,7 @@ 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 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) | return ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
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.
@ -171,8 +169,7 @@ namespace Bit{
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) | 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 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) | ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
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.
@ -188,4 +185,3 @@ namespace Bit{
} }
}// namespace Bit }// namespace Bit

View file

@ -50,8 +50,7 @@ namespace Utils{
// 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(), DEBUG_MSG(DLVL_ERROR, "Not enough bits left in stream. Left: %d requested: %d", (int)size(), (int)count);
(int)count);
return 0; return 0;
} }
long long unsigned int retval = 0; long long unsigned int retval = 0;
@ -131,16 +130,14 @@ namespace Utils{
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) * return (temp >> 1) * (1 - ((temp & 1) << 1)); // Is actually return (temp / 2) * (1 - (temp & 1) * 2);
(1 - ((temp & 1) << 1)); // Is actually return (temp / 2) * (1 - (temp & 1) * 2);
} }
long long unsigned int bitstream::getUExpGolomb(){return golombGetter() - 1;} long long unsigned int bitstream::getUExpGolomb(){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) * return (temp >> 1) * (1 - ((temp & 1) << 1)); // Is actually return (temp / 2) * (1 - (temp & 1) * 2);
(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;}
@ -285,4 +282,3 @@ namespace Utils{
data.erase(0, pos); data.erase(0, pos);
} }
}// namespace Utils }// namespace Utils

View file

@ -93,4 +93,3 @@ namespace Utils{
void fixData(); void fixData();
}; };
}// namespace Utils }// namespace Utils

View file

@ -1,48 +1,44 @@
#include "certificate.h" #include "certificate.h"
#include "defines.h" #include "defines.h"
Certificate::Certificate() Certificate::Certificate() : rsa_ctx(NULL){
:rsa_ctx(NULL) memset((void *)&cert, 0x00, sizeof(cert));
{ memset((void *)&key, 0x00, sizeof(key));
memset((void*)&cert, 0x00, sizeof(cert));
memset((void*)&key, 0x00, sizeof(key));
} }
int Certificate::init(const std::string &countryName, int Certificate::init(const std::string &countryName, const std::string &organization,
const std::string &organization, const std::string &commonName){
const std::string& commonName)
{
mbedtls_ctr_drbg_context rand_ctx = {}; mbedtls_ctr_drbg_context rand_ctx ={};
mbedtls_entropy_context entropy_ctx = {}; mbedtls_entropy_context entropy_ctx ={};
mbedtls_x509write_cert write_cert = {}; mbedtls_x509write_cert write_cert ={};
const char* personalisation = "mbedtls-self-signed-key"; const char *personalisation = "mbedtls-self-signed-key";
std::string subject_name = "C=" +countryName +",O=" +organization +",CN=" +commonName; std::string subject_name = "C=" + countryName + ",O=" + organization + ",CN=" + commonName;
time_t time_from = { 0 }; time_t time_from ={0};
time_t time_to = { 0 }; time_t time_to ={0};
char time_from_str[20] = { 0 }; char time_from_str[20] ={0};
char time_to_str[20] = { 0 }; char time_to_str[20] ={0};
mbedtls_mpi serial_mpi = { 0 }; mbedtls_mpi serial_mpi ={0};
char serial_hex[17] = { 0 }; char serial_hex[17] ={0};
uint64_t serial_num = 0; uint64_t serial_num = 0;
uint8_t* serial_ptr = (uint8_t*)&serial_num; uint8_t *serial_ptr = (uint8_t *)&serial_num;
int r = 0; int r = 0;
int i = 0; int i = 0;
uint8_t buf[4096] = { 0 }; uint8_t buf[4096] ={0};
// validate // validate
if (countryName.empty()) { if (countryName.empty()){
FAIL_MSG("Given `countryName`, C=<countryName>, is empty."); FAIL_MSG("Given `countryName`, C=<countryName>, is empty.");
r = -1; r = -1;
goto error; goto error;
} }
if (organization.empty()) { if (organization.empty()){
FAIL_MSG("Given `organization`, O=<organization>, is empty."); FAIL_MSG("Given `organization`, O=<organization>, is empty.");
r = -2; r = -2;
goto error; goto error;
} }
if (commonName.empty()) { if (commonName.empty()){
FAIL_MSG("Given `commonName`, CN=<commonName>, is empty."); FAIL_MSG("Given `commonName`, CN=<commonName>, is empty.");
r = -3; r = -3;
goto error; goto error;
@ -51,8 +47,9 @@ int Certificate::init(const std::string &countryName,
// initialize random number generator // initialize random number generator
mbedtls_ctr_drbg_init(&rand_ctx); mbedtls_ctr_drbg_init(&rand_ctx);
mbedtls_entropy_init(&entropy_ctx); mbedtls_entropy_init(&entropy_ctx);
r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx, (const unsigned char*)personalisation, strlen(personalisation)); r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx,
if (0 != r) { (const unsigned char *)personalisation, strlen(personalisation));
if (0 != r){
FAIL_MSG("Failed to initialize and seed the entropy context."); FAIL_MSG("Failed to initialize and seed the entropy context.");
r = -10; r = -10;
goto error; goto error;
@ -61,21 +58,21 @@ int Certificate::init(const std::string &countryName,
// initialize the public key context // initialize the public key context
mbedtls_pk_init(&key); mbedtls_pk_init(&key);
r = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); r = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
if (0 != r) { if (0 != r){
FAIL_MSG("Faild to initialize the PK context."); FAIL_MSG("Faild to initialize the PK context.");
r = -20; r = -20;
goto error; goto error;
} }
rsa_ctx = mbedtls_pk_rsa(key); rsa_ctx = mbedtls_pk_rsa(key);
if (NULL == rsa_ctx) { if (NULL == rsa_ctx){
FAIL_MSG("Failed to get the RSA context from from the public key context (key)."); FAIL_MSG("Failed to get the RSA context from from the public key context (key).");
r = -30; r = -30;
goto error; goto error;
} }
r = mbedtls_rsa_gen_key(rsa_ctx, mbedtls_ctr_drbg_random, &rand_ctx, 2048, 65537); r = mbedtls_rsa_gen_key(rsa_ctx, mbedtls_ctr_drbg_random, &rand_ctx, 2048, 65537);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to generate a private key."); FAIL_MSG("Failed to generate a private key.");
r = -40; r = -40;
goto error; goto error;
@ -86,34 +83,30 @@ int Certificate::init(const std::string &countryName,
time_from = (time_from < 1000000000) ? 1000000000 : time_from; time_from = (time_from < 1000000000) ? 1000000000 : time_from;
time_to = time_from + (60 * 60 * 24 * 365); // valid for a year time_to = time_from + (60 * 60 * 24 * 365); // valid for a year
if (time_to < time_from) { if (time_to < time_from){time_to = INT_MAX;}
time_to = INT_MAX;
}
r = strftime(time_from_str, sizeof(time_from_str), "%Y%m%d%H%M%S", gmtime(&time_from)); r = strftime(time_from_str, sizeof(time_from_str), "%Y%m%d%H%M%S", gmtime(&time_from));
if (0 == r) { if (0 == r){
FAIL_MSG("Failed to generate the valid-from time string."); FAIL_MSG("Failed to generate the valid-from time string.");
r = -50; r = -50;
goto error; goto error;
} }
r = strftime(time_to_str, sizeof(time_to_str), "%Y%m%d%H%M%S", gmtime(&time_to)); r = strftime(time_to_str, sizeof(time_to_str), "%Y%m%d%H%M%S", gmtime(&time_to));
if (0 == r) { if (0 == r){
FAIL_MSG("Failed to generate the valid-to time string."); FAIL_MSG("Failed to generate the valid-to time string.");
r = -60; r = -60;
goto error; goto error;
} }
r = mbedtls_ctr_drbg_random((void*)&rand_ctx, (uint8_t*)&serial_num, sizeof(serial_num)); r = mbedtls_ctr_drbg_random((void *)&rand_ctx, (uint8_t *)&serial_num, sizeof(serial_num));
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to generate a random u64."); FAIL_MSG("Failed to generate a random u64.");
r = -70; r = -70;
goto error; goto error;
} }
for (i = 0; i < 8; ++i) { for (i = 0; i < 8; ++i){sprintf(serial_hex + (i * 2), "%02x", serial_ptr[i]);}
sprintf(serial_hex + (i * 2), "%02x", serial_ptr[i]);
}
// start creating the certificate // start creating the certificate
mbedtls_x509write_crt_init(&write_cert); mbedtls_x509write_crt_init(&write_cert);
@ -122,42 +115,42 @@ int Certificate::init(const std::string &countryName,
mbedtls_x509write_crt_set_subject_key(&write_cert, &key); mbedtls_x509write_crt_set_subject_key(&write_cert, &key);
r = mbedtls_x509write_crt_set_subject_name(&write_cert, subject_name.c_str()); r = mbedtls_x509write_crt_set_subject_name(&write_cert, subject_name.c_str());
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to set the subject name."); FAIL_MSG("Failed to set the subject name.");
r = -80; r = -80;
goto error; goto error;
} }
r = mbedtls_x509write_crt_set_issuer_name(&write_cert, subject_name.c_str()); r = mbedtls_x509write_crt_set_issuer_name(&write_cert, subject_name.c_str());
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to set the issuer name."); FAIL_MSG("Failed to set the issuer name.");
r = -90; r = -90;
goto error; goto error;
} }
r = mbedtls_x509write_crt_set_validity(&write_cert, time_from_str, time_to_str); r = mbedtls_x509write_crt_set_validity(&write_cert, time_from_str, time_to_str);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to set the x509 validity string."); FAIL_MSG("Failed to set the x509 validity string.");
r = -100; r = -100;
goto error; goto error;
} }
r = mbedtls_x509write_crt_set_basic_constraints(&write_cert, 0, -1); r = mbedtls_x509write_crt_set_basic_constraints(&write_cert, 0, -1);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed ot set the basic constraints for the certificate."); FAIL_MSG("Failed ot set the basic constraints for the certificate.");
r = -110; r = -110;
goto error; goto error;
} }
r = mbedtls_x509write_crt_set_subject_key_identifier(&write_cert); r = mbedtls_x509write_crt_set_subject_key_identifier(&write_cert);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to set the subjectKeyIdentifier."); FAIL_MSG("Failed to set the subjectKeyIdentifier.");
r = -120; r = -120;
goto error; goto error;
} }
r = mbedtls_x509write_crt_set_authority_key_identifier(&write_cert); r = mbedtls_x509write_crt_set_authority_key_identifier(&write_cert);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to set the authorityKeyIdentifier."); FAIL_MSG("Failed to set the authorityKeyIdentifier.");
r = -130; r = -130;
goto error; goto error;
@ -167,7 +160,7 @@ int Certificate::init(const std::string &countryName,
mbedtls_mpi_init(&serial_mpi); mbedtls_mpi_init(&serial_mpi);
mbedtls_mpi_read_string(&serial_mpi, 16, serial_hex); mbedtls_mpi_read_string(&serial_mpi, 16, serial_hex);
r = mbedtls_x509write_crt_set_serial(&write_cert, &serial_mpi); r = mbedtls_x509write_crt_set_serial(&write_cert, &serial_mpi);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to set the certificate serial."); FAIL_MSG("Failed to set the certificate serial.");
r = -140; r = -140;
goto error; goto error;
@ -175,7 +168,7 @@ int Certificate::init(const std::string &countryName,
// write the certificate into a PEM structure // write the certificate into a PEM structure
r = mbedtls_x509write_crt_pem(&write_cert, buf, sizeof(buf), mbedtls_ctr_drbg_random, &rand_ctx); r = mbedtls_x509write_crt_pem(&write_cert, buf, sizeof(buf), mbedtls_ctr_drbg_random, &rand_ctx);
if (0 != r) { if (0 != r){
FAIL_MSG("Failed to create the PEM data from the x509 write structure."); FAIL_MSG("Failed to create the PEM data from the x509 write structure.");
r = -150; r = -150;
goto error; goto error;
@ -188,15 +181,15 @@ int Certificate::init(const std::string &countryName,
// function. // function.
mbedtls_x509_crt_init(&cert); mbedtls_x509_crt_init(&cert);
r = mbedtls_x509_crt_parse(&cert, (const unsigned char*)buf, strlen((char*)buf) + 1); r = mbedtls_x509_crt_parse(&cert, (const unsigned char *)buf, strlen((char *)buf) + 1);
if (0 != r) { if (0 != r){
mbedtls_strerror(r, (char*)buf, sizeof(buf)); mbedtls_strerror(r, (char *)buf, sizeof(buf));
FAIL_MSG("Failed to convert the mbedtls_x509write_crt into a mbedtls_x509_crt: %s", buf); FAIL_MSG("Failed to convert the mbedtls_x509write_crt into a mbedtls_x509_crt: %s", buf);
r = -160; r = -160;
goto error; goto error;
} }
error: error:
// cleanup // cleanup
mbedtls_ctr_drbg_free(&rand_ctx); mbedtls_ctr_drbg_free(&rand_ctx);
@ -204,37 +197,32 @@ int Certificate::init(const std::string &countryName,
mbedtls_x509write_crt_free(&write_cert); mbedtls_x509write_crt_free(&write_cert);
mbedtls_mpi_free(&serial_mpi); mbedtls_mpi_free(&serial_mpi);
if (r < 0) { if (r < 0){shutdown();}
shutdown();
}
return r; return r;
} }
int Certificate::shutdown() { int Certificate::shutdown(){
rsa_ctx = NULL; rsa_ctx = NULL;
mbedtls_pk_free(&key); mbedtls_pk_free(&key);
mbedtls_x509_crt_free(&cert); mbedtls_x509_crt_free(&cert);
return 0; return 0;
} }
std::string Certificate::getFingerprintSha256() { std::string Certificate::getFingerprintSha256(){
uint8_t fingerprint_raw[32] = {}; uint8_t fingerprint_raw[32] ={};
uint8_t fingerprint_hex[128] = {}; uint8_t fingerprint_hex[128] ={};
mbedtls_md_type_t hash_type = MBEDTLS_MD_SHA256; mbedtls_md_type_t hash_type = MBEDTLS_MD_SHA256;
mbedtls_sha256(cert.raw.p, cert.raw.len, fingerprint_raw, 0); mbedtls_sha256(cert.raw.p, cert.raw.len, fingerprint_raw, 0);
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i){
sprintf((char*)(fingerprint_hex + (i * 3)), ":%02X", (int)fingerprint_raw[i]); sprintf((char *)(fingerprint_hex + (i * 3)), ":%02X", (int)fingerprint_raw[i]);
} }
fingerprint_hex[32 * 3] = '\0'; fingerprint_hex[32 * 3] = '\0';
std::string result = std::string((char*)fingerprint_hex + 1, (32 * 3) - 1); std::string result = std::string((char *)fingerprint_hex + 1, (32 * 3) - 1);
return result; return result;
} }

View file

@ -10,25 +10,25 @@
*/ */
#include <string>
#include <mbedtls/config.h> #include <mbedtls/config.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha256.h>
#include <mbedtls/x509_crt.h> #include <mbedtls/x509_crt.h>
#include <mbedtls/x509_csr.h> #include <mbedtls/x509_csr.h>
#include <mbedtls/entropy.h> #include <string>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/md.h>
#include <mbedtls/error.h>
#include <mbedtls/sha256.h>
class Certificate { class Certificate{
public: public:
Certificate(); Certificate();
int init(const std::string &countryName, const std::string &organization, const std::string& commonName); int init(const std::string &countryName, const std::string &organization, const std::string &commonName);
int shutdown(); int shutdown();
std::string getFingerprintSha256(); std::string getFingerprintSha256();
public: public:
mbedtls_x509_crt cert; mbedtls_x509_crt cert;
mbedtls_pk_context key; /* key context, stores private and public key. */ mbedtls_pk_context key; /* key context, stores private and public key. */
mbedtls_rsa_context* rsa_ctx; /* rsa context, stored in key_ctx */ mbedtls_rsa_context *rsa_ctx; /* rsa context, stored in key_ctx */
}; };

View file

@ -1,75 +1,48 @@
#include <stddef.h> #include <stddef.h>
namespace checksum { namespace checksum{
inline unsigned int crc32c(unsigned int crc, const char * data, size_t len) { inline unsigned int crc32c(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] = { static const unsigned int table[256] ={
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x130476DCU, 0x17C56B6BU, 0x1A864DB2U,
0x130476DCU, 0x17C56B6BU, 0x1A864DB2U, 0x1E475005U, 0x1E475005U, 0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, 0x350C9B64U, 0x31CD86D3U,
0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, 0x3C8EA00AU, 0x384FBDBDU, 0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, 0x5F15ADACU,
0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, 0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU,
0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x95609039U, 0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xBE2B5B58U, 0xBAEA46EFU,
0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U, 0xB7A96036U, 0xB3687D81U, 0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0xD4326D90U,
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U, 0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, 0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU,
0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xEC7DD02DU, 0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0x278206ABU, 0x23431B1CU,
0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U, 0x2E003DC5U, 0x2AC12072U, 0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0x018AEB13U,
0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, 0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U,
0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U, 0x53DC6066U, 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, 0xACA5C697U, 0xA864DB20U,
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, 0xA527FDF9U, 0xA1E6E04EU, 0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0x8AAD2B2FU,
0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, 0xF3B06B3BU, 0xF771768CU, 0xFA325055U,
0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U, 0xFEF34DE2U, 0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0xD5B88683U, 0xD1799B34U,
0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0xDC3ABDEDU, 0xD8FBA05AU, 0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, 0x7A089632U,
0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU, 0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U,
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x285E1D47U, 0x36194D42U, 0x32D850F5U, 0x3F9B762CU, 0x3B5A6B9BU, 0x0315D626U, 0x07D4CB91U,
0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U, 0x53DC6066U, 0x0A97ED48U, 0x0E56F0FFU, 0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U, 0xF12F560EU,
0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U, 0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU,
0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU, 0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU, 0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U,
0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0xC960EBB3U, 0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U, 0xAE3AFBA2U, 0xAAFBE615U,
0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0xA7B8C0CCU, 0xA379DD7BU, 0x9B3660C6U, 0x9FF77D71U, 0x92B45BA8U, 0x9675461FU, 0x8832161AU,
0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U, 0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U,
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, 0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU, 0x7B827D21U, 0x7F436096U, 0x7200464FU,
0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U, 0x76C15BF8U, 0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U, 0x119B4BE9U, 0x155A565EU,
0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0x18197087U, 0x1CD86D30U, 0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU, 0x3793A651U,
0xD5B88683U, 0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U, 0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U,
0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, 0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U, 0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU,
0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0xDBEE767CU, 0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU, 0xEEE2ED18U, 0xF0A5BD1DU, 0xF464A0AAU,
0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU, 0xF9278673U, 0xFDE69BC4U, 0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U, 0x9ABC8BD5U,
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU, 0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U,
0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U, 0x285E1D47U, 0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U,
0x36194D42U, 0x32D850F5U, 0x3F9B762CU, 0x3B5A6B9BU,
0x0315D626U, 0x07D4CB91U, 0x0A97ED48U, 0x0E56F0FFU,
0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U,
0xF12F560EU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U,
0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU,
0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU,
0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U, 0xC960EBB3U,
0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U,
0xAE3AFBA2U, 0xAAFBE615U, 0xA7B8C0CCU, 0xA379DD7BU,
0x9B3660C6U, 0x9FF77D71U, 0x92B45BA8U, 0x9675461FU,
0x8832161AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U,
0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U,
0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU,
0x7B827D21U, 0x7F436096U, 0x7200464FU, 0x76C15BF8U,
0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U,
0x119B4BE9U, 0x155A565EU, 0x18197087U, 0x1CD86D30U,
0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU,
0x3793A651U, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U,
0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U,
0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U,
0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU, 0xDBEE767CU,
0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU, 0xEEE2ED18U,
0xF0A5BD1DU, 0xF464A0AAU, 0xF9278673U, 0xFDE69BC4U,
0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U,
0x9ABC8BD5U, 0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU,
0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U,
0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U,
}; };
while (len > 0) { while (len > 0){
crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8); crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
data++; data++;
len--; len--;
@ -77,75 +50,47 @@ namespace checksum {
return crc; return crc;
} }
inline unsigned int crc32LE(unsigned int crc, const char * data, size_t len) { inline unsigned int crc32LE(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] = { static const unsigned int table[256] ={
0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, 0x706af48fU, 0xe963a535U,
0x076dc419U, 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU,
0x0edb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d988U, 0xe7b82d07U, 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 0x1adad47dU,
0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 0x90bf1d91U, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU,
0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 0x14015c4fU, 0x63066cd9U, 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 0x35b5a8faU, 0x42b2986cU,
0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU,
0x14015c4fU, 0x63066cd9U, 0xfa0f3d63U, 0x8d080df5U, 0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 0xb8bda50fU,
0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 0xa2677172U, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU,
0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 0xb6662d3dU, 0x76dc4190U, 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 0xe10e9818U, 0x7f6a0dbbU,
0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU,
0x26d930acU, 0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, 0x8bbeb8eaU,
0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 0xb8bda50fU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU,
0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 0xa3bc0074U, 0xd4bb30e2U, 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U,
0x76dc4190U, 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U,
0x71b18589U, 0x06b6b51fU, 0x9fbfe4a5U, 0xe8b8d433U, 0xce61e49fU, 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 0x2eb40d81U,
0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 0xe10e9818U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 0x03b6e20cU, 0x74b1d29aU, 0xead54739U,
0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, 0x9dd277afU, 0x04db2615U, 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, 0x8708a3d2U, 0x1e01f268U,
0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U,
0x65b0d9c6U, 0x12b7e950U, 0x8bbeb8eaU, 0xfcb9887cU, 0x10da7a5aU, 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, 0xd6d6a3e8U,
0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd44c65U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU,
0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 0xd80d2bdaU, 0xaf0a1b4cU, 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, 0xcc0c7795U, 0xbb0b4703U,
0x4369e96aU, 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U,
0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U, 0xb5d0cf31U, 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 0x026d930aU,
0x5005713cU, 0x270241aaU, 0xbe0b1010U, 0xc90c2086U, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU,
0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, 0x0cb61b38U, 0x92d28e9bU, 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 0x18b74777U, 0x88085ae6U,
0x59b33d17U, 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U,
0xedb88320U, 0x9abfb3b6U, 0x03b6e20cU, 0x74b1d29aU, 0xa00ae278U, 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, 0x4969474dU,
0xead54739U, 0x9dd277afU, 0x04db2615U, 0x73dc1683U, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U,
0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, 0x47b2cf7fU, 0x30b5ffe9U, 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, 0x5d681b02U, 0x2a6f2b94U,
0xf00f9344U, 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU};
0xf762575dU, 0x806567cbU, 0x196c3671U, 0x6e6b06e7U,
0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 0x67dd4accU,
0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U,
0xd1bb67f1U, 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU,
0xd80d2bdaU, 0xaf0a1b4cU, 0x36034af6U, 0x41047a60U,
0xdf60efc3U, 0xa867df55U, 0x316e8eefU, 0x4669be79U,
0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU,
0xc5ba3bbeU, 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U,
0xc2d7ffa7U, 0xb5d0cf31U, 0x2cd99e8bU, 0x5bdeae1dU,
0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 0x026d930aU,
0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U,
0x92d28e9bU, 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U,
0x86d3d2d4U, 0xf1d4e242U, 0x68ddb3f8U, 0x1fda836eU,
0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 0x18b74777U,
0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U,
0xa00ae278U, 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U,
0xa7672661U, 0xd06016f7U, 0x4969474dU, 0x3e6e77dbU,
0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, 0x37d83bf0U,
0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U,
0xbad03605U, 0xcdd70693U, 0x54de5729U, 0x23d967bfU,
0xb3667a2eU, 0xc4614ab8U, 0x5d681b02U, 0x2a6f2b94U,
0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU
};
while (len > 0) { while (len > 0){
crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8); crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
data++; data++;
len--; len--;
@ -153,79 +98,49 @@ namespace checksum {
return crc; return crc;
} }
inline unsigned int crc32(unsigned int crc, const char * data, size_t len) { inline unsigned int crc32(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] = { static const unsigned int table[256] ={
0x00000000U, 0xB71DC104U, 0x6E3B8209U, 0xD926430DU, 0x00000000U, 0xB71DC104U, 0x6E3B8209U, 0xD926430DU, 0xDC760413U, 0x6B6BC517U, 0xB24D861AU,
0xDC760413U, 0x6B6BC517U, 0xB24D861AU, 0x0550471EU, 0x0550471EU, 0xB8ED0826U, 0x0FF0C922U, 0xD6D68A2FU, 0x61CB4B2BU, 0x649B0C35U, 0xD386CD31U,
0xB8ED0826U, 0x0FF0C922U, 0xD6D68A2FU, 0x61CB4B2BU, 0x0AA08E3CU, 0xBDBD4F38U, 0x70DB114CU, 0xC7C6D048U, 0x1EE09345U, 0xA9FD5241U, 0xACAD155FU,
0x649B0C35U, 0xD386CD31U, 0x0AA08E3CU, 0xBDBD4F38U, 0x1BB0D45BU, 0xC2969756U, 0x758B5652U, 0xC836196AU, 0x7F2BD86EU, 0xA60D9B63U, 0x11105A67U,
0x70DB114CU, 0xC7C6D048U, 0x1EE09345U, 0xA9FD5241U, 0x14401D79U, 0xA35DDC7DU, 0x7A7B9F70U, 0xCD665E74U, 0xE0B62398U, 0x57ABE29CU, 0x8E8DA191U,
0xACAD155FU, 0x1BB0D45BU, 0xC2969756U, 0x758B5652U, 0x39906095U, 0x3CC0278BU, 0x8BDDE68FU, 0x52FBA582U, 0xE5E66486U, 0x585B2BBEU, 0xEF46EABAU,
0xC836196AU, 0x7F2BD86EU, 0xA60D9B63U, 0x11105A67U, 0x3660A9B7U, 0x817D68B3U, 0x842D2FADU, 0x3330EEA9U, 0xEA16ADA4U, 0x5D0B6CA0U, 0x906D32D4U,
0x14401D79U, 0xA35DDC7DU, 0x7A7B9F70U, 0xCD665E74U, 0x2770F3D0U, 0xFE56B0DDU, 0x494B71D9U, 0x4C1B36C7U, 0xFB06F7C3U, 0x2220B4CEU, 0x953D75CAU,
0xE0B62398U, 0x57ABE29CU, 0x8E8DA191U, 0x39906095U, 0x28803AF2U, 0x9F9DFBF6U, 0x46BBB8FBU, 0xF1A679FFU, 0xF4F63EE1U, 0x43EBFFE5U, 0x9ACDBCE8U,
0x3CC0278BU, 0x8BDDE68FU, 0x52FBA582U, 0xE5E66486U, 0x2DD07DECU, 0x77708634U, 0xC06D4730U, 0x194B043DU, 0xAE56C539U, 0xAB068227U, 0x1C1B4323U,
0x585B2BBEU, 0xEF46EABAU, 0x3660A9B7U, 0x817D68B3U, 0xC53D002EU, 0x7220C12AU, 0xCF9D8E12U, 0x78804F16U, 0xA1A60C1BU, 0x16BBCD1FU, 0x13EB8A01U,
0x842D2FADU, 0x3330EEA9U, 0xEA16ADA4U, 0x5D0B6CA0U, 0xA4F64B05U, 0x7DD00808U, 0xCACDC90CU, 0x07AB9778U, 0xB0B6567CU, 0x69901571U, 0xDE8DD475U,
0x906D32D4U, 0x2770F3D0U, 0xFE56B0DDU, 0x494B71D9U, 0xDBDD936BU, 0x6CC0526FU, 0xB5E61162U, 0x02FBD066U, 0xBF469F5EU, 0x085B5E5AU, 0xD17D1D57U,
0x4C1B36C7U, 0xFB06F7C3U, 0x2220B4CEU, 0x953D75CAU, 0x6660DC53U, 0x63309B4DU, 0xD42D5A49U, 0x0D0B1944U, 0xBA16D840U, 0x97C6A5ACU, 0x20DB64A8U,
0x28803AF2U, 0x9F9DFBF6U, 0x46BBB8FBU, 0xF1A679FFU, 0xF9FD27A5U, 0x4EE0E6A1U, 0x4BB0A1BFU, 0xFCAD60BBU, 0x258B23B6U, 0x9296E2B2U, 0x2F2BAD8AU,
0xF4F63EE1U, 0x43EBFFE5U, 0x9ACDBCE8U, 0x2DD07DECU, 0x98366C8EU, 0x41102F83U, 0xF60DEE87U, 0xF35DA999U, 0x4440689DU, 0x9D662B90U, 0x2A7BEA94U,
0x77708634U, 0xC06D4730U, 0x194B043DU, 0xAE56C539U, 0xE71DB4E0U, 0x500075E4U, 0x892636E9U, 0x3E3BF7EDU, 0x3B6BB0F3U, 0x8C7671F7U, 0x555032FAU,
0xAB068227U, 0x1C1B4323U, 0xC53D002EU, 0x7220C12AU, 0xE24DF3FEU, 0x5FF0BCC6U, 0xE8ED7DC2U, 0x31CB3ECFU, 0x86D6FFCBU, 0x8386B8D5U, 0x349B79D1U,
0xCF9D8E12U, 0x78804F16U, 0xA1A60C1BU, 0x16BBCD1FU, 0xEDBD3ADCU, 0x5AA0FBD8U, 0xEEE00C69U, 0x59FDCD6DU, 0x80DB8E60U, 0x37C64F64U, 0x3296087AU,
0x13EB8A01U, 0xA4F64B05U, 0x7DD00808U, 0xCACDC90CU, 0x858BC97EU, 0x5CAD8A73U, 0xEBB04B77U, 0x560D044FU, 0xE110C54BU, 0x38368646U, 0x8F2B4742U,
0x07AB9778U, 0xB0B6567CU, 0x69901571U, 0xDE8DD475U, 0x8A7B005CU, 0x3D66C158U, 0xE4408255U, 0x535D4351U, 0x9E3B1D25U, 0x2926DC21U, 0xF0009F2CU,
0xDBDD936BU, 0x6CC0526FU, 0xB5E61162U, 0x02FBD066U, 0x471D5E28U, 0x424D1936U, 0xF550D832U, 0x2C769B3FU, 0x9B6B5A3BU, 0x26D61503U, 0x91CBD407U,
0xBF469F5EU, 0x085B5E5AU, 0xD17D1D57U, 0x6660DC53U, 0x48ED970AU, 0xFFF0560EU, 0xFAA01110U, 0x4DBDD014U, 0x949B9319U, 0x2386521DU, 0x0E562FF1U,
0x63309B4DU, 0xD42D5A49U, 0x0D0B1944U, 0xBA16D840U, 0xB94BEEF5U, 0x606DADF8U, 0xD7706CFCU, 0xD2202BE2U, 0x653DEAE6U, 0xBC1BA9EBU, 0x0B0668EFU,
0x97C6A5ACU, 0x20DB64A8U, 0xF9FD27A5U, 0x4EE0E6A1U, 0xB6BB27D7U, 0x01A6E6D3U, 0xD880A5DEU, 0x6F9D64DAU, 0x6ACD23C4U, 0xDDD0E2C0U, 0x04F6A1CDU,
0x4BB0A1BFU, 0xFCAD60BBU, 0x258B23B6U, 0x9296E2B2U, 0xB3EB60C9U, 0x7E8D3EBDU, 0xC990FFB9U, 0x10B6BCB4U, 0xA7AB7DB0U, 0xA2FB3AAEU, 0x15E6FBAAU,
0x2F2BAD8AU, 0x98366C8EU, 0x41102F83U, 0xF60DEE87U, 0xCCC0B8A7U, 0x7BDD79A3U, 0xC660369BU, 0x717DF79FU, 0xA85BB492U, 0x1F467596U, 0x1A163288U,
0xF35DA999U, 0x4440689DU, 0x9D662B90U, 0x2A7BEA94U, 0xAD0BF38CU, 0x742DB081U, 0xC3307185U, 0x99908A5DU, 0x2E8D4B59U, 0xF7AB0854U, 0x40B6C950U,
0xE71DB4E0U, 0x500075E4U, 0x892636E9U, 0x3E3BF7EDU, 0x45E68E4EU, 0xF2FB4F4AU, 0x2BDD0C47U, 0x9CC0CD43U, 0x217D827BU, 0x9660437FU, 0x4F460072U,
0x3B6BB0F3U, 0x8C7671F7U, 0x555032FAU, 0xE24DF3FEU, 0xF85BC176U, 0xFD0B8668U, 0x4A16476CU, 0x93300461U, 0x242DC565U, 0xE94B9B11U, 0x5E565A15U,
0x5FF0BCC6U, 0xE8ED7DC2U, 0x31CB3ECFU, 0x86D6FFCBU, 0x87701918U, 0x306DD81CU, 0x353D9F02U, 0x82205E06U, 0x5B061D0BU, 0xEC1BDC0FU, 0x51A69337U,
0x8386B8D5U, 0x349B79D1U, 0xEDBD3ADCU, 0x5AA0FBD8U, 0xE6BB5233U, 0x3F9D113EU, 0x8880D03AU, 0x8DD09724U, 0x3ACD5620U, 0xE3EB152DU, 0x54F6D429U,
0xEEE00C69U, 0x59FDCD6DU, 0x80DB8E60U, 0x37C64F64U, 0x7926A9C5U, 0xCE3B68C1U, 0x171D2BCCU, 0xA000EAC8U, 0xA550ADD6U, 0x124D6CD2U, 0xCB6B2FDFU,
0x3296087AU, 0x858BC97EU, 0x5CAD8A73U, 0xEBB04B77U, 0x7C76EEDBU, 0xC1CBA1E3U, 0x76D660E7U, 0xAFF023EAU, 0x18EDE2EEU, 0x1DBDA5F0U, 0xAAA064F4U,
0x560D044FU, 0xE110C54BU, 0x38368646U, 0x8F2B4742U, 0x738627F9U, 0xC49BE6FDU, 0x09FDB889U, 0xBEE0798DU, 0x67C63A80U, 0xD0DBFB84U, 0xD58BBC9AU,
0x8A7B005CU, 0x3D66C158U, 0xE4408255U, 0x535D4351U, 0x62967D9EU, 0xBBB03E93U, 0x0CADFF97U, 0xB110B0AFU, 0x060D71ABU, 0xDF2B32A6U, 0x6836F3A2U,
0x9E3B1D25U, 0x2926DC21U, 0xF0009F2CU, 0x471D5E28U, 0x6D66B4BCU, 0xDA7B75B8U, 0x035D36B5U, 0xB440F7B1U};
0x424D1936U, 0xF550D832U, 0x2C769B3FU, 0x9B6B5A3BU,
0x26D61503U, 0x91CBD407U, 0x48ED970AU, 0xFFF0560EU,
0xFAA01110U, 0x4DBDD014U, 0x949B9319U, 0x2386521DU,
0x0E562FF1U, 0xB94BEEF5U, 0x606DADF8U, 0xD7706CFCU,
0xD2202BE2U, 0x653DEAE6U, 0xBC1BA9EBU, 0x0B0668EFU,
0xB6BB27D7U, 0x01A6E6D3U, 0xD880A5DEU, 0x6F9D64DAU,
0x6ACD23C4U, 0xDDD0E2C0U, 0x04F6A1CDU, 0xB3EB60C9U,
0x7E8D3EBDU, 0xC990FFB9U, 0x10B6BCB4U, 0xA7AB7DB0U,
0xA2FB3AAEU, 0x15E6FBAAU, 0xCCC0B8A7U, 0x7BDD79A3U,
0xC660369BU, 0x717DF79FU, 0xA85BB492U, 0x1F467596U,
0x1A163288U, 0xAD0BF38CU, 0x742DB081U, 0xC3307185U,
0x99908A5DU, 0x2E8D4B59U, 0xF7AB0854U, 0x40B6C950U,
0x45E68E4EU, 0xF2FB4F4AU, 0x2BDD0C47U, 0x9CC0CD43U,
0x217D827BU, 0x9660437FU, 0x4F460072U, 0xF85BC176U,
0xFD0B8668U, 0x4A16476CU, 0x93300461U, 0x242DC565U,
0xE94B9B11U, 0x5E565A15U, 0x87701918U, 0x306DD81CU,
0x353D9F02U, 0x82205E06U, 0x5B061D0BU, 0xEC1BDC0FU,
0x51A69337U, 0xE6BB5233U, 0x3F9D113EU, 0x8880D03AU,
0x8DD09724U, 0x3ACD5620U, 0xE3EB152DU, 0x54F6D429U,
0x7926A9C5U, 0xCE3B68C1U, 0x171D2BCCU, 0xA000EAC8U,
0xA550ADD6U, 0x124D6CD2U, 0xCB6B2FDFU, 0x7C76EEDBU,
0xC1CBA1E3U, 0x76D660E7U, 0xAFF023EAU, 0x18EDE2EEU,
0x1DBDA5F0U, 0xAAA064F4U, 0x738627F9U, 0xC49BE6FDU,
0x09FDB889U, 0xBEE0798DU, 0x67C63A80U, 0xD0DBFB84U,
0xD58BBC9AU, 0x62967D9EU, 0xBBB03E93U, 0x0CADFF97U,
0xB110B0AFU, 0x060D71ABU, 0xDF2B32A6U, 0x6836F3A2U,
0x6D66B4BCU, 0xDA7B75B8U, 0x035D36B5U, 0xB440F7B1U
};
const char * tmpData = data; const char *tmpData = data;
const char * end = tmpData + len; const char *end = tmpData + len;
while(tmpData < end){ while (tmpData < end){crc = table[((unsigned char)crc) ^ *tmpData++] ^ (crc >> 8);}
crc = table[((unsigned char) crc) ^ *tmpData++] ^ (crc >> 8);
}
return crc; return crc;
} }
} }// namespace checksum

View file

@ -132,8 +132,7 @@ void Util::Config::printHelp(std::ostream &output){
} }
while (f.size() < longest){f.append(" ");} while (f.size() < longest){f.append(" ");}
if (it->isMember("arg")){ if (it->isMember("arg")){
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() << std::endl;
<< std::endl;
}else{ }else{
output << f << (*it)["help"].asString() << std::endl; output << f << (*it)["help"].asString() << std::endl;
} }
@ -141,8 +140,7 @@ void Util::Config::printHelp(std::ostream &output){
if (it->isMember("arg_num")){ if (it->isMember("arg_num")){
f = it.key(); f = it.key();
while (f.size() < longest){f.append(" ");} while (f.size() < longest){f.append(" ");}
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() << std::endl;
<< std::endl;
} }
} }
} }
@ -188,9 +186,9 @@ bool Util::Config::parseArgs(int &argc, char **&argv){
<< std::endl; << std::endl;
#endif #endif
#ifdef WITH_THREADNAMES #ifdef WITH_THREADNAMES
std::cout std::cout << "- Flag: With threadnames. Debuggers will show sensible human-readable thread "
<< "- Flag: With threadnames. Debuggers will show sensible human-readable thread names." "names."
<< std::endl; << std::endl;
#endif #endif
/*LTS-START*/ /*LTS-START*/
#ifndef UPDATER #ifndef UPDATER
@ -210,9 +208,8 @@ bool Util::Config::parseArgs(int &argc, char **&argv){
#endif #endif
#ifdef STATS_DELAY #ifdef STATS_DELAY
if (STATS_DELAY != 15){ if (STATS_DELAY != 15){
std::cout << "- Setting: Stats delay " << STATS_DELAY std::cout << "- Setting: Stats delay " << STATS_DELAY << ". Statistics of viewer counts are delayed by "
<< ". Statistics of viewer counts are delayed by " << STATS_DELAY << STATS_DELAY << " seconds as opposed to the default of 15 seconds. ";
<< " 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{
@ -263,8 +260,7 @@ bool Util::Config::hasOption(const std::string &optname){
/// 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::cout << "Fatal error: a non-existent option '" << optname << "' was accessed." << std::endl;
<< std::endl;
exit(37); exit(37);
} }
if (!vals[optname].isMember("value") || !vals[optname]["value"].isArray()){ if (!vals[optname].isMember("value") || !vals[optname]["value"].isArray()){
@ -313,8 +309,7 @@ static void callThreadCallback(void *cDataArg){
INSANE_MSG("Thread for %p ended", cDataArg); INSANE_MSG("Thread for %p ended", cDataArg);
} }
int Util::Config::threadServer(Socket::Server &server_socket, int Util::Config::threadServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &)){
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();
@ -354,9 +349,7 @@ int Util::Config::forkServer(Socket::Server &server_socket, int (*callback)(Sock
} }
} }
Util::Procs::socketList.erase(server_socket.getSocket()); Util::Procs::socketList.erase(server_socket.getSocket());
if (!is_restarting){ if (!is_restarting){server_socket.close();}
server_socket.close();
}
return 0; return 0;
} }
@ -366,7 +359,7 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
server_socket = Socket::Server(0); server_socket = Socket::Server(0);
}else if (vals.isMember("socket")){ }else if (vals.isMember("socket")){
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
} else if (vals.isMember("port") && vals.isMember("interface")){ }else 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()){
@ -394,7 +387,7 @@ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){
server_socket = Socket::Server(0); server_socket = Socket::Server(0);
}else if (vals.isMember("socket")){ }else if (vals.isMember("socket")){
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
} else if (vals.isMember("port") && vals.isMember("interface")){ }else 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()){
@ -463,8 +456,7 @@ 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, INFO_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid);
sigInfo->si_pid);
break; break;
default: INFO_MSG("Received signal %s (%d)", strsignal(signum), signum); break; default: INFO_MSG("Received signal %s (%d)", strsignal(signum), signum); break;
} }
@ -653,4 +645,3 @@ void Util::setUser(std::string username){
} }
} }
} }

View file

@ -23,7 +23,7 @@ namespace Util{
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 bool is_restarting; ///< Set to true when restarting, set to false on boot. static bool is_restarting; ///< Set to true when restarting, set to false on boot.
static uint32_t 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
@ -64,4 +64,3 @@ namespace Util{
void setUser(std::string user); void setUser(std::string user);
}// namespace Util }// namespace Util

View file

@ -2,31 +2,33 @@
// Defines to print debug messages. // Defines to print debug messages.
#ifndef MIST_DEBUG #ifndef MIST_DEBUG
#define MIST_DEBUG 1 #define MIST_DEBUG 1
#define DLVL_NONE 0 // All debugging disabled. #define DLVL_NONE 0 // All debugging disabled.
#define DLVL_FAIL 1 // Only messages about failed operations. #define DLVL_FAIL 1 // Only messages about failed operations.
#define DLVL_ERROR 2 // Only messages about errors and failed operations. #define DLVL_ERROR 2 // Only messages about errors and failed operations.
#define DLVL_WARN 3 // Warnings, errors, and fail messages. #define DLVL_WARN 3 // Warnings, errors, and fail messages.
#define DLVL_DEVEL 4 // All of the above, plus status messages handy during development. #define DLVL_DEVEL 4 // All of the above, plus status messages handy during development.
#define DLVL_INFO 4 // All of the above, plus status messages handy during development. #define DLVL_INFO 4 // All of the above, plus status messages handy during development.
#define DLVL_MEDIUM 5 // Slightly more than just development-level messages. #define DLVL_MEDIUM 5 // Slightly more than just development-level messages.
#define DLVL_HIGH 6 // Verbose debugging messages. #define DLVL_HIGH 6 // Verbose debugging messages.
#define DLVL_VERYHIGH 7 // Very verbose debugging messages. #define DLVL_VERYHIGH 7 // Very verbose debugging messages.
#define DLVL_EXTREME 8 // Everything is reported in extreme detail. #define DLVL_EXTREME 8 // Everything is reported in extreme detail.
#define DLVL_INSANE 9 // Everything is reported in insane detail. #define DLVL_INSANE 9 // Everything is reported in insane detail.
#define DLVL_DONTEVEN 10 // All messages enabled, even pointless ones. #define DLVL_DONTEVEN 10 // All messages enabled, even pointless ones.
#define PRETTY_PRINT_TIME "%ud%uh%um%us" #define PRETTY_PRINT_TIME "%ud%uh%um%us"
#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
#define PRETTY_PRINT_MSTIME "%ud%.2uh%.2um%.2us.%.3u" #define PRETTY_PRINT_MSTIME "%ud%.2uh%.2um%.2us.%.3u"
#define PRETTY_ARG_MSTIME(t) PRETTY_ARG_TIME(t/1000), (int)(t%1000) #define PRETTY_ARG_MSTIME(t) PRETTY_ARG_TIME(t / 1000), (int)(t % 1000)
#if DEBUG > -1 #if DEBUG > -1
#define __STDC_FORMAT_MACROS 1 #define __STDC_FORMAT_MACROS 1
#include <stdio.h> #include "config.h"
#include <unistd.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
#include "config.h" #include <stdio.h>
static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "MEDIUM", "HIGH", "VERYHIGH", "EXTREME", "INSANE", "DONTEVEN"}; #include <unistd.h>
static const char *DBG_LVL_LIST[] ={"NONE", "FAIL", "ERROR", "WARN", "INFO", "MEDIUM",
"HIGH", "VERYHIGH", "EXTREME", "INSANE", "DONTEVEN"};
#if !defined(PRIu64) #if !defined(PRIu64)
#define PRIu64 "llu" #define PRIu64 "llu"
@ -40,15 +42,31 @@ static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "
#include <errno.h> #include <errno.h>
#if DEBUG >= DLVL_DEVEL #if DEBUG >= DLVL_DEVEL
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|%s|%d|%s:%d|%s|" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, getpid(), __FILE__, __LINE__, Util::Config::streamName.c_str(), ##__VA_ARGS__);} #define DEBUG_MSG(lvl, msg, ...) \
if (Util::Config::printDebugLevel >= lvl){\
fprintf(stderr, "%s|%s|%d|%s:%d|%s|" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, \
getpid(), __FILE__, __LINE__, Util::Config::streamName.c_str(), ##__VA_ARGS__); \
}
#else #else
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|%s|%d||%s|" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, getpid(), Util::Config::streamName.c_str(), ##__VA_ARGS__);} #define DEBUG_MSG(lvl, msg, ...) \
if (Util::Config::printDebugLevel >= lvl){\
fprintf(stderr, "%s|%s|%d||%s|" msg "\n", DBG_LVL_LIST[lvl], program_invocation_short_name, \
getpid(), Util::Config::streamName.c_str(), ##__VA_ARGS__); \
}
#endif #endif
#else #else
#if DEBUG >= DLVL_DEVEL #if DEBUG >= DLVL_DEVEL
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|MistProcess|%d|%s:%d|%s|" msg "\n", DBG_LVL_LIST[lvl], getpid(), __FILE__, __LINE__, Util::Config::streamName.c_str(), ##__VA_ARGS__);} #define DEBUG_MSG(lvl, msg, ...) \
if (Util::Config::printDebugLevel >= lvl){\
fprintf(stderr, "%s|MistProcess|%d|%s:%d|%s|" msg "\n", DBG_LVL_LIST[lvl], getpid(), __FILE__, \
__LINE__, Util::Config::streamName.c_str(), ##__VA_ARGS__); \
}
#else #else
#define DEBUG_MSG(lvl, msg, ...) if (Util::Config::printDebugLevel >= lvl){fprintf(stderr, "%s|MistProcess|%d||%s|" msg "\n", DBG_LVL_LIST[lvl], getpid(), Util::Config::streamName.c_str(), ##__VA_ARGS__);} #define DEBUG_MSG(lvl, msg, ...) \
if (Util::Config::printDebugLevel >= lvl){\
fprintf(stderr, "%s|MistProcess|%d||%s|" msg "\n", DBG_LVL_LIST[lvl], getpid(), \
Util::Config::streamName.c_str(), ##__VA_ARGS__); \
}
#endif #endif
#endif #endif
@ -56,18 +74,16 @@ static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "
static inline void show_stackframe(){} static inline void show_stackframe(){}
#else #else
#include <execinfo.h> #include <execinfo.h>
static inline void show_stackframe() { static inline void show_stackframe(){
void *trace[16]; void *trace[16];
char **messages = 0; char **messages = 0;
int i, trace_size = 0; int i, trace_size = 0;
trace_size = backtrace(trace, 16); trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size); messages = backtrace_symbols(trace, trace_size);
for (i=1; i<trace_size; ++i){ for (i = 1; i < trace_size; ++i){
size_t p = 0; size_t p = 0;
while(messages[i][p] != '(' && messages[i][p] != ' ' && messages[i][p] != 0){ while (messages[i][p] != '(' && messages[i][p] != ' ' && messages[i][p] != 0){++p;}
++p; DEBUG_MSG(0, "Backtrace[%d]: %s", i, messages[i] + p);
}
DEBUG_MSG(0, "Backtrace[%d]: %s", i, messages[i]+p);
} }
} }
#endif #endif
@ -94,12 +110,12 @@ static inline void show_stackframe(){}
#endif #endif
#ifndef SHM_DATASIZE #ifndef SHM_DATASIZE
#define SHM_DATASIZE 20 #define SHM_DATASIZE 20
#endif #endif
#define AUDIO_KEY_INTERVAL 2000 ///< This define controls the keyframe interval for non-video tracks, such as audio and metadata tracks. #define AUDIO_KEY_INTERVAL \
2000 ///< This define controls the keyframe interval for non-video tracks, such as audio and metadata tracks.
#ifndef STATS_DELAY #ifndef STATS_DELAY
#define STATS_DELAY 15 #define STATS_DELAY 15
@ -107,7 +123,7 @@ static inline void show_stackframe(){}
#define STATS_INPUT_DELAY 2 #define STATS_INPUT_DELAY 2
#ifndef INPUT_TIMEOUT #ifndef INPUT_TIMEOUT
#define INPUT_TIMEOUT STATS_DELAY*2 #define INPUT_TIMEOUT STATS_DELAY * 2
#endif #endif
/// The size used for stream headers for live streams /// The size used for stream headers for live streams
@ -130,9 +146,9 @@ static inline void show_stackframe(){}
/// Interval where the input refreshes the user data for stats etc. /// Interval where the input refreshes the user data for stats etc.
#define INPUT_USER_INTERVAL 1000 #define INPUT_USER_INTERVAL 1000
#define SHM_STREAM_INDEX "MstSTRM%s" //%s stream name #define SHM_STREAM_INDEX "MstSTRM%s" //%s stream name
#define SHM_STREAM_STATE "MstSTATE%s" //%s stream name #define SHM_STREAM_STATE "MstSTATE%s" //%s stream name
#define SHM_STREAM_CONF "MstSCnf%s" //%s stream name #define SHM_STREAM_CONF "MstSCnf%s" //%s stream name
#define SHM_GLOBAL_CONF "MstGlobalConfig" #define SHM_GLOBAL_CONF "MstGlobalConfig"
#define STRMSTAT_OFF 0 #define STRMSTAT_OFF 0
#define STRMSTAT_INIT 1 #define STRMSTAT_INIT 1
@ -141,15 +157,15 @@ static inline void show_stackframe(){}
#define STRMSTAT_READY 4 #define STRMSTAT_READY 4
#define STRMSTAT_SHUTDOWN 5 #define STRMSTAT_SHUTDOWN 5
#define STRMSTAT_INVALID 255 #define STRMSTAT_INVALID 255
#define SHM_TRACK_META "MstTRAK%s@%lu" //%s stream name, %lu track ID #define SHM_TRACK_META "MstTRAK%s@%lu" //%s stream name, %lu track ID
#define SHM_TRACK_INDEX "MstTRID%s@%lu" //%s stream name, %lu track ID #define SHM_TRACK_INDEX "MstTRID%s@%lu" //%s stream name, %lu track ID
#define SHM_TRACK_INDEX_SIZE 8192 #define SHM_TRACK_INDEX_SIZE 8192
#define SHM_TRACK_DATA "MstDATA%s@%lu_%lu" //%s stream name, %lu track ID, %lu page # #define SHM_TRACK_DATA "MstDATA%s@%lu_%lu" //%s stream name, %lu track ID, %lu page #
#define SHM_STATISTICS "MstSTAT" #define SHM_STATISTICS "MstSTAT"
#define SHM_USERS "MstUSER%s" //%s stream name #define SHM_USERS "MstUSER%s" //%s stream name
#define SHM_TRIGGER "MstTRGR%s" //%s trigger name #define SHM_TRIGGER "MstTRGR%s" //%s trigger name
#define SEM_LIVE "/MstLIVE%s" //%s stream name #define SEM_LIVE "/MstLIVE%s" //%s stream name
#define SEM_INPUT "/MstInpt%s" //%s stream name #define SEM_INPUT "/MstInpt%s" //%s stream name
#define SEM_SESSCACHE "/MstSessCacheLock" #define SEM_SESSCACHE "/MstSessCacheLock"
#define SHM_CAPA "MstCapa" #define SHM_CAPA "MstCapa"
#define SHM_PROTO "MstProt" #define SHM_PROTO "MstProt"
@ -157,16 +173,15 @@ static inline void show_stackframe(){}
#define SHM_STATE_LOGS "MstStateLogs" #define SHM_STATE_LOGS "MstStateLogs"
#define SHM_STATE_ACCS "MstStateAccs" #define SHM_STATE_ACCS "MstStateAccs"
#define SHM_STATE_STREAMS "MstStateStreams" #define SHM_STATE_STREAMS "MstStateStreams"
#define NAME_BUFFER_SIZE 200 //char buffer size for snprintf'ing shm filenames #define NAME_BUFFER_SIZE 200 // char buffer size for snprintf'ing shm filenames
#define SHM_SESSIONS "/MstSess" #define SHM_SESSIONS "/MstSess"
#define SHM_SESSIONS_ITEM 165 //4 byte crc, 100b streamname, 20b connector, 40b host, 1b sync #define SHM_SESSIONS_ITEM 165 // 4 byte crc, 100b streamname, 20b connector, 40b host, 1b sync
#define SHM_SESSIONS_SIZE 5248000 //5MiB = almost 32k sessions #define SHM_SESSIONS_SIZE 5248000 // 5MiB = almost 32k sessions
#define SHM_STREAM_ENCRYPT "MstCRYP%s" //%s stream name #define SHM_STREAM_ENCRYPT "MstCRYP%s" //%s stream name
#define SIMUL_TRACKS 20 #define SIMUL_TRACKS 20
#ifndef UDP_API_HOST #ifndef UDP_API_HOST
#define UDP_API_HOST "localhost" #define UDP_API_HOST "localhost"
#endif #endif
@ -177,7 +192,6 @@ static inline void show_stackframe(){}
#define INVALID_TRACK_ID 0 #define INVALID_TRACK_ID 0
//The amount of milliseconds a simulated live stream is allowed to be "behind". // The amount of milliseconds a simulated live stream is allowed to be "behind".
//Setting this value to lower than 2 seconds **WILL** cause stuttering in playback due to buffer negotiation. // Setting this value to lower than 2 seconds **WILL** cause stuttering in playback due to buffer negotiation.
#define SIMULATED_LIVE_BUFFER 7000 #define SIMULATED_LIVE_BUFFER 7000

View file

@ -1,5 +1,5 @@
#include "downloader.h"
#include "defines.h" #include "defines.h"
#include "downloader.h"
#include "encode.h" #include "encode.h"
#include "timing.h" #include "timing.h"
@ -136,7 +136,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 void * body, const size_t bodyLen){ void Downloader::doRequest(const HTTP::URL &link, const std::string &method, const void *body,
const size_t bodyLen){
prepareRequest(link, method); prepareRequest(link, method);
H.sendRequest(getSocket(), body, bodyLen, false); H.sendRequest(getSocket(), body, bodyLen, false);
H.Clean(); H.Clean();
@ -147,7 +148,6 @@ namespace HTTP{
doRequest(link, method, body.data(), body.size()); doRequest(link, method, body.data(), body.size());
} }
/// Do a HEAD request to download the HTTP headers only, returns true on success /// Do a HEAD request to download the HTTP headers only, returns true on success
bool Downloader::head(const HTTP::URL &link, uint8_t maxRecursiveDepth){ bool Downloader::head(const HTTP::URL &link, uint8_t maxRecursiveDepth){
if (!canRequest(link)){return false;} if (!canRequest(link)){return false;}
@ -190,9 +190,7 @@ namespace HTTP{
} }
} }
if(H.protocol == "HTTP/1.0"){ if (H.protocol == "HTTP/1.0"){getSocket().close();}
getSocket().close();
}
H.headerOnly = false; H.headerOnly = false;
return true; // Success! return true; // Success!
@ -218,9 +216,11 @@ namespace HTTP{
getSocket().close(); getSocket().close();
}else{ }else{
if (retryCount - loop + 1 > 2){ if (retryCount - loop + 1 > 2){
INFO_MSG("Lost connection while retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(), retryCount - loop + 1, retryCount); INFO_MSG("Lost connection while retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(),
retryCount - loop + 1, retryCount);
}else{ }else{
MEDIUM_MSG("Lost connection while retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(), retryCount - loop + 1, retryCount); MEDIUM_MSG("Lost connection while retrieving %s (%zu/%" PRIu32 ")", link.getUrl().c_str(),
retryCount - loop + 1, retryCount);
} }
H.Clean(); H.Clean();
} }
@ -230,7 +230,8 @@ namespace HTTP{
return false; return false;
} }
bool Downloader::getRangeNonBlocking(const HTTP::URL &link, size_t byteStart, size_t byteEnd, Util::DataCallback &cb){ bool Downloader::getRangeNonBlocking(const HTTP::URL &link, size_t byteStart, size_t byteEnd,
Util::DataCallback &cb){
char tmp[32]; char tmp[32];
if (byteEnd <= 0){// get range from byteStart til eof if (byteEnd <= 0){// get range from byteStart til eof
sprintf(tmp, "bytes=%zu-", byteStart); sprintf(tmp, "bytes=%zu-", byteStart);
@ -277,9 +278,7 @@ namespace HTTP{
return true; return true;
} }
const HTTP::URL & Downloader::lastURL(){ const HTTP::URL &Downloader::lastURL(){return nbLink;}
return nbLink;
}
// continue handling a request, originally set up by the getNonBlocking() function // continue handling a request, originally set up by the getNonBlocking() function
// returns true if the request is complete // returns true if the request is complete
@ -368,14 +367,15 @@ namespace HTTP{
} }
} }
WARN_MSG("Invalid connection state for HTTP request"); WARN_MSG("Invalid connection state for HTTP request");
return false; //we should never get here return false; // we should never get here
} }
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){
return post(link, payload.data(), payload.size(), sync, maxRecursiveDepth); return post(link, payload.data(), payload.size(), sync, maxRecursiveDepth);
} }
bool Downloader::post(const HTTP::URL &link, const void * payload, const size_t payloadLen, bool sync, uint8_t maxRecursiveDepth){ bool Downloader::post(const HTTP::URL &link, const void *payload, const size_t payloadLen,
bool sync, uint8_t maxRecursiveDepth){
if (!canRequest(link)){return false;} if (!canRequest(link)){return false;}
size_t 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
@ -499,4 +499,3 @@ namespace HTTP{
} }
}// namespace HTTP }// namespace HTTP

View file

@ -1,6 +1,6 @@
#include "http_parser.h" #include "http_parser.h"
#include "url.h"
#include "socket.h" #include "socket.h"
#include "url.h"
#include "util.h" #include "util.h"
namespace HTTP{ namespace HTTP{
@ -11,7 +11,8 @@ namespace HTTP{
std::string &data(); std::string &data();
const std::string &const_data() const; const std::string &const_data() const;
void prepareRequest(const HTTP::URL &link, const std::string &method = ""); void prepareRequest(const HTTP::URL &link, const std::string &method = "");
void doRequest(const HTTP::URL &link, const std::string &method = "", const void * body = 0, const size_t bodyLen = 0); void doRequest(const HTTP::URL &link, const std::string &method = "", const void *body = 0,
const size_t bodyLen = 0);
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, Util::DataCallback &cb = Util::defaultDataCallback); bool get(const std::string &link, Util::DataCallback &cb = Util::defaultDataCallback);
bool get(const HTTP::URL &link, uint8_t maxRecursiveDepth = 6, Util::DataCallback &cb = Util::defaultDataCallback); bool get(const HTTP::URL &link, uint8_t maxRecursiveDepth = 6, Util::DataCallback &cb = Util::defaultDataCallback);
@ -20,7 +21,8 @@ namespace HTTP{
Util::DataCallback &cb = Util::defaultDataCallback); Util::DataCallback &cb = Util::defaultDataCallback);
bool getRangeNonBlocking(const HTTP::URL &link, size_t byteStart, size_t byteEnd, bool getRangeNonBlocking(const HTTP::URL &link, size_t byteStart, size_t byteEnd,
Util::DataCallback &cb = Util::defaultDataCallback); Util::DataCallback &cb = Util::defaultDataCallback);
bool post(const HTTP::URL &link, const void * payload, const size_t payloadLen, bool sync = true, uint8_t maxRecursiveDepth = 6); bool post(const HTTP::URL &link, const void *payload, const size_t payloadLen, bool sync = true,
uint8_t maxRecursiveDepth = 6);
bool post(const HTTP::URL &link, const std::string &payload, bool sync = true, bool post(const HTTP::URL &link, const std::string &payload, bool sync = true,
uint8_t maxRecursiveDepth = 6); uint8_t maxRecursiveDepth = 6);
@ -45,7 +47,7 @@ namespace HTTP{
const Socket::Connection &getSocket() const; const Socket::Connection &getSocket() const;
uint32_t retryCount, dataTimeout; uint32_t retryCount, dataTimeout;
bool isProxied() const; bool isProxied() const;
const HTTP::URL & lastURL(); const HTTP::URL &lastURL();
private: private:
bool isComplete; bool isComplete;
@ -54,7 +56,7 @@ namespace HTTP{
uint32_t connectedPort; ///< Currently connected port number uint32_t connectedPort; ///< Currently connected port number
Parser H; ///< HTTP parser for downloader Parser H; ///< HTTP parser for downloader
Socket::Connection S; ///< TCP socket for downloader Socket::Connection S; ///< TCP socket for downloader
bool ssl; ///< True if ssl is currently in use. bool ssl; ///< True if ssl is currently in use.
std::string authStr; ///< Most recently seen WWW-Authenticate request std::string authStr; ///< Most recently seen WWW-Authenticate request
std::string proxyAuthStr; ///< Most recently seen Proxy-Authenticate request std::string proxyAuthStr; ///< Most recently seen Proxy-Authenticate request
bool proxied; ///< True if proxy server is configured. bool proxied; ///< True if proxy server is configured.
@ -65,8 +67,4 @@ namespace HTTP{
uint64_t nbReqTime; uint64_t nbReqTime;
}; };
}// namespace HTTP }// namespace HTTP

View file

@ -1,61 +1,54 @@
#include <algorithm>
#include "defines.h" #include "defines.h"
#include "dtls_srtp_handshake.h" #include "dtls_srtp_handshake.h"
#include <algorithm>
/* Write mbedtls into a log file. */ /* Write mbedtls into a log file. */
#define LOG_TO_FILE 0 #define LOG_TO_FILE 0
#if LOG_TO_FILE #if LOG_TO_FILE
# include <fstream> #include <fstream>
#endif #endif
/* ----------------------------------------- */ /* ----------------------------------------- */
static void print_mbedtls_error(int r); static void print_mbedtls_error(int r);
static void print_mbedtls_debug_message(void *ctx, int level, const char *file, int line, const char *str); static void print_mbedtls_debug_message(void *ctx, int level, const char *file, int line, const char *str);
static int on_mbedtls_wants_to_read(void* user, unsigned char* buf, size_t len); /* Called when mbedtls wants to read data from e.g. a socket. */ static int on_mbedtls_wants_to_read(void *user, unsigned char *buf,
static int on_mbedtls_wants_to_write(void* user, const unsigned char* buf, size_t len); /* Called when mbedtls wants to write data to e.g. a socket. */ size_t len); /* Called when mbedtls wants to read data from e.g. a socket. */
static int on_mbedtls_wants_to_write(void *user, const unsigned char *buf,
size_t len); /* Called when mbedtls wants to write data to e.g. a socket. */
static std::string mbedtls_err_to_string(int r); static std::string mbedtls_err_to_string(int r);
/* ----------------------------------------- */ /* ----------------------------------------- */
DTLSSRTPHandshake::DTLSSRTPHandshake() DTLSSRTPHandshake::DTLSSRTPHandshake() : write_callback(NULL), cert(NULL), key(NULL){
:write_callback(NULL) memset((void *)&entropy_ctx, 0x00, sizeof(entropy_ctx));
,cert(NULL) memset((void *)&rand_ctx, 0x00, sizeof(rand_ctx));
,key(NULL) memset((void *)&ssl_ctx, 0x00, sizeof(ssl_ctx));
{ memset((void *)&ssl_conf, 0x00, sizeof(ssl_conf));
memset((void*)&entropy_ctx, 0x00, sizeof(entropy_ctx)); memset((void *)&cookie_ctx, 0x00, sizeof(cookie_ctx));
memset((void*)&rand_ctx, 0x00, sizeof(rand_ctx)); memset((void *)&timer_ctx, 0x00, sizeof(timer_ctx));
memset((void*)&ssl_ctx, 0x00, sizeof(ssl_ctx));
memset((void*)&ssl_conf, 0x00, sizeof(ssl_conf));
memset((void*)&cookie_ctx, 0x00, sizeof(cookie_ctx));
memset((void*)&timer_ctx, 0x00, sizeof(timer_ctx));
} }
int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate, int DTLSSRTPHandshake::init(mbedtls_x509_crt *certificate, mbedtls_pk_context *privateKey,
mbedtls_pk_context* privateKey, int (*writeCallback)(const uint8_t *data, int *nbytes)){
int(*writeCallback)(const uint8_t* data, int* nbytes)
)
{
int r = 0; int r = 0;
mbedtls_ssl_srtp_profile srtp_profiles[] = { mbedtls_ssl_srtp_profile srtp_profiles[] ={MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80,
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80, MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32};
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32
};
if (!writeCallback) { if (!writeCallback){
FAIL_MSG("No writeCallack function given."); FAIL_MSG("No writeCallack function given.");
r = -3; r = -3;
goto error; goto error;
} }
if (!certificate) { if (!certificate){
FAIL_MSG("Given certificate is null."); FAIL_MSG("Given certificate is null.");
r = -5; r = -5;
goto error; goto error;
} }
if (!privateKey) { if (!privateKey){
FAIL_MSG("Given key is null."); FAIL_MSG("Given key is null.");
r = -10; r = -10;
goto error; goto error;
@ -72,16 +65,18 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
mbedtls_ssl_cookie_init(&cookie_ctx); mbedtls_ssl_cookie_init(&cookie_ctx);
/* seed and setup the random number generator */ /* seed and setup the random number generator */
r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx, (const unsigned char*)"mist-srtp", 9); r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx,
if (0 != r) { (const unsigned char *)"mist-srtp", 9);
if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -20; r = -20;
goto error; goto error;
} }
/* load defaults into our ssl_conf */ /* load defaults into our ssl_conf */
r = mbedtls_ssl_config_defaults(&ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); r = mbedtls_ssl_config_defaults(&ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM,
if (0 != r) { MBEDTLS_SSL_PRESET_DEFAULT);
if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -30; r = -30;
goto error; goto error;
@ -95,8 +90,9 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
mbedtls_debug_set_threshold(10); mbedtls_debug_set_threshold(10);
/* enable SRTP */ /* enable SRTP */
r = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles, sizeof(srtp_profiles) / sizeof(srtp_profiles[0])); r = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles,
if (0 != r) { sizeof(srtp_profiles) / sizeof(srtp_profiles[0]));
if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -40; r = -40;
goto error; goto error;
@ -104,7 +100,7 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
/* cert certificate chain + key, so we can verify the client-hello signed data */ /* cert certificate chain + key, so we can verify the client-hello signed data */
r = mbedtls_ssl_conf_own_cert(&ssl_conf, cert, key); r = mbedtls_ssl_conf_own_cert(&ssl_conf, cert, key);
if (0 != r) { if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -50; r = -50;
goto error; goto error;
@ -112,7 +108,7 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
/* cookie setup (e.g. to prevent ddos). */ /* cookie setup (e.g. to prevent ddos). */
r = mbedtls_ssl_cookie_setup(&cookie_ctx, mbedtls_ctr_drbg_random, &rand_ctx); r = mbedtls_ssl_cookie_setup(&cookie_ctx, mbedtls_ctr_drbg_random, &rand_ctx);
if (0 != r) { if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -60; r = -60;
goto error; goto error;
@ -123,20 +119,21 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
/* setup the ssl context for use. note that ssl_conf will be referenced internall by the context and therefore should be kept around. */ /* setup the ssl context for use. note that ssl_conf will be referenced internall by the context and therefore should be kept around. */
r = mbedtls_ssl_setup(&ssl_ctx, &ssl_conf); r = mbedtls_ssl_setup(&ssl_ctx, &ssl_conf);
if (0 != r) { if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -70; r = -70;
goto error; goto error;
} }
/* set bio handlers */ /* set bio handlers */
mbedtls_ssl_set_bio(&ssl_ctx, (void*)this, on_mbedtls_wants_to_write, on_mbedtls_wants_to_read, NULL); mbedtls_ssl_set_bio(&ssl_ctx, (void *)this, on_mbedtls_wants_to_write, on_mbedtls_wants_to_read, NULL);
/* set temp id, just adds some exta randomness */ /* set temp id, just adds some exta randomness */
{ {
std::string remote_id = "mist"; std::string remote_id = "mist";
r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char*)remote_id.c_str(), remote_id.size()); r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char *)remote_id.c_str(),
if (0 != r) { remote_id.size());
if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
r = -80; r = -80;
goto error; goto error;
@ -148,16 +145,14 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
write_callback = writeCallback; write_callback = writeCallback;
error: error:
if (r < 0) { if (r < 0){shutdown();}
shutdown();
}
return r; return r;
} }
int DTLSSRTPHandshake::shutdown() { int DTLSSRTPHandshake::shutdown(){
/* cleanup the refs from the settings. */ /* cleanup the refs from the settings. */
cert = NULL; cert = NULL;
@ -181,19 +176,19 @@ int DTLSSRTPHandshake::shutdown() {
/* ----------------------------------------- */ /* ----------------------------------------- */
int DTLSSRTPHandshake::parse(const uint8_t* data, size_t nbytes) { int DTLSSRTPHandshake::parse(const uint8_t *data, size_t nbytes){
if (NULL == data) { if (NULL == data){
ERROR_MSG("Given `data` is NULL."); ERROR_MSG("Given `data` is NULL.");
return -1; return -1;
} }
if (0 == nbytes) { if (0 == nbytes){
ERROR_MSG("Given nbytes is 0."); ERROR_MSG("Given nbytes is 0.");
return -2; return -2;
} }
if (MBEDTLS_SSL_HANDSHAKE_OVER == ssl_ctx.state) { if (MBEDTLS_SSL_HANDSHAKE_OVER == ssl_ctx.state){
ERROR_MSG("Already finished the handshake."); ERROR_MSG("Already finished the handshake.");
return -3; return -3;
} }
@ -202,58 +197,60 @@ int DTLSSRTPHandshake::parse(const uint8_t* data, size_t nbytes) {
int r = 0; int r = 0;
std::copy(data, data + nbytes, std::back_inserter(buffer)); std::copy(data, data + nbytes, std::back_inserter(buffer));
do { do{
r = mbedtls_ssl_handshake(&ssl_ctx); r = mbedtls_ssl_handshake(&ssl_ctx);
switch (r) { switch (r){
/* 0 = handshake done. */ /* 0 = handshake done. */
case 0: { case 0:{
if (0 != extractKeyingMaterial()) { if (0 != extractKeyingMaterial()){
ERROR_MSG("Failed to extract keying material after handshake was done."); ERROR_MSG("Failed to extract keying material after handshake was done.");
return -2;
}
return 0;
}
/* see the dtls server example; this is used to prevent certain attacks (ddos) */
case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: {
if (0 != resetSession()) {
ERROR_MSG("Failed to reset the session which is necessary when we need to verify the HELLO.");
return -3;
}
break;
}
case MBEDTLS_ERR_SSL_WANT_READ: {
DONTEVEN_MSG("mbedtls wants a bit more data before it can continue parsing the DTLS handshake.");
break;
}
default: {
ERROR_MSG("A serious mbedtls error occured.");
print_mbedtls_error(r);
return -2; return -2;
} }
return 0;
} }
} /* see the dtls server example; this is used to prevent certain attacks (ddos) */
while (MBEDTLS_ERR_SSL_WANT_WRITE == r); case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED:{
if (0 != resetSession()){
ERROR_MSG(
"Failed to reset the session which is necessary when we need to verify the HELLO.");
return -3;
}
break;
}
case MBEDTLS_ERR_SSL_WANT_READ:{
DONTEVEN_MSG(
"mbedtls wants a bit more data before it can continue parsing the DTLS handshake.");
break;
}
default:{
ERROR_MSG("A serious mbedtls error occured.");
print_mbedtls_error(r);
return -2;
}
}
}while (MBEDTLS_ERR_SSL_WANT_WRITE == r);
return 0; return 0;
} }
/* ----------------------------------------- */ /* ----------------------------------------- */
int DTLSSRTPHandshake::resetSession() { int DTLSSRTPHandshake::resetSession(){
std::string remote_id = "mist"; /* @todo for now we hardcoded this... */ std::string remote_id = "mist"; /* @todo for now we hardcoded this... */
int r = 0; int r = 0;
r = mbedtls_ssl_session_reset(&ssl_ctx); r = mbedtls_ssl_session_reset(&ssl_ctx);
if (0 != r) { if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
return -1; return -1;
} }
r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char*)remote_id.c_str(), remote_id.size()); r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char *)remote_id.c_str(),
if (0 != r) { remote_id.size());
if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
return -2; return -2;
} }
@ -267,39 +264,39 @@ int DTLSSRTPHandshake::resetSession() {
master key is 128 bits => 16 bytes. master key is 128 bits => 16 bytes.
master salt is 112 bits => 14 bytes master salt is 112 bits => 14 bytes
*/ */
int DTLSSRTPHandshake::extractKeyingMaterial() { int DTLSSRTPHandshake::extractKeyingMaterial(){
int r = 0; int r = 0;
uint8_t keying_material[MBEDTLS_DTLS_SRTP_MAX_KEY_MATERIAL_LENGTH] = {}; uint8_t keying_material[MBEDTLS_DTLS_SRTP_MAX_KEY_MATERIAL_LENGTH] ={};
size_t keying_material_len = sizeof(keying_material); size_t keying_material_len = sizeof(keying_material);
r = mbedtls_ssl_get_dtls_srtp_key_material(&ssl_ctx, keying_material, &keying_material_len); r = mbedtls_ssl_get_dtls_srtp_key_material(&ssl_ctx, keying_material, &keying_material_len);
if (0 != r) { if (0 != r){
print_mbedtls_error(r); print_mbedtls_error(r);
return -1; return -1;
} }
/* @todo following code is for server mode only */ /* @todo following code is for server mode only */
mbedtls_ssl_srtp_profile srtp_profile = mbedtls_ssl_get_dtls_srtp_protection_profile(&ssl_ctx); mbedtls_ssl_srtp_profile srtp_profile = mbedtls_ssl_get_dtls_srtp_protection_profile(&ssl_ctx);
switch (srtp_profile) { switch (srtp_profile){
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80: { case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80:{
cipher = "SRTP_AES128_CM_SHA1_80"; cipher = "SRTP_AES128_CM_SHA1_80";
break; break;
} }
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32: { case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32:{
cipher = "SRTP_AES128_CM_SHA1_32"; cipher = "SRTP_AES128_CM_SHA1_32";
break; break;
} }
default: { default:{
ERROR_MSG("Unhandled SRTP profile, cannot extract keying material."); ERROR_MSG("Unhandled SRTP profile, cannot extract keying material.");
return -6; return -6;
} }
} }
remote_key.assign((char*)(&keying_material[0]) + 0, 16); remote_key.assign((char *)(&keying_material[0]) + 0, 16);
local_key.assign((char*)(&keying_material[0]) + 16, 16); local_key.assign((char *)(&keying_material[0]) + 16, 16);
remote_salt.assign((char*)(&keying_material[0]) + 32, 14); remote_salt.assign((char *)(&keying_material[0]) + 32, 14);
local_salt.assign((char*)(&keying_material[0]) + 46, 14); local_salt.assign((char *)(&keying_material[0]) + 46, 14);
DONTEVEN_MSG("Extracted the DTLS SRTP keying material with cipher %s.", cipher.c_str()); DONTEVEN_MSG("Extracted the DTLS SRTP keying material with cipher %s.", cipher.c_str());
DONTEVEN_MSG("Remote DTLS SRTP key size is %zu.", remote_key.size()); DONTEVEN_MSG("Remote DTLS SRTP key size is %zu.", remote_key.size());
@ -327,23 +324,19 @@ int DTLSSRTPHandshake::extractKeyingMaterial() {
- when there is data in our temporary buffer, we read from that - when there is data in our temporary buffer, we read from that
*/ */
static int on_mbedtls_wants_to_read(void* user, unsigned char* buf, size_t len) { static int on_mbedtls_wants_to_read(void *user, unsigned char *buf, size_t len){
DTLSSRTPHandshake* hs = static_cast<DTLSSRTPHandshake*>(user); DTLSSRTPHandshake *hs = static_cast<DTLSSRTPHandshake *>(user);
if (NULL == hs) { if (NULL == hs){
ERROR_MSG("Failed to cast the user pointer into a DTLSSRTPHandshake."); ERROR_MSG("Failed to cast the user pointer into a DTLSSRTPHandshake.");
return -1; return -1;
} }
/* figure out how much we can read. */ /* figure out how much we can read. */
if (hs->buffer.size() == 0) { if (hs->buffer.size() == 0){return MBEDTLS_ERR_SSL_WANT_READ;}
return MBEDTLS_ERR_SSL_WANT_READ;
}
size_t nbytes = hs->buffer.size(); size_t nbytes = hs->buffer.size();
if (nbytes > len) { if (nbytes > len){nbytes = len;}
nbytes = len;
}
/* "read" into the given buffer. */ /* "read" into the given buffer. */
memcpy(buf, &hs->buffer[0], nbytes); memcpy(buf, &hs->buffer[0], nbytes);
@ -352,26 +345,26 @@ static int on_mbedtls_wants_to_read(void* user, unsigned char* buf, size_t len)
return (int)nbytes; return (int)nbytes;
} }
static int on_mbedtls_wants_to_write(void* user, const unsigned char* buf, size_t len) { static int on_mbedtls_wants_to_write(void *user, const unsigned char *buf, size_t len){
DTLSSRTPHandshake* hs = static_cast<DTLSSRTPHandshake*>(user); DTLSSRTPHandshake *hs = static_cast<DTLSSRTPHandshake *>(user);
if (!hs) { if (!hs){
FAIL_MSG("Failed to cast the user pointer into a DTLSSRTPHandshake."); FAIL_MSG("Failed to cast the user pointer into a DTLSSRTPHandshake.");
return -1; return -1;
} }
if (!hs->write_callback) { if (!hs->write_callback){
FAIL_MSG("The `write_callback` member is NULL."); FAIL_MSG("The `write_callback` member is NULL.");
return -2; return -2;
} }
int nwritten = (int)len; int nwritten = (int)len;
if (0 != hs->write_callback(buf, &nwritten)) { if (0 != hs->write_callback(buf, &nwritten)){
FAIL_MSG("Failed to write some DTLS handshake data."); FAIL_MSG("Failed to write some DTLS handshake data.");
return -3; return -3;
} }
if (nwritten != (int)len) { if (nwritten != (int)len){
FAIL_MSG("The DTLS-SRTP handshake listener MUST write all the data."); FAIL_MSG("The DTLS-SRTP handshake listener MUST write all the data.");
return -4; return -4;
} }
@ -381,40 +374,37 @@ static int on_mbedtls_wants_to_write(void* user, const unsigned char* buf, size_
/* ----------------------------------------- */ /* ----------------------------------------- */
static void print_mbedtls_error(int r) { static void print_mbedtls_error(int r){
char buf[1024] = {}; char buf[1024] ={};
mbedtls_strerror(r, buf, sizeof(buf)); mbedtls_strerror(r, buf, sizeof(buf));
ERROR_MSG("mbedtls error: %s", buf); ERROR_MSG("mbedtls error: %s", buf);
} }
static void print_mbedtls_debug_message(void *ctx, int level, const char *file, int line, const char *str) { static void print_mbedtls_debug_message(void *ctx, int level, const char *file, int line, const char *str){
DONTEVEN_MSG("%s:%04d: %.*s", file, line, strlen(str) - 1, str); DONTEVEN_MSG("%s:%04d: %.*s", file, line, strlen(str) - 1, str);
#if LOG_TO_FILE #if LOG_TO_FILE
static std::ofstream ofs; static std::ofstream ofs;
if (!ofs.is_open()) { if (!ofs.is_open()){ofs.open("mbedtls.log", std::ios::out);}
ofs.open("mbedtls.log", std::ios::out); if (!ofs.is_open()){return;}
}
if (!ofs.is_open()) {
return;
}
ofs << str; ofs << str;
ofs.flush(); ofs.flush();
#endif #endif
} }
static std::string mbedtls_err_to_string(int r) { static std::string mbedtls_err_to_string(int r){
switch (r) { switch (r){
case MBEDTLS_ERR_SSL_WANT_READ: { return "MBEDTLS_ERR_SSL_WANT_READ"; } case MBEDTLS_ERR_SSL_WANT_READ:{
case MBEDTLS_ERR_SSL_WANT_WRITE: { return "MBEDTLS_ERR_SSL_WANT_WRITE"; } return "MBEDTLS_ERR_SSL_WANT_READ";
default: { }
print_mbedtls_error(r); case MBEDTLS_ERR_SSL_WANT_WRITE:{
return "UNKNOWN"; return "MBEDTLS_ERR_SSL_WANT_WRITE";
} }
default:{
print_mbedtls_error(r);
return "UNKNOWN";
}
} }
} }
/* ---------------------------------------- */ /* ---------------------------------------- */

View file

@ -1,26 +1,27 @@
#pragma once #pragma once
#include <stdint.h>
#include <deque> #include <deque>
#include <mbedtls/config.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/certs.h> #include <mbedtls/certs.h>
#include <mbedtls/x509.h> #include <mbedtls/config.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/debug.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/ssl_cookie.h> #include <mbedtls/ssl_cookie.h>
#include <mbedtls/error.h>
#include <mbedtls/debug.h>
#include <mbedtls/timing.h> #include <mbedtls/timing.h>
#include <mbedtls/x509.h>
#include <stdint.h>
/* ----------------------------------------- */ /* ----------------------------------------- */
class DTLSSRTPHandshake { class DTLSSRTPHandshake{
public: public:
DTLSSRTPHandshake(); DTLSSRTPHandshake();
int init(mbedtls_x509_crt* certificate, mbedtls_pk_context* privateKey, int(*writeCallback)(const uint8_t* data, int* nbytes)); // writeCallback should return 0 on succes < 0 on error. nbytes holds the number of bytes to be sent and needs to be set to the number of bytes actually sent. int init(mbedtls_x509_crt *certificate,
mbedtls_pk_context *privateKey, int (*writeCallback)(const uint8_t *data, int *nbytes)); // writeCallback should return 0 on succes < 0 on error. nbytes holds the number of bytes to be sent and needs to be set to the number of bytes actually sent.
int shutdown(); int shutdown();
int parse(const uint8_t* data, size_t nbytes); int parse(const uint8_t *data, size_t nbytes);
bool hasKeyingMaterial(); bool hasKeyingMaterial();
private: private:
@ -28,8 +29,8 @@ private:
int resetSession(); int resetSession();
private: private:
mbedtls_x509_crt* cert; /* Certificate, we do not own the key. Make sure it's kept alive during the livetime of this class instance. */ mbedtls_x509_crt *cert; /* Certificate, we do not own the key. Make sure it's kept alive during the livetime of this class instance. */
mbedtls_pk_context* key; /* Private key, we do not own the key. Make sure it's kept alive during the livetime of this class instance. */ mbedtls_pk_context *key; /* Private key, we do not own the key. Make sure it's kept alive during the livetime of this class instance. */
mbedtls_entropy_context entropy_ctx; mbedtls_entropy_context entropy_ctx;
mbedtls_ctr_drbg_context rand_ctx; mbedtls_ctr_drbg_context rand_ctx;
mbedtls_ssl_context ssl_ctx; mbedtls_ssl_context ssl_ctx;
@ -38,9 +39,9 @@ private:
mbedtls_timing_delay_context timer_ctx; mbedtls_timing_delay_context timer_ctx;
public: public:
int (*write_callback)(const uint8_t* data, int* nbytes); int (*write_callback)(const uint8_t *data, int *nbytes);
std::deque<uint8_t> buffer; /* Accessed from BIO callbback. We copy the bytes you pass into `parse()` into this temporary buffer which is read by a trigger to `mbedlts_ssl_handshake()`. */ std::deque<uint8_t> buffer; /* Accessed from BIO callbback. We copy the bytes you pass into `parse()` into this temporary buffer which is read by a trigger to `mbedlts_ssl_handshake()`. */
std::string cipher; /* selected SRTP cipher. */ std::string cipher; /* selected SRTP cipher. */
std::string remote_key; std::string remote_key;
std::string remote_salt; std::string remote_salt;
std::string local_key; std::string local_key;
@ -49,11 +50,9 @@ public:
/* ----------------------------------------- */ /* ----------------------------------------- */
inline bool DTLSSRTPHandshake::hasKeyingMaterial() { inline bool DTLSSRTPHandshake::hasKeyingMaterial(){
return (0 != remote_key.size() return (0 != remote_key.size() && 0 != remote_salt.size() && 0 != local_key.size() &&
&& 0 != remote_salt.size() 0 != local_salt.size());
&& 0 != local_key.size()
&& 0 != local_salt.size());
} }
/* ----------------------------------------- */ /* ----------------------------------------- */

View file

@ -1,38 +1,36 @@
/// \file dtsc.cpp /// \file dtsc.cpp
/// Holds all code for DDVTECH Stream Container parsing/generation. /// Holds all code for DDVTECH Stream Container parsing/generation.
#include "dtsc.h"
#include "defines.h" #include "defines.h"
#include "dtsc.h"
#include <arpa/inet.h> //for htonl/ntohl
#include <stdlib.h> #include <stdlib.h>
#include <string.h> //for memcmp #include <string.h> //for memcmp
#include <arpa/inet.h> //for htonl/ntohl
char DTSC::Magic_Header[] = "DTSC"; char DTSC::Magic_Header[] = "DTSC";
char DTSC::Magic_Packet[] = "DTPD"; char DTSC::Magic_Packet[] = "DTPD";
char DTSC::Magic_Packet2[] = "DTP2"; char DTSC::Magic_Packet2[] = "DTP2";
char DTSC::Magic_Command[] = "DTCM"; char DTSC::Magic_Command[] = "DTCM";
DTSC::File::File() { DTSC::File::File(){
F = 0; F = 0;
buffer = malloc(4); buffer = malloc(4);
endPos = 0; endPos = 0;
} }
DTSC::File::File(const File & rhs) { DTSC::File::File(const File &rhs){
buffer = malloc(4); buffer = malloc(4);
*this = rhs; *this = rhs;
} }
DTSC::File & DTSC::File::operator =(const File & rhs) { DTSC::File &DTSC::File::operator=(const File &rhs){
created = rhs.created; created = rhs.created;
if (rhs.F) { if (rhs.F){
F = fdopen(dup(fileno(rhs.F)), (created ? "w+b" : "r+b")); F = fdopen(dup(fileno(rhs.F)), (created ? "w+b" : "r+b"));
} else { }else{
F = 0; F = 0;
} }
endPos = rhs.endPos; endPos = rhs.endPos;
if (rhs.myPack) { if (rhs.myPack){myPack = rhs.myPack;}
myPack = rhs.myPack;
}
metadata = rhs.metadata; metadata = rhs.metadata;
currtime = rhs.currtime; currtime = rhs.currtime;
lastreadpos = rhs.lastreadpos; lastreadpos = rhs.lastreadpos;
@ -42,31 +40,31 @@ DTSC::File & DTSC::File::operator =(const File & rhs) {
return *this; return *this;
} }
DTSC::File::operator bool() const { DTSC::File::operator bool() const{
return F; return F;
} }
/// Open a filename for DTSC reading/writing. /// Open a filename for DTSC reading/writing.
/// If create is true and file does not exist, attempt to create. /// If create is true and file does not exist, attempt to create.
DTSC::File::File(std::string filename, bool create) { DTSC::File::File(std::string filename, bool create){
buffer = malloc(8); buffer = malloc(8);
if (create) { if (create){
F = fopen(filename.c_str(), "w+b"); F = fopen(filename.c_str(), "w+b");
if (!F) { if (!F){
DEBUG_MSG(DLVL_ERROR, "Could not create file %s: %s", filename.c_str(), strerror(errno)); DEBUG_MSG(DLVL_ERROR, "Could not create file %s: %s", filename.c_str(), strerror(errno));
return; return;
} }
//write an empty header // write an empty header
fseek(F, 0, SEEK_SET); fseek(F, 0, SEEK_SET);
fwrite(DTSC::Magic_Header, 4, 1, F); fwrite(DTSC::Magic_Header, 4, 1, F);
memset(buffer, 0, 4); memset(buffer, 0, 4);
fwrite(buffer, 4, 1, F); //write 4 zero-bytes fwrite(buffer, 4, 1, F); // write 4 zero-bytes
headerSize = 0; headerSize = 0;
} else { }else{
F = fopen(filename.c_str(), "r+b"); F = fopen(filename.c_str(), "r+b");
} }
created = create; created = create;
if (!F) { if (!F){
HIGH_MSG("Could not open file %s", filename.c_str()); HIGH_MSG("Could not open file %s", filename.c_str());
return; return;
} }
@ -74,62 +72,59 @@ DTSC::File::File(std::string filename, bool create) {
endPos = ftell(F); endPos = ftell(F);
bool sepHeader = false; bool sepHeader = false;
if (!create) { if (!create){
fseek(F, 0, SEEK_SET); fseek(F, 0, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Can't read file contents of %s", filename.c_str()); DEBUG_MSG(DLVL_ERROR, "Can't read file contents of %s", filename.c_str());
fclose(F); fclose(F);
F = 0; F = 0;
return; return;
} }
if (memcmp(buffer, DTSC::Magic_Header, 4) != 0) { if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){
if (memcmp(buffer, DTSC::Magic_Packet2, 4) != 0 && memcmp(buffer, DTSC::Magic_Packet, 4) != 0 && memcmp(buffer, DTSC::Magic_Command, 4) != 0) { if (memcmp(buffer, DTSC::Magic_Packet2, 4) != 0 &&
memcmp(buffer, DTSC::Magic_Packet, 4) != 0 && memcmp(buffer, DTSC::Magic_Command, 4) != 0){
DEBUG_MSG(DLVL_ERROR, "%s is not a valid DTSC file", filename.c_str()); DEBUG_MSG(DLVL_ERROR, "%s is not a valid DTSC file", filename.c_str());
fclose(F); fclose(F);
F = 0; F = 0;
return; return;
} else { }else{
metadata.moreheader = -1; metadata.moreheader = -1;
} }
} }
} }
//we now know the first 4 bytes are DTSC::Magic_Header and we have a valid file // we now know the first 4 bytes are DTSC::Magic_Header and we have a valid file
fseek(F, 4, SEEK_SET); fseek(F, 4, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
fseek(F, 4, SEEK_SET); fseek(F, 4, SEEK_SET);
memset(buffer, 0, 4); memset(buffer, 0, 4);
fwrite(buffer, 4, 1, F); //write 4 zero-bytes fwrite(buffer, 4, 1, F); // write 4 zero-bytes
} else { }else{
headerSize = ntohl(((uint32_t *)buffer)[0]); headerSize = ntohl(((uint32_t *)buffer)[0]);
} }
if (metadata.moreheader != -1) { if (metadata.moreheader != -1){
if (!sepHeader) { if (!sepHeader){
readHeader(0); readHeader(0);
fseek(F, 8 + headerSize, SEEK_SET); fseek(F, 8 + headerSize, SEEK_SET);
} else { }else{
fseek(F, 0, SEEK_SET); fseek(F, 0, SEEK_SET);
} }
} else { }else{
fseek(F, 0, SEEK_SET); fseek(F, 0, SEEK_SET);
File Fhead(filename + ".dtsh"); File Fhead(filename + ".dtsh");
if (Fhead) { if (Fhead){metadata = Fhead.metadata;}
metadata = Fhead.metadata;
}
} }
currframe = 0; currframe = 0;
} }
/// Returns the header metadata for this file as JSON::Value. /// Returns the header metadata for this file as JSON::Value.
DTSC::Meta & DTSC::File::getMeta() { DTSC::Meta &DTSC::File::getMeta(){
return metadata; return metadata;
} }
/// (Re)writes the given string to the header area if the size is the same as the existing header. /// (Re)writes the given string to the header area if the size is the same as the existing header.
/// Forces a write if force is set to true. /// Forces a write if force is set to true.
bool DTSC::File::writeHeader(std::string & header, bool force) { bool DTSC::File::writeHeader(std::string &header, bool force){
if (headerSize != header.size() && !force) { if (headerSize != header.size() && !force){
DEBUG_MSG(DLVL_ERROR, "Could not overwrite header - not equal size"); DEBUG_MSG(DLVL_ERROR, "Could not overwrite header - not equal size");
return false; return false;
} }
@ -137,9 +132,7 @@ bool DTSC::File::writeHeader(std::string & header, bool force) {
int pSize = htonl(header.size()); int pSize = htonl(header.size());
fseek(F, 4, SEEK_SET); fseek(F, 4, SEEK_SET);
int tmpret = fwrite((void *)(&pSize), 4, 1, F); int tmpret = fwrite((void *)(&pSize), 4, 1, F);
if (tmpret != 1) { if (tmpret != 1){return false;}
return false;
}
fseek(F, 8, SEEK_SET); fseek(F, 8, SEEK_SET);
int ret = fwrite(header.c_str(), headerSize, 1, F); int ret = fwrite(header.c_str(), headerSize, 1, F);
fseek(F, 8 + headerSize, SEEK_SET); fseek(F, 8 + headerSize, SEEK_SET);
@ -148,47 +141,41 @@ bool DTSC::File::writeHeader(std::string & header, bool force) {
/// Adds the given string as a new header to the end of the file. /// Adds the given string as a new header to the end of the file.
/// \returns The positon the header was written at, or 0 on failure. /// \returns The positon the header was written at, or 0 on failure.
long long int DTSC::File::addHeader(std::string & header) { long long int DTSC::File::addHeader(std::string &header){
fseek(F, 0, SEEK_END); fseek(F, 0, SEEK_END);
long long int writePos = ftell(F); long long int writePos = ftell(F);
int hSize = htonl(header.size()); int hSize = htonl(header.size());
int ret = fwrite(DTSC::Magic_Header, 4, 1, F); //write header int ret = fwrite(DTSC::Magic_Header, 4, 1, F); // write header
if (ret != 1) { if (ret != 1){return 0;}
return 0; ret = fwrite((void *)(&hSize), 4, 1, F); // write size
} if (ret != 1){return 0;}
ret = fwrite((void *)(&hSize), 4, 1, F); //write size ret = fwrite(header.c_str(), header.size(), 1, F); // write contents
if (ret != 1) { if (ret != 1){return 0;}
return 0;
}
ret = fwrite(header.c_str(), header.size(), 1, F); //write contents
if (ret != 1) {
return 0;
}
fseek(F, 0, SEEK_END); fseek(F, 0, SEEK_END);
endPos = ftell(F); endPos = ftell(F);
return writePos; //return position written at return writePos; // return position written at
} }
/// Reads the header at the given file position. /// Reads the header at the given file position.
/// If the packet could not be read for any reason, the reason is printed. /// If the packet could not be read for any reason, the reason is printed.
/// Reading the header means the file position is moved to after the header. /// Reading the header means the file position is moved to after the header.
void DTSC::File::readHeader(int pos) { void DTSC::File::readHeader(int pos){
fseek(F, pos, SEEK_SET); fseek(F, pos, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
if (feof(F)) { if (feof(F)){
DEBUG_MSG(DLVL_DEVEL, "End of file reached while reading header @ %d", pos); DEBUG_MSG(DLVL_DEVEL, "End of file reached while reading header @ %d", pos);
} else { }else{
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", pos); DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", pos);
} }
metadata = Meta(); metadata = Meta();
return; return;
} }
if (memcmp(buffer, DTSC::Magic_Header, 4) != 0) { if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){
DEBUG_MSG(DLVL_ERROR, "Invalid header - %.4s != %.4s @ %i", (char *)buffer, DTSC::Magic_Header, pos); DEBUG_MSG(DLVL_ERROR, "Invalid header - %.4s != %.4s @ %i", (char *)buffer, DTSC::Magic_Header, pos);
metadata = Meta(); metadata = Meta();
return; return;
} }
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read header size @ %i", pos); DEBUG_MSG(DLVL_ERROR, "Could not read header size @ %i", pos);
metadata = Meta(); metadata = Meta();
return; return;
@ -196,96 +183,91 @@ void DTSC::File::readHeader(int pos) {
long packSize = ntohl(((unsigned long *)buffer)[0]) + 8; long packSize = ntohl(((unsigned long *)buffer)[0]) + 8;
std::string strBuffer; std::string strBuffer;
strBuffer.resize(packSize); strBuffer.resize(packSize);
if (packSize) { if (packSize){
fseek(F, pos, SEEK_SET); fseek(F, pos, SEEK_SET);
if (fread((void *)strBuffer.c_str(), packSize, 1, F) != 1) { if (fread((void *)strBuffer.c_str(), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read header packet @ %i", pos); DEBUG_MSG(DLVL_ERROR, "Could not read header packet @ %i", pos);
metadata = Meta(); metadata = Meta();
return; return;
} }
metadata = Meta(DTSC::Packet(strBuffer.data(), strBuffer.size(),true)); metadata = Meta(DTSC::Packet(strBuffer.data(), strBuffer.size(), true));
} }
//if there is another header, read it and replace metadata with that one. // if there is another header, read it and replace metadata with that one.
if (metadata.moreheader) { if (metadata.moreheader){
if (metadata.moreheader < getBytePosEOF()) { if (metadata.moreheader < getBytePosEOF()){
readHeader(metadata.moreheader); readHeader(metadata.moreheader);
return; return;
} }
} }
if (!metadata.live){ if (!metadata.live){metadata.vod = true;}
metadata.vod = true;
}
} }
long int DTSC::File::getBytePosEOF() { long int DTSC::File::getBytePosEOF(){
return endPos; return endPos;
} }
long int DTSC::File::getBytePos() { long int DTSC::File::getBytePos(){
return ftell(F); return ftell(F);
} }
bool DTSC::File::reachedEOF() { bool DTSC::File::reachedEOF(){
return feof(F); return feof(F);
} }
/// Reads the packet available at the current file position. /// Reads the packet available at the current file position.
/// If the packet could not be read for any reason, the reason is printed. /// If the packet could not be read for any reason, the reason is printed.
/// Reading the packet means the file position is increased to the next packet. /// Reading the packet means the file position is increased to the next packet.
void DTSC::File::seekNext() { void DTSC::File::seekNext(){
if (!currentPositions.size()) { if (!currentPositions.size()){
DEBUG_MSG(DLVL_WARN, "No seek positions set - returning empty packet."); DEBUG_MSG(DLVL_WARN, "No seek positions set - returning empty packet.");
myPack.null(); myPack.null();
return; return;
} }
seekPos thisPos = *currentPositions.begin(); seekPos thisPos = *currentPositions.begin();
fseek(F, thisPos.bytePos, SEEK_SET); fseek(F, thisPos.bytePos, SEEK_SET);
if (reachedEOF()) { if (reachedEOF()){
myPack.null(); myPack.null();
return; return;
} }
clearerr(F); clearerr(F);
currentPositions.erase(currentPositions.begin()); currentPositions.erase(currentPositions.begin());
lastreadpos = ftell(F); lastreadpos = ftell(F);
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
if (feof(F)) { if (feof(F)){
DEBUG_MSG(DLVL_DEVEL, "End of file reached while seeking @ %i", (int)lastreadpos); DEBUG_MSG(DLVL_DEVEL, "End of file reached while seeking @ %i", (int)lastreadpos);
} else { }else{
DEBUG_MSG(DLVL_ERROR, "Could not seek to next @ %i", (int)lastreadpos); DEBUG_MSG(DLVL_ERROR, "Could not seek to next @ %i", (int)lastreadpos);
} }
myPack.null(); myPack.null();
return; return;
} }
if (memcmp(buffer, DTSC::Magic_Header, 4) == 0) { if (memcmp(buffer, DTSC::Magic_Header, 4) == 0){
seek_time(myPack.getTime(), myPack.getTrackId(), true); seek_time(myPack.getTime(), myPack.getTrackId(), true);
return seekNext(); return seekNext();
} }
long long unsigned int version = 0; long long unsigned int version = 0;
if (memcmp(buffer, DTSC::Magic_Packet, 4) == 0) { if (memcmp(buffer, DTSC::Magic_Packet, 4) == 0){version = 1;}
version = 1; if (memcmp(buffer, DTSC::Magic_Packet2, 4) == 0){version = 2;}
} if (version == 0){
if (memcmp(buffer, DTSC::Magic_Packet2, 4) == 0) { DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d",
version = 2; (unsigned int)lastreadpos, (char *)buffer, DTSC::Magic_Packet2, (int)lastreadpos);
}
if (version == 0) {
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d", (unsigned int)lastreadpos, (char *)buffer, DTSC::Magic_Packet2, (int)lastreadpos);
myPack.null(); myPack.null();
return; return;
} }
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %d", (int)lastreadpos); DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %d", (int)lastreadpos);
myPack.null(); myPack.null();
return; return;
} }
long packSize = ntohl(((unsigned long *)buffer)[0]); long packSize = ntohl(((unsigned long *)buffer)[0]);
char * packBuffer = (char *)malloc(packSize + 8); char *packBuffer = (char *)malloc(packSize + 8);
if (version == 1) { if (version == 1){
memcpy(packBuffer, "DTPD", 4); memcpy(packBuffer, "DTPD", 4);
} else { }else{
memcpy(packBuffer, "DTP2", 4); memcpy(packBuffer, "DTP2", 4);
} }
memcpy(packBuffer + 4, buffer, 4); memcpy(packBuffer + 4, buffer, 4);
if (fread((void *)(packBuffer + 8), packSize, 1, F) != 1) { if (fread((void *)(packBuffer + 8), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos); DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos);
myPack.null(); myPack.null();
free(packBuffer); free(packBuffer);
@ -293,24 +275,24 @@ void DTSC::File::seekNext() {
} }
myPack.reInit(packBuffer, packSize + 8); myPack.reInit(packBuffer, packSize + 8);
free(packBuffer); free(packBuffer);
if (metadata.merged) { if (metadata.merged){
int tempLoc = getBytePos(); int tempLoc = getBytePos();
char newHeader[20]; char newHeader[20];
bool insert = false; bool insert = false;
seekPos tmpPos; seekPos tmpPos;
if (fread((void *)newHeader, 20, 1, F) == 1) { if (fread((void *)newHeader, 20, 1, F) == 1){
if (memcmp(newHeader, DTSC::Magic_Packet2, 4) == 0) { if (memcmp(newHeader, DTSC::Magic_Packet2, 4) == 0){
tmpPos.bytePos = tempLoc; tmpPos.bytePos = tempLoc;
tmpPos.trackID = ntohl(((int *)newHeader)[2]); tmpPos.trackID = ntohl(((int *)newHeader)[2]);
tmpPos.seekTime = 0; tmpPos.seekTime = 0;
if (selectedTracks.find(tmpPos.trackID) != selectedTracks.end()) { if (selectedTracks.find(tmpPos.trackID) != selectedTracks.end()){
tmpPos.seekTime = ((long long unsigned int)ntohl(((int *)newHeader)[3])) << 32; tmpPos.seekTime = ((long long unsigned int)ntohl(((int *)newHeader)[3])) << 32;
tmpPos.seekTime += ntohl(((int *)newHeader)[4]); tmpPos.seekTime += ntohl(((int *)newHeader)[4]);
insert = true; insert = true;
} else { }else{
long tid = myPack.getTrackId(); long tid = myPack.getTrackId();
for (unsigned int i = 0; i != metadata.tracks[tid].keys.size(); i++) { for (unsigned int i = 0; i != metadata.tracks[tid].keys.size(); i++){
if ((unsigned long long)metadata.tracks[tid].keys[i].getTime() > myPack.getTime()) { if ((unsigned long long)metadata.tracks[tid].keys[i].getTime() > myPack.getTime()){
tmpPos.seekTime = metadata.tracks[tid].keys[i].getTime(); tmpPos.seekTime = metadata.tracks[tid].keys[i].getTime();
tmpPos.bytePos = metadata.tracks[tid].keys[i].getBpos(); tmpPos.bytePos = metadata.tracks[tid].keys[i].getBpos();
tmpPos.trackID = tid; tmpPos.trackID = tid;
@ -319,9 +301,10 @@ void DTSC::File::seekNext() {
} }
} }
} }
if (currentPositions.size()) { if (currentPositions.size()){
for (std::set<seekPos>::iterator curPosIter = currentPositions.begin(); curPosIter != currentPositions.end(); curPosIter++) { for (std::set<seekPos>::iterator curPosIter = currentPositions.begin();
if ((*curPosIter).trackID == tmpPos.trackID && (*curPosIter).seekTime >= tmpPos.seekTime) { curPosIter != currentPositions.end(); curPosIter++){
if ((*curPosIter).trackID == tmpPos.trackID && (*curPosIter).seekTime >= tmpPos.seekTime){
insert = false; insert = false;
break; break;
} }
@ -330,11 +313,9 @@ void DTSC::File::seekNext() {
} }
} }
if (insert){ if (insert){
if (tmpPos.seekTime > 0xffffffffffffff00ll){ if (tmpPos.seekTime > 0xffffffffffffff00ll){tmpPos.seekTime = 0;}
tmpPos.seekTime = 0;
}
currentPositions.insert(tmpPos); currentPositions.insert(tmpPos);
} else { }else{
seek_time(myPack.getTime(), myPack.getTrackId(), true); seek_time(myPack.getTime(), myPack.getTrackId(), true);
} }
seek_bpos(tempLoc); seek_bpos(tempLoc);
@ -345,39 +326,38 @@ void DTSC::File::seekNext() {
} }
void DTSC::File::parseNext(){ void DTSC::File::parseNext(){
char header_buffer[4] = {0, 0, 0, 0}; char header_buffer[4] ={0, 0, 0, 0};
lastreadpos = ftell(F); lastreadpos = ftell(F);
if (fread(header_buffer, 4, 1, F) != 1) { if (fread(header_buffer, 4, 1, F) != 1){
if (feof(F)) { if (feof(F)){
DEBUG_MSG(DLVL_DEVEL, "End of file reached @ %d", (int)lastreadpos); DEBUG_MSG(DLVL_DEVEL, "End of file reached @ %d", (int)lastreadpos);
} else { }else{
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos); DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
} }
myPack.null(); myPack.null();
return; return;
} }
long long unsigned int version = 0; long long unsigned int version = 0;
if (memcmp(header_buffer, DTSC::Magic_Packet, 4) == 0 || memcmp(header_buffer, DTSC::Magic_Command, 4) == 0 || memcmp(header_buffer, DTSC::Magic_Header, 4) == 0) { if (memcmp(header_buffer, DTSC::Magic_Packet, 4) == 0 || memcmp(header_buffer, DTSC::Magic_Command, 4) == 0 ||
memcmp(header_buffer, DTSC::Magic_Header, 4) == 0){
version = 1; version = 1;
} }
if (memcmp(header_buffer, DTSC::Magic_Packet2, 4) == 0) { if (memcmp(header_buffer, DTSC::Magic_Packet2, 4) == 0){version = 2;}
version = 2; if (version == 0){
}
if (version == 0) {
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x: %.4s", (unsigned int)lastreadpos, (char *)buffer); DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x: %.4s", (unsigned int)lastreadpos, (char *)buffer);
myPack.null(); myPack.null();
return; return;
} }
if (fread(buffer, 4, 1, F) != 1) { if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %#x", (unsigned int)lastreadpos); DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %#x", (unsigned int)lastreadpos);
myPack.null(); myPack.null();
return; return;
} }
long packSize = ntohl(((unsigned long *)buffer)[0]); long packSize = ntohl(((unsigned long *)buffer)[0]);
char * packBuffer = (char *)malloc(packSize + 8); char *packBuffer = (char *)malloc(packSize + 8);
memcpy(packBuffer, header_buffer, 4); memcpy(packBuffer, header_buffer, 4);
memcpy(packBuffer + 4, buffer, 4); memcpy(packBuffer + 4, buffer, 4);
if (fread((void *)(packBuffer + 8), packSize, 1, F) != 1) { if (fread((void *)(packBuffer + 8), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos); DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos);
myPack.null(); myPack.null();
free(packBuffer); free(packBuffer);
@ -388,19 +368,19 @@ void DTSC::File::parseNext(){
} }
/// Returns the byte positon of the start of the last packet that was read. /// Returns the byte positon of the start of the last packet that was read.
long long int DTSC::File::getLastReadPos() { long long int DTSC::File::getLastReadPos(){
return lastreadpos; return lastreadpos;
} }
/// Returns the internal buffer of the last read packet in raw binary format. /// Returns the internal buffer of the last read packet in raw binary format.
DTSC::Packet & DTSC::File::getPacket() { DTSC::Packet &DTSC::File::getPacket(){
return myPack; return myPack;
} }
bool DTSC::File::seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek) { bool DTSC::File::seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek){
seekPos tmpPos; seekPos tmpPos;
tmpPos.trackID = trackNo; tmpPos.trackID = trackNo;
if (!forceSeek && myPack && ms >= myPack.getTime() && trackNo >= myPack.getTrackId()) { if (!forceSeek && myPack && ms >= myPack.getTime() && trackNo >= myPack.getTrackId()){
tmpPos.seekTime = myPack.getTime(); tmpPos.seekTime = myPack.getTime();
tmpPos.bytePos = getBytePos(); tmpPos.bytePos = getBytePos();
/* /*
@ -408,135 +388,124 @@ bool DTSC::File::seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek
tmpPos.bytePos += myPack.getDataLen(); tmpPos.bytePos += myPack.getDataLen();
} }
*/ */
} else { }else{
tmpPos.seekTime = 0; tmpPos.seekTime = 0;
tmpPos.bytePos = 0; tmpPos.bytePos = 0;
} }
if (reachedEOF()) { if (reachedEOF()){
clearerr(F); clearerr(F);
seek_bpos(0); seek_bpos(0);
tmpPos.bytePos = 0; tmpPos.bytePos = 0;
tmpPos.seekTime = 0; tmpPos.seekTime = 0;
} }
DTSC::Track & trackRef = metadata.tracks[trackNo]; DTSC::Track &trackRef = metadata.tracks[trackNo];
for (unsigned int i = 0; i < trackRef.keys.size(); i++) { for (unsigned int i = 0; i < trackRef.keys.size(); i++){
long keyTime = trackRef.keys[i].getTime(); long keyTime = trackRef.keys[i].getTime();
if (keyTime > ms) { if (keyTime > ms){break;}
break; if ((long long unsigned int)keyTime > tmpPos.seekTime){
}
if ((long long unsigned int)keyTime > tmpPos.seekTime) {
tmpPos.seekTime = keyTime; tmpPos.seekTime = keyTime;
tmpPos.bytePos = trackRef.keys[i].getBpos(); tmpPos.bytePos = trackRef.keys[i].getBpos();
} }
} }
bool foundPacket = false; bool foundPacket = false;
while (!foundPacket) { while (!foundPacket){
lastreadpos = ftell(F); lastreadpos = ftell(F);
if (reachedEOF()) { if (reachedEOF()){
DEBUG_MSG(DLVL_WARN, "Reached EOF during seek to %u in track %d - aborting @ %lld", ms, trackNo, lastreadpos); DEBUG_MSG(DLVL_WARN, "Reached EOF during seek to %u in track %d - aborting @ %lld", ms, trackNo, lastreadpos);
return false; return false;
} }
//Seek to first packet after ms. // Seek to first packet after ms.
seek_bpos(tmpPos.bytePos); seek_bpos(tmpPos.bytePos);
//read the header // read the header
char header[20]; char header[20];
if (fread((void *)header, 20, 1, F) != 1){ if (fread((void *)header, 20, 1, F) != 1){
DEBUG_MSG(DLVL_WARN, "Could not read header from file. Much sadface."); DEBUG_MSG(DLVL_WARN, "Could not read header from file. Much sadface.");
return false; return false;
} }
//check if packetID matches, if not, skip size + 8 bytes. // check if packetID matches, if not, skip size + 8 bytes.
int packSize = ntohl(((int *)header)[1]); int packSize = ntohl(((int *)header)[1]);
unsigned int packID = ntohl(((int *)header)[2]); unsigned int packID = ntohl(((int *)header)[2]);
if (memcmp(header, Magic_Packet2, 4) != 0 || packID != trackNo) { if (memcmp(header, Magic_Packet2, 4) != 0 || packID != trackNo){
if (memcmp(header, "DT", 2) != 0) { if (memcmp(header, "DT", 2) != 0){
DEBUG_MSG(DLVL_WARN, "Invalid header during seek to %u in track %d @ %lld - resetting bytePos from %lld to zero", ms, trackNo, lastreadpos, tmpPos.bytePos); DEBUG_MSG(DLVL_WARN, "Invalid header during seek to %u in track %d @ %lld - resetting bytePos from %lld to zero",
ms, trackNo, lastreadpos, tmpPos.bytePos);
tmpPos.bytePos = 0; tmpPos.bytePos = 0;
continue; continue;
} }
tmpPos.bytePos += 8 + packSize; tmpPos.bytePos += 8 + packSize;
continue; continue;
} }
//get timestamp of packet, if too large, break, if not, skip size bytes. // get timestamp of packet, if too large, break, if not, skip size bytes.
long long unsigned int myTime = ((long long unsigned int)ntohl(((int *)header)[3]) << 32); long long unsigned int myTime = ((long long unsigned int)ntohl(((int *)header)[3]) << 32);
myTime += ntohl(((int *)header)[4]); myTime += ntohl(((int *)header)[4]);
tmpPos.seekTime = myTime; tmpPos.seekTime = myTime;
if (myTime >= ms) { if (myTime >= ms){
foundPacket = true; foundPacket = true;
} else { }else{
tmpPos.bytePos += 8 + packSize; tmpPos.bytePos += 8 + packSize;
continue; continue;
} }
} }
//DEBUG_MSG(DLVL_HIGH, "Seek to %u:%d resulted in %lli", trackNo, ms, tmpPos.seekTime); // DEBUG_MSG(DLVL_HIGH, "Seek to %u:%d resulted in %lli", trackNo, ms, tmpPos.seekTime);
if (tmpPos.seekTime > 0xffffffffffffff00ll){ if (tmpPos.seekTime > 0xffffffffffffff00ll){tmpPos.seekTime = 0;}
tmpPos.seekTime = 0;
}
currentPositions.insert(tmpPos); currentPositions.insert(tmpPos);
return true; return true;
} }
/// Attempts to seek to the given time in ms within the file. /// Attempts to seek to the given time in ms within the file.
/// Returns true if successful, false otherwise. /// Returns true if successful, false otherwise.
bool DTSC::File::seek_time(unsigned int ms) { bool DTSC::File::seek_time(unsigned int ms){
currentPositions.clear(); currentPositions.clear();
if (selectedTracks.size()) { if (selectedTracks.size()){
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) { for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
seek_time(ms, (*it), true); seek_time(ms, (*it), true);
} }
} }
return true; return true;
} }
bool DTSC::File::seek_bpos(int bpos) { bool DTSC::File::seek_bpos(int bpos){
if (fseek(F, bpos, SEEK_SET) == 0) { if (fseek(F, bpos, SEEK_SET) == 0){return true;}
return true;
}
return false; return false;
} }
void DTSC::File::rewritePacket(std::string & newPacket, int bytePos) { void DTSC::File::rewritePacket(std::string &newPacket, int bytePos){
fseek(F, bytePos, SEEK_SET); fseek(F, bytePos, SEEK_SET);
fwrite(newPacket.c_str(), newPacket.size(), 1, F); fwrite(newPacket.c_str(), newPacket.size(), 1, F);
fseek(F, 0, SEEK_END); fseek(F, 0, SEEK_END);
if (ftell(F) > endPos) { if (ftell(F) > endPos){endPos = ftell(F);}
endPos = ftell(F);
}
} }
void DTSC::File::writePacket(std::string & newPacket) { void DTSC::File::writePacket(std::string &newPacket){
fseek(F, 0, SEEK_END); fseek(F, 0, SEEK_END);
fwrite(newPacket.c_str(), newPacket.size(), 1, F); //write contents fwrite(newPacket.c_str(), newPacket.size(), 1, F); // write contents
fseek(F, 0, SEEK_END); fseek(F, 0, SEEK_END);
endPos = ftell(F); endPos = ftell(F);
} }
void DTSC::File::writePacket(JSON::Value & newPacket) { void DTSC::File::writePacket(JSON::Value &newPacket){
writePacket(newPacket.toNetPacked()); writePacket(newPacket.toNetPacked());
} }
bool DTSC::File::atKeyframe() { bool DTSC::File::atKeyframe(){
if (myPack.getFlag("keyframe")) { if (myPack.getFlag("keyframe")){return true;}
return true;
}
long long int bTime = myPack.getTime(); long long int bTime = myPack.getTime();
DTSC::Track & trackRef = metadata.tracks[myPack.getTrackId()]; DTSC::Track &trackRef = metadata.tracks[myPack.getTrackId()];
for (unsigned int i = 0; i < trackRef.keys.size(); i++) { for (unsigned int i = 0; i < trackRef.keys.size(); i++){
if (trackRef.keys[i].getTime() >= bTime) { if (trackRef.keys[i].getTime() >= bTime){return (trackRef.keys[i].getTime() == bTime);}
return (trackRef.keys[i].getTime() == bTime);
}
} }
return false; return false;
} }
void DTSC::File::selectTracks(std::set<unsigned long> & tracks) { void DTSC::File::selectTracks(std::set<unsigned long> &tracks){
selectedTracks = tracks; selectedTracks = tracks;
currentPositions.clear(); currentPositions.clear();
seek_time(0); seek_time(0);
} }
/// Close the file if open /// Close the file if open
DTSC::File::~File() { DTSC::File::~File(){
if (F) { if (F){
fclose(F); fclose(F);
F = 0; F = 0;
} }

View file

@ -2,16 +2,16 @@
/// Holds all headers for DDVTECH Stream Container parsing/generation. /// Holds all headers for DDVTECH Stream Container parsing/generation.
#pragma once #pragma once
#include <vector>
#include <iostream>
#include <stdint.h> //for uint64_t
#include <string>
#include <deque>
#include <set>
#include <stdio.h> //for FILE
#include "json.h" #include "json.h"
#include "socket.h" #include "socket.h"
#include "timing.h" #include "timing.h"
#include <deque>
#include <iostream>
#include <set>
#include <stdint.h> //for uint64_t
#include <stdio.h> //for FILE
#include <string>
#include <vector>
#define DTSC_INT 0x01 #define DTSC_INT 0x01
#define DTSC_STR 0x02 #define DTSC_STR 0x02
@ -19,187 +19,179 @@
#define DTSC_ARR 0x0A #define DTSC_ARR 0x0A
#define DTSC_CON 0xFF #define DTSC_CON 0xFF
//Increase this value every time the DTSH file format changes in an incompatible way // Increase this value every time the DTSH file format changes in an incompatible way
//Changelog: // Changelog:
// Version 0-2: Undocumented changes // Version 0-2: Undocumented changes
// Version 3: switched to bigMeta-style by default, Parts layout switched from 3/2/4 to 3/3/3 bytes // Version 3: switched to bigMeta-style by default, Parts layout switched from 3/2/4 to 3/3/3 bytes
// Version 4: renamed bps to maxbps (peak bit rate) and added new value bps (average bit rate) // Version 4: renamed bps to maxbps (peak bit rate) and added new value bps (average bit rate)
#define DTSH_VERSION 4 #define DTSH_VERSION 4
namespace DTSC { namespace DTSC{
///\brief This enum holds all possible datatypes for DTSC packets. ///\brief This enum holds all possible datatypes for DTSC packets.
enum datatype { enum datatype{
AUDIO, ///< Stream Audio data AUDIO, ///< Stream Audio data
VIDEO, ///< Stream Video data VIDEO, ///< Stream Video data
META, ///< Stream Metadata META, ///< Stream Metadata
PAUSEMARK, ///< Pause marker PAUSEMARK, ///< Pause marker
MODIFIEDHEADER, ///< Modified header data. MODIFIEDHEADER, ///< Modified header data.
INVALID ///< Anything else or no data available. INVALID ///< Anything else or no data available.
}; };
extern char Magic_Header[]; ///< The magic bytes for a DTSC header extern char Magic_Header[]; ///< The magic bytes for a DTSC header
extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet
extern char Magic_Packet2[]; ///< The magic bytes for a DTSC packet version 2 extern char Magic_Packet2[]; ///< The magic bytes for a DTSC packet version 2
extern char Magic_Command[]; ///< The magic bytes for a DTCM packet extern char Magic_Command[]; ///< The magic bytes for a DTCM packet
///\brief A simple structure used for ordering byte seek positions. ///\brief A simple structure used for ordering byte seek positions.
struct seekPos { struct seekPos{
///\brief Less-than comparison for seekPos structures. ///\brief Less-than comparison for seekPos structures.
///\param rhs The seekPos to compare with. ///\param rhs The seekPos to compare with.
///\return Whether this object is smaller than rhs. ///\return Whether this object is smaller than rhs.
bool operator < (const seekPos & rhs) const { bool operator<(const seekPos &rhs) const{
if (seekTime < rhs.seekTime) { if (seekTime < rhs.seekTime){
return true; return true;
} else { }else{
if (seekTime == rhs.seekTime) { if (seekTime == rhs.seekTime){
if (trackID < rhs.trackID) { if (trackID < rhs.trackID){return true;}
return true;
}
} }
} }
return false; return false;
} }
long long unsigned int seekTime;///< Stores the timestamp of the DTSC packet referenced by this structure. long long unsigned int seekTime; ///< Stores the timestamp of the DTSC packet referenced by this structure.
long long unsigned int bytePos;///< Stores the byteposition of the DTSC packet referenced by this structure. long long unsigned int bytePos; ///< Stores the byteposition of the DTSC packet referenced by this structure.
unsigned int trackID;///< Stores the track the DTSC packet referenced by this structure is associated with. unsigned int trackID; ///< Stores the track the DTSC packet referenced by this structure is associated with.
}; };
enum packType { enum packType{DTSC_INVALID, DTSC_HEAD, DTSC_V1, DTSC_V2, DTCM};
DTSC_INVALID,
DTSC_HEAD,
DTSC_V1,
DTSC_V2,
DTCM
};
/// This class allows scanning through raw binary format DTSC data. /// This class allows scanning through raw binary format DTSC data.
/// It can be used as an iterator or as a direct accessor. /// It can be used as an iterator or as a direct accessor.
class Scan { class Scan{
public: public:
Scan(); Scan();
Scan(char * pointer, size_t len); Scan(char *pointer, size_t len);
operator bool() const; operator bool() const;
std::string toPrettyString(size_t indent = 0) const; std::string toPrettyString(size_t indent = 0) const;
bool hasMember(const std::string & indice) const; bool hasMember(const std::string &indice) const;
bool hasMember(const char * indice, size_t ind_len) const; bool hasMember(const char *indice, size_t ind_len) const;
Scan getMember(const std::string & indice) const; Scan getMember(const std::string &indice) const;
Scan getMember(const char * indice) const; Scan getMember(const char *indice) const;
Scan getMember(const char * indice, size_t ind_len) const; Scan getMember(const char *indice, size_t ind_len) const;
void nullMember(const std::string & indice); void nullMember(const std::string &indice);
void nullMember(const char * indice, size_t ind_len); void nullMember(const char *indice, size_t ind_len);
Scan getIndice(size_t num) const; Scan getIndice(size_t num) const;
std::string getIndiceName(size_t num) const; std::string getIndiceName(size_t num) const;
size_t getSize() const; size_t getSize() const;
char getType() const; char getType() const;
bool asBool() const; bool asBool() const;
int64_t asInt() const; int64_t asInt() const;
std::string asString() const; std::string asString() const;
void getString(char *& result, size_t & len) const; void getString(char *&result, size_t &len) const;
JSON::Value asJSON() const; JSON::Value asJSON() const;
private:
char * p; private:
size_t len; char *p;
size_t len;
}; };
/// DTSC::Packets can currently be three types: /// DTSC::Packets can currently be three types:
/// DTSC_HEAD packets are the "DTSC" header string, followed by 4 bytes len and packed content. /// DTSC_HEAD packets are the "DTSC" header string, followed by 4 bytes len and packed content.
/// DTSC_V1 packets are "DTPD", followed by 4 bytes len and packed content. /// DTSC_V1 packets are "DTPD", followed by 4 bytes len and packed content.
/// DTSC_V2 packets are "DTP2", followed by 4 bytes len, 4 bytes trackID, 8 bytes time, and packed content. /// DTSC_V2 packets are "DTP2", followed by 4 bytes len, 4 bytes trackID, 8 bytes time, and packed
/// The len is always without the first 8 bytes counted. /// content. The len is always without the first 8 bytes counted.
class Packet { class Packet{
public: public:
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);
virtual ~Packet(); virtual ~Packet();
void null(); void null();
void operator = (const Packet & rhs); void operator=(const Packet &rhs);
operator bool() const; operator bool() const;
packType getVersion() const; packType getVersion() const;
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,
void appendData(const char * appendData, uint32_t appendLen); const char *packData, long long packDataSize, uint64_t packBytePos,
void getString(const char * identifier, char *& result, size_t & len) const; bool isKeyframe, int64_t bootMsOffset = 0);
void getString(const char * identifier, std::string & result) const; void appendData(const char *appendData, uint32_t appendLen);
void getInt(const char * identifier, uint64_t & result) const; void getString(const char *identifier, char *&result, size_t &len) const;
uint64_t getInt(const char * identifier) const; void getString(const char *identifier, std::string &result) const;
void getFlag(const char * identifier, bool & result) const; void getInt(const char *identifier, uint64_t &result) const;
bool getFlag(const char * identifier) const; uint64_t getInt(const char *identifier) const;
bool hasMember(const char * identifier) const; void getFlag(const char *identifier, bool &result) const;
void appendNal(const char * appendData, uint32_t appendLen); bool getFlag(const char *identifier) const;
void upgradeNal(const char * appendData, uint32_t appendLen); bool hasMember(const char *identifier) const;
void setKeyFrame(bool kf); void appendNal(const char *appendData, uint32_t appendLen);
virtual uint64_t getTime() const; void upgradeNal(const char *appendData, uint32_t appendLen);
void setTime(uint64_t _time); void setKeyFrame(bool kf);
void nullMember(const std::string & memb); virtual uint64_t getTime() const;
size_t getTrackId() const; void setTime(uint64_t _time);
char * getData() const; void nullMember(const std::string &memb);
size_t getDataLen() const; size_t getTrackId() const;
size_t getPayloadLen() const; char *getData() const;
size_t getDataStringLen(); size_t getDataLen() const;
size_t getDataStringLenOffset(); size_t getPayloadLen() const;
JSON::Value toJSON() const; size_t getDataStringLen();
std::string toSummary() const; size_t getDataStringLenOffset();
Scan getScan() const; JSON::Value toJSON() const;
Scan getScan(); std::string toSummary() const;
protected: Scan getScan() const;
bool master; Scan getScan();
packType version;
void resize(size_t size);
char * data;
size_t bufferLen;
size_t dataLen;
uint64_t prevNalSize; protected:
bool master;
packType version;
void resize(size_t size);
char *data;
size_t bufferLen;
size_t dataLen;
uint64_t prevNalSize;
}; };
/// A child class of DTSC::Packet, which allows overriding the packet time efficiently. /// A child class of DTSC::Packet, which allows overriding the packet time efficiently.
class RetimedPacket : public Packet { class RetimedPacket : public Packet{
public: public:
RetimedPacket(uint64_t reTime){ RetimedPacket(uint64_t reTime){timeOverride = reTime;}
timeOverride = reTime; RetimedPacket(uint64_t reTime, const Packet &rhs) : Packet(rhs){timeOverride = reTime;}
} RetimedPacket(uint64_t reTime, const char *data_, unsigned int len, bool noCopy = false)
RetimedPacket(uint64_t reTime, const Packet & rhs) : Packet(rhs){ : Packet(data_, len, noCopy){
timeOverride = reTime; timeOverride = reTime;
} }
RetimedPacket(uint64_t reTime, const char * data_, unsigned int len, bool noCopy = false) : Packet(data_, len, noCopy){ virtual uint64_t getTime() const{return timeOverride;}
timeOverride = reTime;
} protected:
virtual uint64_t getTime() const{return timeOverride;} uint64_t timeOverride;
protected:
uint64_t timeOverride;
}; };
/// A simple structure used for ordering byte seek positions. /// A simple structure used for ordering byte seek positions.
struct livePos { struct livePos{
livePos() { livePos(){
seekTime = 0; seekTime = 0;
trackID = 0; trackID = 0;
} }
livePos(const livePos & rhs) { livePos(const livePos &rhs){
seekTime = rhs.seekTime; seekTime = rhs.seekTime;
trackID = rhs.trackID; trackID = rhs.trackID;
} }
void operator = (const livePos & rhs) { void operator=(const livePos &rhs){
seekTime = rhs.seekTime; seekTime = rhs.seekTime;
trackID = rhs.trackID; trackID = rhs.trackID;
} }
bool operator == (const livePos & rhs) { bool operator==(const livePos &rhs){
return seekTime == rhs.seekTime && trackID == rhs.trackID; return seekTime == rhs.seekTime && trackID == rhs.trackID;
} }
bool operator != (const livePos & rhs) { bool operator!=(const livePos &rhs){
return seekTime != rhs.seekTime || trackID != rhs.trackID; return seekTime != rhs.seekTime || trackID != rhs.trackID;
} }
bool operator < (const livePos & rhs) const { bool operator<(const livePos &rhs) const{
if (seekTime < rhs.seekTime) { if (seekTime < rhs.seekTime){
return true; return true;
} else { }else{
if (seekTime > rhs.seekTime) { if (seekTime > rhs.seekTime){return false;}
return false;
}
} }
return (trackID < rhs.trackID); return (trackID < rhs.trackID);
} }
@ -210,261 +202,274 @@ namespace DTSC {
/*LTS-START*/ /*LTS-START*/
///\brief Basic class supporting initialization Vectors. ///\brief Basic class supporting initialization Vectors.
/// ///
///These are used for encryption of data. /// These are used for encryption of data.
class Ivec { class Ivec{
public: public:
Ivec(); Ivec();
Ivec(long long int iVec); Ivec(long long int iVec);
void setIvec(long long int iVec); void setIvec(long long int iVec);
void setIvec(std::string iVec); void setIvec(std::string iVec);
void setIvec(const char * iVec, int len); void setIvec(const char *iVec, int len);
long long int asInt(); long long int asInt();
char * getData(); char *getData();
private:
///\brief Data storage for this initialization vector. private:
/// ///\brief Data storage for this initialization vector.
/// - 8 bytes: MSB storage of the initialization vector. ///
char data[8]; /// - 8 bytes: MSB storage of the initialization vector.
char data[8];
}; };
/*LTS-END*/ /*LTS-END*/
///\brief Basic class for storage of data associated with single DTSC packets, a.k.a. parts. ///\brief Basic class for storage of data associated with single DTSC packets, a.k.a. parts.
class Part { class Part{
public: public:
uint32_t getSize(); uint32_t getSize();
void setSize(uint32_t newSize); void setSize(uint32_t newSize);
uint32_t getDuration(); uint32_t getDuration();
void setDuration(uint32_t newDuration); void setDuration(uint32_t newDuration);
uint32_t getOffset(); uint32_t getOffset();
void setOffset(uint32_t newOffset); void setOffset(uint32_t newOffset);
char * getData(); char *getData();
void toPrettyString(std::ostream & str, int indent = 0); void toPrettyString(std::ostream &str, int indent = 0);
private:
private:
#define PACKED_PART_SIZE 9 #define PACKED_PART_SIZE 9
///\brief Data storage for this Part. ///\brief Data storage for this Part.
/// ///
/// - 3 bytes: MSB storage of the payload size of this packet in bytes. /// - 3 bytes: MSB storage of the payload size of this packet in bytes.
/// - 3 bytes: MSB storage of the duration of this packet in milliseconds. /// - 3 bytes: MSB storage of the duration of this packet in milliseconds.
/// - 3 bytes: MSB storage of the presentation time offset of this packet in milliseconds. /// - 3 bytes: MSB storage of the presentation time offset of this packet in milliseconds.
char data[PACKED_PART_SIZE]; char data[PACKED_PART_SIZE];
}; };
///\brief Basic class for storage of data associated with keyframes. ///\brief Basic class for storage of data associated with keyframes.
/// ///
/// When deleting this object, make sure to remove all DTSC::Part associated with it, if any. If you fail doing this, it *will* cause data corruption. /// When deleting this object, make sure to remove all DTSC::Part associated with it, if any. If you fail doing this, it *will* cause data corruption.
class Key { class Key{
public: public:
unsigned long long getBpos(); unsigned long long getBpos();
void setBpos(unsigned long long newBpos); void setBpos(unsigned long long newBpos);
unsigned long getLength(); unsigned long getLength();
void setLength(unsigned long newLength); void setLength(unsigned long newLength);
unsigned long getNumber(); unsigned long getNumber();
void setNumber(unsigned long newNumber); void setNumber(unsigned long newNumber);
unsigned short getParts(); unsigned short getParts();
void setParts(unsigned short newParts); void setParts(unsigned short newParts);
unsigned long long getTime(); unsigned long long getTime();
void setTime(unsigned long long newTime); void setTime(unsigned long long newTime);
char * getData(); char *getData();
void toPrettyString(std::ostream & str, int indent = 0); void toPrettyString(std::ostream &str, int indent = 0);
private:
private:
#define PACKED_KEY_SIZE 25 #define PACKED_KEY_SIZE 25
///\brief Data storage for this Key. ///\brief Data storage for this Key.
/// ///
/// - 8 bytes: MSB storage of the position of the first packet of this keyframe within the file. /// - 8 bytes: MSB storage of the position of the first packet of this keyframe within the file.
/// - 3 bytes: MSB storage of the duration of this keyframe. /// - 3 bytes: MSB storage of the duration of this keyframe.
/// - 4 bytes: MSB storage of the number of this keyframe. /// - 4 bytes: MSB storage of the number of this keyframe.
/// - 2 bytes: MSB storage of the amount of parts in this keyframe. /// - 2 bytes: MSB storage of the amount of parts in this keyframe.
/// - 8 bytes: MSB storage of the timestamp associated with this keyframe's first packet. /// - 8 bytes: MSB storage of the timestamp associated with this keyframe's first packet.
char data[PACKED_KEY_SIZE]; char data[PACKED_KEY_SIZE];
}; };
///\brief Basic class for storage of data associated with fragments. ///\brief Basic class for storage of data associated with fragments.
class Fragment { class Fragment{
public: public:
unsigned long getDuration(); unsigned long getDuration();
void setDuration(unsigned long newDuration); void setDuration(unsigned long newDuration);
char getLength(); char getLength();
void setLength(char newLength); void setLength(char newLength);
unsigned long getNumber(); unsigned long getNumber();
void setNumber(unsigned long newNumber); void setNumber(unsigned long newNumber);
unsigned long getSize(); unsigned long getSize();
void setSize(unsigned long newSize); void setSize(unsigned long newSize);
char * getData(); char *getData();
void toPrettyString(std::ostream & str, int indent = 0); void toPrettyString(std::ostream &str, int indent = 0);
private:
private:
#define PACKED_FRAGMENT_SIZE 13 #define PACKED_FRAGMENT_SIZE 13
///\brief Data storage for this Fragment. ///\brief Data storage for this Fragment.
/// ///
/// - 4 bytes: duration (in milliseconds) /// - 4 bytes: duration (in milliseconds)
/// - 1 byte: length (amount of keyframes) /// - 1 byte: length (amount of keyframes)
/// - 4 bytes: number of first keyframe in fragment /// - 4 bytes: number of first keyframe in fragment
/// - 4 bytes: size of fragment in bytes /// - 4 bytes: size of fragment in bytes
char data[PACKED_FRAGMENT_SIZE]; char data[PACKED_FRAGMENT_SIZE];
}; };
///\brief Class for storage of track data ///\brief Class for storage of track data
class Track { class Track{
public: public:
Track(); Track();
Track(JSON::Value & trackRef); Track(JSON::Value &trackRef);
Track(Scan & trackRef); Track(Scan &trackRef);
void clearParts(); void clearParts();
inline operator bool() const { inline operator bool() const{
return (parts.size() && keySizes.size() && (keySizes.size() == keys.size())); return (parts.size() && keySizes.size() && (keySizes.size() == keys.size()));
} }
/* /*
void update(long long packTime, long long packOffset, long long packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize, unsigned long segment_size = 1900); void update(long long packTime, long long packOffset, long long packDataSize, uint64_t
*/ packBytePos, bool isKeyframe, long long packSendSize, unsigned long segment_size = 1900);
void update(long long packTime, long long packOffset, long long packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize, unsigned long segment_size = 1900, const char * iVec = 0); */
int getSendLen(bool skipDynamic = false); void update(long long packTime, long long packOffset, long long packDataSize,
void send(Socket::Connection & conn, bool skipDynamic = false); uint64_t packBytePos, bool isKeyframe, long long packSendSize,
void writeTo(char *& p); unsigned long segment_size = 1900, const char *iVec = 0);
JSON::Value toJSON(bool skipDynamic = false); int getSendLen(bool skipDynamic = false);
std::deque<Fragment> fragments; void send(Socket::Connection &conn, bool skipDynamic = false);
std::deque<Key> keys; void writeTo(char *&p);
std::deque<unsigned long> keySizes; JSON::Value toJSON(bool skipDynamic = false);
std::deque<Part> parts; std::deque<Fragment> fragments;
std::deque<Ivec> ivecs; /*LTS*/ std::deque<Key> keys;
Key & getKey(unsigned int keyNum); std::deque<unsigned long> keySizes;
Fragment & getFrag(unsigned int fragNum); std::deque<Part> parts;
unsigned int timeToKeynum(unsigned int timestamp); std::deque<Ivec> ivecs; /*LTS*/
uint32_t timeToFragnum(uint64_t timestamp); Key &getKey(unsigned int keyNum);
void reset(); Fragment &getFrag(unsigned int fragNum);
void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); unsigned int timeToKeynum(unsigned int timestamp);
void finalize(); uint32_t timeToFragnum(uint64_t timestamp);
uint32_t biggestFragment(); void reset();
void toPrettyString(std::ostream &str, int indent = 0, int verbosity = 0);
void finalize();
uint32_t biggestFragment();
std::string getIdentifier(); std::string getIdentifier();
std::string getWritableIdentifier(); std::string getWritableIdentifier();
unsigned int trackID; unsigned int trackID;
uint64_t firstms; uint64_t firstms;
uint64_t lastms; uint64_t lastms;
int bps; int bps;
int max_bps; int max_bps;
int missedFrags; int missedFrags;
std::string init; std::string init;
std::string codec; std::string codec;
std::string type; std::string type;
std::string lang;///< ISO 639-2 Language of track, empty or und if unknown. std::string lang; ///< ISO 639-2 Language of track, empty or und if unknown.
uint32_t minKeepAway;///<Time in MS to never seek closer than live point to uint32_t minKeepAway; ///< Time in MS to never seek closer than live point to
//audio only // audio only
int rate; int rate;
int size; int size;
int channels; int channels;
//video only // video only
int width; int width;
int height; int height;
int fpks; int fpks;
void removeFirstKey(); void removeFirstKey();
uint32_t secsSinceFirstFragmentInsert(); uint32_t secsSinceFirstFragmentInsert();
private:
std::string cachedIdent; private:
std::deque<uint32_t> fragInsertTime; std::string cachedIdent;
std::deque<uint32_t> fragInsertTime;
}; };
///\brief Class for storage of meta data ///\brief Class for storage of meta data
class Meta{ class Meta{
/// \todo Make toJSON().toNetpacked() shorter /// \todo Make toJSON().toNetpacked() shorter
public: public:
Meta(); Meta();
Meta(const DTSC::Packet & source); Meta(const DTSC::Packet &source);
Meta(JSON::Value & meta); Meta(JSON::Value &meta);
bool nextIsKey; bool nextIsKey;
inline operator bool() const { //returns if the object contains valid meta data BY LOOKING AT vod/live FLAGS inline operator bool() const{// returns if the object contains valid meta data BY LOOKING AT vod/live FLAGS
return vod || live; return vod || live;
} }
void reinit(const DTSC::Packet & source); void reinit(const DTSC::Packet &source);
void update(const DTSC::Packet & pack, unsigned long segment_size = 1900); void update(const DTSC::Packet &pack, unsigned long segment_size = 1900);
void updatePosOverride(DTSC::Packet & pack, uint64_t bpos); void updatePosOverride(DTSC::Packet &pack, uint64_t bpos);
void update(JSON::Value & pack, unsigned long segment_size = 1900); void update(JSON::Value &pack, unsigned long segment_size = 1900);
/*LTS /*LTS
void update(long long packTime, long long packOffset, long long packTrack, long long packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize = 0, unsigned long segment_size = 1900); void update(long long packTime, long long packOffset, long long packTrack, long long
LTS*/ packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize = 0, unsigned long
void update(long long packTime, long long packOffset, long long packTrack, long long packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize = 0, unsigned long segment_size = 1900, const char * iVec = 0); segment_size = 1900); LTS*/
unsigned int getSendLen(bool skipDynamic = false, std::set<unsigned long> selectedTracks = std::set<unsigned long>()); void update(long long packTime, long long packOffset, long long packTrack,
void send(Socket::Connection & conn, bool skipDynamic = false, std::set<unsigned long> selectedTracks = std::set<unsigned long>()); long long packDataSize, uint64_t packBytePos, bool isKeyframe,
void writeTo(char * p); long long packSendSize = 0, unsigned long segment_size = 1900, const char *iVec = 0);
JSON::Value toJSON(); unsigned int getSendLen(bool skipDynamic = false,
void reset(); std::set<unsigned long> selectedTracks = std::set<unsigned long>());
bool toFile(const std::string & fileName); void send(Socket::Connection &conn, bool skipDynamic = false,
void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); std::set<unsigned long> selectedTracks = std::set<unsigned long>());
//members: void writeTo(char *p);
std::map<unsigned int, Track> tracks; JSON::Value toJSON();
Track & mainTrack(); void reset();
uint32_t biggestFragment(); bool toFile(const std::string &fileName);
bool vod; void toPrettyString(std::ostream &str, int indent = 0, int verbosity = 0);
bool live; // members:
bool merged; std::map<unsigned int, Track> tracks;
uint16_t version; Track &mainTrack();
int64_t moreheader; uint32_t biggestFragment();
int64_t bufferWindow; bool vod;
int64_t bootMsOffset;///< Millis to add to packet timestamps to get millis since system boot. bool live;
std::string sourceURI; bool merged;
JSON::Value inputLocalVars; uint16_t version;
int64_t moreheader;
int64_t bufferWindow;
int64_t bootMsOffset; ///< Millis to add to packet timestamps to get millis since system boot.
std::string sourceURI;
JSON::Value inputLocalVars;
}; };
/// An iterator helper for easily iterating over the parts in a Fragment. /// An iterator helper for easily iterating over the parts in a Fragment.
class PartIter { class PartIter{
public: public:
PartIter(Track & Trk, Fragment & frag); PartIter(Track &Trk, Fragment &frag);
Part & operator*() const;///< Dereferences into a Value reference. Part &operator*() const; ///< Dereferences into a Value reference.
Part* operator->() const;///< Dereferences into a Value reference. Part *operator->() const; ///< Dereferences into a Value reference.
operator bool() const;///< True if not done iterating. operator bool() const; ///< True if not done iterating.
PartIter & operator++();///<Go to next iteration. PartIter &operator++(); ///< Go to next iteration.
private: private:
uint32_t lastKey; uint32_t lastKey;
uint32_t currInKey; uint32_t currInKey;
Track * tRef; Track *tRef;
std::deque<Part>::iterator pIt; std::deque<Part>::iterator pIt;
std::deque<Key>::iterator kIt; std::deque<Key>::iterator kIt;
}; };
/// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it. /// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it.
class File { class File{
public: public:
File(); File();
File(const File & rhs); File(const File &rhs);
File(std::string filename, bool create = false); File(std::string filename, bool create = false);
File & operator = (const File & rhs); File &operator=(const File &rhs);
operator bool() const; operator bool() const;
~File(); ~File();
Meta & getMeta(); Meta &getMeta();
long long int getLastReadPos(); long long int getLastReadPos();
bool writeHeader(std::string & header, bool force = false); bool writeHeader(std::string &header, bool force = false);
long long int addHeader(std::string & header); long long int addHeader(std::string &header);
long int getBytePosEOF(); long int getBytePosEOF();
long int getBytePos(); long int getBytePos();
bool reachedEOF(); bool reachedEOF();
void seekNext(); void seekNext();
void parseNext(); void parseNext();
DTSC::Packet & getPacket(); DTSC::Packet &getPacket();
bool seek_time(unsigned int ms); bool seek_time(unsigned int ms);
bool seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek = false); bool seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek = false);
bool seek_bpos(int bpos); bool seek_bpos(int bpos);
void rewritePacket(std::string & newPacket, int bytePos); void rewritePacket(std::string &newPacket, int bytePos);
void writePacket(std::string & newPacket); void writePacket(std::string &newPacket);
void writePacket(JSON::Value & newPacket); void writePacket(JSON::Value &newPacket);
bool atKeyframe(); bool atKeyframe();
void selectTracks(std::set<unsigned long> & tracks); void selectTracks(std::set<unsigned long> &tracks);
private:
long int endPos; private:
void readHeader(int pos); long int endPos;
DTSC::Packet myPack; void readHeader(int pos);
Meta metadata; DTSC::Packet myPack;
std::map<unsigned int, std::string> trackMapping; Meta metadata;
long long int currtime; std::map<unsigned int, std::string> trackMapping;
long long int lastreadpos; long long int currtime;
int currframe; long long int lastreadpos;
FILE * F; int currframe;
unsigned long headerSize; FILE *F;
void * buffer; unsigned long headerSize;
bool created; void *buffer;
std::set<seekPos> currentPositions; bool created;
std::set<unsigned long> selectedTracks; std::set<seekPos> currentPositions;
std::set<unsigned long> selectedTracks;
}; };
//FileWriter // FileWriter
}
}// namespace DTSC

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
#include "ebml.h"
#include "bitfields.h" #include "bitfields.h"
#include "defines.h" #include "defines.h"
#include "ebml.h"
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
@ -380,8 +380,7 @@ namespace EBML{
switch (getType()){ switch (getType()){
case ELEM_MASTER:{ case ELEM_MASTER:{
const uint64_t payLen = getPayloadLen(); const uint64_t payLen = getPayloadLen();
ret << std::string(indent, ' ') << "Element [" << getIDString(getID()) << "] (" ret << std::string(indent, ' ') << "Element [" << getIDString(getID()) << "] (" << getOuterLen() << "b, ";
<< getOuterLen() << "b, ";
if (payLen == 0xFFFFFFFFFFFFFFFFull){ if (payLen == 0xFFFFFFFFFFFFFFFFull){
ret << "infinite"; ret << "infinite";
}else{ }else{
@ -639,9 +638,8 @@ namespace EBML{
std::string Block::toPrettyString(const uint8_t indent, const uint8_t detail) const{ std::string Block::toPrettyString(const uint8_t indent, const uint8_t detail) const{
std::stringstream ret; std::stringstream ret;
ret << std::string(indent, ' ') << getIDString(getID()) << " with " ret << std::string(indent, ' ') << getIDString(getID()) << " with " << (unsigned int)getFrameCount()
<< (unsigned int)getFrameCount() << " frame(s) for track " << getTrackNum() << " @ " << " frame(s) for track " << getTrackNum() << " @ " << getTimecode();
<< getTimecode();
if (isKeyframe()){ret << " [KeyOnly]";} if (isKeyframe()){ret << " [KeyOnly]";}
if (isInvisible()){ret << " [Invisible]";} if (isInvisible()){ret << " [Invisible]";}
if (isDiscardable()){ret << " [Discardable]";} if (isDiscardable()){ret << " [Discardable]";}
@ -656,8 +654,7 @@ 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) << " (" ret << std::dec << std::string(indent + 4, ' ') << "Frame " << (frameNo + 1) << " (" << payLen << "b):";
<< payLen << "b):";
if (!payDat || !payLen || detail < 6){ if (!payDat || !payLen || detail < 6){
ret << std::endl; ret << std::endl;
continue; continue;
@ -683,4 +680,3 @@ namespace EBML{
return ret.str(); return ret.str();
} }
}// namespace EBML }// namespace EBML

View file

@ -121,4 +121,3 @@ namespace EBML{
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 }// namespace EBML

View file

@ -118,8 +118,7 @@ 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, sendElemHead(C, EID_INFO,
13 + 2 * appName.size() + 13 + 2 * appName.size() + (duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
(duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
sendElemUInt(C, EID_TIMECODESCALE, 1000000); sendElemUInt(C, EID_TIMECODESCALE, 1000000);
if (duration > 0){sendElemDbl(C, EID_DURATION, duration);} if (duration > 0){sendElemDbl(C, EID_DURATION, duration);}
sendElemStr(C, EID_MUXINGAPP, appName); sendElemStr(C, EID_MUXINGAPP, appName);
@ -136,8 +135,7 @@ namespace EBML{
(duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0)); (duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
} }
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime, void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime, bool forceKeyframe){
bool forceKeyframe){
size_t dataLen = 0; size_t dataLen = 0;
char *dataPointer = 0; char *dataPointer = 0;
pkt.getString("data", dataPointer, dataLen); pkt.getString("data", dataPointer, dataLen);
@ -170,8 +168,7 @@ 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, void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos){
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);
@ -196,4 +193,3 @@ namespace EBML{
} }
}// namespace EBML }// namespace EBML

View file

@ -17,8 +17,7 @@ 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, void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos);
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);
@ -28,8 +27,6 @@ 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, void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime, bool forceKeyframe = false);
bool forceKeyframe = false);
uint32_t sizeSimpleBlock(uint64_t trackId, uint32_t dataSize); uint32_t sizeSimpleBlock(uint64_t trackId, uint32_t dataSize);
}// namespace EBML }// namespace EBML

View file

@ -101,11 +101,9 @@ namespace Encodings{
std::string escaped = ""; std::string escaped = "";
int max = c.length(); int max = c.length();
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] == '~' || c[i] == ';' || c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'') ||
c[i] == '\'') ||
(ign.size() && ign.find(c[i]) != std::string::npos)){ (ign.size() && ign.find(c[i]) != std::string::npos)){
escaped.append(&c[i], 1); escaped.append(&c[i], 1);
}else{ }else{
@ -143,4 +141,3 @@ namespace Encodings{
} }
}// namespace Encodings }// namespace Encodings

View file

@ -40,4 +40,3 @@ namespace Encodings{
}; };
}// namespace Encodings }// namespace Encodings

View file

@ -1,38 +1,35 @@
#include "encryption.h"
#include "auth.h" #include "auth.h"
#include "bitfields.h"
#include "defines.h"
#include "encode.h"
#include "encryption.h"
#include "http_parser.h"
#include "nal.h" /*LTS*/
#include "rijndael.h"
#include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iomanip> #include <iomanip>
#include <cstdio>
#include <iostream> #include <iostream>
#include "rijndael.h"
#include "defines.h"
#include "bitfields.h"
#include "http_parser.h"
#include "encode.h"
#include "nal.h"/*LTS*/
#include <sstream> #include <sstream>
namespace Encryption { namespace Encryption{
///helper function for printing binary values /// helper function for printing binary values
std::string hexString(const char * data, unsigned long dataLen){ std::string hexString(const char *data, unsigned long dataLen){
std::stringstream res; std::stringstream res;
for (int i = 0; i < dataLen; i++){ for (int i = 0; i < dataLen; i++){
res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i]; res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
if (i % 4 == 3){ if (i % 4 == 3){res << " ";}
res << " ";
}
} }
return res.str(); return res.str();
} }
std::string AES_Crypt(const std::string &data, const std::string &key, std::string &ivec){
std::string AES_Crypt(const std::string & data, const std::string & key, std::string & ivec) {
return AES_Crypt(data.data(), data.size(), key.data(), ivec.data()); return AES_Crypt(data.data(), data.size(), key.data(), ivec.data());
} }
std::string AES_Crypt(const char * data, int dataLen, const char * key, const char * ivec) { std::string AES_Crypt(const char *data, int dataLen, const char *key, const char *ivec){
char * outData = (char *)malloc(dataLen * sizeof(char)); char *outData = (char *)malloc(dataLen * sizeof(char));
memcpy(outData, data, dataLen); memcpy(outData, data, dataLen);
AESFullCrypt(outData, dataLen, key, ivec); AESFullCrypt(outData, dataLen, key, ivec);
std::string result = std::string(outData, dataLen); std::string result = std::string(outData, dataLen);
@ -40,51 +37,52 @@ namespace Encryption {
return result; return result;
} }
///This function encrypts data in-place. /// This function encrypts data in-place.
///It alters all parameters except dataLen. /// It alters all parameters except dataLen.
///Do not use it unless you know what you are doing. /// Do not use it unless you know what you are doing.
void AESPartialCrypt(char * data, int dataLen, char * expandedKey, char * eCount, char * iVec, unsigned int & num, bool & initialize) { void AESPartialCrypt(char *data, int dataLen, char *expandedKey, char *eCount, char *iVec,
if (initialize) { unsigned int &num, bool &initialize){
if (initialize){
num = 0; num = 0;
memset(eCount, 0, 16); memset(eCount, 0, 16);
///Before use, make sure the iVec is in the UPPER 8 bytes /// Before use, make sure the iVec is in the UPPER 8 bytes
memset(iVec + 8, 0, 8); memset(iVec + 8, 0, 8);
///Before use, make sure this is not the only copy of the key you had. It is lost upon initialization /// Before use, make sure this is not the only copy of the key you had. It is lost upon initialization
char cryptKey[224]; char cryptKey[224];
AES_set_encrypt_key(expandedKey, 128, cryptKey); AES_set_encrypt_key(expandedKey, 128, cryptKey);
memcpy(expandedKey, cryptKey, 224); memcpy(expandedKey, cryptKey, 224);
initialize = false; initialize = false;
} }
char * outData = (char *)malloc(dataLen * sizeof(char)); char *outData = (char *)malloc(dataLen * sizeof(char));
AES_CTR128_crypt(data, outData, dataLen, expandedKey, iVec, eCount, num); AES_CTR128_crypt(data, outData, dataLen, expandedKey, iVec, eCount, num);
memcpy(data, outData, dataLen); memcpy(data, outData, dataLen);
free(outData); free(outData);
} }
//Generates the contentkey from a keyseed and a keyid // Generates the contentkey from a keyseed and a keyid
std::string PR_GenerateContentKey(std::string & keyseed, std::string & keyid) { std::string PR_GenerateContentKey(std::string &keyseed, std::string &keyid){
char contentKey[16]; char contentKey[16];
char dataBlob[92]; char dataBlob[92];
char keyA[32], keyB[32], keyC[32]; char keyA[32], keyB[32], keyC[32];
std::string keyidBytes = PR_GuidToByteArray(keyid); std::string keyidBytes = PR_GuidToByteArray(keyid);
memcpy(dataBlob, keyseed.data(), 30); memcpy(dataBlob, keyseed.data(), 30);
memcpy(dataBlob + 30, keyidBytes.data(), 16); memcpy(dataBlob + 30, keyidBytes.data(), 16);
memcpy(dataBlob + 46, keyseed.data(), 30); memcpy(dataBlob + 46, keyseed.data(), 30);
memcpy(dataBlob + 76, keyidBytes.data(), 16); memcpy(dataBlob + 76, keyidBytes.data(), 16);
//KeyA is generated from keyseed/keyid // KeyA is generated from keyseed/keyid
Secure::sha256bin(dataBlob, 46, keyA); Secure::sha256bin(dataBlob, 46, keyA);
//KeyB is generated from keyseed/keyid/keyseed // KeyB is generated from keyseed/keyid/keyseed
Secure::sha256bin(dataBlob, 76, keyB); Secure::sha256bin(dataBlob, 76, keyB);
//KeyC is generated from keyseed/keyid/keyseed/keyid // KeyC is generated from keyseed/keyid/keyseed/keyid
Secure::sha256bin(dataBlob, 92, keyC); Secure::sha256bin(dataBlob, 92, keyC);
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++){
contentKey[i] = keyA[i] ^ keyA[i + 16] ^ keyB[i] ^ keyB[i + 16] ^ keyC[i] ^ keyC[i + 16]; contentKey[i] = keyA[i] ^ keyA[i + 16] ^ keyB[i] ^ keyB[i + 16] ^ keyC[i] ^ keyC[i + 16];
} }
return std::string(contentKey, 16); return std::string(contentKey, 16);
} }
//Transforms a guid to the MS byte array representation // Transforms a guid to the MS byte array representation
std::string PR_GuidToByteArray(std::string & guid) { std::string PR_GuidToByteArray(std::string &guid){
char result[16]; char result[16];
result[0] = guid[3]; result[0] = guid[3];
result[1] = guid[2]; result[1] = guid[2];
@ -100,9 +98,8 @@ namespace Encryption {
return std::string(result, 8); return std::string(result, 8);
} }
/// This function encrypts data in-place.
///This function encrypts data in-place. void AESFullCrypt(char *data, int dataLen, const char *key, const char *ivec){
void AESFullCrypt(char * data, int dataLen, const char * key, const char * ivec) {
unsigned int num = 0; unsigned int num = 0;
char expandedKey[224]; char expandedKey[224];
memcpy(expandedKey, key, 16); memcpy(expandedKey, key, 16);
@ -113,12 +110,12 @@ namespace Encryption {
AESPartialCrypt(data, dataLen, expandedKey, eCount, iVec, num, initialize); AESPartialCrypt(data, dataLen, expandedKey, eCount, iVec, num, initialize);
} }
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;
size_t dataLen; size_t dataLen;
thisPack.getString("data", data, dataLen); thisPack.getString("data", data, dataLen);
if (codec == "H264") { if (codec == "H264"){
unsigned int num = 0; unsigned int num = 0;
char expandedKey[224]; char expandedKey[224];
memcpy(expandedKey, key, 16); memcpy(expandedKey, key, 16);
@ -130,33 +127,30 @@ namespace Encryption {
int pos = 0; int pos = 0;
std::deque<int> nalSizes = nalu::parseNalSizes(thisPack); std::deque<int> nalSizes = nalu::parseNalSizes(thisPack);
for (std::deque<int>::iterator it = nalSizes.begin(); it != nalSizes.end(); it++) { for (std::deque<int>::iterator it = nalSizes.begin(); it != nalSizes.end(); it++){
int encrypted = (*it - 5) & ~0xF;//Bitmask to a multiple of 16 int encrypted = (*it - 5) & ~0xF; // Bitmask to a multiple of 16
int clear = *it - encrypted; int clear = *it - encrypted;
Encryption::AESPartialCrypt(data + pos + clear, encrypted, expandedKey, eCount, initVec, num, initialize); Encryption::AESPartialCrypt(data + pos + clear, encrypted, expandedKey, eCount, initVec, num, initialize);
pos += *it; pos += *it;
} }
} }
if (codec == "AAC") { if (codec == "AAC"){Encryption::AESFullCrypt(data, dataLen, key, iVec);}
Encryption::AESFullCrypt(data, dataLen, key, iVec);
}
} }
/// Converts a hexidecimal string format key to binary string format. /// Converts a hexidecimal string format key to binary string format.
std::string binKey(std::string hexkey) { std::string binKey(std::string hexkey){
char newkey[16]; char newkey[16];
memset(newkey, 0, 16); memset(newkey, 0, 16);
for (size_t i = 0; i < hexkey.size(); ++i) { for (size_t i = 0; i < hexkey.size(); ++i){
char c = hexkey[i]; char c = hexkey[i];
newkey[i >> 1] |= ((c & 15) + (((c & 64) >> 6) | ((c & 64) >> 3))) << ((~i & 1) << 2); newkey[i >> 1] |= ((c & 15) + (((c & 64) >> 6) | ((c & 64) >> 3))) << ((~i & 1) << 2);
} }
return std::string(newkey, 16); return std::string(newkey, 16);
} }
/// Helper function for urlescape. /// Helper function for urlescape.
/// Encodes a character as two hex digits. /// Encodes a character as two hex digits.
std::string hex(char dec) { std::string hex(char dec){
char dig1 = (dec & 0xF0) >> 4; char dig1 = (dec & 0xF0) >> 4;
char dig2 = (dec & 0x0F); char dig2 = (dec & 0x0F);
if (dig1 <= 9) dig1 += 48; if (dig1 <= 9) dig1 += 48;
@ -168,20 +162,19 @@ namespace Encryption {
r.append(&dig2, 1); r.append(&dig2, 1);
return r; return r;
} }
std::string hex(const std::string & input) { std::string hex(const std::string &input){
std::string res; std::string res;
res.reserve(input.size() * 2); res.reserve(input.size() * 2);
for (unsigned int i = 0; i < input.size(); i++) { for (unsigned int i = 0; i < input.size(); i++){res += hex(input[i]);}
res += hex(input[i]);
}
return res; return res;
} }
void fillVerimatrix(verimatrixData & vmData) { void fillVerimatrix(verimatrixData &vmData){
int hostPos = vmData.url.find("://") + 3; int hostPos = vmData.url.find("://") + 3;
int portPos = vmData.url.find(":", hostPos); int portPos = vmData.url.find(":", hostPos);
std::string hostName = vmData.url.substr(hostPos, (portPos == std::string::npos ? portPos : portPos - hostPos)); std::string hostName =
vmData.url.substr(hostPos, (portPos == std::string::npos ? portPos : portPos - hostPos));
int port = (portPos == std::string::npos ? 80 : atoi(vmData.url.data() + portPos + 1)); int port = (portPos == std::string::npos ? 80 : atoi(vmData.url.data() + portPos + 1));
Socket::Connection veriConn(hostName, port, true); Socket::Connection veriConn(hostName, port, true);
@ -190,44 +183,43 @@ namespace Encryption {
H.SetHeader("Host", vmData.url.substr(hostPos)); H.SetHeader("Host", vmData.url.substr(hostPos));
H.SendRequest(veriConn); H.SendRequest(veriConn);
H.Clean(); H.Clean();
while (veriConn && (!veriConn.spool() || !H.Read(veriConn))) {} while (veriConn && (!veriConn.spool() || !H.Read(veriConn))){}
vmData.key = binKey(H.GetHeader("Key")); vmData.key = binKey(H.GetHeader("Key"));
vmData.keyid = H.GetHeader("KeyId"); vmData.keyid = H.GetHeader("KeyId");
vmData.laurl = H.GetHeader("LAURL"); vmData.laurl = H.GetHeader("LAURL");
vmData.lauurl = H.GetHeader("LAUURL"); vmData.lauurl = H.GetHeader("LAUURL");
} }
void verimatrixData::read(const char * shmPage) { void verimatrixData::read(const char *shmPage){
int offset = 0; int offset = 0;
url = std::string(shmPage + offset); url = std::string(shmPage + offset);
offset += url.size() + 1;//+1 for the concluding 0-byte offset += url.size() + 1; //+1 for the concluding 0-byte
name = std::string(shmPage + offset); name = std::string(shmPage + offset);
offset += name.size() + 1;//+1 for the concluding 0-byte offset += name.size() + 1; //+1 for the concluding 0-byte
key = std::string(shmPage + offset); key = std::string(shmPage + offset);
offset += key.size() + 1;//+1 for the concluding 0-byte offset += key.size() + 1; //+1 for the concluding 0-byte
keyid = std::string(shmPage + offset); keyid = std::string(shmPage + offset);
offset += keyid.size() + 1;//+1 for the concluding 0-byte offset += keyid.size() + 1; //+1 for the concluding 0-byte
laurl = std::string(shmPage + offset); laurl = std::string(shmPage + offset);
offset += laurl.size() + 1;//+1 for the concluding 0-byte offset += laurl.size() + 1; //+1 for the concluding 0-byte
lauurl = std::string(shmPage + offset); lauurl = std::string(shmPage + offset);
key = binKey(key); key = binKey(key);
} }
void verimatrixData::write(char * shmPage) { void verimatrixData::write(char *shmPage){
int offset = 0; int offset = 0;
memcpy(shmPage + offset, url.c_str(), url.size() + 1); memcpy(shmPage + offset, url.c_str(), url.size() + 1);
offset += url.size() + 1;//+1 for the concluding 0-byte offset += url.size() + 1; //+1 for the concluding 0-byte
memcpy(shmPage + offset, name.c_str(), name.size() + 1); memcpy(shmPage + offset, name.c_str(), name.size() + 1);
offset += name.size() + 1;//+1 for the concluding 0-byte offset += name.size() + 1; //+1 for the concluding 0-byte
std::string tmpKey = hex(key); std::string tmpKey = hex(key);
memcpy(shmPage + offset, tmpKey.c_str(), tmpKey.size() + 1); memcpy(shmPage + offset, tmpKey.c_str(), tmpKey.size() + 1);
offset += tmpKey.size() + 1;//+1 for the concluding 0-byte offset += tmpKey.size() + 1; //+1 for the concluding 0-byte
memcpy(shmPage + offset, keyid.c_str(), keyid.size() + 1); memcpy(shmPage + offset, keyid.c_str(), keyid.size() + 1);
offset += keyid.size() + 1;//+1 for the concluding 0-byte offset += keyid.size() + 1; //+1 for the concluding 0-byte
memcpy(shmPage + offset, laurl.c_str(), laurl.size() + 1); memcpy(shmPage + offset, laurl.c_str(), laurl.size() + 1);
offset += laurl.size() + 1;//+1 for the concluding 0-byte offset += laurl.size() + 1; //+1 for the concluding 0-byte
memcpy(shmPage + offset, lauurl.c_str(), lauurl.size() + 1); memcpy(shmPage + offset, lauurl.c_str(), lauurl.size() + 1);
} }
} }// namespace Encryption

View file

@ -1,34 +1,35 @@
#pragma once #pragma once
#include <string>
#include "dtsc.h" #include "dtsc.h"
#include <string>
namespace Encryption { namespace Encryption{
class verimatrixData { class verimatrixData{
public: public:
void read(const char * shmPage); void read(const char *shmPage);
void write(char * shmPage); void write(char *shmPage);
std::string url; std::string url;
std::string name; std::string name;
std::string key; std::string key;
std::string keyid; std::string keyid;
std::string keyseed; std::string keyseed;
std::string laurl; std::string laurl;
std::string lauurl; std::string lauurl;
}; };
std::string hexString(const char * data, unsigned long dataLen); std::string hexString(const char *data, unsigned long dataLen);
std::string AES_Crypt(const std::string & data, const std::string & key, std::string & ivec); std::string AES_Crypt(const std::string &data, const std::string &key, std::string &ivec);
std::string AES_Crypt(const char * data, int dataLen, const char * key, const char * ivec); std::string AES_Crypt(const char *data, int dataLen, const char *key, const char *ivec);
//These functions are dangerous for your data // These functions are dangerous for your data
void AESFullCrypt(char * data, int dataLen, const char * key, const char * ivec); void AESFullCrypt(char *data, int dataLen, const char *key, const char *ivec);
void AESPartialCrypt(char * data, int dataLen, char * expandedKey, char * eCount, char * iVec, unsigned int & num, bool & initialize); void AESPartialCrypt(char *data, int dataLen, char *expandedKey, char *eCount, char *iVec,
unsigned int &num, bool &initialize);
std::string PR_GenerateContentKey(std::string & keyseed, std::string & keyid); std::string PR_GenerateContentKey(std::string &keyseed, std::string &keyid);
std::string PR_GuidToByteArray(std::string & guid); std::string PR_GuidToByteArray(std::string &guid);
void encryptPlayReady(DTSC::Packet & pack, std::string & codec, const char * iVec, const char * key); void encryptPlayReady(DTSC::Packet &pack, std::string &codec, const char *iVec, const char *key);
void fillVerimatrix(verimatrixData & vmData); void fillVerimatrix(verimatrixData &vmData);
} }// namespace Encryption

View file

@ -1,12 +1,12 @@
/// \file flv_tag.cpp /// \file flv_tag.cpp
/// Holds all code for the FLV namespace. /// Holds all code for the FLV namespace.
#include "flv_tag.h" #include "adts.h"
#include "defines.h" #include "defines.h"
#include "flv_tag.h"
#include "rtmpchunks.h" #include "rtmpchunks.h"
#include "timing.h" #include "timing.h"
#include "util.h" #include "util.h"
#include "adts.h"
#include <fcntl.h> //for Tag::FileLoader #include <fcntl.h> //for Tag::FileLoader
#include <sstream> #include <sstream>
#include <stdio.h> //for Tag::FileLoader #include <stdio.h> //for Tag::FileLoader
@ -20,8 +20,7 @@
/// Defaults to a audio+video header on FLV version 0x01 if no header received yet. /// Defaults to a audio+video header on FLV version 0x01 if no header received yet.
char FLV::Header[13] ={'F', 'L', 'V', 0x01, 0x05, 0, 0, 0, 0x09, 0, 0, 0, 0}; char FLV::Header[13] ={'F', 'L', 'V', 0x01, 0x05, 0, 0, 0, 0x09, 0, 0, 0, 0};
bool FLV::Parse_Error = bool FLV::Parse_Error = false; ///< This variable is set to true if a problem is encountered while parsing the FLV.
false; ///< This variable is set to true if a problem is encountered while parsing the FLV.
std::string FLV::Error_Str = ""; std::string FLV::Error_Str = "";
/// Checks a FLV Header for validness. Returns true if the header is valid, false /// Checks a FLV Header for validness. Returns true if the header is valid, false
@ -307,8 +306,8 @@ FLV::Tag::~Tag(){
/// Assignment operator - works exactly like the copy constructor. /// Assignment operator - works exactly like the copy constructor.
/// This operator checks for self-assignment. /// This operator checks for self-assignment.
FLV::Tag &FLV::Tag::operator=(const FLV::Tag & O){ FLV::Tag &FLV::Tag::operator=(const FLV::Tag &O){
if (this != &O){ //no self-assignment if (this != &O){// no self-assignment
done = true; done = true;
sofar = 0; sofar = 0;
len = O.len; len = O.len;
@ -504,51 +503,41 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Meta &M, std::set<long unsigned int> &selTrack
if (M.tracks[*it].type == "video"){ if (M.tracks[*it].type == "video"){
trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT)); trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT));
trinfo.getContentP(i)->addContent(AMF::Object( trinfo.getContentP(i)->addContent(AMF::Object(
"length", ((double)M.tracks[*it].lastms / 1000) * ((double)M.tracks[*it].fpks / 1000.0), "length", ((double)M.tracks[*it].lastms / 1000) * ((double)M.tracks[*it].fpks / 1000.0), AMF::AMF0_NUMBER));
AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent( trinfo.getContentP(i)->addContent(
AMF::Object("timescale", ((double)M.tracks[*it].fpks / 1000.0), AMF::AMF0_NUMBER)); AMF::Object("timescale", ((double)M.tracks[*it].fpks / 1000.0), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY)); trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY));
amfdata.getContentP(1)->addContent(AMF::Object("hasVideo", 1, AMF::AMF0_BOOL)); amfdata.getContentP(1)->addContent(AMF::Object("hasVideo", 1, AMF::AMF0_BOOL));
if (M.tracks[*it].codec == "H264"){ if (M.tracks[*it].codec == "H264"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 7, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 7, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "avc1"));
AMF::Object("sampletype", (std::string) "avc1"));
} }
if (M.tracks[*it].codec == "ScreenVideo2"){ if (M.tracks[*it].codec == "ScreenVideo2"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 6, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 6, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "sv2"));
AMF::Object("sampletype", (std::string) "sv2"));
} }
if (M.tracks[*it].codec == "VP6Alpha"){ if (M.tracks[*it].codec == "VP6Alpha"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 5, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 5, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "vp6a"));
AMF::Object("sampletype", (std::string) "vp6a"));
} }
if (M.tracks[*it].codec == "VP6"){ if (M.tracks[*it].codec == "VP6"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 4, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 4, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "vp6"));
AMF::Object("sampletype", (std::string) "vp6"));
} }
if (M.tracks[*it].codec == "ScreenVideo1"){ if (M.tracks[*it].codec == "ScreenVideo1"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 3, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 3, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "sv1"));
AMF::Object("sampletype", (std::string) "sv1"));
} }
if (M.tracks[*it].codec == "H263"){ if (M.tracks[*it].codec == "H263"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 2, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 2, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "h263"));
AMF::Object("sampletype", (std::string) "h263"));
} }
if (M.tracks[*it].codec == "JPEG"){ if (M.tracks[*it].codec == "JPEG"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 1, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 1, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "jpeg"));
AMF::Object("sampletype", (std::string) "jpeg"));
} }
amfdata.getContentP(1)->addContent( amfdata.getContentP(1)->addContent(AMF::Object("width", M.tracks[*it].width, AMF::AMF0_NUMBER));
AMF::Object("width", M.tracks[*it].width, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("height", M.tracks[*it].height, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(
AMF::Object("height", M.tracks[*it].height, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent( amfdata.getContentP(1)->addContent(
AMF::Object("videoframerate", (double)M.tracks[*it].fpks / 1000.0, AMF::AMF0_NUMBER)); AMF::Object("videoframerate", (double)M.tracks[*it].fpks / 1000.0, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent( amfdata.getContentP(1)->addContent(
@ -557,30 +546,23 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Meta &M, std::set<long unsigned int> &selTrack
} }
if (M.tracks[*it].type == "audio"){ if (M.tracks[*it].type == "audio"){
trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT)); trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT));
trinfo.getContentP(i)->addContent( trinfo.getContentP(i)->addContent(AMF::Object(
AMF::Object("length", ((double)M.tracks[*it].lastms) * ((double)M.tracks[*it].rate), "length", ((double)M.tracks[*it].lastms) * ((double)M.tracks[*it].rate), AMF::AMF0_NUMBER));
AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("timescale", M.tracks[*it].rate, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(
AMF::Object("timescale", M.tracks[*it].rate, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY)); trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY));
amfdata.getContentP(1)->addContent(AMF::Object("hasAudio", 1, AMF::AMF0_BOOL)); amfdata.getContentP(1)->addContent(AMF::Object("hasAudio", 1, AMF::AMF0_BOOL));
amfdata.getContentP(1)->addContent(AMF::Object("audiodelay", 0.0, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("audiodelay", 0.0, AMF::AMF0_NUMBER));
if (M.tracks[*it].codec == "AAC"){ if (M.tracks[*it].codec == "AAC"){
amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string) "mp4a")); amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string) "mp4a"));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "mp4a"));
AMF::Object("sampletype", (std::string) "mp4a"));
} }
if (M.tracks[*it].codec == "MP3"){ if (M.tracks[*it].codec == "MP3"){
amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string) "mp3")); amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string) "mp3"));
trinfo.getContentP(i)->getContentP(2)->addContent( trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string) "mp3"));
AMF::Object("sampletype", (std::string) "mp3"));
} }
amfdata.getContentP(1)->addContent( amfdata.getContentP(1)->addContent(AMF::Object("audiochannels", M.tracks[*it].channels, AMF::AMF0_NUMBER));
AMF::Object("audiochannels", M.tracks[*it].channels, AMF::AMF0_NUMBER)); amfdata.getContentP(1)->addContent(AMF::Object("audiosamplerate", M.tracks[*it].rate, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent( amfdata.getContentP(1)->addContent(AMF::Object("audiosamplesize", M.tracks[*it].size, AMF::AMF0_NUMBER));
AMF::Object("audiosamplerate", M.tracks[*it].rate, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(
AMF::Object("audiosamplesize", M.tracks[*it].size, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent( amfdata.getContentP(1)->addContent(
AMF::Object("audiodatarate", (double)M.tracks[*it].bps / 128.0, AMF::AMF0_NUMBER)); AMF::Object("audiodatarate", (double)M.tracks[*it].bps / 128.0, AMF::AMF0_NUMBER));
++i; ++i;
@ -836,21 +818,18 @@ void FLV::Tag::toMeta(DTSC::Meta &metadata, AMF::Object &amf_storage, unsigned i
if (data[0] == 0x12){ if (data[0] == 0x12){
AMF::Object meta_in = AMF::parse((unsigned char *)data + 11, len - 15); AMF::Object meta_in = AMF::parse((unsigned char *)data + 11, len - 15);
AMF::Object *tmp = 0; AMF::Object *tmp = 0;
if (meta_in.getContentP(1) && meta_in.getContentP(0) && if (meta_in.getContentP(1) && meta_in.getContentP(0) && (meta_in.getContentP(0)->StrValue() == "onMetaData")){
(meta_in.getContentP(0)->StrValue() == "onMetaData")){
tmp = meta_in.getContentP(1); tmp = meta_in.getContentP(1);
}else{ }else{
if (meta_in.getContentP(2) && meta_in.getContentP(1) && if (meta_in.getContentP(2) && meta_in.getContentP(1) && (meta_in.getContentP(1)->StrValue() == "onMetaData")){
(meta_in.getContentP(1)->StrValue() == "onMetaData")){
tmp = meta_in.getContentP(2); tmp = meta_in.getContentP(2);
} }
} }
if (tmp){amf_storage = *tmp;} if (tmp){amf_storage = *tmp;}
return; return;
} }
if (data[0] == 0x08 && if (data[0] == 0x08 && (metadata.tracks[reTrack].codec == "" || metadata.tracks[reTrack].codec != getAudioCodec() ||
(metadata.tracks[reTrack].codec == "" || metadata.tracks[reTrack].codec != getAudioCodec() || (needsInitData() && isInitData()))){
(needsInitData() && isInitData()))){
char audiodata = data[11]; char audiodata = data[11];
metadata.tracks[reTrack].trackID = reTrack; metadata.tracks[reTrack].trackID = reTrack;
metadata.tracks[reTrack].type = "audio"; metadata.tracks[reTrack].type = "audio";
@ -863,16 +842,14 @@ void FLV::Tag::toMeta(DTSC::Meta &metadata, AMF::Object &amf_storage, unsigned i
case 0xC: metadata.tracks[reTrack].rate = 44100; break; case 0xC: metadata.tracks[reTrack].rate = 44100; break;
} }
if (amf_storage.getContentP("audiosamplerate")){ if (amf_storage.getContentP("audiosamplerate")){
metadata.tracks[reTrack].rate = metadata.tracks[reTrack].rate = (long long int)amf_storage.getContentP("audiosamplerate")->NumValue();
(long long int)amf_storage.getContentP("audiosamplerate")->NumValue();
} }
switch (audiodata & 0x02){ switch (audiodata & 0x02){
case 0x0: metadata.tracks[reTrack].size = 8; break; case 0x0: metadata.tracks[reTrack].size = 8; break;
case 0x2: metadata.tracks[reTrack].size = 16; break; case 0x2: metadata.tracks[reTrack].size = 16; break;
} }
if (amf_storage.getContentP("audiosamplesize")){ if (amf_storage.getContentP("audiosamplesize")){
metadata.tracks[reTrack].size = metadata.tracks[reTrack].size = (long long int)amf_storage.getContentP("audiosamplesize")->NumValue();
(long long int)amf_storage.getContentP("audiosamplesize")->NumValue();
} }
switch (audiodata & 0x01){ switch (audiodata & 0x01){
case 0x0: metadata.tracks[reTrack].channels = 1; break; case 0x0: metadata.tracks[reTrack].channels = 1; break;
@ -898,8 +875,7 @@ void FLV::Tag::toMeta(DTSC::Meta &metadata, AMF::Object &amf_storage, unsigned i
} }
} }
if (data[0] == 0x09 && if (data[0] == 0x09 && ((needsInitData() && isInitData()) || !metadata.tracks[reTrack].codec.size())){
((needsInitData() && isInitData()) || !metadata.tracks[reTrack].codec.size())){
char videodata = data[11]; char videodata = data[11];
metadata.tracks[reTrack].codec = getVideoCodec(); metadata.tracks[reTrack].codec = getVideoCodec();
metadata.tracks[reTrack].type = "video"; metadata.tracks[reTrack].type = "video";
@ -908,8 +884,7 @@ void FLV::Tag::toMeta(DTSC::Meta &metadata, AMF::Object &amf_storage, unsigned i
metadata.tracks[reTrack].width = (long long int)amf_storage.getContentP("width")->NumValue(); metadata.tracks[reTrack].width = (long long int)amf_storage.getContentP("width")->NumValue();
} }
if (amf_storage.getContentP("height")){ if (amf_storage.getContentP("height")){
metadata.tracks[reTrack].height = metadata.tracks[reTrack].height = (long long int)amf_storage.getContentP("height")->NumValue();
(long long int)amf_storage.getContentP("height")->NumValue();
} }
if (!metadata.tracks[reTrack].fpks && amf_storage.getContentP("videoframerate")){ if (!metadata.tracks[reTrack].fpks && amf_storage.getContentP("videoframerate")){
if (amf_storage.getContentP("videoframerate")->NumValue()){ if (amf_storage.getContentP("videoframerate")->NumValue()){
@ -960,4 +935,3 @@ bool FLV::Tag::checkBufferSize(){
} }
return true; return true;
} }

View file

@ -18,8 +18,7 @@ namespace FLV{
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 extern bool Parse_Error; ///< This variable is set to true if a problem is encountered while
///< parsing the FLV. ///< parsing the FLV.
extern std::string extern std::string Error_Str; ///< This variable is set if a problem is encountered while parsing the FLV.
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.
@ -43,10 +42,9 @@ namespace FLV{
void tagTime(uint64_t T); void tagTime(uint64_t T);
int64_t offset(); int64_t offset();
void offset(int64_t 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 & Tag &operator=(const Tag &O); ///< Assignment operator - works exactly like the copy constructor.
operator=(const Tag &O); ///< Assignment operator - works exactly like the copy constructor.
Tag(const RTMPStream::Chunk &O); ///< Copy constructor from a RTMP chunk. Tag(const RTMPStream::Chunk &O); ///< Copy constructor from a RTMP chunk.
~Tag(); ///< Generic destructor. ~Tag(); ///< Generic destructor.
// loader functions // loader functions
@ -76,4 +74,3 @@ namespace FLV{
// Tag // Tag
}// namespace FLV }// namespace FLV

View file

@ -1,10 +1,10 @@
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
#include "h264.h"
#include "bitfields.h" #include "bitfields.h"
#include "bitstream.h" #include "bitstream.h"
#include "defines.h" #include "defines.h"
#include "h264.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <iomanip> #include <iomanip>
@ -93,8 +93,7 @@ namespace h264{
// Fill the bitstream // Fill the bitstream
Utils::bitstream bs; Utils::bitstream bs;
for (size_t i = 1; i < dataLen; i++){ for (size_t i = 1; i < dataLen; i++){
if (i + 2 < dataLen && if (i + 2 < dataLen && (memcmp(data + i, "\000\000\003", 3) == 0)){// Emulation prevention bytes
(memcmp(data + i, "\000\000\003", 3) == 0)){// Emulation prevention bytes
// Yes, we increase i here // Yes, we increase i here
bs.append(data + i, 2); bs.append(data + i, 2);
i += 2; i += 2;
@ -111,8 +110,7 @@ namespace h264{
result.level = bs.get(8); result.level = bs.get(8);
bs.getUExpGolomb(); bs.getUExpGolomb();
if (profileIdc == 100 || profileIdc == 110 || profileIdc == 122 || profileIdc == 244 || if (profileIdc == 100 || profileIdc == 110 || profileIdc == 122 || profileIdc == 244 ||
profileIdc == 44 || profileIdc == 83 || profileIdc == 86 || profileIdc == 118 || profileIdc == 44 || profileIdc == 83 || profileIdc == 86 || profileIdc == 118 || profileIdc == 128){
profileIdc == 128){
// chroma format idc // chroma format idc
char chromaFormatIdc = bs.getUExpGolomb(); char chromaFormatIdc = bs.getUExpGolomb();
if (chromaFormatIdc == 3){result.sep_col_plane = (bs.get(1) == 1);} if (chromaFormatIdc == 3){result.sep_col_plane = (bs.get(1) == 1);}
@ -260,7 +258,6 @@ namespace h264{
result.width = ((result.width * sar_width) / sar_height); result.width = ((result.width * sar_width) / sar_height);
}else{ }else{
result.height = ((result.height * sar_height) / sar_width); result.height = ((result.height * sar_height) / sar_width);
} }
} }
return result; return result;
@ -351,8 +348,7 @@ namespace h264{
bitDepthChromaMinus8 = bs.getUExpGolomb(); bitDepthChromaMinus8 = bs.getUExpGolomb();
derived_bitDepth_C = 8 + bitDepthChromaMinus8; derived_bitDepth_C = 8 + bitDepthChromaMinus8;
derived_qpBdOffset_C = 6 * bitDepthChromaMinus8; derived_qpBdOffset_C = 6 * bitDepthChromaMinus8;
derived_rawMbBits = derived_rawMbBits = 256 * derived_bitDepth_Y + 2 * derived_mbWidthC * derived_mbHeightC * derived_bitDepth_C;
256 * derived_bitDepth_Y + 2 * derived_mbWidthC * derived_mbHeightC * derived_bitDepth_C;
qpprimeYZeroTransformBypassFlag = bs.get(1); qpprimeYZeroTransformBypassFlag = bs.get(1);
seqScalingMatrixPresentFlag = bs.get(1); seqScalingMatrixPresentFlag = bs.get(1);
if (seqScalingMatrixPresentFlag){ if (seqScalingMatrixPresentFlag){
@ -361,8 +357,7 @@ namespace h264{
derived_scalingList4x4Amount = 6; derived_scalingList4x4Amount = 6;
scalingList4x4 = (uint64_t **)malloc(derived_scalingList4x4Amount * sizeof(uint64_t *)); scalingList4x4 = (uint64_t **)malloc(derived_scalingList4x4Amount * sizeof(uint64_t *));
useDefaultScalingMatrix4x4Flag = useDefaultScalingMatrix4x4Flag = (bool *)malloc(derived_scalingList4x4Amount * sizeof(bool));
(bool *)malloc(derived_scalingList4x4Amount * sizeof(bool));
for (int i = 0; i < derived_scalingList4x4Amount; i++){ for (int i = 0; i < derived_scalingList4x4Amount; i++){
scalingList4x4[i] = NULL; scalingList4x4[i] = NULL;
useDefaultScalingMatrix4x4Flag[i] = false; useDefaultScalingMatrix4x4Flag[i] = false;
@ -370,8 +365,7 @@ namespace h264{
derived_scalingList8x8Amount = derived_scalingListSize - 6; derived_scalingList8x8Amount = derived_scalingListSize - 6;
scalingList8x8 = (uint64_t **)malloc(derived_scalingList8x8Amount * sizeof(uint64_t *)); scalingList8x8 = (uint64_t **)malloc(derived_scalingList8x8Amount * sizeof(uint64_t *));
useDefaultScalingMatrix8x8Flag = useDefaultScalingMatrix8x8Flag = (bool *)malloc(derived_scalingList8x8Amount * sizeof(bool));
(bool *)malloc(derived_scalingList8x8Amount * sizeof(bool));
for (int i = 0; i < derived_scalingList8x8Amount; i++){ for (int i = 0; i < derived_scalingList8x8Amount; i++){
scalingList8x8[i] = NULL; scalingList8x8[i] = NULL;
useDefaultScalingMatrix8x8Flag[i] = false; useDefaultScalingMatrix8x8Flag[i] = false;
@ -472,8 +466,7 @@ namespace h264{
out << " -> RawMbBits: " << derived_rawMbBits << std::endl; out << " -> RawMbBits: " << derived_rawMbBits << std::endl;
out << " qpprime_y_zero-transform_bypass_flag: " << (qpprimeYZeroTransformBypassFlag ? 1 : 0) out << " qpprime_y_zero-transform_bypass_flag: " << (qpprimeYZeroTransformBypassFlag ? 1 : 0)
<< std::endl; << std::endl;
out << " seq_scaling_matrix_present_flag: " << (seqScalingMatrixPresentFlag ? 1 : 0) out << " seq_scaling_matrix_present_flag: " << (seqScalingMatrixPresentFlag ? 1 : 0) << std::endl;
<< std::endl;
if (seqScalingMatrixPresentFlag){ if (seqScalingMatrixPresentFlag){
for (int i = 0; i < derived_scalingListSize; i++){ for (int i = 0; i < derived_scalingListSize; i++){
out << " seq_scaling_list_present_flag[" << i out << " seq_scaling_list_present_flag[" << i
@ -503,16 +496,14 @@ namespace h264{
out << " log2_max_frame_num_minus4: " << log2MaxFrameNumMinus4 out << " log2_max_frame_num_minus4: " << log2MaxFrameNumMinus4
<< (log2MaxFrameNumMinus4 >= 13 ? " INVALID" : "") << std::endl; << (log2MaxFrameNumMinus4 >= 13 ? " INVALID" : "") << std::endl;
out << " -> MaxFrameNum: " << derived_maxFrameNum << std::endl; out << " -> MaxFrameNum: " << derived_maxFrameNum << std::endl;
out << " pic_order_cnt_type: " << picOrderCntType << (picOrderCntType >= 3 ? " INVALID" : "") out << " pic_order_cnt_type: " << picOrderCntType << (picOrderCntType >= 3 ? " INVALID" : "") << std::endl;
<< std::endl;
if (!picOrderCntType){ if (!picOrderCntType){
out << " log2_max_pic_order_cnt_lsb_minus4: " << log2MaxPicOrderCntLsbMinus4 out << " log2_max_pic_order_cnt_lsb_minus4: " << log2MaxPicOrderCntLsbMinus4
<< (log2MaxPicOrderCntLsbMinus4 >= 13 ? " INVALID" : "") << std::endl; << (log2MaxPicOrderCntLsbMinus4 >= 13 ? " INVALID" : "") << std::endl;
out << " -> MaxPicOrderCntLsb: " << derived_maxPicOrderCntLsb << std::endl; out << " -> MaxPicOrderCntLsb: " << derived_maxPicOrderCntLsb << std::endl;
} }
out << " max_num_ref_frames: " << maxNumRefFrames << std::endl; out << " max_num_ref_frames: " << maxNumRefFrames << std::endl;
out << " gaps_in_frame_num_value_allowed_flag: " << (gapsInFrameNumValueAllowedFlag ? 1 : 0) out << " gaps_in_frame_num_value_allowed_flag: " << (gapsInFrameNumValueAllowedFlag ? 1 : 0) << std::endl;
<< std::endl;
out << " pic_width_in_mbs_minus_1: " << picWidthInMbsMinus1 << std::endl; out << " pic_width_in_mbs_minus_1: " << picWidthInMbsMinus1 << std::endl;
out << " -> PicWidthInMbs: " << derived_picWidthInMbs << std::endl; out << " -> PicWidthInMbs: " << derived_picWidthInMbs << std::endl;
out << " -> PicWidthInSamples_L: " << derived_picWidthInSamples_L << std::endl; out << " -> PicWidthInSamples_L: " << derived_picWidthInSamples_L << std::endl;
@ -725,17 +716,14 @@ namespace h264{
<< (bottomFieldPicOrderInFramePresentFlag ? 1 : 0) << std::endl; << (bottomFieldPicOrderInFramePresentFlag ? 1 : 0) << std::endl;
out << " num_slice_groups_minus1: " << numSliceGroupsMinus1 << std::endl; out << " num_slice_groups_minus1: " << numSliceGroupsMinus1 << std::endl;
if (numSliceGroupsMinus1 > 0){return;} if (numSliceGroupsMinus1 > 0){return;}
out << " num_ref_idx_10_default_active_minus1: " << numrefIdx10DefaultActiveMinus1 out << " num_ref_idx_10_default_active_minus1: " << numrefIdx10DefaultActiveMinus1 << std::endl;
<< std::endl; out << " num_ref_idx_11_default_active_minus1: " << numrefIdx11DefaultActiveMinus1 << std::endl;
out << " num_ref_idx_11_default_active_minus1: " << numrefIdx11DefaultActiveMinus1
<< std::endl;
out << " weighted_pred_flag: " << (weightedPredFlag ? 1 : 0) << std::endl; out << " weighted_pred_flag: " << (weightedPredFlag ? 1 : 0) << std::endl;
out << " weighted_bipred_idc: " << (uint32_t)weightedBipredIdc << std::endl; out << " weighted_bipred_idc: " << (uint32_t)weightedBipredIdc << std::endl;
out << " pic_init_qp_minus26: " << picInitQpMinus26 << std::endl; out << " pic_init_qp_minus26: " << picInitQpMinus26 << std::endl;
out << " pic_init_qs_minus26: " << picInitQsMinus26 << std::endl; out << " pic_init_qs_minus26: " << picInitQsMinus26 << std::endl;
out << " chroma_qp_index_offset: " << chromaQpIndexOffset << std::endl; out << " chroma_qp_index_offset: " << chromaQpIndexOffset << std::endl;
out << " deblocking_filter_control_present_flag: " << deblockingFilterControlPresentFlag out << " deblocking_filter_control_present_flag: " << deblockingFilterControlPresentFlag << std::endl;
<< std::endl;
out << " constrained_intra_pred_flag: " << constrainedIntraPredFlag << std::endl; out << " constrained_intra_pred_flag: " << constrainedIntraPredFlag << std::endl;
out << " redundant_pic_cnt_present_flag: " << redundantPicCntPresentFlag << std::endl; out << " redundant_pic_cnt_present_flag: " << redundantPicCntPresentFlag << std::endl;
if (status_moreRBSP){ if (status_moreRBSP){
@ -848,8 +836,7 @@ namespace h264{
payload[1 + byteOffset] |= (0x08 >> bitOffset); payload[1 + byteOffset] |= (0x08 >> bitOffset);
payload[2 + byteOffset] &= secondBitmask; payload[2 + byteOffset] &= secondBitmask;
payload[2 + byteOffset] |= (0x08 << (8 - bitOffset)); payload[2 + byteOffset] |= (0x08 << (8 - bitOffset));
INFO_MSG("Translated %.2X to %.2X %.2X", toCopy, payload[1 + byteOffset], INFO_MSG("Translated %.2X to %.2X %.2X", toCopy, payload[1 + byteOffset], payload[2 + byteOffset]);
payload[2 + byteOffset]);
} }
void codedSliceUnit::toPrettyString(std::ostream &out){ void codedSliceUnit::toPrettyString(std::ostream &out){
@ -922,12 +909,10 @@ namespace h264{
uuid.str("x264 encoder configuration"); uuid.str("x264 encoder configuration");
} }
out << " UUID: " << uuid.str() << std::endl; out << " UUID: " << uuid.str() << std::endl;
out << " Payload: " << std::string(payload.data() + payloadOffset + 16, payloadSize - 17) out << " Payload: " << std::string(payload.data() + payloadOffset + 16, payloadSize - 17) << std::endl;
<< std::endl;
}break; }break;
default: default:
out << " Message of type " << payloadType << ", " << payloadSize << " bytes long" out << " Message of type " << payloadType << ", " << payloadSize << " bytes long" << std::endl;
<< std::endl;
} }
} }
@ -1149,8 +1134,7 @@ namespace h264{
out << std::string(indent + 2, ' ') out << std::string(indent + 2, ' ')
<< "aspect_ratio_info_present_flag: " << aspectRatioInfoPresentFlag << std::endl; << "aspect_ratio_info_present_flag: " << aspectRatioInfoPresentFlag << std::endl;
if (aspectRatioInfoPresentFlag){ if (aspectRatioInfoPresentFlag){
out << std::string(indent + 2, ' ') << "aspect_ratio_idc: " << (int32_t)aspectRatioIdc out << std::string(indent + 2, ' ') << "aspect_ratio_idc: " << (int32_t)aspectRatioIdc << std::endl;
<< std::endl;
if (aspectRatioIdc == 255){ if (aspectRatioIdc == 255){
out << std::string(indent + 2, ' ') << "sar_width: " << sarWidth << std::endl; out << std::string(indent + 2, ' ') << "sar_width: " << sarWidth << std::endl;
out << std::string(indent + 2, ' ') << "sar_height: " << sarHeight << std::endl; out << std::string(indent + 2, ' ') << "sar_height: " << sarHeight << std::endl;
@ -1166,16 +1150,14 @@ namespace h264{
<< "video_signal_type_present_flag: " << videoSignalTypePresentFlag << std::endl; << "video_signal_type_present_flag: " << videoSignalTypePresentFlag << std::endl;
if (videoSignalTypePresentFlag){ if (videoSignalTypePresentFlag){
out << std::string(indent + 2, ' ') << "video_format" << videoFormat << std::endl; out << std::string(indent + 2, ' ') << "video_format" << videoFormat << std::endl;
out << std::string(indent + 2, ' ') << "video_full_range_flag" << videoFullRangeFlag out << std::string(indent + 2, ' ') << "video_full_range_flag" << videoFullRangeFlag << std::endl;
<< std::endl;
out << std::string(indent + 2, ' ') << "colour_description_present_flag" out << std::string(indent + 2, ' ') << "colour_description_present_flag"
<< colourDescriptionPresentFlag << std::endl; << colourDescriptionPresentFlag << std::endl;
if (colourDescriptionPresentFlag){ if (colourDescriptionPresentFlag){
out << std::string(indent + 2, ' ') << "colour_primaries" << colourPrimaries << std::endl; out << std::string(indent + 2, ' ') << "colour_primaries" << colourPrimaries << std::endl;
out << std::string(indent + 2, ' ') << "transfer_characteristics" << transferCharacteristics out << std::string(indent + 2, ' ') << "transfer_characteristics" << transferCharacteristics
<< std::endl; << std::endl;
out << std::string(indent + 2, ' ') << "matrix_coefficients" << matrixCoefficients out << std::string(indent + 2, ' ') << "matrix_coefficients" << matrixCoefficients << std::endl;
<< std::endl;
} }
} }
out << std::string(indent + 2, ' ') out << std::string(indent + 2, ' ')
@ -1186,13 +1168,11 @@ namespace h264{
out << std::string(indent + 2, ' ') << "chroma_sample_loc_type_bottom_field" out << std::string(indent + 2, ' ') << "chroma_sample_loc_type_bottom_field"
<< chromaSampleLocTypeBottomField << std::endl; << chromaSampleLocTypeBottomField << std::endl;
} }
out << std::string(indent + 2, ' ') << "timing_info_present_flag: " << timingInfoPresentFlag out << std::string(indent + 2, ' ') << "timing_info_present_flag: " << timingInfoPresentFlag << std::endl;
<< std::endl;
if (timingInfoPresentFlag){ if (timingInfoPresentFlag){
out << std::string(indent + 2, ' ') << "num_units_in_tick: " << numUnitsInTick << std::endl; out << std::string(indent + 2, ' ') << "num_units_in_tick: " << numUnitsInTick << std::endl;
out << std::string(indent + 2, ' ') << "time_scale: " << timeScale << std::endl; out << std::string(indent + 2, ' ') << "time_scale: " << timeScale << std::endl;
out << std::string(indent + 2, ' ') << "fixed_frame_rate_flag: " << fixedFrameRateFlag out << std::string(indent + 2, ' ') << "fixed_frame_rate_flag: " << fixedFrameRateFlag << std::endl;
<< std::endl;
} }
out << std::string(indent + 2, ' ') out << std::string(indent + 2, ' ')
<< "nal_hrd_parameters_present_flag: " << nalHrdParametersPresentFlag << std::endl; << "nal_hrd_parameters_present_flag: " << nalHrdParametersPresentFlag << std::endl;
@ -1202,27 +1182,20 @@ namespace h264{
if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag){ if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag){
out << std::string(indent + 2, ' ') << "low_delay_hrd_flag: " << lowDelayHrdFlag << std::endl; out << std::string(indent + 2, ' ') << "low_delay_hrd_flag: " << lowDelayHrdFlag << std::endl;
} }
out << std::string(indent + 2, ' ') << "pic_struct_present_flag: " << picStructPresentFlag out << std::string(indent + 2, ' ') << "pic_struct_present_flag: " << picStructPresentFlag << std::endl;
<< std::endl;
out << std::string(indent + 2, ' ') << "bitstream_restiction_flag: " << bitstreamRestrictionFlag out << std::string(indent + 2, ' ') << "bitstream_restiction_flag: " << bitstreamRestrictionFlag
<< std::endl; << std::endl;
if (bitstreamRestrictionFlag){ if (bitstreamRestrictionFlag){
out << std::string(indent + 2, ' ') out << std::string(indent + 2, ' ')
<< "motion_vectors_over_pic_boundaries_flag: " << motionVectorsOverPicBoundariesFlag << "motion_vectors_over_pic_boundaries_flag: " << motionVectorsOverPicBoundariesFlag << std::endl;
<< std::endl; out << std::string(indent + 2, ' ') << "max_bytes_per_pic_denom: " << maxBytesPerPicDenom << std::endl;
out << std::string(indent + 2, ' ') << "max_bytes_per_pic_denom: " << maxBytesPerPicDenom out << std::string(indent + 2, ' ') << "max_bits_per_mb_denom: " << maxBitsPerMbDenom << std::endl;
<< std::endl;
out << std::string(indent + 2, ' ') << "max_bits_per_mb_denom: " << maxBitsPerMbDenom
<< std::endl;
out << std::string(indent + 2, ' ') out << std::string(indent + 2, ' ')
<< "log2_max_mv_length_horizontal: " << log2MaxMvLengthHorizontal << std::endl; << "log2_max_mv_length_horizontal: " << log2MaxMvLengthHorizontal << std::endl;
out << std::string(indent + 2, ' ') out << std::string(indent + 2, ' ')
<< "log2_max_mv_length_vertical: " << log2MaxMvLengthVertical << std::endl; << "log2_max_mv_length_vertical: " << log2MaxMvLengthVertical << std::endl;
out << std::string(indent + 2, ' ') << "num_reorder_frames: " << numReorderFrames out << std::string(indent + 2, ' ') << "num_reorder_frames: " << numReorderFrames << std::endl;
<< std::endl; out << std::string(indent + 2, ' ') << "max_dec_frame_buffering: " << maxDecFrameBuffering << std::endl;
out << std::string(indent + 2, ' ') << "max_dec_frame_buffering: " << maxDecFrameBuffering
<< std::endl;
} }
} }
}// namespace h264 }// namespace h264

View file

@ -303,4 +303,3 @@ namespace h264{
nalUnit *nalFactory(FILE *in, bool annexb = true); nalUnit *nalFactory(FILE *in, bool annexb = true);
nalUnit *nalFactory(const char *data, size_t len, size_t &offset, bool annexb = true); nalUnit *nalFactory(const char *data, size_t len, size_t &offset, bool annexb = true);
}// namespace h264 }// namespace h264

View file

@ -1,6 +1,6 @@
#include "h265.h"
#include "bitfields.h" #include "bitfields.h"
#include "defines.h" #include "defines.h"
#include "h265.h"
namespace h265{ namespace h265{
const char *typeToStr(uint8_t type){ const char *typeToStr(uint8_t type){
@ -64,8 +64,7 @@ namespace h265{
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(); for (std::deque<std::string>::iterator nalIt = it->nalUnits.begin(); nalIt != it->nalUnits.end(); nalIt++){
nalIt != it->nalUnits.end(); nalIt++){
nalUnits[it->nalUnitType].insert(*nalIt); nalUnits[it->nalUnitType].insert(*nalIt);
} }
} }
@ -156,8 +155,7 @@ namespace h265{
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;
@ -195,8 +193,7 @@ namespace h265{
} }
} }
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned int maxSubLayersMinus1, std::string printProfileTierLevel(Utils::bitstream &bs, unsigned int maxSubLayersMinus1, size_t indent){
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;
@ -205,10 +202,8 @@ namespace h265{
<< bs.get(32) << std::dec << std::endl; << 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) r << std::string(indent, ' ') << "general_non_packed_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_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;
@ -226,8 +221,7 @@ namespace h265{
if (maxSubLayersMinus1){ if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){ for (int i = maxSubLayersMinus1; i < 8; i++){
r << std::string(indent + 1, ' ') << "reserved_zero_2_bits[" << i << "]: " << bs.get(2) r << std::string(indent + 1, ' ') << "reserved_zero_2_bits[" << i << "]: " << bs.get(2) << std::endl;
<< std::endl;
} }
} }
for (int i = 0; i < maxSubLayersMinus1; i++){ for (int i = 0; i < maxSubLayersMinus1; i++){
@ -238,16 +232,11 @@ namespace h265{
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 r << std::string(indent + 2, ' ') << "sub_layer_profile_compatibility_flags: " << std::hex
<< bs.get(32) << std::dec << std::endl; << bs.get(32) << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1) r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1) << std::endl;
<< std::endl; r << std::string(indent + 2, ' ') << "sub_layer_interlaced_source_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_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_non_packed_constraint_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_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;
@ -256,17 +245,13 @@ namespace h265{
return r.str(); return r.str();
} }
void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox, void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox, unsigned int maxSubLayersMinus1){
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( hvccBox.setGeneralProfileIdc(std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5)));
std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5))); hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() & bs.get(32));
hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() & hvccBox.setGeneralConstraintIndicatorFlags(hvccBox.getGeneralConstraintIndicatorFlags() & bs.get(48));
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()){
@ -309,8 +294,7 @@ namespace h265{
unsigned int maxSubLayers = bs.get(3) + 1; unsigned int maxSubLayers = bs.get(3) + 1;
hvccBox.setNumberOfTemporalLayers( hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
bs.skip(17); bs.skip(17);
@ -326,8 +310,7 @@ namespace h265{
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 r << std::string(indent, ' ') << "vps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl;
<< 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) r << std::string(indent, ' ') << "vps_reserved_0xffff_16bits: " << std::hex << bs.get(16)
<< std::dec << std::endl; << std::dec << std::endl;
@ -347,8 +330,7 @@ namespace h265{
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 r << std::string(indent, ' ') << "vps_num_layer_sets_minus1: " << vps_num_layer_sets_minus1 << std::endl;
<< 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 r << std::string(indent, ' ') << "layer_id_included_flag[" << i << "][" << j
@ -356,8 +338,7 @@ namespace h265{
} }
} }
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) r << std::string(indent, ' ') << "vps_timing_info_present_flag: " << (vps_timing_info ? 1 : 0) << std::endl;
<< std::endl;
return r.str(); return r.str();
} }
@ -420,15 +401,14 @@ namespace h265{
deltaIdxMinus1 = bs.getUExpGolomb(); deltaIdxMinus1 = bs.getUExpGolomb();
r << std::string(indent, ' ') << "delta_idx_minus_1: " << deltaIdxMinus1 << std::endl; r << std::string(indent, ' ') << "delta_idx_minus_1: " << deltaIdxMinus1 << std::endl;
} }
r << std::string(indent, ' ') r << std::string(indent, ' ') << "delta_rps_sign: " << (int)bs.get(1) << std::endl;
<< "delta_rps_sign: " << (int)bs.get(1) << std::endl; r << std::string(indent, ' ') << "abs_delta_rps_minus1: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ')
<< "abs_delta_rps_minus1: " << bs.getUExpGolomb() << std::endl;
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);
r << std::string(indent + 1, ' ') << "used_by_curr_pic_flag[" << j << "]: " << usedByCurrPicFlag << std::endl; r << std::string(indent + 1, ' ') << "used_by_curr_pic_flag[" << j
<< "]: " << usedByCurrPicFlag << std::endl;
if (!usedByCurrPicFlag){ if (!usedByCurrPicFlag){
r << std::string(indent + 1, ' ') << "used_delta_flag[" << j << "]: " << bs.get(1) << std::endl; r << std::string(indent + 1, ' ') << "used_delta_flag[" << j << "]: " << bs.get(1) << std::endl;
} }
@ -492,8 +472,7 @@ 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) r << std::string(indent, ' ') << "aspect_ratio_info_present_flag: " << (aspectRatio ? 1 : 0) << std::endl;
<< 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;
@ -595,39 +574,29 @@ namespace h265{
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 r << std::string(indent, ' ') << "sps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl;
<< 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 r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl
<< printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1); << printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1);
r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb() r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb() << std::endl;
<< 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() r << std::string(indent, ' ') << "pic_width_in_luma_samples: " << bs.getUExpGolomb() << std::endl;
<< std::endl; r << std::string(indent, ' ') << "pic_height_in_luma_samples: " << bs.getUExpGolomb() << 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 r << std::string(indent, ' ') << "conformance_window_flag: " << conformance_window_flag << std::endl;
<< std::endl;
if (conformance_window_flag){ if (conformance_window_flag){
r << std::string(indent, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb() r << std::string(indent, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb() << std::endl;
<< std::endl; r << std::string(indent, ' ') << "conf_window_right_offset: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "conf_window_right_offset: " << bs.getUExpGolomb() r << std::string(indent, ' ') << "conf_window_top_offset: " << bs.getUExpGolomb() << std::endl;
<< std::endl; r << std::string(indent, ' ') << "conf_window_bottom_offset: " << bs.getUExpGolomb() << 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() r << std::string(indent, ' ') << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb() << std::endl;
<< std::endl;
bool subLayerOrdering = bs.get(1); bool subLayerOrdering = bs.get(1);
r << std::string(indent, ' ') r << std::string(indent, ' ')
<< "sps_sub_layer_ordering_info_present_flag: " << subLayerOrdering << std::endl; << "sps_sub_layer_ordering_info_present_flag: " << subLayerOrdering << std::endl;
@ -647,23 +616,18 @@ namespace h265{
<< std::endl; << 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_transform_block_size: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb() r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb() << std::endl;
<< std::endl; r << std::string(indent, ' ') << "max_transform_hierarchy_depth_intra: " << 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 r << std::string(indent, ' ') << "scaling_list_enabled_flag: " << scalingListEnabled << std::endl;
<< std::endl;
if (scalingListEnabled){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) r << std::string(indent, ' ') << "sample_adaptive_offset_enabled_flag: " << bs.get(1) << std::endl;
<< 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){WARN_MSG("Not implemented pcm_enabled in HEVC sps");} if (pcmEnabled){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 r << std::string(indent, ' ') << "num_short_term_ref_pic_sets: " << shortTermPicSets << std::endl;
<< std::endl;
for (int i = 0; i < shortTermPicSets; i++){ for (int i = 0; i < shortTermPicSets; i++){
r << std::string(indent, ' ') << "short_term_ref_pic_set(" << i << "):" << std::endl r << std::string(indent, ' ') << "short_term_ref_pic_set(" << i << "):" << std::endl
<< printShortTermRefPicSet(bs, i, shortTermPicSets, indent + 1); << printShortTermRefPicSet(bs, i, shortTermPicSets, indent + 1);
@ -673,12 +637,10 @@ namespace h265{
<< "long_term_ref_pics_present_flag: " << (longTermRefPics ? 1 : 0) << std::endl; << "long_term_ref_pics_present_flag: " << (longTermRefPics ? 1 : 0) << std::endl;
if (longTermRefPics){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) r << std::string(indent, ' ') << "strong_intra_smoothing_enabled_flag: " << bs.get(1) << std::endl;
<< std::endl;
bool vuiParams = bs.get(1); bool vuiParams = bs.get(1);
r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0) r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0) << std::endl;
<< std::endl;
if (vuiParams){ if (vuiParams){
r << std::string(indent, ' ') << "vui_parameters:" << std::endl r << std::string(indent, ' ') << "vui_parameters:" << std::endl
<< printVuiParameters(bs, indent + 1); << printVuiParameters(bs, indent + 1);
@ -694,8 +656,7 @@ namespace h265{
unsigned int maxSubLayers = bs.get(3) + 1; unsigned int maxSubLayers = bs.get(3) + 1;
hvccBox.setNumberOfTemporalLayers( hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
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);
@ -858,8 +819,7 @@ 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( hvccBox.setMinSpatialSegmentationIdc(std::min((int)hvccBox.getMinSpatialSegmentationIdc(), spatialSegmentIdc));
std::min((int)hvccBox.getMinSpatialSegmentationIdc(), spatialSegmentIdc));
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
bs.getUExpGolomb(); bs.getUExpGolomb();
@ -868,4 +828,3 @@ namespace h265{
} }
} }
}// namespace h265 }// namespace h265

View file

@ -13,10 +13,8 @@ namespace h265{
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, void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox, unsigned long maxSubLayersMinus1);
unsigned long maxSubLayersMinus1); std::string printProfileTierLevel(Utils::bitstream &bs, unsigned long maxSubLayersMinus1, size_t indent);
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned long maxSubLayersMinus1,
size_t indent);
struct metaInfo{ struct metaInfo{
uint64_t width; uint64_t width;
@ -71,4 +69,3 @@ namespace h265{
// NOTE: no ppsUnit, as the only information it contains is parallelism mode, which can be set to // NOTE: no ppsUnit, as the only information it contains is parallelism mode, which can be set to
// 0 for 'unknown' // 0 for 'unknown'
}// namespace h265 }// namespace h265

View file

@ -8,8 +8,8 @@
#include "timing.h" #include "timing.h"
#include "url.h" #include "url.h"
#include "util.h" #include "util.h"
#include <strings.h>
#include <iomanip> #include <iomanip>
#include <strings.h>
/// This constructor creates an empty HTTP::Parser, ready for use for either reading or writing. /// This constructor creates an empty HTTP::Parser, ready for use for either reading or writing.
/// All this constructor does is call HTTP::Parser::Clean(). /// All this constructor does is call HTTP::Parser::Clean().
@ -167,7 +167,8 @@ void HTTP::Parser::SendRequest(Socket::Connection &conn, const std::string &reqb
sendRequest(conn, reqbody.data(), reqbody.size(), allAtOnce); sendRequest(conn, reqbody.data(), reqbody.size(), allAtOnce);
} }
void HTTP::Parser::sendRequest(Socket::Connection &conn, const void * reqbody, const size_t reqbodyLen, bool allAtOnce){ void HTTP::Parser::sendRequest(Socket::Connection &conn, const void *reqbody,
const size_t reqbodyLen, bool allAtOnce){
/// \todo Include GET/POST variable parsing? /// \todo Include GET/POST variable parsing?
if (allAtOnce){ if (allAtOnce){
/// \TODO Make this less duplicated / more pretty. /// \TODO Make this less duplicated / more pretty.
@ -183,7 +184,7 @@ void HTTP::Parser::sendRequest(Socket::Connection &conn, const void * reqbody, c
} }
builder += "\r\n"; builder += "\r\n";
if (reqbodyLen){ if (reqbodyLen){
builder += std::string((char*)reqbody, reqbodyLen); builder += std::string((char *)reqbody, reqbodyLen);
}else{ }else{
builder += body; builder += body;
} }
@ -203,7 +204,7 @@ void HTTP::Parser::sendRequest(Socket::Connection &conn, const void * reqbody, c
} }
conn.SendNow("\r\n", 2); conn.SendNow("\r\n", 2);
if (reqbodyLen){ if (reqbodyLen){
conn.SendNow((char*)reqbody, reqbodyLen); conn.SendNow((char *)reqbody, reqbodyLen);
}else{ }else{
conn.SendNow(body); conn.SendNow(body);
} }
@ -421,11 +422,9 @@ const std::string &HTTP::Parser::GetHeader(const std::string &i) const{
if (headers.count(i)){return headers.at(i);} if (headers.count(i)){return headers.at(i);}
for (std::map<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it){ for (std::map<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it){
if (it->first.length() != i.length()){continue;} if (it->first.length() != i.length()){continue;}
if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){ if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){return it->second;}
return it->second;
}
} }
//Return empty string if not found // Return empty string if not found
static const std::string empty; static const std::string empty;
return empty; return empty;
} }
@ -435,9 +434,7 @@ bool HTTP::Parser::hasHeader(const std::string &i) const{
if (headers.count(i)){return true;} if (headers.count(i)){return true;}
for (std::map<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it){ for (std::map<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it){
if (it->first.length() != i.length()){continue;} if (it->first.length() != i.length()){continue;}
if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){ if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){return true;}
return true;
}
} }
return false; return false;
} }
@ -499,7 +496,7 @@ void HTTP::Parser::SetVar(std::string i, std::string v){
/// returned. If not, as much as can be interpreted is removed and false returned. \param conn The /// returned. If not, as much as can be interpreted is removed and false returned. \param conn The
/// socket to read from. \return True if a whole request or response was read, false otherwise. /// socket to read from. \return True if a whole request or response was read, false otherwise.
bool HTTP::Parser::Read(Socket::Connection &conn, Util::DataCallback &cb){ bool HTTP::Parser::Read(Socket::Connection &conn, Util::DataCallback &cb){
//In this case, we might have a broken connection and need to check if we're done // In this case, we might have a broken connection and need to check if we're done
if (!conn.Received().size()){ if (!conn.Received().size()){
return (parse(conn.Received().get(), cb) && (!possiblyComplete || !conn || !JSON::Value(url).asInt())); return (parse(conn.Received().get(), cb) && (!possiblyComplete || !conn || !JSON::Value(url).asInt()));
} }
@ -708,9 +705,7 @@ bool HTTP::Parser::parse(std::string &HTTPbuffer, Util::DataCallback &cb){
} }
return false; return false;
}else{ }else{
if (protocol.substr(0, 4) == "RTSP" || method.substr(0,4) == "RTSP"){ if (protocol.substr(0, 4) == "RTSP" || method.substr(0, 4) == "RTSP"){return true;}
return true;
}
unsigned int toappend = HTTPbuffer.size(); unsigned int toappend = HTTPbuffer.size();
bool shouldAppend = true; bool shouldAppend = true;
if (bodyCallback){ if (bodyCallback){

View file

@ -39,7 +39,8 @@ namespace HTTP{
std::string &BuildResponse(); std::string &BuildResponse();
std::string &BuildResponse(std::string code, std::string message); std::string &BuildResponse(std::string code, std::string message);
void SendRequest(Socket::Connection &conn, const std::string &reqbody = "", bool allAtOnce = false); void SendRequest(Socket::Connection &conn, const std::string &reqbody = "", bool allAtOnce = false);
void sendRequest(Socket::Connection &conn, const void * body = 0, const size_t bodyLen = 0, bool allAtOnce = false); void sendRequest(Socket::Connection &conn, const void *body = 0, const size_t bodyLen = 0,
bool allAtOnce = false);
void SendResponse(std::string code, std::string message, Socket::Connection &conn); void SendResponse(std::string code, std::string message, Socket::Connection &conn);
void StartResponse(std::string code, std::string message, Parser &request, void StartResponse(std::string code, std::string message, Parser &request,
Socket::Connection &conn, bool bufferAllChunks = false); Socket::Connection &conn, bool bufferAllChunks = false);

View file

@ -1,8 +1,8 @@
/// \file json.cpp Holds all JSON-related code. /// \file json.cpp Holds all JSON-related code.
#include "json.h"
#include "bitfields.h" #include "bitfields.h"
#include "defines.h" #include "defines.h"
#include "json.h"
#include <arpa/inet.h> //for htonl #include <arpa/inet.h> //for htonl
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -274,8 +274,7 @@ std::string JSON::string_escape(const std::string &val){
if ((c & 0xC0) == 0xC0){ if ((c & 0xC0) == 0xC0){
// possible UTF-8 sequence // possible UTF-8 sequence
// check for 2-byte sequence // check for 2-byte sequence
if (((c & 0xE0) == 0XC0) && (i + 1 < val.size()) && if (((c & 0xE0) == 0XC0) && (i + 1 < val.size()) && ((val.data()[i + 1] & 0xC0) == 0x80)){
((val.data()[i + 1] & 0xC0) == 0x80)){
// valid 2-byte sequence // valid 2-byte sequence
out += UTF16(((c & 0x1F) << 6) | (val.data()[i + 1] & 0x3F)); out += UTF16(((c & 0x1F) << 6) | (val.data()[i + 1] & 0x3F));
i += 1; i += 1;
@ -285,15 +284,13 @@ std::string JSON::string_escape(const std::string &val){
if (((c & 0xF0) == 0XE0) && (i + 2 < val.size()) && if (((c & 0xF0) == 0XE0) && (i + 2 < val.size()) &&
((val.data()[i + 1] & 0xC0) == 0x80) && ((val.data()[i + 2] & 0xC0) == 0x80)){ ((val.data()[i + 1] & 0xC0) == 0x80) && ((val.data()[i + 2] & 0xC0) == 0x80)){
// valid 3-byte sequence // valid 3-byte sequence
out += UTF16(((c & 0x1F) << 12) | ((val.data()[i + 1] & 0x3F) << 6) | out += UTF16(((c & 0x1F) << 12) | ((val.data()[i + 1] & 0x3F) << 6) | (val.data()[i + 2] & 0x3F));
(val.data()[i + 2] & 0x3F));
i += 2; i += 2;
break; break;
} }
// check for 4-byte sequence // check for 4-byte sequence
if (((c & 0xF8) == 0XF0) && (i + 3 < val.size()) && if (((c & 0xF8) == 0XF0) && (i + 3 < val.size()) && ((val.data()[i + 1] & 0xC0) == 0x80) &&
((val.data()[i + 1] & 0xC0) == 0x80) && ((val.data()[i + 2] & 0xC0) == 0x80) && ((val.data()[i + 2] & 0xC0) == 0x80) && ((val.data()[i + 3] & 0xC0) == 0x80)){
((val.data()[i + 3] & 0xC0) == 0x80)){
// valid 4-byte sequence // valid 4-byte sequence
out += UTF16(((c & 0x1F) << 18) | ((val.data()[i + 1] & 0x3F) << 12) | out += UTF16(((c & 0x1F) << 18) | ((val.data()[i + 1] & 0x3F) << 12) |
((val.data()[i + 2] & 0x3F) << 6) | (val.data()[i + 3] & 0x3F)); ((val.data()[i + 2] & 0x3F) << 6) | (val.data()[i + 3] & 0x3F));
@ -614,9 +611,9 @@ JSON::Value &JSON::Value::assignFrom(const Value &rhs, const std::set<std::strin
/// Extends this JSON::Value object with the given JSON::Value object, skipping given member(s) recursively. /// Extends this JSON::Value object with the given JSON::Value object, skipping given member(s) recursively.
JSON::Value &JSON::Value::extend(const Value &rhs, const std::set<std::string> &skip){ JSON::Value &JSON::Value::extend(const Value &rhs, const std::set<std::string> &skip){
//Null values turn into objects automatically for sanity reasons // Null values turn into objects automatically for sanity reasons
if (myType == EMPTY){myType = OBJECT;} if (myType == EMPTY){myType = OBJECT;}
//Abort if either value is not an object // Abort if either value is not an object
if (myType != rhs.myType || myType != OBJECT){return *this;} if (myType != rhs.myType || myType != OBJECT){return *this;}
jsonForEachConst(rhs, i){ jsonForEachConst(rhs, i){
if (!skip.count(i.key())){ if (!skip.count(i.key())){
@ -919,8 +916,7 @@ void JSON::Value::sendTo(Socket::Connection &socket) const{
unsigned int size = 16; unsigned int size = 16;
if (objVal.size() > 0){ if (objVal.size() > 0){
jsonForEachConst(*this, i){ jsonForEachConst(*this, i){
if (i.key().size() > 0 && i.key() != "trackid" && i.key() != "time" && if (i.key().size() > 0 && i.key() != "trackid" && i.key() != "time" && i.key() != "datatype"){
i.key() != "datatype"){
size += 2 + i.key().size() + i->packedSize(); size += 2 + i.key().size() + i->packedSize();
} }
} }
@ -937,8 +933,7 @@ void JSON::Value::sendTo(Socket::Connection &socket) const{
socket.SendNow("\340", 1); socket.SendNow("\340", 1);
if (objVal.size() > 0){ if (objVal.size() > 0){
jsonForEachConst(*this, i){ jsonForEachConst(*this, i){
if (i.key().size() > 0 && i.key() != "trackid" && i.key() != "time" && if (i.key().size() > 0 && i.key() != "trackid" && i.key() != "time" && i.key() != "datatype"){
i.key() != "datatype"){
char sizebuffer[2] ={0, 0}; char sizebuffer[2] ={0, 0};
sizebuffer[0] = (i.key().size() >> 8) & 0xFF; sizebuffer[0] = (i.key().size() >> 8) & 0xFF;
sizebuffer[1] = i.key().size() & 0xFF; sizebuffer[1] = i.key().size() & 0xFF;
@ -1395,16 +1390,14 @@ void JSON::fromDTMI(const char *data, uint64_t len, uint32_t &i, JSON::Value &re
case 0xFF: // also object case 0xFF: // also object
case 0xE0:{// object case 0xE0:{// object
++i; ++i;
while (data[i] + data[i + 1] != 0 && while (data[i] + data[i + 1] != 0 && i < len){// while not encountering 0x0000 (we assume 0x0000EE)
i < len){// while not encountering 0x0000 (we assume 0x0000EE)
if (i + 2 >= len){return;} if (i + 2 >= len){return;}
uint16_t tmpi = Bit::btohs(data + i); // set tmpi to the UTF-8 length uint16_t tmpi = Bit::btohs(data + i); // set tmpi to the UTF-8 length
std::string tmpstr = std::string(data + i + 2, tmpi); // set the string data std::string tmpstr = std::string(data + i + 2, tmpi); // set the string data
i += tmpi + 2; // skip length+size forwards i += tmpi + 2; // skip length+size forwards
ret[tmpstr].null(); ret[tmpstr].null();
fromDTMI( fromDTMI(data, len, i,
data, len, i, ret[tmpstr]); // add content, recursively parsed, updating i, setting indice to tmpstr
ret[tmpstr]); // add content, recursively parsed, updating i, setting indice to tmpstr
} }
i += 3; // skip 0x0000EE i += 3; // skip 0x0000EE
return; return;
@ -1412,8 +1405,7 @@ void JSON::fromDTMI(const char *data, uint64_t len, uint32_t &i, JSON::Value &re
} }
case 0x0A:{// array case 0x0A:{// array
++i; ++i;
while (data[i] + data[i + 1] != 0 && while (data[i] + data[i + 1] != 0 && i < len){// while not encountering 0x0000 (we assume 0x0000EE)
i < len){// while not encountering 0x0000 (we assume 0x0000EE)
JSON::Value tval; JSON::Value tval;
fromDTMI(data, len, i, tval); // add content, recursively parsed, updating i fromDTMI(data, len, i, tval); // add content, recursively parsed, updating i
ret.append(tval); ret.append(tval);
@ -1471,4 +1463,3 @@ JSON::Value JSON::fromDTMI2(const char *data, uint64_t len, uint32_t &i){
fromDTMI2(data, len, i, ret); fromDTMI2(data, len, i, ret);
return ret; return ret;
} }

View file

@ -159,4 +159,3 @@ namespace JSON{
#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 }// namespace JSON

View file

@ -1221,4 +1221,3 @@ namespace Encodings{
} }
}// namespace Encodings }// namespace Encodings

View file

@ -1,14 +1,12 @@
#include <string> #include <string>
namespace Encodings { namespace Encodings{
class ISO639{ class ISO639{
public: public:
static std::string decode(const std::string & lang); static std::string decode(const std::string &lang);
static std::string twoToThree(const std::string & lang); static std::string twoToThree(const std::string &lang);
static std::string encode(const std::string & lang); static std::string encode(const std::string &lang);
}; };
}// namespace Encodings
}

File diff suppressed because it is too large Load diff

227
lib/mp4.h
View file

@ -1,127 +1,122 @@
#pragma once #pragma once
#include "dtsc.h"
#include "json.h"
#include <algorithm>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>
#include <stdint.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <stdint.h>
#include <sstream>
#include <deque>
#include <algorithm>
#include <vector>
#include "json.h"
#include "dtsc.h"
/// Contains all MP4 format related code. /// Contains all MP4 format related code.
namespace MP4 { namespace MP4{
std::string readBoxType(FILE * newData); std::string readBoxType(FILE *newData);
bool skipBox(FILE * newData); bool skipBox(FILE *newData);
uint64_t calcBoxSize(const char * p); uint64_t calcBoxSize(const char *p);
class Box{
public:
Box(char *datapointer = 0, bool manage = true);
Box(const Box &rs);
Box &operator=(const Box &rs);
~Box();
operator bool() const{return data && data_size >= 8 && !isType("erro");}
void copyFrom(const Box &rs);
class Box { std::string getType() const;
public: bool isType(const char *boxType) const;
Box(char * datapointer = 0, bool manage = true); bool read(FILE *newData);
Box(const Box & rs); bool read(std::string &newData);
Box & operator = (const Box & rs);
~Box(); uint64_t boxedSize() const;
operator bool() const { uint64_t payloadSize() const;
return data && data_size >= 8 && !isType("erro"); char *asBox();
char *payload();
void clear();
std::string toPrettyString(uint32_t indent = 0) const;
protected:
// integer functions
void setInt8(char newData, size_t index);
char getInt8(size_t index);
char getInt8(size_t index) const;
void setInt16(short newData, size_t index);
short getInt16(size_t index);
short getInt16(size_t index) const;
void setInt24(uint32_t newData, size_t index);
uint32_t getInt24(size_t index);
uint32_t getInt24(size_t index) const;
void setInt32(uint32_t newData, size_t index);
uint32_t getInt32(size_t index);
uint32_t getInt32(size_t index) const;
void setInt64(uint64_t newData, size_t index);
uint64_t getInt64(size_t index);
uint64_t getInt64(size_t index) const;
// string functions
void setString(std::string newData, size_t index);
void setString(char *newData, size_t size, size_t index);
char *getString(size_t index);
size_t getStringLen(size_t index) const;
// box functions
Box &getBox(size_t index);
size_t getBoxLen(size_t index) const;
void setBox(Box &newEntry, size_t index);
// data functions
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
char *data; ///< Holds the data of this box
unsigned int data_size; ///< Currently reserved size
bool managed; ///< If false, will not attempt to resize/free the data pointer.
unsigned int payloadOffset; ///< The offset of the payload with regards to the data
};
// Box Class
class fullBox : public Box{
public:
fullBox();
void setVersion(char newVersion);
char getVersion() const;
void setFlags(uint32_t newFlags);
uint32_t getFlags() const;
std::string toPrettyString(uint32_t indent = 0) const;
};
class containerBox : public Box{
public:
containerBox();
uint32_t getContentCount();
void setContent(Box &newContent, uint32_t no);
Box &getContent(uint32_t no, bool unsafe = false);
std::string toPrettyString(uint32_t indent = 0);
Box getChild(const char *boxName);
template <typename T> T getChild(){
T a;
MP4::Box r = getChild(a.getType().c_str());
return (T &)r;
}
std::deque<Box> getChildren(const char *boxName);
template <typename T> std::deque<T> getChildren(){
T a;
std::deque<Box> tmpRes = getChildren(a.getType().c_str());
std::deque<T> res;
for (std::deque<Box>::iterator it = tmpRes.begin(); it != tmpRes.end(); it++){
res.push_back((T &)*it);
} }
void copyFrom(const Box & rs); return res;
}
std::string getType() const;
bool isType(const char * boxType) const;
bool read(FILE * newData);
bool read(std::string & newData);
uint64_t boxedSize() const;
uint64_t payloadSize() const;
char * asBox();
char * payload();
void clear();
std::string toPrettyString(uint32_t indent = 0) const;
protected:
//integer functions
void setInt8(char newData, size_t index);
char getInt8(size_t index);
char getInt8(size_t index) const;
void setInt16(short newData, size_t index);
short getInt16(size_t index);
short getInt16(size_t index) const;
void setInt24(uint32_t newData, size_t index);
uint32_t getInt24(size_t index);
uint32_t getInt24(size_t index) const;
void setInt32(uint32_t newData, size_t index);
uint32_t getInt32(size_t index);
uint32_t getInt32(size_t index) const;
void setInt64(uint64_t newData, size_t index);
uint64_t getInt64(size_t index);
uint64_t getInt64(size_t index) const;
//string functions
void setString(std::string newData, size_t index);
void setString(char * newData, size_t size, size_t index);
char * getString(size_t index);
size_t getStringLen(size_t index) const;
//box functions
Box & getBox(size_t index);
size_t getBoxLen(size_t index) const;
void setBox(Box & newEntry, size_t index);
//data functions
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
char * data; ///< Holds the data of this box
unsigned int data_size; ///< Currently reserved size
bool managed; ///< If false, will not attempt to resize/free the data pointer.
unsigned int payloadOffset; ///<The offset of the payload with regards to the data
};
//Box Class
class fullBox: public Box {
public:
fullBox();
void setVersion(char newVersion);
char getVersion() const;
void setFlags(uint32_t newFlags);
uint32_t getFlags() const;
std::string toPrettyString(uint32_t indent = 0) const ;
}; };
class containerBox: public Box { class containerFullBox : public fullBox{
public: public:
containerBox(); uint32_t getContentCount();
uint32_t getContentCount(); void setContent(Box &newContent, uint32_t no);
void setContent(Box & newContent, uint32_t no); Box &getContent(uint32_t no);
Box & getContent(uint32_t no, bool unsafe = false); std::string toPrettyCFBString(uint32_t indent, std::string boxName);
std::string toPrettyString(uint32_t indent = 0);
Box getChild(const char * boxName);
template <typename T>
T getChild(){
T a;
MP4::Box r = getChild(a.getType().c_str());
return (T&)r;
}
std::deque<Box> getChildren(const char * boxName);
template <typename T>
std::deque<T> getChildren(){
T a;
std::deque<Box> tmpRes = getChildren(a.getType().c_str());
std::deque<T> res;
for (std::deque<Box>::iterator it = tmpRes.begin(); it != tmpRes.end(); it++){
res.push_back((T&)*it);
}
return res;
}
}; };
}// namespace MP4
class containerFullBox: public fullBox {
public:
uint32_t getContentCount();
void setContent(Box & newContent, uint32_t no);
Box & getContent(uint32_t no);
std::string toPrettyCFBString(uint32_t indent, std::string boxName);
};
}

File diff suppressed because it is too large Load diff

View file

@ -2,138 +2,137 @@
#include "mp4.h" #include "mp4.h"
#include <stdint.h> #include <stdint.h>
namespace MP4 { namespace MP4{
//class Box; // class Box;
struct afrt_runtable { struct afrt_runtable{
uint32_t firstFragment; uint32_t firstFragment;
uint64_t firstTimestamp; uint64_t firstTimestamp;
uint32_t duration; uint32_t duration;
uint32_t discontinuity; uint32_t discontinuity;
}; };
//fragmentRun // fragmentRun
/// AFRT Box class /// AFRT Box class
class AFRT: public Box { class AFRT : public Box{
public: public:
AFRT(); AFRT();
void setVersion(char newVersion); void setVersion(char newVersion);
uint32_t getVersion(); uint32_t getVersion();
void setUpdate(uint32_t newUpdate); void setUpdate(uint32_t newUpdate);
uint32_t getUpdate(); uint32_t getUpdate();
void setTimeScale(uint32_t newScale); void setTimeScale(uint32_t newScale);
uint32_t getTimeScale(); uint32_t getTimeScale();
uint32_t getQualityEntryCount(); uint32_t getQualityEntryCount();
void setQualityEntry(std::string & newQuality, uint32_t no); void setQualityEntry(std::string &newQuality, uint32_t no);
const char * getQualityEntry(uint32_t no); const char *getQualityEntry(uint32_t no);
uint32_t getFragmentRunCount(); uint32_t getFragmentRunCount();
void setFragmentRun(afrt_runtable newRun, uint32_t no); void setFragmentRun(afrt_runtable newRun, uint32_t no);
afrt_runtable getFragmentRun(uint32_t no); afrt_runtable getFragmentRun(uint32_t no);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
//AFRT Box // AFRT Box
struct asrt_runtable { struct asrt_runtable{
uint32_t firstSegment; uint32_t firstSegment;
uint32_t fragmentsPerSegment; uint32_t fragmentsPerSegment;
}; };
/// ASRT Box class /// ASRT Box class
class ASRT: public Box { class ASRT : public Box{
public: public:
ASRT(); ASRT();
void setVersion(char newVersion); void setVersion(char newVersion);
uint32_t getVersion(); uint32_t getVersion();
void setUpdate(uint32_t newUpdate); void setUpdate(uint32_t newUpdate);
uint32_t getUpdate(); uint32_t getUpdate();
uint32_t getQualityEntryCount(); uint32_t getQualityEntryCount();
void setQualityEntry(std::string & newQuality, uint32_t no); void setQualityEntry(std::string &newQuality, uint32_t no);
const char * getQualityEntry(uint32_t no); const char *getQualityEntry(uint32_t no);
uint32_t getSegmentRunEntryCount(); uint32_t getSegmentRunEntryCount();
void setSegmentRun(uint32_t firstSegment, uint32_t fragmentsPerSegment, uint32_t no); void setSegmentRun(uint32_t firstSegment, uint32_t fragmentsPerSegment, uint32_t no);
asrt_runtable getSegmentRun(uint32_t no); asrt_runtable getSegmentRun(uint32_t no);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
//ASRT Box // ASRT Box
/// ABST Box class /// ABST Box class
class ABST: public Box { class ABST : public Box{
public: public:
ABST(); ABST();
void setVersion(char newVersion); void setVersion(char newVersion);
char getVersion(); char getVersion();
void setFlags(uint32_t newFlags); void setFlags(uint32_t newFlags);
uint32_t getFlags(); uint32_t getFlags();
void setBootstrapinfoVersion(uint32_t newVersion); void setBootstrapinfoVersion(uint32_t newVersion);
uint32_t getBootstrapinfoVersion(); uint32_t getBootstrapinfoVersion();
void setProfile(char newProfile); void setProfile(char newProfile);
char getProfile(); char getProfile();
void setLive(bool newLive); void setLive(bool newLive);
bool getLive(); bool getLive();
void setUpdate(bool newUpdate); void setUpdate(bool newUpdate);
bool getUpdate(); bool getUpdate();
void setTimeScale(uint32_t newTimeScale); void setTimeScale(uint32_t newTimeScale);
uint32_t getTimeScale(); uint32_t getTimeScale();
void setCurrentMediaTime(uint64_t newTime); void setCurrentMediaTime(uint64_t newTime);
uint64_t getCurrentMediaTime(); uint64_t getCurrentMediaTime();
void setSmpteTimeCodeOffset(uint64_t newTime); void setSmpteTimeCodeOffset(uint64_t newTime);
uint64_t getSmpteTimeCodeOffset(); uint64_t getSmpteTimeCodeOffset();
void setMovieIdentifier(std::string & newIdentifier); void setMovieIdentifier(std::string &newIdentifier);
char * getMovieIdentifier(); char *getMovieIdentifier();
uint32_t getServerEntryCount(); uint32_t getServerEntryCount();
void setServerEntry(std::string & entry, uint32_t no); void setServerEntry(std::string &entry, uint32_t no);
const char * getServerEntry(uint32_t no); const char *getServerEntry(uint32_t no);
uint32_t getQualityEntryCount(); uint32_t getQualityEntryCount();
void setQualityEntry(std::string & entry, uint32_t no); void setQualityEntry(std::string &entry, uint32_t no);
const char * getQualityEntry(uint32_t no); const char *getQualityEntry(uint32_t no);
void setDrmData(std::string newDrm); void setDrmData(std::string newDrm);
char * getDrmData(); char *getDrmData();
void setMetaData(std::string newMetaData); void setMetaData(std::string newMetaData);
char * getMetaData(); char *getMetaData();
uint32_t getSegmentRunTableCount(); uint32_t getSegmentRunTableCount();
void setSegmentRunTable(ASRT & table, uint32_t no); void setSegmentRunTable(ASRT &table, uint32_t no);
ASRT & getSegmentRunTable(uint32_t no); ASRT &getSegmentRunTable(uint32_t no);
uint32_t getFragmentRunTableCount(); uint32_t getFragmentRunTableCount();
void setFragmentRunTable(AFRT & table, uint32_t no); void setFragmentRunTable(AFRT &table, uint32_t no);
AFRT & getFragmentRunTable(uint32_t no); AFRT &getFragmentRunTable(uint32_t no);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
//ABST Box // ABST Box
struct afraentry { struct afraentry{
uint64_t time; uint64_t time;
uint64_t offset; uint64_t offset;
}; };
struct globalafraentry { struct globalafraentry{
uint64_t time; uint64_t time;
uint32_t segment; uint32_t segment;
uint32_t fragment; uint32_t fragment;
uint64_t afraoffset; uint64_t afraoffset;
uint64_t offsetfromafra; uint64_t offsetfromafra;
}; };
class AFRA: public Box { class AFRA : public Box{
public: public:
AFRA(); AFRA();
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);
uint32_t getFlags(); uint32_t getFlags();
void setLongIDs(bool newVal); void setLongIDs(bool newVal);
bool getLongIDs(); bool getLongIDs();
void setLongOffsets(bool newVal); void setLongOffsets(bool newVal);
bool getLongOffsets(); bool getLongOffsets();
void setGlobalEntries(bool newVal); void setGlobalEntries(bool newVal);
bool getGlobalEntries(); bool getGlobalEntries();
void setTimeScale(uint32_t newVal); void setTimeScale(uint32_t newVal);
uint32_t getTimeScale(); uint32_t getTimeScale();
uint32_t getEntryCount(); uint32_t getEntryCount();
void setEntry(afraentry newEntry, uint32_t no); void setEntry(afraentry newEntry, uint32_t no);
afraentry getEntry(uint32_t no); afraentry getEntry(uint32_t no);
uint32_t getGlobalEntryCount(); uint32_t getGlobalEntryCount();
void setGlobalEntry(globalafraentry newEntry, uint32_t no); void setGlobalEntry(globalafraentry newEntry, uint32_t no);
globalafraentry getGlobalEntry(uint32_t no); globalafraentry getGlobalEntry(uint32_t no);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
} }// namespace MP4

View file

@ -1,70 +1,54 @@
#include "mp4_dash.h"
#include "defines.h" #include "defines.h"
#include "mp4_dash.h"
namespace MP4 { namespace MP4{
SIDX::SIDX() { SIDX::SIDX(){
memcpy(data + 4, "sidx", 4); memcpy(data + 4, "sidx", 4);
setVersion(0); setVersion(0);
setFlags(0); setFlags(0);
} }
void SIDX::setReferenceID(uint32_t newReferenceID) { void SIDX::setReferenceID(uint32_t newReferenceID){setInt32(newReferenceID, 4);}
setInt32(newReferenceID, 4);
}
uint32_t SIDX::getReferenceID() { uint32_t SIDX::getReferenceID(){return getInt32(4);}
return getInt32(4);
}
void SIDX::setTimescale(uint32_t newTimescale) { void SIDX::setTimescale(uint32_t newTimescale){setInt32(newTimescale, 8);}
setInt32(newTimescale, 8);
}
uint32_t SIDX::getTimescale() { uint32_t SIDX::getTimescale(){return getInt32(8);}
return getInt32(8);
}
void SIDX::setEarliestPresentationTime(uint64_t newEarliestPresentationTime) { void SIDX::setEarliestPresentationTime(uint64_t newEarliestPresentationTime){
if (getVersion() == 0) { if (getVersion() == 0){
setInt32(newEarliestPresentationTime, 12); setInt32(newEarliestPresentationTime, 12);
} else { }else{
setInt64(newEarliestPresentationTime, 12); setInt64(newEarliestPresentationTime, 12);
} }
} }
uint64_t SIDX::getEarliestPresentationTime() { uint64_t SIDX::getEarliestPresentationTime(){
if (getVersion() == 0) { if (getVersion() == 0){return getInt32(12);}
return getInt32(12);
}
return getInt64(12); return getInt64(12);
} }
void SIDX::setFirstOffset(uint64_t newFirstOffset) { void SIDX::setFirstOffset(uint64_t newFirstOffset){
if (getVersion() == 0) { if (getVersion() == 0){
setInt32(newFirstOffset, 16); setInt32(newFirstOffset, 16);
} else { }else{
setInt64(newFirstOffset, 20); setInt64(newFirstOffset, 20);
} }
} }
uint64_t SIDX::getFirstOffset() { uint64_t SIDX::getFirstOffset(){
if (getVersion() == 0) { if (getVersion() == 0){return getInt32(16);}
return getInt32(16);
}
return getInt64(20); return getInt64(20);
} }
uint16_t SIDX::getReferenceCount() { uint16_t SIDX::getReferenceCount(){
if (getVersion() == 0) { if (getVersion() == 0){return getInt16(22);}
return getInt16(22);
}
return getInt16(30); return getInt16(30);
} }
void SIDX::setReference(sidxReference & newRef, size_t index) { void SIDX::setReference(sidxReference &newRef, size_t index){
if (index >= getReferenceCount()) { if (index >= getReferenceCount()){setInt16(index + 1, (getVersion() == 0 ? 22 : 30));}
setInt16(index + 1, (getVersion() == 0 ? 22 : 30));
}
uint32_t offset = 24 + (index * 12) + (getVersion() == 0 ? 0 : 8); uint32_t offset = 24 + (index * 12) + (getVersion() == 0 ? 0 : 8);
uint32_t tmp = (newRef.referenceType ? 0x80000000 : 0) | newRef.referencedSize; uint32_t tmp = (newRef.referenceType ? 0x80000000 : 0) | newRef.referencedSize;
setInt32(tmp, offset); setInt32(tmp, offset);
@ -73,9 +57,9 @@ namespace MP4 {
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()){
DEVEL_MSG("Warning, attempt to obtain reference out of bounds"); DEVEL_MSG("Warning, attempt to obtain reference out of bounds");
return result; return result;
} }
@ -91,59 +75,59 @@ namespace MP4 {
return result; return result;
} }
std::string SIDX::toPrettyString(uint32_t indent) { std::string SIDX::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[sidx] Segment Index Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[sidx] Segment Index Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "ReferenceID " << getReferenceID() << std::endl; r << std::string(indent + 1, ' ') << "ReferenceID " << getReferenceID() << std::endl;
r << std::string(indent + 1, ' ') << "Timescale " << getTimescale() << std::endl; r << std::string(indent + 1, ' ') << "Timescale " << getTimescale() << std::endl;
r << std::string(indent + 1, ' ') << "EarliestPresentationTime " << getEarliestPresentationTime() << std::endl; r << std::string(indent + 1, ' ') << "EarliestPresentationTime "
r << std::string(indent + 1, ' ') << "FirstOffset " << getFirstOffset() << std::endl; << getEarliestPresentationTime() << std::endl;
r << std::string(indent + 1, ' ') << "References [" << getReferenceCount() << "]" << std::endl; r << std::string(indent + 1, ' ') << "FirstOffset " << getFirstOffset() << std::endl;
for (int i = 0; i < getReferenceCount(); i++) { r << std::string(indent + 1, ' ') << "References [" << getReferenceCount() << "]" << std::endl;
for (int i = 0; i < getReferenceCount(); i++){
sidxReference tmp = getReference(i); sidxReference tmp = getReference(i);
r << std::string(indent + 2, ' ') << "[" << i << "]" << std::endl; r << std::string(indent + 2, ' ') << "[" << i << "]" << std::endl;
r << std::string(indent + 3, ' ') << "ReferenceType " << (int)tmp.referenceType << std::endl; r << std::string(indent + 3, ' ') << "ReferenceType " << (int)tmp.referenceType << std::endl;
r << std::string(indent + 3, ' ') << "ReferencedSize " << tmp.referencedSize << std::endl; r << std::string(indent + 3, ' ') << "ReferencedSize " << tmp.referencedSize << std::endl;
r << std::string(indent + 3, ' ') << "SubSegmentDuration " << tmp.subSegmentDuration << std::endl; r << std::string(indent + 3, ' ') << "SubSegmentDuration " << tmp.subSegmentDuration << std::endl;
r << std::string(indent + 3, ' ') << "StartsWithSAP " << (int)tmp.sapStart << std::endl; r << std::string(indent + 3, ' ') << "StartsWithSAP " << (int)tmp.sapStart << std::endl;
r << std::string(indent + 3, ' ') << "SAP Type " << (int)tmp.sapType << std::endl; r << std::string(indent + 3, ' ') << "SAP Type " << (int)tmp.sapType << std::endl;
r << std::string(indent + 3, ' ') << "SAP DeltaTime " << tmp.sapDeltaTime << std::endl; r << std::string(indent + 3, ' ') << "SAP DeltaTime " << tmp.sapDeltaTime << std::endl;
} }
return r.str(); return r.str();
} }
TFDT::TFDT() { TFDT::TFDT(){
memcpy(data + 4, "tfdt", 4); memcpy(data + 4, "tfdt", 4);
setVersion(1); setVersion(1);
setFlags(0); setFlags(0);
setBaseMediaDecodeTime(0); setBaseMediaDecodeTime(0);
} }
void TFDT::setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime) { void TFDT::setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime){
if (getVersion() == 1) { if (getVersion() == 1){
setInt64(newBaseMediaDecodeTime, 4); setInt64(newBaseMediaDecodeTime, 4);
} else { }else{
setInt32(newBaseMediaDecodeTime, 4); setInt32(newBaseMediaDecodeTime, 4);
} }
} }
uint64_t TFDT::getBaseMediaDecodeTime() { uint64_t TFDT::getBaseMediaDecodeTime(){
if (getVersion() == 1) { if (getVersion() == 1){return getInt64(4);}
return getInt64(4);
}
return getInt32(4); return getInt32(4);
} }
std::string TFDT::toPrettyString(uint32_t indent) { std::string TFDT::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[tfdt] Track Fragment Base Media Decode Time Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[tfdt] Track Fragment Base Media Decode Time Box ("
<< boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "BaseMediaDecodeTime " << getBaseMediaDecodeTime() << std::endl; r << std::string(indent + 1, ' ') << "BaseMediaDecodeTime " << getBaseMediaDecodeTime() << std::endl;
return r.str(); return r.str();
} }
IODS::IODS() { IODS::IODS(){
memcpy(data + 4, "iods", 4); memcpy(data + 4, "iods", 4);
setVersion(0); setVersion(0);
setFlags(0); setFlags(0);
@ -157,85 +141,58 @@ namespace MP4 {
setODGraphicsLevel(0xFF); setODGraphicsLevel(0xFF);
} }
void IODS::setIODTypeTag(char value) { void IODS::setIODTypeTag(char value){setInt8(value, 4);}
setInt8(value, 4);
}
char IODS::getIODTypeTag() { char IODS::getIODTypeTag(){return getInt8(4);}
return getInt8(4);
}
void IODS::setDescriptorTypeLength(char length) { void IODS::setDescriptorTypeLength(char length){setInt8(length, 5);}
setInt8(length, 5);
}
char IODS::getDescriptorTypeLength() { char IODS::getDescriptorTypeLength(){return getInt8(5);}
return getInt8(5);
}
void IODS::setODID(short id) { void IODS::setODID(short id){setInt16(id, 6);}
setInt16(id, 6);
}
short IODS::getODID() { short IODS::getODID(){return getInt16(6);}
return getInt16(6);
}
void IODS::setODProfileLevel(char value) { void IODS::setODProfileLevel(char value){setInt8(value, 8);}
setInt8(value, 8);
}
char IODS::getODProfileLevel() { char IODS::getODProfileLevel(){return getInt8(8);}
return getInt8(8);
}
void IODS::setODSceneLevel(char value) { void IODS::setODSceneLevel(char value){setInt8(value, 9);}
setInt8(value, 9);
}
char IODS::getODSceneLevel() { char IODS::getODSceneLevel(){return getInt8(9);}
return getInt8(9);
}
void IODS::setODAudioLevel(char value) { void IODS::setODAudioLevel(char value){setInt8(value, 10);}
setInt8(value, 10);
}
char IODS::getODAudioLevel() { char IODS::getODAudioLevel(){return getInt8(10);}
return getInt8(10);
}
void IODS::setODVideoLevel(char value) { void IODS::setODVideoLevel(char value){setInt8(value, 11);}
setInt8(value, 11);
}
char IODS::getODVideoLevel() { char IODS::getODVideoLevel(){return getInt8(11);}
return getInt8(11);
}
void IODS::setODGraphicsLevel(char value) { void IODS::setODGraphicsLevel(char value){setInt8(value, 12);}
setInt8(value, 12);
}
char IODS::getODGraphicsLevel() { char IODS::getODGraphicsLevel(){return getInt8(12);}
return getInt8(12);
}
std::string IODS::toPrettyString(uint32_t indent){
std::string IODS::toPrettyString(uint32_t indent) {
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[iods] IODS Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[iods] IODS Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 2, ' ') << "IOD Type Tag: " << std::hex << std::setw(2) << std::setfill('0') << (int)getIODTypeTag() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "IOD Type Tag: " << std::hex << std::setw(2)
r << std::string(indent + 2, ' ') << "DescriptorTypeLength: " << std::hex << std::setw(2) << std::setfill('0') << (int)getDescriptorTypeLength() << std::dec << std::endl; << std::setfill('0') << (int)getIODTypeTag() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD ID: " << std::hex << std::setw(4) << std::setfill('0') << (int)getODID() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "DescriptorTypeLength: " << std::hex << std::setw(2)
r << std::string(indent + 2, ' ') << "OD Profile Level: " << std::hex << std::setw(2) << std::setfill('0') << (int)getODProfileLevel() << std::dec << std::endl; << std::setfill('0') << (int)getDescriptorTypeLength() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD Scene Level: " << std::hex << std::setw(2) << std::setfill('0') << (int)getODSceneLevel() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "OD ID: " << std::hex << std::setw(4) << std::setfill('0')
r << std::string(indent + 2, ' ') << "OD Audio Level: " << std::hex << std::setw(2) << std::setfill('0') << (int)getODAudioLevel() << std::dec << std::endl; << (int)getODID() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD Video Level: " << std::hex << std::setw(2) << std::setfill('0') << (int)getODVideoLevel() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "OD Profile Level: " << std::hex << std::setw(2)
r << std::string(indent + 2, ' ') << "OD Graphics Level: " << std::hex << std::setw(2) << std::setfill('0') << (int)getODGraphicsLevel() << std::dec << std::endl; << std::setfill('0') << (int)getODProfileLevel() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD Scene Level: " << std::hex << std::setw(2)
<< std::setfill('0') << (int)getODSceneLevel() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD Audio Level: " << std::hex << std::setw(2)
<< std::setfill('0') << (int)getODAudioLevel() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD Video Level: " << std::hex << std::setw(2)
<< std::setfill('0') << (int)getODVideoLevel() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "OD Graphics Level: " << std::hex << std::setw(2)
<< std::setfill('0') << (int)getODGraphicsLevel() << std::dec << std::endl;
return r.str(); return r.str();
} }
} }// namespace MP4

View file

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "mp4.h" #include "mp4.h"
namespace MP4 { namespace MP4{
struct sidxReference { struct sidxReference{
bool referenceType; bool referenceType;
uint32_t referencedSize; uint32_t referencedSize;
uint32_t subSegmentDuration; uint32_t subSegmentDuration;
@ -11,63 +11,62 @@ namespace MP4 {
uint32_t sapDeltaTime; uint32_t sapDeltaTime;
}; };
class SIDX: public fullBox { class SIDX : public fullBox{
public: public:
SIDX(); SIDX();
void setReferenceID(uint32_t newReferenceID); void setReferenceID(uint32_t newReferenceID);
uint32_t getReferenceID(); uint32_t getReferenceID();
void setTimescale(uint32_t newTimescale); void setTimescale(uint32_t newTimescale);
uint32_t getTimescale(); uint32_t getTimescale();
void setEarliestPresentationTime(uint64_t newEarliestPresentationTime); void setEarliestPresentationTime(uint64_t newEarliestPresentationTime);
uint64_t getEarliestPresentationTime(); uint64_t getEarliestPresentationTime();
void setFirstOffset(uint64_t newFirstOffset); void setFirstOffset(uint64_t newFirstOffset);
uint64_t getFirstOffset(); uint64_t getFirstOffset();
uint16_t getReferenceCount(); uint16_t getReferenceCount();
void setReference(sidxReference & newRef, size_t index); void setReference(sidxReference &newRef, size_t index);
sidxReference getReference(size_t index); sidxReference getReference(size_t index);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class TFDT: public fullBox { class TFDT : public fullBox{
public: public:
TFDT(); TFDT();
void setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime); void setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime);
uint64_t getBaseMediaDecodeTime(); uint64_t getBaseMediaDecodeTime();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class IODS: public fullBox { class IODS : public fullBox{
public: public:
IODS(); IODS();
void setIODTypeTag(char value); void setIODTypeTag(char value);
char getIODTypeTag(); char getIODTypeTag();
void setDescriptorTypeLength(char length); void setDescriptorTypeLength(char length);
char getDescriptorTypeLength(); char getDescriptorTypeLength();
void setODID(short id); void setODID(short id);
short getODID(); short getODID();
void setODProfileLevel(char value); void setODProfileLevel(char value);
char getODProfileLevel(); char getODProfileLevel();
void setODSceneLevel(char value); void setODSceneLevel(char value);
char getODSceneLevel(); char getODSceneLevel();
void setODAudioLevel(char value); void setODAudioLevel(char value);
char getODAudioLevel(); char getODAudioLevel();
void setODVideoLevel(char value); void setODVideoLevel(char value);
char getODVideoLevel(); char getODVideoLevel();
void setODGraphicsLevel(char value); void setODGraphicsLevel(char value);
char getODGraphicsLevel(); char getODGraphicsLevel();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
} }// namespace MP4

View file

@ -1,15 +1,14 @@
#include "mp4_encryption.h"
#include "defines.h" #include "defines.h"
#include "mp4_encryption.h"
namespace MP4 { namespace MP4{
PSSH::PSSH() { PSSH::PSSH(){memcpy(data + 4, "pssh", 4);}
memcpy(data + 4, "pssh", 4);
}
std::string PSSH::toPrettyString(uint32_t indent) { std::string PSSH::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[pssh] Protection System Specific Header Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[pssh] Protection System Specific Header Box (" << boxedSize()
<< ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "SystemID: " << getSystemIDHex() << std::endl; r << std::string(indent + 1, ' ') << "SystemID: " << getSystemIDHex() << std::endl;
if (getVersion()){ if (getVersion()){
@ -18,7 +17,7 @@ namespace MP4 {
r << std::string(indent + 1, ' ') << "DataSize: " << getDataSize() << std::endl; r << std::string(indent + 1, ' ') << "DataSize: " << getDataSize() << std::endl;
r << std::string(indent + 1, ' ') << "Data: "; r << std::string(indent + 1, ' ') << "Data: ";
size_t dataSize = getDataSize(); size_t dataSize = getDataSize();
char * data = getData(); char *data = getData();
for (size_t i = 0; i < dataSize; ++i){ for (size_t i = 0; i < dataSize; ++i){
r << std::hex << std::setw(2) << std::setfill('0') << (int)data[i] << std::dec << ""; r << std::hex << std::setw(2) << std::setfill('0') << (int)data[i] << std::dec << "";
} }
@ -26,8 +25,8 @@ namespace MP4 {
return r.str(); return r.str();
} }
std::string PSSH::getSystemIDHex() { std::string PSSH::getSystemIDHex(){
char * systemID = getString(4); char *systemID = getString(4);
std::stringstream res; std::stringstream res;
for (size_t i = 0; i < 16; ++i){ for (size_t i = 0; i < 16; ++i){
res << std::hex << std::setw(2) << std::setfill('0') << (int)systemID[i] << std::dec; res << std::hex << std::setw(2) << std::setfill('0') << (int)systemID[i] << std::dec;
@ -35,13 +34,9 @@ namespace MP4 {
return "0x" + res.str(); return "0x" + res.str();
} }
void PSSH::setSystemIDHex(const std::string & systemID) { void PSSH::setSystemIDHex(const std::string &systemID){setString(systemID, 4);}
setString(systemID, 4);
}
size_t PSSH::getKIDCount(){ size_t PSSH::getKIDCount(){return getVersion() ? getInt32(20) : 0;}
return getVersion() ? getInt32(20) : 0;
}
size_t PSSH::getDataSize(){ size_t PSSH::getDataSize(){
if (getVersion()){ if (getVersion()){
@ -51,7 +46,7 @@ namespace MP4 {
return getInt32(20); return getInt32(20);
} }
char * PSSH::getData(){ char *PSSH::getData(){
if (getVersion()){ if (getVersion()){
size_t kidCount = getInt32(20); size_t kidCount = getInt32(20);
return getString(24 + (kidCount * 16) + 4); return getString(24 + (kidCount * 16) + 4);
@ -59,25 +54,23 @@ namespace MP4 {
return getString(24); return getString(24);
} }
void PSSH::setData(const std::string & data){ void PSSH::setData(const std::string &data){
if (getVersion()){ if (getVersion()){
WARN_MSG("Not implemented yet!"); WARN_MSG("Not implemented yet!");
return; return;
} }
for (int i = 0; i < data.size(); i++){ for (int i = 0; i < data.size(); i++){setInt8(data[i], 24 + i);}
setInt8(data[i], 24 + i);
}
setInt32(data.size(), 20); setInt32(data.size(), 20);
} }
std::string TENC::toPrettyString(uint32_t indent) { std::string TENC::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[tenc] Track Encryption Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[tenc] Track Encryption Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "default_isEncrypted: " << getDefaultIsEncrypted() << std::endl; 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_IV_size: " << getDefaultIVSize() << std::endl;
r << std::string(indent + 1, ' ') << "default_KID: "; r << std::string(indent + 1, ' ') << "default_KID: ";
std::string defaultKID = getDefaultKID(); std::string defaultKID = getDefaultKID();
for (int i = 0; i < 16; i++){ for (int i = 0; i < 16; i++){
r << std::hex << std::setw(2) << std::setfill('0') << (int)defaultKID[i] << std::dec << " "; r << std::hex << std::setw(2) << std::setfill('0') << (int)defaultKID[i] << std::dec << " ";
} }
@ -85,31 +78,21 @@ namespace MP4 {
return r.str(); return r.str();
} }
TENC::TENC() { TENC::TENC(){
memcpy(data + 4, "tenc", 4); memcpy(data + 4, "tenc", 4);
setDefaultIsEncrypted(1); setDefaultIsEncrypted(1);
setDefaultIVSize(8); setDefaultIVSize(8);
} }
size_t TENC::getDefaultIsEncrypted(){ size_t TENC::getDefaultIsEncrypted(){return getInt24(4);}
return getInt24(4); void TENC::setDefaultIsEncrypted(size_t isEncrypted){setInt24(isEncrypted, 4);}
} size_t TENC::getDefaultIVSize(){return getInt8(7);}
void TENC::setDefaultIsEncrypted(size_t isEncrypted){ void TENC::setDefaultIVSize(uint8_t ivSize){setInt8(ivSize, 7);}
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 TENC::getDefaultKID(){
std::string result; std::string result;
for (int i = 8; i < 24; i++){ for (int i = 8; i < 24; i++){result += getInt8(i);}
result += getInt8(i);
}
return result; return result;
} }
void TENC::setDefaultKID(const std::string & kid){ void TENC::setDefaultKID(const std::string &kid){
for (int i = 0; i < 16; i++){ for (int i = 0; i < 16; i++){
if (i < kid.size()){ if (i < kid.size()){
setInt8(kid[i], i + 8); setInt8(kid[i], i + 8);
@ -119,80 +102,75 @@ namespace MP4 {
} }
} }
SENC::SENC() { SENC::SENC(){
memcpy(data + 4, "senc", 4); memcpy(data + 4, "senc", 4);
setFlags(2); setFlags(2);
} }
uint32_t SENC::getSampleCount() const { uint32_t SENC::getSampleCount() const{return getInt32(4);}
return getInt32(4);
}
#define IV_SIZE 8 #define IV_SIZE 8
void SENC::setSample(UUID_SampleEncryption_Sample newSample, size_t index) { void SENC::setSample(UUID_SampleEncryption_Sample newSample, size_t index){
int myOffset = 8; int myOffset = 8;
for (unsigned int i = 0; i < std::min(index, (size_t)getSampleCount()); i++) { for (unsigned int i = 0; i < std::min(index, (size_t)getSampleCount()); i++){
myOffset += IV_SIZE; myOffset += IV_SIZE;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
int entryCount = getInt16(myOffset); int entryCount = getInt16(myOffset);
myOffset += 2 + (entryCount * 6); myOffset += 2 + (entryCount * 6);
} }
} }
if (index > getSampleCount()) { if (index > getSampleCount()){
ERROR_MSG("First fill intermediate entries!"); ERROR_MSG("First fill intermediate entries!");
return; return;
/* /*
//we are now at the end of currently reserved space, reserve more and adapt offset accordingly. //we are now at the end of currently reserved space, reserve more and adapt offset
int reserveSize = ((index - getSampleCount())) * (IV_SIZE + (getFlags() & 0x02)); accordingly. int reserveSize = ((index - getSampleCount())) * (IV_SIZE + (getFlags() & 0x02));
reserveSize += IV_SIZE; reserveSize += IV_SIZE;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
reserveSize += 2 + newSample.Entries.size(); reserveSize += 2 + newSample.Entries.size();
} }
if (!reserve(myOffset, 0, reserveSize)) { if (!reserve(myOffset, 0, reserveSize)){
return;//Memory errors... return;//Memory errors...
} }
myOffset += (index - getSampleCount()) * (IV_SIZE + (getFlags() & 0x02)); 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++){
setInt8(newSample.InitializationVector[i], myOffset ++);//set and skip setInt8(newSample.InitializationVector[i], myOffset++); // set and skip
} }
if (getFlags() & 0x02) { if (getFlags() & 0x02){
setInt16(newSample.Entries.size(), myOffset); setInt16(newSample.Entries.size(), myOffset);
myOffset += 2; myOffset += 2;
for (std::vector<UUID_SampleEncryption_Sample_Entry>::iterator it = newSample.Entries.begin(); it != newSample.Entries.end(); it++) { for (std::vector<UUID_SampleEncryption_Sample_Entry>::iterator it = newSample.Entries.begin();
it != newSample.Entries.end(); it++){
setInt16(it->BytesClear, myOffset); setInt16(it->BytesClear, myOffset);
myOffset += 2; myOffset += 2;
setInt32(it->BytesEncrypted, myOffset); setInt32(it->BytesEncrypted, myOffset);
myOffset += 4; myOffset += 4;
} }
} }
if (index >= getSampleCount()) { if (index >= getSampleCount()){setInt32(index + 1, 4);}
setInt32(index + 1, 4);
}
} }
UUID_SampleEncryption_Sample SENC::getSample(size_t index) const { UUID_SampleEncryption_Sample SENC::getSample(size_t index) const{
if (index >= getSampleCount()) { if (index >= getSampleCount()){return UUID_SampleEncryption_Sample();}
return UUID_SampleEncryption_Sample();
}
int myOffset = 8; int myOffset = 8;
for (unsigned int i = 0; i < index; i++) { for (unsigned int i = 0; i < index; i++){
myOffset += IV_SIZE; myOffset += IV_SIZE;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
int entryCount = getInt16(myOffset); int entryCount = getInt16(myOffset);
myOffset += 2;//skip over entrycount myOffset += 2; // skip over entrycount
myOffset += entryCount * 6;//skip entryCount sample entries myOffset += entryCount * 6; // skip entryCount sample entries
} }
} }
UUID_SampleEncryption_Sample result; UUID_SampleEncryption_Sample result;
for (int i = 0; i < IV_SIZE; i++) { for (int i = 0; i < IV_SIZE; i++){
result.InitializationVector += (char)getInt8(myOffset++);//read and skip result.InitializationVector += (char)getInt8(myOffset++); // read and skip
} }
if (getFlags() & 0x02) { if (getFlags() & 0x02){
result.NumberOfEntries = getInt16(myOffset); result.NumberOfEntries = getInt16(myOffset);
myOffset += 2; myOffset += 2;
for (unsigned int i = 0; i < result.NumberOfEntries; i++) { for (unsigned int i = 0; i < result.NumberOfEntries; i++){
result.Entries.push_back(UUID_SampleEncryption_Sample_Entry()); result.Entries.push_back(UUID_SampleEncryption_Sample_Entry());
result.Entries[i].BytesClear = getInt16(myOffset); result.Entries[i].BytesClear = getInt16(myOffset);
myOffset += 2; myOffset += 2;
@ -203,25 +181,27 @@ namespace MP4 {
return result; return result;
} }
std::string SENC::toPrettyString(uint32_t indent) const { std::string SENC::toPrettyString(uint32_t indent) const{
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[senc] Sample Encryption Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[senc] Sample Encryption Box (" << boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "Sample Count: " << getSampleCount() << std::endl; r << std::string(indent + 1, ' ') << "Sample Count: " << getSampleCount() << std::endl;
for (unsigned int i = 0; i < getSampleCount(); i++) { for (unsigned int i = 0; i < getSampleCount(); i++){
UUID_SampleEncryption_Sample tmpSample = getSample(i); UUID_SampleEncryption_Sample tmpSample = getSample(i);
r << std::string(indent + 1, ' ') << "[" << i << "]" << std::endl; r << std::string(indent + 1, ' ') << "[" << i << "]" << std::endl;
r << std::string(indent + 3, ' ') << "Initialization Vector: 0x"; r << std::string(indent + 3, ' ') << "Initialization Vector: 0x";
for (unsigned int j = 0; j < tmpSample.InitializationVector.size(); j++) { 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::hex << std::setw(2) << std::setfill('0') << (int)tmpSample.InitializationVector[j]
<< std::dec;
} }
r << std::endl; r << std::endl;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
r << std::string(indent + 3, ' ') << "Number of entries: " << tmpSample.NumberOfEntries << std::endl; r << std::string(indent + 3, ' ') << "Number of entries: " << tmpSample.NumberOfEntries << std::endl;
for (unsigned int j = 0; j < tmpSample.NumberOfEntries; j++) { for (unsigned int j = 0; j < tmpSample.NumberOfEntries; j++){
r << std::string(indent + 3, ' ') << "[" << j << "]" << std::endl; 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 clear: " << tmpSample.Entries[j].BytesClear << std::endl;
r << std::string(indent + 5, ' ') << "Bytes encrypted: " << tmpSample.Entries[j].BytesEncrypted << std::endl; r << std::string(indent + 5, ' ')
<< "Bytes encrypted: " << tmpSample.Entries[j].BytesEncrypted << std::endl;
} }
} }
} }
@ -232,29 +212,26 @@ namespace MP4 {
memcpy(data + 4, "saiz", 4); memcpy(data + 4, "saiz", 4);
setFlags(0); setFlags(0);
setVersion(0); setVersion(0);
setInt24(0, 4); //Default sample size setInt24(0, 4); // Default sample size
setInt16(entryCount, 7);//EntryCount Samples setInt16(entryCount, 7); // EntryCount Samples
for (int i = 0; i < entryCount; i++){ for (int i = 0; i < entryCount; i++){
setInt8(16, i+9);//16 bytes IV's setInt8(16, i + 9); // 16 bytes IV's
} }
} }
size_t SAIZ::getDefaultSampleSize(){ size_t SAIZ::getDefaultSampleSize(){return getInt24(4);}
return getInt24(4);
}
size_t SAIZ::getEntryCount(){ size_t SAIZ::getEntryCount(){return getInt16(7);}
return getInt16(7);
}
size_t SAIZ::getEntrySize(size_t entryNo){ size_t SAIZ::getEntrySize(size_t entryNo){
if (entryNo >= getEntryCount()){return -1;} if (entryNo >= getEntryCount()){return -1;}
return getInt8(9 + entryNo); return getInt8(9 + entryNo);
} }
std::string SAIZ::toPrettyString(uint32_t indent) { std::string SAIZ::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[saiz] Sample Auxiliary Information Size Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[saiz] Sample Auxiliary Information Size Box (" << boxedSize()
<< ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "Default Sample Size: " << getDefaultSampleSize() << std::endl; r << std::string(indent + 1, ' ') << "Default Sample Size: " << getDefaultSampleSize() << std::endl;
r << std::string(indent + 1, ' ') << "Entry Count: " << getEntryCount() << std::endl; r << std::string(indent + 1, ' ') << "Entry Count: " << getEntryCount() << std::endl;
@ -270,18 +247,17 @@ namespace MP4 {
setInt32(offset, 8); setInt32(offset, 8);
} }
size_t SAIO::getEntryCount(){ size_t SAIO::getEntryCount(){return getInt32(4);}
return getInt32(4);
}
size_t SAIO::getEntrySize(size_t entryNo){ size_t SAIO::getEntrySize(size_t entryNo){
if (entryNo >= getEntryCount()){return -1;} if (entryNo >= getEntryCount()){return -1;}
return getInt32(8 + (entryNo * 4)); return getInt32(8 + (entryNo * 4));
} }
std::string SAIO::toPrettyString(uint32_t indent) { std::string SAIO::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[saio] Sample Auxiliary Information Offset Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[saio] Sample Auxiliary Information Offset Box ("
<< boxedSize() << ")" << std::endl;
r << fullBox::toPrettyString(indent); r << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "Entry Count: " << getEntryCount() << std::endl; r << std::string(indent + 1, ' ') << "Entry Count: " << getEntryCount() << std::endl;
for (size_t i = 0; i < getEntryCount(); ++i){ for (size_t i = 0; i < getEntryCount(); ++i){
@ -290,153 +266,122 @@ namespace MP4 {
return r.str(); 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){ UUID_SampleEncryption::UUID_SampleEncryption(const SENC &senc){
setUUID((std::string)"a2394f52-5a9b-4f14-a244-6c427c648df4"); setUUID((std::string) "a2394f52-5a9b-4f14-a244-6c427c648df4");
setVersion(0); setVersion(0);
setFlags(2); setFlags(2);
size_t sampleCount = senc.getSampleCount(); size_t sampleCount = senc.getSampleCount();
for (size_t i = 0; i < sampleCount; ++i){ for (size_t i = 0; i < sampleCount; ++i){setSample(senc.getSample(i), 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);
uint32_t UUID_SampleEncryption::getVersion(){return getInt8(16);}
void UUID_SampleEncryption::setFlags(uint32_t newFlags){setInt24(newFlags, 17);}
uint32_t UUID_SampleEncryption::getFlags(){return getInt24(17);}
void UUID_SampleEncryption::setAlgorithmID(uint32_t newAlgorithmID){
if (getFlags() & 0x01){setInt24(newAlgorithmID, 20);}
} }
uint32_t UUID_SampleEncryption::getVersion() { uint32_t UUID_SampleEncryption::getAlgorithmID(){
return getInt8(16); if (getFlags() & 0x01){return getInt24(20);}
}
void UUID_SampleEncryption::setFlags(uint32_t newFlags) {
setInt24(newFlags, 17);
}
uint32_t UUID_SampleEncryption::getFlags() {
return getInt24(17);
}
void UUID_SampleEncryption::setAlgorithmID(uint32_t newAlgorithmID) {
if (getFlags() & 0x01) {
setInt24(newAlgorithmID, 20);
}
}
uint32_t UUID_SampleEncryption::getAlgorithmID() {
if (getFlags() & 0x01) {
return getInt24(20);
}
return -1; return -1;
} }
void UUID_SampleEncryption::setIVSize(uint32_t newIVSize) { void UUID_SampleEncryption::setIVSize(uint32_t newIVSize){
if (getFlags() & 0x01) { if (getFlags() & 0x01){setInt8(newIVSize, 23);}
setInt8(newIVSize, 23);
}
} }
uint32_t UUID_SampleEncryption::getIVSize() { uint32_t UUID_SampleEncryption::getIVSize(){
if (getFlags() & 0x01) { if (getFlags() & 0x01){return getInt8(23);}
return getInt8(23);
}
return -1; return -1;
} }
void UUID_SampleEncryption::setKID(std::string newKID) { void UUID_SampleEncryption::setKID(std::string newKID){
if (newKID == "") { if (newKID == ""){return;}
return; if (getFlags() & 0x01){
} while (newKID.size() < 16){newKID += (char)0x00;}
if (getFlags() & 0x01) { for (int i = 0; i < 16; i++){setInt8(newKID[i], 24 + i);}
while (newKID.size() < 16) {
newKID += (char)0x00;
}
for (int i = 0; i < 16; i++) {
setInt8(newKID[i], 24 + i);
}
} }
} }
std::string UUID_SampleEncryption::getKID() { std::string UUID_SampleEncryption::getKID(){
if (getFlags() & 0x01) { if (getFlags() & 0x01){
std::string result; std::string result;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++){result += (char)getInt8(24 + i);}
result += (char)getInt8(24 + i);
}
return result; return result;
} }
return ""; return "";
} }
uint32_t UUID_SampleEncryption::getSampleCount() { uint32_t UUID_SampleEncryption::getSampleCount(){
int myOffset = 20; int myOffset = 20;
if (getFlags() & 0x01) { if (getFlags() & 0x01){myOffset += 20;}
myOffset += 20;
}
return getInt32(myOffset); return getInt32(myOffset);
} }
#define IV_SIZE 8 #define IV_SIZE 8
void UUID_SampleEncryption::setSample(UUID_SampleEncryption_Sample newSample, size_t index) { void UUID_SampleEncryption::setSample(UUID_SampleEncryption_Sample newSample, size_t index){
int myOffset = 20; int myOffset = 20;
myOffset += 20 * (getFlags() & 0x01); myOffset += 20 * (getFlags() & 0x01);
myOffset += 4;//sampleCount is here; myOffset += 4; // sampleCount is here;
for (unsigned int i = 0; i < std::min(index, (size_t)getSampleCount()); i++) { for (unsigned int i = 0; i < std::min(index, (size_t)getSampleCount()); i++){
myOffset += IV_SIZE; myOffset += IV_SIZE;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
int entryCount = getInt16(myOffset); int entryCount = getInt16(myOffset);
myOffset += 2 + (entryCount * 6); myOffset += 2 + (entryCount * 6);
} }
} }
if (index > getSampleCount()) { if (index > getSampleCount()){
ERROR_MSG("First fill intermediate entries!"); ERROR_MSG("First fill intermediate entries!");
return; return;
} }
//write box. // write box.
for (int i = 0; i < IV_SIZE; i++) { for (int i = 0; i < IV_SIZE; i++){
setInt8(newSample.InitializationVector[i], myOffset ++);//set and skip setInt8(newSample.InitializationVector[i], myOffset++); // set and skip
} }
if (getFlags() & 0x02) { if (getFlags() & 0x02){
setInt16(newSample.Entries.size(), myOffset); setInt16(newSample.Entries.size(), myOffset);
myOffset += 2; myOffset += 2;
for (std::vector<UUID_SampleEncryption_Sample_Entry>::iterator it = newSample.Entries.begin(); it != newSample.Entries.end(); it++) { for (std::vector<UUID_SampleEncryption_Sample_Entry>::iterator it = newSample.Entries.begin();
it != newSample.Entries.end(); it++){
setInt16(it->BytesClear, myOffset); setInt16(it->BytesClear, myOffset);
myOffset += 2; myOffset += 2;
setInt32(it->BytesEncrypted, myOffset); setInt32(it->BytesEncrypted, myOffset);
myOffset += 4; myOffset += 4;
} }
} }
if (index >= getSampleCount()) { if (index >= getSampleCount()){setInt32(index + 1, 20 + (20 * (getFlags() & 0x01)));}
setInt32(index + 1, 20 + (20 * (getFlags() & 0x01)));
}
} }
UUID_SampleEncryption_Sample UUID_SampleEncryption::getSample(size_t index) { UUID_SampleEncryption_Sample UUID_SampleEncryption::getSample(size_t index){
if (index >= getSampleCount()) { if (index >= getSampleCount()){return UUID_SampleEncryption_Sample();}
return UUID_SampleEncryption_Sample();
}
int myOffset = 20; int myOffset = 20;
myOffset += 20 * (getFlags() & 0x01); myOffset += 20 * (getFlags() & 0x01);
myOffset += 4;//sampleCount is here myOffset += 4; // sampleCount is here
for (unsigned int i = 0; i < index; i++) { for (unsigned int i = 0; i < index; i++){
myOffset += IV_SIZE; myOffset += IV_SIZE;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
int entryCount = getInt16(myOffset); int entryCount = getInt16(myOffset);
myOffset += 2;//skip over entrycount myOffset += 2; // skip over entrycount
myOffset += entryCount * 6;//skip entryCount sample entries myOffset += entryCount * 6; // skip entryCount sample entries
} }
} }
UUID_SampleEncryption_Sample result; UUID_SampleEncryption_Sample result;
for (int i = 0; i < IV_SIZE; i++) { for (int i = 0; i < IV_SIZE; i++){
result.InitializationVector += getInt8(myOffset++);//read and skip result.InitializationVector += getInt8(myOffset++); // read and skip
} }
if (getFlags() & 0x02) { if (getFlags() & 0x02){
result.NumberOfEntries = getInt16(myOffset); result.NumberOfEntries = getInt16(myOffset);
myOffset += 2; myOffset += 2;
for (unsigned int i = 0; i < result.NumberOfEntries; i++) { for (unsigned int i = 0; i < result.NumberOfEntries; i++){
result.Entries.push_back(UUID_SampleEncryption_Sample_Entry()); result.Entries.push_back(UUID_SampleEncryption_Sample_Entry());
result.Entries[i].BytesClear = getInt16(myOffset); result.Entries[i].BytesClear = getInt16(myOffset);
myOffset += 2; myOffset += 2;
@ -447,162 +392,136 @@ namespace MP4 {
return result; return result;
} }
std::string UUID_SampleEncryption::toPrettyString(uint32_t indent) { std::string UUID_SampleEncryption::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[a2394f52-5a9b-4f14-a244-6c427c648df4] Sample Encryption Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[a2394f52-5a9b-4f14-a244-6c427c648df4] Sample Encryption Box ("
<< boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl; r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 1, ' ') << "Flags: " << getFlags() << std::endl; r << std::string(indent + 1, ' ') << "Flags: " << getFlags() << std::endl;
if (getFlags() & 0x01) { if (getFlags() & 0x01){
r << std::string(indent + 1, ' ') << "Algorithm ID: " << getAlgorithmID() << std::endl; r << std::string(indent + 1, ' ') << "Algorithm ID: " << getAlgorithmID() << std::endl;
r << std::string(indent + 1, ' ') << "IV Size: " << getIVSize() << std::endl; r << std::string(indent + 1, ' ') << "IV Size: " << getIVSize() << std::endl;
r << std::string(indent + 1, ' ') << "Key ID: " << getKID() << std::endl; r << std::string(indent + 1, ' ') << "Key ID: " << getKID() << std::endl;
} }
r << std::string(indent + 1, ' ') << "Sample Count: " << getSampleCount() << std::endl; r << std::string(indent + 1, ' ') << "Sample Count: " << getSampleCount() << std::endl;
for (unsigned int i = 0; i < getSampleCount(); i++) { for (unsigned int i = 0; i < getSampleCount(); i++){
UUID_SampleEncryption_Sample tmpSample = getSample(i); UUID_SampleEncryption_Sample tmpSample = getSample(i);
r << std::string(indent + 1, ' ') << "[" << i << "]" << std::endl; r << std::string(indent + 1, ' ') << "[" << i << "]" << std::endl;
r << std::string(indent + 3, ' ') << "Initialization Vector: 0x"; r << std::string(indent + 3, ' ') << "Initialization Vector: 0x";
for (unsigned int j = 0; j < tmpSample.InitializationVector.size(); j++) { 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::hex << std::setw(2) << std::setfill('0') << (int)tmpSample.InitializationVector[j]
<< std::dec;
} }
r << std::endl; r << std::endl;
if (getFlags() & 0x02) { if (getFlags() & 0x02){
r << std::string(indent + 3, ' ') << "Number of entries: " << tmpSample.NumberOfEntries << std::endl; r << std::string(indent + 3, ' ') << "Number of entries: " << tmpSample.NumberOfEntries << std::endl;
for (unsigned int j = 0; j < tmpSample.NumberOfEntries; j++) { for (unsigned int j = 0; j < tmpSample.NumberOfEntries; j++){
r << std::string(indent + 3, ' ') << "[" << j << "]" << std::endl; 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 clear: " << tmpSample.Entries[j].BytesClear << std::endl;
r << std::string(indent + 5, ' ') << "Bytes encrypted: " << tmpSample.Entries[j].BytesEncrypted << std::endl; r << std::string(indent + 5, ' ')
<< "Bytes encrypted: " << tmpSample.Entries[j].BytesEncrypted << std::endl;
} }
} }
} }
return r.str(); return r.str();
} }
UUID_TrackEncryption::UUID_TrackEncryption() { UUID_TrackEncryption::UUID_TrackEncryption(){
setUUID((std::string)"8974dbce-7be7-4c51-84f9-7148f9882554"); setUUID((std::string) "8974dbce-7be7-4c51-84f9-7148f9882554");
} }
void UUID_TrackEncryption::setVersion(uint32_t newVersion) { void UUID_TrackEncryption::setVersion(uint32_t newVersion){setInt8(newVersion, 16);}
setInt8(newVersion, 16);
}
uint32_t UUID_TrackEncryption::getVersion() { uint32_t UUID_TrackEncryption::getVersion(){return getInt8(16);}
return getInt8(16);
}
void UUID_TrackEncryption::setFlags(uint32_t newFlags) { void UUID_TrackEncryption::setFlags(uint32_t newFlags){setInt24(newFlags, 17);}
setInt24(newFlags, 17);
}
uint32_t UUID_TrackEncryption::getFlags() { uint32_t UUID_TrackEncryption::getFlags(){return getInt24(17);}
return getInt24(17);
}
void UUID_TrackEncryption::setDefaultAlgorithmID(uint32_t newID) { void UUID_TrackEncryption::setDefaultAlgorithmID(uint32_t newID){setInt24(newID, 20);}
setInt24(newID, 20);
}
uint32_t UUID_TrackEncryption::getDefaultAlgorithmID() { uint32_t UUID_TrackEncryption::getDefaultAlgorithmID(){return getInt24(20);}
return getInt24(20);
}
void UUID_TrackEncryption::setDefaultIVSize(uint8_t newIVSize) { void UUID_TrackEncryption::setDefaultIVSize(uint8_t newIVSize){setInt8(newIVSize, 23);}
setInt8(newIVSize, 23);
}
uint8_t UUID_TrackEncryption::getDefaultIVSize() { uint8_t UUID_TrackEncryption::getDefaultIVSize(){return getInt8(23);}
return getInt8(23);
}
void UUID_TrackEncryption::setDefaultKID(std::string newKID) { void UUID_TrackEncryption::setDefaultKID(std::string newKID){
for (unsigned int i = 0; i < 16; i++) { for (unsigned int i = 0; i < 16; i++){
if (i < newKID.size()) { if (i < newKID.size()){
setInt8(newKID[i], 24 + i); setInt8(newKID[i], 24 + i);
} else { }else{
setInt8(0x00, 24 + i); setInt8(0x00, 24 + i);
} }
} }
} }
std::string UUID_TrackEncryption::getDefaultKID() { std::string UUID_TrackEncryption::getDefaultKID(){
std::string result; std::string result;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++){result += getInt8(24 + i);}
result += getInt8(24 + i);
}
return result; return result;
} }
std::string UUID_TrackEncryption::toPrettyString(uint32_t indent) { std::string UUID_TrackEncryption::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[8974dbce-7be7-4c51-84f9-7148f9882554] Track Encryption Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[8974dbce-7be7-4c51-84f9-7148f9882554] Track Encryption Box ("
<< boxedSize() << ")" << std::endl;
r << std::string(indent + 2, ' ') << "Version: " << getVersion() << std::endl; r << std::string(indent + 2, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 2, ' ') << "Flags: " << getFlags() << std::endl; r << std::string(indent + 2, ' ') << "Flags: " << getFlags() << std::endl;
r << std::string(indent + 2, ' ') << "Default Algorithm ID: " << std::hex << getDefaultAlgorithmID() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "Default Algorithm ID: " << std::hex
<< getDefaultAlgorithmID() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "Default IV Size: " << (int)getDefaultIVSize() << std::endl; r << std::string(indent + 2, ' ') << "Default IV Size: " << (int)getDefaultIVSize() << std::endl;
r << std::string(indent + 2, ' ') << "Default KID: 16 bytes of binary data." << std::endl; r << std::string(indent + 2, ' ') << "Default KID: 16 bytes of binary data." << std::endl;
return r.str(); return r.str();
} }
UUID_ProtectionSystemSpecificHeader::UUID_ProtectionSystemSpecificHeader() { UUID_ProtectionSystemSpecificHeader::UUID_ProtectionSystemSpecificHeader(){
setUUID((std::string)"d08a4f18-10f3-4a82-b6c8-32d8aba183d3"); setUUID((std::string) "d08a4f18-10f3-4a82-b6c8-32d8aba183d3");
} }
void UUID_ProtectionSystemSpecificHeader::setVersion(uint32_t newVersion) { void UUID_ProtectionSystemSpecificHeader::setVersion(uint32_t newVersion){
setInt8(newVersion, 16); setInt8(newVersion, 16);
} }
uint32_t UUID_ProtectionSystemSpecificHeader::getVersion() { uint32_t UUID_ProtectionSystemSpecificHeader::getVersion(){return getInt8(16);}
return getInt8(16);
}
void UUID_ProtectionSystemSpecificHeader::setFlags(uint32_t newFlags) { void UUID_ProtectionSystemSpecificHeader::setFlags(uint32_t newFlags){setInt24(newFlags, 17);}
setInt24(newFlags, 17);
}
uint32_t UUID_ProtectionSystemSpecificHeader::getFlags() { uint32_t UUID_ProtectionSystemSpecificHeader::getFlags(){return getInt24(17);}
return getInt24(17);
}
void UUID_ProtectionSystemSpecificHeader::setSystemID(std::string newID) { void UUID_ProtectionSystemSpecificHeader::setSystemID(std::string newID){
for (unsigned int i = 0; i < 16; i++) { for (unsigned int i = 0; i < 16; i++){
if (i < newID.size()) { if (i < newID.size()){
setInt8(newID[i], 20 + i); setInt8(newID[i], 20 + i);
} else { }else{
setInt8(0x00, 20 + i); setInt8(0x00, 20 + i);
} }
} }
} }
std::string UUID_ProtectionSystemSpecificHeader::getSystemID() { std::string UUID_ProtectionSystemSpecificHeader::getSystemID(){
std::string result; std::string result;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++){result += getInt8(20 + i);}
result += getInt8(20 + i);
}
return result; return result;
} }
uint32_t UUID_ProtectionSystemSpecificHeader::getDataSize() { uint32_t UUID_ProtectionSystemSpecificHeader::getDataSize(){return getInt32(36);}
return getInt32(36);
}
void UUID_ProtectionSystemSpecificHeader::setData(std::string newData) { void UUID_ProtectionSystemSpecificHeader::setData(std::string newData){
setInt32(newData.size(), 36); setInt32(newData.size(), 36);
for (unsigned int i = 0; i < newData.size(); i++) { for (unsigned int i = 0; i < newData.size(); i++){setInt8(newData[i], 40 + i);}
setInt8(newData[i], 40 + i);
}
} }
std::string UUID_ProtectionSystemSpecificHeader::getData() { std::string UUID_ProtectionSystemSpecificHeader::getData(){
std::string result; std::string result;
for (unsigned int i = 0; i < getDataSize(); i++) { for (unsigned int i = 0; i < getDataSize(); i++){result += getInt8(40 + i);}
result += getInt8(40 + i);
}
return result; return result;
} }
std::string UUID_ProtectionSystemSpecificHeader::toPrettyString(uint32_t indent) { std::string UUID_ProtectionSystemSpecificHeader::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[d08a4f18-10f3-4a82-b6c8-32d8aba183d3] Protection System Specific Header Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[d08a4f18-10f3-4a82-b6c8-32d8aba183d3] Protection System Specific Header Box ("
<< boxedSize() << ")" << std::endl;
r << std::string(indent + 2, ' ') << "Version: " << getVersion() << std::endl; r << std::string(indent + 2, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 2, ' ') << "Flags: " << getFlags() << std::endl; r << std::string(indent + 2, ' ') << "Flags: " << getFlags() << std::endl;
r << std::string(indent + 2, ' ') << "System ID: " << getSystemID() << std::endl; r << std::string(indent + 2, ' ') << "System ID: " << getSystemID() << std::endl;
@ -611,66 +530,54 @@ namespace MP4 {
return r.str(); return r.str();
} }
SINF::SINF() { SINF::SINF(){memcpy(data + 4, "sinf", 4);}
memcpy(data + 4, "sinf", 4);
}
void SINF::setEntry(Box & newEntry, uint32_t no) { void SINF::setEntry(Box &newEntry, uint32_t no){
if (no > 4) { if (no > 4){return;}
return;
}
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 += Box(getBox(tempLoc).asBox(), false).boxedSize();
} }
setBox(newEntry, tempLoc); setBox(newEntry, tempLoc);
} }
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){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 += getBoxLen(tempLoc);}
tempLoc += getBoxLen(tempLoc);
}
return getBox(tempLoc); return getBox(tempLoc);
} }
std::string SINF::toPrettyString(uint32_t indent) { std::string SINF::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
std::cerr << payloadOffset << std::endl; std::cerr << payloadOffset << std::endl;
r << std::string(indent, ' ') << "[sinf] Protection Scheme Info Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[sinf] Protection Scheme Info Box (" << boxedSize() << ")" << std::endl;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++){
if (!getEntry(i).isType("erro")) { if (!getEntry(i).isType("erro")){r << getEntry(i).toPrettyString(indent + 2);}
r << getEntry(i).toPrettyString(indent + 2);
}
} }
r << std::endl; r << std::endl;
return r.str(); return r.str();
} }
FRMA::FRMA(const std::string & originalFormat) { FRMA::FRMA(const std::string &originalFormat){
memcpy(data + 4, "frma", 4); memcpy(data + 4, "frma", 4);
setOriginalFormat(originalFormat); setOriginalFormat(originalFormat);
} }
void FRMA::setOriginalFormat(const 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);
} else { }else{
setInt8(0x00, i); setInt8(0x00, i);
} }
} }
} }
std::string FRMA::getOriginalFormat() { std::string FRMA::getOriginalFormat(){return std::string(payload(), 4);}
return std::string(payload(), 4);
}
std::string FRMA::toPrettyString(uint32_t indent) { std::string FRMA::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[frma] Original Format Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[frma] Original Format Box (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 2, ' ') << "Original Format: " << getOriginalFormat() << std::endl; r << std::string(indent + 2, ' ') << "Original Format: " << getOriginalFormat() << std::endl;
@ -683,65 +590,50 @@ namespace MP4 {
setSchemeVersion(schemeVersion); setSchemeVersion(schemeVersion);
} }
void SCHM::setSchemeType(uint32_t newType) { void SCHM::setSchemeType(uint32_t newType){setInt32(htonl(newType), 4);}
setInt32(htonl(newType), 4);
}
uint32_t SCHM::getSchemeType() { uint32_t SCHM::getSchemeType(){return ntohl(getInt32(4));}
return ntohl(getInt32(4));
}
void SCHM::setSchemeVersion(uint32_t newVersion) { void SCHM::setSchemeVersion(uint32_t newVersion){setInt32(htonl(newVersion), 8);}
setInt32(htonl(newVersion), 8);
}
uint32_t SCHM::getSchemeVersion() { uint32_t SCHM::getSchemeVersion(){return ntohl(getInt32(8));}
return ntohl(getInt32(8));
}
void SCHM::setSchemeURI(std::string newURI) { void SCHM::setSchemeURI(std::string newURI){
setFlags(getFlags() | 0x01); setFlags(getFlags() | 0x01);
setString(newURI, 12); setString(newURI, 12);
} }
std::string SCHM::getSchemeURI() { std::string SCHM::getSchemeURI(){
if (getFlags() & 0x01) { if (getFlags() & 0x01){return getString(12);}
return getString(12);
}
return ""; return "";
} }
std::string SCHM::toPrettyString(uint32_t indent) { std::string SCHM::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[schm] Scheme Type Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[schm] Scheme Type Box (" << boxedSize() << ")" << std::endl;
char tmpStr[10]; char tmpStr[10];
int tmpInt = getSchemeType(); int tmpInt = getSchemeType();
sprintf(tmpStr, "%.4s", (char *)&tmpInt); sprintf(tmpStr, "%.4s", (char *)&tmpInt);
r << std::string(indent + 2, ' ') << "SchemeType: " << std::string(tmpStr, 4) << std::endl; r << std::string(indent + 2, ' ') << "SchemeType: " << std::string(tmpStr, 4) << std::endl;
r << std::string(indent + 2, ' ') << "SchemeVersion: 0x" << std::hex << std::setw(8) << std::setfill('0') << getSchemeVersion() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "SchemeVersion: 0x" << std::hex << std::setw(8)
if (getFlags() & 0x01) { << std::setfill('0') << getSchemeVersion() << std::dec << std::endl;
if (getFlags() & 0x01){
r << std::string(indent + 2, ' ') << "SchemeURI: " << getSchemeURI() << std::endl; r << std::string(indent + 2, ' ') << "SchemeURI: " << getSchemeURI() << std::endl;
} }
return r.str(); return r.str();
} }
SCHI::SCHI() { SCHI::SCHI(){memcpy(data + 4, "schi", 4);}
memcpy(data + 4, "schi", 4);
}
void SCHI::setContent(Box & newContent) { void SCHI::setContent(Box &newContent){setBox(newContent, 0);}
setBox(newContent, 0);
}
Box & SCHI::getContent() { Box &SCHI::getContent(){return getBox(0);}
return getBox(0);
}
std::string SCHI::toPrettyString(uint32_t indent) { std::string SCHI::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[schi] Scheme Information Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[schi] Scheme Information Box (" << boxedSize() << ")" << std::endl;
r << getContent().toPrettyString(indent + 2); r << getContent().toPrettyString(indent + 2);
return r.str(); return r.str();
} }
} }// namespace MP4

View file

@ -1,155 +1,155 @@
#include "mp4.h" #include "mp4.h"
#include "mp4_ms.h" #include "mp4_ms.h"
namespace MP4 { namespace MP4{
struct UUID_SampleEncryption_Sample_Entry { struct UUID_SampleEncryption_Sample_Entry{
uint32_t BytesClear; uint32_t BytesClear;
uint32_t BytesEncrypted; uint32_t BytesEncrypted;
}; };
struct UUID_SampleEncryption_Sample { struct UUID_SampleEncryption_Sample{
std::string InitializationVector; std::string InitializationVector;
uint32_t NumberOfEntries; uint32_t NumberOfEntries;
std::vector<UUID_SampleEncryption_Sample_Entry> Entries; std::vector<UUID_SampleEncryption_Sample_Entry> Entries;
}; };
class PSSH: public fullBox { class PSSH : public fullBox{
public: public:
PSSH(); PSSH();
std::string getSystemIDHex(); std::string getSystemIDHex();
void setSystemIDHex(const std::string & systemID); void setSystemIDHex(const std::string &systemID);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
size_t getKIDCount(); size_t getKIDCount();
size_t getDataSize(); size_t getDataSize();
char * getData(); char *getData();
void setData(const std::string & data); void setData(const std::string &data);
}; };
class TENC: public fullBox { class TENC : public fullBox{
public: public:
TENC(); TENC();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
size_t getDefaultIsEncrypted(); size_t getDefaultIsEncrypted();
void setDefaultIsEncrypted(size_t isEncrypted); void setDefaultIsEncrypted(size_t isEncrypted);
size_t getDefaultIVSize(); size_t getDefaultIVSize();
void setDefaultIVSize(uint8_t ivSize); void setDefaultIVSize(uint8_t ivSize);
std::string getDefaultKID(); std::string getDefaultKID();
void setDefaultKID(const std::string & kid); void setDefaultKID(const std::string &kid);
}; };
class SENC: public fullBox { class SENC : public fullBox{
public: public:
SENC(); SENC();
uint32_t getSampleCount() const; uint32_t getSampleCount() const;
void setSample(UUID_SampleEncryption_Sample newSample, size_t index); void setSample(UUID_SampleEncryption_Sample newSample, size_t index);
UUID_SampleEncryption_Sample getSample(size_t index) const; UUID_SampleEncryption_Sample getSample(size_t index) const;
std::string toPrettyString(uint32_t indent = 0) const; std::string toPrettyString(uint32_t indent = 0) const;
}; };
class SAIZ : public fullBox { class SAIZ : public fullBox{
public: public:
SAIZ(size_t entryCount = 0); SAIZ(size_t entryCount = 0);
size_t getDefaultSampleSize(); size_t getDefaultSampleSize();
size_t getEntryCount(); size_t getEntryCount();
size_t getEntrySize(size_t entryNo); size_t getEntrySize(size_t entryNo);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class SAIO : public fullBox { class SAIO : public fullBox{
public: public:
SAIO(size_t offset = 0); SAIO(size_t offset = 0);
size_t getEntryCount(); size_t getEntryCount();
size_t getEntrySize(size_t entryNo); size_t getEntrySize(size_t entryNo);
std::string toPrettyString(uint32_t indent = 0); 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); 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);
uint32_t getFlags(); uint32_t getFlags();
void setAlgorithmID(uint32_t newAlgorithmID); void setAlgorithmID(uint32_t newAlgorithmID);
uint32_t getAlgorithmID(); uint32_t getAlgorithmID();
void setIVSize(uint32_t newIVSize); void setIVSize(uint32_t newIVSize);
uint32_t getIVSize(); uint32_t getIVSize();
void setKID(std::string newKID); void setKID(std::string newKID);
std::string getKID(); std::string getKID();
uint32_t getSampleCount(); uint32_t getSampleCount();
void setSample(UUID_SampleEncryption_Sample newSample, size_t index); void setSample(UUID_SampleEncryption_Sample newSample, size_t index);
UUID_SampleEncryption_Sample getSample(size_t index); UUID_SampleEncryption_Sample getSample(size_t index);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class UUID_TrackEncryption: public UUID { class UUID_TrackEncryption : public UUID{
public: public:
UUID_TrackEncryption(); UUID_TrackEncryption();
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);
uint32_t getFlags(); uint32_t getFlags();
void setDefaultAlgorithmID(uint32_t newAlgorithmID); void setDefaultAlgorithmID(uint32_t newAlgorithmID);
uint32_t getDefaultAlgorithmID(); uint32_t getDefaultAlgorithmID();
void setDefaultIVSize(uint8_t newIVSize); void setDefaultIVSize(uint8_t newIVSize);
uint8_t getDefaultIVSize(); uint8_t getDefaultIVSize();
void setDefaultKID(std::string newKID); void setDefaultKID(std::string newKID);
std::string getDefaultKID(); std::string getDefaultKID();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class UUID_ProtectionSystemSpecificHeader: public UUID { class UUID_ProtectionSystemSpecificHeader : public UUID{
public: public:
UUID_ProtectionSystemSpecificHeader(); UUID_ProtectionSystemSpecificHeader();
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);
uint32_t getFlags(); uint32_t getFlags();
void setSystemID(std::string newID); void setSystemID(std::string newID);
std::string getSystemID(); std::string getSystemID();
void setDataSize(uint32_t newDataSize); void setDataSize(uint32_t newDataSize);
uint32_t getDataSize(); uint32_t getDataSize();
void setData(std::string newData); void setData(std::string newData);
std::string getData(); std::string getData();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class SINF: public Box { class SINF : public Box{
public: public:
SINF(); SINF();
void setEntry(Box & newEntry, uint32_t no); void setEntry(Box &newEntry, uint32_t no);
Box & getEntry(uint32_t no); Box &getEntry(uint32_t no);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class FRMA: public Box { class FRMA : public Box{
public: public:
FRMA(const std::string & originalFormat = ""); FRMA(const std::string &originalFormat = "");
void setOriginalFormat(const 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(uint32_t schemeType = 0x636E6563, uint32_t schemeVersion = 0x00000100);//CENC defaults 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);
uint32_t getSchemeVersion(); uint32_t getSchemeVersion();
void setSchemeURI(std::string newURI); void setSchemeURI(std::string newURI);
std::string getSchemeURI(); std::string getSchemeURI();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class SCHI: public Box { class SCHI : public Box{
public: public:
SCHI(); SCHI();
void setContent(Box & newContent); void setContent(Box &newContent);
Box & getContent(); Box &getContent();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
} }// namespace MP4

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,144 +1,101 @@
#include "mp4_ms.h"
#include "mp4_encryption.h" /*LTS*/ #include "mp4_encryption.h" /*LTS*/
#include "mp4_ms.h"
namespace MP4 { namespace MP4{
static char c2hex(int c) { static char c2hex(int c){
if (c >= '0' && c <= '9') return c - '0'; if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return 0; return 0;
} }
SDTP::SDTP(){memcpy(data + 4, "sdtp", 4);}
SDTP::SDTP() { void SDTP::setVersion(uint32_t newVersion){setInt8(newVersion, 0);}
memcpy(data + 4, "sdtp", 4);
}
void SDTP::setVersion(uint32_t newVersion) { uint32_t SDTP::getVersion(){return getInt8(0);}
setInt8(newVersion, 0);
}
uint32_t SDTP::getVersion() { void SDTP::setValue(uint32_t newValue, size_t index){setInt8(newValue, index);}
return getInt8(0);
}
void SDTP::setValue(uint32_t newValue, size_t index) { uint32_t SDTP::getValue(size_t index){return getInt8(index);}
setInt8(newValue, index);
}
uint32_t SDTP::getValue(size_t index) { std::string SDTP::toPrettyString(uint32_t indent){
return getInt8(index);
}
std::string SDTP::toPrettyString(uint32_t indent) {
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[sdtp] Sample Dependancy Type (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[sdtp] Sample Dependancy Type (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "Samples: " << (boxedSize() - 12) << std::endl; r << std::string(indent + 1, ' ') << "Samples: " << (boxedSize() - 12) << std::endl;
for (size_t i = 1; i <= boxedSize() - 12; ++i) { for (size_t i = 1; i <= boxedSize() - 12; ++i){
uint32_t val = getValue(i + 3); uint32_t val = getValue(i + 3);
r << std::string(indent + 2, ' ') << "[" << i << "] = "; r << std::string(indent + 2, ' ') << "[" << i << "] = ";
switch (val & 3) { switch (val & 3){
case 0: case 0: r << " "; break;
r << " "; case 1: r << "Redundant, "; break;
break; case 2: r << "Not redundant, "; break;
case 1: case 3: r << "Error, "; break;
r << "Redundant, ";
break;
case 2:
r << "Not redundant, ";
break;
case 3:
r << "Error, ";
break;
} }
switch (val & 12) { switch (val & 12){
case 0: case 0: r << " "; break;
r << " "; case 4: r << "Not disposable, "; break;
break; case 8: r << "Disposable, "; break;
case 4: case 12: r << "Error, "; break;
r << "Not disposable, ";
break;
case 8:
r << "Disposable, ";
break;
case 12:
r << "Error, ";
break;
} }
switch (val & 48) { switch (val & 48){
case 0: case 0: r << " "; break;
r << " "; case 16: r << "IFrame, "; break;
break; case 32: r << "Not IFrame, "; break;
case 16: case 48: r << "Error, "; break;
r << "IFrame, ";
break;
case 32:
r << "Not IFrame, ";
break;
case 48:
r << "Error, ";
break;
} }
r << "(" << val << ")" << std::endl; r << "(" << val << ")" << std::endl;
} }
return r.str(); return r.str();
} }
UUID::UUID() { UUID::UUID(){
memcpy(data + 4, "uuid", 4); memcpy(data + 4, "uuid", 4);
setInt64(0, 0); setInt64(0, 0);
setInt64(0, 8); setInt64(0, 8);
} }
std::string UUID::getUUID() { std::string UUID::getUUID(){
std::stringstream r; std::stringstream r;
r << std::hex; r << std::hex;
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i){
if (i == 4 || i == 6 || i == 8 || i == 10) { if (i == 4 || i == 6 || i == 8 || i == 10){r << "-";}
r << "-";
}
r << std::setfill('0') << std::setw(2) << std::right << (int)(data[8 + i]); r << std::setfill('0') << std::setw(2) << std::right << (int)(data[8 + i]);
} }
return r.str(); return r.str();
} }
void UUID::setUUID(const std::string & uuid_string) { void UUID::setUUID(const std::string &uuid_string){
//reset UUID to zero // reset UUID to zero
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i){((uint32_t *)(data + 8))[i] = 0;}
((uint32_t *)(data + 8))[i] = 0; // set the UUID from the string, char by char
}
//set the UUID from the string, char by char
int i = 0; int i = 0;
for (size_t j = 0; j < uuid_string.size(); ++j) { for (size_t j = 0; j < uuid_string.size(); ++j){
if (uuid_string[j] == '-') { if (uuid_string[j] == '-'){continue;}
continue;
}
data[8 + i / 2] |= (c2hex(uuid_string[j]) << ((~i & 1) << 2)); data[8 + i / 2] |= (c2hex(uuid_string[j]) << ((~i & 1) << 2));
++i; ++i;
} }
} }
void UUID::setUUID(const char * raw_uuid) { void UUID::setUUID(const char *raw_uuid){memcpy(data + 8, raw_uuid, 16);}
memcpy(data + 8, raw_uuid, 16);
}
std::string UUID::toPrettyString(uint32_t indent) { std::string UUID::toPrettyString(uint32_t indent){
std::string UUID = getUUID(); std::string UUID = getUUID();
if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f") { if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f"){
return ((UUID_TrackFragmentReference *)this)->toPrettyString(indent); return ((UUID_TrackFragmentReference *)this)->toPrettyString(indent);
} }
/*LTS-START*/ /*LTS-START*/
if (UUID == "a2394f52-5a9b-4f14-a244-6c427c648df4") { if (UUID == "a2394f52-5a9b-4f14-a244-6c427c648df4"){
return ((UUID_SampleEncryption *)this)->toPrettyString(indent); return ((UUID_SampleEncryption *)this)->toPrettyString(indent);
} }
if (UUID == "8974dbce-7be7-4c51-84f9-7148f9882554") { if (UUID == "8974dbce-7be7-4c51-84f9-7148f9882554"){
return ((UUID_TrackEncryption *)this)->toPrettyString(indent); return ((UUID_TrackEncryption *)this)->toPrettyString(indent);
} }
if (UUID == "d08a4f18-10f3-4a82-b6c8-32d8aba183d3") { if (UUID == "d08a4f18-10f3-4a82-b6c8-32d8aba183d3"){
return ((UUID_ProtectionSystemSpecificHeader *)this)->toPrettyString(indent); return ((UUID_ProtectionSystemSpecificHeader *)this)->toPrettyString(indent);
} }
if (UUID == "6d1d9b05-42d5-44e6-80e2-141daff757b2") { if (UUID == "6d1d9b05-42d5-44e6-80e2-141daff757b2"){
return ((UUID_TFXD *)this)->toPrettyString(indent); return ((UUID_TFXD *)this)->toPrettyString(indent);
} }
/*LTS-END*/ /*LTS-END*/
@ -149,139 +106,122 @@ namespace MP4 {
return r.str(); return r.str();
} }
UUID_TrackFragmentReference::UUID_TrackFragmentReference() { UUID_TrackFragmentReference::UUID_TrackFragmentReference(){
setUUID((std::string)"d4807ef2-ca39-4695-8e54-26cb9e46a79f"); setUUID((std::string) "d4807ef2-ca39-4695-8e54-26cb9e46a79f");
} }
void UUID_TrackFragmentReference::setVersion(uint32_t newVersion) { void UUID_TrackFragmentReference::setVersion(uint32_t newVersion){setInt8(newVersion, 16);}
setInt8(newVersion, 16);
}
uint32_t UUID_TrackFragmentReference::getVersion() { uint32_t UUID_TrackFragmentReference::getVersion(){return getInt8(16);}
return getInt8(16);
}
void UUID_TrackFragmentReference::setFlags(uint32_t newFlags) { void UUID_TrackFragmentReference::setFlags(uint32_t newFlags){setInt24(newFlags, 17);}
setInt24(newFlags, 17);
}
uint32_t UUID_TrackFragmentReference::getFlags() { uint32_t UUID_TrackFragmentReference::getFlags(){return getInt24(17);}
return getInt24(17);
}
void UUID_TrackFragmentReference::setFragmentCount(uint32_t newCount) { void UUID_TrackFragmentReference::setFragmentCount(uint32_t newCount){setInt8(newCount, 20);}
setInt8(newCount, 20);
}
uint32_t UUID_TrackFragmentReference::getFragmentCount() { uint32_t UUID_TrackFragmentReference::getFragmentCount(){return getInt8(20);}
return getInt8(20);
}
void UUID_TrackFragmentReference::setTime(size_t num, uint64_t newTime) { void UUID_TrackFragmentReference::setTime(size_t num, uint64_t newTime){
if (getVersion() == 0) { if (getVersion() == 0){
setInt32(newTime, 21 + (num * 8)); setInt32(newTime, 21 + (num * 8));
} else { }else{
setInt64(newTime, 21 + (num * 16)); setInt64(newTime, 21 + (num * 16));
} }
} }
uint64_t UUID_TrackFragmentReference::getTime(size_t num) { uint64_t UUID_TrackFragmentReference::getTime(size_t num){
if (getVersion() == 0) { if (getVersion() == 0){
return getInt32(21 + (num * 8)); return getInt32(21 + (num * 8));
} else { }else{
return getInt64(21 + (num * 16)); return getInt64(21 + (num * 16));
} }
} }
void UUID_TrackFragmentReference::setDuration(size_t num, uint64_t newDuration) { void UUID_TrackFragmentReference::setDuration(size_t num, uint64_t newDuration){
if (getVersion() == 0) { if (getVersion() == 0){
setInt32(newDuration, 21 + (num * 8) + 4); setInt32(newDuration, 21 + (num * 8) + 4);
} else { }else{
setInt64(newDuration, 21 + (num * 16) + 8); setInt64(newDuration, 21 + (num * 16) + 8);
} }
} }
uint64_t UUID_TrackFragmentReference::getDuration(size_t num) { uint64_t UUID_TrackFragmentReference::getDuration(size_t num){
if (getVersion() == 0) { if (getVersion() == 0){
return getInt32(21 + (num * 8) + 4); return getInt32(21 + (num * 8) + 4);
} else { }else{
return getInt64(21 + (num * 16) + 8); return getInt64(21 + (num * 16) + 8);
} }
} }
std::string UUID_TrackFragmentReference::toPrettyString(uint32_t indent) { std::string UUID_TrackFragmentReference::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent, ' ') << "[d4807ef2-ca39-4695-8e54-26cb9e46a79f] Track Fragment Reference (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[d4807ef2-ca39-4695-8e54-26cb9e46a79f] Track Fragment Reference ("
<< boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl; r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 1, ' ') << "Fragments: " << getFragmentCount() << std::endl; r << std::string(indent + 1, ' ') << "Fragments: " << getFragmentCount() << std::endl;
int j = getFragmentCount(); int j = getFragmentCount();
for (int i = 0; i < j; ++i) { for (int i = 0; i < j; ++i){
r << std::string(indent + 2, ' ') << "[" << i << "] Time = " << getTime(i) << ", Duration = " << getDuration(i) << std::endl; r << std::string(indent + 2, ' ') << "[" << i << "] Time = " << getTime(i)
<< ", Duration = " << getDuration(i) << std::endl;
} }
return r.str(); return r.str();
} }
UUID_TFXD::UUID_TFXD() { UUID_TFXD::UUID_TFXD(){
setUUID((std::string)"6d1d9b05-42d5-44e6-80e2-141daff757b2"); setUUID((std::string) "6d1d9b05-42d5-44e6-80e2-141daff757b2");
setVersion(0); setVersion(0);
setFlags(0); setFlags(0);
} }
void UUID_TFXD::setVersion(uint32_t newVersion) { void UUID_TFXD::setVersion(uint32_t newVersion){setInt8(newVersion, 16);}
setInt8(newVersion, 16);
}
uint32_t UUID_TFXD::getVersion() { uint32_t UUID_TFXD::getVersion(){return getInt8(16);}
return getInt8(16);
}
void UUID_TFXD::setFlags(uint32_t newFlags) { void UUID_TFXD::setFlags(uint32_t newFlags){setInt24(newFlags, 17);}
setInt24(newFlags, 17);
}
uint32_t UUID_TFXD::getFlags() { uint32_t UUID_TFXD::getFlags(){return getInt24(17);}
return getInt24(17);
}
void UUID_TFXD::setTime(uint64_t newTime) { void UUID_TFXD::setTime(uint64_t newTime){
if (getVersion() == 0) { if (getVersion() == 0){
setInt32(newTime, 20); setInt32(newTime, 20);
} else { }else{
setInt64(newTime, 20); setInt64(newTime, 20);
} }
} }
uint64_t UUID_TFXD::getTime() { uint64_t UUID_TFXD::getTime(){
if (getVersion() == 0) { if (getVersion() == 0){
return getInt32(20); return getInt32(20);
} else { }else{
return getInt64(20); return getInt64(20);
} }
} }
void UUID_TFXD::setDuration(uint64_t newDuration) { void UUID_TFXD::setDuration(uint64_t newDuration){
if (getVersion() == 0) { if (getVersion() == 0){
setInt32(newDuration, 24); setInt32(newDuration, 24);
} else { }else{
setInt64(newDuration, 28); setInt64(newDuration, 28);
} }
} }
uint64_t UUID_TFXD::getDuration() { uint64_t UUID_TFXD::getDuration(){
if (getVersion() == 0) { if (getVersion() == 0){
return getInt32(24); return getInt32(24);
} else { }else{
return getInt64(28); return getInt64(28);
} }
} }
std::string UUID_TFXD::toPrettyString(uint32_t indent) { std::string UUID_TFXD::toPrettyString(uint32_t indent){
std::stringstream r; std::stringstream r;
setUUID((std::string)"6d1d9b05-42d5-44e6-80e2-141daff757b2"); setUUID((std::string) "6d1d9b05-42d5-44e6-80e2-141daff757b2");
r << std::string(indent, ' ') << "[6d1d9b05-42d5-44e6-80e2-141daff757b2] TFXD Box (" << boxedSize() << ")" << std::endl; r << std::string(indent, ' ') << "[6d1d9b05-42d5-44e6-80e2-141daff757b2] TFXD Box ("
<< boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl; r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 1, ' ') << "Time = " << getTime() << std::endl; r << std::string(indent + 1, ' ') << "Time = " << getTime() << std::endl;
r << std::string(indent + 1, ' ') << "Duration = " << getDuration() << std::endl; r << std::string(indent + 1, ' ') << "Duration = " << getDuration() << std::endl;
return r.str(); return r.str();
} }
} }// namespace MP4

View file

@ -1,53 +1,53 @@
#pragma once #pragma once
#include "mp4.h" #include "mp4.h"
namespace MP4 { namespace MP4{
class SDTP: public Box { class SDTP : public Box{
public: public:
SDTP(); SDTP();
void setVersion(uint32_t newVersion); void setVersion(uint32_t newVersion);
uint32_t getVersion(); uint32_t getVersion();
void setValue(uint32_t newValue, size_t index); void setValue(uint32_t newValue, size_t index);
uint32_t getValue(size_t index); uint32_t getValue(size_t index);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class UUID: public Box { class UUID : public Box{
public: public:
UUID(); UUID();
std::string getUUID(); std::string getUUID();
void setUUID(const std::string & uuid_string); void setUUID(const std::string &uuid_string);
void setUUID(const char * raw_uuid); void setUUID(const char *raw_uuid);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class UUID_TrackFragmentReference: public UUID { class UUID_TrackFragmentReference : public UUID{
public: public:
UUID_TrackFragmentReference(); UUID_TrackFragmentReference();
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);
uint32_t getFlags(); uint32_t getFlags();
void setFragmentCount(uint32_t newCount); void setFragmentCount(uint32_t newCount);
uint32_t getFragmentCount(); uint32_t getFragmentCount();
void setTime(size_t num, uint64_t newTime); void setTime(size_t num, uint64_t newTime);
uint64_t getTime(size_t num); uint64_t getTime(size_t num);
void setDuration(size_t num, uint64_t newDuration); void setDuration(size_t num, uint64_t newDuration);
uint64_t getDuration(size_t num); uint64_t getDuration(size_t num);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
class UUID_TFXD: public UUID { class UUID_TFXD : public UUID{
public: public:
UUID_TFXD(); UUID_TFXD();
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);
uint32_t getFlags(); uint32_t getFlags();
void setTime(uint64_t newTime); void setTime(uint64_t newTime);
uint64_t getTime(); uint64_t getTime();
void setDuration(uint64_t newDuration); void setDuration(uint64_t newDuration);
uint64_t getDuration(); uint64_t getDuration();
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
}; };
} }// namespace MP4

View file

@ -81,4 +81,3 @@ namespace Mpeg{
return res; return res;
} }
}// namespace Mpeg }// namespace Mpeg

View file

@ -42,4 +42,3 @@ namespace Mpeg{
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 }// namespace Mpeg

View file

@ -34,8 +34,7 @@ namespace nalu{
size_t dataLen = data.size(); size_t dataLen = data.size();
size_t 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
result[resPtr++] = data[dataPtr++]; result[resPtr++] = data[dataPtr++];
result[resPtr++] = data[dataPtr++]; result[resPtr++] = data[dataPtr++];
dataPtr++; // Skip the emulation prevention byte dataPtr++; // Skip the emulation prevention byte
@ -129,4 +128,3 @@ namespace nalu{
return newOffset; return newOffset;
} }
}// namespace nalu }// namespace nalu

View file

@ -18,4 +18,3 @@ namespace nalu{
const char *scanAnnexB(const char *data, uint32_t dataSize); const char *scanAnnexB(const char *data, uint32_t dataSize);
const char *nalEndPosition(const char *data, uint32_t dataSize); const char *nalEndPosition(const char *data, uint32_t dataSize);
}// namespace nalu }// namespace nalu

View file

@ -1,13 +1,13 @@
#include "ogg.h" #include "bitstream.h"
#include "defines.h" #include "defines.h"
#include <string.h> #include "ogg.h"
#include <stdlib.h>
#include <sstream>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <iomanip> #include <iomanip>
#include "bitstream.h" #include <sstream>
#include <stdlib.h>
#include <string.h>
namespace OGG { namespace OGG{
oggSegment::oggSegment(){ oggSegment::oggSegment(){
isKeyframe = 0; isKeyframe = 0;
@ -16,21 +16,17 @@ namespace OGG {
framesSinceKeyFrame = 0; framesSinceKeyFrame = 0;
} }
std::deque<unsigned int> decodeXiphSize(char * data, size_t len){ std::deque<unsigned int> decodeXiphSize(char *data, size_t len){
std::deque<unsigned int> res; std::deque<unsigned int> res;
res.push_back(0); res.push_back(0);
for (unsigned int i = 0; i < len; i++){ for (unsigned int i = 0; i < len; i++){
*res.rbegin() += data[i]; *res.rbegin() += data[i];
if (data[i] != 0xFF){ if (data[i] != 0xFF){res.push_back(0);}
res.push_back(0);
}
}
if (*res.rbegin() == 0){
res.resize(res.size() - 1);
} }
if (*res.rbegin() == 0){res.resize(res.size() - 1);}
return res; return res;
} }
inline long long unsigned int get_64(char * data){ inline long long unsigned int get_64(char *data){
long long unsigned int temp = 0; long long unsigned int temp = 0;
for (int i = 7; i >= 0; --i){ for (int i = 7; i >= 0; --i){
temp <<= 8; temp <<= 8;
@ -39,7 +35,7 @@ namespace OGG {
return temp; return temp;
} }
inline long unsigned int get_32(char * data){ inline long unsigned int get_32(char *data){
long unsigned int temp = 0; long unsigned int temp = 0;
for (int i = 3; i >= 0; --i){ for (int i = 3; i >= 0; --i){
temp <<= 8; temp <<= 8;
@ -48,22 +44,20 @@ namespace OGG {
return temp; return temp;
} }
inline void set_64(char * data, long unsigned int val){ inline void set_64(char *data, long unsigned int val){
for (int i = 0; i < 8; ++i){ for (int i = 0; i < 8; ++i){
data[i] = val & 0xFF; data[i] = val & 0xFF;
val >>= 8; val >>= 8;
} }
} }
inline void set_32(char *data, long unsigned int val){
inline void set_32(char * data, long unsigned int val){
for (int i = 0; i < 4; ++i){ for (int i = 0; i < 4; ++i){
data[i] = val & 0xFF; data[i] = val & 0xFF;
val >>= 8; val >>= 8;
} }
} }
Page::Page(){ Page::Page(){
framesSeen = 0; framesSeen = 0;
lastKeyFrame = 0; lastKeyFrame = 0;
@ -74,66 +68,60 @@ namespace OGG {
memset(data, 0, 282); memset(data, 0, 282);
} }
Page::Page(const Page & rhs){ Page::Page(const Page &rhs){
framesSeen=rhs.framesSeen; framesSeen = rhs.framesSeen;
pageSequenceNumber = rhs.pageSequenceNumber; pageSequenceNumber = rhs.pageSequenceNumber;
lastKeyFrame = rhs.lastKeyFrame; lastKeyFrame = rhs.lastKeyFrame;
sampleRate = rhs.sampleRate; sampleRate = rhs.sampleRate;
firstSample = rhs.firstSample; firstSample = rhs.firstSample;
totalFrames= rhs.totalFrames; totalFrames = rhs.totalFrames;
memcpy(data, rhs.data, 282); memcpy(data, rhs.data, 282);
segments = rhs.segments; segments = rhs.segments;
} }
void Page::operator = (const Page & rhs){ void Page::operator=(const Page &rhs){
framesSeen=rhs.framesSeen; framesSeen = rhs.framesSeen;
pageSequenceNumber = rhs.pageSequenceNumber; pageSequenceNumber = rhs.pageSequenceNumber;
lastKeyFrame = rhs.lastKeyFrame; lastKeyFrame = rhs.lastKeyFrame;
firstSample = rhs.firstSample; firstSample = rhs.firstSample;
sampleRate = rhs.sampleRate; sampleRate = rhs.sampleRate;
totalFrames= rhs.totalFrames; totalFrames = rhs.totalFrames;
memcpy(data, rhs.data, 282); memcpy(data, rhs.data, 282);
segments = rhs.segments; segments = rhs.segments;
} }
unsigned int Page::calcPayloadSize(){ unsigned int Page::calcPayloadSize(){
unsigned int retVal = 0; unsigned int retVal = 0;
for (unsigned int i = 0; i < segments.size(); i++){ for (unsigned int i = 0; i < segments.size(); i++){retVal += segments[i].size();}
retVal += segments[i].size();
}
return retVal; return retVal;
} }
/// Reads an OGG Page from the source and if valid, removes it from source. /// Reads an OGG Page from the source and if valid, removes it from source.
bool Page::read(std::string & newData){ bool Page::read(std::string &newData){
int len = newData.size(); int len = newData.size();
int total = 0; int total = 0;
segments.clear(); segments.clear();
if (newData.size() < 27){ if (newData.size() < 27){return false;}
return false;
}
if (newData.substr(0, 4) != "OggS"){ if (newData.substr(0, 4) != "OggS"){
FAIL_MSG("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
if (newData.size() < 27u + getPageSegments()){ //check input size if (newData.size() < 27u + getPageSegments()){// check input size
return false; return false;
} }
memcpy(data + 27, newData.data()+27, getPageSegments()); memcpy(data + 27, newData.data() + 27, getPageSegments());
std::deque<unsigned int> segSizes = decodeXiphSize(data + 27, getPageSegments()); std::deque<unsigned int> segSizes = decodeXiphSize(data + 27, getPageSegments());
for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){ for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
total += *it; total += *it;
} }
total += 27; total += 27;
//return false if the segment is not complete // return false if the segment is not complete
total += getPageSegments(); total += getPageSegments();
if(total >= len){ if (total >= len){return false;}
return false;
}
newData.erase(0, getPageSegments()+27); newData.erase(0, getPageSegments() + 27);
for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){ for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
segments.push_back(std::string(newData.data(), *it)); segments.push_back(std::string(newData.data(), *it));
newData.erase(0, *it); newData.erase(0, *it);
@ -143,11 +131,10 @@ namespace OGG {
return true; return true;
} }
bool Page::read(FILE *inFile){
bool Page::read(FILE * inFile){
segments.clear(); segments.clear();
int oriPos = ftell(inFile); int oriPos = ftell(inFile);
//INFO_MSG("pos: %d", oriPos); // INFO_MSG("pos: %d", oriPos);
if (!fread(data, 27, 1, inFile)){ if (!fread(data, 27, 1, inFile)){
fseek(inFile, oriPos, SEEK_SET); fseek(inFile, oriPos, SEEK_SET);
FAIL_MSG("failed to fread(data, 27, 1, inFile) @ pos %d", oriPos); FAIL_MSG("failed to fread(data, 27, 1, inFile) @ pos %d", oriPos);
@ -165,12 +152,11 @@ namespace OGG {
std::deque<unsigned int> segSizes = decodeXiphSize(data + 27, getPageSegments()); std::deque<unsigned int> segSizes = decodeXiphSize(data + 27, getPageSegments());
for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){ for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
if (*it){ if (*it){
char * thisSeg = (char *)malloc(*it * sizeof(char)); char *thisSeg = (char *)malloc(*it * sizeof(char));
if (!thisSeg){ if (!thisSeg){WARN_MSG("malloc failed");}
WARN_MSG("malloc failed");
}
if (!fread(thisSeg, *it, 1, inFile)){ if (!fread(thisSeg, *it, 1, inFile)){
WARN_MSG("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;
} }
@ -179,13 +165,12 @@ namespace OGG {
}else{ }else{
segments.push_back(std::string("", 0)); segments.push_back(std::string("", 0));
} }
} }
return true; return true;
} }
bool Page::getSegment(unsigned int index, std::string & ret){ bool Page::getSegment(unsigned int index, std::string &ret){
if (index >= segments.size()){ if (index >= segments.size()){
ret.clear(); ret.clear();
return false; return false;
@ -194,94 +179,60 @@ namespace OGG {
return true; return true;
} }
const char * Page::getSegment(unsigned int index){ const char *Page::getSegment(unsigned int index){
if (index >= segments.size()){ if (index >= segments.size()){return 0;}
return 0;
}
return segments[index].data(); return segments[index].data();
} }
unsigned long Page::getSegmentLen(unsigned int index){ unsigned long Page::getSegmentLen(unsigned int index){
if (index >= segments.size()){ if (index >= segments.size()){return 0;}
return 0;
}
return segments[index].size(); return segments[index].size();
} }
void Page::setMagicNumber(){ void Page::setMagicNumber(){memcpy(data, "OggS", 4);}
memcpy(data, "OggS", 4);
}
char Page::getVersion(){ char Page::getVersion(){return data[4];}
return data[4];
}
void Page::setVersion(char newVal){ void Page::setVersion(char newVal){data[4] = newVal;}
data[4] = newVal;
}
char Page::getHeaderType(){ char Page::getHeaderType(){return data[5];}
return data[5];
}
void Page::setHeaderType(char newVal){ void Page::setHeaderType(char newVal){data[5] = newVal;}
data[5] = newVal;
}
long long unsigned int Page::getGranulePosition(){ long long unsigned int Page::getGranulePosition(){return get_64(data + 6);}
return get_64(data + 6);
}
void Page::setGranulePosition(long long unsigned int newVal){ void Page::setGranulePosition(long long unsigned int newVal){set_64(data + 6, newVal);}
set_64(data + 6, newVal);
}
long unsigned int Page::getBitstreamSerialNumber(){ long unsigned int Page::getBitstreamSerialNumber(){
//return ntohl(((long unsigned int*)(data+14))[0]); // return ntohl(((long unsigned int*)(data+14))[0]);
return get_32(data + 14); return get_32(data + 14);
} }
void Page::setBitstreamSerialNumber(long unsigned int newVal){ void Page::setBitstreamSerialNumber(long unsigned int newVal){set_32(data + 14, newVal);}
set_32(data + 14, newVal);
}
long unsigned int Page::getPageSequenceNumber(){ long unsigned int Page::getPageSequenceNumber(){return get_32(data + 18);}
return get_32(data + 18);
}
void Page::setPageSequenceNumber(long unsigned int newVal){ void Page::setPageSequenceNumber(long unsigned int newVal){set_32(data + 18, newVal);}
set_32(data + 18, newVal);
}
long unsigned int Page::getCRCChecksum(){ long unsigned int Page::getCRCChecksum(){return get_32(data + 22);}
return get_32(data + 22);
}
void Page::setCRCChecksum(long unsigned int newVal){ void Page::setCRCChecksum(long unsigned int newVal){set_32(data + 22, newVal);}
set_32(data + 22, newVal);
}
char Page::getPageSegments(){ char Page::getPageSegments(){return data[26];}
return data[26];
}
inline void Page::setPageSegments(char newVal){ inline void Page::setPageSegments(char newVal){data[26] = newVal;}
data[26] = newVal;
}
bool Page::verifyChecksum(){ bool Page::verifyChecksum(){
if (getCRCChecksum() == calcChecksum()){ //NOTE: calcChecksum is currently not functional (it will always return 0) if (getCRCChecksum() == calcChecksum()){// NOTE: calcChecksum is currently not functional (it will always return 0)
return true; return true;
} else { }else{
return false; return false;
} }
} }
bool Page::possiblyContinued(){ bool Page::possiblyContinued(){
if (getPageSegments() == 255){ if (getPageSegments() == 255){
if (data[281] == 255){ if (data[281] == 255){return true;}
return true;
}
} }
return false; return false;
} }
@ -293,99 +244,65 @@ namespace OGG {
r << std::string(indent + 2, ' ') << "Header type:"; r << std::string(indent + 2, ' ') << "Header type:";
if (!getHeaderType()){ if (!getHeaderType()){
r << " Normal"; r << " Normal";
} else { }else{
if (getHeaderType() & Continued){ if (getHeaderType() & Continued){r << " Continued";}
r << " Continued"; if (getHeaderType() & BeginOfStream){r << " BeginOfStream";}
} if (getHeaderType() & EndOfStream){r << " EndOfStream";}
if (getHeaderType() & BeginOfStream){
r << " BeginOfStream";
}
if (getHeaderType() & EndOfStream){
r << " EndOfStream";
}
} }
r << " (" << (int)getHeaderType() << ")" << std::endl; r << " (" << (int)getHeaderType() << ")" << std::endl;
r << std::string(indent + 2, ' ') << "Granule position: " << std::hex << std::setw(16) << std::setfill('0') << getGranulePosition() << std::dec << std::endl; r << std::string(indent + 2, ' ') << "Granule position: " << std::hex << std::setw(16)
<< std::setfill('0') << getGranulePosition() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl; r << std::string(indent + 2, ' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl;
r << std::string(indent + 2, ' ') << "Sequence number: " << getPageSequenceNumber() << std::endl; r << std::string(indent + 2, ' ') << "Sequence number: " << getPageSequenceNumber() << std::endl;
r << std::string(indent + 2, ' ') << "Checksum Correct: " << verifyChecksum() << std::endl; r << std::string(indent + 2, ' ') << "Checksum Correct: " << verifyChecksum() << std::endl;
//r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl; // r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "Checksum: " << getCRCChecksum() << std::endl; r << std::string(indent + 2, ' ') << "Checksum: " << getCRCChecksum() << std::endl;
r << std::string(indent + 2, ' ') << (int)getPageSegments() << " segments:" << std::endl; r << std::string(indent + 2, ' ') << (int)getPageSegments() << " segments:" << std::endl;
r << std::string(indent + 3, ' '); r << std::string(indent + 3, ' ');
for (unsigned int i = 0; i < segments.size(); i++){ for (unsigned int i = 0; i < segments.size(); i++){r << " " << segments[i].size();}
r << " " << segments[i].size();
}
r << std::endl; r << std::endl;
return r.str(); return r.str();
} }
inline unsigned int crc32(unsigned int crc, const char * data, size_t len){ inline unsigned int crc32(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] = { static const unsigned int table[256] ={
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x130476DCU, 0x17C56B6BU, 0x1A864DB2U,
0x130476DCU, 0x17C56B6BU, 0x1A864DB2U, 0x1E475005U, 0x1E475005U, 0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, 0x350C9B64U, 0x31CD86D3U,
0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, 0x3C8EA00AU, 0x384FBDBDU, 0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, 0x5F15ADACU,
0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, 0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU,
0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x95609039U, 0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xBE2B5B58U, 0xBAEA46EFU,
0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U, 0xB7A96036U, 0xB3687D81U, 0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0xD4326D90U,
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U, 0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, 0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU,
0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xEC7DD02DU, 0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0x278206ABU, 0x23431B1CU,
0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U, 0x2E003DC5U, 0x2AC12072U, 0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0x018AEB13U,
0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, 0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U,
0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U, 0x53DC6066U, 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, 0xACA5C697U, 0xA864DB20U,
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, 0xA527FDF9U, 0xA1E6E04EU, 0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0x8AAD2B2FU,
0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, 0xF3B06B3BU, 0xF771768CU, 0xFA325055U,
0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U, 0xFEF34DE2U, 0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0xD5B88683U, 0xD1799B34U,
0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0xDC3ABDEDU, 0xD8FBA05AU, 0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, 0x7A089632U,
0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU, 0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U,
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x285E1D47U, 0x36194D42U, 0x32D850F5U, 0x3F9B762CU, 0x3B5A6B9BU, 0x0315D626U, 0x07D4CB91U,
0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U, 0x53DC6066U, 0x0A97ED48U, 0x0E56F0FFU, 0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U, 0xF12F560EU,
0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U, 0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU,
0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU, 0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU, 0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U,
0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0xC960EBB3U, 0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U, 0xAE3AFBA2U, 0xAAFBE615U,
0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0xA7B8C0CCU, 0xA379DD7BU, 0x9B3660C6U, 0x9FF77D71U, 0x92B45BA8U, 0x9675461FU, 0x8832161AU,
0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U, 0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U,
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, 0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU, 0x7B827D21U, 0x7F436096U, 0x7200464FU,
0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U, 0x76C15BF8U, 0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U, 0x119B4BE9U, 0x155A565EU,
0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0x18197087U, 0x1CD86D30U, 0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU, 0x3793A651U,
0xD5B88683U, 0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U, 0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U,
0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, 0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U, 0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU,
0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0xDBEE767CU, 0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU, 0xEEE2ED18U, 0xF0A5BD1DU, 0xF464A0AAU,
0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU, 0xF9278673U, 0xFDE69BC4U, 0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U, 0x9ABC8BD5U,
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU, 0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U,
0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U, 0x285E1D47U, 0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U,
0x36194D42U, 0x32D850F5U, 0x3F9B762CU, 0x3B5A6B9BU,
0x0315D626U, 0x07D4CB91U, 0x0A97ED48U, 0x0E56F0FFU,
0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U,
0xF12F560EU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U,
0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU,
0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU,
0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U, 0xC960EBB3U,
0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U,
0xAE3AFBA2U, 0xAAFBE615U, 0xA7B8C0CCU, 0xA379DD7BU,
0x9B3660C6U, 0x9FF77D71U, 0x92B45BA8U, 0x9675461FU,
0x8832161AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U,
0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U,
0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU,
0x7B827D21U, 0x7F436096U, 0x7200464FU, 0x76C15BF8U,
0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U,
0x119B4BE9U, 0x155A565EU, 0x18197087U, 0x1CD86D30U,
0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU,
0x3793A651U, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U,
0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U,
0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U,
0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU, 0xDBEE767CU,
0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU, 0xEEE2ED18U,
0xF0A5BD1DU, 0xF464A0AAU, 0xF9278673U, 0xFDE69BC4U,
0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U,
0x9ABC8BD5U, 0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU,
0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U,
0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U,
}; };
while (len > 0){ while (len > 0){
@ -396,7 +313,7 @@ namespace OGG {
return crc; return crc;
} }
long unsigned int Page::calcChecksum(){ //implement in sending out page, probably delete this -- probably don't delete this because this function appears to be in use long unsigned int Page::calcChecksum(){// implement in sending out page, probably delete this -- probably don't delete this because this function appears to be in use
long unsigned int retVal = 0; long unsigned int retVal = 0;
/* /*
long unsigned int oldChecksum = getCRCChecksum(); long unsigned int oldChecksum = getCRCChecksum();
@ -417,19 +334,15 @@ namespace OGG {
int Page::getPayloadSize(){ int Page::getPayloadSize(){
size_t res = 0; size_t res = 0;
for (unsigned int i = 0; i < segments.size(); i++){ for (unsigned int i = 0; i < segments.size(); i++){res += segments[i].size();}
res += segments[i].size();
}
return res; return res;
} }
const std::deque<std::string> & Page::getAllSegments(){ const std::deque<std::string> &Page::getAllSegments(){return segments;}
return segments;
}
void Page::prepareNext(bool continueMe){ void Page::prepareNext(bool continueMe){
clear(0, -1, getBitstreamSerialNumber(), getPageSequenceNumber() + 1); clear(0, -1, getBitstreamSerialNumber(), getPageSequenceNumber() + 1);
if (continueMe){ //noting that the page will be continued if (continueMe){// noting that the page will be continued
setHeaderType(OGG::Continued); setHeaderType(OGG::Continued);
} }
} }
@ -444,27 +357,27 @@ namespace OGG {
setPageSequenceNumber(PSN); setPageSequenceNumber(PSN);
} }
unsigned int Page::addSegment(const std::string &payload){// returns added bytes
unsigned int Page::addSegment(const std::string & payload){ //returns added bytes
segments.push_back(payload); segments.push_back(payload);
return payload.size(); return payload.size();
} }
unsigned int Page::addSegment(const char * content, unsigned int length){ unsigned int Page::addSegment(const char *content, unsigned int length){
segments.push_back(std::string(content, length)); segments.push_back(std::string(content, length));
return length; return length;
} }
unsigned int Page::overFlow(){ //returns the amount of bytes that don't fit in this page from the segments; unsigned int Page::overFlow(){// returns the amount of bytes that don't fit in this page from the segments;
unsigned int retVal = 0; unsigned int retVal = 0;
unsigned int curSegNum = 0;//the current segment number we are looking at unsigned int curSegNum = 0; // the current segment number we are looking at
unsigned int segAmount = 0; unsigned int segAmount = 0;
for (unsigned int i = 0; i < segments.size(); i++){ for (unsigned int i = 0; i < segments.size(); i++){
segAmount = (segments[i].size() / 255) + 1; segAmount = (segments[i].size() / 255) + 1;
if (segAmount + curSegNum > 255){ if (segAmount + curSegNum > 255){
retVal += ((segAmount - (255 - curSegNum + 1)) * 255) + (segments[i].size() % 255);//calculate the extra bytes that overflow retVal += ((segAmount - (255 - curSegNum + 1)) * 255) +
curSegNum = 255;//making sure the segment numbers are at maximum (segments[i].size() % 255); // calculate the extra bytes that overflow
} else { curSegNum = 255; // making sure the segment numbers are at maximum
}else{
curSegNum += segAmount; curSegNum += segAmount;
} }
} }
@ -473,7 +386,7 @@ namespace OGG {
void Page::vorbisStuff(){ void Page::vorbisStuff(){
Utils::bitstreamLSBF packet; Utils::bitstreamLSBF packet;
packet.append(oggSegments.rbegin()->dataString);//this is a heavy operation, it needs to be optimised //todo? packet.append(oggSegments.rbegin()->dataString); // this is a heavy operation, it needs to be optimised //todo?
int curPCMSamples = 0; int curPCMSamples = 0;
long long unsigned int packetType = packet.get(1); long long unsigned int packetType = packet.get(1);
if (packetType == 0){ if (packetType == 0){
@ -484,45 +397,38 @@ namespace OGG {
if (prevBlockFlag != -1){ if (prevBlockFlag != -1){
if (curBlockFlag == prevBlockFlag){ if (curBlockFlag == prevBlockFlag){
curPCMSamples /= 2; curPCMSamples /= 2;
} else { }else{
curPCMSamples -= (1 << blockSize[0]) / 4 + (1 << blockSize[1]) / 4; curPCMSamples -= (1 << blockSize[0]) / 4 + (1 << blockSize[1]) / 4;
} }
} }
prevBlockFlag = curBlockFlag; prevBlockFlag = curBlockFlag;
} else { }else{
ERROR_MSG("Error, Vorbis packet type !=0 actual type: %llu",packetType ); ERROR_MSG("Error, Vorbis packet type !=0 actual type: %llu", packetType);
} }
//add to granule position // add to granule position
lastKeyFrame += curPCMSamples; lastKeyFrame += curPCMSamples;
oggSegments.rbegin()->lastKeyFrameSeen = lastKeyFrame; oggSegments.rbegin()->lastKeyFrameSeen = lastKeyFrame;
} }
///this calculates the granule position for a DTSC packet /// this calculates the granule position for a DTSC packet
long long unsigned int Page::calculateGranule(oggSegment & currentSegment){ long long unsigned int Page::calculateGranule(oggSegment &currentSegment){
long long unsigned int tempGranule = 0; long long unsigned int tempGranule = 0;
if (codec == OGG::THEORA){ if (codec == OGG::THEORA){
tempGranule = (currentSegment.lastKeyFrameSeen << split) | currentSegment.framesSinceKeyFrame; tempGranule = (currentSegment.lastKeyFrameSeen << split) | currentSegment.framesSinceKeyFrame;
} else if (codec == OGG::VORBIS){ }else if (codec == OGG::VORBIS){
tempGranule = currentSegment.lastKeyFrameSeen; tempGranule = currentSegment.lastKeyFrameSeen;
} else if (codec == OGG::OPUS){ }else if (codec == OGG::OPUS){
tempGranule = currentSegment.timeStamp*48; tempGranule = currentSegment.timeStamp * 48;
} }
return tempGranule; return tempGranule;
} }
bool Page::shouldSend(){ bool Page::shouldSend(){
unsigned int totalSegmentSize = 0; unsigned int totalSegmentSize = 0;
if (!oggSegments.size()){ if (!oggSegments.size()){return false;}
return false; if (oggSegments.rbegin()->isKeyframe){return true;}
}
if (oggSegments.rbegin()->isKeyframe){
return true;
}
if (codec == OGG::VORBIS){ if (codec == OGG::VORBIS){
if (lastKeyFrame - firstSample >= sampleRate){ if (lastKeyFrame - firstSample >= sampleRate){return true;}
return true;
}
} }
for (unsigned int i = 0; i < oggSegments.size(); i++){ for (unsigned int i = 0; i < oggSegments.size(); i++){
@ -534,79 +440,75 @@ 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()){
HIGH_MSG("!segments.size()"); HIGH_MSG("!segments.size()");
return; return;
} }
if (codec == OGG::VORBIS){ if (codec == OGG::VORBIS){firstSample = lastKeyFrame;}
firstSample = lastKeyFrame;
}
int temp = 0; int temp = 0;
long unsigned int checksum = 0; //reset checksum long unsigned int checksum = 0; // reset checksum
setCRCChecksum(0); setCRCChecksum(0);
unsigned int numSegments = oggSegments.size(); unsigned int numSegments = oggSegments.size();
int tableIndex = 0; int tableIndex = 0;
char tableSize = 0; char tableSize = 0;
//char table[255]; // char table[255];
char * table = (char *)malloc(255); char *table = (char *)malloc(255);
unsigned int bytesLeft = 0; unsigned int bytesLeft = 0;
for (unsigned int i = 0; i < numSegments; i++){ for (unsigned int i = 0; i < numSegments; i++){
//calculate amount of 255 bytes needed to store size (remainder not counted) // calculate amount of 255 bytes needed to store size (remainder not counted)
temp = (oggSegments[i].dataString.size() / 255); temp = (oggSegments[i].dataString.size() / 255);
//if everything still fits in the table // if everything still fits in the table
if ((temp + tableIndex + 1) <= 255){ if ((temp + tableIndex + 1) <= 255){
//set the 255 bytes // set the 255 bytes
memset(table + tableIndex, 255, temp); memset(table + tableIndex, 255, temp);
//increment tableIndex with 255 byte count // increment tableIndex with 255 byte count
tableIndex += temp; tableIndex += temp;
//set the last table entry to the remainder, and increase tableIndex with one // set the last table entry to the remainder, and increase tableIndex with one
table[tableIndex++] = (oggSegments[i].dataString.size() % 255); table[tableIndex++] = (oggSegments[i].dataString.size() % 255);
//update tableSize to be equal to tableIndex // update tableSize to be equal to tableIndex
tableSize = tableIndex; tableSize = tableIndex;
bytesLeft = 0; bytesLeft = 0;
} else { }else{
//stuff doesn't fit // stuff doesn't fit
//set the rest of the table to 255s // set the rest of the table to 255s
memset(table + tableIndex, 255, (255 - tableIndex)); memset(table + tableIndex, 255, (255 - tableIndex));
//table size is full table in use // table size is full table in use
tableSize = 255; tableSize = 255;
//space left on current page, for this segment: (255-tableIndex)*255 // space left on current page, for this segment: (255-tableIndex)*255
bytesLeft = (255 - tableIndex) * 255; bytesLeft = (255 - tableIndex) * 255;
if (oggSegments[i].dataString.size() == bytesLeft){ if (oggSegments[i].dataString.size() == bytesLeft){
bytesLeft = 0; //segment barely fits. bytesLeft = 0; // segment barely fits.
} }
break; break;
} }
} }
if (calcGranule < -1){ if (calcGranule < -1){
if (numSegments == 1 && bytesLeft){ //no segment ends on this page. if (numSegments == 1 && bytesLeft){// no segment ends on this page.
granules = -1; granules = -1;
} else { }else{
unsigned int tempIndex = numSegments - 1; unsigned int tempIndex = numSegments - 1;
if (bytesLeft != 0){ if (bytesLeft != 0){tempIndex = numSegments - 2;}
tempIndex = numSegments - 2;
}
granules = calculateGranule(oggSegments[tempIndex]); granules = calculateGranule(oggSegments[tempIndex]);
} }
} else { }else{
granules = calcGranule; //force granule granules = calcGranule; // force granule
} }
setGranulePosition(granules); setGranulePosition(granules);
checksum = crc32(checksum, data, 22);//calculating the checksum over the first part of the page checksum = crc32(checksum, data, 22); // calculating the checksum over the first part of the page
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
DONTEVEN_MSG("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);
if (bytesLeft != 0 && ((i + 1) == numSegments)){ if (bytesLeft != 0 && ((i + 1) == numSegments)){
checksum = crc32(checksum, oggSegments[i].dataString.data(), bytesLeft); checksum = crc32(checksum, oggSegments[i].dataString.data(), bytesLeft);
//take only part of this segment // take only part of this segment
} else { //take the entire segment }else{// take the entire segment
checksum = crc32(checksum, oggSegments[i].dataString.data(), oggSegments[i].dataString.size()); checksum = crc32(checksum, oggSegments[i].dataString.data(), oggSegments[i].dataString.size());
} }
} }
@ -617,35 +519,27 @@ namespace OGG {
destination.SendNow(&tableSize, 1); destination.SendNow(&tableSize, 1);
destination.SendNow(table, tableSize); destination.SendNow(table, tableSize);
for (unsigned int i = 0; i < numSegments; i++){ for (unsigned int i = 0; i < numSegments; i++){
if (bytesLeft != 0 && ((i + 1) == numSegments)){ if (bytesLeft != 0 && ((i + 1) == numSegments)){
destination.SendNow(oggSegments.begin()->dataString.data(), bytesLeft); destination.SendNow(oggSegments.begin()->dataString.data(), bytesLeft);
oggSegments.begin()->dataString.erase(0, bytesLeft); oggSegments.begin()->dataString.erase(0, bytesLeft);
setHeaderType(OGG::Continued);//set continuation flag setHeaderType(OGG::Continued); // set continuation flag
break; break;
//for loop WILL exit after this. // for loop WILL exit after this.
} else { }else{
destination.SendNow(oggSegments.begin()->dataString.data(), oggSegments.begin()->dataString.size()); destination.SendNow(oggSegments.begin()->dataString.data(), oggSegments.begin()->dataString.size());
//this segment WILL be deleted // this segment WILL be deleted
oggSegments.erase(oggSegments.begin()); oggSegments.erase(oggSegments.begin());
setHeaderType(OGG::Plain);//not a continuation setHeaderType(OGG::Plain); // not a continuation
} }
} }
//done sending, assume start of new page. // done sending, assume start of new page.
//inc. page num, write to header // inc. page num, write to header
pageSequenceNumber++; pageSequenceNumber++;
setPageSequenceNumber(pageSequenceNumber); setPageSequenceNumber(pageSequenceNumber);
//granule still requires setting! // granule still requires setting!
free(table); free(table);
return; return;
} }
} }// namespace OGG

242
lib/ogg.h
View file

@ -1,141 +1,129 @@
#pragma once #pragma once
#include <cstdlib>
#include <string>
#include <vector>
#include <deque>
#include <sstream>
#include "dtsc.h" #include "dtsc.h"
#include "socket.h"
#include "theora.h" #include "theora.h"
#include "vorbis.h" #include "vorbis.h"
#include "socket.h" #include <cstdlib>
#include <deque>
#include <sstream>
#include <string>
#include <vector>
namespace OGG { namespace OGG{
class oggSegment { class oggSegment{
public: public:
oggSegment(); oggSegment();
std::string dataString; std::string dataString;
int isKeyframe; int isKeyframe;
long long unsigned int lastKeyFrameSeen; long long unsigned int lastKeyFrameSeen;
long long unsigned int framesSinceKeyFrame; long long unsigned int framesSinceKeyFrame;
unsigned int frameNumber; unsigned int frameNumber;
long long unsigned int timeStamp; long long unsigned int timeStamp;
}; };
enum oggCodec {THEORA, VORBIS, OPUS}; enum oggCodec{THEORA, VORBIS, OPUS};
enum HeaderType { enum HeaderType{Plain = 0, Continued = 1, BeginOfStream = 2, EndOfStream = 4};
Plain = 0,
Continued = 1, std::deque<unsigned int> decodeXiphSize(char *data, size_t len);
BeginOfStream = 2,
EndOfStream = 4 class Page{
public:
Page();
Page(const Page &rhs);
void operator=(const Page &rhs);
bool read(std::string &newData);
bool read(FILE *inFile);
bool getSegment(unsigned int index, std::string &ret);
const char *getSegment(unsigned int index);
unsigned long getSegmentLen(unsigned int index);
void setMagicNumber();
char getVersion();
void setVersion(char newVal = 0);
char getHeaderType();
void setHeaderType(char newVal);
long long unsigned int getGranulePosition();
void setGranulePosition(long long unsigned int newVal);
long unsigned int getBitstreamSerialNumber();
void setBitstreamSerialNumber(long unsigned int newVal);
long unsigned int getCRCChecksum();
void setCRCChecksum(long unsigned int newVal);
long unsigned int getPageSequenceNumber();
void setPageSequenceNumber(long unsigned int newVal);
char getPageSegments(); // get the amount of page segments
inline void setPageSegments(char newVal); // set the amount of page segments
int getPayloadSize();
const std::deque<std::string> &getAllSegments();
bool possiblyContinued();
std::string toPrettyString(size_t indent = 0);
long unsigned int calcChecksum();
bool verifyChecksum();
unsigned int calcPayloadSize();
// void clear();
void clear(char HeaderType, long long unsigned int GranPos, long unsigned int BSN, long unsigned int PSN);
void prepareNext(bool continueMe = false); // prepare the page to become the next page
bool setPayload(char *newData, unsigned int length); // probably obsolete
unsigned int addSegment(const std::string &content); // add a segment to the page, returns added bytes
unsigned int addSegment(const char *content, unsigned int length); // add a segment to the page, returns added bytes
void sendTo(Socket::Connection &destination, int calcGranule = -2); // combines all data and sends it to socket
unsigned int setNextSegmentTableEntry(unsigned int entrySize); // returns the size that could not be added to the table
unsigned int overFlow(); // returns the amount of bytes that don't fit in this page from the segments;
long long unsigned int calculateGranule(oggSegment &currentSegment);
bool shouldSend();
void vorbisStuff(); // process most recent segment
long long unsigned int totalFrames;
int granules;
OGG::oggCodec codec;
std::deque<oggSegment> oggSegments; // used for ogg output
unsigned int pageSequenceNumber;
unsigned int framesSeen;
unsigned int lastKeyFrame;
unsigned int firstSample; // for vorbis, to handle "when to send the page"
unsigned int sampleRate; // for vorbis, to handle the sampleRate
int prevBlockFlag;
char blockSize[2];
std::deque<vorbis::mode> vorbisModes; // modes for vorbis
unsigned int split; // KFGShift for theora
private:
char data[282]; // Fulldata
std::deque<std::string> segments;
}; };
std::deque<unsigned int> decodeXiphSize(char * data, size_t len); class oggTrack{
public:
oggTrack() : KFGShift(0), lastTime(0), parsedHeaders(false), lastPageOffset(0), nxtSegment(0){}
oggCodec codec;
std::string name;
class Page { std::string contBuffer; // buffer for continuing pages
public: long long unsigned int dtscID;
Page(); char KFGShift;
Page(const Page & rhs); double lastTime;
void operator = (const Page & rhs); long long unsigned int lastGran;
bool read(std::string & newData); bool parsedHeaders;
bool read(FILE * inFile); long long unsigned int lastPageOffset;
bool getSegment(unsigned int index, std::string & ret); unsigned int nxtSegment;
const char * getSegment(unsigned int index); double msPerFrame;
unsigned long getSegmentLen(unsigned int index); Page myPage;
void setMagicNumber(); // Codec specific elements
char getVersion(); // theora
void setVersion(char newVal = 0); // theora::header idHeader;//needed to determine keyframe //bullshit?
char getHeaderType(); // vorbis
void setHeaderType(char newVal); std::deque<vorbis::mode> vModes;
long long unsigned int getGranulePosition(); char channels;
void setGranulePosition(long long unsigned int newVal); long long unsigned int blockSize[2];
long unsigned int getBitstreamSerialNumber(); // unsigned long getBlockSize(unsigned int vModeIndex);
void setBitstreamSerialNumber(long unsigned int newVal);
long unsigned int getCRCChecksum();
void setCRCChecksum(long unsigned int newVal);
long unsigned int getPageSequenceNumber();
void setPageSequenceNumber(long unsigned int newVal);
char getPageSegments();//get the amount of page segments
inline void setPageSegments(char newVal);//set the amount of page segments
int getPayloadSize();
const std::deque<std::string> & getAllSegments();
bool possiblyContinued();
std::string toPrettyString(size_t indent = 0);
long unsigned int calcChecksum();
bool verifyChecksum();
unsigned int calcPayloadSize();
//void clear();
void clear(char HeaderType, long long unsigned int GranPos, long unsigned int BSN, long unsigned int PSN);
void prepareNext(bool continueMe = false);//prepare the page to become the next page
bool setPayload(char * newData, unsigned int length); //probably obsolete
unsigned int addSegment(const std::string & content); //add a segment to the page, returns added bytes
unsigned int addSegment(const char * content, unsigned int length); //add a segment to the page, returns added bytes
void sendTo(Socket::Connection & destination, int calcGranule = -2); //combines all data and sends it to socket
unsigned int setNextSegmentTableEntry(unsigned int entrySize);//returns the size that could not be added to the table
unsigned int overFlow();//returns the amount of bytes that don't fit in this page from the segments;
long long unsigned int calculateGranule(oggSegment & currentSegment);
bool shouldSend();
void vorbisStuff();//process most recent segment
long long unsigned int totalFrames;
int granules;
OGG::oggCodec codec;
std::deque<oggSegment> oggSegments; //used for ogg output
unsigned int pageSequenceNumber;
unsigned int framesSeen;
unsigned int lastKeyFrame;
unsigned int firstSample;//for vorbis, to handle "when to send the page"
unsigned int sampleRate;//for vorbis, to handle the sampleRate
int prevBlockFlag;
char blockSize[2];
std::deque<vorbis::mode> vorbisModes;//modes for vorbis
unsigned int split; //KFGShift for theora
private:
char data[282];//Fulldata
std::deque<std::string> segments;
}; };
class oggTrack { class headerPages{
public: public:
oggTrack() : KFGShift(0), lastTime(0), parsedHeaders(false), lastPageOffset(0), nxtSegment(0){ } std::map<long long unsigned int, unsigned int> DTSCID2OGGSerial;
oggCodec codec; std::map<long long unsigned int, unsigned int> DTSCID2seqNum;
std::string name; std::string parsedPages;
std::string contBuffer;//buffer for continuing pages
long long unsigned int dtscID;
char KFGShift;
double lastTime;
long long unsigned int lastGran;
bool parsedHeaders;
long long unsigned int lastPageOffset;
unsigned int nxtSegment;
double msPerFrame;
Page myPage;
//Codec specific elements
//theora
// theora::header idHeader;//needed to determine keyframe //bullshit?
//vorbis
std::deque<vorbis::mode> vModes;
char channels;
long long unsigned int blockSize[2];
//unsigned long getBlockSize(unsigned int vModeIndex);
}; };
}// namespace OGG
class headerPages {
public:
std::map <long long unsigned int, unsigned int> DTSCID2OGGSerial;
std::map <long long unsigned int, unsigned int> DTSCID2seqNum;
std::string parsedPages;
};
}

View file

@ -3,10 +3,7 @@
namespace Opus{ namespace Opus{
uint16_t getPreSkip(const char *initData){return initData[10] + initData[11] * 256;}
uint16_t getPreSkip(const char * initData){
return initData[10] + initData[11]* 256;
}
unsigned int Opus_getDuration(const char *part){ unsigned int Opus_getDuration(const char *part){
const char config = part[0] >> 3; const char config = part[0] >> 3;
@ -14,28 +11,28 @@ namespace Opus{
double dur = 0; double dur = 0;
if (config < 14){ if (config < 14){
switch (config % 4){ switch (config % 4){
case 0: dur = 10; break; case 0: dur = 10; break;
case 1: dur = 20; break; case 1: dur = 20; break;
case 2: dur = 40; break; case 2: dur = 40; break;
case 3: dur = 60; break; case 3: dur = 60; break;
} }
} else if (config < 16){ }else if (config < 16){
if (config % 2 == 0){ if (config % 2 == 0){
dur = 10; dur = 10;
}else{ }else{
dur = 20; dur = 20;
} }
} else { }else{
switch (config % 4){ switch (config % 4){
case 0: dur = 2.5; break; case 0: dur = 2.5; break;
case 1: dur = 5; break; case 1: dur = 5; break;
case 2: dur = 10; break; case 2: dur = 10; break;
case 3: dur = 20; break; case 3: dur = 20; break;
} }
} }
if (code == 0){return (unsigned int)dur;} if (code == 0){return (unsigned int)dur;}
if (code < 3){return (unsigned int)(dur*2);} if (code < 3){return (unsigned int)(dur * 2);}
return (unsigned int)(dur*(part[1] & 63)); return (unsigned int)(dur * (part[1] & 63));
} }
std::string Opus_prettyPacket(const char *part, int len){ std::string Opus_prettyPacket(const char *part, int len){
@ -107,5 +104,4 @@ namespace Opus{
r << ": " << packets << " packets (VBR = " << VBR << ", padding = " << pad << ")"; r << ": " << packets << " packets (VBR = " << VBR << ", padding = " << pad << ")";
return r.str(); return r.str();
} }
} }// namespace Opus

View file

@ -1,9 +1,8 @@
#include <string>
#include <stdint.h> #include <stdint.h>
#include <string>
namespace Opus{ namespace Opus{
uint16_t getPreSkip(const char * initData); uint16_t getPreSkip(const char *initData);
unsigned int Opus_getDuration(const char *part); unsigned int Opus_getDuration(const char *part);
std::string Opus_prettyPacket(const char *part, int len); std::string Opus_prettyPacket(const char *part, int len);
} }// namespace Opus

View file

@ -1,57 +1,54 @@
/// \file procs.cpp /// \file procs.cpp
/// Contains generic functions for managing processes. /// Contains generic functions for managing processes.
#include "procs.h"
#include "defines.h" #include "defines.h"
#include "procs.h"
#include <signal.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <signal.h>
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__) #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
#include <sys/wait.h> #include <sys/wait.h>
#else #else
#include <wait.h> #include <wait.h>
#endif #endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include "timing.h" #include "timing.h"
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
std::set<pid_t> Util::Procs::plist; std::set<pid_t> Util::Procs::plist;
std::set<int> Util::Procs::socketList; std::set<int> Util::Procs::socketList;
bool Util::Procs::handler_set = false; bool Util::Procs::handler_set = false;
bool Util::Procs::thread_handler = false; bool Util::Procs::thread_handler = false;
tthread::mutex Util::Procs::plistMutex; tthread::mutex Util::Procs::plistMutex;
tthread::thread * Util::Procs::reaper_thread = 0; tthread::thread *Util::Procs::reaper_thread = 0;
/// Local-only function. Attempts to reap child and returns current running status. /// Local-only function. Attempts to reap child and returns current running status.
bool Util::Procs::childRunning(pid_t p) { bool Util::Procs::childRunning(pid_t p){
int status; int status;
pid_t ret = waitpid(p, &status, WNOHANG); pid_t ret = waitpid(p, &status, WNOHANG);
if (ret == p) { if (ret == p){
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
int exitcode = -1; int exitcode = -1;
if (WIFEXITED(status)) { if (WIFEXITED(status)){
exitcode = WEXITSTATUS(status); exitcode = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) { }else if (WIFSIGNALED(status)){
exitcode = -WTERMSIG(status); exitcode = -WTERMSIG(status);
} }
if (plist.count(ret)) { if (plist.count(ret)){
HIGH_MSG("Process %d fully terminated with code %d", ret, exitcode); HIGH_MSG("Process %d fully terminated with code %d", ret, exitcode);
plist.erase(ret); plist.erase(ret);
} else { }else{
HIGH_MSG("Child process %d exited with code %d", ret, exitcode); HIGH_MSG("Child process %d exited with code %d", ret, exitcode);
} }
return false; return false;
} }
if (ret < 0 && errno == EINTR) { if (ret < 0 && errno == EINTR){return childRunning(p);}
return childRunning(p);
}
return !kill(p, 0); return !kill(p, 0);
} }
@ -64,7 +61,7 @@ bool Util::Procs::isRunning(pid_t pid){
/// Waits up to 1 second, then sends SIGINT signal to all managed processes. /// Waits up to 1 second, then sends SIGINT signal to all managed processes.
/// After that waits up to 5 seconds for children to exit, then sends SIGKILL to /// After that waits up to 5 seconds for children to exit, then sends SIGKILL to
/// all remaining children. Waits one more second for cleanup to finish, then exits. /// all remaining children. Waits one more second for cleanup to finish, then exits.
void Util::Procs::exit_handler() { void Util::Procs::exit_handler(){
if (!handler_set){return;} if (!handler_set){return;}
int waiting = 0; int waiting = 0;
std::set<pid_t> listcopy; std::set<pid_t> listcopy;
@ -79,42 +76,39 @@ void Util::Procs::exit_handler() {
reaper_thread = 0; reaper_thread = 0;
} }
std::set<pid_t>::iterator it; std::set<pid_t>::iterator it;
if (listcopy.empty()) { if (listcopy.empty()){return;}
return;
}
//wait up to 0.5 second for applications to shut down // wait up to 0.5 second for applications to shut down
while (!listcopy.empty() && waiting <= 25) { while (!listcopy.empty() && waiting <= 25){
for (it = listcopy.begin(); it != listcopy.end(); it++) { for (it = listcopy.begin(); it != listcopy.end(); it++){
if (!childRunning(*it)) { if (!childRunning(*it)){
listcopy.erase(it); listcopy.erase(it);
break; break;
} }
if (!listcopy.empty()) { if (!listcopy.empty()){
Util::wait(20); Util::wait(20);
++waiting; ++waiting;
} }
} }
} }
if (listcopy.empty()) { if (listcopy.empty()){return;}
return;
}
INFO_MSG("Sending SIGINT and waiting up to 10 seconds for %d children to terminate.", (int)listcopy.size()); INFO_MSG("Sending SIGINT and waiting up to 10 seconds for %d children to terminate.",
(int)listcopy.size());
waiting = 0; waiting = 0;
//wait up to 10 seconds for applications to shut down // wait up to 10 seconds for applications to shut down
while (!listcopy.empty() && waiting <= 500) { while (!listcopy.empty() && waiting <= 500){
bool doWait = true; bool doWait = true;
for (it = listcopy.begin(); it != listcopy.end(); it++) { for (it = listcopy.begin(); it != listcopy.end(); it++){
if (!childRunning(*it)) { if (!childRunning(*it)){
listcopy.erase(it); listcopy.erase(it);
doWait = false; doWait = false;
break; break;
} }
} }
if (doWait && !listcopy.empty()) { if (doWait && !listcopy.empty()){
if ((waiting % 50) == 0){ if ((waiting % 50) == 0){
for (it = listcopy.begin(); it != listcopy.end(); it++) { for (it = listcopy.begin(); it != listcopy.end(); it++){
INFO_MSG("SIGINT %d", *it); INFO_MSG("SIGINT %d", *it);
kill(*it, SIGINT); kill(*it, SIGINT);
} }
@ -123,14 +117,12 @@ void Util::Procs::exit_handler() {
++waiting; ++waiting;
} }
} }
if (listcopy.empty()) { if (listcopy.empty()){return;}
return;
}
ERROR_MSG("Sending SIGKILL to remaining %d children", (int)listcopy.size()); ERROR_MSG("Sending SIGKILL to remaining %d children", (int)listcopy.size());
//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++){
INFO_MSG("SIGKILL %d", *it); INFO_MSG("SIGKILL %d", *it);
kill(*it, SIGKILL); kill(*it, SIGKILL);
} }
@ -138,22 +130,20 @@ void Util::Procs::exit_handler() {
INFO_MSG("Waiting up to a second for %d children to terminate.", (int)listcopy.size()); INFO_MSG("Waiting up to a second for %d children to terminate.", (int)listcopy.size());
waiting = 0; waiting = 0;
//wait up to 1 second for applications to shut down // wait up to 1 second for applications to shut down
while (!listcopy.empty() && waiting <= 50) { while (!listcopy.empty() && waiting <= 50){
for (it = listcopy.begin(); it != listcopy.end(); it++) { for (it = listcopy.begin(); it != listcopy.end(); it++){
if (!childRunning(*it)) { if (!childRunning(*it)){
listcopy.erase(it); listcopy.erase(it);
break; break;
} }
if (!listcopy.empty()) { if (!listcopy.empty()){
Util::wait(20); Util::wait(20);
++waiting; ++waiting;
} }
} }
} }
if (listcopy.empty()) { if (listcopy.empty()){return;}
return;
}
FAIL_MSG("Giving up with %d children left.", (int)listcopy.size()); FAIL_MSG("Giving up with %d children left.", (int)listcopy.size());
} }
@ -182,9 +172,9 @@ void Util::Procs::fork_complete(){
/// Sets up exit and childsig handlers. /// Sets up exit and childsig handlers.
/// Spawns grim_reaper. exit handler despawns grim_reaper /// Spawns grim_reaper. exit handler despawns grim_reaper
/// Called by every Start* function. /// Called by every Start* function.
void Util::Procs::setHandler() { void Util::Procs::setHandler(){
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
if (!handler_set) { if (!handler_set){
thread_handler = true; thread_handler = true;
reaper_thread = new tthread::thread(grim_reaper, 0); reaper_thread = new tthread::thread(grim_reaper, 0);
struct sigaction new_action; struct sigaction new_action;
@ -197,36 +187,34 @@ void Util::Procs::setHandler() {
} }
} }
///Thread that loops until thread_handler is false. /// Thread that loops until thread_handler is false.
///Reaps available children and then sleeps for a second. /// Reaps available children and then sleeps for a second.
///Not done in signal handler so we can use a mutex to prevent race conditions. /// Not done in signal handler so we can use a mutex to prevent race conditions.
void Util::Procs::grim_reaper(void * n){ void Util::Procs::grim_reaper(void *n){
VERYHIGH_MSG("Grim reaper start"); VERYHIGH_MSG("Grim reaper start");
while (thread_handler){ while (thread_handler){
{ {
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
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) { //ignore, would block otherwise if (ret <= 0){// ignore, would block otherwise
if (ret == 0 || errno != EINTR) { if (ret == 0 || errno != EINTR){break;}
break;
}
continue; continue;
} }
int exitcode; int exitcode;
if (WIFEXITED(status)) { if (WIFEXITED(status)){
exitcode = WEXITSTATUS(status); exitcode = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) { }else if (WIFSIGNALED(status)){
exitcode = -WTERMSIG(status); exitcode = -WTERMSIG(status);
} else { // not possible }else{// not possible
break; break;
} }
if (plist.count(ret)) { if (plist.count(ret)){
HIGH_MSG("Process %d fully terminated with code %d", ret, exitcode); HIGH_MSG("Process %d fully terminated with code %d", ret, exitcode);
plist.erase(ret); plist.erase(ret);
} else { }else{
HIGH_MSG("Child process %d exited with code %d", ret, exitcode); HIGH_MSG("Child process %d exited with code %d", ret, exitcode);
} }
} }
@ -237,23 +225,20 @@ void Util::Procs::grim_reaper(void * n){
} }
/// Ignores everything. Separate thread handles waiting for children. /// Ignores everything. Separate thread handles waiting for children.
void Util::Procs::childsig_handler(int signum) { void Util::Procs::childsig_handler(int signum){
return; return;
} }
/// Runs the given command and returns the stdout output as a string. /// Runs the given command and returns the stdout output as a string.
std::string Util::Procs::getOutputOf(char * const * argv) { std::string Util::Procs::getOutputOf(char *const *argv){
std::string ret; std::string ret;
int fin = 0, fout = -1, ferr = 0; int fin = 0, fout = -1, ferr = 0;
pid_t myProc = StartPiped(argv, &fin, &fout, &ferr); pid_t myProc = StartPiped(argv, &fin, &fout, &ferr);
while (childRunning(myProc)) { while (childRunning(myProc)){Util::sleep(100);}
Util::sleep(100); FILE *outFile = fdopen(fout, "r");
} char *fileBuf = 0;
FILE * outFile = fdopen(fout, "r");
char * fileBuf = 0;
size_t fileBufLen = 0; size_t fileBufLen = 0;
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)) { while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
ret += fileBuf; ret += fileBuf;
} }
fclose(outFile); fclose(outFile);
@ -261,27 +246,24 @@ std::string Util::Procs::getOutputOf(char * const * argv) {
return ret; return ret;
} }
/// This function prepares a deque for getOutputOf and automatically inserts a NULL at the end of the char* const*
///This function prepares a deque for getOutputOf and automatically inserts a NULL at the end of the char* const* char *const *Util::Procs::dequeToArgv(std::deque<std::string> &argDeq){
char* const* Util::Procs::dequeToArgv(std::deque<std::string> & argDeq){ char **ret = (char **)malloc((argDeq.size() + 1) * sizeof(char *));
char** ret = (char**)malloc((argDeq.size()+1)*sizeof(char*)); for (int i = 0; i < argDeq.size(); i++){ret[i] = (char *)argDeq[i].c_str();}
for (int i = 0; i<argDeq.size(); i++){
ret[i] = (char*)argDeq[i].c_str();
}
ret[argDeq.size()] = NULL; ret[argDeq.size()] = NULL;
return ret; return ret;
} }
std::string Util::Procs::getOutputOf(std::deque<std::string> & argDeq){ std::string Util::Procs::getOutputOf(std::deque<std::string> &argDeq){
std::string ret; std::string ret;
char* const* argv = dequeToArgv(argDeq);//Note: Do not edit deque before executing command char *const *argv = dequeToArgv(argDeq); // Note: Do not edit deque before executing command
ret = getOutputOf(argv); ret = getOutputOf(argv);
return ret; return ret;
} }
pid_t Util::Procs::StartPiped(std::deque<std::string> & argDeq, int * fdin, int * fdout, int * fderr) { pid_t Util::Procs::StartPiped(std::deque<std::string> &argDeq, int *fdin, int *fdout, int *fderr){
pid_t ret; pid_t ret;
char* const* argv = dequeToArgv(argDeq);//Note: Do not edit deque before executing command char *const *argv = dequeToArgv(argDeq); // Note: Do not edit deque before executing command
ret = Util::Procs::StartPiped(argv, fdin, fdout, fderr); ret = Util::Procs::StartPiped(argv, fdin, fdout, fderr);
return ret; return ret;
} }
@ -289,51 +271,51 @@ pid_t Util::Procs::StartPiped(std::deque<std::string> & argDeq, int * fdin, int
/// Starts a new process with given fds if the name is not already active. /// Starts a new process with given fds if the name is not already active.
/// \return 0 if process was not started, process PID otherwise. /// \return 0 if process was not started, process PID otherwise.
/// \arg argv Command for this process. /// \arg argv Command for this process.
/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd. /// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg
/// \arg fdout Same as fdin, but for stdout. /// contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be
/// \arg fdout Same as fdin, but for stderr. /// used as fd. \arg fdout Same as fdin, but for stdout. \arg fdout Same as fdin, but for stderr.
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];
setHandler(); setHandler();
if (fdin && *fdin == -1 && pipe(pipein) < 0) { if (fdin && *fdin == -1 && pipe(pipein) < 0){
ERROR_MSG("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){
ERROR_MSG("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]);
} }
return 0; return 0;
} }
if (fderr && *fderr == -1 && pipe(pipeerr) < 0) { if (fderr && *fderr == -1 && pipe(pipeerr) < 0){
ERROR_MSG("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]);
} }
if (*fdout == -1) { if (*fdout == -1){
close(pipeout[0]); close(pipeout[0]);
close(pipeout[1]); close(pipeout[1]);
} }
return 0; return 0;
} }
int devnull = -1; int devnull = -1;
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){
ERROR_MSG("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]);
} }
if (*fdout == -1) { if (*fdout == -1){
close(pipeout[0]); close(pipeout[0]);
close(pipeout[1]); close(pipeout[1]);
} }
if (*fderr == -1) { if (*fderr == -1){
close(pipeerr[0]); close(pipeerr[0]);
close(pipeerr[1]); close(pipeerr[1]);
} }
@ -341,55 +323,48 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
} }
} }
pid = fork(); pid = fork();
if (pid == 0) { //child if (pid == 0){// child
handler_set = false; handler_set = false;
//Close all sockets in the socketList // Close all sockets in the socketList
for (std::set<int>::iterator it = Util::Procs::socketList.begin(); it != Util::Procs::socketList.end(); ++it){ for (std::set<int>::iterator it = Util::Procs::socketList.begin();
it != Util::Procs::socketList.end(); ++it){
close(*it); close(*it);
} }
if (!fdin) { if (!fdin){
dup2(devnull, STDIN_FILENO); dup2(devnull, STDIN_FILENO);
} else if (*fdin == -1) { }else if (*fdin == -1){
close(pipein[1]); // close unused write end close(pipein[1]); // close unused write end
dup2(pipein[0], STDIN_FILENO); dup2(pipein[0], STDIN_FILENO);
close(pipein[0]); close(pipein[0]);
} else if (*fdin != STDIN_FILENO) { }else if (*fdin != STDIN_FILENO){
dup2(*fdin, STDIN_FILENO); dup2(*fdin, STDIN_FILENO);
} }
if (!fdout) { if (!fdout){
dup2(devnull, STDOUT_FILENO); dup2(devnull, STDOUT_FILENO);
} else if (*fdout == -1) { }else if (*fdout == -1){
close(pipeout[0]); // close unused read end close(pipeout[0]); // close unused read end
dup2(pipeout[1], STDOUT_FILENO); dup2(pipeout[1], STDOUT_FILENO);
close(pipeout[1]); close(pipeout[1]);
} else if (*fdout != STDOUT_FILENO) { }else if (*fdout != STDOUT_FILENO){
dup2(*fdout, STDOUT_FILENO); dup2(*fdout, STDOUT_FILENO);
} }
if (!fderr) { if (!fderr){
dup2(devnull, STDERR_FILENO); dup2(devnull, STDERR_FILENO);
} else if (*fderr == -1) { }else if (*fderr == -1){
close(pipeerr[0]); // close unused read end close(pipeerr[0]); // close unused read end
dup2(pipeerr[1], STDERR_FILENO); dup2(pipeerr[1], STDERR_FILENO);
close(pipeerr[1]); close(pipeerr[1]);
} else if (*fderr != STDERR_FILENO) { }else if (*fderr != STDERR_FILENO){
dup2(*fderr, STDERR_FILENO); dup2(*fderr, STDERR_FILENO);
} }
if (fdin && *fdin != -1 && *fdin != STDIN_FILENO) { if (fdin && *fdin != -1 && *fdin != STDIN_FILENO){close(*fdin);}
close(*fdin); if (fdout && *fdout != -1 && *fdout != STDOUT_FILENO){close(*fdout);}
} if (fderr && *fderr != -1 && *fderr != STDERR_FILENO){close(*fderr);}
if (fdout && *fdout != -1 && *fdout != STDOUT_FILENO) { if (devnull != -1){close(devnull);}
close(*fdout); // Because execvp requires a char* const* and we have a const char* const*
} execvp(argv[0], (char *const *)argv);
if (fderr && *fderr != -1 && *fderr != STDERR_FILENO) {
close(*fderr);
}
if (devnull != -1) {
close(devnull);
}
//Because execvp requires a char* const* and we have a const char* const*
execvp(argv[0], (char* const*)argv);
/*LTS-START*/ /*LTS-START*/
char * trggr = getenv("MIST_TRIGGER"); char *trggr = getenv("MIST_TRIGGER");
if (trggr && strlen(trggr)){ if (trggr && strlen(trggr)){
ERROR_MSG("%s trigger failed to execute %s: %s", trggr, argv[0], strerror(errno)); ERROR_MSG("%s trigger failed to execute %s: %s", trggr, argv[0], strerror(errno));
JSON::Value j; JSON::Value j;
@ -403,42 +378,38 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
/*LTS-END*/ /*LTS-END*/
ERROR_MSG("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){
ERROR_MSG("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]);
} }
if (fdout && *fdout == -1) { if (fdout && *fdout == -1){
close(pipeout[0]); close(pipeout[0]);
close(pipeout[1]); close(pipeout[1]);
} }
if (fderr && *fderr == -1) { if (fderr && *fderr == -1){
close(pipeerr[0]); close(pipeerr[0]);
close(pipeerr[1]); close(pipeerr[1]);
} }
if (devnull != -1) { if (devnull != -1){close(devnull);}
close(devnull);
}
return 0; return 0;
} else { //parent }else{// parent
{ {
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
plist.insert(pid); plist.insert(pid);
} }
HIGH_MSG("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); if (fdin && *fdin == -1){
}
if (fdin && *fdin == -1) {
close(pipein[0]); // close unused end end close(pipein[0]); // close unused end end
*fdin = pipein[1]; *fdin = pipein[1];
} }
if (fdout && *fdout == -1) { if (fdout && *fdout == -1){
close(pipeout[1]); // close unused write end close(pipeout[1]); // close unused write end
*fdout = pipeout[0]; *fdout = pipeout[0];
} }
if (fderr && *fderr == -1) { if (fderr && *fderr == -1){
close(pipeerr[1]); // close unused write end close(pipeerr[1]); // close unused write end
*fderr = pipeerr[0]; *fderr = pipeerr[0];
} }
@ -448,50 +419,47 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
/// Stops the process with this pid, if running. /// Stops the process with this pid, if running.
/// \arg name The PID of the process to stop. /// \arg name The PID of the process to stop.
void Util::Procs::Stop(pid_t name) { void Util::Procs::Stop(pid_t name){
kill(name, SIGTERM); kill(name, SIGTERM);
} }
/// Stops the process with this pid, if running. /// Stops the process with this pid, if running.
/// \arg name The PID of the process to murder. /// \arg name The PID of the process to murder.
void Util::Procs::Murder(pid_t name) { void Util::Procs::Murder(pid_t name){
kill(name, SIGKILL); kill(name, SIGKILL);
} }
/// (Attempts to) stop all running child processes. /// (Attempts to) stop all running child processes.
void Util::Procs::StopAll() { void Util::Procs::StopAll(){
std::set<pid_t> listcopy; std::set<pid_t> listcopy;
{ {
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
listcopy = plist; listcopy = plist;
} }
std::set<pid_t>::iterator it; std::set<pid_t>::iterator it;
for (it = listcopy.begin(); it != listcopy.end(); it++) { for (it = listcopy.begin(); it != listcopy.end(); it++){Stop(*it);}
Stop(*it);
}
} }
/// Returns the number of active child processes. /// Returns the number of active child processes.
int Util::Procs::Count() { int Util::Procs::Count(){
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
return plist.size(); return plist.size();
} }
/// Returns true if a process with this PID is currently active. /// Returns true if a process with this PID is currently active.
bool Util::Procs::isActive(pid_t name) { bool Util::Procs::isActive(pid_t name){
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
return (kill(name, 0) == 0); return (kill(name, 0) == 0);
} }
/// Forget about the given PID, keeping it running on shutdown. /// Forget about the given PID, keeping it running on shutdown.
void Util::Procs::forget(pid_t pid) { void Util::Procs::forget(pid_t pid){
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
plist.erase(pid); plist.erase(pid);
} }
/// Remember the given PID, killing it on shutdown. /// Remember the given PID, killing it on shutdown.
void Util::Procs::remember(pid_t pid) { void Util::Procs::remember(pid_t pid){
tthread::lock_guard<tthread::mutex> guard(plistMutex); tthread::lock_guard<tthread::mutex> guard(plistMutex);
plist.insert(pid); plist.insert(pid);
} }

View file

@ -2,46 +2,46 @@
/// Contains generic function headers for managing processes. /// Contains generic function headers for managing processes.
#pragma once #pragma once
#include <unistd.h>
#include <string>
#include <set>
#include <vector>
#include <deque>
#include "tinythread.h" #include "tinythread.h"
#include <deque>
#include <set>
#include <string>
#include <unistd.h>
#include <vector>
/// Contains utility code, not directly related to streaming media /// Contains utility code, not directly related to streaming media
namespace Util { namespace Util{
/// Deals with spawning, monitoring and stopping child processes /// Deals with spawning, monitoring and stopping child processes
class Procs { class Procs{
private: private:
static tthread::mutex plistMutex; static tthread::mutex plistMutex;
static std::set<pid_t> plist; ///< Holds active process list. static std::set<pid_t> plist; ///< Holds active process list.
static bool thread_handler;///< True while thread handler should be running. static bool thread_handler; ///< True while thread handler should be running.
static void childsig_handler(int signum); static void childsig_handler(int signum);
static void exit_handler(); static void exit_handler();
static char* const* dequeToArgv(std::deque<std::string> & argDeq); static char *const *dequeToArgv(std::deque<std::string> &argDeq);
static void grim_reaper(void * n); static void grim_reaper(void *n);
public:
static bool childRunning(pid_t p);
static tthread::thread * reaper_thread;
static bool handler_set; ///< If true, the sigchld handler has been setup.
static void fork_prepare();
static void fork_complete();
static void setHandler();
static std::string getOutputOf(char * const * argv);
static std::string getOutputOf(std::deque<std::string> & argDeq);
static pid_t StartPiped(const char * const * argv, int * fdin, int * fdout, int * fderr);
static pid_t StartPiped(std::deque<std::string> & argDeq, int * fdin, int * fdout, int * fderr);
static void Stop(pid_t name);
static void Murder(pid_t name);
static void StopAll();
static int Count();
static bool isActive(pid_t name);
static bool isRunning(pid_t pid);
static void forget(pid_t pid);
static void remember(pid_t pid);
static std::set<int> socketList; ///< Holds sockets that should be closed before forking
};
}
public:
static bool childRunning(pid_t p);
static tthread::thread *reaper_thread;
static bool handler_set; ///< If true, the sigchld handler has been setup.
static void fork_prepare();
static void fork_complete();
static void setHandler();
static std::string getOutputOf(char *const *argv);
static std::string getOutputOf(std::deque<std::string> &argDeq);
static pid_t StartPiped(const char *const *argv, int *fdin, int *fdout, int *fderr);
static pid_t StartPiped(std::deque<std::string> &argDeq, int *fdin, int *fdout, int *fderr);
static void Stop(pid_t name);
static void Murder(pid_t name);
static void StopAll();
static int Count();
static bool isActive(pid_t name);
static bool isRunning(pid_t pid);
static void forget(pid_t pid);
static void remember(pid_t pid);
static std::set<int> socketList; ///< Holds sockets that should be closed before forking
};
}// namespace Util

View file

@ -5,16 +5,16 @@ 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 (%" PRIu32 "b) does not fit in %" PRIu32 " bytes length!", getType().c_str(), FAIL_MSG("Chunk %s (%" PRIu32 "b) does not fit in %" PRIu32 " bytes length!",
getPayloadSize() + 8, len); getType().c_str(), getPayloadSize() + 8, len);
p = 0; p = 0;
} }
} }
Chunk::Chunk(void *_p, const char * t, uint32_t len){ Chunk::Chunk(void *_p, const char *t, uint32_t len){
p = (const char *)_p; p = (const char *)_p;
memcpy((void*)p, t, 4); memcpy((void *)p, t, 4);
Bit::htobl_le((char*)p+4, len); Bit::htobl_le((char *)p + 4, len);
} }
void Chunk::toPrettyString(std::ostream &o, size_t indent) const{ void Chunk::toPrettyString(std::ostream &o, size_t indent) const{
@ -109,11 +109,9 @@ namespace RIFF{
return std::string(p + 32, 16); return std::string(p + 32, 16);
} }
void fmt::toPrettyString(std::ostream &o, size_t indent) const{ void fmt::toPrettyString(std::ostream &o, size_t indent) const{
o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) << "b):" << std::endl;
<< "b):" << std::endl;
indent += 1; indent += 1;
o << std::string(indent, ' ') << "Codec: " << getCodec() << " (" << getFormat() << ")" o << std::string(indent, ' ') << "Codec: " << getCodec() << " (" << getFormat() << ")" << std::endl;
<< std::endl;
o << std::string(indent, ' ') << "Channels: " << getChannels() << std::endl; o << std::string(indent, ' ') << "Channels: " << getChannels() << std::endl;
o << std::string(indent, ' ') << "Sample rate: " << getHz() << "Hz" << std::endl; o << std::string(indent, ' ') << "Sample rate: " << getHz() << "Hz" << std::endl;
o << std::string(indent, ' ') << "Bytes/s: " << getBPS() << std::endl; o << std::string(indent, ' ') << "Bytes/s: " << getBPS() << std::endl;
@ -132,16 +130,17 @@ namespace RIFF{
} }
} }
} }
std::string fmt::generate(uint16_t format, uint16_t channels, uint32_t hz, uint32_t bps, uint16_t blocksize, uint16_t size){ std::string fmt::generate(uint16_t format, uint16_t channels, uint32_t hz, uint32_t bps,
uint16_t blocksize, uint16_t size){
std::string ret("fmt \022\000\000\000", 8); std::string ret("fmt \022\000\000\000", 8);
ret.append(std::string((size_t)18, '\000')); ret.append(std::string((size_t)18, '\000'));
Bit::htobs_le((char*)ret.data()+8, format); Bit::htobs_le((char *)ret.data() + 8, format);
Bit::htobs_le((char*)ret.data()+10, channels); Bit::htobs_le((char *)ret.data() + 10, channels);
Bit::htobl_le((char*)ret.data()+12, hz); Bit::htobl_le((char *)ret.data() + 12, hz);
Bit::htobl_le((char*)ret.data()+16, bps); Bit::htobl_le((char *)ret.data() + 16, bps);
Bit::htobs_le((char*)ret.data()+20, blocksize); Bit::htobs_le((char *)ret.data() + 20, blocksize);
Bit::htobs_le((char*)ret.data()+22, size); Bit::htobs_le((char *)ret.data() + 22, size);
Bit::htobs_le((char*)ret.data()+24, 0); Bit::htobs_le((char *)ret.data() + 24, 0);
return ret; return ret;
} }
@ -150,26 +149,23 @@ namespace RIFF{
return Bit::btohl_le(p + 8); return Bit::btohl_le(p + 8);
} }
void fact::toPrettyString(std::ostream &o, size_t indent) const{ void fact::toPrettyString(std::ostream &o, size_t indent) const{
o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) << "b):" << std::endl;
<< "b):" << std::endl;
indent += 1; indent += 1;
o << std::string(indent, ' ') << "Samples per channel: " << getSamplesPerChannel() << std::endl; o << std::string(indent, ' ') << "Samples per channel: " << getSamplesPerChannel() << std::endl;
} }
std::string fact::generate(uint32_t samples){ std::string fact::generate(uint32_t samples){
std::string ret("fact\004\000\000\000\000\000\000\000", 12); std::string ret("fact\004\000\000\000\000\000\000\000", 12);
Bit::htobl_le((char*)ret.data()+8, samples); Bit::htobl_le((char *)ret.data() + 8, samples);
return ret; return ret;
} }
std::string ISFT::getSoftware() const{ std::string ISFT::getSoftware() const{
if (!p){return 0;} if (!p){return 0;}
return std::string(p+8, getPayloadSize()); return std::string(p + 8, getPayloadSize());
} }
void ISFT::toPrettyString(std::ostream &o, size_t indent) const{ void ISFT::toPrettyString(std::ostream &o, size_t indent) const{
o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) << "b):" << std::endl;
<< "b):" << std::endl;
indent += 1; indent += 1;
o << std::string(indent, ' ') << "Software: " << getSoftware() << std::endl; o << std::string(indent, ' ') << "Software: " << getSoftware() << std::endl;
} }
} }// namespace RIFF

View file

@ -10,7 +10,7 @@ namespace RIFF{
class Chunk{ class Chunk{
public: public:
Chunk(const void *_p = 0, uint32_t len = 0); Chunk(const void *_p = 0, uint32_t len = 0);
Chunk(void *_p, const char * t, uint32_t len); Chunk(void *_p, const char *t, uint32_t len);
inline operator bool() const{return p;} inline operator bool() const{return p;}
inline std::string getType() const{ inline std::string getType() const{
if (!p){return "";} if (!p){return "";}
@ -41,7 +41,8 @@ namespace RIFF{
/// WAVE "fmt " class. /// WAVE "fmt " class.
class fmt : public Chunk{ class fmt : public Chunk{
public: public:
static std::string generate(uint16_t format, uint16_t channels, uint32_t hz, uint32_t bps, uint16_t blocksize, uint16_t size); static std::string generate(uint16_t format, uint16_t channels, uint32_t hz, uint32_t bps,
uint16_t blocksize, uint16_t size);
fmt(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){} fmt(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
uint16_t getFormat() const; uint16_t getFormat() const;
std::string getCodec() const; std::string getCodec() const;
@ -58,7 +59,7 @@ namespace RIFF{
}; };
/// WAVE fact class. /// WAVE fact class.
class fact : public Chunk { class fact : public Chunk{
public: public:
static std::string generate(uint32_t samples); static std::string generate(uint32_t samples);
fact(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){} fact(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
@ -67,13 +68,11 @@ namespace RIFF{
}; };
/// ISFT class. Contains software name. /// ISFT class. Contains software name.
class ISFT : public Chunk { class ISFT : public Chunk{
public: public:
ISFT(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){} ISFT(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
std::string getSoftware() const; std::string getSoftware() const;
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const; virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
}; };
}// namespace RIFF
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,10 @@
#pragma once #pragma once
void AES_set_encrypt_key(const char * userKey, const int bits, char * key); void AES_set_encrypt_key(const char *userKey, const int bits, char *key);
void AES_set_decrypt_key(const char * userKey, const int bits, char * key); void AES_set_decrypt_key(const char *userKey, const int bits, char *key);
void AES_encrypt(const char * in, char * out, const int bits, const char * key); void AES_encrypt(const char *in, char *out, const int bits, const char *key);
void AES_decrypt(const char * in, char * out, const char * key, unsigned int bits); void AES_decrypt(const char *in, char *out, const char *key, unsigned int bits);
static void increaseCounter(char * counter); static void increaseCounter(char *counter);
void AES_CTR128_crypt(const char * in, char * out, unsigned int len, const char * key, char ivec[16], char ecount_buf[16], unsigned int & num); void AES_CTR128_crypt(const char *in, char *out, unsigned int len, const char *key, char ivec[16],
void printInverted(const unsigned int * data, unsigned int len); char ecount_buf[16], unsigned int &num);
void printInverted(const unsigned int *data, unsigned int len);

View file

@ -1,10 +1,10 @@
/// \file rtmpchunks.cpp /// \file rtmpchunks.cpp
/// Holds all code for the RTMPStream namespace. /// Holds all code for the RTMPStream namespace.
#include "rtmpchunks.h"
#include "auth.h" #include "auth.h"
#include "defines.h" #include "defines.h"
#include "flv_tag.h" #include "flv_tag.h"
#include "rtmpchunks.h"
#include "timing.h" #include "timing.h"
std::string RTMPStream::handshake_in; ///< Input for the handshake. std::string RTMPStream::handshake_in; ///< Input for the handshake.
@ -41,13 +41,12 @@ char genuineFMSKey[] ={
0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68
char genuineFPKey[] ={ char genuineFPKey[] ={0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65,
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x50, 0x6c, 0x61,
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,
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d,
0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 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){
@ -61,8 +60,7 @@ 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, memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - 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);
@ -217,8 +215,7 @@ std::string &RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id
/// \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, std::string &RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char *data, int len, unsigned int ts){
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;
@ -353,8 +350,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer &buffer){
// 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;
DONTEVEN_MSG("Parsing RTMP chunk header (%#.2hhX) at offset %#zx", chunktype, DONTEVEN_MSG("Parsing RTMP chunk header (%#.2hhX) at offset %#zx", chunktype, RTMPStream::rec_cnt);
RTMPStream::rec_cnt);
switch (headertype){ switch (headertype){
case 0x00: case 0x00:
@ -512,8 +508,7 @@ bool RTMPStream::doHandshake(){
// 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, memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1504 - serverDigestOffset);
1504 - serverDigestOffset);
Secure::hmac_sha256bin(pTempBuffer, 1504, genuineFMSKey, 36, (char *)Server + serverDigestOffset); Secure::hmac_sha256bin(pTempBuffer, 1504, genuineFMSKey, 36, (char *)Server + serverDigestOffset);
// SECOND 1536 bytes for server response // SECOND 1536 bytes for server response
@ -523,12 +518,10 @@ bool RTMPStream::doHandshake(){
}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, Secure::hmac_sha256bin((char *)Server + 1536, 1536 - 32, pTempHash, 32, (char *)Server + 1536 * 2 - 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

@ -86,4 +86,3 @@ namespace RTMPStream{
/// 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();
}// namespace RTMPStream }// namespace RTMPStream

View file

@ -1,10 +1,10 @@
#include "rtp.h"
#include "adts.h" #include "adts.h"
#include "bitfields.h" #include "bitfields.h"
#include "defines.h" #include "defines.h"
#include "encode.h" #include "encode.h"
#include "h264.h" #include "h264.h"
#include "mpeg.h" #include "mpeg.h"
#include "rtp.h"
#include "sdp.h" #include "sdp.h"
#include "timing.h" #include "timing.h"
#include <arpa/inet.h> #include <arpa/inet.h>
@ -15,14 +15,12 @@ namespace RTP{
unsigned int Packet::getHsize() const{ unsigned int Packet::getHsize() const{
unsigned int r = 12 + 4 * getContribCount(); unsigned int r = 12 + 4 * getContribCount();
if (getExtension()){ if (getExtension()){r += (1 + Bit::btohs(data + r + 2)) * 4;}
r += (1+Bit::btohs(data+r+2)) * 4;
}
return r; return r;
} }
unsigned int Packet::getPayloadSize() const{ unsigned int Packet::getPayloadSize() const{
return maxDataLen - getHsize() - (getPadding() ? data[maxDataLen-1] : 0); return maxDataLen - getHsize() - (getPadding() ? data[maxDataLen - 1] : 0);
} }
char *Packet::getPayload() const{return data + getHsize();} char *Packet::getPayload() const{return data + getHsize();}
@ -47,7 +45,7 @@ namespace RTP{
char *Packet::getData(){return data + 8 + 4 * getContribCount() + getExtension();} char *Packet::getData(){return data + 8 + 4 * getContribCount() + getExtension();}
void Packet::setTimestamp(uint32_t t){Bit::htobl(data+4, t);} void Packet::setTimestamp(uint32_t t){Bit::htobl(data + 4, t);}
void Packet::setSequence(unsigned int seq){*((short *)(data + 2)) = htons(seq);} void Packet::setSequence(unsigned int seq){*((short *)(data + 2)) = htons(seq);}
@ -75,8 +73,7 @@ namespace RTP{
}else{ }else{
data[1] &= 0x7F; // setting the RTP marker bit to 0 data[1] &= 0x7F; // setting the RTP marker bit to 0
unsigned int sent = 0; unsigned int sent = 0;
unsigned int sending = unsigned int sending = maxDataLen - getHsize() - 2; // packages are of size MAX_SEND, except for the final one
maxDataLen - getHsize() - 2; // packages are of size MAX_SEND, except for the final one
char initByte = (payload[0] & 0xE0) | 0x1C; char initByte = (payload[0] & 0xE0) | 0x1C;
char serByte = payload[0] & 0x1F; // ser is now 000 char serByte = payload[0] & 0x1F; // ser is now 000
data[getHsize()] = initByte; data[getHsize()] = initByte;
@ -118,15 +115,10 @@ namespace RTP{
chunkSize = std::min<size_t>(1200, payloadlen); chunkSize = std::min<size_t>(1200, payloadlen);
payloadlen -= chunkSize; payloadlen -= chunkSize;
data[1] = data[1] = (0 != payloadlen) ? (data[1] & 0x7F) : (data[1] | 0x80); // marker bit, 1 for last chunk.
(0 != payloadlen) ? (data[1] & 0x7F) : (data[1] | 0x80); // marker bit, 1 for last chunk. data[headerSize] = 0x00; // reset
data[headerSize] = 0x00; // reset data[headerSize] |= (isStartOfPartition) ? 0x10 : 0x00; // first chunk is always start of a partition.
data[headerSize] |= data[headerSize] |= (isKeyframe) ? 0x00 : 0x20; // non-reference frame. 0 = frame is needed, 1 = frame can be disgarded.
(isStartOfPartition) ? 0x10 : 0x00; // first chunk is always start of a partition.
data[headerSize] |=
(isKeyframe)
? 0x00
: 0x20; // non-reference frame. 0 = frame is needed, 1 = frame can be disgarded.
memcpy(data + headerSize + 1, payload + bytesWritten, chunkSize); memcpy(data + headerSize + 1, payload + bytesWritten, chunkSize);
callBack(socket, data, headerSize + 1 + chunkSize, channel); callBack(socket, data, headerSize + 1 + chunkSize, channel);
@ -154,8 +146,7 @@ namespace RTP{
}else{ }else{
data[1] &= 0x7F; // setting the RTP marker bit to 0 data[1] &= 0x7F; // setting the RTP marker bit to 0
unsigned int sent = 0; unsigned int sent = 0;
unsigned int sending = unsigned int sending = maxDataLen - getHsize() - 3; // packages are of size MAX_SEND, except for the final one
maxDataLen - getHsize() - 3; // packages are of size MAX_SEND, except for the final one
char initByteA = (payload[0] & 0x81) | 0x62; char initByteA = (payload[0] & 0x81) | 0x62;
char initByteB = payload[1]; char initByteB = payload[1];
char serByte = (payload[0] & 0x7E) >> 1; // SE is now 00 char serByte = (payload[0] & 0x7E) >> 1; // SE is now 00
@ -205,8 +196,7 @@ namespace RTP{
}else{ }else{
data[1] &= 0x7F; // setting the RTP marker bit to 0 data[1] &= 0x7F; // setting the RTP marker bit to 0
unsigned int sent = 0; unsigned int sent = 0;
unsigned int sending = unsigned int sending = maxDataLen - getHsize() - 4; // packages are of size MAX_SEND, except for the final one
maxDataLen - getHsize() - 4; // packages are of size MAX_SEND, except for the final one
Mpeg::MPEG2Info mInfo; Mpeg::MPEG2Info mInfo;
MPEGVideoHeader mHead(data + getHsize()); MPEGVideoHeader mHead(data + getHsize());
while (sent < payloadlen){ while (sent < payloadlen){
@ -234,13 +224,13 @@ namespace RTP{
} }
void Packet::sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int), void Packet::sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
const char *payload, unsigned int payloadlen, unsigned int channel, const char *payload, unsigned int payloadlen, unsigned int channel, std::string codec){
std::string codec){
if (codec == "H264"){ if (codec == "H264"){
unsigned long sent = 0; unsigned long sent = 0;
while (sent < payloadlen){ while (sent < payloadlen){
unsigned long nalSize = ntohl(*((unsigned long *)(payload + sent))); unsigned long nalSize = ntohl(*((unsigned long *)(payload + sent)));
sendH264(socket, callBack, payload + sent + 4, nalSize, channel, (sent + nalSize + 4) >= payloadlen ? true : false); sendH264(socket, callBack, payload + sent + 4, nalSize, channel,
(sent + nalSize + 4) >= payloadlen ? true : false);
sent += nalSize + 4; sent += nalSize + 4;
} }
return; return;
@ -299,8 +289,7 @@ namespace RTP{
increaseSequence(); increaseSequence();
} }
void Packet::sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, void Packet::sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata,
DTSC::Meta &metadata,
void callBack(void *, char *, unsigned int, unsigned int)){ void callBack(void *, char *, unsigned int, unsigned int)){
char *rtcpData = (char *)malloc(32); char *rtcpData = (char *)malloc(32);
if (!rtcpData){ if (!rtcpData){
@ -322,8 +311,7 @@ namespace RTP{
free(rtcpData); free(rtcpData);
} }
void Packet::sendRTCP_RR(long long &connectedAt, SDP::Track &sTrk, unsigned int tid, void Packet::sendRTCP_RR(long long &connectedAt, SDP::Track &sTrk, unsigned int tid, DTSC::Meta &metadata,
DTSC::Meta &metadata,
void callBack(void *, char *, unsigned int, unsigned int)){ void callBack(void *, char *, unsigned int, unsigned int)){
char *rtcpData = (char *)malloc(32); char *rtcpData = (char *)malloc(32);
if (!rtcpData){ if (!rtcpData){
@ -336,12 +324,9 @@ namespace RTP{
Bit::htobs(rtcpData + 2, 7); // 7 4-byte words follow the header Bit::htobs(rtcpData + 2, 7); // 7 4-byte words follow the header
Bit::htobl(rtcpData + 4, sTrk.mySSRC); // set receiver identifier Bit::htobl(rtcpData + 4, sTrk.mySSRC); // set receiver identifier
Bit::htobl(rtcpData + 8, sTrk.theirSSRC); // set source identifier Bit::htobl(rtcpData + 8, sTrk.theirSSRC); // set source identifier
rtcpData[12] = rtcpData[12] = (sTrk.sorter.lostCurrent * 255) / (sTrk.sorter.lostCurrent + sTrk.sorter.packCurrent); // fraction lost since prev RR
(sTrk.sorter.lostCurrent * 255) / Bit::htob24(rtcpData + 13, sTrk.sorter.lostTotal); // cumulative packets lost since start
(sTrk.sorter.lostCurrent + sTrk.sorter.packCurrent); // fraction lost since prev RR Bit::htobl(rtcpData + 16, sTrk.sorter.rtpSeq | (sTrk.sorter.packTotal & 0xFFFF0000ul)); // highest sequence received
Bit::htob24(rtcpData + 13, sTrk.sorter.lostTotal); // cumulative packets lost since start
Bit::htobl(rtcpData + 16, sTrk.sorter.rtpSeq | (sTrk.sorter.packTotal &
0xFFFF0000ul)); // highest sequence received
Bit::htobl(rtcpData + 20, 0); /// \TODO jitter (diff in timestamp vs packet arrival) Bit::htobl(rtcpData + 20, 0); /// \TODO jitter (diff in timestamp vs packet arrival)
Bit::htobl(rtcpData + 24, 0); /// \TODO last SR (middle 32 bits of last SR or zero) Bit::htobl(rtcpData + 24, 0); /// \TODO last SR (middle 32 bits of last SR or zero)
Bit::htobl(rtcpData + 28, 0); /// \TODO delay since last SR in 2b seconds + 2b fraction Bit::htobl(rtcpData + 28, 0); /// \TODO delay since last SR in 2b seconds + 2b fraction
@ -362,8 +347,7 @@ namespace RTP{
Packet::Packet(unsigned int payloadType, unsigned int sequence, unsigned int timestamp, Packet::Packet(unsigned int payloadType, unsigned int sequence, unsigned int timestamp,
unsigned int ssrc, unsigned int csrcCount){ unsigned int ssrc, unsigned int csrcCount){
managed = true; managed = true;
data = new char[12 + 4 * csrcCount + 2 + data = new char[12 + 4 * csrcCount + 2 + MAX_SEND]; // headerSize, 2 for FU-A, MAX_SEND for maximum sent size
MAX_SEND]; // headerSize, 2 for FU-A, MAX_SEND for maximum sent size
if (data){ if (data){
maxDataLen = 12 + 4 * csrcCount + 2 + MAX_SEND; maxDataLen = 12 + 4 * csrcCount + 2 + MAX_SEND;
data[0] = ((2) << 6) | ((0 & 1) << 5) | ((0 & 1) << 4) | data[0] = ((2) << 6) | ((0 & 1) << 5) | ((0 & 1) << 4) |
@ -397,7 +381,6 @@ namespace RTP{
} }
sentBytes = o.sentBytes; sentBytes = o.sentBytes;
sentPackets = o.sentPackets; sentPackets = o.sentPackets;
} }
void Packet::operator=(const Packet &o){ void Packet::operator=(const Packet &o){
@ -613,7 +596,8 @@ namespace RTP{
int64_t pTime = pkt.getTimeStamp(); int64_t pTime = pkt.getTimeStamp();
if (!firstTime){ if (!firstTime){
firstTime = pTime + 1; firstTime = pTime + 1;
INFO_MSG("RTP timestamp rollover expected in " PRETTY_PRINT_TIME, PRETTY_ARG_TIME((0xFFFFFFFFul - firstTime) / multiplier / 1000)); INFO_MSG("RTP timestamp rollover expected in " PRETTY_PRINT_TIME,
PRETTY_ARG_TIME((0xFFFFFFFFul - firstTime) / multiplier / 1000));
}else{ }else{
if (prevTime > pTime && pTime < 0x40000000lu && prevTime > 0x80000000lu){ if (prevTime > pTime && pTime < 0x40000000lu && prevTime > 0x80000000lu){
++wrapArounds; ++wrapArounds;
@ -625,7 +609,7 @@ namespace RTP{
} }
} }
prevTime = pkt.getTimeStamp(); prevTime = pkt.getTimeStamp();
uint64_t msTime = ((uint64_t)pTime - firstTime + 1 + 0xFFFFFFFFull*wrapArounds) / multiplier; uint64_t msTime = ((uint64_t)pTime - firstTime + 1 + 0xFFFFFFFFull * wrapArounds) / multiplier;
char *pl = pkt.getPayload(); char *pl = pkt.getPayload();
uint32_t plSize = pkt.getPayloadSize(); uint32_t plSize = pkt.getPayloadSize();
bool missed = lastSeq != (pkt.getSequence() - 1); bool missed = lastSeq != (pkt.getSequence() - 1);
@ -657,8 +641,7 @@ namespace RTP{
void toDTSC::handleAAC(uint64_t msTime, char *pl, uint32_t plSize){ void toDTSC::handleAAC(uint64_t msTime, char *pl, uint32_t plSize){
// assume AAC packets are single AU units // assume AAC packets are single AU units
/// \todo Support other input than single AU units /// \todo Support other input than single AU units
unsigned int headLen = unsigned int headLen = (Bit::btohs(pl) >> 3) + 2; // in bits, so /8, plus two for the prepended size
(Bit::btohs(pl) >> 3) + 2; // in bits, so /8, plus two for the prepended size
DTSC::Packet nextPack; DTSC::Packet nextPack;
uint16_t samples = aac::AudSpecConf::samples(init); uint16_t samples = aac::AudSpecConf::samples(init);
uint32_t sampleOffset = 0; uint32_t sampleOffset = 0;
@ -706,7 +689,7 @@ namespace RTP{
unsigned int pos = 2; unsigned int pos = 2;
while (pos + 2 < plSize){ while (pos + 2 < plSize){
unsigned int pLen = Bit::btohs(pl + pos); unsigned int pLen = Bit::btohs(pl + pos);
VERYHIGH_MSG("AP Packet of %ub and type %s", pLen, h265::typeToStr((pl[pos+2]&0x7E) >> 1)); VERYHIGH_MSG("AP Packet of %ub and type %s", pLen, h265::typeToStr((pl[pos + 2] & 0x7E) >> 1));
if (packBuffer.allocate(4 + pLen)){ if (packBuffer.allocate(4 + pLen)){
Bit::htobl(packBuffer, pLen); // size-prepend Bit::htobl(packBuffer, pLen); // size-prepend
memcpy(packBuffer + 4, pl + pos + 2, pLen); memcpy(packBuffer + 4, pl + pos + 2, pLen);
@ -808,8 +791,7 @@ namespace RTP{
isKey ? "key" : "i", frameNo, fps, packCount, (frameNo - packCount), offset); isKey ? "key" : "i", frameNo, fps, packCount, (frameNo - packCount), offset);
}else{ }else{
// For non-steady frame rate, assume no offsets are used and the timestamp is already correct // For non-steady frame rate, assume no offsets are used and the timestamp is already correct
VERYHIGH_MSG("Packing time %llu = %sframe %llu (variable rate)", ts, isKey ? "key" : "i", VERYHIGH_MSG("Packing time %llu = %sframe %llu (variable rate)", ts, isKey ? "key" : "i", packCount);
packCount);
} }
// Fill the new DTSC packet, buffer it. // Fill the new DTSC packet, buffer it.
DTSC::Packet nextPack; DTSC::Packet nextPack;
@ -823,8 +805,7 @@ namespace RTP{
/// for that data. /// for that data.
/// Prints a WARN-level message if packet type is unsupported. /// Prints a WARN-level message if packet type is unsupported.
/// \todo Support other H264 packets types? /// \todo Support other H264 packets types?
void toDTSC::handleH264(uint64_t msTime, char *pl, uint32_t plSize, bool missed, void toDTSC::handleH264(uint64_t msTime, char *pl, uint32_t plSize, bool missed, bool hasPadding){
bool hasPadding){
if (!plSize){ if (!plSize){
WARN_MSG("Empty packet ignored!"); WARN_MSG("Empty packet ignored!");
return; return;
@ -1000,8 +981,7 @@ namespace RTP{
}else{ }else{
// For non-steady frame rate, assume no offsets are used and the timestamp is already // For non-steady frame rate, assume no offsets are used and the timestamp is already
// correct // correct
VERYHIGH_MSG("Packing time %llu = %sframe %llu (variable rate)", ts, isKey ? "key" : "i", VERYHIGH_MSG("Packing time %llu = %sframe %llu (variable rate)", ts, isKey ? "key" : "i", packCount);
packCount);
} }
// Fill the new DTSC packet, buffer it. // Fill the new DTSC packet, buffer it.
DTSC::Packet nextPack; DTSC::Packet nextPack;
@ -1031,8 +1011,7 @@ namespace RTP{
isKey ? "key" : "i", frameNo, fps, packCount, (frameNo - packCount), offset); isKey ? "key" : "i", frameNo, fps, packCount, (frameNo - packCount), offset);
}else{ }else{
// For non-steady frame rate, assume no offsets are used and the timestamp is already correct // For non-steady frame rate, assume no offsets are used and the timestamp is already correct
VERYHIGH_MSG("Packing time %llu = %sframe %llu (variable rate)", ts, isKey ? "key" : "i", VERYHIGH_MSG("Packing time %llu = %sframe %llu (variable rate)", ts, isKey ? "key" : "i", packCount);
packCount);
} }
// Fill the new DTSC packet, buffer it. // Fill the new DTSC packet, buffer it.
DTSC::Packet nextPack; DTSC::Packet nextPack;
@ -1062,8 +1041,7 @@ namespace RTP{
h264::isKeyframe(buffer + lastStart + 4, len - lastStart - 4)); h264::isKeyframe(buffer + lastStart + 4, len - lastStart - 4));
} }
void toDTSC::handleVP8(uint64_t msTime, const char *buffer, const uint32_t len, bool missed, void toDTSC::handleVP8(uint64_t msTime, const char *buffer, const uint32_t len, bool missed, bool hasPadding){
bool hasPadding){
// 1 byte is required but we assume that there some payload // 1 byte is required but we assume that there some payload
// data too :P // data too :P
@ -1136,15 +1114,14 @@ namespace RTP{
// (e.g. only received the first partition of a frame) we will // (e.g. only received the first partition of a frame) we will
// flush a new DTSC packet. // flush a new DTSC packet.
if (vp8FrameBuffer.size()){ if (vp8FrameBuffer.size()){
//new frame and nothing missed? Send. // new frame and nothing missed? Send.
if (start_of_frame && !missed){ if (start_of_frame && !missed){
DTSC::Packet nextPack; DTSC::Packet nextPack;
nextPack.genericFill(msTime, 0, trackId, vp8FrameBuffer, vp8FrameBuffer.size(), 0, nextPack.genericFill(msTime, 0, trackId, vp8FrameBuffer, vp8FrameBuffer.size(), 0, vp8BufferHasKeyframe);
vp8BufferHasKeyframe);
packCount++; packCount++;
outPacket(nextPack); outPacket(nextPack);
} }
//Wipe the buffer clean if missed packets or we just sent data out. // Wipe the buffer clean if missed packets or we just sent data out.
if (start_of_frame || missed){ if (start_of_frame || missed){
vp8FrameBuffer.assign(0, 0); vp8FrameBuffer.assign(0, 0);
vp8BufferHasKeyframe = false; vp8BufferHasKeyframe = false;
@ -1170,4 +1147,3 @@ namespace RTP{
if (start_of_frame && is_keyframe){vp8BufferHasKeyframe = true;} if (start_of_frame && is_keyframe){vp8BufferHasKeyframe = true;}
} }
}// namespace RTP }// namespace RTP

View file

@ -33,8 +33,8 @@ namespace RTP{
class Packet{ class Packet{
private: private:
bool managed; bool managed;
char *data; ///< The actual RTP packet that is being sent char *data; ///< The actual RTP packet that is being sent
uint32_t maxDataLen; ///< Amount of reserved bytes for the packet(s) uint32_t maxDataLen; ///< Amount of reserved bytes for the packet(s)
int sentPackets; int sentPackets;
int sentBytes; // Because ugly is beautiful int sentBytes; // Because ugly is beautiful
public: public:
@ -65,23 +65,20 @@ namespace RTP{
void sendMPEG2(void *socket, void callBack(void *, char *, unsigned int, unsigned int), void sendMPEG2(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
const char *payload, unsigned int payloadlen, unsigned int channel); const char *payload, unsigned int payloadlen, unsigned int channel);
void sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int), void sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
const char *payload, unsigned int payloadlen, unsigned int channel, const char *payload, unsigned int payloadlen, unsigned int channel, std::string codec);
std::string codec);
void sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata, void sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata,
void callBack(void *, char *, unsigned int, unsigned int)); void callBack(void *, char *, unsigned int, unsigned int));
void sendRTCP_RR(long long &connectedAt, SDP::Track &sTrk, unsigned int tid, void sendRTCP_RR(long long &connectedAt, SDP::Track &sTrk, unsigned int tid,
DTSC::Meta &metadata, DTSC::Meta &metadata, void callBack(void *, char *, unsigned int, unsigned int));
void callBack(void *, char *, unsigned int, unsigned int));
Packet(); Packet();
Packet(unsigned int pt, unsigned int seq, unsigned int ts, unsigned int ssr, Packet(unsigned int pt, unsigned int seq, unsigned int ts, unsigned int ssr, unsigned int csrcCount = 0);
unsigned int csrcCount = 0);
Packet(const Packet &o); Packet(const Packet &o);
void operator=(const Packet &o); void operator=(const Packet &o);
~Packet(); ~Packet();
Packet(const char *dat, unsigned int len); Packet(const char *dat, unsigned int len);
char *getData(); char *getData();
char *ptr() const { return data; } char *ptr() const{return data;}
}; };
/// Sorts RTP packets, outputting them through a callback in correct order. /// Sorts RTP packets, outputting them through a callback in correct order.
@ -173,13 +170,10 @@ namespace RTP{
void handleH264Multi(uint64_t ts, char *buffer, const uint32_t len); void handleH264Multi(uint64_t ts, char *buffer, const uint32_t len);
std::string spsData; ///< SPS for H264 std::string spsData; ///< SPS for H264
std::string ppsData; ///< PPS for H264 std::string ppsData; ///< PPS for H264
void handleVP8(uint64_t msTime, const char *buffer, const uint32_t len, bool missed, void handleVP8(uint64_t msTime, const char *buffer, const uint32_t len, bool missed, bool hasPadding);
bool hasPadding); Util::ResizeablePointer vp8FrameBuffer; ///< Stores successive VP8 payload data. We always start with the first
Util::ResizeablePointer ///< partition; but we might be missing other partitions when they were
vp8FrameBuffer; ///< Stores successive VP8 payload data. We always start with the first ///< lost. (a partition is basically what's called a slice in H264).
///< partition; but we might be missing other partitions when they were
///< lost. (a partition is basically what's called a slice in H264).
bool vp8BufferHasKeyframe; bool vp8BufferHasKeyframe;
}; };
}// namespace RTP }// namespace RTP

View file

@ -1,6 +1,6 @@
#include "defines.h" #include "defines.h"
#include "rtp_fec.h"
#include "rtp.h" #include "rtp.h"
#include "rtp_fec.h"
namespace RTP{ namespace RTP{
/// Based on the `block PT` value, we can either find the /// Based on the `block PT` value, we can either find the
@ -49,49 +49,50 @@ namespace RTP{
/// | mask cont. (present only when L = 1) | /// | mask cont. (present only when L = 1) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ///
PacketFEC::PacketFEC() { PacketFEC::PacketFEC(){}
}
PacketFEC::~PacketFEC() { PacketFEC::~PacketFEC(){
receivedSeqNums.clear(); receivedSeqNums.clear();
coveredSeqNums.clear(); coveredSeqNums.clear();
} }
bool PacketFEC::initWithREDPacket(const char* data, size_t nbytes) { bool PacketFEC::initWithREDPacket(const char *data, size_t nbytes){
if (!data) { if (!data){
FAIL_MSG("Given fecData pointer is NULL."); FAIL_MSG("Given fecData pointer is NULL.");
return false; return false;
} }
if (nbytes < 23) { if (nbytes < 23){
FAIL_MSG("Given fecData is too small. Should be at least: 12 (RTP) + 1 (RED) + 10 (FEC) 23 bytes."); FAIL_MSG("Given fecData is too small. Should be at least: 12 (RTP) + 1 (RED) + 10 (FEC) 23 "
"bytes.");
return false; return false;
} }
if (coveredSeqNums.size() != 0) { if (coveredSeqNums.size() != 0){
FAIL_MSG("It seems we're already initialized; coveredSeqNums already set."); FAIL_MSG("It seems we're already initialized; coveredSeqNums already set.");
return false; return false;
} }
if (receivedSeqNums.size() != 0) { if (receivedSeqNums.size() != 0){
FAIL_MSG("It seems we're already initialized; receivedSeqNums is not empty."); FAIL_MSG("It seems we're already initialized; receivedSeqNums is not empty.");
return false; return false;
} }
// Decode RED header. // Decode RED header.
RTP::Packet rtpPkt(data, nbytes); RTP::Packet rtpPkt(data, nbytes);
uint8_t* redHeader = (uint8_t*)(data + rtpPkt.getHsize()); uint8_t *redHeader = (uint8_t *)(data + rtpPkt.getHsize());
uint8_t moreBlocks = redHeader[0] & 0x80; uint8_t moreBlocks = redHeader[0] & 0x80;
if (moreBlocks == 1) { if (moreBlocks == 1){
FAIL_MSG("RED header indicates there are multiple blocks. Haven't seen this before (@todo implement, exiting now)."); FAIL_MSG("RED header indicates there are multiple blocks. Haven't seen this before (@todo "
"implement, exiting now).");
// \todo do not EXIT! // \todo do not EXIT!
return false; return false;
} }
// Copy the data, starting at the FEC header (skip RTP + RED header) // Copy the data, starting at the FEC header (skip RTP + RED header)
size_t numHeaderBytes = rtpPkt.getHsize() + 1; size_t numHeaderBytes = rtpPkt.getHsize() + 1;
if (numHeaderBytes > nbytes) { if (numHeaderBytes > nbytes){
FAIL_MSG("Invalid FEC packet; too small to contain FEC data."); FAIL_MSG("Invalid FEC packet; too small to contain FEC data.");
return false; return false;
} }
@ -100,7 +101,7 @@ namespace RTP{
fecPacketData.append(data + numHeaderBytes, nbytes - numHeaderBytes); fecPacketData.append(data + numHeaderBytes, nbytes - numHeaderBytes);
// Extract the sequence numbers this packet protects. // Extract the sequence numbers this packet protects.
if (!extractCoveringSequenceNumbers()) { if (!extractCoveringSequenceNumbers()){
FAIL_MSG("Failed to extract the protected sequence numbers for this FEC."); FAIL_MSG("Failed to extract the protected sequence numbers for this FEC.");
// @todo we probably want to reset our set. // @todo we probably want to reset our set.
return false; return false;
@ -109,20 +110,22 @@ namespace RTP{
return true; return true;
} }
uint8_t PacketFEC::getExtensionFlag() { uint8_t PacketFEC::getExtensionFlag(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get extension-flag from the FEC header; fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get extension-flag from the FEC header; fecPacketData member is not set. "
"Not initialized?");
return 0; return 0;
} }
return ((fecPacketData[0] & 0x80) >> 7); return ((fecPacketData[0] & 0x80) >> 7);
} }
uint8_t PacketFEC::getLongMaskFlag() { uint8_t PacketFEC::getLongMaskFlag(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get the long-mask-flag from the FEC header. fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get the long-mask-flag from the FEC header. fecPacketData member is not "
"set. Not initialized?");
return 0; return 0;
} }
@ -130,52 +133,52 @@ namespace RTP{
} }
// Returns 0 (error), 2 or 6, wich are the valid sizes of the mask. // Returns 0 (error), 2 or 6, wich are the valid sizes of the mask.
uint8_t PacketFEC::getNumBytesUsedForMask() { uint8_t PacketFEC::getNumBytesUsedForMask(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get the number of bytes used by the mask. fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get the number of bytes used by the mask. fecPacketData member is not set. "
"Not initialized?");
return 0; return 0;
} }
if (getLongMaskFlag() == 0) { if (getLongMaskFlag() == 0){return 2;}
return 2;
}
return 6; return 6;
} }
uint16_t PacketFEC::getSequenceBaseNumber() { uint16_t PacketFEC::getSequenceBaseNumber(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get the sequence base number. fecPacketData member is not set. Not initialized?"); FAIL_MSG(
"Cannot get the sequence base number. fecPacketData member is not set. Not initialized?");
return 0; return 0;
} }
return (uint16_t) (fecPacketData[2] << 8) | fecPacketData[3]; return (uint16_t)(fecPacketData[2] << 8) | fecPacketData[3];
} }
char* PacketFEC::getFECHeader() { char *PacketFEC::getFECHeader(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get fec header. fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get fec header. fecPacketData member is not set. Not initialized?");
} }
return fecPacketData; return fecPacketData;
} }
char* PacketFEC::getLevel0Header() { char *PacketFEC::getLevel0Header(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get the level 0 header. fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get the level 0 header. fecPacketData member is not set. Not initialized?");
return NULL; return NULL;
} }
return (char*)(fecPacketData + 10); return (char *)(fecPacketData + 10);
} }
char* PacketFEC::getLevel0Payload() { char *PacketFEC::getLevel0Payload(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get the level 0 payload. fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get the level 0 payload. fecPacketData member is not set. Not initialized?");
return NULL; return NULL;
} }
@ -183,18 +186,19 @@ namespace RTP{
// 10 bytes for FEC header // 10 bytes for FEC header
// 2 bytes for `Protection Length` // 2 bytes for `Protection Length`
// 2 or 6 bytes for `mask`. // 2 or 6 bytes for `mask`.
return (char*)(fecPacketData + 10 + 2 + getNumBytesUsedForMask()); return (char *)(fecPacketData + 10 + 2 + getNumBytesUsedForMask());
} }
uint16_t PacketFEC::getLevel0ProtectionLength() { uint16_t PacketFEC::getLevel0ProtectionLength(){
if (fecPacketData.size() == 0) { if (fecPacketData.size() == 0){
FAIL_MSG("Cannot get the level 0 protection length. fecPacketData member is not set. Not initialized?"); FAIL_MSG("Cannot get the level 0 protection length. fecPacketData member is not set. Not "
"initialized?");
return 0; return 0;
} }
char* level0Header = getLevel0Header(); char *level0Header = getLevel0Header();
if (!level0Header) { if (!level0Header){
FAIL_MSG("Failed to get the level 0 header, cannot get protection length."); FAIL_MSG("Failed to get the level 0 header, cannot get protection length.");
return 0; return 0;
} }
@ -203,11 +207,12 @@ namespace RTP{
return protectionLength; return protectionLength;
} }
uint16_t PacketFEC::getLengthRecovery() { uint16_t PacketFEC::getLengthRecovery(){
char* fecHeader = getFECHeader(); char *fecHeader = getFECHeader();
if (!fecHeader) { if (!fecHeader){
FAIL_MSG("Cannot get the FEC header which we need to get the `length recovery` field. Not initialized?"); FAIL_MSG("Cannot get the FEC header which we need to get the `length recovery` field. Not "
"initialized?");
return 0; return 0;
} }
@ -226,37 +231,35 @@ namespace RTP{
// packet protects the media packet with sequence number // packet protects the media packet with sequence number
// 230. We have to start counting the bit numbers from the // 230. We have to start counting the bit numbers from the
// most-significant-bit (e.g. 1 << 7). // most-significant-bit (e.g. 1 << 7).
bool PacketFEC::extractCoveringSequenceNumbers() { bool PacketFEC::extractCoveringSequenceNumbers(){
if (coveredSeqNums.size() != 0) { if (coveredSeqNums.size() != 0){
FAIL_MSG("Cannot extract protected sequence numbers; looks like we already did that."); FAIL_MSG("Cannot extract protected sequence numbers; looks like we already did that.");
return false; return false;
} }
size_t maskNumBytes = getNumBytesUsedForMask(); size_t maskNumBytes = getNumBytesUsedForMask();
if (maskNumBytes != 2 && maskNumBytes != 6) { if (maskNumBytes != 2 && maskNumBytes != 6){
FAIL_MSG("Invalid mask size (%u) cannot extract sequence numbers.", maskNumBytes); FAIL_MSG("Invalid mask size (%u) cannot extract sequence numbers.", maskNumBytes);
return false; return false;
} }
char* maskPtr = getLevel0Header(); char *maskPtr = getLevel0Header();
if (!maskPtr) { if (!maskPtr){
FAIL_MSG("Failed to get the level-0 header ptr. Cannot extract protected sequence numbers."); FAIL_MSG("Failed to get the level-0 header ptr. Cannot extract protected sequence numbers.");
return false; return false;
} }
uint16_t seqNumBase = getSequenceBaseNumber(); uint16_t seqNumBase = getSequenceBaseNumber();
if (seqNumBase == 0) { if (seqNumBase == 0){WARN_MSG("Base sequence number is 0; it's possible but unlikely.");}
WARN_MSG("Base sequence number is 0; it's possible but unlikely.");
}
// Skip the `Protection Length` // Skip the `Protection Length`
maskPtr = maskPtr + 2; maskPtr = maskPtr + 2;
for (uint16_t byteDX = 0; byteDX < maskNumBytes; ++byteDX) { for (uint16_t byteDX = 0; byteDX < maskNumBytes; ++byteDX){
uint8_t maskByte = maskPtr[byteDX]; uint8_t maskByte = maskPtr[byteDX];
for (uint16_t bitDX = 0; bitDX < 8; ++bitDX) { for (uint16_t bitDX = 0; bitDX < 8; ++bitDX){
if (maskByte & (1 << 7 - bitDX)) { if (maskByte & (1 << 7 - bitDX)){
uint16_t seqNum = seqNumBase + (byteDX << 3) + bitDX; uint16_t seqNum = seqNumBase + (byteDX << 3) + bitDX;
coveredSeqNums.insert(seqNum); coveredSeqNums.insert(seqNum);
} }
@ -267,12 +270,12 @@ namespace RTP{
} }
// \todo rename coversSequenceNumber // \todo rename coversSequenceNumber
bool PacketFEC::coversSequenceNumber(uint16_t sn) { bool PacketFEC::coversSequenceNumber(uint16_t sn){
return (coveredSeqNums.count(sn) == 0) ? false : true; return (coveredSeqNums.count(sn) == 0) ? false : true;
} }
void PacketFEC::addReceivedSequenceNumber(uint16_t sn) { void PacketFEC::addReceivedSequenceNumber(uint16_t sn){
if (false == coversSequenceNumber(sn)) { if (false == coversSequenceNumber(sn)){
FAIL_MSG("Trying to add a received sequence number this instance is not handling (%u).", sn); FAIL_MSG("Trying to add a received sequence number this instance is not handling (%u).", sn);
return; return;
} }
@ -292,26 +295,23 @@ namespace RTP{
/// The `receivedMediaPackets` is the history of media packets /// The `receivedMediaPackets` is the history of media packets
/// that you received and keep in a memory. These are used /// that you received and keep in a memory. These are used
/// when XORing when we reconstruct a packet. /// when XORing when we reconstruct a packet.
void PacketFEC::tryToRecoverMissingPacket(std::map<uint16_t, Packet>& receivedMediaPackets, Packet& reconstructedPacket) { void PacketFEC::tryToRecoverMissingPacket(std::map<uint16_t, Packet> &receivedMediaPackets,
Packet &reconstructedPacket){
// Mark all the media packets that we protect and which have // Mark all the media packets that we protect and which have
// been received as "received" in our internal list. // been received as "received" in our internal list.
std::set<uint16_t>::iterator protIt = coveredSeqNums.begin(); std::set<uint16_t>::iterator protIt = coveredSeqNums.begin();
while (protIt != coveredSeqNums.end()) { while (protIt != coveredSeqNums.end()){
if (receivedMediaPackets.count(*protIt) == 1) { if (receivedMediaPackets.count(*protIt) == 1){addReceivedSequenceNumber(*protIt);}
addReceivedSequenceNumber(*protIt);
}
protIt++; protIt++;
} }
// We have received all media packets that we could recover; // We have received all media packets that we could recover;
// so there is no need for this FEC packet. // so there is no need for this FEC packet.
// @todo Jaron shall we reuse allocs/PacketFECs? // @todo Jaron shall we reuse allocs/PacketFECs?
if (receivedSeqNums.size() == coveredSeqNums.size()) { if (receivedSeqNums.size() == coveredSeqNums.size()){return;}
return;
}
if (coveredSeqNums.size() != (receivedSeqNums.size() + 1)) { if (coveredSeqNums.size() != (receivedSeqNums.size() + 1)){
// missing more then 1 packet. we can only recover when // missing more then 1 packet. we can only recover when
// one packet is lost. // one packet is lost.
return; return;
@ -320,21 +320,21 @@ namespace RTP{
// Find missing sequence number. // Find missing sequence number.
uint16_t missingSeqNum = 0; uint16_t missingSeqNum = 0;
protIt = coveredSeqNums.begin(); protIt = coveredSeqNums.begin();
while (protIt != coveredSeqNums.end()) { while (protIt != coveredSeqNums.end()){
if (receivedSeqNums.count(*protIt) == 0) { if (receivedSeqNums.count(*protIt) == 0){
missingSeqNum = *protIt; missingSeqNum = *protIt;
break; break;
} }
++protIt; ++protIt;
} }
if (!coversSequenceNumber(missingSeqNum)) { if (!coversSequenceNumber(missingSeqNum)){
WARN_MSG("We cannot recover %u.", missingSeqNum); WARN_MSG("We cannot recover %u.", missingSeqNum);
return; return;
} }
// Copy FEC into new RTP-header // Copy FEC into new RTP-header
char* fecHeader = getFECHeader(); char *fecHeader = getFECHeader();
if (!fecHeader) { if (!fecHeader){
FAIL_MSG("Failed to get the fec header. Cannot recover."); FAIL_MSG("Failed to get the fec header. Cannot recover.");
return; return;
} }
@ -342,34 +342,34 @@ namespace RTP{
recoverData.append(fecHeader, 12); recoverData.append(fecHeader, 12);
// Copy FEC into new RTP-payload // Copy FEC into new RTP-payload
char* level0Payload = getLevel0Payload(); char *level0Payload = getLevel0Payload();
if (!level0Payload) { if (!level0Payload){
FAIL_MSG("Failed to get the level-0 payload data (XOR'd media data from FEC packet)."); FAIL_MSG("Failed to get the level-0 payload data (XOR'd media data from FEC packet).");
return; return;
} }
uint16_t level0ProtLen = getLevel0ProtectionLength(); uint16_t level0ProtLen = getLevel0ProtectionLength();
if (level0ProtLen == 0) { if (level0ProtLen == 0){
FAIL_MSG("Failed to get the level-0 protection length."); FAIL_MSG("Failed to get the level-0 protection length.");
return; return;
} }
recoverData.append(level0Payload, level0ProtLen); recoverData.append(level0Payload, level0ProtLen);
uint8_t recoverLength[2] = { fecHeader[8], fecHeader[9] }; uint8_t recoverLength[2] ={fecHeader[8], fecHeader[9]};
// XOR headers // XOR headers
protIt = coveredSeqNums.begin(); protIt = coveredSeqNums.begin();
while (protIt != coveredSeqNums.end()) { while (protIt != coveredSeqNums.end()){
uint16_t seqNum = *protIt; uint16_t seqNum = *protIt;
if (seqNum == missingSeqNum) { if (seqNum == missingSeqNum){
++protIt; ++protIt;
continue; continue;
} }
Packet& mediaPacket = receivedMediaPackets[seqNum]; Packet &mediaPacket = receivedMediaPackets[seqNum];
char* mediaData = mediaPacket.ptr(); char *mediaData = mediaPacket.ptr();
uint16_t mediaSize = mediaPacket.getPayloadSize(); uint16_t mediaSize = mediaPacket.getPayloadSize();
uint8_t* mediaSizePtr = (uint8_t*)&mediaSize; uint8_t *mediaSizePtr = (uint8_t *)&mediaSize;
WARN_MSG(" => XOR header with %u, size: %u.", seqNum, mediaSize); WARN_MSG(" => XOR header with %u, size: %u.", seqNum, mediaSize);
@ -390,21 +390,19 @@ namespace RTP{
++protIt; ++protIt;
} }
uint16_t recoverPayloadSize = ntohs(*(uint16_t*)recoverLength); uint16_t recoverPayloadSize = ntohs(*(uint16_t *)recoverLength);
// XOR payloads // XOR payloads
protIt = coveredSeqNums.begin(); protIt = coveredSeqNums.begin();
while (protIt != coveredSeqNums.end()) { while (protIt != coveredSeqNums.end()){
uint16_t seqNum = *protIt; uint16_t seqNum = *protIt;
if (seqNum == missingSeqNum) { if (seqNum == missingSeqNum){
++protIt; ++protIt;
continue; continue;
} }
Packet& mediaPacket = receivedMediaPackets[seqNum]; Packet &mediaPacket = receivedMediaPackets[seqNum];
char* mediaData = mediaPacket.ptr() + mediaPacket.getHsize(); char *mediaData = mediaPacket.ptr() + mediaPacket.getHsize();
for (size_t i = 0; i < recoverPayloadSize; ++i) { for (size_t i = 0; i < recoverPayloadSize; ++i){recoverData[12 + i] ^= mediaData[i];}
recoverData[12 + i] ^= mediaData[i];
}
++protIt; ++protIt;
} }
@ -414,9 +412,8 @@ namespace RTP{
// @todo check what other header fields we need to fix. // @todo check what other header fields we need to fix.
} }
void FECSorter::addPacket(const Packet &pack){ void FECSorter::addPacket(const Packet &pack){
if (tmpVideoLossPrevention & SDP_LOSS_PREVENTION_ULPFEC) { if (tmpVideoLossPrevention & SDP_LOSS_PREVENTION_ULPFEC){
packetHistory[pack.getSequence()] = pack; packetHistory[pack.getSequence()] = pack;
while (packetHistory.begin()->first < pack.getSequence() - 500){ while (packetHistory.begin()->first < pack.getSequence() - 500){
packetHistory.erase(packetHistory.begin()); packetHistory.erase(packetHistory.begin());
@ -447,24 +444,20 @@ namespace RTP{
/// |F| block PT | timestamp offset | block length | /// |F| block PT | timestamp offset | block length |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ///
void FECSorter::addREDPacket(char* dat, void FECSorter::addREDPacket(char *dat, unsigned int len, uint8_t codecPayloadType,
unsigned int len, uint8_t REDPayloadType, uint8_t ULPFECPayloadType){
uint8_t codecPayloadType,
uint8_t REDPayloadType,
uint8_t ULPFECPayloadType)
{
RTP::Packet pkt(dat, len); RTP::Packet pkt(dat, len);
if (pkt.getPayloadType() != REDPayloadType) { if (pkt.getPayloadType() != REDPayloadType){
FAIL_MSG("Requested to add a RED packet, but it has an invalid payload type."); FAIL_MSG("Requested to add a RED packet, but it has an invalid payload type.");
return; return;
} }
// Check if the `F` flag is set. Chromium will always set // Check if the `F` flag is set. Chromium will always set
// this to 0 (at time of writing, check: https://goo.gl/y1eJ6k // this to 0 (at time of writing, check: https://goo.gl/y1eJ6k
uint8_t* REDHeader = (uint8_t*)(dat + pkt.getHsize()); uint8_t *REDHeader = (uint8_t *)(dat + pkt.getHsize());
uint8_t moreBlocksAvailable = REDHeader[0] & 0x80; uint8_t moreBlocksAvailable = REDHeader[0] & 0x80;
if (moreBlocksAvailable == 1) { if (moreBlocksAvailable == 1){
FAIL_MSG("Not yet received a RED packet that had it's F bit set; @todo implement."); FAIL_MSG("Not yet received a RED packet that had it's F bit set; @todo implement.");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
return; return;
@ -474,11 +467,11 @@ namespace RTP{
// fec-pt. When it's just media that follows, we move all // fec-pt. When it's just media that follows, we move all
// data one byte up and reconstruct a normal media packet. // data one byte up and reconstruct a normal media packet.
uint8_t blockPayloadType = REDHeader[0] & 0x7F; uint8_t blockPayloadType = REDHeader[0] & 0x7F;
if (blockPayloadType == codecPayloadType) { if (blockPayloadType == codecPayloadType){
memmove(dat + pkt.getHsize(), dat + pkt.getHsize() + 1, len - pkt.getHsize() - 1); memmove(dat + pkt.getHsize(), dat + pkt.getHsize() + 1, len - pkt.getHsize() - 1);
dat[1] &= 0x80; dat[1] &= 0x80;
dat[1] |= codecPayloadType; dat[1] |= codecPayloadType;
RTP::Packet mediaPacket((const char*)dat, len -1); RTP::Packet mediaPacket((const char *)dat, len - 1);
addPacket(mediaPacket); addPacket(mediaPacket);
return; return;
} }
@ -496,10 +489,10 @@ namespace RTP{
// is going to deal with FEC. // is going to deal with FEC.
// //
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (blockPayloadType == ULPFECPayloadType) { if (blockPayloadType == ULPFECPayloadType){
WARN_MSG(" => got fec packet: %u", pkt.getSequence()); WARN_MSG(" => got fec packet: %u", pkt.getSequence());
PacketFEC* fec = new PacketFEC(); PacketFEC *fec = new PacketFEC();
if (!fec->initWithREDPacket(dat, len)) { if (!fec->initWithREDPacket(dat, len)){
delete fec; delete fec;
fec = NULL; fec = NULL;
FAIL_MSG("Failed to initialize a `PacketFEC`"); FAIL_MSG("Failed to initialize a `PacketFEC`");
@ -508,9 +501,10 @@ namespace RTP{
Packet recreatedPacket; Packet recreatedPacket;
fec->tryToRecoverMissingPacket(packetHistory, recreatedPacket); fec->tryToRecoverMissingPacket(packetHistory, recreatedPacket);
if (recreatedPacket.ptr() != NULL) { if (recreatedPacket.ptr() != NULL){
char* pl = recreatedPacket.getPayload(); char *pl = recreatedPacket.getPayload();
WARN_MSG(" => reconstructed %u, %02X %02X %02X %02X | %02X %02X %02X %02X", recreatedPacket.getSequence(), pl[0], pl[1], pl[2], pl[3], pl[4], pl[5], pl[6], pl[7]); WARN_MSG(" => reconstructed %u, %02X %02X %02X %02X | %02X %02X %02X %02X",
recreatedPacket.getSequence(), pl[0], pl[1], pl[2], pl[3], pl[4], pl[5], pl[6], pl[7]);
addPacket(recreatedPacket); addPacket(recreatedPacket);
} }
return; return;
@ -527,35 +521,31 @@ namespace RTP{
/// have been received except the one that we want to /// have been received except the one that we want to
/// recover. This function returns the FEC packet might be able /// recover. This function returns the FEC packet might be able
/// to recover the given sequence number. /// to recover the given sequence number.
PacketFEC* FECSorter::getFECPacketWhichCoversSequenceNumber(uint16_t sn) { PacketFEC *FECSorter::getFECPacketWhichCoversSequenceNumber(uint16_t sn){
size_t nfecs = fecPackets.size(); size_t nfecs = fecPackets.size();
for (size_t i = 0; i < nfecs; ++i) { for (size_t i = 0; i < nfecs; ++i){
PacketFEC* fec = fecPackets[i]; PacketFEC *fec = fecPackets[i];
if (fec->coversSequenceNumber(sn)) { if (fec->coversSequenceNumber(sn)){return fec;}
return fec;
}
} }
return NULL; return NULL;
} }
void FECPacket::sendRTCP_RR(RTP::FECSorter &sorter, uint32_t mySSRC, uint32_t theirSSRC, void* userData, void callBack(void* userData, const char* payload, uint32_t nbytes)) { void FECPacket::sendRTCP_RR(RTP::FECSorter &sorter, uint32_t mySSRC, uint32_t theirSSRC, void *userData,
void callBack(void *userData, const char *payload, uint32_t nbytes)){
char *rtcpData = (char *)malloc(32); char *rtcpData = (char *)malloc(32);
if (!rtcpData){ if (!rtcpData){
FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up."); FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up.");
return; return;
} }
if (!(sorter.lostCurrent + sorter.packCurrent)){sorter.packCurrent++;} if (!(sorter.lostCurrent + sorter.packCurrent)){sorter.packCurrent++;}
rtcpData[0] = 0x81; // version 2, no padding, one receiver report rtcpData[0] = 0x81; // version 2, no padding, one receiver report
rtcpData[1] = 201; // receiver report rtcpData[1] = 201; // receiver report
Bit::htobs(rtcpData + 2, 7); // 7 4-byte words follow the header Bit::htobs(rtcpData + 2, 7); // 7 4-byte words follow the header
Bit::htobl(rtcpData + 4, mySSRC); // set receiver identifier Bit::htobl(rtcpData + 4, mySSRC); // set receiver identifier
Bit::htobl(rtcpData + 8, theirSSRC); // set source identifier Bit::htobl(rtcpData + 8, theirSSRC); // set source identifier
rtcpData[12] = rtcpData[12] = (sorter.lostCurrent * 255) / (sorter.lostCurrent + sorter.packCurrent); // fraction lost since prev RR
(sorter.lostCurrent * 255) / Bit::htob24(rtcpData + 13, sorter.lostTotal); // cumulative packets lost since start
(sorter.lostCurrent + sorter.packCurrent); // fraction lost since prev RR Bit::htobl(rtcpData + 16, sorter.rtpSeq | (sorter.packTotal & 0xFFFF0000ul)); // highest sequence received
Bit::htob24(rtcpData + 13, sorter.lostTotal); // cumulative packets lost since start
Bit::htobl(rtcpData + 16, sorter.rtpSeq | (sorter.packTotal &
0xFFFF0000ul)); // highest sequence received
Bit::htobl(rtcpData + 20, 0); /// \TODO jitter (diff in timestamp vs packet arrival) Bit::htobl(rtcpData + 20, 0); /// \TODO jitter (diff in timestamp vs packet arrival)
Bit::htobl(rtcpData + 24, 0); /// \TODO last SR (middle 32 bits of last SR or zero) Bit::htobl(rtcpData + 24, 0); /// \TODO last SR (middle 32 bits of last SR or zero)
Bit::htobl(rtcpData + 28, 0); /// \TODO delay since last SR in 2b seconds + 2b fraction Bit::htobl(rtcpData + 28, 0); /// \TODO delay since last SR in 2b seconds + 2b fraction
@ -565,5 +555,4 @@ namespace RTP{
free(rtcpData); free(rtcpData);
} }
} }// namespace RTP

View file

@ -21,16 +21,14 @@ namespace RTP{
public: public:
PacketFEC(); PacketFEC();
~PacketFEC(); ~PacketFEC();
bool initWithREDPacket( bool initWithREDPacket(const char *data,
const char *data, size_t nbytes); /// Initialize using the given data. `data` must point to the first byte of
size_t nbytes); /// Initialize using the given data. `data` must point to the first byte of /// the RTP packet which contains the RED and FEC headers and data.
/// the RTP packet which contains the RED and FEC headers and data.
uint8_t getExtensionFlag(); ///< From fec header: should be 0, see uint8_t getExtensionFlag(); ///< From fec header: should be 0, see
///< https://tools.ietf.org/html/rfc5109#section-7.3. ///< https://tools.ietf.org/html/rfc5109#section-7.3.
uint8_t uint8_t getLongMaskFlag(); ///< From fec header: returns 0 when the short mask version is used (16
getLongMaskFlag(); ///< From fec header: returns 0 when the short mask version is used (16 ///< bits), otherwise 1 (48 bits). The mask is used to calculate what
///< bits), otherwise 1 (48 bits). The mask is used to calculate what ///< sequence numbers are protected, starting at the base sequence number.
///< sequence numbers are protected, starting at the base sequence number.
uint16_t getSequenceBaseNumber(); ///< From fec header: get the base sequence number. The base uint16_t getSequenceBaseNumber(); ///< From fec header: get the base sequence number. The base
///< sequence number is used together with the mask to ///< sequence number is used together with the mask to
///< determine what the sequence numbers of the media packets ///< determine what the sequence numbers of the media packets
@ -44,15 +42,13 @@ namespace RTP{
/// and paylaod. /// and paylaod.
char *getFECHeader(); ///< Get a pointer to the first byte of the FEC header. char *getFECHeader(); ///< Get a pointer to the first byte of the FEC header.
uint16_t getLevel0ProtectionLength(); ///< Get the length of the `getLevel0Payload()`. uint16_t getLevel0ProtectionLength(); ///< Get the length of the `getLevel0Payload()`.
uint16_t uint16_t getLengthRecovery(); ///< Get the `length recovery` value (Little Endian). This value is used
getLengthRecovery(); ///< Get the `length recovery` value (Little Endian). This value is used ///< while XORing to recover the length of the missing media packet.
///< while XORing to recover the length of the missing media packet.
bool coversSequenceNumber(uint16_t sn); ///< Returns true when this `PacketFEC` instance is used bool coversSequenceNumber(uint16_t sn); ///< Returns true when this `PacketFEC` instance is used
///< to protect the given sequence number. ///< to protect the given sequence number.
void void addReceivedSequenceNumber(uint16_t sn); ///< Whenever you receive a media packet (complete) call
addReceivedSequenceNumber(uint16_t sn); ///< Whenever you receive a media packet (complete) call ///< this as we need to know if enough media packets
///< this as we need to know if enough media packets ///< exist that are needed to recover another one.
///< exist that are needed to recover another one.
void tryToRecoverMissingPacket( void tryToRecoverMissingPacket(
std::map<uint16_t, RTP::Packet> &receivedMediaPackets, std::map<uint16_t, RTP::Packet> &receivedMediaPackets,
Packet &reconstructedPacket); ///< Pass in a `std::map` indexed by sequence number of -all- Packet &reconstructedPacket); ///< Pass in a `std::map` indexed by sequence number of -all-
@ -61,19 +57,16 @@ namespace RTP{
///< will fill the packet passed by reference. ///< will fill the packet passed by reference.
private: private:
bool bool extractCoveringSequenceNumbers(); ///< Used internally to fill the `coveredSeqNums` member which
extractCoveringSequenceNumbers(); ///< Used internally to fill the `coveredSeqNums` member which ///< tell us what media packets this FEC packet rotects.
///< tell us what media packets this FEC packet rotects.
public: public:
Util::ResizeablePointer fecPacketData; Util::ResizeablePointer fecPacketData;
Util::ResizeablePointer recoverData; Util::ResizeablePointer recoverData;
std::set<uint16_t> std::set<uint16_t> coveredSeqNums; ///< The sequence numbers of the packets that this FEC protects.
coveredSeqNums; ///< The sequence numbers of the packets that this FEC protects. std::set<uint16_t> receivedSeqNums; ///< We keep track of sequence numbers that were received (at some higher
std::set<uint16_t> ///< level). We can only recover 1 media packet and this is used to check
receivedSeqNums; ///< We keep track of sequence numbers that were received (at some higher ///< if this `PacketFEC` instance is capable of recovering anything.
///< level). We can only recover 1 media packet and this is used to check
///< if this `PacketFEC` instance is capable of recovering anything.
}; };
class FECSorter : public Sorter{ class FECSorter : public Sorter{
@ -97,4 +90,3 @@ namespace RTP{
}; };
}// namespace RTP }// namespace RTP

View file

@ -1,12 +1,12 @@
#include "sdp.h"
#include "adts.h" #include "adts.h"
#include "defines.h" #include "defines.h"
#include "encode.h" #include "encode.h"
#include "h264.h" #include "h264.h"
#include "h265.h" #include "h265.h"
#include "http_parser.h" #include "http_parser.h"
#include "util.h" #include "sdp.h"
#include "url.h" #include "url.h"
#include "util.h"
namespace SDP{ namespace SDP{
@ -15,7 +15,6 @@ namespace SDP{
snglState->updateInit(track, initData); snglState->updateInit(track, initData);
} }
Track::Track(){ Track::Track(){
rtcpSent = 0; rtcpSent = 0;
channel = -1; channel = -1;
@ -67,15 +66,13 @@ namespace SDP{
size_t count = avccbox.getSPSCount(); size_t count = avccbox.getSPSCount();
for (size_t i = 0; i < count; ++i){ for (size_t i = 0; i < count; ++i){
mediaDesc << (i ? "," : "") mediaDesc << (i ? "," : "")
<< Encodings::Base64::encode( << Encodings::Base64::encode(std::string(avccbox.getSPS(i), avccbox.getSPSLen(i)));
std::string(avccbox.getSPS(i), avccbox.getSPSLen(i)));
} }
mediaDesc << ","; mediaDesc << ",";
count = avccbox.getPPSCount(); count = avccbox.getPPSCount();
for (size_t i = 0; i < count; ++i){ for (size_t i = 0; i < count; ++i){
mediaDesc << (i ? "," : "") mediaDesc << (i ? "," : "")
<< Encodings::Base64::encode( << Encodings::Base64::encode(std::string(avccbox.getPPS(i), avccbox.getPPSLen(i)));
std::string(avccbox.getPPS(i), avccbox.getPPSLen(i)));
} }
mediaDesc << "\r\n" mediaDesc << "\r\n"
<< "a=framerate:" << ((double)trk.fpks) / 1000.0 << "a=framerate:" << ((double)trk.fpks) / 1000.0
@ -188,8 +185,7 @@ namespace SDP{
}else{ }else{
mediaDesc << "m=audio 0 RTP/AVP 103" mediaDesc << "m=audio 0 RTP/AVP 103"
<< "\r\n"; << "\r\n";
mediaDesc << "a=rtpmap:103 L" << trk.size << "/" << trk.rate << "/" << trk.channels mediaDesc << "a=rtpmap:103 L" << trk.size << "/" << trk.rate << "/" << trk.channels << "\r\n";
<< "\r\n";
} }
mediaDesc << "a=control:track" << trk.trackID << "\r\n"; mediaDesc << "a=control:track" << trk.trackID << "\r\n";
}else if (trk.codec == "opus"){ }else if (trk.codec == "opus"){
@ -212,8 +208,7 @@ namespace SDP{
// We simply request interleaved delivery over a trackNo-based identifier. // We simply request interleaved delivery over a trackNo-based identifier.
// No need to set any internal state, parseTransport will handle it all. // No need to set any internal state, parseTransport will handle it all.
std::stringstream tStr; std::stringstream tStr;
tStr << "RTP/AVP/TCP;unicast;interleaved=" << ((trackNo - 1) * 2) << "-" tStr << "RTP/AVP/TCP;unicast;interleaved=" << ((trackNo - 1) * 2) << "-" << ((trackNo - 1) * 2 + 1);
<< ((trackNo - 1) * 2 + 1);
return tStr.str(); return tStr.str();
}else{ }else{
// A little more tricky: we need to find free ports and remember them. // A little more tricky: we need to find free ports and remember them.
@ -277,9 +272,8 @@ namespace SDP{
return false; return false;
} }
if (transport.find("TCP") != std::string::npos){ if (transport.find("TCP") != std::string::npos){
std::string chanE = std::string chanE = transport.substr(transport.find("interleaved=") + 12,
transport.substr(transport.find("interleaved=") + 12, (transport.size() - transport.rfind('-') - 1)); // extract channel ID
(transport.size() - transport.rfind('-') - 1)); // extract channel ID
channel = atol(chanE.c_str()); channel = atol(chanE.c_str());
rtcpSent = 0; rtcpSent = 0;
transportString = transport; transportString = transport;
@ -289,8 +283,7 @@ namespace SDP{
cPortA = cPortB = 0; cPortA = cPortB = 0;
size_t sPort_loc = transport.rfind("server_port=") + 12; size_t sPort_loc = transport.rfind("server_port=") + 12;
if (sPort_loc != std::string::npos){ if (sPort_loc != std::string::npos){
sPortA = sPortA = atol(transport.substr(sPort_loc, transport.find('-', sPort_loc) - sPort_loc).c_str());
atol(transport.substr(sPort_loc, transport.find('-', sPort_loc) - sPort_loc).c_str());
sPortB = atol(transport.substr(transport.find('-', sPort_loc) + 1).c_str()); sPortB = atol(transport.substr(transport.find('-', sPort_loc) + 1).c_str());
} }
size_t port_loc = transport.rfind("client_port=") + 12; size_t port_loc = transport.rfind("client_port=") + 12;
@ -311,8 +304,7 @@ namespace SDP{
std::stringstream tStr; std::stringstream tStr;
tStr << "RTP/AVP/UDP;unicast;client_port=" << cPortA << '-' << cPortB << ";"; tStr << "RTP/AVP/UDP;unicast;client_port=" << cPortA << '-' << cPortB << ";";
if (source.size()){tStr << "source=" << source << ";";} if (source.size()){tStr << "source=" << source << ";";}
tStr << "server_port=" << portA << "-" << portB << ";ssrc=" << std::hex << mySSRC tStr << "server_port=" << portA << "-" << portB << ";ssrc=" << std::hex << mySSRC << std::dec;
<< std::dec;
transportString = tStr.str(); transportString = tStr.str();
}else{ }else{
// Client mode - check ports and/or obey given ports if possible // Client mode - check ports and/or obey given ports if possible
@ -342,11 +334,9 @@ namespace SDP{
} }
/// Gets the rtpInfo for a given DTSC::Track, source identifier and timestamp (in millis). /// Gets the rtpInfo for a given DTSC::Track, source identifier and timestamp (in millis).
std::string Track::rtpInfo(const DTSC::Track &trk, const std::string &source, std::string Track::rtpInfo(const DTSC::Track &trk, const std::string &source, uint64_t currentTime){
uint64_t currentTime){
std::stringstream rInfo; std::stringstream rInfo;
rInfo << "url=" << source << "/track" << trk.trackID rInfo << "url=" << source << "/track" << trk.trackID << ";"; // get the current url, not localhost
<< ";"; // get the current url, not localhost
rInfo << "sequence=" << pack.getSequence() << ";rtptime=" << currentTime * getMultiplier(trk); rInfo << "sequence=" << pack.getSequence() << ";rtptime=" << currentTime * getMultiplier(trk);
return rInfo.str(); return rInfo.str();
} }
@ -503,7 +493,7 @@ namespace SDP{
thisTrack->codec = "PCM"; thisTrack->codec = "PCM";
thisTrack->size = 20; thisTrack->size = 20;
} }
if (trCodec == "L24"|| trCodec == "PCM"){ if (trCodec == "L24" || trCodec == "PCM"){
thisTrack->codec = "PCM"; thisTrack->codec = "PCM";
thisTrack->size = 24; thisTrack->size = 24;
} }
@ -541,8 +531,7 @@ namespace SDP{
// a=fmtp:97 // a=fmtp:97
// profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; // profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;
// config=120856E500 // config=120856E500
FAIL_MSG("AAC transport mode not supported: %s", FAIL_MSG("AAC transport mode not supported: %s", tracks[trackNo].getParamString("mode").c_str());
tracks[trackNo].getParamString("mode").c_str());
nope = true; nope = true;
myMeta->tracks.erase(trackNo); myMeta->tracks.erase(trackNo);
tracks.erase(trackNo); tracks.erase(trackNo);
@ -562,12 +551,9 @@ namespace SDP{
updateH264Init(trackNo); updateH264Init(trackNo);
} }
if (thisTrack->codec == "HEVC"){ if (thisTrack->codec == "HEVC"){
tracks[trackNo].hevcInfo.addUnit( tracks[trackNo].hevcInfo.addUnit(Encodings::Base64::decode(tracks[trackNo].getParamString("sprop-vps")));
Encodings::Base64::decode(tracks[trackNo].getParamString("sprop-vps"))); tracks[trackNo].hevcInfo.addUnit(Encodings::Base64::decode(tracks[trackNo].getParamString("sprop-sps")));
tracks[trackNo].hevcInfo.addUnit( tracks[trackNo].hevcInfo.addUnit(Encodings::Base64::decode(tracks[trackNo].getParamString("sprop-pps")));
Encodings::Base64::decode(tracks[trackNo].getParamString("sprop-sps")));
tracks[trackNo].hevcInfo.addUnit(
Encodings::Base64::decode(tracks[trackNo].getParamString("sprop-pps")));
updateH265Init(trackNo); updateH265Init(trackNo);
} }
continue; continue;
@ -639,8 +625,7 @@ namespace SDP{
if (H.url == "200"){ if (H.url == "200"){
++trackCounter; ++trackCounter;
if (!tracks.count(trackCounter)){return 0;} if (!tracks.count(trackCounter)){return 0;}
if (!tracks[trackCounter].parseTransport(H.GetHeader("Transport"), cH, src, if (!tracks[trackCounter].parseTransport(H.GetHeader("Transport"), cH, src, myMeta->tracks[trackCounter])){
myMeta->tracks[trackCounter])){
return 0; return 0;
} }
return trackCounter; return trackCounter;
@ -660,13 +645,11 @@ namespace SDP{
} }
if ((urlString.size() >= it->second.control.size() && if ((urlString.size() >= it->second.control.size() &&
urlString.substr(urlString.size() - it->second.control.size()) == urlString.substr(urlString.size() - it->second.control.size()) == it->second.control) ||
it->second.control) ||
(pw.size() >= it->second.control.size() && (pw.size() >= it->second.control.size() &&
pw.substr(pw.size() - it->second.control.size()) == it->second.control)){ pw.substr(pw.size() - it->second.control.size()) == it->second.control)){
INFO_MSG("Parsing SETUP against track %lu", it->first); INFO_MSG("Parsing SETUP against track %lu", it->first);
if (!it->second.parseTransport(H.GetHeader("Transport"), cH, src, if (!it->second.parseTransport(H.GetHeader("Transport"), cH, src, myMeta->tracks[it->first])){
myMeta->tracks[it->first])){
return 0; return 0;
} }
return it->first; return it->first;
@ -677,8 +660,7 @@ namespace SDP{
uint32_t trackNo = atoi(H.url.c_str() + H.url.find("/track") + 6); uint32_t trackNo = atoi(H.url.c_str() + H.url.find("/track") + 6);
if (trackNo){ if (trackNo){
INFO_MSG("Parsing SETUP against track %lu", trackNo); INFO_MSG("Parsing SETUP against track %lu", trackNo);
if (!tracks[trackNo].parseTransport(H.GetHeader("Transport"), cH, src, if (!tracks[trackNo].parseTransport(H.GetHeader("Transport"), cH, src, myMeta->tracks[trackNo])){
myMeta->tracks[trackNo])){
return 0; return 0;
} }
return trackNo; return trackNo;
@ -701,9 +683,7 @@ namespace SDP{
} }
void State::updateInit(const uint64_t trackNo, const std::string &initData){ void State::updateInit(const uint64_t trackNo, const std::string &initData){
if (myMeta->tracks.count(trackNo)){ if (myMeta->tracks.count(trackNo)){myMeta->tracks[trackNo].init = initData;}
myMeta->tracks[trackNo].init = initData;
}
} }
/// Handles RTP packets generically, for both TCP and UDP-based connections. /// Handles RTP packets generically, for both TCP and UDP-based connections.
@ -714,4 +694,3 @@ namespace SDP{
} }
}// namespace SDP }// namespace SDP

View file

@ -13,8 +13,7 @@ namespace SDP{
class Track{ class Track{
public: public:
Track(); Track();
std::string generateTransport(uint32_t trackNo, const std::string &dest = "", std::string generateTransport(uint32_t trackNo, const std::string &dest = "", bool TCPmode = true);
bool TCPmode = true);
std::string getParamString(const std::string &param) const; std::string getParamString(const std::string &param) const;
uint64_t getParamInt(const std::string &param) const; uint64_t getParamInt(const std::string &param) const;
bool parseTransport(const std::string &transport, const std::string &host, bool parseTransport(const std::string &transport, const std::string &host,
@ -54,12 +53,12 @@ namespace SDP{
uint32_t getTrackNoForChannel(uint8_t chan); uint32_t getTrackNoForChannel(uint8_t chan);
uint32_t parseSetup(HTTP::Parser &H, const std::string &host, const std::string &source); uint32_t parseSetup(HTTP::Parser &H, const std::string &host, const std::string &source);
void handleIncomingRTP(const uint64_t track, const RTP::Packet &pkt); void handleIncomingRTP(const uint64_t track, const RTP::Packet &pkt);
public: public:
DTSC::Meta *myMeta; DTSC::Meta *myMeta;
std::map<uint32_t, RTP::toDTSC> tConv; ///<Converters to DTSC std::map<uint32_t, RTP::toDTSC> tConv; ///< Converters to DTSC
std::map<uint32_t, Track> tracks; ///< List of selected tracks with SDP-specific session data. std::map<uint32_t, Track> tracks; ///< List of selected tracks with SDP-specific session data.
}; };
std::string mediaDescription(const DTSC::Track &trk); std::string mediaDescription(const DTSC::Track &trk);
}// namespace SDP }// namespace SDP

View file

@ -38,7 +38,7 @@ namespace SDP{
}else if (codec == "RED"){ }else if (codec == "RED"){
return ""; return "";
} }
ERROR_MSG( "%s support not implemented", codec.c_str()); ERROR_MSG("%s support not implemented", codec.c_str());
return ""; return "";
} }
@ -70,31 +70,27 @@ namespace SDP{
}else if (codec == "RED"){ }else if (codec == "RED"){
return ""; return "";
} }
ERROR_MSG( "%s support not implemented", codec.c_str()); ERROR_MSG("%s support not implemented", codec.c_str());
BACKTRACE; BACKTRACE;
return ""; return "";
} }
static std::vector<std::string> sdp_split( static std::vector<std::string>
const std::string &str, const std::string &delim, sdp_split(const std::string &str, const std::string &delim,
bool keepEmpty); // Split a string on the given delimeter and return a vector with the parts. bool keepEmpty); // Split a string on the given delimeter and return a vector with the parts.
static bool static bool sdp_extract_payload_type(const std::string &str,
sdp_extract_payload_type(const std::string &str, uint64_t &result); // Extract the payload number from a SDP line that
uint64_t &result); // Extract the payload number from a SDP line that // starts like: `a=something:[payloadtype]`.
// starts like: `a=something:[payloadtype]`. static bool sdp_get_name_value_from_varval(const std::string &str, std::string &var,
static bool sdp_get_name_value_from_varval( std::string &value); // Extracts the `name` and `value` from a string like `<name>=<value>`.
const std::string &str, std::string &var, // The `name` will always be converted to lowercase!.
std::string &value); // Extracts the `name` and `value` from a string like `<name>=<value>`. static void
// The `name` will always be converted to lowercase!. sdp_get_all_name_values_from_string(const std::string &str, std::map<std::string, std::string> &result); // Extracts all the name/value pairs from a string like:
static void sdp_get_all_name_values_from_string( // `<name>=<value>;<name>=<value>`. The `name` part will
const std::string &str, std::map<std::string, std::string> // always be converted to lowercase.
&result); // Extracts all the name/value pairs from a string like: static bool sdp_get_attribute_value(const std::string &str,
// `<name>=<value>;<name>=<value>`. The `name` part will std::string &result); // Extract an "attribute" value, which is formatted
// always be converted to lowercase. // like: `a=something:<attribute-value>`
static bool
sdp_get_attribute_value(const std::string &str,
std::string &result); // Extract an "attribute" value, which is formatted
// like: `a=something:<attribute-value>`
static std::string string_to_upper(const std::string &str); static std::string string_to_upper(const std::string &str);
MediaFormat::MediaFormat(){ MediaFormat::MediaFormat(){
@ -234,9 +230,9 @@ namespace SDP{
return pm; return pm;
} }
std::string MediaFormat::getProfileLevelIdForH264() { std::string MediaFormat::getProfileLevelIdForH264(){
if (encodingName != "H264") { if (encodingName != "H264"){
ERROR_MSG("Encoding is not H264, cannot get profile-level-id."); ERROR_MSG("Encoding is not H264, cannot get profile-level-id.");
return ""; return "";
} }
@ -352,8 +348,7 @@ namespace SDP{
bool Media::parseFrameRateLine(const std::string &line){ bool Media::parseFrameRateLine(const std::string &line){
if (line.substr(0, 12) != "a=framerate:"){ if (line.substr(0, 12) != "a=framerate:"){
ERROR_MSG("Cannot parse the `a=framerate:` line because it's incorrectly formatted: `%s`.", ERROR_MSG("Cannot parse the `a=framerate:` line because it's incorrectly formatted: `%s`.", line.c_str());
line.c_str());
return false; return false;
} }
@ -389,7 +384,7 @@ namespace SDP{
// When this format is associated with another format // When this format is associated with another format
// which is the case for RTX, we store the associated // which is the case for RTX, we store the associated
// payload type too. `apt` means "Associated Payload Type". // payload type too. `apt` means "Associated Payload Type".
if (format->formatParameters.count("apt") != 0) { if (format->formatParameters.count("apt") != 0){
std::stringstream ss(format->formatParameters["apt"]); std::stringstream ss(format->formatParameters["apt"]);
ss >> format->associatedPayloadType; ss >> format->associatedPayloadType;
} }
@ -530,17 +525,13 @@ namespace SDP{
return result; return result;
} }
MediaFormat* Media::getRetransMissionFormatForPayloadType(uint64_t pt) { MediaFormat *Media::getRetransMissionFormatForPayloadType(uint64_t pt){
std::vector<SDP::MediaFormat*> rtxFormats = getFormatsForEncodingName("RTX"); std::vector<SDP::MediaFormat *> rtxFormats = getFormatsForEncodingName("RTX");
if (rtxFormats.size() == 0) { if (rtxFormats.size() == 0){return NULL;}
return NULL;
}
for (size_t i = 0; i < rtxFormats.size(); ++i) { for (size_t i = 0; i < rtxFormats.size(); ++i){
if (rtxFormats[i]->associatedPayloadType == pt) { if (rtxFormats[i]->associatedPayloadType == pt){return rtxFormats[i];}
return rtxFormats[i];
}
} }
return NULL; return NULL;
@ -567,8 +558,7 @@ namespace SDP{
/// ///
/// @param mediaType `video` or `audio` /// @param mediaType `video` or `audio`
/// @param encodingName Encoding name in fullcaps, e.g. `H264`, `OPUS`, etc. /// @param encodingName Encoding name in fullcaps, e.g. `H264`, `OPUS`, etc.
MediaFormat *Session::getMediaFormatByEncodingName(const std::string &mediaType, MediaFormat *Session::getMediaFormatByEncodingName(const std::string &mediaType, const std::string &encodingName){
const std::string &encodingName){
SDP::Media *media = getMediaForType(mediaType); SDP::Media *media = getMediaForType(mediaType);
if (!media){ if (!media){
WARN_MSG("No SDP::Media found for media type %s.", mediaType.c_str()); WARN_MSG("No SDP::Media found for media type %s.", mediaType.c_str());
@ -666,8 +656,7 @@ namespace SDP{
return true; return true;
} }
static std::vector<std::string> sdp_split(const std::string &str, const std::string &delim, static std::vector<std::string> sdp_split(const std::string &str, const std::string &delim, bool keepEmpty){
bool keepEmpty){
std::vector<std::string> strings; std::vector<std::string> strings;
std::ostringstream word; std::ostringstream word;
for (size_t n = 0; n < str.size(); ++n){ for (size_t n = 0; n < str.size(); ++n){
@ -686,8 +675,7 @@ namespace SDP{
// extract payload type. // extract payload type.
size_t start_pos = str.find_first_of(':'); size_t start_pos = str.find_first_of(':');
size_t end_pos = str.find_first_of(' ', start_pos); size_t end_pos = str.find_first_of(' ', start_pos);
if (start_pos == std::string::npos || end_pos == std::string::npos || if (start_pos == std::string::npos || end_pos == std::string::npos || (start_pos + 1) >= end_pos){
(start_pos + 1) >= end_pos){
FAIL_MSG("Invalid `a=rtpmap` line. Has not payload type."); FAIL_MSG("Invalid `a=rtpmap` line. Has not payload type.");
return false; return false;
} }
@ -704,8 +692,7 @@ namespace SDP{
// when parsing the `a=fmtp:<fmt>` line. // when parsing the `a=fmtp:<fmt>` line.
// //
// Note that we will always convert the `var` to lowercase. // Note that we will always convert the `var` to lowercase.
static bool sdp_get_name_value_from_varval(const std::string &str, std::string &var, static bool sdp_get_name_value_from_varval(const std::string &str, std::string &var, std::string &value){
std::string &value){
if (str.empty()){ if (str.empty()){
ERROR_MSG("Cannot get `name` and `value` from string because the given string is empty. " ERROR_MSG("Cannot get `name` and `value` from string because the given string is empty. "
@ -764,8 +751,7 @@ namespace SDP{
size_t start = str.find(":"); size_t start = str.find(":");
if (start == std::string::npos){ if (start == std::string::npos){
ERROR_MSG("Cannot get attribute value because we did not find the : character in %s.", ERROR_MSG("Cannot get attribute value because we did not find the : character in %s.", str.c_str());
str.c_str());
return false; return false;
} }
@ -773,12 +759,9 @@ namespace SDP{
return true; return true;
} }
Answer::Answer() : Answer::Answer()
isVideoEnabled(false), : isVideoEnabled(false), isAudioEnabled(false), candidatePort(0),
isAudioEnabled(false), videoLossPrevention(SDP_LOSS_PREVENTION_NONE){}
candidatePort(0),
videoLossPrevention(SDP_LOSS_PREVENTION_NONE)
{}
bool Answer::parseOffer(const std::string &sdp){ bool Answer::parseOffer(const std::string &sdp){
@ -931,8 +914,8 @@ namespace SDP{
std::string type = mediaOffer.type; std::string type = mediaOffer.type;
SDP::Media *media = NULL; SDP::Media *media = NULL;
SDP::MediaFormat *fmtMedia = NULL; SDP::MediaFormat *fmtMedia = NULL;
SDP::MediaFormat* fmtRED = NULL; SDP::MediaFormat *fmtRED = NULL;
SDP::MediaFormat* fmtULPFEC = NULL; SDP::MediaFormat *fmtULPFEC = NULL;
bool isEnabled = false; bool isEnabled = false;
std::vector<uint8_t> supportedPayloadTypes; std::vector<uint8_t> supportedPayloadTypes;
@ -951,11 +934,11 @@ namespace SDP{
fmtULPFEC = media->getFormatForEncodingName("ULPFEC"); fmtULPFEC = media->getFormatForEncodingName("ULPFEC");
} }
if (!media) { if (!media){
WARN_MSG("No media found."); WARN_MSG("No media found.");
continue; continue;
} }
if (!fmtMedia) { if (!fmtMedia){
WARN_MSG("No format found."); WARN_MSG("No format found.");
continue; continue;
} }
@ -964,21 +947,16 @@ namespace SDP{
// them payload types into a string that is used with the // them payload types into a string that is used with the
// `m=` line to indicate we have support for these. // `m=` line to indicate we have support for these.
supportedPayloadTypes.push_back((uint8_t)fmtMedia->payloadType); supportedPayloadTypes.push_back((uint8_t)fmtMedia->payloadType);
if ((videoLossPrevention & SDP_LOSS_PREVENTION_ULPFEC) if ((videoLossPrevention & SDP_LOSS_PREVENTION_ULPFEC) && fmtRED && fmtULPFEC){
&& fmtRED supportedPayloadTypes.push_back(fmtRED->payloadType);
&& fmtULPFEC) supportedPayloadTypes.push_back(fmtULPFEC->payloadType);
{ }
supportedPayloadTypes.push_back(fmtRED->payloadType);
supportedPayloadTypes.push_back(fmtULPFEC->payloadType);
}
std::stringstream ss; std::stringstream ss;
size_t nels = supportedPayloadTypes.size(); size_t nels = supportedPayloadTypes.size();
for (size_t k = 0; k < nels; ++k) { for (size_t k = 0; k < nels; ++k){
ss << (int)supportedPayloadTypes[k]; ss << (int)supportedPayloadTypes[k];
if ((k + 1) < nels) { if ((k + 1) < nels){ss << " ";}
ss << " ";
}
} }
std::string payloadTypes = ss.str(); std::string payloadTypes = ss.str();
@ -1008,14 +986,11 @@ namespace SDP{
addLine("a=%s", fmtMedia->rtpmap.c_str()); addLine("a=%s", fmtMedia->rtpmap.c_str());
// BEGIN FEC/RTX: testing with just FEC or RTX // BEGIN FEC/RTX: testing with just FEC or RTX
if ((videoLossPrevention & SDP_LOSS_PREVENTION_ULPFEC) if ((videoLossPrevention & SDP_LOSS_PREVENTION_ULPFEC) && fmtRED && fmtULPFEC){
&& fmtRED addLine("a=rtpmap:%u ulpfec/90000", fmtULPFEC->payloadType);
&& fmtULPFEC) addLine("a=rtpmap:%u red/90000", fmtRED->payloadType);
{ }
addLine("a=rtpmap:%u ulpfec/90000", fmtULPFEC->payloadType); if (videoLossPrevention & SDP_LOSS_PREVENTION_NACK){
addLine("a=rtpmap:%u red/90000", fmtRED->payloadType);
}
if (videoLossPrevention & SDP_LOSS_PREVENTION_NACK) {
addLine("a=rtcp-fb:%u nack", fmtMedia->payloadType); addLine("a=rtcp-fb:%u nack", fmtMedia->payloadType);
} }
// END FEC/RTX // END FEC/RTX
@ -1026,7 +1001,8 @@ namespace SDP{
if (fmtMedia->encodingName == "H264"){ if (fmtMedia->encodingName == "H264"){
std::string usedProfile = fmtMedia->getFormatParameterForName("profile-level-id"); std::string usedProfile = fmtMedia->getFormatParameterForName("profile-level-id");
if (usedProfile != "42e01f"){ if (usedProfile != "42e01f"){
WARN_MSG("The selected profile-level-id was not 42e01f. We rewrite it into this because that's what we support atm."); WARN_MSG("The selected profile-level-id was not 42e01f. We rewrite it into this because "
"that's what we support atm.");
usedProfile = "42e01f"; usedProfile = "42e01f";
} }
@ -1074,8 +1050,7 @@ namespace SDP{
SDP::Media &outMedia, SDP::MediaFormat &outFormat){ SDP::Media &outMedia, SDP::MediaFormat &outFormat){
Media *media = sdpOffer.getMediaForType(type); Media *media = sdpOffer.getMediaForType(type);
if (!media){ if (!media){
INFO_MSG("Cannot enable %s codec; offer doesn't have %s media.", codecList.c_str(), INFO_MSG("Cannot enable %s codec; offer doesn't have %s media.", codecList.c_str(), type.c_str());
type.c_str());
return false; return false;
} }
@ -1102,8 +1077,9 @@ namespace SDP{
format = NULL; format = NULL;
continue; continue;
} }
if (formats[j]->getProfileLevelIdForH264() != "42e01f") { if (formats[j]->getProfileLevelIdForH264() != "42e01f"){
MEDIUM_MSG("Skipping this H264 format because it uses an unsupported profile-level-id."); MEDIUM_MSG(
"Skipping this H264 format because it uses an unsupported profile-level-id.");
format = NULL; format = NULL;
continue; continue;
} }
@ -1179,6 +1155,4 @@ namespace SDP{
return result; return result;
} }
}// namespace SDP
}

View file

@ -1,14 +1,16 @@
#pragma once #pragma once
#include <string> #include "dtsc.h"
#include <map> #include <map>
#include <set> #include <set>
#include <string>
#include <vector> #include <vector>
#include "dtsc.h"
#define SDP_PAYLOAD_TYPE_NONE 9999 /// Define that is used to indicate a payload type is not set. #define SDP_PAYLOAD_TYPE_NONE 9999 /// Define that is used to indicate a payload type is not set.
#define SDP_LOSS_PREVENTION_NONE 0 #define SDP_LOSS_PREVENTION_NONE 0
#define SDP_LOSS_PREVENTION_NACK (1 << 1) /// Use simple NACK based loss prevention. (e.g. send a NACK to pusher of video stream when a packet is lost) #define SDP_LOSS_PREVENTION_NACK \
#define SDP_LOSS_PREVENTION_ULPFEC (1 << 2) /// Use FEC (See rtp.cpp, PacketRED). When used we try to add the correct `a=rtpmap` for RED and ULPFEC to the SDP when supported by the offer. (1 << 1) /// Use simple NACK based loss prevention. (e.g. send a NACK to pusher of video stream when a packet is lost)
#define SDP_LOSS_PREVENTION_ULPFEC \
(1 << 2) /// Use FEC (See rtp.cpp, PacketRED). When used we try to add the correct `a=rtpmap` for RED and ULPFEC to the SDP when supported by the offer.
namespace SDP{ namespace SDP{
@ -30,36 +32,31 @@ namespace SDP{
class MediaFormat{ class MediaFormat{
public: public:
MediaFormat(); MediaFormat();
std::string getFormatParameterForName( std::string getFormatParameterForName(const std::string &name) const; ///< Get a parameter which was part of the `a=fmtp:` line.
const std::string &name) const; ///< Get a parameter which was part of the `a=fmtp:` line. uint32_t getAudioSampleRate() const; ///< Returns the audio sample rate. When `audioSampleRate` has been set this will be
uint32_t getAudioSampleRate() ///< returned, otherwise we use the `payloadType` to determine the samplerate or
const; ///< Returns the audio sample rate. When `audioSampleRate` has been set this will be ///< return 0 when we fail to determine to samplerate.
///< returned, otherwise we use the `payloadType` to determine the samplerate or
///< return 0 when we fail to determine to samplerate.
uint32_t getAudioNumChannels()
const; ///< Returns the number of audio channels. When `audioNumChannels` has been set this
///< will be returned, otherwise we use the `payloadType` when it's set to determine
///< the samplerate or we return 0 when we can't determine the number of channels.
uint32_t getAudioBitSize()
const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be
///< returned, othwerise we use the `encodingName` to determine the right
///< `audioBitSize` or 0 when we can't determine the `audioBitSize`
uint32_t uint32_t
getVideoRate() const; ///< Returns the video time base. When `videoRate` has been set this will getAudioNumChannels() const; ///< Returns the number of audio channels. When `audioNumChannels` has been set this
///< be returned, otherwise we use the `encodingName` to determine the ///< will be returned, otherwise we use the `payloadType` when it's set to determine
///< right value or 0 when we can't determine the video rate. ///< the samplerate or we return 0 when we can't determine the number of channels.
uint32_t getAudioBitSize() const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be
///< returned, othwerise we use the `encodingName` to determine the right
///< `audioBitSize` or 0 when we can't determine the `audioBitSize`
uint32_t getVideoRate() const; ///< Returns the video time base. When `videoRate` has been set this will
///< be returned, otherwise we use the `encodingName` to determine the
///< right value or 0 when we can't determine the video rate.
uint32_t getVideoOrAudioRate() const; ///< Returns whichever rate has been set. uint32_t getVideoOrAudioRate() const; ///< Returns whichever rate has been set.
uint64_t getPayloadType() const; ///< Returns the `payloadType` member. uint64_t getPayloadType() const; ///< Returns the `payloadType` member.
int32_t int32_t getPacketizationModeForH264(); ///< When this represents a h264 format this will return the
getPacketizationModeForH264(); ///< When this represents a h264 format this will return the ///< packetization mode when it was provided in the SDP
///< packetization mode when it was provided in the SDP
std::string getProfileLevelIdForH264(); ///< When this represents a H264 format, this will return the profile-level-id from the format parameters. std::string getProfileLevelIdForH264(); ///< When this represents a H264 format, this will return the profile-level-id from the format parameters.
operator bool() const; operator bool() const;
public: public:
uint64_t payloadType; ///< The payload type as set in the media line (the <fmt> is -the- uint64_t payloadType; ///< The payload type as set in the media line (the <fmt> is -the-
///< payloadType). ///< payloadType).
uint64_t associatedPayloadType; ///< From `a=fmtp:<pt> apt=<apt>`; maps this format to another payload type. uint64_t associatedPayloadType; ///< From `a=fmtp:<pt> apt=<apt>`; maps this format to another payload type.
int32_t audioSampleRate; ///< Samplerate of the audio type. int32_t audioSampleRate; ///< Samplerate of the audio type.
int32_t audioNumChannels; ///< Number of audio channels extracted from the `a=fmtp` or set in int32_t audioNumChannels; ///< Number of audio channels extracted from the `a=fmtp` or set in
@ -72,12 +69,10 @@ namespace SDP{
std::string iceUFrag; ///< From `a=ice-ufrag:<ufrag>, used with WebRTC / STUN. std::string iceUFrag; ///< From `a=ice-ufrag:<ufrag>, used with WebRTC / STUN.
std::string icePwd; ///< From `a=ice-pwd:<pwd>`, used with WebRTC / STUN std::string icePwd; ///< From `a=ice-pwd:<pwd>`, used with WebRTC / STUN
std::string rtpmap; ///< The `a=<rtpmap:...> value; value between brackets. std::string rtpmap; ///< The `a=<rtpmap:...> value; value between brackets.
std::map<std::string, std::string> std::map<std::string, std::string> formatParameters; ///< Stores the var-val pairs from `a=fmtp:<fmt>` entry e.g. =
formatParameters; ///< Stores the var-val pairs from `a=fmtp:<fmt>` entry e.g. = ///< `packetization-mode=1;profile-level-id=4d0029;sprop-parameter-sets=Z00AKeKQCADDYC3AQEBpB4kRUA==,aO48gA==`
///< `packetization-mode=1;profile-level-id=4d0029;sprop-parameter-sets=Z00AKeKQCADDYC3AQEBpB4kRUA==,aO48gA==` ///< */
///< */ std::set<std::string> rtcpFormats; ///< Stores the `fb-val` from the line with `a=rtcp-fb:<fmt> <fb-val>`.
std::set<std::string>
rtcpFormats; ///< Stores the `fb-val` from the line with `a=rtcp-fb:<fmt> <fb-val>`.
}; };
class Media{ class Media{
@ -85,40 +80,32 @@ namespace SDP{
Media(); Media();
bool parseMediaLine(const std::string &sdpLine); ///< Parses `m=` line. Creates a `MediaFormat` bool parseMediaLine(const std::string &sdpLine); ///< Parses `m=` line. Creates a `MediaFormat`
///< entry for each of the found <fmt> values. ///< entry for each of the found <fmt> values.
bool parseRtpMapLine( bool parseRtpMapLine(const std::string &sdpLine); ///< Parses `a=rtpmap:` line which contains the some codec
const std::string &sdpLine); ///< Parses `a=rtpmap:` line which contains the some codec ///< specific info. When this line contains the samplerate and
///< specific info. When this line contains the samplerate and ///< number of audio channels they will be extracted.
///< number of audio channels they will be extracted.
bool parseRtspControlLine(const std::string &sdpLine); ///< Parses `a=control:` bool parseRtspControlLine(const std::string &sdpLine); ///< Parses `a=control:`
bool parseFrameRateLine(const std::string &sdpLine); ///< Parses `a=framerate:` bool parseFrameRateLine(const std::string &sdpLine); ///< Parses `a=framerate:`
bool parseFormatParametersLine(const std::string &sdpLine); ///< Parses `a=fmtp:<payload-type>`. bool parseFormatParametersLine(const std::string &sdpLine); ///< Parses `a=fmtp:<payload-type>`.
bool parseRtcpFeedbackLine( bool parseRtcpFeedbackLine(const std::string &sdpLine); ///< Parses `a=rtcp-fb:<payload-type>`. See RFC4584
const std::string &sdpLine); ///< Parses `a=rtcp-fb:<payload-type>`. See RFC4584 bool parseFingerprintLine(const std::string &sdpLine); ///< Parses `a=fingerprint:<hash-func> <value>`. See
bool parseFingerprintLine( ///< https://tools.ietf.org/html/rfc8122#section-5, used with WebRTC
const std::string
&sdpLine); ///< Parses `a=fingerprint:<hash-func> <value>`. See
///< https://tools.ietf.org/html/rfc8122#section-5, used with WebRTC
bool parseSSRCLine(const std::string &sdpLine); ///< Parses `a=ssrc:<ssrc>`. bool parseSSRCLine(const std::string &sdpLine); ///< Parses `a=ssrc:<ssrc>`.
MediaFormat *getFormatForSdpLine( MediaFormat *getFormatForSdpLine(const std::string &sdpLine); ///< Returns the track to which this SDP line applies. This means that the
const std::string ///< SDP line should be formatteed like: `a=something:[payloadtype]`.
&sdpLine); ///< Returns the track to which this SDP line applies. This means that the MediaFormat *
///< SDP line should be formatteed like: `a=something:[payloadtype]`. getFormatForPayloadType(uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no
MediaFormat *getFormatForPayloadType( ///< format was found for the given payload type. .
uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no MediaFormat *getFormatForEncodingName(const std::string &encName); ///< Finds the `MediaFormats in `formats`. Returns NULL when no format was
///< format was found for the given payload type. . ///< found for the given encoding name. E.g. `VP8`, `VP9`, `H264`
MediaFormat *getFormatForEncodingName(
const std::string
&encName); ///< Finds the `MediaFormats in `formats`. Returns NULL when no format was
///< found for the given encoding name. E.g. `VP8`, `VP9`, `H264`
std::vector<SDP::MediaFormat *> getFormatsForEncodingName(const std::string &encName); std::vector<SDP::MediaFormat *> getFormatsForEncodingName(const std::string &encName);
std::string getIcePwdForFormat( std::string getIcePwdForFormat(const MediaFormat &fmt); ///< The `a=ice-pwd` can be session global or media specific. This function will
const MediaFormat ///< check if the `SDP::MediaFormat` has a ice-pwd that we should use.
&fmt); ///< The `a=ice-pwd` can be session global or media specific. This function will uint32_t getSSRC() const; ///< Returns the first SSRC `a=ssrc:<value>` value found for the media.
///< check if the `SDP::MediaFormat` has a ice-pwd that we should use.
uint32_t
getSSRC() const; ///< Returns the first SSRC `a=ssrc:<value>` value found for the media.
operator bool() const; operator bool() const;
MediaFormat* getRetransMissionFormatForPayloadType(uint64_t pt); ///< When available, it resurns the RTX format that is directly associated with the media (not encapsulated with a RED header). RTX can be combined with FEC in which case it's supposed to be stored in RED packets. The `encName` should be something like H264,VP8; e.g. the format for which you want to get the RTX format. MediaFormat *getRetransMissionFormatForPayloadType(
uint64_t pt); ///< When available, it resurns the RTX format that is directly associated with
///< the media (not encapsulated with a RED header). RTX can be combined with
///< FEC in which case it's supposed to be stored in RED packets. The `encName` should be something like H264,VP8; e.g. the format for which you want to get the RTX format.
public: public:
std::string type; ///< The `media` field of the media line: `m=<media> <port> <proto> <fmt>`, std::string type; ///< The `media` field of the media line: `m=<media> <port> <proto> <fmt>`,
@ -132,9 +119,8 @@ namespace SDP{
std::string setupMethod; ///< From `a=setup:<passive, active, actpass>, used with WebRTC / STUN std::string setupMethod; ///< From `a=setup:<passive, active, actpass>, used with WebRTC / STUN
std::string fingerprintHash; ///< From `a=fingerprint:<hash> <value>`, e.g. sha-256, used with std::string fingerprintHash; ///< From `a=fingerprint:<hash> <value>`, e.g. sha-256, used with
///< WebRTC / STUN ///< WebRTC / STUN
std::string std::string fingerprintValue; ///< From `a=fingerprint:<hash> <value>`, the actual fingerprint, used
fingerprintValue; ///< From `a=fingerprint:<hash> <value>`, the actual fingerprint, used ///< with WebRTC / STUN, see https://tools.ietf.org/html/rfc8122#section-5
///< with WebRTC / STUN, see https://tools.ietf.org/html/rfc8122#section-5
std::string mediaID; ///< From `a=mid:<value>`. When generating an WebRTC answer this value must std::string mediaID; ///< From `a=mid:<value>`. When generating an WebRTC answer this value must
///< be the same as in the offer. ///< be the same as in the offer.
std::string candidateIP; ///< Used when we generate a WebRTC answer. std::string candidateIP; ///< Used when we generate a WebRTC answer.
@ -144,21 +130,17 @@ namespace SDP{
bool supportsRTCPMux; ///< From `a=rtcp-mux`, indicates if it can mux RTP and RTCP on one bool supportsRTCPMux; ///< From `a=rtcp-mux`, indicates if it can mux RTP and RTCP on one
///< transport channel. ///< transport channel.
bool supportsRTCPReducedSize; ///< From `a=rtcp-rsize`, reduced size RTCP packets. bool supportsRTCPReducedSize; ///< From `a=rtcp-rsize`, reduced size RTCP packets.
std::string std::string payloadTypes; ///< From `m=` line, all the payload types as string, separated by space.
payloadTypes; ///< From `m=` line, all the payload types as string, separated by space. std::map<uint64_t, MediaFormat> formats; ///< Formats indexed by payload type. Payload type is the number in the <fmt>
std::map<uint64_t, MediaFormat> ///< field(s) from the `m=` line.
formats; ///< Formats indexed by payload type. Payload type is the number in the <fmt>
///< field(s) from the `m=` line.
}; };
class Session{ class Session{
public: public:
bool parseSDP(const std::string &sdp); bool parseSDP(const std::string &sdp);
Media *getMediaForType( Media *getMediaForType(const std::string &type); ///< Get a `SDP::Media*` for the given type, e.g. `video` or
const std::string &type); ///< Get a `SDP::Media*` for the given type, e.g. `video` or ///< `audio`. Returns NULL when the type was not found.
///< `audio`. Returns NULL when the type was not found. MediaFormat *getMediaFormatByEncodingName(const std::string &mediaType, const std::string &encodingName);
MediaFormat *getMediaFormatByEncodingName(const std::string &mediaType,
const std::string &encodingName);
bool hasReceiveOnlyMedia(); ///< Returns true when one of the media sections has a `a=recvonly` bool hasReceiveOnlyMedia(); ///< Returns true when one of the media sections has a `a=recvonly`
///< attribute. This is used to determine if the other peer only ///< attribute. This is used to determine if the other peer only
///< wants to receive or also sent data. */ ///< wants to receive or also sent data. */
@ -168,9 +150,8 @@ namespace SDP{
///< stream specific infomration is stored in a `MediaFormat` ///< stream specific infomration is stored in a `MediaFormat`
std::string icePwd; ///< From `a=ice-pwd`, this property can be session-wide or media specific. std::string icePwd; ///< From `a=ice-pwd`, this property can be session-wide or media specific.
///< Used with WebRTC and STUN when calculating the message-integrity. ///< Used with WebRTC and STUN when calculating the message-integrity.
std::string std::string iceUFrag; ///< From `a=ice-ufag`, this property can be session-wide or media specific. Used
iceUFrag; ///< From `a=ice-ufag`, this property can be session-wide or media specific. Used ///< with WebRTC and STUN when calculating the message-integrity.
///< with WebRTC and STUN when calculating the message-integrity.
}; };
class Answer{ class Answer{
@ -216,5 +197,4 @@ namespace SDP{
uint8_t videoLossPrevention; ///< See the SDP_LOSS_PREVENTION_* values at the top of this header. uint8_t videoLossPrevention; ///< See the SDP_LOSS_PREVENTION_* values at the top of this header.
}; };
} }// namespace SDP

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <string>
#include <set> #include <set>
#include <string>
#include "timing.h"
#include "defines.h" #include "defines.h"
#include "timing.h"
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
#include <windows.h> #include <windows.h>
@ -12,120 +12,121 @@
#endif #endif
#ifndef ACCESSPERMS #ifndef ACCESSPERMS
#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) #define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)
#endif #endif
#define STAT_EX_SIZE 177 #define STAT_EX_SIZE 177
#define PLAY_EX_SIZE 2+6*SIMUL_TRACKS #define PLAY_EX_SIZE 2 + 6 * SIMUL_TRACKS
namespace IPC { namespace IPC{
///\brief A class used for the exchange of statistics over shared memory. ///\brief A class used for the exchange of statistics over shared memory.
class statExchange { class statExchange{
public: public:
statExchange(char * _data); statExchange(char *_data);
void now(long long int time); void now(long long int time);
long long int now(); long long int now();
void time(long time); void time(long time);
long time(); long time();
void lastSecond(long time); void lastSecond(long time);
long lastSecond(); long lastSecond();
void down(long long int bytes); void down(long long int bytes);
long long int down(); long long int down();
void up(long long int bytes); void up(long long int bytes);
long long int up(); long long int up();
void host(std::string name); void host(std::string name);
std::string host(); std::string host();
void streamName(std::string name); void streamName(std::string name);
std::string streamName(); std::string streamName();
void connector(std::string name); void connector(std::string name);
std::string connector(); std::string connector();
void crc(unsigned int sum); void crc(unsigned int sum);
char getSync(); char getSync();
void setSync(char s); void setSync(char s);
unsigned int crc(); unsigned int crc();
uint32_t getPID(); uint32_t getPID();
std::string getSessId(); std::string getSessId();
private: private:
///\brief The payload for the stat exchange ///\brief The payload for the stat exchange
/// - 8 byte - now (timestamp of last statistics) /// - 8 byte - now (timestamp of last statistics)
/// - 4 byte - time (duration of the current connection) /// - 4 byte - time (duration of the current connection)
/// - 4 byte - lastSecond (last second of content viewed) /// - 4 byte - lastSecond (last second of content viewed)
/// - 8 byte - down (Number of bytes received from peer) /// - 8 byte - down (Number of bytes received from peer)
/// - 8 byte - up (Number of bytes sent to peer) /// - 8 byte - up (Number of bytes sent to peer)
/// - 16 byte - host (ip address of the peer) /// - 16 byte - host (ip address of the peer)
/// - 100 byte - streamName (name of the stream peer is viewing) /// - 100 byte - streamName (name of the stream peer is viewing)
/// - 20 byte - connector (name of the connector the peer is using) /// - 20 byte - connector (name of the connector the peer is using)
/// - 4 byte - CRC32 of user agent (or zero if none) /// - 4 byte - CRC32 of user agent (or zero if none)
/// - 1 byte sync (was seen by controller yes/no) /// - 1 byte sync (was seen by controller yes/no)
/// - (implicit 4 bytes: PID) /// - (implicit 4 bytes: PID)
char * data; char *data;
}; };
///\brief A class used for the abstraction of semaphores ///\brief A class used for the abstraction of semaphores
class semaphore { class semaphore{
public: public:
semaphore(); semaphore();
semaphore(const char * name, int oflag, mode_t mode = 0, unsigned int value = 0, bool noWait = false); semaphore(const char *name, int oflag, mode_t mode = 0, unsigned int value = 0, bool noWait = false);
~semaphore(); ~semaphore();
operator bool() const; operator bool() const;
void open(const char * name, int oflag, mode_t mode = 0, unsigned int value = 0, bool noWait = false); void open(const char *name, int oflag, mode_t mode = 0, unsigned int value = 0, bool noWait = false);
int getVal() const; int getVal() const;
void post(); void post();
void wait(); void wait();
bool tryWait(); bool tryWait();
bool tryWaitOneSecond(); bool tryWaitOneSecond();
void close(); void close();
void abandon(); void abandon();
void unlink(); void unlink();
private:
private:
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
///\todo Maybe sometime implement anything else than 777 ///\todo Maybe sometime implement anything else than 777
static SECURITY_ATTRIBUTES getSecurityAttributes(); static SECURITY_ATTRIBUTES getSecurityAttributes();
HANDLE mySem; HANDLE mySem;
#else #else
sem_t * mySem; sem_t *mySem;
#endif #endif
unsigned int isLocked; unsigned int isLocked;
uint64_t lockTime; uint64_t lockTime;
std::string myName; std::string myName;
}; };
///\brief A class used as a semaphore guard ///\brief A class used as a semaphore guard
class semGuard { class semGuard{
public: public:
semGuard(semaphore * thisSemaphore); semGuard(semaphore *thisSemaphore);
~semGuard(); ~semGuard();
private:
///\brief The semaphore to guard. private:
semaphore * mySemaphore; ///\brief The semaphore to guard.
semaphore *mySemaphore;
}; };
///\brief A class for managing shared files. ///\brief A class for managing shared files.
class sharedFile { class sharedFile{
public: public:
sharedFile(const std::string & name_ = "", uint64_t 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(const std::string & name_, uint64_t 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; void close();
} void unmap();
void close(); bool exists();
void unmap(); ///\brief The fd handle of the opened shared file
bool exists(); int handle;
///\brief The fd handle of the opened shared file ///\brief The name of the opened shared file
int handle; std::string name;
///\brief The name of the opened shared file ///\brief The size in bytes of the opened shared file
std::string name; uint64_t len;
///\brief The size in bytes of the opened shared file ///\brief Whether this class should unlink the shared file upon deletion or not
uint64_t len; bool master;
///\brief Whether this class should unlink the shared file upon deletion or not ///\brief A pointer to the payload of the file file
bool master; char *mapped;
///\brief A pointer to the payload of the file file
char * mapped;
}; };
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
@ -135,27 +136,25 @@ namespace IPC {
#ifdef SHM_ENABLED #ifdef SHM_ENABLED
///\brief A class for managing shared memory pages. ///\brief A class for managing shared memory pages.
class sharedPage { class sharedPage{
public: public:
sharedPage(const std::string & name_ = "", uint64_t 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(const std::string & name_, uint64_t 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;
}
void unmap(); void unmap();
void close(); void close();
bool exists(); bool exists();
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
///\brief The handle of the opened shared memory page ///\brief The handle of the opened shared memory page
HANDLE handle; HANDLE handle;
#else #else
///\brief The fd handle of the opened shared memory page ///\brief The fd handle of the opened shared memory page
int handle; int handle;
#endif #endif
///\brief The name of the opened shared memory page ///\brief The name of the opened shared memory page
std::string name; std::string name;
///\brief The size in bytes of the opened shared memory page ///\brief The size in bytes of the opened shared memory page
@ -163,104 +162,108 @@ namespace IPC {
///\brief Whether this class should unlink the shared memory upon deletion or not ///\brief Whether this class should unlink the shared memory upon deletion or not
bool master; bool master;
///\brief A pointer to the payload of the page ///\brief A pointer to the payload of the page
char * mapped; char *mapped;
}; };
#else #else
///\brief A class for handling shared memory pages. ///\brief A class for handling shared memory pages.
///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(const std::string & name_ = "", uint64_t 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();
}; };
#endif #endif
///\brief The server part of a server/client model for shared memory. ///\brief The server part of a server/client model for shared memory.
/// ///
///The server manages the shared memory pages, and allocates new pages when needed. /// The server manages the shared memory pages, and allocates new pages when needed.
/// ///
///Pages are created with a basename + index, where index is in the range of 'A' - 'Z' /// Pages are created with a basename + index, where index is in the range of 'A' - 'Z'
///Each time a page is nearly full, the next page is created with a size double to the previous one. /// Each time a page is nearly full, the next page is created with a size double to the previous one.
/// ///
///Clients should allocate payLen bytes at a time, possibly with the addition of a counter. /// Clients should allocate payLen bytes at a time, possibly with the addition of a counter.
///If no such length can be allocated, the next page should be tried, and so on. /// If no such length can be allocated, the next page should be tried, and so on.
class sharedServer { class sharedServer{
public: public:
sharedServer(); sharedServer();
sharedServer(std::string name, int len, bool withCounter = false); sharedServer(std::string name, int len, bool withCounter = false);
void init(std::string name, int len, bool withCounter = false); void init(std::string name, int len, bool withCounter = false);
~sharedServer(); ~sharedServer();
void parseEach(void (*activeCallback)(char * data, size_t len, unsigned int id), void (*disconCallback)(char * data, size_t len, unsigned int id) = 0); void parseEach(void (*activeCallback)(char *data, size_t len, unsigned int id),
char * getIndex(unsigned int id); void (*disconCallback)(char *data, size_t len, unsigned int id) = 0);
operator bool() const; char *getIndex(unsigned int id);
///\brief The amount of connected clients operator bool() const;
unsigned int amount; ///\brief The amount of connected clients
unsigned int connectedUsers; unsigned int amount;
void finishEach(); unsigned int connectedUsers;
void abandon(); void finishEach();
private: void abandon();
bool isInUse(unsigned int id);
void newPage(); private:
void deletePage(); bool isInUse(unsigned int id);
///\brief The basename of the shared pages. void newPage();
std::string baseName; void deletePage();
///\brief The length of each consecutive piece of payload ///\brief The basename of the shared pages.
unsigned int payLen; std::string baseName;
///\brief The set of sharedPage structures to manage the actual memory ///\brief The length of each consecutive piece of payload
std::deque<sharedPage> myPages; unsigned int payLen;
///\brief A semaphore that is locked upon creation and deletion of the page, to ensure no new data is allocated during this step. ///\brief The set of sharedPage structures to manage the actual memory
semaphore mySemaphore; std::deque<sharedPage> myPages;
///\brief Whether the payload has a counter, if so, it is added in front of the payload ///\brief A semaphore that is locked upon creation and deletion of the page, to ensure no new data is allocated during this step.
bool hasCounter; semaphore mySemaphore;
///\brief Whether the payload has a counter, if so, it is added in front of the payload
bool hasCounter;
}; };
///\brief The client part of a server/client model for shared memory. ///\brief The client part of a server/client model for shared memory.
/// ///
///The server manages the shared memory pages, and allocates new pages when needed. /// The server manages the shared memory pages, and allocates new pages when needed.
/// ///
///Pages are created with a basename + index, where index is in the range of 'A' - 'Z' /// Pages are created with a basename + index, where index is in the range of 'A' - 'Z'
///Each time a page is nearly full, the next page is created with a size double to the previous one. /// Each time a page is nearly full, the next page is created with a size double to the previous one.
/// ///
///Clients should allocate payLen bytes at a time, possibly with the addition of a counter. /// Clients should allocate payLen bytes at a time, possibly with the addition of a counter.
///If no such length can be allocated, the next page should be tried, and so on. /// If no such length can be allocated, the next page should be tried, and so on.
class sharedClient { class sharedClient{
public: public:
sharedClient(); sharedClient();
sharedClient(const sharedClient & rhs); sharedClient(const sharedClient &rhs);
sharedClient(std::string name, int len, bool withCounter = false); sharedClient(std::string name, int len, bool withCounter = false);
void operator = (const sharedClient & rhs); void operator=(const sharedClient &rhs);
~sharedClient(); ~sharedClient();
void write(char * data, int len); void write(char *data, int len);
void finish(); void finish();
void keepAlive(); void keepAlive();
bool isAlive(); bool isAlive();
char * getData(); char *getData();
int getCounter(); int getCounter();
bool countAsViewer; bool countAsViewer;
private:
///\brief The basename of the shared pages. private:
std::string baseName; ///\brief The basename of the shared pages.
///\brief The shared page this client has reserved a space on. std::string baseName;
sharedPage myPage; ///\brief The shared page this client has reserved a space on.
///\brief A semaphore that is locked upon trying to allocate space on a page sharedPage myPage;
semaphore mySemaphore; ///\brief A semaphore that is locked upon trying to allocate space on a page
///\brief The size in bytes of the opened page semaphore mySemaphore;
int payLen; ///\brief The size in bytes of the opened page
///\brief The offset of the payload reserved for this client within the opened page int payLen;
int offsetOnPage; ///\brief The offset of the payload reserved for this client within the opened page
///\brief Whether the payload has a counter, if so, it is added in front of the payload int offsetOnPage;
bool hasCounter; ///\brief Whether the payload has a counter, if so, it is added in front of the payload
bool hasCounter;
}; };
class userConnection { class userConnection{
public: public:
userConnection(char * _data); userConnection(char *_data);
unsigned long getTrackId(size_t offset) const; unsigned long getTrackId(size_t offset) const;
void setTrackId(size_t offset, unsigned long trackId) const; void setTrackId(size_t offset, unsigned long trackId) const;
unsigned long getKeynum(size_t offset) const; unsigned long getKeynum(size_t offset) const;
void setKeynum(size_t offset, unsigned long keynum); void setKeynum(size_t offset, unsigned long keynum);
private:
char * data; private:
char *data;
}; };
} }// namespace IPC

View file

@ -34,7 +34,7 @@ static const char *addrFam(int f){
} }
/// Calls gai_strerror with the given argument, calling regular strerror on the global errno as needed /// Calls gai_strerror with the given argument, calling regular strerror on the global errno as needed
static const char * gai_strmagic(int errcode){ static const char *gai_strmagic(int errcode){
if (errcode == EAI_SYSTEM){ if (errcode == EAI_SYSTEM){
return strerror(errno); return strerror(errno);
}else{ }else{
@ -272,12 +272,10 @@ std::string Socket::resolveHostToBestExternalAddrGuess(const std::string &host,
/// Gets bound host and port for a socket and returns them by reference. /// Gets bound host and port for a socket and returns them by reference.
/// Returns true on success and false on failure. /// Returns true on success and false on failure.
bool Socket::getSocketName(int fd, std::string & host, uint32_t & port){ bool Socket::getSocketName(int fd, std::string &host, uint32_t &port){
struct sockaddr_in6 tmpaddr; struct sockaddr_in6 tmpaddr;
socklen_t len = sizeof(tmpaddr); socklen_t len = sizeof(tmpaddr);
if (getsockname(fd, (sockaddr *)&tmpaddr, &len)){ if (getsockname(fd, (sockaddr *)&tmpaddr, &len)){return false;}
return false;
}
static char addrconv[INET6_ADDRSTRLEN]; static char addrconv[INET6_ADDRSTRLEN];
if (tmpaddr.sin6_family == AF_INET6){ if (tmpaddr.sin6_family == AF_INET6){
host = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN); host = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN);
@ -480,18 +478,18 @@ void Socket::Buffer::clear(){
} }
void Socket::Connection::setBoundAddr(){ void Socket::Connection::setBoundAddr(){
//If a bound address was set through environment (e.g. HTTPS output), restore it from there. // If a bound address was set through environment (e.g. HTTPS output), restore it from there.
char * envbound = getenv("MIST_BOUND_ADDR"); char *envbound = getenv("MIST_BOUND_ADDR");
if (envbound){ if (envbound){
boundaddr = envbound; boundaddr = envbound;
return; return;
} }
//If we can't read the address, don't try // If we can't read the address, don't try
if (!isTrueSocket){ if (!isTrueSocket){
boundaddr = ""; boundaddr = "";
return; return;
} }
//Otherwise, read from socket pointer. Works for both SSL and non-SSL sockets, and real sockets passed as fd's, but not for non-sockets (duh) // Otherwise, read from socket pointer. Works for both SSL and non-SSL sockets, and real sockets passed as fd's, but not for non-sockets (duh)
uint32_t boundport = 0; uint32_t boundport = 0;
getSocketName(getSocket(), boundaddr, boundport); getSocketName(getSocket(), boundaddr, boundport);
} }
@ -1184,9 +1182,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){memcpy(&remoteaddr, result->ai_addr, result->ai_addrlen);}
memcpy(&remoteaddr, result->ai_addr, result->ai_addrlen);
}
freeaddrinfo(result); freeaddrinfo(result);
} }

View file

@ -44,7 +44,7 @@ namespace Socket{
bool checkTrueSocket(int sock); bool checkTrueSocket(int sock);
std::string resolveHostToBestExternalAddrGuess(const std::string &host, int family = AF_UNSPEC, std::string resolveHostToBestExternalAddrGuess(const std::string &host, int family = AF_UNSPEC,
const std::string &hint = ""); const std::string &hint = "");
bool getSocketName(int fd, std::string & host, uint32_t & port); bool getSocketName(int fd, std::string &host, uint32_t &port);
/// A buffer made out of std::string objects that can be efficiently read from and written to. /// A buffer made out of std::string objects that can be efficiently read from and written to.
class Buffer{ class Buffer{
@ -91,6 +91,7 @@ namespace Socket{
bool iread(Buffer &buffer, int flags = 0); ///< Incremental write call that is compatible with Socket::Buffer. bool iread(Buffer &buffer, int flags = 0); ///< Incremental write call that is compatible with Socket::Buffer.
bool iwrite(std::string &buffer); ///< Write call that is compatible with std::string. bool iwrite(std::string &buffer); ///< Write call that is compatible with std::string.
void setBoundAddr(); void setBoundAddr();
protected: protected:
std::string lastErr; ///< Stores last error, if any. std::string lastErr; ///< Stores last error, if any.
#ifdef SSL #ifdef SSL
@ -139,10 +140,10 @@ namespace Socket{
bool isAddress(const std::string &addr); bool isAddress(const std::string &addr);
bool isLocal(); ///< Returns true if remote address is a local address. bool isLocal(); ///< Returns true if remote address is a local address.
// buffered i/o methods // buffered i/o methods
bool spool(); ///< Updates the downbufferinternal variables. bool spool(); ///< Updates the downbufferinternal variables.
bool peek(); ///< Clears the downbuffer and fills it with peek bool peek(); ///< Clears the downbuffer and fills it with peek
Buffer &Received(); ///< Returns a reference to the download buffer. Buffer &Received(); ///< Returns a reference to the download buffer.
const Buffer &Received() const; ///< Returns a reference to the download buffer. const Buffer &Received() const; ///< Returns a reference to the download buffer.
void SendNow(const std::string &data); ///< Will not buffer anything but always send right away. Blocks. void SendNow(const std::string &data); ///< Will not buffer anything but always send right away. Blocks.
void SendNow(const char *data); ///< Will not buffer anything but always send right away. Blocks. void SendNow(const char *data); ///< Will not buffer anything but always send right away. Blocks.
void SendNow(const char *data, void SendNow(const char *data,

View file

@ -1,6 +1,6 @@
#include <algorithm>
#include "defines.h" #include "defines.h"
#include "srtp.h" #include "srtp.h"
#include <algorithm>
/* --------------------------------------- */ /* --------------------------------------- */
@ -8,34 +8,34 @@ static std::string srtp_status_to_string(uint32_t status);
/* --------------------------------------- */ /* --------------------------------------- */
SRTPReader::SRTPReader() { SRTPReader::SRTPReader(){
memset((void*)&session, 0x00, sizeof(session)); memset((void *)&session, 0x00, sizeof(session));
memset((void*)&policy, 0x00, sizeof(policy)); memset((void *)&policy, 0x00, sizeof(policy));
} }
/* /*
Before initializing the srtp library we shut it down first Before initializing the srtp library we shut it down first
because initializing the library twice results in an error. because initializing the library twice results in an error.
*/ */
int SRTPReader::init(const std::string& cipher, const std::string& key, const std::string& salt) { int SRTPReader::init(const std::string &cipher, const std::string &key, const std::string &salt){
int r = 0; int r = 0;
srtp_err_status_t status = srtp_err_status_ok; srtp_err_status_t status = srtp_err_status_ok;
srtp_profile_t profile; srtp_profile_t profile;
memset((void*) &profile, 0x00, sizeof(profile)); memset((void *)&profile, 0x00, sizeof(profile));
/* validate input */ /* validate input */
if (cipher.empty()) { if (cipher.empty()){
FAIL_MSG("Given `cipher` is empty."); FAIL_MSG("Given `cipher` is empty.");
r = -1; r = -1;
goto error; goto error;
} }
if (key.empty()) { if (key.empty()){
FAIL_MSG("Given `key` is empty."); FAIL_MSG("Given `key` is empty.");
r = -2; r = -2;
goto error; goto error;
} }
if (salt.empty()) { if (salt.empty()){
FAIL_MSG("Given `salt` is empty."); FAIL_MSG("Given `salt` is empty.");
r = -3; r = -3;
goto error; goto error;
@ -43,27 +43,25 @@ int SRTPReader::init(const std::string& cipher, const std::string& key, const st
/* re-initialize the srtp library. */ /* re-initialize the srtp library. */
status = srtp_shutdown(); status = srtp_shutdown();
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to shutdown the srtp lib %s", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to shutdown the srtp lib %s", srtp_status_to_string(status).c_str());
r = -1; r = -1;
goto error; goto error;
} }
status = srtp_init(); status = srtp_init();
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to initialize the SRTP library. %s", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to initialize the SRTP library. %s", srtp_status_to_string(status).c_str());
r = -2; r = -2;
goto error; goto error;
} }
/* select the right profile from exchanged cipher */ /* select the right profile from exchanged cipher */
if ("SRTP_AES128_CM_SHA1_80" == cipher) { if ("SRTP_AES128_CM_SHA1_80" == cipher){
profile = srtp_profile_aes128_cm_sha1_80; profile = srtp_profile_aes128_cm_sha1_80;
} }else if ("SRTP_AES128_CM_SHA1_32" == cipher){
else if ("SRTP_AES128_CM_SHA1_32" == cipher) {
profile = srtp_profile_aes128_cm_sha1_32; profile = srtp_profile_aes128_cm_sha1_32;
} }else{
else {
ERROR_MSG("Unsupported SRTP cipher used: %s.", cipher.c_str()); ERROR_MSG("Unsupported SRTP cipher used: %s.", cipher.c_str());
r = -2; r = -2;
goto error; goto error;
@ -71,14 +69,14 @@ int SRTPReader::init(const std::string& cipher, const std::string& key, const st
/* set the crypto policy using the profile. */ /* set the crypto policy using the profile. */
status = srtp_crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile); status = srtp_crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to set the crypto policy for RTP for cipher %s.", cipher.c_str()); ERROR_MSG("Failed to set the crypto policy for RTP for cipher %s.", cipher.c_str());
r = -3; r = -3;
goto error; goto error;
} }
status = srtp_crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile); status = srtp_crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to set the crypto policy for RTCP for cipher %s.", cipher.c_str()); ERROR_MSG("Failed to set the crypto policy for RTCP for cipher %s.", cipher.c_str());
r = -4; r = -4;
goto error; goto error;
@ -87,7 +85,7 @@ int SRTPReader::init(const std::string& cipher, const std::string& key, const st
/* set the keying material. */ /* set the keying material. */
std::copy(key.begin(), key.end(), std::back_inserter(key_salt)); std::copy(key.begin(), key.end(), std::back_inserter(key_salt));
std::copy(salt.begin(), salt.end(), std::back_inserter(key_salt)); std::copy(salt.begin(), salt.end(), std::back_inserter(key_salt));
policy.key = (unsigned char*)&key_salt[0]; policy.key = (unsigned char *)&key_salt[0];
/* only unprotecting data for now, so using inbound; and some other settings. */ /* only unprotecting data for now, so using inbound; and some other settings. */
policy.ssrc.type = ssrc_any_inbound; policy.ssrc.type = ssrc_any_inbound;
@ -96,62 +94,61 @@ int SRTPReader::init(const std::string& cipher, const std::string& key, const st
/* create the srtp session. */ /* create the srtp session. */
status = srtp_create(&session, &policy); status = srtp_create(&session, &policy);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to initialize our SRTP session. Status: %s. ", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to initialize our SRTP session. Status: %s. ", srtp_status_to_string(status).c_str());
r = -3; r = -3;
goto error; goto error;
} }
error: error:
if (r < 0) { if (r < 0){shutdown();}
shutdown();
}
return r; return r;
} }
int SRTPReader::shutdown() { int SRTPReader::shutdown(){
int r = 0; int r = 0;
srtp_err_status_t status = srtp_dealloc(session); srtp_err_status_t status = srtp_dealloc(session);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s",
srtp_status_to_string(status).c_str());
r -= 5; r -= 5;
} }
memset((void*)&policy, 0x00, sizeof(policy)); memset((void *)&policy, 0x00, sizeof(policy));
memset((char*)&session, 0x00, sizeof(session)); memset((char *)&session, 0x00, sizeof(session));
return r; return r;
} }
/* --------------------------------------- */ /* --------------------------------------- */
int SRTPReader::unprotectRtp(uint8_t* data, int* nbytes) { int SRTPReader::unprotectRtp(uint8_t *data, int *nbytes){
if (NULL == data) { if (NULL == data){
ERROR_MSG("Cannot unprotect the given SRTP, because data is NULL."); ERROR_MSG("Cannot unprotect the given SRTP, because data is NULL.");
return -1; return -1;
} }
if (NULL == nbytes) { if (NULL == nbytes){
ERROR_MSG("Cannot unprotect the given SRTP, becuase nbytes is NULL."); ERROR_MSG("Cannot unprotect the given SRTP, becuase nbytes is NULL.");
return -2; return -2;
} }
if (0 == (*nbytes)) { if (0 == (*nbytes)){
ERROR_MSG("Cannot unprotect the given SRTP, because nbytes is 0."); ERROR_MSG("Cannot unprotect the given SRTP, because nbytes is 0.");
return -3; return -3;
} }
if (NULL == policy.key) { if (NULL == policy.key){
ERROR_MSG("Cannot unprotect the SRTP packet, it seems we're not initialized."); ERROR_MSG("Cannot unprotect the SRTP packet, it seems we're not initialized.");
return -4; return -4;
} }
srtp_err_status_t status = srtp_unprotect(session, data, nbytes); srtp_err_status_t status = srtp_unprotect(session, data, nbytes);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to unprotect the given SRTP. %s.", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to unprotect the given SRTP. %s.", srtp_status_to_string(status).c_str());
return -5; return -5;
} }
@ -161,30 +158,30 @@ int SRTPReader::unprotectRtp(uint8_t* data, int* nbytes) {
return 0; return 0;
} }
int SRTPReader::unprotectRtcp(uint8_t* data, int* nbytes) { int SRTPReader::unprotectRtcp(uint8_t *data, int *nbytes){
if (NULL == data) { if (NULL == data){
ERROR_MSG("Cannot unprotect the given SRTCP, because data is NULL."); ERROR_MSG("Cannot unprotect the given SRTCP, because data is NULL.");
return -1; return -1;
} }
if (NULL == nbytes) { if (NULL == nbytes){
ERROR_MSG("Cannot unprotect the given SRTCP, becuase nbytes is NULL."); ERROR_MSG("Cannot unprotect the given SRTCP, becuase nbytes is NULL.");
return -2; return -2;
} }
if (0 == (*nbytes)) { if (0 == (*nbytes)){
ERROR_MSG("Cannot unprotect the given SRTCP, because nbytes is 0."); ERROR_MSG("Cannot unprotect the given SRTCP, because nbytes is 0.");
return -3; return -3;
} }
if (NULL == policy.key) { if (NULL == policy.key){
ERROR_MSG("Cannot unprotect the SRTCP packet, it seems we're not initialized."); ERROR_MSG("Cannot unprotect the SRTCP packet, it seems we're not initialized.");
return -4; return -4;
} }
srtp_err_status_t status = srtp_unprotect_rtcp(session, data, nbytes); srtp_err_status_t status = srtp_unprotect_rtcp(session, data, nbytes);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to unprotect the given SRTCP. %s.", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to unprotect the given SRTCP. %s.", srtp_status_to_string(status).c_str());
return -5; return -5;
} }
@ -194,34 +191,34 @@ int SRTPReader::unprotectRtcp(uint8_t* data, int* nbytes) {
/* --------------------------------------- */ /* --------------------------------------- */
SRTPWriter::SRTPWriter() { SRTPWriter::SRTPWriter(){
memset((void*)&session, 0x00, sizeof(session)); memset((void *)&session, 0x00, sizeof(session));
memset((void*)&policy, 0x00, sizeof(policy)); memset((void *)&policy, 0x00, sizeof(policy));
} }
/* /*
Before initializing the srtp library we shut it down first Before initializing the srtp library we shut it down first
because initializing the library twice results in an error. because initializing the library twice results in an error.
*/ */
int SRTPWriter::init(const std::string& cipher, const std::string& key, const std::string& salt) { int SRTPWriter::init(const std::string &cipher, const std::string &key, const std::string &salt){
int r = 0; int r = 0;
srtp_err_status_t status = srtp_err_status_ok; srtp_err_status_t status = srtp_err_status_ok;
srtp_profile_t profile; srtp_profile_t profile;
memset((void*)&profile, 0x00, sizeof(profile)); memset((void *)&profile, 0x00, sizeof(profile));
/* validate input */ /* validate input */
if (cipher.empty()) { if (cipher.empty()){
FAIL_MSG("Given `cipher` is empty."); FAIL_MSG("Given `cipher` is empty.");
r = -1; r = -1;
goto error; goto error;
} }
if (key.empty()) { if (key.empty()){
FAIL_MSG("Given `key` is empty."); FAIL_MSG("Given `key` is empty.");
r = -2; r = -2;
goto error; goto error;
} }
if (salt.empty()) { if (salt.empty()){
FAIL_MSG("Given `salt` is empty."); FAIL_MSG("Given `salt` is empty.");
r = -3; r = -3;
goto error; goto error;
@ -229,27 +226,25 @@ int SRTPWriter::init(const std::string& cipher, const std::string& key, const st
/* re-initialize the srtp library. */ /* re-initialize the srtp library. */
status = srtp_shutdown(); status = srtp_shutdown();
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to shutdown the srtp lib %s", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to shutdown the srtp lib %s", srtp_status_to_string(status).c_str());
r = -1; r = -1;
goto error; goto error;
} }
status = srtp_init(); status = srtp_init();
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to initialize the SRTP library. %s", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to initialize the SRTP library. %s", srtp_status_to_string(status).c_str());
r = -2; r = -2;
goto error; goto error;
} }
/* select the exchanged cipher */ /* select the exchanged cipher */
if ("SRTP_AES128_CM_SHA1_80" == cipher) { if ("SRTP_AES128_CM_SHA1_80" == cipher){
profile = srtp_profile_aes128_cm_sha1_80; profile = srtp_profile_aes128_cm_sha1_80;
} }else if ("SRTP_AES128_CM_SHA1_32" == cipher){
else if ("SRTP_AES128_CM_SHA1_32" == cipher) {
profile = srtp_profile_aes128_cm_sha1_32; profile = srtp_profile_aes128_cm_sha1_32;
} }else{
else {
ERROR_MSG("Unsupported SRTP cipher used: %s.", cipher.c_str()); ERROR_MSG("Unsupported SRTP cipher used: %s.", cipher.c_str());
r = -2; r = -2;
goto error; goto error;
@ -257,14 +252,14 @@ int SRTPWriter::init(const std::string& cipher, const std::string& key, const st
/* set the crypto policy using the profile. */ /* set the crypto policy using the profile. */
status = srtp_crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile); status = srtp_crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to set the crypto policy for RTP for cipher %s.", cipher.c_str()); ERROR_MSG("Failed to set the crypto policy for RTP for cipher %s.", cipher.c_str());
r = -3; r = -3;
goto error; goto error;
} }
status = srtp_crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile); status = srtp_crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to set the crypto policy for RTCP for cipher %s.", cipher.c_str()); ERROR_MSG("Failed to set the crypto policy for RTCP for cipher %s.", cipher.c_str());
r = -4; r = -4;
goto error; goto error;
@ -273,7 +268,7 @@ int SRTPWriter::init(const std::string& cipher, const std::string& key, const st
/* set the keying material. */ /* set the keying material. */
std::copy(key.begin(), key.end(), std::back_inserter(key_salt)); std::copy(key.begin(), key.end(), std::back_inserter(key_salt));
std::copy(salt.begin(), salt.end(), std::back_inserter(key_salt)); std::copy(salt.begin(), salt.end(), std::back_inserter(key_salt));
policy.key = (unsigned char*)&key_salt[0]; policy.key = (unsigned char *)&key_salt[0];
/* only unprotecting data for now, so using inbound; and some other settings. */ /* only unprotecting data for now, so using inbound; and some other settings. */
policy.ssrc.type = ssrc_any_outbound; policy.ssrc.type = ssrc_any_outbound;
@ -282,62 +277,61 @@ int SRTPWriter::init(const std::string& cipher, const std::string& key, const st
/* create the srtp session. */ /* create the srtp session. */
status = srtp_create(&session, &policy); status = srtp_create(&session, &policy);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to initialize our SRTP session. Status: %s. ", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to initialize our SRTP session. Status: %s. ", srtp_status_to_string(status).c_str());
r = -3; r = -3;
goto error; goto error;
} }
error: error:
if (r < 0) { if (r < 0){shutdown();}
shutdown();
}
return r; return r;
} }
int SRTPWriter::shutdown() { int SRTPWriter::shutdown(){
int r = 0; int r = 0;
srtp_err_status_t status = srtp_dealloc(session); srtp_err_status_t status = srtp_dealloc(session);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s",
srtp_status_to_string(status).c_str());
r -= 5; r -= 5;
} }
memset((char*)&policy, 0x00, sizeof(policy)); memset((char *)&policy, 0x00, sizeof(policy));
memset((char*)&session, 0x00, sizeof(session)); memset((char *)&session, 0x00, sizeof(session));
return r; return r;
} }
/* --------------------------------------- */ /* --------------------------------------- */
int SRTPWriter::protectRtp(uint8_t* data, int* nbytes) { int SRTPWriter::protectRtp(uint8_t *data, int *nbytes){
if (NULL == data) { if (NULL == data){
ERROR_MSG("Cannot protect the RTP packet because given data is NULL."); ERROR_MSG("Cannot protect the RTP packet because given data is NULL.");
return -1; return -1;
} }
if (NULL == nbytes) { if (NULL == nbytes){
ERROR_MSG("Cannot protect the RTP packet because the given nbytes is NULL."); ERROR_MSG("Cannot protect the RTP packet because the given nbytes is NULL.");
return -2; return -2;
} }
if ((*nbytes) <= 0) { if ((*nbytes) <= 0){
ERROR_MSG("Cannot protect the RTP packet because the given nbytes has a value <= 0."); ERROR_MSG("Cannot protect the RTP packet because the given nbytes has a value <= 0.");
return -3; return -3;
} }
if (NULL == policy.key) { if (NULL == policy.key){
ERROR_MSG("Cannot protect the RTP packet because we're not initialized."); ERROR_MSG("Cannot protect the RTP packet because we're not initialized.");
return -4; return -4;
} }
srtp_err_status_t status = srtp_protect(session, (void*)data, nbytes); srtp_err_status_t status = srtp_protect(session, (void *)data, nbytes);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to protect the RTP packet. %s.", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to protect the RTP packet. %s.", srtp_status_to_string(status).c_str());
return -5; return -5;
} }
@ -350,30 +344,30 @@ int SRTPWriter::protectRtp(uint8_t* data, int* nbytes) {
of bytes at the into which libsrtp can write the of bytes at the into which libsrtp can write the
authentication tag authentication tag
*/ */
int SRTPWriter::protectRtcp(uint8_t* data, int* nbytes) { int SRTPWriter::protectRtcp(uint8_t *data, int *nbytes){
if (NULL == data) { if (NULL == data){
ERROR_MSG("Cannot protect the RTCP packet because given data is NULL."); ERROR_MSG("Cannot protect the RTCP packet because given data is NULL.");
return -1; return -1;
} }
if (NULL == nbytes) { if (NULL == nbytes){
ERROR_MSG("Cannot protect the RTCP packet because nbytes is NULL."); ERROR_MSG("Cannot protect the RTCP packet because nbytes is NULL.");
return -2; return -2;
} }
if ((*nbytes) <= 0) { if ((*nbytes) <= 0){
ERROR_MSG("Cannot protect the RTCP packet because *nbytes is <= 0."); ERROR_MSG("Cannot protect the RTCP packet because *nbytes is <= 0.");
return -3; return -3;
} }
if (NULL == policy.key) { if (NULL == policy.key){
ERROR_MSG("Not initialized cannot protect the RTCP packet."); ERROR_MSG("Not initialized cannot protect the RTCP packet.");
return -4; return -4;
} }
srtp_err_status_t status = srtp_protect_rtcp(session, (void*)data, nbytes); srtp_err_status_t status = srtp_protect_rtcp(session, (void *)data, nbytes);
if (srtp_err_status_ok != status) { if (srtp_err_status_ok != status){
ERROR_MSG("Failed to protect the RTCP packet. %s.", srtp_status_to_string(status).c_str()); ERROR_MSG("Failed to protect the RTCP packet. %s.", srtp_status_to_string(status).c_str());
return -3; return -3;
} }
@ -381,41 +375,98 @@ int SRTPWriter::protectRtcp(uint8_t* data, int* nbytes) {
return 0; return 0;
} }
/* --------------------------------------- */ /* --------------------------------------- */
static std::string srtp_status_to_string(uint32_t status) { static std::string srtp_status_to_string(uint32_t status){
switch (status) { switch (status){
case srtp_err_status_ok: { return "srtp_err_status_ok"; } case srtp_err_status_ok:{
case srtp_err_status_fail: { return "srtp_err_status_fail"; } return "srtp_err_status_ok";
case srtp_err_status_bad_param: { return "srtp_err_status_bad_param"; } }
case srtp_err_status_alloc_fail: { return "srtp_err_status_alloc_fail"; } case srtp_err_status_fail:{
case srtp_err_status_dealloc_fail: { return "srtp_err_status_dealloc_fail"; } return "srtp_err_status_fail";
case srtp_err_status_init_fail: { return "srtp_err_status_init_fail"; } }
case srtp_err_status_terminus: { return "srtp_err_status_terminus"; } case srtp_err_status_bad_param:{
case srtp_err_status_auth_fail: { return "srtp_err_status_auth_fail"; } return "srtp_err_status_bad_param";
case srtp_err_status_cipher_fail: { return "srtp_err_status_cipher_fail"; } }
case srtp_err_status_replay_fail: { return "srtp_err_status_replay_fail"; } case srtp_err_status_alloc_fail:{
case srtp_err_status_replay_old: { return "srtp_err_status_replay_old"; } return "srtp_err_status_alloc_fail";
case srtp_err_status_algo_fail: { return "srtp_err_status_algo_fail"; } }
case srtp_err_status_no_such_op: { return "srtp_err_status_no_such_op"; } case srtp_err_status_dealloc_fail:{
case srtp_err_status_no_ctx: { return "srtp_err_status_no_ctx"; } return "srtp_err_status_dealloc_fail";
case srtp_err_status_cant_check: { return "srtp_err_status_cant_check"; } }
case srtp_err_status_key_expired: { return "srtp_err_status_key_expired"; } case srtp_err_status_init_fail:{
case srtp_err_status_socket_err: { return "srtp_err_status_socket_err"; } return "srtp_err_status_init_fail";
case srtp_err_status_signal_err: { return "srtp_err_status_signal_err"; } }
case srtp_err_status_nonce_bad: { return "srtp_err_status_nonce_bad"; } case srtp_err_status_terminus:{
case srtp_err_status_read_fail: { return "srtp_err_status_read_fail"; } return "srtp_err_status_terminus";
case srtp_err_status_write_fail: { return "srtp_err_status_write_fail"; } }
case srtp_err_status_parse_err: { return "srtp_err_status_parse_err"; } case srtp_err_status_auth_fail:{
case srtp_err_status_encode_err: { return "srtp_err_status_encode_err"; } return "srtp_err_status_auth_fail";
case srtp_err_status_semaphore_err: { return "srtp_err_status_semaphore_err"; } }
case srtp_err_status_pfkey_err: { return "srtp_err_status_pfkey_err"; } case srtp_err_status_cipher_fail:{
case srtp_err_status_bad_mki: { return "srtp_err_status_bad_mki"; } return "srtp_err_status_cipher_fail";
case srtp_err_status_pkt_idx_old: { return "srtp_err_status_pkt_idx_old"; } }
case srtp_err_status_pkt_idx_adv: { return "srtp_err_status_pkt_idx_adv"; } case srtp_err_status_replay_fail:{
default: { return "UNKNOWN"; } return "srtp_err_status_replay_fail";
}
case srtp_err_status_replay_old:{
return "srtp_err_status_replay_old";
}
case srtp_err_status_algo_fail:{
return "srtp_err_status_algo_fail";
}
case srtp_err_status_no_such_op:{
return "srtp_err_status_no_such_op";
}
case srtp_err_status_no_ctx:{
return "srtp_err_status_no_ctx";
}
case srtp_err_status_cant_check:{
return "srtp_err_status_cant_check";
}
case srtp_err_status_key_expired:{
return "srtp_err_status_key_expired";
}
case srtp_err_status_socket_err:{
return "srtp_err_status_socket_err";
}
case srtp_err_status_signal_err:{
return "srtp_err_status_signal_err";
}
case srtp_err_status_nonce_bad:{
return "srtp_err_status_nonce_bad";
}
case srtp_err_status_read_fail:{
return "srtp_err_status_read_fail";
}
case srtp_err_status_write_fail:{
return "srtp_err_status_write_fail";
}
case srtp_err_status_parse_err:{
return "srtp_err_status_parse_err";
}
case srtp_err_status_encode_err:{
return "srtp_err_status_encode_err";
}
case srtp_err_status_semaphore_err:{
return "srtp_err_status_semaphore_err";
}
case srtp_err_status_pfkey_err:{
return "srtp_err_status_pfkey_err";
}
case srtp_err_status_bad_mki:{
return "srtp_err_status_bad_mki";
}
case srtp_err_status_pkt_idx_old:{
return "srtp_err_status_pkt_idx_old";
}
case srtp_err_status_pkt_idx_adv:{
return "srtp_err_status_pkt_idx_adv";
}
default:{
return "UNKNOWN";
}
} }
} }

View file

@ -1,22 +1,22 @@
#pragma once #pragma once
#include <srtp2/srtp.h>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <srtp2/srtp.h>
#define SRTP_PARSER_MASTER_KEY_LEN 16 #define SRTP_PARSER_MASTER_KEY_LEN 16
#define SRTP_PARSER_MASTER_SALT_LEN 14 #define SRTP_PARSER_MASTER_SALT_LEN 14
#define SRTP_PARSER_MASTER_LEN (SRTP_PARSER_MASTER_KEY_LEN + SRTP_PARSER_MASTER_SALT_LEN) #define SRTP_PARSER_MASTER_LEN (SRTP_PARSER_MASTER_KEY_LEN + SRTP_PARSER_MASTER_SALT_LEN)
/* --------------------------------------- */ /* --------------------------------------- */
class SRTPReader { class SRTPReader{
public: public:
SRTPReader(); SRTPReader();
int init(const std::string& cipher, const std::string& key, const std::string& salt); int init(const std::string &cipher, const std::string &key, const std::string &salt);
int shutdown(); int shutdown();
int unprotectRtp(uint8_t* data, int* nbytes); /* `nbytes` should contain the number of bytes in `data`. On success `nbytes` will hold the number of bytes of the decoded RTP packet. */ int unprotectRtp(uint8_t *data, int *nbytes); /* `nbytes` should contain the number of bytes in `data`. On success `nbytes` will hold the number of bytes of the decoded RTP packet. */
int unprotectRtcp(uint8_t* data, int* nbytes); /* `nbytes` should contains the number of bytes in `data`. On success `nbytes` will hold the number of bytes the decoded RTCP packet. */ int unprotectRtcp(uint8_t *data, int *nbytes); /* `nbytes` should contains the number of bytes in `data`. On success `nbytes` will hold the number of bytes the decoded RTCP packet. */
private: private:
srtp_t session; srtp_t session;
@ -26,13 +26,13 @@ private:
/* --------------------------------------- */ /* --------------------------------------- */
class SRTPWriter { class SRTPWriter{
public: public:
SRTPWriter(); SRTPWriter();
int init(const std::string& cipher, const std::string& key, const std::string& salt); int init(const std::string &cipher, const std::string &key, const std::string &salt);
int shutdown(); int shutdown();
int protectRtp(uint8_t* data, int* nbytes); int protectRtp(uint8_t *data, int *nbytes);
int protectRtcp(uint8_t* data, int* nbytes); int protectRtcp(uint8_t *data, int *nbytes);
private: private:
srtp_t session; srtp_t session;

View file

@ -1,19 +1,19 @@
/// \file stream.cpp /// \file stream.cpp
/// Utilities for handling streams. /// Utilities for handling streams.
#include "stream.h"
#include "config.h" #include "config.h"
#include "defines.h" #include "defines.h"
#include "dtsc.h" #include "dtsc.h"
#include "h265.h"
#include "http_parser.h"
#include "json.h" #include "json.h"
#include "langcodes.h"
#include "mp4_generic.h"
#include "procs.h" #include "procs.h"
#include "shared_memory.h" #include "shared_memory.h"
#include "socket.h" #include "socket.h"
#include "stream.h"
#include "triggers.h" //LTS #include "triggers.h" //LTS
#include "h265.h"
#include "mp4_generic.h"
#include "langcodes.h"
#include "http_parser.h"
#include <semaphore.h> #include <semaphore.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -41,7 +41,7 @@ static void replace(std::string &str, const std::string &from, const std::string
} }
} }
std::string Util::codecString(const std::string & codec, const std::string & initData){ std::string Util::codecString(const std::string &codec, const std::string &initData){
if (codec == "H264"){ if (codec == "H264"){
std::stringstream r; std::stringstream r;
MP4::AVCC avccBox; MP4::AVCC avccBox;
@ -58,10 +58,10 @@ std::string Util::codecString(const std::string & codec, const std::string & ini
std::stringstream r; std::stringstream r;
r << "hev1."; r << "hev1.";
switch (mInfo.general_profile_space){ switch (mInfo.general_profile_space){
case 0: break; case 0: break;
case 1: r << 'A'; break; case 1: r << 'A'; break;
case 2: r << 'B'; break; case 2: r << 'B'; break;
case 3: r << 'C'; break; case 3: r << 'C'; break;
} }
r << (unsigned long)mInfo.general_profile_idc << '.'; r << (unsigned long)mInfo.general_profile_idc << '.';
uint32_t mappedFlags = 0; uint32_t mappedFlags = 0;
@ -98,7 +98,11 @@ std::string Util::codecString(const std::string & codec, const std::string & ini
if (mInfo.general_profile_compatflags & 0x40000000ul){mappedFlags += 0x00000002ul;} if (mInfo.general_profile_compatflags & 0x40000000ul){mappedFlags += 0x00000002ul;}
if (mInfo.general_profile_compatflags & 0x80000000ul){mappedFlags += 0x00000001ul;} if (mInfo.general_profile_compatflags & 0x80000000ul){mappedFlags += 0x00000001ul;}
r << std::hex << (unsigned long)mappedFlags << std::dec << '.'; r << std::hex << (unsigned long)mappedFlags << std::dec << '.';
if (mInfo.general_tier_flag){r << 'H';}else{r << 'L';} if (mInfo.general_tier_flag){
r << 'H';
}else{
r << 'L';
}
r << (unsigned long)mInfo.general_level_idc; r << (unsigned long)mInfo.general_level_idc;
if (mInfo.constraint_flags[0]){ if (mInfo.constraint_flags[0]){
r << '.' << std::hex << (unsigned long)mInfo.constraint_flags[0] << std::dec; r << '.' << std::hex << (unsigned long)mInfo.constraint_flags[0] << std::dec;
@ -112,8 +116,7 @@ std::string Util::codecString(const std::string & codec, const std::string & ini
} }
/// 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, void Util::streamVariables(std::string &str, const std::string &streamname, const std::string &source){
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"));
@ -122,9 +125,9 @@ void Util::streamVariables(std::string &str, const std::string &streamname,
replace(str, "$hour", strftime_now("%H")); replace(str, "$hour", strftime_now("%H"));
replace(str, "$minute", strftime_now("%M")); replace(str, "$minute", strftime_now("%M"));
replace(str, "$second", strftime_now("%S")); replace(str, "$second", strftime_now("%S"));
replace(str, "$wday", strftime_now("%u"));//weekday, 1-7, monday=1 replace(str, "$wday", strftime_now("%u")); // weekday, 1-7, monday=1
replace(str, "$yday", strftime_now("%j"));//yearday, 001-366 replace(str, "$yday", strftime_now("%j")); // yearday, 001-366
replace(str, "$week", strftime_now("%V"));//week number, 01-53 replace(str, "$week", strftime_now("%V")); // week number, 01-53
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('+'));
@ -213,7 +216,9 @@ JSON::Value Util::getStreamConfig(const std::string &streamname){
if (!Util::getGlobalConfig("defaultStream")){ if (!Util::getGlobalConfig("defaultStream")){
WARN_MSG("Could not get stream '%s' config!", smp.c_str()); WARN_MSG("Could not get stream '%s' config!", smp.c_str());
}else{ }else{
INFO_MSG("Could not get stream '%s' config, not emitting WARN message because fallback is configured", smp.c_str()); INFO_MSG("Could not get stream '%s' config, not emitting WARN message because fallback is "
"configured",
smp.c_str());
} }
return result; return result;
} }
@ -233,18 +238,18 @@ JSON::Value Util::getGlobalConfig(const std::string &optionName){
} }
Util::RelAccXFieldData dataField = cfgData.getFieldData(optionName); Util::RelAccXFieldData dataField = cfgData.getFieldData(optionName);
switch (dataField.type & 0xF0){ switch (dataField.type & 0xF0){
case RAX_INT: case RAX_INT:
case RAX_UINT: case RAX_UINT:
//Integer types, return JSON::Value integer // Integer types, return JSON::Value integer
return JSON::Value(cfgData.getInt(dataField)); return JSON::Value(cfgData.getInt(dataField));
case RAX_RAW: case RAX_RAW:
case RAX_STRING: case RAX_STRING:
//String types, return JSON::Value string // String types, return JSON::Value string
return JSON::Value(std::string(cfgData.getPointer(dataField), cfgData.getSize(optionName))); return JSON::Value(std::string(cfgData.getPointer(dataField), cfgData.getSize(optionName)));
default: default:
//Unimplemented types // Unimplemented types
FAIL_MSG("Global configuration setting for '%s' is not an implemented datatype!", optionName.c_str()); FAIL_MSG("Global configuration setting for '%s' is not an implemented datatype!", optionName.c_str());
return JSON::Value(); return JSON::Value();
} }
} }
@ -447,7 +452,8 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
} }
if (pid == 0){ if (pid == 0){
for (std::set<int>::iterator it = Util::Procs::socketList.begin(); it != Util::Procs::socketList.end(); ++it){ for (std::set<int>::iterator it = Util::Procs::socketList.begin();
it != Util::Procs::socketList.end(); ++it){
close(*it); close(*it);
} }
Socket::Connection io(0, 1); Socket::Connection io(0, 1);
@ -511,8 +517,7 @@ JSON::Value Util::getInputBySource(const std::string &filename, bool isProvider)
MEDIUM_MSG("Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(), MEDIUM_MSG("Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(),
tmp_input.getMember("name").asString().c_str(), source.c_str()); tmp_input.getMember("name").asString().c_str(), source.c_str());
if (tmpFn.substr(0, front.size()) == front && if (tmpFn.substr(0, front.size()) == front && tmpFn.substr(tmpFn.size() - back.size()) == back){
tmpFn.substr(tmpFn.size() - back.size()) == back){
if (tmp_input.getMember("non-provider") && !isProvider){ if (tmp_input.getMember("non-provider") && !isProvider){
noProviderNoPick = true; noProviderNoPick = true;
continue; continue;
@ -569,7 +574,7 @@ pid_t Util::startPush(const std::string &streamname, std::string &target){
return 0; return 0;
} }
//Set original target string in environment // Set original target string in environment
setenv("MST_ORIG_TARGET", target.c_str(), 1); setenv("MST_ORIG_TARGET", target.c_str(), 1);
// The target can hold variables like current time etc // The target can hold variables like current time etc
@ -617,11 +622,11 @@ pid_t Util::startPush(const std::string &streamname, std::string &target){
(char *)target.c_str(), (char *)NULL}; (char *)target.c_str(), (char *)NULL};
int stdErr = 2; int stdErr = 2;
//Cache return value so we can do some cleaning before we return // Cache return value so we can do some cleaning before we return
pid_t ret = Util::Procs::StartPiped(argv, 0, 0, &stdErr); pid_t ret = Util::Procs::StartPiped(argv, 0, 0, &stdErr);
//Clean up environment // Clean up environment
unsetenv("MST_ORIG_TARGET"); unsetenv("MST_ORIG_TARGET");
//Actually return the resulting PID // Actually return the resulting PID
return ret; return ret;
} }
@ -634,8 +639,8 @@ uint8_t Util::getStreamStatus(const std::string &streamname){
} }
/// Checks if a given user agent is allowed according to the given exception. /// Checks if a given user agent is allowed according to the given exception.
bool Util::checkException(const JSON::Value & ex, const std::string & useragent){ bool Util::checkException(const JSON::Value &ex, const std::string &useragent){
//No user agent? Always allow everything. // No user agent? Always allow everything.
if (!useragent.size()){return true;} if (!useragent.size()){return true;}
if (!ex.isArray() || !ex.size()){return true;} if (!ex.isArray() || !ex.size()){return true;}
bool ret = true; bool ret = true;
@ -643,12 +648,24 @@ bool Util::checkException(const JSON::Value & ex, const std::string & useragent)
if (!e->isArray() || !e->size()){continue;} if (!e->isArray() || !e->size()){continue;}
bool setTo = false; bool setTo = false;
bool except = false; bool except = false;
//whitelist makes the return value true if any value is contained in the UA, blacklist makes it false. // whitelist makes the return value true if any value is contained in the UA, blacklist makes it
//the '_except' variants do so only if none of the values are contained in the UA. // false. the '_except' variants do so only if none of the values are contained in the UA.
if ((*e)[0u].asStringRef() == "whitelist"){setTo = true; except = false;} if ((*e)[0u].asStringRef() == "whitelist"){
if ((*e)[0u].asStringRef() == "whitelist_except"){setTo = true; except = true;} setTo = true;
if ((*e)[0u].asStringRef() == "blacklist"){setTo = false; except = false;} except = false;
if ((*e)[0u].asStringRef() == "blacklist_except"){setTo = false; except = true;} }
if ((*e)[0u].asStringRef() == "whitelist_except"){
setTo = true;
except = true;
}
if ((*e)[0u].asStringRef() == "blacklist"){
setTo = false;
except = false;
}
if ((*e)[0u].asStringRef() == "blacklist_except"){
setTo = false;
except = true;
}
if (e->size() == 1){ if (e->size() == 1){
ret = setTo; ret = setTo;
continue; continue;
@ -658,7 +675,7 @@ bool Util::checkException(const JSON::Value & ex, const std::string & useragent)
jsonForEachConst((*e)[1u], i){ jsonForEachConst((*e)[1u], i){
if (useragent.find(i->asStringRef()) != std::string::npos){match = true;} if (useragent.find(i->asStringRef()) != std::string::npos){match = true;}
} }
//set the (temp) return value if this was either a match in regular mode, or a non-match in except-mode. // set the (temp) return value if this was either a match in regular mode, or a non-match in except-mode.
if (except != match){ret = setTo;} if (except != match){ret = setTo;}
} }
return ret; return ret;
@ -679,9 +696,12 @@ DTSC::Scan Util::DTSCShmReader::getScan(){
return DTSC::Scan(rAcc.getPointer("dtsc_data"), rAcc.getSize("dtsc_data")); return DTSC::Scan(rAcc.getPointer("dtsc_data"), rAcc.getSize("dtsc_data"));
} }
std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa, const std::string &trackType, const std::string &trackVal, const std::string &UA){ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa, const std::string &trackType,
const std::string &trackVal, const std::string &UA){
std::set<size_t> result; std::set<size_t> result;
if (!trackVal.size() || trackVal == "0" || trackVal == "-1" || trackVal == "none"){return result;}//don't select anything in particular if (!trackVal.size() || trackVal == "0" || trackVal == "-1" || trackVal == "none"){
return result;
}// don't select anything in particular
if (trackVal.find(',') != std::string::npos){ if (trackVal.find(',') != std::string::npos){
// Comma-separated list, recurse. // Comma-separated list, recurse.
std::stringstream ss(trackVal); std::stringstream ss(trackVal);
@ -695,17 +715,19 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
{ {
size_t trackNo = JSON::Value(trackVal).asInt(); size_t trackNo = JSON::Value(trackVal).asInt();
if (trackVal == JSON::Value((uint64_t)trackNo).asString()){ if (trackVal == JSON::Value((uint64_t)trackNo).asString()){
//It's an integer number // It's an integer number
if (!M.tracks.count(trackNo)){ if (!M.tracks.count(trackNo)){
INFO_MSG("Track %zd does not exist in stream, cannot select", trackNo); INFO_MSG("Track %zd does not exist in stream, cannot select", trackNo);
return result; return result;
} }
const DTSC::Track & Trk = M.tracks.at(trackNo); const DTSC::Track &Trk = M.tracks.at(trackNo);
if (Trk.type != trackType && Trk.codec != trackType){ if (Trk.type != trackType && Trk.codec != trackType){
INFO_MSG("Track %zd is not %s (%s/%s), cannot select", trackNo, trackType.c_str(), Trk.type.c_str(), Trk.codec.c_str()); INFO_MSG("Track %zd is not %s (%s/%s), cannot select", trackNo, trackType.c_str(),
Trk.type.c_str(), Trk.codec.c_str());
return result; return result;
} }
INFO_MSG("Selecting %s track %zd (%s/%s)", trackType.c_str(), trackNo, Trk.type.c_str(), Trk.codec.c_str()); INFO_MSG("Selecting %s track %zd (%s/%s)", trackType.c_str(), trackNo, Trk.type.c_str(),
Trk.codec.c_str());
result.insert(trackNo); result.insert(trackNo);
return result; return result;
} }
@ -716,8 +738,10 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
// select all tracks of this type // select all tracks of this type
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){result.insert(*it);} if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
result.insert(*it);
}
} }
return result; return result;
} }
@ -727,7 +751,7 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint32_t currRate = 0; uint32_t currRate = 0;
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
if (currRate < Trk.bps){ if (currRate < Trk.bps){
currVal = *it; currVal = *it;
@ -744,7 +768,7 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint32_t currRate = 0xFFFFFFFFul; uint32_t currRate = 0xFFFFFFFFul;
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
if (currRate > Trk.bps){ if (currRate > Trk.bps){
currVal = *it; currVal = *it;
@ -755,22 +779,34 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
if (currVal != INVALID_TRACK_ID){result.insert(currVal);} if (currVal != INVALID_TRACK_ID){result.insert(currVal);}
return result; return result;
} }
//less-than or greater-than track matching on bit rate or resolution // less-than or greater-than track matching on bit rate or resolution
if (trackLow[0] == '<' || trackLow[0] == '>'){ if (trackLow[0] == '<' || trackLow[0] == '>'){
unsigned int bpsVal; unsigned int bpsVal;
uint64_t targetBps = 0; uint64_t targetBps = 0;
if (trackLow.find("bps") != std::string::npos && sscanf(trackLow.c_str(), "<%ubps", &bpsVal) == 1){targetBps = bpsVal;} if (trackLow.find("bps") != std::string::npos && sscanf(trackLow.c_str(), "<%ubps", &bpsVal) == 1){
if (trackLow.find("kbps") != std::string::npos && sscanf(trackLow.c_str(), "<%ukbps", &bpsVal) == 1){targetBps = bpsVal*1024;} targetBps = bpsVal;
if (trackLow.find("mbps") != std::string::npos && sscanf(trackLow.c_str(), "<%umbps", &bpsVal) == 1){targetBps = bpsVal*1024*1024;} }
if (trackLow.find("bps") != std::string::npos && sscanf(trackLow.c_str(), ">%ubps", &bpsVal) == 1){targetBps = bpsVal;} if (trackLow.find("kbps") != std::string::npos && sscanf(trackLow.c_str(), "<%ukbps", &bpsVal) == 1){
if (trackLow.find("kbps") != std::string::npos && sscanf(trackLow.c_str(), ">%ukbps", &bpsVal) == 1){targetBps = bpsVal*1024;} targetBps = bpsVal * 1024;
if (trackLow.find("mbps") != std::string::npos && sscanf(trackLow.c_str(), ">%umbps", &bpsVal) == 1){targetBps = bpsVal*1024*1024;} }
if (trackLow.find("mbps") != std::string::npos && sscanf(trackLow.c_str(), "<%umbps", &bpsVal) == 1){
targetBps = bpsVal * 1024 * 1024;
}
if (trackLow.find("bps") != std::string::npos && sscanf(trackLow.c_str(), ">%ubps", &bpsVal) == 1){
targetBps = bpsVal;
}
if (trackLow.find("kbps") != std::string::npos && sscanf(trackLow.c_str(), ">%ukbps", &bpsVal) == 1){
targetBps = bpsVal * 1024;
}
if (trackLow.find("mbps") != std::string::npos && sscanf(trackLow.c_str(), ">%umbps", &bpsVal) == 1){
targetBps = bpsVal * 1024 * 1024;
}
if (targetBps){ if (targetBps){
targetBps >>= 3; targetBps >>= 3;
// select all tracks of this type that match the requirements // select all tracks of this type that match the requirements
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
if (trackLow[0] == '>' && Trk.bps > targetBps){result.insert(*it);} if (trackLow[0] == '>' && Trk.bps > targetBps){result.insert(*it);}
if (trackLow[0] == '<' && Trk.bps < targetBps){result.insert(*it);} if (trackLow[0] == '<' && Trk.bps < targetBps){result.insert(*it);}
@ -780,14 +816,14 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
} }
unsigned int resX, resY; unsigned int resX, resY;
uint64_t targetArea = 0; uint64_t targetArea = 0;
if (sscanf(trackLow.c_str(), "<%ux%u", &resX, &resY) == 2){targetArea = resX*resY;} if (sscanf(trackLow.c_str(), "<%ux%u", &resX, &resY) == 2){targetArea = resX * resY;}
if (sscanf(trackLow.c_str(), ">%ux%u", &resX, &resY) == 2){targetArea = resX*resY;} if (sscanf(trackLow.c_str(), ">%ux%u", &resX, &resY) == 2){targetArea = resX * resY;}
if (targetArea){ if (targetArea){
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
uint64_t trackArea = Trk.width*Trk.height; uint64_t trackArea = Trk.width * Trk.height;
if (trackLow[0] == '>' && trackArea > targetArea){result.insert(*it);} if (trackLow[0] == '>' && trackArea > targetArea){result.insert(*it);}
if (trackLow[0] == '<' && trackArea < targetArea){result.insert(*it);} if (trackLow[0] == '<' && trackArea < targetArea){result.insert(*it);}
} }
@ -795,13 +831,19 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
return result; return result;
} }
} }
//approx bitrate matching // approx bitrate matching
{ {
unsigned int bpsVal; unsigned int bpsVal;
uint64_t targetBps = 0; uint64_t targetBps = 0;
if (trackLow.find("bps") != std::string::npos && sscanf(trackLow.c_str(), "%ubps", &bpsVal) == 1){targetBps = bpsVal;} if (trackLow.find("bps") != std::string::npos && sscanf(trackLow.c_str(), "%ubps", &bpsVal) == 1){
if (trackLow.find("kbps") != std::string::npos && sscanf(trackLow.c_str(), "%ukbps", &bpsVal) == 1){targetBps = bpsVal*1024;} targetBps = bpsVal;
if (trackLow.find("mbps") != std::string::npos && sscanf(trackLow.c_str(), "%umbps", &bpsVal) == 1){targetBps = bpsVal*1024*1024;} }
if (trackLow.find("kbps") != std::string::npos && sscanf(trackLow.c_str(), "%ukbps", &bpsVal) == 1){
targetBps = bpsVal * 1024;
}
if (trackLow.find("mbps") != std::string::npos && sscanf(trackLow.c_str(), "%umbps", &bpsVal) == 1){
targetBps = bpsVal * 1024 * 1024;
}
if (targetBps){ if (targetBps){
targetBps >>= 3; targetBps >>= 3;
// select nearest bit rate track of this type // select nearest bit rate track of this type
@ -809,11 +851,12 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint32_t currDist = 0; uint32_t currDist = 0;
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
if (currVal == INVALID_TRACK_ID || (Trk.bps >= targetBps && currDist > (Trk.bps-targetBps)) || (Trk.bps < targetBps && currDist > (targetBps-Trk.bps))){ if (currVal == INVALID_TRACK_ID || (Trk.bps >= targetBps && currDist > (Trk.bps - targetBps)) ||
(Trk.bps < targetBps && currDist > (targetBps - Trk.bps))){
currVal = *it; currVal = *it;
currDist = (Trk.bps >= targetBps)?(Trk.bps-targetBps):(targetBps-Trk.bps); currDist = (Trk.bps >= targetBps) ? (Trk.bps - targetBps) : (targetBps - Trk.bps);
} }
} }
} }
@ -821,12 +864,12 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
return result; return result;
} }
} }
//audio channel matching // audio channel matching
if (!trackType.size() || trackType == "audio"){ if (!trackType.size() || trackType == "audio"){
if (trackLow == "surround"){ if (trackLow == "surround"){
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
if (Trk.channels > 2){result.insert(*it);} if (Trk.channels > 2){result.insert(*it);}
} }
@ -838,11 +881,13 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
if (trackLow == "mono"){targetChannel = 1;} if (trackLow == "mono"){targetChannel = 1;}
if (trackLow == "stereo"){targetChannel = 2;} if (trackLow == "stereo"){targetChannel = 2;}
if (trackLow == "stereo"){targetChannel = 2;} if (trackLow == "stereo"){targetChannel = 2;}
if (trackLow.find("ch") != std::string::npos && sscanf(trackLow.c_str(), "%uch", &channelVal) == 1){targetChannel = channelVal;} if (trackLow.find("ch") != std::string::npos && sscanf(trackLow.c_str(), "%uch", &channelVal) == 1){
targetChannel = channelVal;
}
if (targetChannel){ if (targetChannel){
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
if (Trk.channels == targetChannel){result.insert(*it);} if (Trk.channels == targetChannel){result.insert(*it);}
} }
@ -850,7 +895,7 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
return result; return result;
} }
} }
//approx resolution matching // approx resolution matching
if (!trackType.size() || trackType == "video"){ if (!trackType.size() || trackType == "video"){
if (trackLow == "highres" || trackLow == "bestres" || trackLow == "maxres"){ if (trackLow == "highres" || trackLow == "bestres" || trackLow == "maxres"){
// select highest resolution track of this type // select highest resolution track of this type
@ -858,9 +903,9 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint64_t currRes = 0; uint64_t currRes = 0;
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
uint64_t trackRes = Trk.width*Trk.height; uint64_t trackRes = Trk.width * Trk.height;
if (currRes < trackRes){ if (currRes < trackRes){
currVal = *it; currVal = *it;
currRes = trackRes; currRes = trackRes;
@ -876,9 +921,9 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint64_t currRes = 0xFFFFFFFFFFFFFFFFull; uint64_t currRes = 0xFFFFFFFFFFFFFFFFull;
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
uint64_t trackRes = Trk.width*Trk.height; uint64_t trackRes = Trk.width * Trk.height;
if (currRes > trackRes){ if (currRes > trackRes){
currVal = *it; currVal = *it;
currRes = trackRes; currRes = trackRes;
@ -894,15 +939,16 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
// select nearest resolution track of this type // select nearest resolution track of this type
size_t currVal = INVALID_TRACK_ID; size_t currVal = INVALID_TRACK_ID;
uint64_t currDist = 0; uint64_t currDist = 0;
uint64_t targetArea = resX*resY; uint64_t targetArea = resX * resY;
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
uint64_t trackArea = Trk.width*Trk.height; uint64_t trackArea = Trk.width * Trk.height;
if (currVal == INVALID_TRACK_ID || (trackArea >= targetArea && currDist > (trackArea-targetArea)) || (trackArea < targetArea && currDist > (targetArea-trackArea))){ if (currVal == INVALID_TRACK_ID || (trackArea >= targetArea && currDist > (trackArea - targetArea)) ||
(trackArea < targetArea && currDist > (targetArea - trackArea))){
currVal = *it; currVal = *it;
currDist = (trackArea >= targetArea)?(trackArea-targetArea):(targetArea-trackArea); currDist = (trackArea >= targetArea) ? (trackArea - targetArea) : (targetArea - trackArea);
} }
} }
} }
@ -910,13 +956,13 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
return result; return result;
} }
} }
}//video track specific }// video track specific
// attempt to do language/codec matching // attempt to do language/codec matching
// convert 2-character language codes into 3-character language codes // convert 2-character language codes into 3-character language codes
if (trackLow.size() == 2){trackLow = Encodings::ISO639::twoToThree(trackLow);} if (trackLow.size() == 2){trackLow = Encodings::ISO639::twoToThree(trackLow);}
std::set<size_t> validTracks = getSupportedTracks(M, capa); std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){ for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it); const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){ if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
std::string codecLow = Trk.codec; std::string codecLow = Trk.codec;
Util::stringToLower(codecLow); Util::stringToLower(codecLow);
@ -930,7 +976,7 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
if (trackLow == "4k" && Trk.width == 3840 && Trk.height == 2160){result.insert(*it);} if (trackLow == "4k" && Trk.width == 3840 && Trk.height == 2160){result.insert(*it);}
if (trackLow == "5k" && Trk.width == 5120 && Trk.height == 2880){result.insert(*it);} if (trackLow == "5k" && Trk.width == 5120 && Trk.height == 2880){result.insert(*it);}
if (trackLow == "8k" && Trk.width == 7680 && Trk.height == 4320){result.insert(*it);} if (trackLow == "8k" && Trk.width == 7680 && Trk.height == 4320){result.insert(*it);}
//match "XxY" format // match "XxY" format
if (sscanf(trackLow.c_str(), "%ux%u", &resX, &resY) == 2){ if (sscanf(trackLow.c_str(), "%ux%u", &resX, &resY) == 2){
if (Trk.width == resX && Trk.height == resY){result.insert(*it);} if (Trk.width == resX && Trk.height == resY){result.insert(*it);}
} }
@ -952,10 +998,8 @@ std::set<size_t> Util::getSupportedTracks(const DTSC::Meta &M, const JSON::Value
const std::string &type, const std::string &UA){ const std::string &type, const std::string &UA){
std::set<size_t> validTracks; std::set<size_t> validTracks;
for (std::map<unsigned int, DTSC::Track>::const_iterator it = M.tracks.begin(); it != M.tracks.end(); it++){ for (std::map<unsigned int, DTSC::Track>::const_iterator it = M.tracks.begin(); it != M.tracks.end(); it++){
const DTSC::Track & Trk = it->second; const DTSC::Track &Trk = it->second;
if (type != "" && type != Trk.type){ if (type != "" && type != Trk.type){continue;}
continue;
}
// Remove tracks for which we don't have codec support // Remove tracks for which we don't have codec support
if (capa.isMember("codecs")){ if (capa.isMember("codecs")){
std::string codec = Trk.codec; std::string codec = Trk.codec;
@ -1042,7 +1086,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
toRemove.insert(*it); toRemove.insert(*it);
continue; continue;
} }
//autoSeeking and target not in bounds? Drop it too. // autoSeeking and target not in bounds? Drop it too.
if (seekTarget && M.tracks.at(*it).lastms < std::max(seekTarget, (uint64_t)6000lu) - 6000){ if (seekTarget && M.tracks.at(*it).lastms < std::max(seekTarget, (uint64_t)6000lu) - 6000){
toRemove.insert(*it); toRemove.insert(*it);
} }
@ -1069,29 +1113,27 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
/*LTS-START*/ /*LTS-START*/
if (!capa.isMember("codecs")){ if (!capa.isMember("codecs")){
for (std::set<size_t>::iterator trit = validTracks.begin(); trit != validTracks.end(); trit++){ for (std::set<size_t>::iterator trit = validTracks.begin(); trit != validTracks.end(); trit++){
const DTSC::Track & Trk = M.tracks.at(*trit); const DTSC::Track &Trk = M.tracks.at(*trit);
bool problems = false; bool problems = false;
if (capa.isMember("exceptions") && capa["exceptions"].isObject() && if (capa.isMember("exceptions") && capa["exceptions"].isObject() && capa["exceptions"].size()){
capa["exceptions"].size()){ jsonForEachConst(capa["exceptions"], ex){
jsonForEachConst(capa["exceptions"], ex){ if (ex.key() == "codec:" + Trk.codec){
if (ex.key() == "codec:" + Trk.codec){ problems = !Util::checkException(*ex, UA);
problems = !Util::checkException(*ex, UA); break;
break;
}
} }
} }
//if (!allowBFrames && M.hasBFrames(*trit)){problems = true;} }
if (problems){continue;} // if (!allowBFrames && M.hasBFrames(*trit)){problems = true;}
if (noSelAudio && Trk.type == "audio"){continue;} if (problems){continue;}
if (noSelVideo && Trk.type == "video"){continue;} if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelSub && (Trk.type == "subtitle" || Trk.codec == "subtitle")){continue;} if (noSelVideo && Trk.type == "video"){continue;}
result.insert(*trit); if (noSelSub && (Trk.type == "subtitle" || Trk.codec == "subtitle")){continue;}
result.insert(*trit);
} }
return result; return result;
} }
/*LTS-END*/ /*LTS-END*/
jsonForEachConst(capa["codecs"], it){ jsonForEachConst(capa["codecs"], it){
unsigned int selCounter = 0; unsigned int selCounter = 0;
if ((*it).size() > 0){ if ((*it).size() > 0){
@ -1111,7 +1153,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
++shift; ++shift;
} }
for (std::set<size_t>::iterator itd = result.begin(); itd != result.end(); itd++){ for (std::set<size_t>::iterator itd = result.begin(); itd != result.end(); itd++){
const DTSC::Track & Trk = M.tracks.at(*itd); const DTSC::Track &Trk = M.tracks.at(*itd);
if ((!byType && Trk.codec == strRef.substr(shift)) || if ((!byType && Trk.codec == strRef.substr(shift)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){ (byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// user-agent-check // user-agent-check
@ -1166,7 +1208,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
++shift; ++shift;
} }
for (std::set<size_t>::iterator itd = result.begin(); itd != result.end(); itd++){ for (std::set<size_t>::iterator itd = result.begin(); itd != result.end(); itd++){
const DTSC::Track & Trk = M.tracks.at(*itd); const DTSC::Track &Trk = M.tracks.at(*itd);
if ((!byType && Trk.codec == strRef.substr(shift)) || if ((!byType && Trk.codec == strRef.substr(shift)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){ (byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// user-agent-check // user-agent-check
@ -1203,7 +1245,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
if (M.live){ if (M.live){
for (std::set<size_t>::reverse_iterator trit = validTracks.rbegin(); for (std::set<size_t>::reverse_iterator trit = validTracks.rbegin();
trit != validTracks.rend(); trit++){ trit != validTracks.rend(); trit++){
const DTSC::Track & Trk = M.tracks.at(*trit); const DTSC::Track &Trk = M.tracks.at(*trit);
if ((!byType && Trk.codec == strRef.substr(shift)) || if ((!byType && Trk.codec == strRef.substr(shift)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){ (byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// user-agent-check // user-agent-check
@ -1217,15 +1259,12 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
} }
} }
} }
//if (!allowBFrames && M.hasBFrames(*trit)){problems = true;} // if (!allowBFrames && M.hasBFrames(*trit)){problems = true;}
if (problems){break;} if (problems){break;}
/*LTS-START*/ /*LTS-START*/
if (noSelAudio && Trk.type == "audio"){continue;} if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelVideo && Trk.type == "video"){continue;} if (noSelVideo && Trk.type == "video"){continue;}
if (noSelSub && if (noSelSub && (Trk.type == "subtitle" || Trk.codec == "subtitle")){continue;}
(Trk.type == "subtitle" || Trk.codec == "subtitle")){
continue;
}
/*LTS-END*/ /*LTS-END*/
result.insert(*trit); result.insert(*trit);
found = true; found = true;
@ -1234,7 +1273,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
} }
}else{ }else{
for (std::set<size_t>::iterator trit = validTracks.begin(); trit != validTracks.end(); trit++){ for (std::set<size_t>::iterator trit = validTracks.begin(); trit != validTracks.end(); trit++){
const DTSC::Track & Trk = M.tracks.at(*trit); const DTSC::Track &Trk = M.tracks.at(*trit);
if ((!byType && Trk.codec == strRef.substr(shift)) || if ((!byType && Trk.codec == strRef.substr(shift)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){ (byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// user-agent-check // user-agent-check
@ -1248,15 +1287,12 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
} }
} }
} }
//if (!allowBFrames && M.hasBFrames(*trit)){problems = true;} // if (!allowBFrames && M.hasBFrames(*trit)){problems = true;}
if (problems){break;} if (problems){break;}
/*LTS-START*/ /*LTS-START*/
if (noSelAudio && Trk.type == "audio"){continue;} if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelVideo && Trk.type == "video"){continue;} if (noSelVideo && Trk.type == "video"){continue;}
if (noSelSub && if (noSelSub && (Trk.type == "subtitle" || Trk.type == "subtitle")){continue;}
(Trk.type == "subtitle" || Trk.type == "subtitle")){
continue;
}
/*LTS-END*/ /*LTS-END*/
result.insert(*trit); result.insert(*trit);
found = true; found = true;

View file

@ -2,44 +2,52 @@
/// Utilities for handling streams. /// Utilities for handling streams.
#pragma once #pragma once
#include <string>
#include "socket.h"
#include "json.h"
#include "dtsc.h" #include "dtsc.h"
#include "json.h"
#include "shared_memory.h" #include "shared_memory.h"
#include "socket.h"
#include "util.h" #include "util.h"
#include <string>
const JSON::Value empty; const JSON::Value empty;
namespace Util { namespace Util{
void streamVariables(std::string &str, const std::string & streamname, const std::string & source = ""); void streamVariables(std::string &str, const std::string &streamname, const std::string &source = "");
std::string getTmpFolder(); std::string getTmpFolder();
void sanitizeName(std::string & streamname); void sanitizeName(std::string &streamname);
bool streamAlive(std::string & streamname); bool streamAlive(std::string &streamname);
bool startInput(std::string streamname, std::string filename = "", bool forkFirst = true, bool isProvider = false, const std::map<std::string, std::string> & overrides = std::map<std::string, std::string>(), pid_t * spawn_pid = NULL); bool startInput(std::string streamname, std::string filename = "", bool forkFirst = true,
int startPush(const std::string & streamname, std::string & target); bool isProvider = false,
JSON::Value getStreamConfig(const std::string & streamname); const std::map<std::string, std::string> &overrides = std::map<std::string, std::string>(),
JSON::Value getGlobalConfig(const std::string & optionName); pid_t *spawn_pid = NULL);
JSON::Value getInputBySource(const std::string & filename, bool isProvider = false); int startPush(const std::string &streamname, std::string &target);
DTSC::Meta getStreamMeta(const std::string & streamname); JSON::Value getStreamConfig(const std::string &streamname);
uint8_t getStreamStatus(const std::string & streamname); JSON::Value getGlobalConfig(const std::string &optionName);
bool checkException(const JSON::Value & ex, const std::string & useragent); JSON::Value getInputBySource(const std::string &filename, bool isProvider = false);
std::string codecString(const std::string & codec, const std::string & initData = ""); DTSC::Meta getStreamMeta(const std::string &streamname);
uint8_t getStreamStatus(const std::string &streamname);
bool checkException(const JSON::Value &ex, const std::string &useragent);
std::string codecString(const std::string &codec, const std::string &initData = "");
std::set<size_t> getSupportedTracks(const DTSC::Meta &M, const JSON::Value &capa = empty, const std::string &type = "", const std::string &UA = ""); std::set<size_t> getSupportedTracks(const DTSC::Meta &M, const JSON::Value &capa = empty,
std::set<size_t> findTracks(const DTSC::Meta &M, const JSON::Value &capa, const std::string &trackType, const std::string &trackVal, const std::string &UA = ""); const std::string &type = "", const std::string &UA = "");
std::set<size_t> wouldSelect(const DTSC::Meta &M, const std::string &trackSelector = "", const JSON::Value &capa = empty, const std::string &UA = ""); std::set<size_t> findTracks(const DTSC::Meta &M, const JSON::Value &capa, const std::string &trackType,
std::set<size_t> wouldSelect(const DTSC::Meta &M, const std::map<std::string, std::string> &targetParams, const JSON::Value &capa = empty, const std::string &UA = "", uint64_t seekTarget = 0); const std::string &trackVal, const std::string &UA = "");
std::set<size_t> wouldSelect(const DTSC::Meta &M, const std::string &trackSelector = "",
const JSON::Value &capa = empty, const std::string &UA = "");
std::set<size_t> wouldSelect(const DTSC::Meta &M, const std::map<std::string, std::string> &targetParams,
const JSON::Value &capa = empty, const std::string &UA = "",
uint64_t seekTarget = 0);
class DTSCShmReader{ class DTSCShmReader{
public: public:
DTSCShmReader(const std::string &pageName); DTSCShmReader(const std::string &pageName);
DTSC::Scan getMember(const std::string &indice); DTSC::Scan getMember(const std::string &indice);
DTSC::Scan getScan(); DTSC::Scan getScan();
private:
IPC::sharedPage rPage; private:
Util::RelAccX rAcc; IPC::sharedPage rPage;
Util::RelAccX rAcc;
}; };
} }// namespace Util

File diff suppressed because it is too large Load diff

View file

@ -1,51 +1,51 @@
#pragma once #pragma once
#include <stdint.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <vector> #include <stdint.h>
#include <string> #include <string>
#include <vector>
/* --------------------------------------- */ /* --------------------------------------- */
#define STUN_IP4 0x01 #define STUN_IP4 0x01
#define STUN_IP6 0x02 #define STUN_IP6 0x02
#define STUN_MSG_TYPE_NONE 0x0000 #define STUN_MSG_TYPE_NONE 0x0000
#define STUN_MSG_TYPE_BINDING_REQUEST 0x0001 #define STUN_MSG_TYPE_BINDING_REQUEST 0x0001
#define STUN_MSG_TYPE_BINDING_RESPONSE_SUCCESS 0x0101 #define STUN_MSG_TYPE_BINDING_RESPONSE_SUCCESS 0x0101
#define STUN_MSG_TYPE_BINDING_RESPONSE_ERROR 0x0111 #define STUN_MSG_TYPE_BINDING_RESPONSE_ERROR 0x0111
#define STUN_MSG_TYPE_BINDING_INDICATION 0x0011 #define STUN_MSG_TYPE_BINDING_INDICATION 0x0011
#define STUN_ATTR_TYPE_NONE 0x0000 #define STUN_ATTR_TYPE_NONE 0x0000
#define STUN_ATTR_TYPE_MAPPED_ADDR 0x0001 #define STUN_ATTR_TYPE_MAPPED_ADDR 0x0001
#define STUN_ATTR_TYPE_CHANGE_REQ 0x0003 #define STUN_ATTR_TYPE_CHANGE_REQ 0x0003
#define STUN_ATTR_TYPE_USERNAME 0x0006 #define STUN_ATTR_TYPE_USERNAME 0x0006
#define STUN_ATTR_TYPE_MESSAGE_INTEGRITY 0x0008 #define STUN_ATTR_TYPE_MESSAGE_INTEGRITY 0x0008
#define STUN_ATTR_TYPE_ERR_CODE 0x0009 #define STUN_ATTR_TYPE_ERR_CODE 0x0009
#define STUN_ATTR_TYPE_UNKNOWN_ATTRIBUTES 0x000a #define STUN_ATTR_TYPE_UNKNOWN_ATTRIBUTES 0x000a
#define STUN_ATTR_TYPE_CHANNEL_NUMBER 0x000c #define STUN_ATTR_TYPE_CHANNEL_NUMBER 0x000c
#define STUN_ATTR_TYPE_LIFETIME 0x000d #define STUN_ATTR_TYPE_LIFETIME 0x000d
#define STUN_ATTR_TYPE_XOR_PEER_ADDR 0x0012 #define STUN_ATTR_TYPE_XOR_PEER_ADDR 0x0012
#define STUN_ATTR_TYPE_DATA 0x0013 #define STUN_ATTR_TYPE_DATA 0x0013
#define STUN_ATTR_TYPE_REALM 0x0014 #define STUN_ATTR_TYPE_REALM 0x0014
#define STUN_ATTR_TYPE_NONCE 0x0015 #define STUN_ATTR_TYPE_NONCE 0x0015
#define STUN_ATTR_TYPE_XOR_RELAY_ADDRESS 0x0016 #define STUN_ATTR_TYPE_XOR_RELAY_ADDRESS 0x0016
#define STUN_ATTR_TYPE_REQ_ADDRESS_FAMILY 0x0017 #define STUN_ATTR_TYPE_REQ_ADDRESS_FAMILY 0x0017
#define STUN_ATTR_TYPE_EVEN_PORT 0x0018 #define STUN_ATTR_TYPE_EVEN_PORT 0x0018
#define STUN_ATTR_TYPE_REQUESTED_TRANSPORT 0x0019 #define STUN_ATTR_TYPE_REQUESTED_TRANSPORT 0x0019
#define STUN_ATTR_TYPE_DONT_FRAGMENT 0x001a #define STUN_ATTR_TYPE_DONT_FRAGMENT 0x001a
#define STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS 0x0020 #define STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS 0x0020
#define STUN_ATTR_TYPE_RESERVATION_TOKEN 0x0022 #define STUN_ATTR_TYPE_RESERVATION_TOKEN 0x0022
#define STUN_ATTR_TYPE_PRIORITY 0x0024 #define STUN_ATTR_TYPE_PRIORITY 0x0024
#define STUN_ATTR_TYPE_USE_CANDIDATE 0x0025 #define STUN_ATTR_TYPE_USE_CANDIDATE 0x0025
#define STUN_ATTR_TYPE_PADDING 0x0026 #define STUN_ATTR_TYPE_PADDING 0x0026
#define STUN_ATTR_TYPE_RESPONSE_PORT 0x0027 #define STUN_ATTR_TYPE_RESPONSE_PORT 0x0027
#define STUN_ATTR_TYPE_SOFTWARE 0x8022 #define STUN_ATTR_TYPE_SOFTWARE 0x8022
#define STUN_ATTR_TYPE_ALTERNATE_SERVER 0x8023 #define STUN_ATTR_TYPE_ALTERNATE_SERVER 0x8023
#define STUN_ATTR_TYPE_FINGERPRINT 0x8028 #define STUN_ATTR_TYPE_FINGERPRINT 0x8028
#define STUN_ATTR_TYPE_ICE_CONTROLLED 0x8029 #define STUN_ATTR_TYPE_ICE_CONTROLLED 0x8029
#define STUN_ATTR_TYPE_ICE_CONTROLLING 0x802a #define STUN_ATTR_TYPE_ICE_CONTROLLING 0x802a
#define STUN_ATTR_TYPE_RESPONSE_ORIGIN 0x802b #define STUN_ATTR_TYPE_RESPONSE_ORIGIN 0x802b
#define STUN_ATTR_TYPE_OTHER_ADDRESS 0x802c #define STUN_ATTR_TYPE_OTHER_ADDRESS 0x802c
/* --------------------------------------- */ /* --------------------------------------- */
@ -60,7 +60,7 @@ std::string stun_family_type_to_string(uint8_t type);
std::string key: key to use for hmac std::string key: key to use for hmac
uint8_t* output: we write the sha1 into this buffer. uint8_t* output: we write the sha1 into this buffer.
*/ */
int stun_compute_hmac_sha1(uint8_t* message, uint32_t nbytes, std::string key, uint8_t* output); int stun_compute_hmac_sha1(uint8_t *message, uint32_t nbytes, std::string key, uint8_t *output);
/* /*
Compute the Message-Integrity of a stun message. Compute the Message-Integrity of a stun message.
@ -70,7 +70,7 @@ int stun_compute_hmac_sha1(uint8_t* message, uint32_t nbytes, std::string key, u
std::string key: key to use for hmac std::string key: key to use for hmac
uint8_t* output: will be filled with the correct hmac-sha1 of that represents the integrity message value. uint8_t* output: will be filled with the correct hmac-sha1 of that represents the integrity message value.
*/ */
int stun_compute_message_integrity(std::vector<uint8_t>& buffer, std::string key, uint8_t* output); int stun_compute_message_integrity(std::vector<uint8_t> &buffer, std::string key, uint8_t *output);
/* /*
Compute the fingerprint value for the stun message. Compute the fingerprint value for the stun message.
@ -78,47 +78,47 @@ int stun_compute_message_integrity(std::vector<uint8_t>& buffer, std::string key
std::vector<uint8_t>& buffer: the buffer that contains a valid stun message. std::vector<uint8_t>& buffer: the buffer that contains a valid stun message.
uint32_t& result: will be set to the calculated crc value. uint32_t& result: will be set to the calculated crc value.
*/ */
int stun_compute_fingerprint(std::vector<uint8_t>& buffer, uint32_t& result); int stun_compute_fingerprint(std::vector<uint8_t> &buffer, uint32_t &result);
/* --------------------------------------- */ /* --------------------------------------- */
/* https://tools.ietf.org/html/rfc5389#section-15.10 */ /* https://tools.ietf.org/html/rfc5389#section-15.10 */
class StunAttribSoftware { class StunAttribSoftware{
public: public:
char* value; char *value;
}; };
class StunAttribFingerprint { class StunAttribFingerprint{
public: public:
uint32_t value; uint32_t value;
}; };
/* https://tools.ietf.org/html/rfc5389#section-15.4 */ /* https://tools.ietf.org/html/rfc5389#section-15.4 */
class StunAttribMessageIntegrity { class StunAttribMessageIntegrity{
public: public:
uint8_t* sha1; uint8_t *sha1;
}; };
/* https://tools.ietf.org/html/rfc5245#section-19.1 */ /* https://tools.ietf.org/html/rfc5245#section-19.1 */
class StunAttribPriority { class StunAttribPriority{
public: public:
uint32_t value; uint32_t value;
}; };
/* https://tools.ietf.org/html/rfc5245#section-19.1 */ /* https://tools.ietf.org/html/rfc5245#section-19.1 */
class StunAttribIceControllling { class StunAttribIceControllling{
public: public:
uint64_t tie_breaker; uint64_t tie_breaker;
}; };
/* https://tools.ietf.org/html/rfc3489#section-11.2.6 */ /* https://tools.ietf.org/html/rfc3489#section-11.2.6 */
class StunAttribUsername { class StunAttribUsername{
public: public:
char* value; /* Must use `length` member of attribute that indicates the number of valid bytes in the username. */ char *value; /* Must use `length` member of attribute that indicates the number of valid bytes in the username. */
}; };
/* https://tools.ietf.org/html/rfc5389#section-15.2 */ /* https://tools.ietf.org/html/rfc5389#section-15.2 */
class StunAttribXorMappedAddress { class StunAttribXorMappedAddress{
public: public:
uint8_t family; uint8_t family;
uint16_t port; uint16_t port;
@ -127,7 +127,7 @@ public:
/* --------------------------------------- */ /* --------------------------------------- */
class StunAttribute { class StunAttribute{
public: public:
StunAttribute(); StunAttribute();
void print(); void print();
@ -135,7 +135,7 @@ public:
public: public:
uint16_t type; uint16_t type;
uint16_t length; uint16_t length;
union { union{
StunAttribXorMappedAddress xor_address; StunAttribXorMappedAddress xor_address;
StunAttribUsername username; StunAttribUsername username;
StunAttribIceControllling ice_controlling; StunAttribIceControllling ice_controlling;
@ -148,15 +148,15 @@ public:
/* --------------------------------------- */ /* --------------------------------------- */
class StunMessage { class StunMessage{
public: public:
StunMessage(); StunMessage();
void setType(uint16_t type); void setType(uint16_t type);
void setTransactionId(uint32_t a, uint32_t b, uint32_t c); void setTransactionId(uint32_t a, uint32_t b, uint32_t c);
void print(); void print();
void addAttribute(StunAttribute& attr); void addAttribute(StunAttribute &attr);
void removeAttributes(); void removeAttributes();
StunAttribute* getAttributeByType(uint16_t type); StunAttribute *getAttributeByType(uint16_t type);
public: public:
uint16_t type; uint16_t type;
@ -168,19 +168,19 @@ public:
/* --------------------------------------- */ /* --------------------------------------- */
class StunReader { class StunReader{
public: public:
StunReader(); StunReader();
int parse(uint8_t* data, size_t nbytes, size_t& nparsed, StunMessage& msg); /* `nparsed` and `msg` are filled. */ int parse(uint8_t *data, size_t nbytes, size_t &nparsed, StunMessage &msg); /* `nparsed` and `msg` are filled. */
private: private:
int parseXorMappedAddress(StunAttribute& attr); int parseXorMappedAddress(StunAttribute &attr);
int parseUsername(StunAttribute& attr); int parseUsername(StunAttribute &attr);
int parseIceControlling(StunAttribute& attr); int parseIceControlling(StunAttribute &attr);
int parsePriority(StunAttribute& attr); int parsePriority(StunAttribute &attr);
int parseSoftware(StunAttribute& attr); int parseSoftware(StunAttribute &attr);
int parseMessageIntegrity(StunAttribute& attr); int parseMessageIntegrity(StunAttribute &attr);
int parseFingerprint(StunAttribute& attr); int parseFingerprint(StunAttribute &attr);
uint8_t readU8(); uint8_t readU8();
uint16_t readU16(); uint16_t readU16();
@ -188,32 +188,35 @@ private:
uint64_t readU64(); uint64_t readU64();
private: private:
uint8_t* buffer_data; uint8_t *buffer_data;
size_t buffer_size; size_t buffer_size;
size_t read_dx; size_t read_dx;
}; };
/* --------------------------------------- */ /* --------------------------------------- */
class StunWriter { class StunWriter{
public: public:
StunWriter(); StunWriter();
/* write header and finalize. call for each stun message */ /* write header and finalize. call for each stun message */
int begin(StunMessage& msg, uint8_t paddingByte = 0x00); /* I've added the padding byte here so that we can use the examples that can be found here https://tools.ietf.org/html/rfc5769#section-2.2 as they use 0x20 or 0x00 as the padding byte which is correct as you are free to use w/e padding byte you want. */ int begin(StunMessage &msg,
uint8_t paddingByte = 0x00); /* I've added the padding byte here so that we can use the
examples that can be found here https://tools.ietf.org/html/rfc5769#section-2.2
as they use 0x20 or 0x00 as the padding byte which is correct as you are free to use w/e padding byte you want. */
int end(); int end();
/* write attributes */ /* write attributes */
int writeXorMappedAddress(sockaddr_in addr); int writeXorMappedAddress(sockaddr_in addr);
int writeXorMappedAddress(uint8_t family, uint16_t port, uint32_t ip); int writeXorMappedAddress(uint8_t family, uint16_t port, uint32_t ip);
int writeXorMappedAddress(uint8_t family, uint16_t port, const std::string& ip); int writeXorMappedAddress(uint8_t family, uint16_t port, const std::string &ip);
int writeUsername(const std::string& username); int writeUsername(const std::string &username);
int writeSoftware(const std::string& software); int writeSoftware(const std::string &software);
int writeMessageIntegrity(const std::string& password); /* When using WebRtc this is the ice-upwd of the other agent. */ int writeMessageIntegrity(const std::string &password); /* When using WebRtc this is the ice-upwd of the other agent. */
int writeFingerprint(); /* Must be the last attribute in the message. When adding a fingerprint, make sure that it is added after the message-integrity (when you also use a message-integrity). */ int writeFingerprint(); /* Must be the last attribute in the message. When adding a fingerprint, make sure that it is added after the message-integrity (when you also use a message-integrity). */
/* get buffer */ /* get buffer */
uint8_t* getBufferPtr(); uint8_t *getBufferPtr();
size_t getBufferSize(); size_t getBufferSize();
private: private:
@ -223,9 +226,9 @@ private:
void writeU64(uint64_t v); void writeU64(uint64_t v);
void rewriteU16(size_t dx, uint16_t v); void rewriteU16(size_t dx, uint16_t v);
void rewriteU32(size_t dx, uint32_t v); void rewriteU32(size_t dx, uint32_t v);
void writeString(const std::string& str); void writeString(const std::string &str);
void writePadding(); void writePadding();
int convertIp4StringToInt(const std::string& ip, uint32_t& result); int convertIp4StringToInt(const std::string &ip, uint32_t &result);
private: private:
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer;
@ -234,16 +237,14 @@ private:
/* --------------------------------------- */ /* --------------------------------------- */
inline uint8_t* StunWriter::getBufferPtr() { inline uint8_t *StunWriter::getBufferPtr(){
if (0 == buffer.size()) { if (0 == buffer.size()){return NULL;}
return NULL;
}
return &buffer[0]; return &buffer[0];
} }
inline size_t StunWriter::getBufferSize() { inline size_t StunWriter::getBufferSize(){
return buffer.size(); return buffer.size();
} }

View file

@ -1,38 +1,35 @@
#include "subtitles.h"
#include "bitfields.h" #include "bitfields.h"
#include "subtitles.h"
#include "defines.h" #include "defines.h"
namespace Subtitle { namespace Subtitle{
Packet getSubtitle(DTSC::Packet packet, DTSC::Meta meta) { Packet getSubtitle(DTSC::Packet packet, DTSC::Meta meta){
char * tmp = 0; char *tmp = 0;
uint16_t length = 0; uint16_t length = 0;
unsigned int len; unsigned int len;
Packet output; Packet output;
long int trackId= packet.getTrackId(); long int trackId = packet.getTrackId();
if(meta.tracks[trackId].codec != "TTXT" && meta.tracks[trackId].codec != "SRT") { if (meta.tracks[trackId].codec != "TTXT" && meta.tracks[trackId].codec != "SRT"){
//no subtitle track // no subtitle track
return output; return output;
} }
if(packet.hasMember("duration")) { if (packet.hasMember("duration")){
output.duration = packet.getInt("duration"); output.duration = packet.getInt("duration");
} else { }else{
//get parts from meta // get parts from meta
//calculate duration // calculate duration
} }
packet.getString("data", output.subtitle); packet.getString("data", output.subtitle);
if(meta.tracks[trackId].codec == "TTXT") { if (meta.tracks[trackId].codec == "TTXT"){
unsigned short size = Bit::btohs(output.subtitle.c_str()); unsigned short size = Bit::btohs(output.subtitle.c_str());
output.subtitle = output.subtitle.substr(2,size); output.subtitle = output.subtitle.substr(2, size);
} }
return output; return output;
} }
}// namespace Subtitle
}

View file

@ -1,15 +1,14 @@
#pragma once #pragma once
#include <string>
#include "dtsc.h" #include "dtsc.h"
#include <string>
namespace Subtitle { namespace Subtitle{
struct Packet { struct Packet{
std::string subtitle; std::string subtitle;
uint64_t duration; uint64_t duration;
}; };
Packet getSubtitle(DTSC::Packet packet, DTSC::Meta meta); Packet getSubtitle(DTSC::Packet packet, DTSC::Meta meta);
} }// namespace Subtitle

View file

@ -1,22 +1,22 @@
#include "defines.h"
#include "theora.h" #include "theora.h"
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sstream> #include <sstream>
#include "defines.h" #include <stdlib.h>
#include <string.h>
namespace theora { namespace theora{
bool header::checkDataSize(unsigned int size){ bool header::checkDataSize(unsigned int size){
if (size > datasize){ if (size > datasize){
void * tmp = realloc(data, size); void *tmp = realloc(data, size);
if (tmp){ if (tmp){
data = (char *)tmp; data = (char *)tmp;
datasize = size; datasize = size;
return true; return true;
} else { }else{
return false; return false;
} }
} else { }else{
return true; return true;
} }
} }
@ -36,9 +36,7 @@ namespace theora {
} }
uint16_t header::getInt16(size_t index){ uint16_t header::getInt16(size_t index){
if (datasize >= (index + 1)){ if (datasize >= (index + 1)){return 0 + (data[index] << 8) + data[index + 1];}
return 0 + (data[index] << 8) + data[index + 1];
}
return 0; return 0;
} }
@ -49,206 +47,147 @@ namespace theora {
return 0; return 0;
} }
header::header(char * newData, unsigned int length){ header::header(char *newData, unsigned int length){
data = newData; data = newData;
datasize = length; datasize = length;
} }
header::~header(){ header::~header(){}
}
bool isHeader(const char * newData, unsigned int length){ bool isHeader(const char *newData, unsigned int length){
if (length < 7){ if (length < 7){return false;}
return false;
}
if (!(newData[0] & 0x80)){ if (!(newData[0] & 0x80)){
FAIL_MSG("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){return false;}
return false;
}
return true; return true;
} }
int header::getHeaderType(){ int header::getHeaderType(){return (data[0] & 0x7F);}
return (data[0] & 0x7F);
}
char header::getVMAJ(){ char header::getVMAJ(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return data[7];}
return data[7];
}
return 0; return 0;
} }
char header::getVMIN(){ char header::getVMIN(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return data[8];}
return data[8];
}
return 0; return 0;
} }
char header::getVREV(){ char header::getVREV(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return data[9];}
return data[9];
}
return 0; return 0;
} }
short header::getFMBW(){ short header::getFMBW(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt16(10);}
return getInt16(10);
}
return 0; return 0;
} }
short header::getFMBH(){ short header::getFMBH(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt16(12);}
return getInt16(12);
}
return 0; return 0;
} }
char header::getPICX(){ char header::getPICX(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return data[20];}
return data[20];
}
return 0; return 0;
} }
char header::getPICY(){ char header::getPICY(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return data[21];}
return data[21];
}
return 0; return 0;
} }
char header::getKFGShift(){ char header::getKFGShift(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return (getInt16(40) >> 5) & 0x1F;}
return (getInt16(40) >> 5) & 0x1F;
}
return 0; return 0;
} }
long unsigned int header::getFRN(){ long unsigned int header::getFRN(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt32(22);}
return getInt32(22);
}
return 0; return 0;
} }
long unsigned int header::getPICH(){ long unsigned int header::getPICH(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt24(17);}
return getInt24(17);
}
return 0; return 0;
} }
long unsigned int header::getPICW(){ long unsigned int header::getPICW(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt24(14);}
return getInt24(14);
}
return 0; return 0;
} }
long unsigned int header::getFRD(){ long unsigned int header::getFRD(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt32(26);}
return getInt32(26);
}
return 0; return 0;
} }
long unsigned int header::getPARN(){ long unsigned int header::getPARN(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt24(30);}
return getInt24(30);
}
return 0; return 0;
} }
long unsigned int header::getPARD(){ long unsigned int header::getPARD(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt24(33);}
return getInt24(33);
}
return 0; return 0;
} }
char header::getCS(){ char header::getCS(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return data[36];}
return data[36];
}
return 0; return 0;
} }
long unsigned int header::getNOMBR(){ long unsigned int header::getNOMBR(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return getInt24(37);}
return getInt24(37);
}
return 0; return 0;
} }
char header::getQUAL(){ char header::getQUAL(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return (data[40] >> 3) & 0x1F;}
return (data[40] >> 3) & 0x1F;
}
return 0; return 0;
} }
char header::getPF(){ char header::getPF(){
if (getHeaderType() == 0){ if (getHeaderType() == 0){return (data[41] >> 3) & 0x03;}
return (data[41] >> 3) & 0x03;
}
return 0; return 0;
} }
std::string header::getVendor(){ std::string header::getVendor(){
if (getHeaderType() != 1){ if (getHeaderType() != 1){return "";}
return "";
}
return std::string(data + 11, commentLen(7)); return std::string(data + 11, commentLen(7));
} }
long unsigned int header::getNComments(){ long unsigned int header::getNComments(){
if (getHeaderType() != 1){ if (getHeaderType() != 1){return 0;}
return 0;
}
int offset = 11 + commentLen(7); int offset = 11 + commentLen(7);
return commentLen(offset); return commentLen(offset);
} }
char header::getLFLIMS(size_t index){ char header::getLFLIMS(size_t index){
if (getHeaderType() != 2){ if (getHeaderType() != 2){return 0;}
return 0; if (index >= 64){return 0;}
}
if (index >= 64){
return 0;
}
char NBITS = (data[0] >> 5) & 0x07; char NBITS = (data[0] >> 5) & 0x07;
return NBITS; return NBITS;
} }
std::string header::getUserComment(size_t index){ std::string header::getUserComment(size_t index){
if (index >= getNComments()){ if (index >= getNComments()){return "";}
return "";
}
int offset = 11 + commentLen(7) + 4; int offset = 11 + commentLen(7) + 4;
for (size_t i = 0; i < index; i++){ for (size_t i = 0; i < index; i++){offset += 4 + commentLen(offset);}
offset += 4 + commentLen(offset);
}
return std::string(data + offset + 4, commentLen(offset)); return std::string(data + offset + 4, commentLen(offset));
} }
char header::getFTYPE(){ char header::getFTYPE(){return (data[0] >> 6) & 0x01;}
return (data[0] >> 6) & 0x01;
}
bool header::isHeader(){ bool header::isHeader(){return ::theora::isHeader(data, datasize);}
return ::theora::isHeader(data, datasize);
}
std::string header::toPrettyString(size_t indent){ std::string header::toPrettyString(size_t indent){
std::stringstream result; std::stringstream result;
if(!isHeader()){ if (!isHeader()){
result << std::string(indent, ' ') << "Theora Frame" << std::endl; result << std::string(indent, ' ') << "Theora Frame" << std::endl;
result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl; result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl;
return result.str(); return result.str();
@ -256,34 +195,33 @@ namespace theora {
result << std::string(indent, ' ') << "Theora header" << std::endl; result << std::string(indent, ' ') << "Theora header" << std::endl;
result << std::string(indent + 2, ' ') << "HeaderType: " << getHeaderType() << std::endl; result << std::string(indent + 2, ' ') << "HeaderType: " << getHeaderType() << std::endl;
switch (getHeaderType()){ switch (getHeaderType()){
case 0: case 0:
result << std::string(indent + 2, ' ') << "VMAJ: " << (int)getVMAJ() << std::endl; result << std::string(indent + 2, ' ') << "VMAJ: " << (int)getVMAJ() << std::endl;
result << std::string(indent + 2, ' ') << "VMIN: " << (int)getVMIN() << std::endl; result << std::string(indent + 2, ' ') << "VMIN: " << (int)getVMIN() << std::endl;
result << std::string(indent + 2, ' ') << "VREV: " << (int)getVREV() << std::endl; result << std::string(indent + 2, ' ') << "VREV: " << (int)getVREV() << std::endl;
result << std::string(indent + 2, ' ') << "FMBW: " << getFMBW() << std::endl; result << std::string(indent + 2, ' ') << "FMBW: " << getFMBW() << std::endl;
result << std::string(indent + 2, ' ') << "FMBH: " << getFMBH() << std::endl; result << std::string(indent + 2, ' ') << "FMBH: " << getFMBH() << std::endl;
result << std::string(indent + 2, ' ') << "PICH: " << getPICH() << std::endl; result << std::string(indent + 2, ' ') << "PICH: " << getPICH() << std::endl;
result << std::string(indent + 2, ' ') << "PICW: " << getPICW() << std::endl; result << std::string(indent + 2, ' ') << "PICW: " << getPICW() << std::endl;
result << std::string(indent + 2, ' ') << "PICX: " << (int)getPICX() << std::endl; result << std::string(indent + 2, ' ') << "PICX: " << (int)getPICX() << std::endl;
result << std::string(indent + 2, ' ') << "PICY: " << (int)getPICY() << std::endl; result << std::string(indent + 2, ' ') << "PICY: " << (int)getPICY() << std::endl;
result << std::string(indent + 2, ' ') << "FRN: " << getFRN() << std::endl; result << std::string(indent + 2, ' ') << "FRN: " << getFRN() << std::endl;
result << std::string(indent + 2, ' ') << "FRD: " << getFRD() << std::endl; result << std::string(indent + 2, ' ') << "FRD: " << getFRD() << std::endl;
result << std::string(indent + 2, ' ') << "PARN: " << getPARN() << std::endl; result << std::string(indent + 2, ' ') << "PARN: " << getPARN() << std::endl;
result << std::string(indent + 2, ' ') << "PARD: " << getPARD() << std::endl; result << std::string(indent + 2, ' ') << "PARD: " << getPARD() << std::endl;
result << std::string(indent + 2, ' ') << "CS: " << (int)getCS() << std::endl; result << std::string(indent + 2, ' ') << "CS: " << (int)getCS() << std::endl;
result << std::string(indent + 2, ' ') << "NOMBR: " << getNOMBR() << std::endl; result << std::string(indent + 2, ' ') << "NOMBR: " << getNOMBR() << std::endl;
result << std::string(indent + 2, ' ') << "QUAL: " << (int)getQUAL() << std::endl; result << std::string(indent + 2, ' ') << "QUAL: " << (int)getQUAL() << std::endl;
result << std::string(indent + 2, ' ') << "KFGShift: " << (int)getKFGShift() << std::endl; result << std::string(indent + 2, ' ') << "KFGShift: " << (int)getKFGShift() << std::endl;
break; break;
case 1: case 1:
result << std::string(indent + 2, ' ') << "Vendor: " << getVendor() << std::endl; result << std::string(indent + 2, ' ') << "Vendor: " << getVendor() << std::endl;
result << std::string(indent + 2, ' ') << "User Comments (" << getNComments() << "):" << std::endl; result << std::string(indent + 2, ' ') << "User Comments (" << getNComments() << "):" << std::endl;
for (long unsigned int i = 0; i < getNComments(); i++){ for (long unsigned int i = 0; i < getNComments(); i++){
result << std::string(indent + 4, ' ') << "[" << i << "] " << getUserComment(i) << std::endl; result << std::string(indent + 4, ' ') << "[" << i << "] " << getUserComment(i) << std::endl;
} }
break; break;
case 2: case 2: result << std::string(indent + 2, ' ') << "NBITS: " << (int)getLFLIMS(0) << std::endl;
result << std::string(indent + 2, ' ') << "NBITS: " << (int)getLFLIMS(0) << std::endl;
} }
return result.str(); return result.str();
} }
@ -307,10 +245,10 @@ namespace theora {
data = (char *)tmp; data = (char *)tmp;
datasize = size; datasize = size;
return true; return true;
} else { }else{
return false; return false;
} }
} else { }else{
return true; return true;
} }
} }
@ -324,7 +262,7 @@ namespace theora {
} }
if (checkDataSize(length)){ if (checkDataSize(length)){
memcpy(data, newData, length); memcpy(data, newData, length);
} else { }else{
return false; return false;
} }
return true; return true;
@ -342,24 +280,19 @@ namespace theora {
return 0; return 0;
} }
*/ */
/* /*
long long unsigned int header::parseGranuleUpper(long long unsigned int granPos){ long long unsigned int header::parseGranuleUpper(long long unsigned int granPos){
return granPos >> getKFGShift(); return granPos >> getKFGShift();
} }
long long unsigned int header::parseGranuleLower(long long unsigned int granPos){
return (granPos & ((1 << getKFGShift()) - 1));
}*/
/*
std::string frame::toPrettyString(size_t indent){
std::stringstream result;
result << std::string(indent, ' ') << "Theora Frame" << std::endl;
result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl;
return result.str();
}*/
}
long long unsigned int header::parseGranuleLower(long long unsigned int granPos){
return (granPos & ((1 << getKFGShift()) - 1));
}*/
/*
std::string frame::toPrettyString(size_t indent){
std::stringstream result;
result << std::string(indent, ' ') << "Theora Frame" << std::endl;
result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl;
return result.str();
}*/
}// namespace theora

View file

@ -1,56 +1,57 @@
#pragma once #pragma once
#include<sys/types.h> #include <stdint.h>
#include<stdint.h> #include <string>
#include<string> #include <sys/types.h>
namespace theora { namespace theora{
bool isHeader(const char * newData, unsigned int length); bool isHeader(const char *newData, unsigned int length);
class header { class header{
public: public:
~header(); ~header();
header(char * newData, unsigned int length); // if managed is true, this class manages the data pointer header(char *newData, unsigned int length); // if managed is true, this class manages the data pointer
int getHeaderType(); int getHeaderType();
char getVMAJ(); char getVMAJ();
char getVMIN(); char getVMIN();
char getVREV(); char getVREV();
short getFMBW(); short getFMBW();
short getFMBH(); short getFMBH();
long unsigned int getPICW();//movie width long unsigned int getPICW(); // movie width
long unsigned int getPICH();//movie height long unsigned int getPICH(); // movie height
char getPICX(); char getPICX();
char getPICY(); char getPICY();
long unsigned int getFRN();//frame rate numerator long unsigned int getFRN(); // frame rate numerator
long unsigned int getFRD();//frame rate denominator long unsigned int getFRD(); // frame rate denominator
long unsigned int getPARN(); long unsigned int getPARN();
long unsigned int getPARD(); long unsigned int getPARD();
char getCS(); char getCS();
long unsigned int getNOMBR(); long unsigned int getNOMBR();
char getQUAL(); char getQUAL();
char getPF(); char getPF();
char getKFGShift(); char getKFGShift();
std::string getVendor(); std::string getVendor();
long unsigned int getNComments(); long unsigned int getNComments();
std::string getUserComment(size_t index); std::string getUserComment(size_t index);
char getLFLIMS(size_t index); char getLFLIMS(size_t index);
std::string toPrettyString(size_t indent = 0); //update this, it should check (header) type and output relevant stuff only. std::string toPrettyString(size_t indent = 0); // update this, it should check (header) type and output relevant stuff only.
//long long unsigned int parseGranuleUpper(long long unsigned int granPos); // long long unsigned int parseGranuleUpper(long long unsigned int granPos);
//long long unsigned int parseGranuleLower(long long unsigned int granPos); // long long unsigned int parseGranuleLower(long long unsigned int granPos);
///\todo put this back in pravate ///\todo put this back in pravate
unsigned int datasize; unsigned int datasize;
bool isHeader(); bool isHeader();
char getFTYPE();//for frames char getFTYPE(); // for frames
protected: protected:
uint32_t getInt32(size_t index); uint32_t getInt32(size_t index);
uint32_t getInt24(size_t index); uint32_t getInt24(size_t index);
uint16_t getInt16(size_t index); uint16_t getInt16(size_t index);
uint32_t commentLen(size_t index); uint32_t commentLen(size_t index);
private:
char * data; private:
bool checkDataSize(unsigned int size); char *data;
bool checkDataSize(unsigned int size);
}; };
/* /*
class frame{ // we don't need this. I hope. class frame{// we don't need this. I hope.
public: public:
frame(); frame();
~frame(); ~frame();
@ -64,5 +65,4 @@ namespace theora {
unsigned int datasize; unsigned int datasize;
bool checkDataSize(unsigned int size); bool checkDataSize(unsigned int size);
};*/ };*/
} }// namespace theora

View file

@ -2,18 +2,18 @@
/// Utilities for handling time and timestamps. /// Utilities for handling time and timestamps.
#include "timing.h" #include "timing.h"
#include <sys/time.h>//for gettimeofday
#include <time.h>//for time and nanosleep
#include <cstring>
#include <cstdio> #include <cstdio>
#include <cstring>
#include <sys/time.h> //for gettimeofday
#include <time.h> //for time and nanosleep
//emulate clock_gettime() for OSX compatibility // emulate clock_gettime() for OSX compatibility
#if defined(__APPLE__) || defined(__MACH__) #if defined(__APPLE__) || defined(__MACH__)
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/mach.h> #include <mach/mach.h>
#define CLOCK_REALTIME CALENDAR_CLOCK #define CLOCK_REALTIME CALENDAR_CLOCK
#define CLOCK_MONOTONIC SYSTEM_CLOCK #define CLOCK_MONOTONIC SYSTEM_CLOCK
void clock_gettime(int ign, struct timespec * ts) { void clock_gettime(int ign, struct timespec *ts){
clock_serv_t cclock; clock_serv_t cclock;
mach_timespec_t mts; mach_timespec_t mts;
host_get_clock_service(mach_host_self(), ign, &cclock); host_get_clock_service(mach_host_self(), ign, &cclock);
@ -30,16 +30,12 @@ void clock_gettime(int ign, struct timespec * ts) {
/// 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(int64_t ms){ void Util::wait(int64_t ms){
if (ms < 0) { if (ms < 0){return;}
return; if (ms > 600000){ms = 600000;}
}
if (ms > 600000) {
ms = 600000;
}
uint64_t start = getMS(); uint64_t start = getMS();
uint64_t 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,39 +45,35 @@ void Util::wait(int64_t 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(int64_t ms) { void Util::sleep(int64_t ms){
if (ms < 0) { if (ms < 0){return;}
return; if (ms > 100000){ms = 100000;}
}
if (ms > 100000) {
ms = 100000;
}
struct timespec T; struct timespec T;
T.tv_sec = ms / 1000; T.tv_sec = ms / 1000;
T.tv_nsec = 1000000 * (ms % 1000); T.tv_nsec = 1000000 * (ms % 1000);
nanosleep(&T, 0); nanosleep(&T, 0);
} }
uint64_t Util::getNTP() { uint64_t Util::getNTP(){
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return ((uint64_t)(t.tv_sec + 2208988800ull) << 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.
uint64_t Util::getMS() { uint64_t Util::getMS(){
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return (uint64_t)t.tv_sec * 1000 + t.tv_nsec / 1000000; return (uint64_t)t.tv_sec * 1000 + t.tv_nsec / 1000000;
} }
uint64_t 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;
} }
uint64_t Util::bootMS() { uint64_t Util::bootMS(){
struct timespec t; struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t); clock_gettime(CLOCK_MONOTONIC, &t);
return ((uint64_t)t.tv_sec) * 1000 + t.tv_nsec / 1000000; return ((uint64_t)t.tv_sec) * 1000 + t.tv_nsec / 1000000;
@ -94,30 +86,31 @@ uint64_t Util::unixMS(){
} }
/// Gets the current time in microseconds. /// Gets the current time in microseconds.
uint64_t Util::getMicros() { uint64_t Util::getMicros(){
struct timespec t; struct timespec t;
clock_gettime(CLOCK_REALTIME, &t); clock_gettime(CLOCK_REALTIME, &t);
return (uint64_t)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.
uint64_t Util::getMicros(uint64_t 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 (uint64_t)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.
uint64_t Util::epoch() { uint64_t Util::epoch(){
return time(0); return time(0);
} }
std::string Util::getUTCString(uint64_t 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, "%.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); 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

@ -4,10 +4,9 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <stdint.h>
namespace Util { namespace Util{
void wait(int64_t 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(int64_t ms); ///< Sleeps for roughly the indicated amount of milliseconds. void sleep(int64_t ms); ///< Sleeps for roughly the indicated amount of milliseconds.
uint64_t getMS(); ///< Gets the current time in milliseconds. uint64_t getMS(); ///< Gets the current time in milliseconds.
uint64_t bootSecs(); ///< Gets the current system uptime in seconds. uint64_t bootSecs(); ///< Gets the current system uptime in seconds.
@ -18,4 +17,4 @@ namespace Util {
uint64_t getNTP(); uint64_t getNTP();
uint64_t 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(uint64_t epoch = 0); std::string getUTCString(uint64_t epoch = 0);
} }// namespace Util

View file

@ -21,32 +21,31 @@ freely, subject to the following restrictions:
distribution. distribution.
*/ */
#include <exception>
#include "tinythread.h" #include "tinythread.h"
#include <exception>
#if defined(_TTHREAD_POSIX_) #if defined(_TTHREAD_POSIX_)
#include <unistd.h>
#include <map> #include <map>
#include <unistd.h>
#elif defined(_TTHREAD_WIN32_) #elif defined(_TTHREAD_WIN32_)
#include <process.h> #include <process.h>
#endif #endif
namespace tthread{
namespace tthread { //------------------------------------------------------------------------------
// condition_variable
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// condition_variable // NOTE 1: The Win32 implementation of the condition_variable class is based on
//------------------------------------------------------------------------------ // the corresponding implementation in GLFW, which in turn is based on a
// NOTE 1: The Win32 implementation of the condition_variable class is based on // description by Douglas C. Schmidt and Irfan Pyarali:
// the corresponding implementation in GLFW, which in turn is based on a // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
// description by Douglas C. Schmidt and Irfan Pyarali: //
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html // NOTE 2: Windows Vista actually has native support for condition variables
// // (InitializeConditionVariable, WakeConditionVariable, etc), but we want to
// NOTE 2: Windows Vista actually has native support for condition variables // be portable with pre-Vista Windows versions, so TinyThread++ does not use
// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to // Vista condition variables.
// be portable with pre-Vista Windows versions, so TinyThread++ does not use //------------------------------------------------------------------------------
// Vista condition variables.
//------------------------------------------------------------------------------
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
#define _CONDITION_EVENT_ONE 0 #define _CONDITION_EVENT_ONE 0
@ -54,7 +53,7 @@ namespace tthread {
#endif #endif
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
condition_variable::condition_variable() : mWaitersCount(0) { condition_variable::condition_variable() : mWaitersCount(0){
mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
InitializeCriticalSection(&mWaitersCountLock); InitializeCriticalSection(&mWaitersCountLock);
@ -62,7 +61,7 @@ namespace tthread {
#endif #endif
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
condition_variable::~condition_variable() { condition_variable::~condition_variable(){
CloseHandle(mEvents[_CONDITION_EVENT_ONE]); CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
CloseHandle(mEvents[_CONDITION_EVENT_ALL]); CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
DeleteCriticalSection(&mWaitersCountLock); DeleteCriticalSection(&mWaitersCountLock);
@ -70,104 +69,97 @@ namespace tthread {
#endif #endif
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
void condition_variable::_wait() { void condition_variable::_wait(){
// Wait for either event to become signaled due to notify_one() or // Wait for either event to become signaled due to notify_one() or
// notify_all() being called // notify_all() being called
int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
// Check if we are the last waiter // Check if we are the last waiter
EnterCriticalSection(&mWaitersCountLock); EnterCriticalSection(&mWaitersCountLock);
-- mWaitersCount; --mWaitersCount;
bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && (mWaitersCount == 0);
(mWaitersCount == 0);
LeaveCriticalSection(&mWaitersCountLock); LeaveCriticalSection(&mWaitersCountLock);
// If we are the last waiter to be notified to stop waiting, reset the event // If we are the last waiter to be notified to stop waiting, reset the event
if (lastWaiter) if (lastWaiter) ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
} }
#endif #endif
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
void condition_variable::notify_one() { void condition_variable::notify_one(){
// Are there any waiters? // Are there any waiters?
EnterCriticalSection(&mWaitersCountLock); EnterCriticalSection(&mWaitersCountLock);
bool haveWaiters = (mWaitersCount > 0); bool haveWaiters = (mWaitersCount > 0);
LeaveCriticalSection(&mWaitersCountLock); LeaveCriticalSection(&mWaitersCountLock);
// If we have any waiting threads, send them a signal // If we have any waiting threads, send them a signal
if (haveWaiters) if (haveWaiters) SetEvent(mEvents[_CONDITION_EVENT_ONE]);
SetEvent(mEvents[_CONDITION_EVENT_ONE]);
} }
#endif #endif
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
void condition_variable::notify_all() { void condition_variable::notify_all(){
// Are there any waiters? // Are there any waiters?
EnterCriticalSection(&mWaitersCountLock); EnterCriticalSection(&mWaitersCountLock);
bool haveWaiters = (mWaitersCount > 0); bool haveWaiters = (mWaitersCount > 0);
LeaveCriticalSection(&mWaitersCountLock); LeaveCriticalSection(&mWaitersCountLock);
// If we have any waiting threads, send them a signal // If we have any waiting threads, send them a signal
if (haveWaiters) if (haveWaiters) SetEvent(mEvents[_CONDITION_EVENT_ALL]);
SetEvent(mEvents[_CONDITION_EVENT_ALL]);
} }
#endif #endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------ // POSIX pthread_t to unique thread::id mapping logic.
// POSIX pthread_t to unique thread::id mapping logic. // Note: Here we use a global thread safe std::map to convert instances of
// Note: Here we use a global thread safe std::map to convert instances of // pthread_t to small thread identifier numbers (unique within one process).
// pthread_t to small thread identifier numbers (unique within one process). // This method should be portable across different POSIX implementations.
// This method should be portable across different POSIX implementations. //------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#if defined(_TTHREAD_POSIX_) #if defined(_TTHREAD_POSIX_)
static thread::id _pthread_t_to_ID(const pthread_t & aHandle) { static thread::id _pthread_t_to_ID(const pthread_t &aHandle){
static mutex idMapLock; static mutex idMapLock;
static std::map<pthread_t, unsigned long int> idMap; static std::map<pthread_t, unsigned long int> idMap;
static unsigned long int idCount(1); static unsigned long int idCount(1);
lock_guard<mutex> guard(idMapLock); lock_guard<mutex> guard(idMapLock);
if (idMap.find(aHandle) == idMap.end()) if (idMap.find(aHandle) == idMap.end()) idMap[aHandle] = idCount++;
idMap[aHandle] = idCount ++;
return thread::id(idMap[aHandle]); return thread::id(idMap[aHandle]);
} }
#endif // _TTHREAD_POSIX_ #endif // _TTHREAD_POSIX_
//------------------------------------------------------------------------------
// thread
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------ /// Information to pass to the new thread (what to run).
// thread struct _thread_start_info{
//------------------------------------------------------------------------------
/// Information to pass to the new thread (what to run).
struct _thread_start_info {
void (*mFunction)(void *); ///< Pointer to the function to be executed. void (*mFunction)(void *); ///< Pointer to the function to be executed.
void * mArg; ///< Function argument for the thread function. void *mArg; ///< Function argument for the thread function.
thread * mThread; ///< Pointer to the thread object. thread *mThread; ///< Pointer to the thread object.
}; };
// Thread wrapper function. // Thread wrapper function.
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
unsigned WINAPI thread::wrapper_function(void * aArg) unsigned WINAPI thread::wrapper_function(void *aArg)
#elif defined(_TTHREAD_POSIX_) #elif defined(_TTHREAD_POSIX_)
void * thread::wrapper_function(void * aArg) void *thread::wrapper_function(void *aArg)
#endif #endif
{ {
// Get thread startup information // Get thread startup information
_thread_start_info * ti = (_thread_start_info *) aArg; _thread_start_info *ti = (_thread_start_info *)aArg;
//try { // try{
// Call the actual client thread function // Call the actual client thread function
ti->mFunction(ti->mArg); ti->mFunction(ti->mArg);
//} catch (...) { //}catch (...){
// Uncaught exceptions will terminate the application (default behavior // Uncaught exceptions will terminate the application (default behavior
// according to C++11) // according to C++11)
//std::terminate(); // std::terminate();
//} //}
// The thread is no longer executing // The thread is no longer executing
if (ti->mThread) { if (ti->mThread){
lock_guard<mutex> guard(ti->mThread->mDataMutex); lock_guard<mutex> guard(ti->mThread->mDataMutex);
if (ti->mThread){ if (ti->mThread){
ti->mThread->mNotAThread = true; ti->mThread->mNotAThread = true;
@ -181,13 +173,13 @@ namespace tthread {
return 0; return 0;
} }
thread::thread(void (*aFunction)(void *), void * aArg) { thread::thread(void (*aFunction)(void *), void *aArg){
// Serialize access to this thread structure // Serialize access to this thread structure
lock_guard<mutex> guard(mDataMutex); lock_guard<mutex> guard(mDataMutex);
// Fill out the thread startup information (passed to the thread wrapper, // Fill out the thread startup information (passed to the thread wrapper,
// which will eventually free it) // which will eventually free it)
_thread_start_info * ti = new _thread_start_info; _thread_start_info *ti = new _thread_start_info;
ti_copy = ti; ti_copy = ti;
ti->mFunction = aFunction; ti->mFunction = aFunction;
ti->mArg = aArg; ti->mArg = aArg;
@ -198,30 +190,26 @@ namespace tthread {
// Create the thread // Create the thread
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); mHandle = (HANDLE)_beginthreadex(0, 0, wrapper_function, (void *)ti, 0, &mWin32ThreadID);
#elif defined(_TTHREAD_POSIX_) #elif defined(_TTHREAD_POSIX_)
if (pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) if (pthread_create(&mHandle, NULL, wrapper_function, (void *)ti) != 0) mHandle = 0;
mHandle = 0;
#endif #endif
// Did we fail to create the thread? // Did we fail to create the thread?
if (!mHandle) { if (!mHandle){
mNotAThread = true; mNotAThread = true;
ti_copy = 0; ti_copy = 0;
delete ti; delete ti;
} }
} }
thread::~thread() { thread::~thread(){
if (ti_copy) { if (ti_copy){((_thread_start_info *)ti_copy)->mThread = 0;}
((_thread_start_info *)ti_copy)->mThread = 0; if (joinable()) std::terminate();
}
if (joinable())
std::terminate();
} }
void thread::join() { void thread::join(){
if (joinable()) { if (joinable()){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
WaitForSingleObject(mHandle, INFINITE); WaitForSingleObject(mHandle, INFINITE);
CloseHandle(mHandle); CloseHandle(mHandle);
@ -231,16 +219,16 @@ namespace tthread {
} }
} }
bool thread::joinable() const { bool thread::joinable() const{
mDataMutex.lock(); mDataMutex.lock();
bool result = !mNotAThread; bool result = !mNotAThread;
mDataMutex.unlock(); mDataMutex.unlock();
return result; return result;
} }
void thread::detach() { void thread::detach(){
mDataMutex.lock(); mDataMutex.lock();
if (!mNotAThread) { if (!mNotAThread){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
CloseHandle(mHandle); CloseHandle(mHandle);
#elif defined(_TTHREAD_POSIX_) #elif defined(_TTHREAD_POSIX_)
@ -251,25 +239,24 @@ namespace tthread {
mDataMutex.unlock(); mDataMutex.unlock();
} }
thread::id thread::get_id() const { thread::id thread::get_id() const{
if (!joinable()) if (!joinable()) return id();
return id();
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
return id((unsigned long int) mWin32ThreadID); return id((unsigned long int)mWin32ThreadID);
#elif defined(_TTHREAD_POSIX_) #elif defined(_TTHREAD_POSIX_)
return _pthread_t_to_ID(mHandle); return _pthread_t_to_ID(mHandle);
#endif #endif
} }
unsigned thread::hardware_concurrency() { unsigned thread::hardware_concurrency(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
SYSTEM_INFO si; SYSTEM_INFO si;
GetSystemInfo(&si); GetSystemInfo(&si);
return (int) si.dwNumberOfProcessors; return (int)si.dwNumberOfProcessors;
#elif defined(_SC_NPROCESSORS_ONLN) #elif defined(_SC_NPROCESSORS_ONLN)
return (int) sysconf(_SC_NPROCESSORS_ONLN); return (int)sysconf(_SC_NPROCESSORS_ONLN);
#elif defined(_SC_NPROC_ONLN) #elif defined(_SC_NPROC_ONLN)
return (int) sysconf(_SC_NPROC_ONLN); return (int)sysconf(_SC_NPROC_ONLN);
#else #else
// The standard requires this function to return zero if the number of // The standard requires this function to return zero if the number of
// hardware cores could not be determined. // hardware cores could not be determined.
@ -277,17 +264,16 @@ namespace tthread {
#endif #endif
} }
//------------------------------------------------------------------------------
// this_thread
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------ thread::id this_thread::get_id(){
// this_thread
//------------------------------------------------------------------------------
thread::id this_thread::get_id() {
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
return thread::id((unsigned long int) GetCurrentThreadId()); return thread::id((unsigned long int)GetCurrentThreadId());
#elif defined(_TTHREAD_POSIX_) #elif defined(_TTHREAD_POSIX_)
return _pthread_t_to_ID(pthread_self()); return _pthread_t_to_ID(pthread_self());
#endif #endif
} }
} }// namespace tthread

View file

@ -78,8 +78,8 @@ freely, subject to the following restrictions:
#endif #endif
#else #else
#include <pthread.h> #include <pthread.h>
#include <signal.h>
#include <sched.h> #include <sched.h>
#include <signal.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -105,13 +105,13 @@ freely, subject to the following restrictions:
// Macro for disabling assignments of objects. // Macro for disabling assignments of objects.
#ifdef _TTHREAD_CPP11_PARTIAL_ #ifdef _TTHREAD_CPP11_PARTIAL_
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \ #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
name(const name&) = delete; \ name(const name &) = delete; \
name& operator=(const name&) = delete; name &operator=(const name &) = delete;
#else #else
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \ #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
name(const name&); \ name(const name &); \
name& operator=(const name&); name &operator=(const name &);
#endif #endif
/// @def thread_local /// @def thread_local
@ -143,518 +143,489 @@ freely, subject to the following restrictions:
#endif #endif
#endif #endif
/// Main name space for TinyThread++. /// Main name space for TinyThread++.
/// This namespace is more or less equivalent to the @c std namespace for the /// This namespace is more or less equivalent to the @c std namespace for the
/// C++11 thread classes. For instance, the tthread::mutex class corresponds to /// C++11 thread classes. For instance, the tthread::mutex class corresponds to
/// the std::mutex class. /// the std::mutex class.
namespace tthread { namespace tthread{
/// Mutex class. /// Mutex class.
/// This is a mutual exclusion object for synchronizing access to shared /// This is a mutual exclusion object for synchronizing access to shared
/// memory areas for several threads. The mutex is non-recursive (i.e. a /// memory areas for several threads. The mutex is non-recursive (i.e. a
/// program may deadlock if the thread that owns a mutex object calls lock() /// program may deadlock if the thread that owns a mutex object calls lock()
/// on that object). /// on that object).
/// @see recursive_mutex /// @see recursive_mutex
class mutex { class mutex{
public: public:
/// Constructor. /// Constructor.
mutex() mutex()
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
: mAlreadyLocked(false) : mAlreadyLocked(false)
#endif #endif
{ {
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
InitializeCriticalSection(&mHandle); InitializeCriticalSection(&mHandle);
#else #else
pthread_mutex_init(&mHandle, NULL); pthread_mutex_init(&mHandle, NULL);
#endif #endif
} }
/// Destructor. /// Destructor.
~mutex() { ~mutex(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
DeleteCriticalSection(&mHandle); DeleteCriticalSection(&mHandle);
#else #else
pthread_mutex_destroy(&mHandle); pthread_mutex_destroy(&mHandle);
#endif #endif
} }
/// Lock the mutex. /// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can /// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until @c unlock() is called. /// be obtained. The mutex remains locked until @c unlock() is called.
/// @see lock_guard /// @see lock_guard
inline void lock() { inline void lock(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
EnterCriticalSection(&mHandle); EnterCriticalSection(&mHandle);
while (mAlreadyLocked) Sleep(1000); // Simulate deadlock... while (mAlreadyLocked) Sleep(1000); // Simulate deadlock...
mAlreadyLocked = true; mAlreadyLocked = true;
#else #else
pthread_mutex_lock(&mHandle); pthread_mutex_lock(&mHandle);
#endif #endif
} }
/// Try to lock the mutex. /// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will /// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking). /// return immediately (non-blocking).
/// @return @c true if the lock was acquired, or @c false if the lock could /// @return @c true if the lock was acquired, or @c false if the lock could
/// not be acquired. /// not be acquired.
inline bool try_lock() { inline bool try_lock(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
if (ret && mAlreadyLocked) { if (ret && mAlreadyLocked){
LeaveCriticalSection(&mHandle);
ret = false;
}
return ret;
#else
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
#endif
}
/// Unlock the mutex.
/// If any threads are waiting for the lock on this mutex, one of them will
/// be unblocked.
inline void unlock() {
#if defined(_TTHREAD_WIN32_)
mAlreadyLocked = false;
LeaveCriticalSection(&mHandle); LeaveCriticalSection(&mHandle);
#else ret = false;
pthread_mutex_unlock(&mHandle);
#endif
} }
return ret;
_TTHREAD_DISABLE_ASSIGNMENT(mutex)
private:
#if defined(_TTHREAD_WIN32_)
CRITICAL_SECTION mHandle;
bool mAlreadyLocked;
#else #else
pthread_mutex_t mHandle; return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
#endif
}
/// Unlock the mutex.
/// If any threads are waiting for the lock on this mutex, one of them will
/// be unblocked.
inline void unlock(){
#if defined(_TTHREAD_WIN32_)
mAlreadyLocked = false;
LeaveCriticalSection(&mHandle);
#else
pthread_mutex_unlock(&mHandle);
#endif
}
_TTHREAD_DISABLE_ASSIGNMENT(mutex)
private:
#if defined(_TTHREAD_WIN32_)
CRITICAL_SECTION mHandle;
bool mAlreadyLocked;
#else
pthread_mutex_t mHandle;
#endif #endif
friend class condition_variable; friend class condition_variable;
}; };
/// Recursive mutex class. /// Recursive mutex class.
/// This is a mutual exclusion object for synchronizing access to shared /// This is a mutual exclusion object for synchronizing access to shared
/// memory areas for several threads. The mutex is recursive (i.e. a thread /// memory areas for several threads. The mutex is recursive (i.e. a thread
/// may lock the mutex several times, as long as it unlocks the mutex the same /// may lock the mutex several times, as long as it unlocks the mutex the same
/// number of times). /// number of times).
/// @see mutex /// @see mutex
class recursive_mutex { class recursive_mutex{
public: public:
/// Constructor. /// Constructor.
recursive_mutex() { recursive_mutex(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
InitializeCriticalSection(&mHandle); InitializeCriticalSection(&mHandle);
#else #else
pthread_mutexattr_t attr; pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mHandle, &attr); pthread_mutex_init(&mHandle, &attr);
#endif #endif
} }
/// Destructor. /// Destructor.
~recursive_mutex() { ~recursive_mutex(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
DeleteCriticalSection(&mHandle); DeleteCriticalSection(&mHandle);
#else #else
pthread_mutex_destroy(&mHandle); pthread_mutex_destroy(&mHandle);
#endif #endif
} }
/// Lock the mutex. /// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can /// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until @c unlock() is called. /// be obtained. The mutex remains locked until @c unlock() is called.
/// @see lock_guard /// @see lock_guard
inline void lock() { inline void lock(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
EnterCriticalSection(&mHandle); EnterCriticalSection(&mHandle);
#else #else
pthread_mutex_lock(&mHandle); pthread_mutex_lock(&mHandle);
#endif #endif
} }
/// Try to lock the mutex. /// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will /// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking). /// return immediately (non-blocking).
/// @return @c true if the lock was acquired, or @c false if the lock could /// @return @c true if the lock was acquired, or @c false if the lock could
/// not be acquired. /// not be acquired.
inline bool try_lock() { inline bool try_lock(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
return TryEnterCriticalSection(&mHandle) ? true : false; return TryEnterCriticalSection(&mHandle) ? true : false;
#else #else
return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
#endif #endif
} }
/// Unlock the mutex. /// Unlock the mutex.
/// If any threads are waiting for the lock on this mutex, one of them will /// If any threads are waiting for the lock on this mutex, one of them will
/// be unblocked. /// be unblocked.
inline void unlock() { inline void unlock(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
LeaveCriticalSection(&mHandle); LeaveCriticalSection(&mHandle);
#else #else
pthread_mutex_unlock(&mHandle); pthread_mutex_unlock(&mHandle);
#endif #endif
} }
_TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
private: private:
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
CRITICAL_SECTION mHandle; CRITICAL_SECTION mHandle;
#else #else
pthread_mutex_t mHandle; pthread_mutex_t mHandle;
#endif #endif
friend class condition_variable; friend class condition_variable;
}; };
/// Lock guard class. /// Lock guard class.
/// The constructor locks the mutex, and the destructor unlocks the mutex, so /// The constructor locks the mutex, and the destructor unlocks the mutex, so
/// the mutex will automatically be unlocked when the lock guard goes out of /// the mutex will automatically be unlocked when the lock guard goes out of
/// scope. Example usage: /// scope. Example usage:
/// @code /// @code
/// mutex m; /// mutex m;
/// int counter; /// int counter;
/// ///
/// void increment() /// void increment()
/// { ///{
/// lock_guard<mutex> guard(m); /// lock_guard<mutex> guard(m);
/// ++ counter; /// ++ counter;
/// } ///}
/// @endcode /// @endcode
template <class T> template <class T> class lock_guard{
class lock_guard { public:
public: typedef T mutex_type;
typedef T mutex_type;
lock_guard() : mMutex(0) {} lock_guard() : mMutex(0){}
/// The constructor locks the mutex. /// The constructor locks the mutex.
explicit lock_guard(mutex_type & aMutex) { explicit lock_guard(mutex_type &aMutex){
mMutex = &aMutex; mMutex = &aMutex;
mMutex->lock(); mMutex->lock();
} }
/// The destructor unlocks the mutex. /// The destructor unlocks the mutex.
~lock_guard() { ~lock_guard(){
if (mMutex) if (mMutex) mMutex->unlock();
mMutex->unlock(); }
}
private: private:
mutex_type * mMutex; mutex_type *mMutex;
}; };
/// Condition variable class. /// Condition variable class.
/// This is a signalling object for synchronizing the execution flow for /// This is a signalling object for synchronizing the execution flow for
/// several threads. Example usage: /// several threads. Example usage:
/// @code /// @code
/// // Shared data and associated mutex and condition variable objects /// // Shared data and associated mutex and condition variable objects
/// int count; /// int count;
/// mutex m; /// mutex m;
/// condition_variable cond; /// condition_variable cond;
/// ///
/// // Wait for the counter to reach a certain number /// // Wait for the counter to reach a certain number
/// void wait_counter(int targetCount) /// void wait_counter(int targetCount)
/// { ///{
/// lock_guard<mutex> guard(m); /// lock_guard<mutex> guard(m);
/// while(count < targetCount) /// while(count < targetCount)
/// cond.wait(m); /// cond.wait(m);
/// } ///}
/// ///
/// // Increment the counter, and notify waiting threads /// // Increment the counter, and notify waiting threads
/// void increment() /// void increment()
/// { ///{
/// lock_guard<mutex> guard(m); /// lock_guard<mutex> guard(m);
/// ++ count; /// ++ count;
/// cond.notify_all(); /// cond.notify_all();
/// } ///}
/// @endcode /// @endcode
class condition_variable { class condition_variable{
public: public:
/// Constructor. /// Constructor.
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
condition_variable(); condition_variable();
#else #else
condition_variable() { condition_variable(){pthread_cond_init(&mHandle, NULL);}
pthread_cond_init(&mHandle, NULL);
}
#endif #endif
/// Destructor. /// Destructor.
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
~condition_variable(); ~condition_variable();
#else #else
~condition_variable() { ~condition_variable(){pthread_cond_destroy(&mHandle);}
pthread_cond_destroy(&mHandle);
}
#endif #endif
/// Wait for the condition. /// Wait for the condition.
/// The function will block the calling thread until the condition variable /// The function will block the calling thread until the condition variable
/// is woken by @c notify_one(), @c notify_all() or a spurious wake up. /// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
/// @param[in] aMutex A mutex that will be unlocked when the wait operation /// @param[in] aMutex A mutex that will be unlocked when the wait operation
/// starts, an locked again as soon as the wait operation is finished. /// starts, an locked again as soon as the wait operation is finished.
template <class _mutexT> template <class _mutexT> inline void wait(_mutexT &aMutex){
inline void wait(_mutexT & aMutex) {
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
// Increment number of waiters // Increment number of waiters
EnterCriticalSection(&mWaitersCountLock); EnterCriticalSection(&mWaitersCountLock);
++ mWaitersCount; ++mWaitersCount;
LeaveCriticalSection(&mWaitersCountLock); LeaveCriticalSection(&mWaitersCountLock);
// Release the mutex while waiting for the condition (will decrease // Release the mutex while waiting for the condition (will decrease
// the number of waiters when done)... // the number of waiters when done)...
aMutex.unlock(); aMutex.unlock();
_wait(); _wait();
aMutex.lock(); aMutex.lock();
#else #else
pthread_cond_wait(&mHandle, &aMutex.mHandle); pthread_cond_wait(&mHandle, &aMutex.mHandle);
#endif #endif
} }
/// Notify one thread that is waiting for the condition. /// Notify one thread that is waiting for the condition.
/// If at least one thread is blocked waiting for this condition variable, /// If at least one thread is blocked waiting for this condition variable,
/// one will be woken up. /// one will be woken up.
/// @note Only threads that started waiting prior to this call will be /// @note Only threads that started waiting prior to this call will be
/// woken up. /// woken up.
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
void notify_one(); void notify_one();
#else #else
inline void notify_one() { inline void notify_one(){pthread_cond_signal(&mHandle);}
pthread_cond_signal(&mHandle);
}
#endif #endif
/// Notify all threads that are waiting for the condition. /// Notify all threads that are waiting for the condition.
/// All threads that are blocked waiting for this condition variable will /// All threads that are blocked waiting for this condition variable will
/// be woken up. /// be woken up.
/// @note Only threads that started waiting prior to this call will be /// @note Only threads that started waiting prior to this call will be
/// woken up. /// woken up.
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
void notify_all(); void notify_all();
#else #else
inline void notify_all() { inline void notify_all(){pthread_cond_broadcast(&mHandle);}
pthread_cond_broadcast(&mHandle);
}
#endif #endif
_TTHREAD_DISABLE_ASSIGNMENT(condition_variable) _TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
private: private:
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
void _wait(); void _wait();
HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs.
unsigned int mWaitersCount; ///< Count of the number of waiters. unsigned int mWaitersCount; ///< Count of the number of waiters.
CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
#else #else
pthread_cond_t mHandle; pthread_cond_t mHandle;
#endif #endif
}; };
/// Thread class.
/// Thread class. class thread{
class thread { public:
public:
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
typedef HANDLE native_handle_type; typedef HANDLE native_handle_type;
#else #else
typedef pthread_t native_handle_type; typedef pthread_t native_handle_type;
#endif #endif
class id; class id;
/// Default constructor. /// Default constructor.
/// Construct a @c thread object without an associated thread of execution /// Construct a @c thread object without an associated thread of execution
/// (i.e. non-joinable). /// (i.e. non-joinable).
thread() : mHandle(0), mNotAThread(true) thread()
: mHandle(0), mNotAThread(true)
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
, mWin32ThreadID(0) ,
mWin32ThreadID(0)
#endif #endif
{} {
}
/// Thread starting constructor. /// Thread starting constructor.
/// Construct a @c thread object with a new thread of execution. /// Construct a @c thread object with a new thread of execution.
/// @param[in] aFunction A function pointer to a function of type: /// @param[in] aFunction A function pointer to a function of type:
/// <tt>void fun(void * arg)</tt> /// <tt>void fun(void * arg)</tt>
/// @param[in] aArg Argument to the thread function. /// @param[in] aArg Argument to the thread function.
/// @note This constructor is not fully compatible with the standard C++ /// @note This constructor is not fully compatible with the standard C++
/// thread class. It is more similar to the pthread_create() (POSIX) and /// thread class. It is more similar to the pthread_create() (POSIX) and
/// CreateThread() (Windows) functions. /// CreateThread() (Windows) functions.
thread(void (*aFunction)(void *), void * aArg); thread(void (*aFunction)(void *), void *aArg);
/// Destructor. /// Destructor.
/// @note If the thread is joinable upon destruction, @c std::terminate() /// @note If the thread is joinable upon destruction, @c std::terminate()
/// will be called, which terminates the process. It is always wise to do /// will be called, which terminates the process. It is always wise to do
/// @c join() before deleting a thread object. /// @c join() before deleting a thread object.
~thread(); ~thread();
/// Wait for the thread to finish (join execution flows). /// Wait for the thread to finish (join execution flows).
/// After calling @c join(), the thread object is no longer associated with /// After calling @c join(), the thread object is no longer associated with
/// a thread of execution (i.e. it is not joinable, and you may not join /// a thread of execution (i.e. it is not joinable, and you may not join
/// with it nor detach from it). /// with it nor detach from it).
void join(); void join();
/// Check if the thread is joinable. /// Check if the thread is joinable.
/// A thread object is joinable if it has an associated thread of execution. /// A thread object is joinable if it has an associated thread of execution.
bool joinable() const; bool joinable() const;
/// Detach from the thread. /// Detach from the thread.
/// After calling @c detach(), the thread object is no longer assicated with /// After calling @c detach(), the thread object is no longer assicated with
/// a thread of execution (i.e. it is not joinable). The thread continues /// a thread of execution (i.e. it is not joinable). The thread continues
/// execution without the calling thread blocking, and when the thread /// execution without the calling thread blocking, and when the thread
/// ends execution, any owned resources are released. /// ends execution, any owned resources are released.
void detach(); void detach();
/// Return the thread ID of a thread object. /// Return the thread ID of a thread object.
id get_id() const; id get_id() const;
/// Get the native handle for this thread. /// Get the native handle for this thread.
/// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
/// is a @c pthread_t. /// is a @c pthread_t.
inline native_handle_type native_handle() { inline native_handle_type native_handle(){return mHandle;}
return mHandle;
}
/// Determine the number of threads which can possibly execute concurrently. /// Determine the number of threads which can possibly execute concurrently.
/// This function is useful for determining the optimal number of threads to /// This function is useful for determining the optimal number of threads to
/// use for a task. /// use for a task.
/// @return The number of hardware thread contexts in the system. /// @return The number of hardware thread contexts in the system.
/// @note If this value is not defined, the function returns zero (0). /// @note If this value is not defined, the function returns zero (0).
static unsigned hardware_concurrency(); static unsigned hardware_concurrency();
_TTHREAD_DISABLE_ASSIGNMENT(thread) _TTHREAD_DISABLE_ASSIGNMENT(thread)
private: private:
native_handle_type mHandle; ///< Thread handle. native_handle_type mHandle; ///< Thread handle.
mutable mutex mDataMutex; ///< Serializer for access to the thread private data. mutable mutex mDataMutex; ///< Serializer for access to the thread private data.
bool mNotAThread; ///< True if this object is not a thread of execution. bool mNotAThread; ///< True if this object is not a thread of execution.
void * ti_copy; void *ti_copy;
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex).
#endif #endif
// This is the internal thread wrapper function. // This is the internal thread wrapper function.
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
static unsigned WINAPI wrapper_function(void * aArg); static unsigned WINAPI wrapper_function(void *aArg);
#else #else
static void * wrapper_function(void * aArg); static void *wrapper_function(void *aArg);
#endif #endif
}; };
/// Thread ID. /// Thread ID.
/// The thread ID is a unique identifier for each thread. /// The thread ID is a unique identifier for each thread.
/// @see thread::get_id() /// @see thread::get_id()
class thread::id { class thread::id{
public: public:
/// Default constructor. /// Default constructor.
/// The default constructed ID is that of thread without a thread of /// The default constructed ID is that of thread without a thread of
/// execution. /// execution.
id() : mId(0) {}; id() : mId(0){};
id(unsigned long int aId) : mId(aId) {}; id(unsigned long int aId) : mId(aId){};
id(const id & aId) : mId(aId.mId) {}; id(const id &aId) : mId(aId.mId){};
inline id & operator=(const id & aId) { inline id &operator=(const id &aId){
mId = aId.mId; mId = aId.mId;
return *this; return *this;
} }
inline friend bool operator==(const id & aId1, const id & aId2) { inline friend bool operator==(const id &aId1, const id &aId2){return (aId1.mId == aId2.mId);}
return (aId1.mId == aId2.mId);
}
inline friend bool operator!=(const id & aId1, const id & aId2) { inline friend bool operator!=(const id &aId1, const id &aId2){return (aId1.mId != aId2.mId);}
return (aId1.mId != aId2.mId);
}
inline friend bool operator<=(const id & aId1, const id & aId2) { inline friend bool operator<=(const id &aId1, const id &aId2){return (aId1.mId <= aId2.mId);}
return (aId1.mId <= aId2.mId);
}
inline friend bool operator<(const id & aId1, const id & aId2) { inline friend bool operator<(const id &aId1, const id &aId2){return (aId1.mId < aId2.mId);}
return (aId1.mId < aId2.mId);
}
inline friend bool operator>=(const id & aId1, const id & aId2) { inline friend bool operator>=(const id &aId1, const id &aId2){return (aId1.mId >= aId2.mId);}
return (aId1.mId >= aId2.mId);
}
inline friend bool operator>(const id & aId1, const id & aId2) { inline friend bool operator>(const id &aId1, const id &aId2){return (aId1.mId > aId2.mId);}
return (aId1.mId > aId2.mId);
}
inline friend std::ostream & operator <<(std::ostream & os, const id & obj) { inline friend std::ostream &operator<<(std::ostream &os, const id &obj){
os << obj.mId; os << obj.mId;
return os; return os;
} }
private: private:
unsigned long int mId; unsigned long int mId;
}; };
// Related to <ratio> - minimal to be able to support chrono.
// Related to <ratio> - minimal to be able to support chrono.
typedef long long __intmax_t; typedef long long __intmax_t;
/// Minimal implementation of the @c ratio class. This class provides enough /// Minimal implementation of the @c ratio class. This class provides enough
/// functionality to implement some basic @c chrono classes. /// functionality to implement some basic @c chrono classes.
template <__intmax_t N, __intmax_t D = 1> class ratio { template <__intmax_t N, __intmax_t D = 1> class ratio{
public: public:
static double _as_double() { static double _as_double(){return double(N) / double(D);}
return double(N) / double(D);
}
}; };
/// Minimal implementation of the @c chrono namespace. /// Minimal implementation of the @c chrono namespace.
/// The @c chrono namespace provides types for specifying time intervals. /// The @c chrono namespace provides types for specifying time intervals.
namespace chrono { namespace chrono{
/// Duration template class. This class provides enough functionality to /// Duration template class. This class provides enough functionality to
/// implement @c this_thread::sleep_for(). /// implement @c this_thread::sleep_for().
template <class _Rep, class _Period = ratio<1> > class duration { template <class _Rep, class _Period = ratio<1> > class duration{
private: private:
_Rep rep_; _Rep rep_;
public:
typedef _Rep rep;
typedef _Period period;
/// Construct a duration object with the given duration. public:
template <class _Rep2> typedef _Rep rep;
explicit duration(const _Rep2 & r) : rep_(r) {}; typedef _Period period;
/// Return the value of the duration object. /// Construct a duration object with the given duration.
rep count() const { template <class _Rep2> explicit duration(const _Rep2 &r) : rep_(r){};
return rep_;
} /// Return the value of the duration object.
rep count() const{return rep_;}
}; };
// Standard duration types. // Standard duration types.
typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds.
typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds.
typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds.
typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes.
typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
} }// namespace chrono
/// The namespace @c this_thread provides methods for dealing with the /// The namespace @c this_thread provides methods for dealing with the
/// calling thread. /// calling thread.
namespace this_thread { namespace this_thread{
/// Return the thread ID of the calling thread. /// Return the thread ID of the calling thread.
thread::id get_id(); thread::id get_id();
/// Yield execution to another thread. /// Yield execution to another thread.
/// Offers the operating system the opportunity to schedule another thread /// Offers the operating system the opportunity to schedule another thread
/// that is ready to run on the current processor. /// that is ready to run on the current processor.
inline void yield() { inline void yield(){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
Sleep(0); Sleep(0);
#else #else
@ -671,16 +642,17 @@ namespace tthread {
/// @endcode /// @endcode
/// @note Supported duration types are: nanoseconds, microseconds, /// @note Supported duration types are: nanoseconds, microseconds,
/// milliseconds, seconds, minutes and hours. /// milliseconds, seconds, minutes and hours.
template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period> & aTime) { template <class _Rep, class _Period>
void sleep_for(const chrono::duration<_Rep, _Period> &aTime){
#if defined(_TTHREAD_WIN32_) #if defined(_TTHREAD_WIN32_)
Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
#else #else
usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
#endif #endif
} }
} }// namespace this_thread
} }// namespace tthread
// Define/macro cleanup // Define/macro cleanup
#undef _TTHREAD_DISABLE_ASSIGNMENT #undef _TTHREAD_DISABLE_ASSIGNMENT

View file

@ -1,35 +1,37 @@
/// \page triggers Triggers /// \page triggers Triggers
/// \brief Listing of all available triggers and their payloads. /// \brief Listing of all available triggers and their payloads.
/// MistServer reports certain occurances as configurable triggers to a URL or executable. This page describes the triggers system in full. /// MistServer reports certain occurances as configurable triggers to a URL or executable. This page
/// describes the triggers system in full.
/// ///
/// Triggers are the preferred way of responding to server events. Each trigger has a name and a payload, and may be stream-specific or global. /// Triggers are the preferred way of responding to server events. Each trigger has a name and a
/// payload, and may be stream-specific or global.
/// ///
/// Triggers may be handled by a URL or an executable. If the handler contains ://, a HTTP URL is assumed. Otherwise, an executable is assumed. /// Triggers may be handled by a URL or an executable. If the handler contains ://, a HTTP URL is
/// If handled by an URL, a POST request is sent to the URL with an extra X-Trigger header containing the trigger name and the payload as the /// assumed. Otherwise, an executable is assumed. If handled by an URL, a POST request is sent to
/// POST body. /// the URL with an extra X-Trigger header containing the trigger name and the payload as the POST
/// If handled by an executable, it's started with the trigger name as its only argument, and the payload is piped into the executable over /// body. If handled by an executable, it's started with the trigger name as its only argument, and
/// standard input. /// the payload is piped into the executable over standard input.
/// ///
/// Currently, all triggers are handled asynchronously and responses (if any) are completely ignored. In the future this may change. /// Currently, all triggers are handled asynchronously and responses (if any) are completely
/// ignored. In the future this may change.
/// ///
#include "triggers.h" #include "bitfields.h" //for strToBool
#include "bitfields.h" //for strToBool #include "defines.h" //for FAIL_MSG and INFO_MSG
#include "defines.h" //for FAIL_MSG and INFO_MSG
#include "downloader.h" //for sending http request #include "downloader.h" //for sending http request
#include "procs.h" //for StartPiped #include "procs.h" //for StartPiped
#include "shared_memory.h" #include "shared_memory.h"
#include "util.h"
#include "timing.h" #include "timing.h"
#include "triggers.h"
#include "util.h"
#include <string.h> //for strncmp #include <string.h> //for strncmp
namespace Triggers{ namespace Triggers{
static void submitTriggerStat(const std::string trigger, uint64_t millis, bool ok){ static void submitTriggerStat(const std::string trigger, uint64_t millis, bool ok){
JSON::Value j; JSON::Value j;
j["trigger_stat"]["name"] = trigger; j["trigger_stat"]["name"] = trigger;
j["trigger_stat"]["ms"] = Util::bootMS()-millis; j["trigger_stat"]["ms"] = Util::bootMS() - millis;
j["trigger_stat"]["ok"] = ok; j["trigger_stat"]["ok"] = ok;
Socket::UDPConnection uSock; Socket::UDPConnection uSock;
uSock.SetDestination(UDP_API_HOST, UDP_API_PORT); uSock.SetDestination(UDP_API_HOST, UDP_API_PORT);
@ -42,7 +44,8 @@ namespace Triggers{
///\param payload This data will be sent to the destionation URL/program ///\param payload This data will be sent to the destionation URL/program
///\param sync If true, handler is executed blocking and uses the response data. ///\param sync If true, handler is executed blocking and uses the response data.
///\returns String, false if further processing should be aborted. ///\returns String, false if further processing should be aborted.
std::string handleTrigger(const std::string &trigger, const std::string &value, const std::string &payload, int sync, const std::string &defaultResponse){ std::string handleTrigger(const std::string &trigger, const std::string &value,
const std::string &payload, int sync, const std::string &defaultResponse){
uint64_t tStartMs = Util::bootMS(); uint64_t tStartMs = Util::bootMS();
if (!value.size()){ if (!value.size()){
WARN_MSG("Trigger requested with empty destination"); WARN_MSG("Trigger requested with empty destination");
@ -58,7 +61,8 @@ namespace Triggers{
submitTriggerStat(trigger, tStartMs, true); submitTriggerStat(trigger, tStartMs, true);
return DL.data(); return DL.data();
} }
FAIL_MSG("Trigger failed to execute (%s), using default response: %s", DL.getStatusText().c_str(), defaultResponse.c_str()); FAIL_MSG("Trigger failed to execute (%s), using default response: %s",
DL.getStatusText().c_str(), defaultResponse.c_str());
submitTriggerStat(trigger, tStartMs, false); submitTriggerStat(trigger, tStartMs, false);
return defaultResponse; return defaultResponse;
}else{// send payload to stdin of newly forked process }else{// send payload to stdin of newly forked process
@ -90,9 +94,7 @@ namespace Triggers{
Util::sleep(100); Util::sleep(100);
++counter; ++counter;
if (counter >= 150){ if (counter >= 150){
if (counter == 150){ if (counter == 150){FAIL_MSG("Trigger taking too long - killing process");}
FAIL_MSG("Trigger taking too long - killing process");
}
if (counter >= 250){ if (counter >= 250){
Util::Procs::Stop(myProc); Util::Procs::Stop(myProc);
}else{ }else{
@ -104,7 +106,9 @@ namespace Triggers{
FILE *outFile = fdopen(fdOut, "r"); FILE *outFile = fdopen(fdOut, "r");
char *fileBuf = 0; char *fileBuf = 0;
size_t fileBufLen = 0; size_t fileBufLen = 0;
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){ret += fileBuf;} while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
ret += fileBuf;
}
fclose(outFile); fclose(outFile);
free(fileBuf); free(fileBuf);
close(fdOut); close(fdOut);
@ -124,14 +128,14 @@ namespace Triggers{
static std::string usually_empty; static std::string usually_empty;
///\brief returns true if a trigger of the specified type should be handled for a specified stream (, or entire server) ///\brief returns true if a trigger of the specified type should be handled for a specified stream
///\param type Trigger event type. ///(, or entire server) \param type Trigger event type. \param streamName the stream to be handled
///\param streamName the stream to be handled
///\return returns true if so ///\return returns true if so
/// calls doTrigger with dryRun set to true /// calls doTrigger with dryRun set to true
/// returns true if a trigger of the specified type should be /// returns true if a trigger of the specified type should be
/// handled for a specified stream (, or entire server) /// handled for a specified stream (, or entire server)
bool shouldTrigger(const std::string & type, const std::string & streamName, bool paramsCB(const char *, const void *), const void * extraParam){ bool shouldTrigger(const std::string &type, const std::string &streamName,
bool paramsCB(const char *, const void *), const void *extraParam){
usually_empty.clear(); usually_empty.clear();
return doTrigger(type, empty, streamName, true, usually_empty, paramsCB, extraParam); return doTrigger(type, empty, streamName, true, usually_empty, paramsCB, extraParam);
} }
@ -142,7 +146,7 @@ namespace Triggers{
///\param streamName The name of a stream. ///\param streamName The name of a stream.
///\returns Boolean, false if further processing should be aborted. ///\returns Boolean, false if further processing should be aborted.
/// calls doTrigger with dryRun set to false /// calls doTrigger with dryRun set to false
bool doTrigger(const std::string & type, const std::string &payload, const std::string &streamName){ bool doTrigger(const std::string &type, const std::string &payload, const std::string &streamName){
usually_empty.clear(); usually_empty.clear();
return doTrigger(type, payload, streamName, false, usually_empty); return doTrigger(type, payload, streamName, false, usually_empty);
} }
@ -158,11 +162,13 @@ namespace Triggers{
/// defined for that trigger event type. /// defined for that trigger event type.
/// The function can be used for two separate purposes, determined by the value of dryRun /// The function can be used for two separate purposes, determined by the value of dryRun
///-if this function is called with dryRun==true (for example, from a handleTrigger function), the return value will be true, if at least one ///-if this function is called with dryRun==true (for example, from a handleTrigger function), the return value will be true, if at least one
///trigger should be handled for the requested type/stream. /// trigger should be handled for the requested type/stream.
/// this can be used to make sure a payload is only generated if at least one trigger should be handled. /// this can be used to make sure a payload is only generated if at least one trigger should be handled.
///-if this function is called with dryRun==false (for example, from one of the overloaded doTrigger functions), handleTrigger is called for ///-if this function is called with dryRun==false (for example, from one of the overloaded doTrigger functions), handleTrigger is called for
///all configured triggers. In that case, the return value does not matter, it will probably be false in all cases. /// all configured triggers. In that case, the return value does not matter, it will probably be false in all cases.
bool doTrigger(const std::string & type, const std::string &payload, const std::string &streamName, bool dryRun, std::string &response, bool paramsCB(const char *, const void *), const void * extraParam){ bool doTrigger(const std::string &type, const std::string &payload, const std::string &streamName,
bool dryRun, std::string &response, bool paramsCB(const char *, const void *),
const void *extraParam){
// open SHM page for this type: // open SHM page for this type:
char thisPageName[NAME_BUFFER_SIZE]; char thisPageName[NAME_BUFFER_SIZE];
snprintf(thisPageName, NAME_BUFFER_SIZE, SHM_TRIGGER, type.c_str()); snprintf(thisPageName, NAME_BUFFER_SIZE, SHM_TRIGGER, type.c_str());
@ -184,23 +190,22 @@ namespace Triggers{
std::string uri = std::string(trigs.getPointer("url", i)); std::string uri = std::string(trigs.getPointer("url", i));
uint8_t sync = trigs.getInt("sync", i); uint8_t sync = trigs.getInt("sync", i);
char * strPtr = trigs.getPointer("streams", i); char *strPtr = trigs.getPointer("streams", i);
uint32_t pLen = trigs.getSize("streams"); uint32_t pLen = trigs.getSize("streams");
uint32_t bPos = 0; uint32_t bPos = 0;
bool isHandled = !streamName.size(); bool isHandled = !streamName.size();
while (bPos + 4 < pLen){ while (bPos + 4 < pLen){
uint32_t stringLen = ((unsigned int *)(strPtr+bPos))[0]; uint32_t stringLen = ((unsigned int *)(strPtr + bPos))[0];
if (bPos + 4 + stringLen > pLen || !stringLen){break;} if (bPos + 4 + stringLen > pLen || !stringLen){break;}
if ((streamName.size() == stringLen || splitter == stringLen) && strncmp(strPtr+bPos+4, streamName.data(), stringLen) == 0){ if ((streamName.size() == stringLen || splitter == stringLen) &&
strncmp(strPtr + bPos + 4, streamName.data(), stringLen) == 0){
isHandled = true; isHandled = true;
} }
bPos += stringLen + 4; bPos += stringLen + 4;
} }
// no streams explicitly defined for this trigger, return true for all streams. // no streams explicitly defined for this trigger, return true for all streams.
if (bPos <= 4){ if (bPos <= 4){isHandled = true;}
isHandled = true;
}
if (isHandled && paramsCB){ if (isHandled && paramsCB){
isHandled = paramsCB(trigs.getPointer("params", i), extraParam); isHandled = paramsCB(trigs.getPointer("params", i), extraParam);
@ -227,5 +232,4 @@ namespace Triggers{
return retVal; return retVal;
} }
} }
} }// namespace Triggers

View file

@ -5,11 +5,15 @@ namespace Triggers{
static const std::string empty; static const std::string empty;
bool doTrigger(const std::string & triggerType, const std::string &payload, const std::string &streamName, bool dryRun, std::string &response, bool paramsCB(const char *, const void *) = 0, const void * extraParam = 0); bool doTrigger(const std::string &triggerType, const std::string &payload,
std::string handleTrigger(const std::string &triggerType, const std::string &value, const std::string &payload, int sync, const std::string &defaultResponse); const std::string &streamName, bool dryRun, std::string &response,
bool paramsCB(const char *, const void *) = 0, const void *extraParam = 0);
std::string handleTrigger(const std::string &triggerType, const std::string &value,
const std::string &payload, int sync, const std::string &defaultResponse);
// All of the below are just shorthands for specific usage of the doTrigger function above: // All of the below are just shorthands for specific usage of the doTrigger function above:
bool shouldTrigger(const std::string & triggerType, const std::string &streamName = empty, bool paramsCB(const char *, const void *) = 0, const void * extraParam = 0); bool shouldTrigger(const std::string &triggerType, const std::string &streamName = empty,
bool doTrigger(const std::string & triggerType, const std::string & payload = empty, const std::string & streamName = empty); bool paramsCB(const char *, const void *) = 0, const void *extraParam = 0);
} bool doTrigger(const std::string &triggerType, const std::string &payload = empty,
const std::string &streamName = empty);
}// namespace Triggers

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more