Restyle
This commit is contained in:
parent
5b79f296d6
commit
fccf66fba2
280 changed files with 56975 additions and 71885 deletions
88
lib/adts.cpp
88
lib/adts.cpp
|
@ -6,66 +6,55 @@
|
||||||
|
|
||||||
#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()){
|
||||||
}
|
|
||||||
switch(getFrequencyIndex()){
|
|
||||||
case 0: return 96000; break;
|
case 0: return 96000; break;
|
||||||
case 1: return 88200; break;
|
case 1: return 88200; break;
|
||||||
case 2: return 64000; break;
|
case 2: return 64000; break;
|
||||||
|
@ -84,55 +73,43 @@ namespace aac {
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
29
lib/adts.h
29
lib/adts.h
|
@ -1,16 +1,16 @@
|
||||||
|
#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;
|
||||||
|
@ -21,21 +21,22 @@ namespace aac {
|
||||||
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:
|
private:
|
||||||
char * data;
|
char *data;
|
||||||
unsigned long len;
|
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;
|
||||||
|
@ -91,6 +92,4 @@ namespace aac {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}// namespace aac
|
||||||
|
|
||||||
}
|
|
||||||
|
|
37
lib/amf.cpp
37
lib/amf.cpp
|
@ -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,8 +408,7 @@ 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
|
||||||
|
@ -429,8 +425,7 @@ 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
|
||||||
|
@ -445,8 +440,7 @@ 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
|
||||||
|
@ -454,12 +448,10 @@ AMF::Object AMF::parseOne(const unsigned char *&data, unsigned int &len, unsigne
|
||||||
}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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
225
lib/auth.cpp
225
lib/auth.cpp
|
@ -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
|
||||||
|
|
||||||
|
|
37
lib/auth.h
37
lib/auth.h
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -93,4 +93,3 @@ namespace Utils{
|
||||||
void fixData();
|
void fixData();
|
||||||
};
|
};
|
||||||
}// namespace Utils
|
}// namespace Utils
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
331
lib/checksum.h
331
lib/checksum.h
|
@ -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,
|
|
||||||
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,
|
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
|
||||||
|
|
|
@ -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,8 +186,8 @@ 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*/
|
||||||
|
@ -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){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,4 +64,3 @@ namespace Util{
|
||||||
void setUser(std::string user);
|
void setUser(std::string user);
|
||||||
|
|
||||||
}// namespace Util
|
}// namespace Util
|
||||||
|
|
||||||
|
|
|
@ -15,18 +15,20 @@
|
||||||
#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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -65,8 +67,4 @@ namespace HTTP{
|
||||||
uint64_t nbReqTime;
|
uint64_t nbReqTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}// namespace HTTP
|
}// namespace HTTP
|
||||||
|
|
||||||
|
|
|
@ -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 -2;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* see the dtls server example; this is used to prevent certain attacks (ddos) */
|
/* see the dtls server example; this is used to prevent certain attacks (ddos) */
|
||||||
case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: {
|
case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED:{
|
||||||
if (0 != resetSession()) {
|
if (0 != resetSession()){
|
||||||
ERROR_MSG("Failed to reset the session which is necessary when we need to verify the HELLO.");
|
ERROR_MSG(
|
||||||
|
"Failed to reset the session which is necessary when we need to verify the HELLO.");
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MBEDTLS_ERR_SSL_WANT_READ: {
|
case MBEDTLS_ERR_SSL_WANT_READ:{
|
||||||
DONTEVEN_MSG("mbedtls wants a bit more data before it can continue parsing the DTLS handshake.");
|
DONTEVEN_MSG(
|
||||||
|
"mbedtls wants a bit more data before it can continue parsing the DTLS handshake.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default:{
|
||||||
ERROR_MSG("A serious mbedtls error occured.");
|
ERROR_MSG("A serious mbedtls error occured.");
|
||||||
print_mbedtls_error(r);
|
print_mbedtls_error(r);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}while (MBEDTLS_ERR_SSL_WANT_WRITE == r);
|
||||||
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,34 +374,33 @@ 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: {
|
}
|
||||||
|
case MBEDTLS_ERR_SSL_WANT_WRITE:{
|
||||||
|
return "MBEDTLS_ERR_SSL_WANT_WRITE";
|
||||||
|
}
|
||||||
|
default:{
|
||||||
print_mbedtls_error(r);
|
print_mbedtls_error(r);
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
@ -416,5 +408,3 @@ static std::string mbedtls_err_to_string(int r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------- */
|
/* ---------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,7 +39,7 @@ 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;
|
||||||
|
@ -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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
|
315
lib/dtsc.cpp
315
lib/dtsc.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
307
lib/dtsc.h
307
lib/dtsc.h
|
@ -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,17 +19,17 @@
|
||||||
#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
|
||||||
|
@ -44,50 +44,42 @@ namespace DTSC {
|
||||||
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;
|
||||||
|
@ -96,47 +88,50 @@ namespace DTSC {
|
||||||
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:
|
private:
|
||||||
char * p;
|
char *p;
|
||||||
size_t len;
|
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 appendNal(const char *appendData, uint32_t appendLen);
|
||||||
|
void upgradeNal(const char *appendData, uint32_t appendLen);
|
||||||
void setKeyFrame(bool kf);
|
void setKeyFrame(bool kf);
|
||||||
virtual uint64_t getTime() const;
|
virtual uint64_t getTime() const;
|
||||||
void setTime(uint64_t _time);
|
void setTime(uint64_t _time);
|
||||||
void nullMember(const std::string & memb);
|
void nullMember(const std::string &memb);
|
||||||
size_t getTrackId() const;
|
size_t getTrackId() const;
|
||||||
char * getData() const;
|
char *getData() const;
|
||||||
size_t getDataLen() const;
|
size_t getDataLen() const;
|
||||||
size_t getPayloadLen() const;
|
size_t getPayloadLen() const;
|
||||||
size_t getDataStringLen();
|
size_t getDataStringLen();
|
||||||
|
@ -145,11 +140,12 @@ namespace DTSC {
|
||||||
std::string toSummary() const;
|
std::string toSummary() const;
|
||||||
Scan getScan() const;
|
Scan getScan() const;
|
||||||
Scan getScan();
|
Scan getScan();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool master;
|
bool master;
|
||||||
packType version;
|
packType version;
|
||||||
void resize(size_t size);
|
void resize(size_t size);
|
||||||
char * data;
|
char *data;
|
||||||
size_t bufferLen;
|
size_t bufferLen;
|
||||||
size_t dataLen;
|
size_t dataLen;
|
||||||
|
|
||||||
|
@ -157,49 +153,45 @@ namespace DTSC {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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;
|
|
||||||
}
|
|
||||||
RetimedPacket(uint64_t reTime, const char * data_, unsigned int len, bool noCopy = false) : Packet(data_, len, noCopy){
|
|
||||||
timeOverride = reTime;
|
timeOverride = reTime;
|
||||||
}
|
}
|
||||||
virtual uint64_t getTime() const{return timeOverride;}
|
virtual uint64_t getTime() const{return timeOverride;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint64_t timeOverride;
|
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,16 +202,17 @@ 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:
|
private:
|
||||||
///\brief Data storage for this initialization vector.
|
///\brief Data storage for this initialization vector.
|
||||||
///
|
///
|
||||||
|
@ -229,7 +222,7 @@ namespace DTSC {
|
||||||
/*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);
|
||||||
|
@ -237,8 +230,9 @@ namespace DTSC {
|
||||||
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.
|
||||||
|
@ -252,7 +246,7 @@ namespace DTSC {
|
||||||
///\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);
|
||||||
|
@ -264,8 +258,9 @@ namespace DTSC {
|
||||||
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.
|
||||||
|
@ -279,7 +274,7 @@ namespace DTSC {
|
||||||
};
|
};
|
||||||
|
|
||||||
///\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);
|
||||||
|
@ -289,8 +284,9 @@ namespace DTSC {
|
||||||
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.
|
||||||
|
@ -303,35 +299,38 @@ namespace DTSC {
|
||||||
};
|
};
|
||||||
|
|
||||||
///\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);
|
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);
|
int getSendLen(bool skipDynamic = false);
|
||||||
void send(Socket::Connection & conn, bool skipDynamic = false);
|
void send(Socket::Connection &conn, bool skipDynamic = false);
|
||||||
void writeTo(char *& p);
|
void writeTo(char *&p);
|
||||||
JSON::Value toJSON(bool skipDynamic = false);
|
JSON::Value toJSON(bool skipDynamic = false);
|
||||||
std::deque<Fragment> fragments;
|
std::deque<Fragment> fragments;
|
||||||
std::deque<Key> keys;
|
std::deque<Key> keys;
|
||||||
std::deque<unsigned long> keySizes;
|
std::deque<unsigned long> keySizes;
|
||||||
std::deque<Part> parts;
|
std::deque<Part> parts;
|
||||||
std::deque<Ivec> ivecs; /*LTS*/
|
std::deque<Ivec> ivecs; /*LTS*/
|
||||||
Key & getKey(unsigned int keyNum);
|
Key &getKey(unsigned int keyNum);
|
||||||
Fragment & getFrag(unsigned int fragNum);
|
Fragment &getFrag(unsigned int fragNum);
|
||||||
unsigned int timeToKeynum(unsigned int timestamp);
|
unsigned int timeToKeynum(unsigned int timestamp);
|
||||||
uint32_t timeToFragnum(uint64_t timestamp);
|
uint32_t timeToFragnum(uint64_t timestamp);
|
||||||
void reset();
|
void reset();
|
||||||
void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0);
|
void toPrettyString(std::ostream &str, int indent = 0, int verbosity = 0);
|
||||||
void finalize();
|
void finalize();
|
||||||
uint32_t biggestFragment();
|
uint32_t biggestFragment();
|
||||||
|
|
||||||
|
@ -346,18 +345,19 @@ namespace DTSC {
|
||||||
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:
|
private:
|
||||||
std::string cachedIdent;
|
std::string cachedIdent;
|
||||||
std::deque<uint32_t> fragInsertTime;
|
std::deque<uint32_t> fragInsertTime;
|
||||||
|
@ -368,31 +368,36 @@ namespace DTSC {
|
||||||
/// \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);
|
||||||
|
unsigned int getSendLen(bool skipDynamic = false,
|
||||||
|
std::set<unsigned long> selectedTracks = std::set<unsigned long>());
|
||||||
|
void send(Socket::Connection &conn, bool skipDynamic = false,
|
||||||
|
std::set<unsigned long> selectedTracks = std::set<unsigned long>());
|
||||||
|
void writeTo(char *p);
|
||||||
JSON::Value toJSON();
|
JSON::Value toJSON();
|
||||||
void reset();
|
void reset();
|
||||||
bool toFile(const std::string & fileName);
|
bool toFile(const std::string &fileName);
|
||||||
void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0);
|
void toPrettyString(std::ostream &str, int indent = 0, int verbosity = 0);
|
||||||
//members:
|
// members:
|
||||||
std::map<unsigned int, Track> tracks;
|
std::map<unsigned int, Track> tracks;
|
||||||
Track & mainTrack();
|
Track &mainTrack();
|
||||||
uint32_t biggestFragment();
|
uint32_t biggestFragment();
|
||||||
bool vod;
|
bool vod;
|
||||||
bool live;
|
bool live;
|
||||||
|
@ -400,54 +405,55 @@ namespace DTSC {
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
int64_t moreheader;
|
int64_t moreheader;
|
||||||
int64_t bufferWindow;
|
int64_t bufferWindow;
|
||||||
int64_t bootMsOffset;///< Millis to add to packet timestamps to get millis since system boot.
|
int64_t bootMsOffset; ///< Millis to add to packet timestamps to get millis since system boot.
|
||||||
std::string sourceURI;
|
std::string sourceURI;
|
||||||
JSON::Value inputLocalVars;
|
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:
|
private:
|
||||||
long int endPos;
|
long int endPos;
|
||||||
void readHeader(int pos);
|
void readHeader(int pos);
|
||||||
|
@ -457,14 +463,13 @@ namespace DTSC {
|
||||||
long long int currtime;
|
long long int currtime;
|
||||||
long long int lastreadpos;
|
long long int lastreadpos;
|
||||||
int currframe;
|
int currframe;
|
||||||
FILE * F;
|
FILE *F;
|
||||||
unsigned long headerSize;
|
unsigned long headerSize;
|
||||||
void * buffer;
|
void *buffer;
|
||||||
bool created;
|
bool created;
|
||||||
std::set<seekPos> currentPositions;
|
std::set<seekPos> currentPositions;
|
||||||
std::set<unsigned long> selectedTracks;
|
std::set<unsigned long> selectedTracks;
|
||||||
};
|
};
|
||||||
//FileWriter
|
// FileWriter
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}// namespace DTSC
|
||||||
|
|
1430
lib/dtscmeta.cpp
1430
lib/dtscmeta.cpp
File diff suppressed because it is too large
Load diff
14
lib/ebml.cpp
14
lib/ebml.cpp
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -40,4 +40,3 @@ namespace Encodings{
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace Encodings
|
}// namespace Encodings
|
||||||
|
|
||||||
|
|
|
@ -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,29 +37,30 @@ 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];
|
||||||
|
@ -71,20 +69,20 @@ namespace Encryption {
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#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;
|
||||||
|
@ -16,19 +16,20 @@ namespace Encryption {
|
||||||
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
|
||||||
|
|
|
@ -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,20 +818,17 @@ 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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -45,8 +44,7 @@ namespace FLV{
|
||||||
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
|
||||||
|
|
||||||
|
|
79
lib/h264.cpp
79
lib/h264.cpp
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
129
lib/h265.cpp
129
lib/h265.cpp
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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){
|
||||||
|
|
|
@ -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);
|
||||||
|
|
33
lib/json.cpp
33
lib/json.cpp
|
@ -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,15 +1390,13 @@ 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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1221,4 +1221,3 @@ namespace Encodings{
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace Encodings
|
}// namespace Encodings
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
|
||||||
|
|
||||||
|
|
746
lib/mp4.cpp
746
lib/mp4.cpp
File diff suppressed because it is too large
Load diff
113
lib/mp4.h
113
lib/mp4.h
|
@ -1,49 +1,46 @@
|
||||||
#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{
|
||||||
class Box {
|
|
||||||
public:
|
public:
|
||||||
Box(char * datapointer = 0, bool manage = true);
|
Box(char *datapointer = 0, bool manage = true);
|
||||||
Box(const Box & rs);
|
Box(const Box &rs);
|
||||||
Box & operator = (const Box & rs);
|
Box &operator=(const Box &rs);
|
||||||
~Box();
|
~Box();
|
||||||
operator bool() const {
|
operator bool() const{return data && data_size >= 8 && !isType("erro");}
|
||||||
return data && data_size >= 8 && !isType("erro");
|
void copyFrom(const Box &rs);
|
||||||
}
|
|
||||||
void copyFrom(const Box & rs);
|
|
||||||
|
|
||||||
std::string getType() const;
|
std::string getType() const;
|
||||||
bool isType(const char * boxType) const;
|
bool isType(const char *boxType) const;
|
||||||
bool read(FILE * newData);
|
bool read(FILE *newData);
|
||||||
bool read(std::string & newData);
|
bool read(std::string &newData);
|
||||||
|
|
||||||
uint64_t boxedSize() const;
|
uint64_t boxedSize() const;
|
||||||
uint64_t payloadSize() const;
|
uint64_t payloadSize() const;
|
||||||
char * asBox();
|
char *asBox();
|
||||||
char * payload();
|
char *payload();
|
||||||
void clear();
|
void clear();
|
||||||
std::string toPrettyString(uint32_t indent = 0) const;
|
std::string toPrettyString(uint32_t indent = 0) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//integer functions
|
// integer functions
|
||||||
void setInt8(char newData, size_t index);
|
void setInt8(char newData, size_t index);
|
||||||
char getInt8(size_t index);
|
char getInt8(size_t index);
|
||||||
char getInt8(size_t index) const;
|
char getInt8(size_t index) const;
|
||||||
|
@ -59,69 +56,67 @@ namespace MP4 {
|
||||||
void setInt64(uint64_t newData, size_t index);
|
void setInt64(uint64_t newData, size_t index);
|
||||||
uint64_t getInt64(size_t index);
|
uint64_t getInt64(size_t index);
|
||||||
uint64_t getInt64(size_t index) const;
|
uint64_t getInt64(size_t index) const;
|
||||||
//string functions
|
// string functions
|
||||||
void setString(std::string newData, size_t index);
|
void setString(std::string newData, size_t index);
|
||||||
void setString(char * newData, size_t size, size_t index);
|
void setString(char *newData, size_t size, size_t index);
|
||||||
char * getString(size_t index);
|
char *getString(size_t index);
|
||||||
size_t getStringLen(size_t index) const;
|
size_t getStringLen(size_t index) const;
|
||||||
//box functions
|
// box functions
|
||||||
Box & getBox(size_t index);
|
Box &getBox(size_t index);
|
||||||
size_t getBoxLen(size_t index) const;
|
size_t getBoxLen(size_t index) const;
|
||||||
void setBox(Box & newEntry, size_t index);
|
void setBox(Box &newEntry, size_t index);
|
||||||
//data functions
|
// data functions
|
||||||
bool reserve(size_t position, size_t current, size_t wanted);
|
bool reserve(size_t position, size_t current, size_t wanted);
|
||||||
bool reserve(size_t position, size_t current, size_t wanted) const {return false;}
|
bool reserve(size_t position, size_t current, size_t wanted) const{return false;}
|
||||||
|
|
||||||
//internal variables
|
// internal variables
|
||||||
char * data; ///< Holds the data of this box
|
char *data; ///< Holds the data of this box
|
||||||
unsigned int data_size; ///< Currently reserved size
|
unsigned int data_size; ///< Currently reserved size
|
||||||
bool managed; ///< If false, will not attempt to resize/free the data pointer.
|
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
|
unsigned int payloadOffset; ///< The offset of the payload with regards to the data
|
||||||
};
|
};
|
||||||
//Box Class
|
// Box Class
|
||||||
|
|
||||||
class fullBox: public Box {
|
class fullBox : public Box{
|
||||||
public:
|
public:
|
||||||
fullBox();
|
fullBox();
|
||||||
void setVersion(char newVersion);
|
void setVersion(char newVersion);
|
||||||
char getVersion() const;
|
char getVersion() const;
|
||||||
void setFlags(uint32_t newFlags);
|
void setFlags(uint32_t newFlags);
|
||||||
uint32_t getFlags() const;
|
uint32_t getFlags() const;
|
||||||
std::string toPrettyString(uint32_t indent = 0) const ;
|
std::string toPrettyString(uint32_t indent = 0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class containerBox: public Box {
|
class containerBox : public Box{
|
||||||
public:
|
public:
|
||||||
containerBox();
|
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, bool unsafe = false);
|
Box &getContent(uint32_t no, bool unsafe = false);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
Box getChild(const char * boxName);
|
Box getChild(const char *boxName);
|
||||||
template <typename T>
|
template <typename T> T getChild(){
|
||||||
T getChild(){
|
|
||||||
T a;
|
T a;
|
||||||
MP4::Box r = getChild(a.getType().c_str());
|
MP4::Box r = getChild(a.getType().c_str());
|
||||||
return (T&)r;
|
return (T &)r;
|
||||||
}
|
}
|
||||||
std::deque<Box> getChildren(const char * boxName);
|
std::deque<Box> getChildren(const char *boxName);
|
||||||
template <typename T>
|
template <typename T> std::deque<T> getChildren(){
|
||||||
std::deque<T> getChildren(){
|
|
||||||
T a;
|
T a;
|
||||||
std::deque<Box> tmpRes = getChildren(a.getType().c_str());
|
std::deque<Box> tmpRes = getChildren(a.getType().c_str());
|
||||||
std::deque<T> res;
|
std::deque<T> res;
|
||||||
for (std::deque<Box>::iterator it = tmpRes.begin(); it != tmpRes.end(); it++){
|
for (std::deque<Box>::iterator it = tmpRes.begin(); it != tmpRes.end(); it++){
|
||||||
res.push_back((T&)*it);
|
res.push_back((T &)*it);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class containerFullBox: public fullBox {
|
class containerFullBox : public fullBox{
|
||||||
public:
|
public:
|
||||||
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);
|
||||||
std::string toPrettyCFBString(uint32_t indent, std::string boxName);
|
std::string toPrettyCFBString(uint32_t indent, std::string boxName);
|
||||||
};
|
};
|
||||||
}
|
}// namespace MP4
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,19 +2,19 @@
|
||||||
#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);
|
||||||
|
@ -24,22 +24,22 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -47,17 +47,17 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -78,40 +78,40 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -135,5 +135,4 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}// namespace MP4
|
||||||
|
|
||||||
|
|
185
lib/mp4_dash.cpp
185
lib/mp4_dash.cpp
|
@ -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,16 +75,17 @@ 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 "
|
||||||
|
<< getEarliestPresentationTime() << std::endl;
|
||||||
r << std::string(indent + 1, ' ') << "FirstOffset " << getFirstOffset() << std::endl;
|
r << std::string(indent + 1, ' ') << "FirstOffset " << getFirstOffset() << std::endl;
|
||||||
r << std::string(indent + 1, ' ') << "References [" << getReferenceCount() << "]" << std::endl;
|
r << std::string(indent + 1, ' ') << "References [" << getReferenceCount() << "]" << std::endl;
|
||||||
for (int i = 0; i < getReferenceCount(); i++) {
|
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;
|
||||||
|
@ -113,37 +98,36 @@ namespace MP4 {
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,7 +11,7 @@ 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);
|
||||||
|
@ -25,13 +25,13 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -40,7 +40,7 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -69,5 +69,4 @@ namespace MP4 {
|
||||||
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
}
|
}// namespace MP4
|
||||||
|
|
||||||
|
|
|
@ -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,18 +54,16 @@ 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);
|
||||||
|
@ -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
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
#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);
|
||||||
|
@ -35,10 +35,10 @@ namespace MP4 {
|
||||||
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;
|
||||||
|
@ -47,7 +47,7 @@ namespace MP4 {
|
||||||
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();
|
||||||
|
@ -56,7 +56,7 @@ namespace MP4 {
|
||||||
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();
|
||||||
|
@ -64,10 +64,10 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -84,7 +84,7 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -100,7 +100,7 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -116,25 +116,25 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -144,12 +144,12 @@ namespace MP4 {
|
||||||
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
|
||||||
|
|
2948
lib/mp4_generic.cpp
2948
lib/mp4_generic.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,43 +1,43 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "mp4.h"
|
#include "mp4.h"
|
||||||
|
|
||||||
namespace h265 {
|
namespace h265{
|
||||||
struct metaInfo;
|
struct metaInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MP4 {
|
namespace MP4{
|
||||||
class MFHD: public Box {
|
class MFHD : public Box{
|
||||||
public:
|
public:
|
||||||
MFHD();
|
MFHD();
|
||||||
void setSequenceNumber(uint32_t newSequenceNumber);
|
void setSequenceNumber(uint32_t newSequenceNumber);
|
||||||
uint32_t getSequenceNumber();
|
uint32_t getSequenceNumber();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
//MFHD Box
|
// MFHD Box
|
||||||
|
|
||||||
class MOOF: public containerBox {
|
class MOOF : public containerBox{
|
||||||
public:
|
public:
|
||||||
MOOF();
|
MOOF();
|
||||||
};
|
};
|
||||||
//MOOF Box
|
// MOOF Box
|
||||||
|
|
||||||
class TRAF: public Box {
|
class TRAF : public Box{
|
||||||
public:
|
public:
|
||||||
TRAF();
|
TRAF();
|
||||||
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, bool unsafe = false);
|
Box &getContent(uint32_t no, bool unsafe = false);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
//TRAF Box
|
// TRAF Box
|
||||||
|
|
||||||
struct trunSampleInformation {
|
struct trunSampleInformation{
|
||||||
uint32_t sampleDuration;
|
uint32_t sampleDuration;
|
||||||
uint32_t sampleSize;
|
uint32_t sampleSize;
|
||||||
uint32_t sampleFlags;
|
uint32_t sampleFlags;
|
||||||
uint32_t sampleOffset;
|
uint32_t sampleOffset;
|
||||||
};
|
};
|
||||||
enum trunflags {
|
enum trunflags{
|
||||||
trundataOffset = 0x00000001,
|
trundataOffset = 0x00000001,
|
||||||
trunfirstSampleFlags = 0x00000004,
|
trunfirstSampleFlags = 0x00000004,
|
||||||
trunsampleDuration = 0x00000100,
|
trunsampleDuration = 0x00000100,
|
||||||
|
@ -45,7 +45,7 @@ namespace MP4 {
|
||||||
trunsampleFlags = 0x00000400,
|
trunsampleFlags = 0x00000400,
|
||||||
trunsampleOffsets = 0x00000800
|
trunsampleOffsets = 0x00000800
|
||||||
};
|
};
|
||||||
enum sampleflags {
|
enum sampleflags{
|
||||||
noIPicture = 0x01000000,
|
noIPicture = 0x01000000,
|
||||||
isIPicture = 0x02000000,
|
isIPicture = 0x02000000,
|
||||||
noDisposable = 0x00400000,
|
noDisposable = 0x00400000,
|
||||||
|
@ -57,7 +57,7 @@ namespace MP4 {
|
||||||
MUST_BE_PRESENT = 0x1
|
MUST_BE_PRESENT = 0x1
|
||||||
};
|
};
|
||||||
std::string prettySampleFlags(uint32_t flag);
|
std::string prettySampleFlags(uint32_t flag);
|
||||||
class TRUN: public Box {
|
class TRUN : public Box{
|
||||||
public:
|
public:
|
||||||
TRUN();
|
TRUN();
|
||||||
void setFlags(uint32_t newFlags);
|
void setFlags(uint32_t newFlags);
|
||||||
|
@ -72,7 +72,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum tfhdflags {
|
enum tfhdflags{
|
||||||
tfhdBaseOffset = 0x000001,
|
tfhdBaseOffset = 0x000001,
|
||||||
tfhdSampleDesc = 0x000002,
|
tfhdSampleDesc = 0x000002,
|
||||||
tfhdSampleDura = 0x000008,
|
tfhdSampleDura = 0x000008,
|
||||||
|
@ -81,7 +81,7 @@ namespace MP4 {
|
||||||
tfhdNoDuration = 0x010000,
|
tfhdNoDuration = 0x010000,
|
||||||
tfhdBaseIsMoof = 0x020000,
|
tfhdBaseIsMoof = 0x020000,
|
||||||
};
|
};
|
||||||
class TFHD: public Box {
|
class TFHD : public Box{
|
||||||
public:
|
public:
|
||||||
TFHD();
|
TFHD();
|
||||||
void setFlags(uint32_t newFlags);
|
void setFlags(uint32_t newFlags);
|
||||||
|
@ -102,8 +102,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AVCC : public Box{
|
||||||
class AVCC: public Box {
|
|
||||||
public:
|
public:
|
||||||
AVCC();
|
AVCC();
|
||||||
void setVersion(uint32_t newVersion);
|
void setVersion(uint32_t newVersion);
|
||||||
|
@ -118,36 +117,36 @@ namespace MP4 {
|
||||||
void setSPSCount(uint32_t _count);
|
void setSPSCount(uint32_t _count);
|
||||||
uint32_t getSPSCount();
|
uint32_t getSPSCount();
|
||||||
void setSPS(std::string newSPS, size_t index = 0);
|
void setSPS(std::string newSPS, size_t index = 0);
|
||||||
void setSPS(const char * data, size_t len, size_t index = 0);
|
void setSPS(const char *data, size_t len, size_t index = 0);
|
||||||
uint32_t getSPSLen(size_t index = 0);
|
uint32_t getSPSLen(size_t index = 0);
|
||||||
char * getSPS(size_t index = 0);
|
char *getSPS(size_t index = 0);
|
||||||
std::string hexSPS(size_t index = 0);
|
std::string hexSPS(size_t index = 0);
|
||||||
|
|
||||||
size_t PPSCountOffset();
|
size_t PPSCountOffset();
|
||||||
void setPPSCount(uint32_t _count);
|
void setPPSCount(uint32_t _count);
|
||||||
uint32_t getPPSCount();
|
uint32_t getPPSCount();
|
||||||
void setPPS(std::string newPPS, size_t index = 0);
|
void setPPS(std::string newPPS, size_t index = 0);
|
||||||
void setPPS(const char * data, size_t len, size_t index = 0);
|
void setPPS(const char *data, size_t len, size_t index = 0);
|
||||||
uint32_t getPPSLen(size_t index = 0);
|
uint32_t getPPSLen(size_t index = 0);
|
||||||
char * getPPS(size_t index = 0);
|
char *getPPS(size_t index = 0);
|
||||||
void multiplyPPS(size_t newAmount);
|
void multiplyPPS(size_t newAmount);
|
||||||
std::string hexPPS(size_t index = 0);
|
std::string hexPPS(size_t index = 0);
|
||||||
std::string asAnnexB();
|
std::string asAnnexB();
|
||||||
void setPayload(std::string newPayload);
|
void setPayload(std::string newPayload);
|
||||||
void setPayload(const char * data, size_t len);
|
void setPayload(const char *data, size_t len);
|
||||||
|
|
||||||
bool sanitize();
|
bool sanitize();
|
||||||
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HVCCArrayEntry {
|
struct HVCCArrayEntry{
|
||||||
char arrayCompleteness;
|
char arrayCompleteness;
|
||||||
char nalUnitType;
|
char nalUnitType;
|
||||||
std::deque<std::string> nalUnits;
|
std::deque<std::string> nalUnits;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HVCC: public Box {
|
class HVCC : public Box{
|
||||||
public:
|
public:
|
||||||
HVCC();
|
HVCC();
|
||||||
void setConfigurationVersion(char newVersion);
|
void setConfigurationVersion(char newVersion);
|
||||||
|
@ -185,7 +184,7 @@ namespace MP4 {
|
||||||
void setLengthSizeMinus1(char newLengthSizeMinus1);
|
void setLengthSizeMinus1(char newLengthSizeMinus1);
|
||||||
char getLengthSizeMinus1();
|
char getLengthSizeMinus1();
|
||||||
///\todo Add setter for the array entries
|
///\todo Add setter for the array entries
|
||||||
void setArrays(std::deque<HVCCArrayEntry> & arrays);
|
void setArrays(std::deque<HVCCArrayEntry> &arrays);
|
||||||
std::deque<HVCCArrayEntry> getArrays();
|
std::deque<HVCCArrayEntry> getArrays();
|
||||||
std::string asAnnexB();
|
std::string asAnnexB();
|
||||||
void setPayload(std::string newPayload);
|
void setPayload(std::string newPayload);
|
||||||
|
@ -196,53 +195,50 @@ namespace MP4 {
|
||||||
class Descriptor{
|
class Descriptor{
|
||||||
public:
|
public:
|
||||||
Descriptor();
|
Descriptor();
|
||||||
Descriptor(const char* pointer, const unsigned long length, const bool master = false);
|
Descriptor(const char *pointer, const unsigned long length, const bool master = false);
|
||||||
char getTag();///< Get type of descriptor
|
char getTag(); ///< Get type of descriptor
|
||||||
void setTag(char t);///< Set type of descriptor
|
void setTag(char t); ///< Set type of descriptor
|
||||||
unsigned long getDataSize();///< Get internal size of descriptor
|
unsigned long getDataSize(); ///< Get internal size of descriptor
|
||||||
unsigned long getFullSize();///< Get external size of descriptor
|
unsigned long getFullSize(); ///< Get external size of descriptor
|
||||||
void resize(unsigned long t);///< Resize descriptor
|
void resize(unsigned long t); ///< Resize descriptor
|
||||||
char* getData();///< Returns pointer to start of internal data
|
char *getData(); ///< Returns pointer to start of internal data
|
||||||
std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string
|
std::string toPrettyString(uint32_t indent = 0); ///< put it into a pretty string
|
||||||
protected:
|
protected:
|
||||||
unsigned long size;///< Length of data
|
unsigned long size; ///< Length of data
|
||||||
char* data;///< Pointer to data in memory
|
char *data; ///< Pointer to data in memory
|
||||||
bool master;
|
bool master;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implements ISO 14496-1 DecSpecificInfoTag
|
/// Implements ISO 14496-1 DecSpecificInfoTag
|
||||||
class DSDescriptor: public Descriptor{
|
class DSDescriptor : public Descriptor{
|
||||||
public:
|
public:
|
||||||
DSDescriptor (const char* pointer, const unsigned long length, const bool master = false);
|
DSDescriptor(const char *pointer, const unsigned long length, const bool master = false);
|
||||||
std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string
|
std::string toPrettyString(uint32_t indent = 0); ///< put it into a pretty string
|
||||||
std::string toString(); ///< Return decoder specific info as standard string in binary format.
|
std::string toString(); ///< Return decoder specific info as standard string in binary format.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implements ISO 14496-1 DecoderConfigDescrTag
|
/// Implements ISO 14496-1 DecoderConfigDescrTag
|
||||||
class DCDescriptor: public Descriptor{
|
class DCDescriptor : public Descriptor{
|
||||||
public:
|
public:
|
||||||
DCDescriptor (const char* pointer, const unsigned long length, const bool master = false);
|
DCDescriptor(const char *pointer, const unsigned long length, const bool master = false);
|
||||||
bool isAAC(); ///< Returns true if this track is AAC.
|
bool isAAC(); ///< Returns true if this track is AAC.
|
||||||
std::string getCodec();
|
std::string getCodec();
|
||||||
DSDescriptor getSpecific();
|
DSDescriptor getSpecific();
|
||||||
std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string
|
std::string toPrettyString(uint32_t indent = 0); ///< put it into a pretty string
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implements ISO 14496-1 ES_DescrTag
|
/// Implements ISO 14496-1 ES_DescrTag
|
||||||
class ESDescriptor: public Descriptor{
|
class ESDescriptor : public Descriptor{
|
||||||
public:
|
public:
|
||||||
ESDescriptor (const char* pointer, const unsigned long length, const bool master = false);
|
ESDescriptor(const char *pointer, const unsigned long length, const bool master = false);
|
||||||
DCDescriptor getDecoderConfig();
|
DCDescriptor getDecoderConfig();
|
||||||
std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string
|
std::string toPrettyString(uint32_t indent = 0); ///< put it into a pretty string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Implements ISO 14496-1 SLConfigDescrTag
|
/// Implements ISO 14496-1 SLConfigDescrTag
|
||||||
class SLCDescriptor: public Descriptor{
|
class SLCDescriptor : public Descriptor{};
|
||||||
};
|
|
||||||
|
|
||||||
class ESDS: public fullBox {
|
class ESDS : public fullBox{
|
||||||
public:
|
public:
|
||||||
ESDS();
|
ESDS();
|
||||||
ESDS(std::string init);
|
ESDS(std::string init);
|
||||||
|
@ -253,54 +249,54 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DAC3: public Box {
|
class DAC3 : public Box{
|
||||||
public:
|
public:
|
||||||
DAC3(unsigned int rate, unsigned int channels);
|
DAC3(unsigned int rate, unsigned int channels);
|
||||||
char getSampleRateCode();//2bits
|
char getSampleRateCode(); // 2bits
|
||||||
void setSampleRateCode(char newVal);//2bits
|
void setSampleRateCode(char newVal); // 2bits
|
||||||
char getBitStreamIdentification();//5bits
|
char getBitStreamIdentification(); // 5bits
|
||||||
void setBitStreamIdentification(char newVal);//5bits
|
void setBitStreamIdentification(char newVal); // 5bits
|
||||||
char getBitStreamMode();//3 bits
|
char getBitStreamMode(); // 3 bits
|
||||||
void setBitStreamMode(char newVal);//3 bits
|
void setBitStreamMode(char newVal); // 3 bits
|
||||||
char getAudioConfigMode();//3 bits
|
char getAudioConfigMode(); // 3 bits
|
||||||
void setAudioConfigMode(char newVal);//3 bits
|
void setAudioConfigMode(char newVal); // 3 bits
|
||||||
bool getLowFrequencyEffectsChannelOn();//1bit
|
bool getLowFrequencyEffectsChannelOn(); // 1bit
|
||||||
void setLowFrequencyEffectsChannelOn(bool newVal);//1bit
|
void setLowFrequencyEffectsChannelOn(bool newVal); // 1bit
|
||||||
char getFrameSizeCode();//6bits
|
char getFrameSizeCode(); // 6bits
|
||||||
void setFrameSizeCode(char newVal);//6bits
|
void setFrameSizeCode(char newVal); // 6bits
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FTYP: public Box {
|
class FTYP : public Box{
|
||||||
public:
|
public:
|
||||||
FTYP(bool fillDefaults = true);
|
FTYP(bool fillDefaults = true);
|
||||||
void setMajorBrand(const char * newMajorBrand);
|
void setMajorBrand(const char *newMajorBrand);
|
||||||
std::string getMajorBrand();
|
std::string getMajorBrand();
|
||||||
void setMinorVersion(const char * newMinorVersion);
|
void setMinorVersion(const char *newMinorVersion);
|
||||||
std::string getMinorVersion();
|
std::string getMinorVersion();
|
||||||
size_t getCompatibleBrandsCount();
|
size_t getCompatibleBrandsCount();
|
||||||
void setCompatibleBrands(const char * newCompatibleBrand, size_t index);
|
void setCompatibleBrands(const char *newCompatibleBrand, size_t index);
|
||||||
std::string getCompatibleBrands(size_t index);
|
std::string getCompatibleBrands(size_t index);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STYP: public FTYP {
|
class STYP : public FTYP{
|
||||||
public:
|
public:
|
||||||
STYP(bool fillDefaults = true);
|
STYP(bool fillDefaults = true);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MOOV: public containerBox {
|
class MOOV : public containerBox{
|
||||||
public:
|
public:
|
||||||
MOOV();
|
MOOV();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MVEX: public containerBox {
|
class MVEX : public containerBox{
|
||||||
public:
|
public:
|
||||||
MVEX();
|
MVEX();
|
||||||
};
|
};
|
||||||
|
|
||||||
class TREX: public fullBox {
|
class TREX : public fullBox{
|
||||||
public:
|
public:
|
||||||
TREX(unsigned int trackId = 0);
|
TREX(unsigned int trackId = 0);
|
||||||
void setTrackID(uint32_t newTrackID);
|
void setTrackID(uint32_t newTrackID);
|
||||||
|
@ -316,33 +312,32 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MFRA : public containerBox{
|
||||||
class MFRA: public containerBox {
|
|
||||||
public:
|
public:
|
||||||
MFRA();
|
MFRA();
|
||||||
};
|
};
|
||||||
|
|
||||||
class TRAK: public containerBox {
|
class TRAK : public containerBox{
|
||||||
public:
|
public:
|
||||||
TRAK();
|
TRAK();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MDIA: public containerBox {
|
class MDIA : public containerBox{
|
||||||
public:
|
public:
|
||||||
MDIA();
|
MDIA();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MINF: public containerBox {
|
class MINF : public containerBox{
|
||||||
public:
|
public:
|
||||||
MINF();
|
MINF();
|
||||||
};
|
};
|
||||||
|
|
||||||
class DINF: public containerBox {
|
class DINF : public containerBox{
|
||||||
public:
|
public:
|
||||||
DINF();
|
DINF();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MFRO: public Box {
|
class MFRO : public Box{
|
||||||
public:
|
public:
|
||||||
MFRO();
|
MFRO();
|
||||||
void setSize(uint32_t newSize);
|
void setSize(uint32_t newSize);
|
||||||
|
@ -350,17 +345,17 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class HDLR: public Box {
|
class HDLR : public Box{
|
||||||
public:
|
public:
|
||||||
HDLR(const std::string & type = "", const std::string & name = "");
|
HDLR(const std::string &type = "", const std::string &name = "");
|
||||||
void setHandlerType(const char * newHandlerType);
|
void setHandlerType(const char *newHandlerType);
|
||||||
std::string getHandlerType();
|
std::string getHandlerType();
|
||||||
void setName(std::string newName);
|
void setName(std::string newName);
|
||||||
std::string getName();
|
std::string getName();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class VMHD: public fullBox {
|
class VMHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
VMHD();
|
VMHD();
|
||||||
void setGraphicsMode(uint16_t newGraphicsMode);
|
void setGraphicsMode(uint16_t newGraphicsMode);
|
||||||
|
@ -371,7 +366,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SMHD: public fullBox {
|
class SMHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
SMHD();
|
SMHD();
|
||||||
void setBalance(int16_t newBalance);
|
void setBalance(int16_t newBalance);
|
||||||
|
@ -379,13 +374,13 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STHD: public fullBox {
|
class STHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
STHD();
|
STHD();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class HMHD: public fullBox {
|
class HMHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
HMHD();
|
HMHD();
|
||||||
void setMaxPDUSize(uint16_t newMaxPDUSize);
|
void setMaxPDUSize(uint16_t newMaxPDUSize);
|
||||||
|
@ -399,13 +394,13 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NMHD: public fullBox {
|
class NMHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
NMHD();
|
NMHD();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MEHD: public fullBox {
|
class MEHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
MEHD();
|
MEHD();
|
||||||
void setFragmentDuration(uint64_t newFragmentDuration);
|
void setFragmentDuration(uint64_t newFragmentDuration);
|
||||||
|
@ -413,12 +408,12 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STBL: public containerBox {
|
class STBL : public containerBox{
|
||||||
public:
|
public:
|
||||||
STBL();
|
STBL();
|
||||||
};
|
};
|
||||||
|
|
||||||
class URL: public fullBox {
|
class URL : public fullBox{
|
||||||
public:
|
public:
|
||||||
URL();
|
URL();
|
||||||
void setLocation(std::string newLocation);
|
void setLocation(std::string newLocation);
|
||||||
|
@ -426,7 +421,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class URN: public fullBox {
|
class URN : public fullBox{
|
||||||
public:
|
public:
|
||||||
URN();
|
URN();
|
||||||
void setName(std::string newName);
|
void setName(std::string newName);
|
||||||
|
@ -436,16 +431,16 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DREF: public fullBox {
|
class DREF : public fullBox{
|
||||||
public:
|
public:
|
||||||
DREF();
|
DREF();
|
||||||
uint32_t getEntryCount();
|
uint32_t getEntryCount();
|
||||||
void setDataEntry(fullBox & newDataEntry, size_t index);
|
void setDataEntry(fullBox &newDataEntry, size_t index);
|
||||||
Box & getDataEntry(size_t index);
|
Box &getDataEntry(size_t index);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MVHD: public fullBox {
|
class MVHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
MVHD(long long unsigned int duration);
|
MVHD(long long unsigned int duration);
|
||||||
void setCreationTime(uint64_t newCreationTime);
|
void setCreationTime(uint64_t newCreationTime);
|
||||||
|
@ -468,7 +463,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TFRAEntry {
|
struct TFRAEntry{
|
||||||
uint64_t time;
|
uint64_t time;
|
||||||
uint64_t moofOffset;
|
uint64_t moofOffset;
|
||||||
uint32_t trafNumber;
|
uint32_t trafNumber;
|
||||||
|
@ -476,7 +471,7 @@ namespace MP4 {
|
||||||
uint32_t sampleNumber;
|
uint32_t sampleNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TFRA: public fullBox {
|
class TFRA : public fullBox{
|
||||||
public:
|
public:
|
||||||
TFRA();
|
TFRA();
|
||||||
void setTrackID(uint32_t newTrackID);
|
void setTrackID(uint32_t newTrackID);
|
||||||
|
@ -490,15 +485,15 @@ namespace MP4 {
|
||||||
void setNumberOfEntry(uint32_t newNumberOfEntry);
|
void setNumberOfEntry(uint32_t newNumberOfEntry);
|
||||||
uint32_t getNumberOfEntry();
|
uint32_t getNumberOfEntry();
|
||||||
void setTFRAEntry(TFRAEntry newTFRAEntry, uint32_t no);
|
void setTFRAEntry(TFRAEntry newTFRAEntry, uint32_t no);
|
||||||
TFRAEntry & getTFRAEntry(uint32_t no);
|
TFRAEntry &getTFRAEntry(uint32_t no);
|
||||||
uint32_t getTFRAEntrySize();
|
uint32_t getTFRAEntrySize();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TKHD: public fullBox {
|
class TKHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
TKHD(uint32_t trackId = 0, uint64_t duration = 0, uint32_t width = 0, uint32_t height = 0);
|
TKHD(uint32_t trackId = 0, uint64_t duration = 0, uint32_t width = 0, uint32_t height = 0);
|
||||||
TKHD(DTSC::Track & track, bool fragmented);
|
TKHD(DTSC::Track &track, bool fragmented);
|
||||||
|
|
||||||
void setCreationTime(uint64_t newCreationTime);
|
void setCreationTime(uint64_t newCreationTime);
|
||||||
uint64_t getCreationTime();
|
uint64_t getCreationTime();
|
||||||
|
@ -525,11 +520,12 @@ namespace MP4 {
|
||||||
void setHeight(double newHeight);
|
void setHeight(double newHeight);
|
||||||
double getHeight();
|
double getHeight();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize();
|
void initialize();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MDHD: public fullBox {
|
class MDHD : public fullBox{
|
||||||
public:
|
public:
|
||||||
MDHD(uint64_t duration = 0);
|
MDHD(uint64_t duration = 0);
|
||||||
void setCreationTime(uint64_t newCreationTime);
|
void setCreationTime(uint64_t newCreationTime);
|
||||||
|
@ -542,17 +538,17 @@ namespace MP4 {
|
||||||
uint64_t getDuration();
|
uint64_t getDuration();
|
||||||
void setLanguage(uint16_t newLanguage);
|
void setLanguage(uint16_t newLanguage);
|
||||||
uint16_t getLanguageInt();
|
uint16_t getLanguageInt();
|
||||||
void setLanguage(const std::string & newLanguage);
|
void setLanguage(const std::string &newLanguage);
|
||||||
std::string getLanguage();
|
std::string getLanguage();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct STTSEntry {
|
struct STTSEntry{
|
||||||
uint32_t sampleCount;
|
uint32_t sampleCount;
|
||||||
uint32_t sampleDelta;
|
uint32_t sampleDelta;
|
||||||
};
|
};
|
||||||
|
|
||||||
class STTS: public fullBox {
|
class STTS : public fullBox{
|
||||||
public:
|
public:
|
||||||
STTS(char v = 1, uint32_t f = 0);
|
STTS(char v = 1, uint32_t f = 0);
|
||||||
void setEntryCount(uint32_t newEntryCount);
|
void setEntryCount(uint32_t newEntryCount);
|
||||||
|
@ -562,12 +558,12 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CTTSEntry {
|
struct CTTSEntry{
|
||||||
uint32_t sampleCount;
|
uint32_t sampleCount;
|
||||||
int32_t sampleOffset;
|
int32_t sampleOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CTTS: public fullBox {
|
class CTTS : public fullBox{
|
||||||
public:
|
public:
|
||||||
CTTS();
|
CTTS();
|
||||||
void setEntryCount(uint32_t newEntryCount);
|
void setEntryCount(uint32_t newEntryCount);
|
||||||
|
@ -577,7 +573,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STSCEntry {
|
class STSCEntry{
|
||||||
public:
|
public:
|
||||||
STSCEntry(unsigned int _first = 0, unsigned int _count = 0, unsigned int _index = 0);
|
STSCEntry(unsigned int _first = 0, unsigned int _count = 0, unsigned int _index = 0);
|
||||||
uint32_t firstChunk;
|
uint32_t firstChunk;
|
||||||
|
@ -585,7 +581,7 @@ namespace MP4 {
|
||||||
uint32_t sampleDescriptionIndex;
|
uint32_t sampleDescriptionIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class STSC: public fullBox {
|
class STSC : public fullBox{
|
||||||
public:
|
public:
|
||||||
STSC(char v = 1, uint32_t f = 0);
|
STSC(char v = 1, uint32_t f = 0);
|
||||||
void setEntryCount(uint32_t newEntryCount);
|
void setEntryCount(uint32_t newEntryCount);
|
||||||
|
@ -595,7 +591,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STCO: public fullBox {
|
class STCO : public fullBox{
|
||||||
public:
|
public:
|
||||||
STCO(char v = 1, uint32_t f = 0);
|
STCO(char v = 1, uint32_t f = 0);
|
||||||
void setEntryCount(uint32_t newEntryCount);
|
void setEntryCount(uint32_t newEntryCount);
|
||||||
|
@ -605,7 +601,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CO64: public fullBox {
|
class CO64 : public fullBox{
|
||||||
public:
|
public:
|
||||||
CO64(char v = 1, uint32_t f = 0);
|
CO64(char v = 1, uint32_t f = 0);
|
||||||
void setEntryCount(uint32_t newEntryCount);
|
void setEntryCount(uint32_t newEntryCount);
|
||||||
|
@ -615,7 +611,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STSZ: public fullBox {
|
class STSZ : public fullBox{
|
||||||
public:
|
public:
|
||||||
STSZ(char v = 1, uint32_t f = 0);
|
STSZ(char v = 1, uint32_t f = 0);
|
||||||
void setSampleSize(uint32_t newSampleSize);
|
void setSampleSize(uint32_t newSampleSize);
|
||||||
|
@ -627,7 +623,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SampleEntry: public Box {
|
class SampleEntry : public Box{
|
||||||
public:
|
public:
|
||||||
SampleEntry();
|
SampleEntry();
|
||||||
void setDataReferenceIndex(uint16_t newDataReferenceIndex);
|
void setDataReferenceIndex(uint16_t newDataReferenceIndex);
|
||||||
|
@ -635,7 +631,7 @@ namespace MP4 {
|
||||||
std::string toPrettySampleString(uint32_t index);
|
std::string toPrettySampleString(uint32_t index);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CLAP: public Box { //CleanApertureBox
|
class CLAP : public Box{// CleanApertureBox
|
||||||
public:
|
public:
|
||||||
CLAP();
|
CLAP();
|
||||||
void setCleanApertureWidthN(uint32_t newVal);
|
void setCleanApertureWidthN(uint32_t newVal);
|
||||||
|
@ -657,7 +653,7 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PASP: public Box { //PixelAspectRatioBox
|
class PASP : public Box{// PixelAspectRatioBox
|
||||||
public:
|
public:
|
||||||
PASP(uint32_t hSpacing = 1, uint32_t vSpacing = 1);
|
PASP(uint32_t hSpacing = 1, uint32_t vSpacing = 1);
|
||||||
void setHSpacing(uint32_t newVal);
|
void setHSpacing(uint32_t newVal);
|
||||||
|
@ -667,13 +663,13 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class VisualSampleEntry: public SampleEntry {
|
class VisualSampleEntry : public SampleEntry{
|
||||||
///\todo set default values
|
///\todo set default values
|
||||||
public:
|
public:
|
||||||
VisualSampleEntry();
|
VisualSampleEntry();
|
||||||
VisualSampleEntry(DTSC::Track & track);
|
VisualSampleEntry(DTSC::Track &track);
|
||||||
void initialize();
|
void initialize();
|
||||||
void setCodec(const char * newCodec);
|
void setCodec(const char *newCodec);
|
||||||
void setWidth(uint16_t newWidth);
|
void setWidth(uint16_t newWidth);
|
||||||
uint16_t getWidth();
|
uint16_t getWidth();
|
||||||
void setHeight(uint16_t newHeight);
|
void setHeight(uint16_t newHeight);
|
||||||
|
@ -688,25 +684,25 @@ namespace MP4 {
|
||||||
std::string getCompressorName();
|
std::string getCompressorName();
|
||||||
void setDepth(uint16_t newDepth);
|
void setDepth(uint16_t newDepth);
|
||||||
uint16_t getDepth();
|
uint16_t getDepth();
|
||||||
Box & getCLAP();
|
Box &getCLAP();
|
||||||
void setCLAP(Box & clap);
|
void setCLAP(Box &clap);
|
||||||
Box & getPASP();
|
Box &getPASP();
|
||||||
void setPASP(Box & pasp);
|
void setPASP(Box &pasp);
|
||||||
|
|
||||||
size_t getBoxEntryCount();
|
size_t getBoxEntryCount();
|
||||||
Box & getBoxEntry(size_t index);
|
Box &getBoxEntry(size_t index);
|
||||||
void setBoxEntry(size_t index, Box & box);
|
void setBoxEntry(size_t index, Box &box);
|
||||||
|
|
||||||
std::string toPrettyVisualString(uint32_t index = 0, std::string = "");
|
std::string toPrettyVisualString(uint32_t index = 0, std::string = "");
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioSampleEntry: public SampleEntry {
|
class AudioSampleEntry : public SampleEntry{
|
||||||
public:
|
public:
|
||||||
///\todo set default values
|
///\todo set default values
|
||||||
AudioSampleEntry();
|
AudioSampleEntry();
|
||||||
AudioSampleEntry(DTSC::Track & track);
|
AudioSampleEntry(DTSC::Track &track);
|
||||||
void initialize();
|
void initialize();
|
||||||
void setCodec(const char * newCodec);
|
void setCodec(const char *newCodec);
|
||||||
void setChannelCount(uint16_t newChannelCount);
|
void setChannelCount(uint16_t newChannelCount);
|
||||||
uint16_t getChannelCount();
|
uint16_t getChannelCount();
|
||||||
void setSampleSize(uint16_t newSampleSize);
|
void setSampleSize(uint16_t newSampleSize);
|
||||||
|
@ -716,20 +712,20 @@ namespace MP4 {
|
||||||
void setSampleRate(uint32_t newSampleRate);
|
void setSampleRate(uint32_t newSampleRate);
|
||||||
uint16_t toAACInit();
|
uint16_t toAACInit();
|
||||||
uint32_t getSampleRate();
|
uint32_t getSampleRate();
|
||||||
void setCodecBox(Box & newBox);
|
void setCodecBox(Box &newBox);
|
||||||
Box & getCodecBox();
|
Box &getCodecBox();
|
||||||
Box & getSINFBox(); /*LTS*/
|
Box &getSINFBox(); /*LTS*/
|
||||||
std::string toPrettyAudioString(uint32_t indent = 0, std::string name = "");
|
std::string toPrettyAudioString(uint32_t indent = 0, std::string name = "");
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BoxRecord {
|
struct BoxRecord{
|
||||||
int16_t top;
|
int16_t top;
|
||||||
int16_t left;
|
int16_t left;
|
||||||
int16_t bottom;
|
int16_t bottom;
|
||||||
int16_t right;
|
int16_t right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StyleRecord {
|
struct StyleRecord{
|
||||||
uint16_t startChar;
|
uint16_t startChar;
|
||||||
uint16_t endChar;
|
uint16_t endChar;
|
||||||
uint16_t font_id;
|
uint16_t font_id;
|
||||||
|
@ -738,19 +734,19 @@ namespace MP4 {
|
||||||
uint8_t text_color_rgba[4];
|
uint8_t text_color_rgba[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
class FontRecord {
|
class FontRecord{
|
||||||
public:
|
public:
|
||||||
FontRecord();
|
FontRecord();
|
||||||
~FontRecord();
|
~FontRecord();
|
||||||
uint16_t font_id;
|
uint16_t font_id;
|
||||||
uint8_t font_name_length;
|
uint8_t font_name_length;
|
||||||
char* font;
|
char *font;
|
||||||
//uint8_t font[font_name_length];
|
// uint8_t font[font_name_length];
|
||||||
|
|
||||||
void setFont(const char* f);
|
void setFont(const char *f);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FontTableBox: public Box {
|
class FontTableBox : public Box{
|
||||||
public:
|
public:
|
||||||
FontTableBox();
|
FontTableBox();
|
||||||
void setEntryCount(uint16_t);
|
void setEntryCount(uint16_t);
|
||||||
|
@ -759,13 +755,13 @@ namespace MP4 {
|
||||||
void setFontRecord(FontRecord f);
|
void setFontRecord(FontRecord f);
|
||||||
FontRecord font_entry[1];
|
FontRecord font_entry[1];
|
||||||
void setFontId(uint16_t id);
|
void setFontId(uint16_t id);
|
||||||
//FontRecord font_entry[entry_count];
|
// FontRecord font_entry[entry_count];
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextSampleEntry: public SampleEntry {
|
class TextSampleEntry : public SampleEntry{
|
||||||
public:
|
public:
|
||||||
TextSampleEntry();
|
TextSampleEntry();
|
||||||
TextSampleEntry(DTSC::Track & track);
|
TextSampleEntry(DTSC::Track &track);
|
||||||
void initialize();
|
void initialize();
|
||||||
void setHzJustification(int8_t n);
|
void setHzJustification(int8_t n);
|
||||||
void setVtJustification(int8_t n);
|
void setVtJustification(int8_t n);
|
||||||
|
@ -776,9 +772,9 @@ namespace MP4 {
|
||||||
uint8_t getBackGroundColorRGBA(uint8_t n = 0);
|
uint8_t getBackGroundColorRGBA(uint8_t n = 0);
|
||||||
void setBackGroundColorRGBA(uint8_t pos, uint8_t value);
|
void setBackGroundColorRGBA(uint8_t pos, uint8_t value);
|
||||||
|
|
||||||
void setCodec(const char * newCodec);
|
void setCodec(const char *newCodec);
|
||||||
void setCodecBox(Box & newBox);
|
void setCodecBox(Box &newBox);
|
||||||
Box & getCodecBox();
|
Box &getCodecBox();
|
||||||
|
|
||||||
BoxRecord getBoxRecord();
|
BoxRecord getBoxRecord();
|
||||||
void setBoxRecord(BoxRecord b);
|
void setBoxRecord(BoxRecord b);
|
||||||
|
@ -789,52 +785,46 @@ namespace MP4 {
|
||||||
FontTableBox getFontTableBox();
|
FontTableBox getFontTableBox();
|
||||||
void setFontTableBox(FontTableBox f);
|
void setFontTableBox(FontTableBox f);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string toPrettyTextString(uint32_t indent = 0, std::string name = "");
|
std::string toPrettyTextString(uint32_t indent = 0, std::string name = "");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TX3G : public TextSampleEntry{
|
||||||
|
|
||||||
class TX3G: public TextSampleEntry {
|
|
||||||
public:
|
public:
|
||||||
TX3G();
|
TX3G();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MP4A : public AudioSampleEntry{
|
||||||
|
|
||||||
class MP4A: public AudioSampleEntry {
|
|
||||||
public:
|
public:
|
||||||
MP4A();
|
MP4A();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AAC: public AudioSampleEntry {
|
class AAC : public AudioSampleEntry{
|
||||||
public:
|
public:
|
||||||
AAC();
|
AAC();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class HEV1: public VisualSampleEntry {
|
class HEV1 : public VisualSampleEntry{
|
||||||
public:
|
public:
|
||||||
HEV1();
|
HEV1();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AVC1: public VisualSampleEntry {
|
class AVC1 : public VisualSampleEntry{
|
||||||
public:
|
public:
|
||||||
AVC1();
|
AVC1();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class H264: public VisualSampleEntry {
|
class H264 : public VisualSampleEntry{
|
||||||
public:
|
public:
|
||||||
H264();
|
H264();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FIEL: public Box {
|
class FIEL : public Box{
|
||||||
public:
|
public:
|
||||||
FIEL();
|
FIEL();
|
||||||
void setTotal(char newTotal);
|
void setTotal(char newTotal);
|
||||||
|
@ -844,37 +834,37 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class STSD: public fullBox {
|
class STSD : public fullBox{
|
||||||
public:
|
public:
|
||||||
STSD(char v = 1, uint32_t f = 0);
|
STSD(char v = 1, uint32_t f = 0);
|
||||||
void setEntryCount(uint32_t newEntryCount);
|
void setEntryCount(uint32_t newEntryCount);
|
||||||
uint32_t getEntryCount();
|
uint32_t getEntryCount();
|
||||||
void setEntry(Box & newContent, uint32_t no);
|
void setEntry(Box &newContent, 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 GMHD: public containerBox {
|
class GMHD : public containerBox{
|
||||||
public:
|
public:
|
||||||
GMHD();
|
GMHD();
|
||||||
};
|
};
|
||||||
|
|
||||||
class TREF: public containerBox {
|
class TREF : public containerBox{
|
||||||
public:
|
public:
|
||||||
TREF();
|
TREF();
|
||||||
};
|
};
|
||||||
|
|
||||||
class EDTS: public containerBox {
|
class EDTS : public containerBox{
|
||||||
public:
|
public:
|
||||||
EDTS();
|
EDTS();
|
||||||
};
|
};
|
||||||
|
|
||||||
class UDTA: public containerBox {
|
class UDTA : public containerBox{
|
||||||
public:
|
public:
|
||||||
UDTA();
|
UDTA();
|
||||||
};
|
};
|
||||||
|
|
||||||
class STSS: public fullBox {
|
class STSS : public fullBox{
|
||||||
public:
|
public:
|
||||||
STSS(char v = 1, uint32_t f = 0);
|
STSS(char v = 1, uint32_t f = 0);
|
||||||
void setEntryCount(uint32_t newVal);
|
void setEntryCount(uint32_t newVal);
|
||||||
|
@ -884,13 +874,13 @@ namespace MP4 {
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class META: public containerFullBox {
|
class META : public containerFullBox{
|
||||||
public:
|
public:
|
||||||
META();
|
META();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ELST: public fullBox {
|
class ELST : public fullBox{
|
||||||
public:
|
public:
|
||||||
ELST();
|
ELST();
|
||||||
void setCount(uint32_t newVal);
|
void setCount(uint32_t newVal);
|
||||||
|
@ -905,5 +895,4 @@ namespace MP4 {
|
||||||
uint16_t getMediaRateFraction(uint32_t cnt);
|
uint16_t getMediaRateFraction(uint32_t cnt);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
}
|
}// namespace MP4
|
||||||
|
|
||||||
|
|
242
lib/mp4_ms.cpp
242
lib/mp4_ms.cpp
|
@ -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
|
||||||
|
|
16
lib/mp4_ms.h
16
lib/mp4_ms.h
|
@ -1,8 +1,8 @@
|
||||||
#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);
|
||||||
|
@ -12,16 +12,16 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -37,7 +37,7 @@ namespace MP4 {
|
||||||
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);
|
||||||
|
@ -50,4 +50,4 @@ namespace MP4 {
|
||||||
uint64_t getDuration();
|
uint64_t getDuration();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
}
|
}// namespace MP4
|
||||||
|
|
|
@ -81,4 +81,3 @@ namespace Mpeg{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}// namespace Mpeg
|
}// namespace Mpeg
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
436
lib/ogg.cpp
436
lib/ogg.cpp
|
@ -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,98 +244,64 @@ 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,
|
|
||||||
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,
|
0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 ¤tSegment){
|
||||||
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.
|
||||||
|
// inc. page num, write to header
|
||||||
//done sending, assume start of new page.
|
|
||||||
//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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
108
lib/ogg.h
108
lib/ogg.h
|
@ -1,17 +1,17 @@
|
||||||
#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;
|
||||||
|
@ -22,29 +22,21 @@ namespace OGG {
|
||||||
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,
|
|
||||||
BeginOfStream = 2,
|
|
||||||
EndOfStream = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
std::deque<unsigned int> decodeXiphSize(char * data, size_t len);
|
std::deque<unsigned int> decodeXiphSize(char *data, size_t len);
|
||||||
|
|
||||||
|
class Page{
|
||||||
|
|
||||||
|
|
||||||
class Page {
|
|
||||||
public:
|
public:
|
||||||
Page();
|
Page();
|
||||||
Page(const Page & rhs);
|
Page(const Page &rhs);
|
||||||
void operator = (const Page & rhs);
|
void operator=(const Page &rhs);
|
||||||
bool read(std::string & newData);
|
bool read(std::string &newData);
|
||||||
bool read(FILE * inFile);
|
bool read(FILE *inFile);
|
||||||
bool getSegment(unsigned int index, std::string & ret);
|
bool getSegment(unsigned int index, std::string &ret);
|
||||||
const char * getSegment(unsigned int index);
|
const char *getSegment(unsigned int index);
|
||||||
unsigned long getSegmentLen(unsigned int index);
|
unsigned long getSegmentLen(unsigned int index);
|
||||||
void setMagicNumber();
|
void setMagicNumber();
|
||||||
char getVersion();
|
char getVersion();
|
||||||
|
@ -59,10 +51,10 @@ namespace OGG {
|
||||||
void setCRCChecksum(long unsigned int newVal);
|
void setCRCChecksum(long unsigned int newVal);
|
||||||
long unsigned int getPageSequenceNumber();
|
long unsigned int getPageSequenceNumber();
|
||||||
void setPageSequenceNumber(long unsigned int newVal);
|
void setPageSequenceNumber(long unsigned int newVal);
|
||||||
char getPageSegments();//get the amount of page segments
|
char getPageSegments(); // get the amount of page segments
|
||||||
inline void setPageSegments(char newVal);//set the amount of page segments
|
inline void setPageSegments(char newVal); // set the amount of page segments
|
||||||
int getPayloadSize();
|
int getPayloadSize();
|
||||||
const std::deque<std::string> & getAllSegments();
|
const std::deque<std::string> &getAllSegments();
|
||||||
|
|
||||||
bool possiblyContinued();
|
bool possiblyContinued();
|
||||||
|
|
||||||
|
@ -71,46 +63,44 @@ namespace OGG {
|
||||||
long unsigned int calcChecksum();
|
long unsigned int calcChecksum();
|
||||||
bool verifyChecksum();
|
bool verifyChecksum();
|
||||||
unsigned int calcPayloadSize();
|
unsigned int calcPayloadSize();
|
||||||
//void clear();
|
// void clear();
|
||||||
void clear(char HeaderType, long long unsigned int GranPos, long unsigned int BSN, long unsigned int PSN);
|
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
|
void prepareNext(bool continueMe = false); // prepare the page to become the next page
|
||||||
bool setPayload(char * newData, unsigned int length); //probably obsolete
|
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 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
|
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
|
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 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;
|
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);
|
long long unsigned int calculateGranule(oggSegment ¤tSegment);
|
||||||
bool shouldSend();
|
bool shouldSend();
|
||||||
void vorbisStuff();//process most recent segment
|
void vorbisStuff(); // process most recent segment
|
||||||
long long unsigned int totalFrames;
|
long long unsigned int totalFrames;
|
||||||
int granules;
|
int granules;
|
||||||
OGG::oggCodec codec;
|
OGG::oggCodec codec;
|
||||||
std::deque<oggSegment> oggSegments; //used for ogg output
|
std::deque<oggSegment> oggSegments; // used for ogg output
|
||||||
unsigned int pageSequenceNumber;
|
unsigned int pageSequenceNumber;
|
||||||
|
|
||||||
unsigned int framesSeen;
|
unsigned int framesSeen;
|
||||||
unsigned int lastKeyFrame;
|
unsigned int lastKeyFrame;
|
||||||
unsigned int firstSample;//for vorbis, to handle "when to send the page"
|
unsigned int firstSample; // for vorbis, to handle "when to send the page"
|
||||||
unsigned int sampleRate;//for vorbis, to handle the sampleRate
|
unsigned int sampleRate; // for vorbis, to handle the sampleRate
|
||||||
int prevBlockFlag;
|
int prevBlockFlag;
|
||||||
char blockSize[2];
|
char blockSize[2];
|
||||||
std::deque<vorbis::mode> vorbisModes;//modes for vorbis
|
std::deque<vorbis::mode> vorbisModes; // modes for vorbis
|
||||||
unsigned int split; //KFGShift for theora
|
unsigned int split; // KFGShift for theora
|
||||||
private:
|
private:
|
||||||
char data[282];//Fulldata
|
char data[282]; // Fulldata
|
||||||
std::deque<std::string> segments;
|
std::deque<std::string> segments;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class oggTrack {
|
class oggTrack{
|
||||||
public:
|
public:
|
||||||
oggTrack() : KFGShift(0), lastTime(0), parsedHeaders(false), lastPageOffset(0), nxtSegment(0){ }
|
oggTrack() : KFGShift(0), lastTime(0), parsedHeaders(false), lastPageOffset(0), nxtSegment(0){}
|
||||||
oggCodec codec;
|
oggCodec codec;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string contBuffer;//buffer for continuing pages
|
std::string contBuffer; // buffer for continuing pages
|
||||||
long long unsigned int dtscID;
|
long long unsigned int dtscID;
|
||||||
char KFGShift;
|
char KFGShift;
|
||||||
double lastTime;
|
double lastTime;
|
||||||
|
@ -120,22 +110,20 @@ namespace OGG {
|
||||||
unsigned int nxtSegment;
|
unsigned int nxtSegment;
|
||||||
double msPerFrame;
|
double msPerFrame;
|
||||||
Page myPage;
|
Page myPage;
|
||||||
//Codec specific elements
|
// Codec specific elements
|
||||||
//theora
|
// theora
|
||||||
// theora::header idHeader;//needed to determine keyframe //bullshit?
|
// theora::header idHeader;//needed to determine keyframe //bullshit?
|
||||||
//vorbis
|
// vorbis
|
||||||
std::deque<vorbis::mode> vModes;
|
std::deque<vorbis::mode> vModes;
|
||||||
char channels;
|
char channels;
|
||||||
long long unsigned int blockSize[2];
|
long long unsigned int blockSize[2];
|
||||||
//unsigned long getBlockSize(unsigned int vModeIndex);
|
// unsigned long getBlockSize(unsigned int vModeIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
class headerPages {
|
class headerPages{
|
||||||
public:
|
public:
|
||||||
std::map <long long unsigned int, unsigned int> DTSCID2OGGSerial;
|
std::map<long long unsigned int, unsigned int> DTSCID2OGGSerial;
|
||||||
std::map <long long unsigned int, unsigned int> DTSCID2seqNum;
|
std::map<long long unsigned int, unsigned int> DTSCID2seqNum;
|
||||||
std::string parsedPages;
|
std::string parsedPages;
|
||||||
};
|
};
|
||||||
}
|
}// namespace OGG
|
||||||
|
|
||||||
|
|
||||||
|
|
16
lib/opus.cpp
16
lib/opus.cpp
|
@ -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;
|
||||||
|
@ -19,13 +16,13 @@ namespace Opus{
|
||||||
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;
|
||||||
|
@ -34,8 +31,8 @@ namespace Opus{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
280
lib/procs.cpp
280
lib/procs.cpp
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
lib/procs.h
34
lib/procs.h
|
@ -2,37 +2,38 @@
|
||||||
/// 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:
|
public:
|
||||||
static bool childRunning(pid_t p);
|
static bool childRunning(pid_t p);
|
||||||
static tthread::thread * reaper_thread;
|
static tthread::thread *reaper_thread;
|
||||||
static bool handler_set; ///< If true, the sigchld handler has been setup.
|
static bool handler_set; ///< If true, the sigchld handler has been setup.
|
||||||
static void fork_prepare();
|
static void fork_prepare();
|
||||||
static void fork_complete();
|
static void fork_complete();
|
||||||
static void setHandler();
|
static void setHandler();
|
||||||
static std::string getOutputOf(char * const * argv);
|
static std::string getOutputOf(char *const *argv);
|
||||||
static std::string getOutputOf(std::deque<std::string> & argDeq);
|
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(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 pid_t StartPiped(std::deque<std::string> &argDeq, int *fdin, int *fdout, int *fderr);
|
||||||
static void Stop(pid_t name);
|
static void Stop(pid_t name);
|
||||||
static void Murder(pid_t name);
|
static void Murder(pid_t name);
|
||||||
static void StopAll();
|
static void StopAll();
|
||||||
|
@ -43,5 +44,4 @@ namespace Util {
|
||||||
static void remember(pid_t pid);
|
static void remember(pid_t pid);
|
||||||
static std::set<int> socketList; ///< Holds sockets that should be closed before forking
|
static std::set<int> socketList; ///< Holds sockets that should be closed before forking
|
||||||
};
|
};
|
||||||
}
|
}// namespace Util
|
||||||
|
|
||||||
|
|
46
lib/riff.cpp
46
lib/riff.cpp
|
@ -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
|
||||||
|
|
||||||
|
|
13
lib/riff.h
13
lib/riff.h
|
@ -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
|
||||||
}
|
|
||||||
|
|
||||||
|
|
719
lib/rijndael.cpp
719
lib/rijndael.cpp
|
@ -1,172 +1,353 @@
|
||||||
// This entire file is public domain and comes with no warranties.
|
// This entire file is public domain and comes with no warranties.
|
||||||
// Based on work by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto.
|
// Based on work by Vincent Rijmen, Antoon Bosselaers and Paulo Barreto.
|
||||||
#include "rijndael.h"
|
|
||||||
#include "bitfields.h"
|
#include "bitfields.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
#include "rijndael.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
static const unsigned int Te0[256] = {
|
static const unsigned int Te0[256] ={
|
||||||
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
|
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U,
|
||||||
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
|
0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U,
|
||||||
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
|
0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U,
|
||||||
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
|
0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
|
||||||
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
|
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU,
|
||||||
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
|
0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U,
|
||||||
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
|
0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU,
|
||||||
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
|
0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
|
||||||
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
|
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU,
|
||||||
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
|
0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U,
|
||||||
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
|
0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU,
|
||||||
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
|
0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
|
||||||
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
|
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U,
|
||||||
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
|
0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU,
|
||||||
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
|
0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU,
|
||||||
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
|
0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
|
||||||
|
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U,
|
||||||
|
0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU,
|
||||||
|
0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U,
|
||||||
|
0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
|
||||||
|
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U,
|
||||||
|
0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U,
|
||||||
|
0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU,
|
||||||
|
0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
|
||||||
|
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U,
|
||||||
|
0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U,
|
||||||
|
0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU,
|
||||||
|
0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
|
||||||
|
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU,
|
||||||
|
0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U,
|
||||||
|
0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U,
|
||||||
|
0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
|
||||||
|
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U,
|
||||||
|
0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU,
|
||||||
|
0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU,
|
||||||
|
0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
|
||||||
|
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
|
||||||
};
|
};
|
||||||
static const unsigned int Te1[256] = {
|
static const unsigned int Te1[256] ={
|
||||||
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
|
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU,
|
||||||
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
|
0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U,
|
||||||
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
|
0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU,
|
||||||
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
|
0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
|
||||||
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
|
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U,
|
||||||
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
|
0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U,
|
||||||
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
|
0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U,
|
||||||
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
|
0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
|
||||||
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
|
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U,
|
||||||
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
|
0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU,
|
||||||
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
|
0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U,
|
||||||
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
|
0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
|
||||||
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
|
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU,
|
||||||
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
|
0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU,
|
||||||
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
|
0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U,
|
||||||
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
|
0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
|
||||||
|
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U,
|
||||||
|
0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU,
|
||||||
|
0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU,
|
||||||
|
0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
|
||||||
|
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU,
|
||||||
|
0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU,
|
||||||
|
0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U,
|
||||||
|
0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
|
||||||
|
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U,
|
||||||
|
0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U,
|
||||||
|
0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U,
|
||||||
|
0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
|
||||||
|
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U,
|
||||||
|
0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU,
|
||||||
|
0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U,
|
||||||
|
0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
|
||||||
|
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU,
|
||||||
|
0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U,
|
||||||
|
0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU,
|
||||||
|
0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
|
||||||
|
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
|
||||||
};
|
};
|
||||||
static const unsigned int Te2[256] = {
|
static const unsigned int Te2[256] ={
|
||||||
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
|
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU,
|
||||||
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
|
0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U,
|
||||||
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
|
0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU,
|
||||||
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
|
0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
|
||||||
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
|
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U,
|
||||||
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
|
0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U,
|
||||||
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
|
0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U,
|
||||||
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
|
0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
|
||||||
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
|
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U,
|
||||||
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
|
0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU,
|
||||||
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
|
0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U,
|
||||||
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
|
0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
|
||||||
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
|
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU,
|
||||||
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
|
0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU,
|
||||||
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
|
0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U,
|
||||||
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
|
0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
|
||||||
|
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U,
|
||||||
|
0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU,
|
||||||
|
0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU,
|
||||||
|
0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
|
||||||
|
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU,
|
||||||
|
0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU,
|
||||||
|
0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U,
|
||||||
|
0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
|
||||||
|
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U,
|
||||||
|
0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U,
|
||||||
|
0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U,
|
||||||
|
0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
|
||||||
|
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U,
|
||||||
|
0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU,
|
||||||
|
0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U,
|
||||||
|
0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
|
||||||
|
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU,
|
||||||
|
0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U,
|
||||||
|
0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU,
|
||||||
|
0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
|
||||||
|
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
|
||||||
};
|
};
|
||||||
static const unsigned int Te3[256] = {
|
static const unsigned int Te3[256] ={
|
||||||
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
|
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU,
|
||||||
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
|
0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U,
|
||||||
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
|
0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU,
|
||||||
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
|
0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
|
||||||
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
|
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU,
|
||||||
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
|
0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U,
|
||||||
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
|
0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U,
|
||||||
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
|
0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
|
||||||
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
|
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU,
|
||||||
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
|
0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU,
|
||||||
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
|
0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U,
|
||||||
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
|
0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
|
||||||
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
|
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U,
|
||||||
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
|
0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U,
|
||||||
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
|
0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU,
|
||||||
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
|
0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
|
||||||
|
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U,
|
||||||
|
0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U,
|
||||||
|
0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU,
|
||||||
|
0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
|
||||||
|
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU,
|
||||||
|
0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U,
|
||||||
|
0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU,
|
||||||
|
0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
|
||||||
|
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U,
|
||||||
|
0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U,
|
||||||
|
0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU,
|
||||||
|
0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
|
||||||
|
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U,
|
||||||
|
0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU,
|
||||||
|
0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U,
|
||||||
|
0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
|
||||||
|
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U,
|
||||||
|
0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU,
|
||||||
|
0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U,
|
||||||
|
0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
|
||||||
|
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int Td0[256] = {
|
static const unsigned int Td0[256] ={
|
||||||
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
|
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU,
|
||||||
0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
|
0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U,
|
||||||
0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
|
0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U,
|
||||||
0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
|
0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
|
||||||
0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
|
0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU,
|
||||||
0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
|
0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U,
|
||||||
0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
|
0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U,
|
||||||
0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
|
0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
|
||||||
0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
|
0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU,
|
||||||
0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
|
0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U,
|
||||||
0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
|
0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U,
|
||||||
0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
|
0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
|
||||||
0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
|
0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU,
|
||||||
0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
|
0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U,
|
||||||
0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
|
0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU,
|
||||||
0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
|
0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
|
||||||
|
0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U,
|
||||||
|
0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU,
|
||||||
|
0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU,
|
||||||
|
0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
|
||||||
|
0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U,
|
||||||
|
0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U,
|
||||||
|
0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U,
|
||||||
|
0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
|
||||||
|
0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU,
|
||||||
|
0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U,
|
||||||
|
0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U,
|
||||||
|
0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
|
||||||
|
0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U,
|
||||||
|
0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU,
|
||||||
|
0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U,
|
||||||
|
0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
|
||||||
|
0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU,
|
||||||
|
0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU,
|
||||||
|
0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U,
|
||||||
|
0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
|
||||||
|
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
|
||||||
};
|
};
|
||||||
static const unsigned int Td1[256] = {
|
static const unsigned int Td1[256] ={
|
||||||
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
|
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U,
|
||||||
0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
|
0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU,
|
||||||
0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
|
0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U,
|
||||||
0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
|
0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
|
||||||
0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
|
0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU,
|
||||||
0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
|
0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U,
|
||||||
0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
|
0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U,
|
||||||
0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
|
0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
|
||||||
0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
|
0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU,
|
||||||
0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
|
0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU,
|
||||||
0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
|
0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU,
|
||||||
0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
|
0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
|
||||||
0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
|
0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U,
|
||||||
0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
|
0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU,
|
||||||
0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
|
0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU,
|
||||||
0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
|
0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
|
||||||
|
0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU,
|
||||||
|
0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U,
|
||||||
|
0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U,
|
||||||
|
0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
|
||||||
|
0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U,
|
||||||
|
0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U,
|
||||||
|
0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU,
|
||||||
|
0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
|
||||||
|
0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U,
|
||||||
|
0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU,
|
||||||
|
0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU,
|
||||||
|
0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
|
||||||
|
0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U,
|
||||||
|
0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U,
|
||||||
|
0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU,
|
||||||
|
0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
|
||||||
|
0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U,
|
||||||
|
0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU,
|
||||||
|
0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U,
|
||||||
|
0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
|
||||||
|
0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
|
||||||
};
|
};
|
||||||
static const unsigned int Td2[256] = {
|
static const unsigned int Td2[256] ={
|
||||||
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
|
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU,
|
||||||
0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
|
0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU,
|
||||||
0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
|
0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU,
|
||||||
0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
|
0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
|
||||||
0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
|
0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U,
|
||||||
0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
|
0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU,
|
||||||
0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
|
0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U,
|
||||||
0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
|
0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
|
||||||
0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
|
0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U,
|
||||||
0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
|
0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U,
|
||||||
0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
|
0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U,
|
||||||
0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
|
0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
|
||||||
0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
|
0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U,
|
||||||
0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
|
0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U,
|
||||||
0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
|
0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU,
|
||||||
0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
|
0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
|
||||||
|
0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U,
|
||||||
|
0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU,
|
||||||
|
0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U,
|
||||||
|
0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
|
||||||
|
0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U,
|
||||||
|
0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U,
|
||||||
|
0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U,
|
||||||
|
0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
|
||||||
|
0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U,
|
||||||
|
0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U,
|
||||||
|
0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U,
|
||||||
|
0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
|
||||||
|
0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U,
|
||||||
|
0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU,
|
||||||
|
0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU,
|
||||||
|
0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
|
||||||
|
0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU,
|
||||||
|
0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU,
|
||||||
|
0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU,
|
||||||
|
0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
|
||||||
|
0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
|
||||||
};
|
};
|
||||||
static const unsigned int Td3[256] = {
|
static const unsigned int Td3[256] ={
|
||||||
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
|
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU,
|
||||||
0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
|
0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U,
|
||||||
0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
|
0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U,
|
||||||
0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
|
0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
|
||||||
0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
|
0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U,
|
||||||
0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
|
0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U,
|
||||||
0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
|
0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U,
|
||||||
0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
|
0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
|
||||||
0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
|
0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U,
|
||||||
0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
|
0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U,
|
||||||
0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
|
0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU,
|
||||||
0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
|
0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
|
||||||
0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
|
0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U,
|
||||||
0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
|
0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU,
|
||||||
0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
|
0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU,
|
||||||
0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
|
0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
|
||||||
|
0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU,
|
||||||
|
0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U,
|
||||||
|
0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U,
|
||||||
|
0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
|
||||||
|
0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU,
|
||||||
|
0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U,
|
||||||
|
0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U,
|
||||||
|
0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
|
||||||
|
0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU,
|
||||||
|
0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U,
|
||||||
|
0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U,
|
||||||
|
0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
|
||||||
|
0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U,
|
||||||
|
0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U,
|
||||||
|
0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU,
|
||||||
|
0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
|
||||||
|
0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U,
|
||||||
|
0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU,
|
||||||
|
0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U,
|
||||||
|
0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
|
||||||
|
0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
|
||||||
};
|
};
|
||||||
static const char Td4[256] = {
|
static const char Td4[256] ={
|
||||||
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
|
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U,
|
||||||
0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
|
0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, 0x34U, 0x8eU,
|
||||||
0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
|
0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U,
|
||||||
0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
|
0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U,
|
||||||
0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
|
0x28U, 0xd9U, 0x24U, 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U,
|
||||||
0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
|
0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U,
|
||||||
0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
|
0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, 0x5eU, 0x15U, 0x46U,
|
||||||
0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
|
0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
|
||||||
|
0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU,
|
||||||
|
0x3fU, 0x0fU, 0x02U, 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U,
|
||||||
|
0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U,
|
||||||
|
0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, 0x37U, 0xe8U,
|
||||||
|
0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, 0x6fU,
|
||||||
|
0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U,
|
||||||
|
0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U,
|
||||||
|
0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
|
||||||
|
0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U,
|
||||||
|
0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, 0xc8U, 0xebU,
|
||||||
|
0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U,
|
||||||
|
0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
|
||||||
};
|
};
|
||||||
static const unsigned int rcon[] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000};
|
static const unsigned int rcon[] ={0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
|
||||||
|
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000};
|
||||||
|
|
||||||
//Expand the cipher key into the encryption key schedule.
|
// Expand the cipher key into the encryption key schedule.
|
||||||
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){
|
||||||
unsigned int * rk = (unsigned int *)key;
|
unsigned int *rk = (unsigned int *)key;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
unsigned int temp;
|
unsigned int temp;
|
||||||
|
|
||||||
|
@ -174,56 +355,60 @@ void AES_set_encrypt_key(const char * userKey, const int bits, char * key) {
|
||||||
rk[1] = Bit::btohl(userKey + 4);
|
rk[1] = Bit::btohl(userKey + 4);
|
||||||
rk[2] = Bit::btohl(userKey + 8);
|
rk[2] = Bit::btohl(userKey + 8);
|
||||||
rk[3] = Bit::btohl(userKey + 12);
|
rk[3] = Bit::btohl(userKey + 12);
|
||||||
if (bits == 128) {
|
if (bits == 128){
|
||||||
while (1) {
|
while (1){
|
||||||
temp = rk[3];
|
temp = rk[3];
|
||||||
rk[4] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
|
rk[4] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
||||||
|
(Te0[(temp)&0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
|
||||||
rk[5] = rk[1] ^ rk[4];
|
rk[5] = rk[1] ^ rk[4];
|
||||||
rk[6] = rk[2] ^ rk[5];
|
rk[6] = rk[2] ^ rk[5];
|
||||||
rk[7] = rk[3] ^ rk[6];
|
rk[7] = rk[3] ^ rk[6];
|
||||||
if (++i == 10) {
|
if (++i == 10){
|
||||||
rk += 8;
|
rk += 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rk += 4;
|
rk += 4;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
rk[4] = (*((uint32_t*)(userKey + 16)));
|
rk[4] = (*((uint32_t *)(userKey + 16)));
|
||||||
rk[5] = (*((uint32_t*)(userKey + 20)));
|
rk[5] = (*((uint32_t *)(userKey + 20)));
|
||||||
if (bits == 192) {
|
if (bits == 192){
|
||||||
while (1) {
|
while (1){
|
||||||
temp = rk[ 5];
|
temp = rk[5];
|
||||||
rk[ 6] = rk[ 0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
|
rk[6] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
||||||
rk[ 7] = rk[ 1] ^ rk[ 6];
|
(Te0[(temp)&0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
|
||||||
rk[ 8] = rk[ 2] ^ rk[ 7];
|
rk[7] = rk[1] ^ rk[6];
|
||||||
rk[ 9] = rk[ 3] ^ rk[ 8];
|
rk[8] = rk[2] ^ rk[7];
|
||||||
if (++i == 8) {
|
rk[9] = rk[3] ^ rk[8];
|
||||||
rk+= 10;
|
if (++i == 8){
|
||||||
|
rk += 10;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rk[10] = rk[ 4] ^ rk[ 9];
|
rk[10] = rk[4] ^ rk[9];
|
||||||
rk[11] = rk[ 5] ^ rk[10];
|
rk[11] = rk[5] ^ rk[10];
|
||||||
rk += 6;
|
rk += 6;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
rk[6] = (*((uint32_t*)(userKey + 24)));
|
rk[6] = (*((uint32_t *)(userKey + 24)));
|
||||||
rk[7] = (*((uint32_t*)(userKey + 28)));
|
rk[7] = (*((uint32_t *)(userKey + 28)));
|
||||||
if (bits == 256) {
|
if (bits == 256){
|
||||||
while (1) {
|
while (1){
|
||||||
temp = rk[ 7];
|
temp = rk[7];
|
||||||
rk[ 8] = rk[ 0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
|
rk[8] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
||||||
rk[ 9] = rk[ 1] ^ rk[ 8];
|
(Te0[(temp)&0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
|
||||||
rk[10] = rk[ 2] ^ rk[ 9];
|
rk[9] = rk[1] ^ rk[8];
|
||||||
rk[11] = rk[ 3] ^ rk[10];
|
rk[10] = rk[2] ^ rk[9];
|
||||||
if (++i == 7) {
|
rk[11] = rk[3] ^ rk[10];
|
||||||
|
if (++i == 7){
|
||||||
rk += 12;
|
rk += 12;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
temp = rk[11];
|
temp = rk[11];
|
||||||
rk[12] = rk[ 4] ^ (Te2[(temp >> 24)] & 0xff000000) ^ (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(temp) & 0xff] & 0x000000ff);
|
rk[12] = rk[4] ^ (Te2[(temp >> 24)] & 0xff000000) ^ (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^
|
||||||
rk[13] = rk[ 5] ^ rk[12];
|
(Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(temp)&0xff] & 0x000000ff);
|
||||||
rk[14] = rk[ 6] ^ rk[13];
|
rk[13] = rk[5] ^ rk[12];
|
||||||
rk[15] = rk[ 7] ^ rk[14];
|
rk[14] = rk[6] ^ rk[13];
|
||||||
|
rk[15] = rk[7] ^ rk[14];
|
||||||
|
|
||||||
rk += 8;
|
rk += 8;
|
||||||
}
|
}
|
||||||
|
@ -232,19 +417,17 @@ void AES_set_encrypt_key(const char * userKey, const int bits, char * key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printInverted(const unsigned int * data, unsigned int len){
|
void printInverted(const unsigned int *data, unsigned int len){
|
||||||
for (int i = 0; i < len; i++){
|
for (int i = 0; i < len; i++){
|
||||||
std::cout << "0x" << std::hex << std::setw(8) << std::setfill('0') << data[i] << ", ";
|
std::cout << "0x" << std::hex << std::setw(8) << std::setfill('0') << data[i] << ", ";
|
||||||
if (i % 4 == 3){
|
if (i % 4 == 3){std::cout << std::endl;}
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand the cipher key into the decryption key schedule.
|
// Expand the cipher key into the decryption key schedule.
|
||||||
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){
|
||||||
unsigned long * rk = (unsigned long *)key;
|
unsigned long *rk = (unsigned long *)key;
|
||||||
int i, j;
|
int i, j;
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
|
@ -252,18 +435,14 @@ void AES_set_decrypt_key(const char * userKey, const int bits, char * key) {
|
||||||
AES_set_encrypt_key(userKey, bits, key);
|
AES_set_encrypt_key(userKey, bits, key);
|
||||||
|
|
||||||
unsigned int rounds = 10;
|
unsigned int rounds = 10;
|
||||||
if (bits > 128) {
|
if (bits > 128){rounds = 12;}
|
||||||
rounds = 12;
|
if (bits > 192){rounds = 14;}
|
||||||
}
|
|
||||||
if (bits > 192) {
|
|
||||||
rounds = 14;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* invert the order of the round keys: */
|
/* invert the order of the round keys: */
|
||||||
for (i = 0, j = 4 * rounds; i < j; i += 4, j -= 4) {
|
for (i = 0, j = 4 * rounds; i < j; i += 4, j -= 4){
|
||||||
temp = rk[i ];
|
temp = rk[i];
|
||||||
rk[i ] = rk[j ];
|
rk[i] = rk[j];
|
||||||
rk[j ] = temp;
|
rk[j] = temp;
|
||||||
temp = rk[i + 1];
|
temp = rk[i + 1];
|
||||||
rk[i + 1] = rk[j + 1];
|
rk[i + 1] = rk[j + 1];
|
||||||
rk[j + 1] = temp;
|
rk[j + 1] = temp;
|
||||||
|
@ -275,33 +454,37 @@ void AES_set_decrypt_key(const char * userKey, const int bits, char * key) {
|
||||||
rk[j + 3] = temp;
|
rk[j + 3] = temp;
|
||||||
}
|
}
|
||||||
/* apply the inverse MixColumn transform to all round keys but the first and the last: */
|
/* apply the inverse MixColumn transform to all round keys but the first and the last: */
|
||||||
for (i = 1; i < rounds; i++) {
|
for (i = 1; i < rounds; i++){
|
||||||
rk += 4;
|
rk += 4;
|
||||||
rk[0] = Td0[Te1[(rk[0] >> 24)] & 0xff] ^ Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[0]) & 0xff] & 0xff];
|
rk[0] = Td0[Te1[(rk[0] >> 24)] & 0xff] ^ Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^
|
||||||
rk[1] = Td0[Te1[(rk[1] >> 24)] & 0xff] ^ Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[1]) & 0xff] & 0xff];
|
Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[0]) & 0xff] & 0xff];
|
||||||
rk[2] = Td0[Te1[(rk[2] >> 24)] & 0xff] ^ Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[2]) & 0xff] & 0xff];
|
rk[1] = Td0[Te1[(rk[1] >> 24)] & 0xff] ^ Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^
|
||||||
rk[3] = Td0[Te1[(rk[3] >> 24)] & 0xff] ^ Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[3]) & 0xff] & 0xff];
|
Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[1]) & 0xff] & 0xff];
|
||||||
|
rk[2] = Td0[Te1[(rk[2] >> 24)] & 0xff] ^ Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^
|
||||||
|
Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[2]) & 0xff] & 0xff];
|
||||||
|
rk[3] = Td0[Te1[(rk[3] >> 24)] & 0xff] ^ Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^
|
||||||
|
Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[3]) & 0xff] & 0xff];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Encrypt a single block in and out can overlap
|
// Encrypt a single block in and out can overlap
|
||||||
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){
|
||||||
const unsigned int * rk = (const unsigned int *)key;
|
const unsigned int *rk = (const unsigned int *)key;
|
||||||
unsigned int s0, s1, s2, s3, t0, t1, t2, t3;
|
unsigned int s0, s1, s2, s3, t0, t1, t2, t3;
|
||||||
|
|
||||||
//map byte array block to cipher state and add initial round key
|
// map byte array block to cipher state and add initial round key
|
||||||
s0 = Bit::btohl(in) ^ rk[0];
|
s0 = Bit::btohl(in) ^ rk[0];
|
||||||
s1 = Bit::btohl(in + 4) ^ rk[1];
|
s1 = Bit::btohl(in + 4) ^ rk[1];
|
||||||
s2 = Bit::btohl(in + 8) ^ rk[2];
|
s2 = Bit::btohl(in + 8) ^ rk[2];
|
||||||
s3 = Bit::btohl(in + 12) ^ rk[3];
|
s3 = Bit::btohl(in + 12) ^ rk[3];
|
||||||
/* round 1:*/
|
/* round 1:*/
|
||||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
|
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[4];
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
|
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[5];
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
|
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[6];
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
|
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[7];
|
||||||
/* round 2:*/
|
/* round 2:*/
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
|
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[8];
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
|
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[9];
|
||||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
|
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
|
||||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
|
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
|
||||||
/* round 3:*/
|
/* round 3:*/
|
||||||
|
@ -339,7 +522,7 @@ void AES_encrypt(const char * in, char * out, const int bits, const char * key)
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
|
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
|
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
|
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
|
||||||
if (bits > 128) {
|
if (bits > 128){
|
||||||
/* round 10:*/
|
/* round 10:*/
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
|
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
|
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
|
||||||
|
@ -350,7 +533,7 @@ void AES_encrypt(const char * in, char * out, const int bits, const char * key)
|
||||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
|
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
|
||||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
|
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
|
||||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
|
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
|
||||||
if (bits > 192) {
|
if (bits > 192){
|
||||||
/* round 12:*/
|
/* round 12:*/
|
||||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
|
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
|
||||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
|
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
|
||||||
|
@ -364,94 +547,94 @@ void AES_encrypt(const char * in, char * out, const int bits, const char * key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rk += 40;
|
rk += 40;
|
||||||
if (bits > 128) {
|
if (bits > 128){rk += 8;}
|
||||||
rk += 8;
|
if (bits > 192){rk += 8;}
|
||||||
}
|
// apply last round and map cipher state to byte array block
|
||||||
if (bits > 192) {
|
s0 = (Te2[(t0 >> 24)] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^
|
||||||
rk += 8;
|
(Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3)&0xff] & 0x000000ff) ^ rk[0];
|
||||||
}
|
|
||||||
//apply last round and map cipher state to byte array block
|
|
||||||
s0 = (Te2[(t0 >> 24)] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3) & 0xff] & 0x000000ff) ^ rk[0];
|
|
||||||
Bit::htobl(out, s0);
|
Bit::htobl(out, s0);
|
||||||
s1 = (Te2[(t1 >> 24)] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0) & 0xff] & 0x000000ff) ^ rk[1];
|
s1 = (Te2[(t1 >> 24)] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^
|
||||||
|
(Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0)&0xff] & 0x000000ff) ^ rk[1];
|
||||||
Bit::htobl(out + 4, s1);
|
Bit::htobl(out + 4, s1);
|
||||||
s2 = (Te2[(t2 >> 24)] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1) & 0xff] & 0x000000ff) ^ rk[2];
|
s2 = (Te2[(t2 >> 24)] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^
|
||||||
|
(Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1)&0xff] & 0x000000ff) ^ rk[2];
|
||||||
Bit::htobl(out + 8, s2);
|
Bit::htobl(out + 8, s2);
|
||||||
s3 = (Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^ rk[3];
|
s3 = (Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^
|
||||||
|
(Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2)&0xff] & 0x000000ff) ^ rk[3];
|
||||||
Bit::htobl(out + 12, s3);
|
Bit::htobl(out + 12, s3);
|
||||||
}
|
}
|
||||||
|
|
||||||
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){
|
||||||
const unsigned long * rk = (const unsigned long *)key;
|
const unsigned long *rk = (const unsigned long *)key;
|
||||||
unsigned long s0, s1, s2, s3, t0, t1, t2, t3;
|
unsigned long s0, s1, s2, s3, t0, t1, t2, t3;
|
||||||
//map byte array block to cipher state and add initial round key:
|
// map byte array block to cipher state and add initial round key:
|
||||||
s0 = htonl(Bit::btohl(in)) ^ rk[0];
|
s0 = htonl(Bit::btohl(in)) ^ rk[0];
|
||||||
s1 = htonl(Bit::btohl(in + 4)) ^ rk[1];
|
s1 = htonl(Bit::btohl(in + 4)) ^ rk[1];
|
||||||
s2 = htonl(Bit::btohl(in + 8)) ^ rk[2];
|
s2 = htonl(Bit::btohl(in + 8)) ^ rk[2];
|
||||||
s3 = htonl(Bit::btohl(in + 12)) ^ rk[3];
|
s3 = htonl(Bit::btohl(in + 12)) ^ rk[3];
|
||||||
//round 1
|
// round 1
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[4];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[5];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[6];
|
||||||
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
|
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[7];
|
||||||
//round 2
|
// round 2
|
||||||
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
|
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[8];
|
||||||
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
|
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[9];
|
||||||
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
|
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
|
||||||
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
|
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
|
||||||
//round 3
|
// round 3
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
|
||||||
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
|
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
|
||||||
//round 4
|
// round 4
|
||||||
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
|
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
|
||||||
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
|
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
|
||||||
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
|
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
|
||||||
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
|
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
|
||||||
//round 5
|
// round 5
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
|
||||||
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
|
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
|
||||||
//round 6
|
// round 6
|
||||||
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
|
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
|
||||||
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
|
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
|
||||||
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
|
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
|
||||||
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
|
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
|
||||||
//round 7
|
// round 7
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
|
||||||
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
|
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
|
||||||
//round 8
|
// round 8
|
||||||
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
|
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
|
||||||
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
|
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
|
||||||
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
|
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
|
||||||
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
|
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
|
||||||
//round 9
|
// round 9
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
|
||||||
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
|
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
|
||||||
if (bits > 128) {
|
if (bits > 128){
|
||||||
//round 10
|
// round 10
|
||||||
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
|
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
|
||||||
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
|
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
|
||||||
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
|
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
|
||||||
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
|
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
|
||||||
//round 11
|
// round 11
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
|
||||||
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
|
t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
|
||||||
if (bits > 192) {
|
if (bits > 192){
|
||||||
//round 12
|
// round 12
|
||||||
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
|
s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
|
||||||
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
|
s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
|
||||||
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
|
s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
|
||||||
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
|
s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
|
||||||
//round 13
|
// round 13
|
||||||
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
|
t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
|
||||||
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
|
t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
|
||||||
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
|
t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
|
||||||
|
@ -459,36 +642,34 @@ void AES_decrypt(const char * in, char * out, const char * key, unsigned int bit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rk += 40;
|
rk += 40;
|
||||||
if (bits > 128) {
|
if (bits > 128){rk += 8;}
|
||||||
rk += 8;
|
if (bits > 192){rk += 8;}
|
||||||
}
|
s0 = ((unsigned long)Td4[(t0 >> 24)] << 24) ^ ((unsigned long)Td4[(t3 >> 16) & 0xff] << 16) ^
|
||||||
if (bits > 192) {
|
((unsigned long)Td4[(t2 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t1)&0xff]) ^ rk[0];
|
||||||
rk += 8;
|
|
||||||
}
|
|
||||||
s0 = ((unsigned long)Td4[(t0 >> 24)] << 24) ^ ((unsigned long)Td4[(t3 >> 16) & 0xff] << 16) ^ ((unsigned long)Td4[(t2 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t1) & 0xff]) ^ rk[0];
|
|
||||||
Bit::htobl(out, s0);
|
Bit::htobl(out, s0);
|
||||||
s1 = ((unsigned long)Td4[(t1 >> 24)] << 24) ^ ((unsigned long)Td4[(t0 >> 16) & 0xff] << 16) ^ ((unsigned long)Td4[(t3 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t2) & 0xff]) ^ rk[1];
|
s1 = ((unsigned long)Td4[(t1 >> 24)] << 24) ^ ((unsigned long)Td4[(t0 >> 16) & 0xff] << 16) ^
|
||||||
|
((unsigned long)Td4[(t3 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t2)&0xff]) ^ rk[1];
|
||||||
Bit::htobl(out + 4, s1);
|
Bit::htobl(out + 4, s1);
|
||||||
s2 = ((unsigned long)Td4[(t2 >> 24)] << 24) ^ ((unsigned long)Td4[(t1 >> 16) & 0xff] << 16) ^ ((unsigned long)Td4[(t0 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t3) & 0xff]) ^ rk[2];
|
s2 = ((unsigned long)Td4[(t2 >> 24)] << 24) ^ ((unsigned long)Td4[(t1 >> 16) & 0xff] << 16) ^
|
||||||
|
((unsigned long)Td4[(t0 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t3)&0xff]) ^ rk[2];
|
||||||
Bit::htobl(out + 8, s2);
|
Bit::htobl(out + 8, s2);
|
||||||
s3 = ((unsigned long)Td4[(t3 >> 24)] << 24) ^ ((unsigned long)Td4[(t2 >> 16) & 0xff] << 16) ^ ((unsigned long)Td4[(t1 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t0) & 0xff]) ^ rk[3];
|
s3 = ((unsigned long)Td4[(t3 >> 24)] << 24) ^ ((unsigned long)Td4[(t2 >> 16) & 0xff] << 16) ^
|
||||||
|
((unsigned long)Td4[(t1 >> 8) & 0xff] << 8) ^ ((unsigned long)Td4[(t0)&0xff]) ^ rk[3];
|
||||||
Bit::htobl(out + 12, s3);
|
Bit::htobl(out + 12, s3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void increaseCounter(char *counter){
|
||||||
static void increaseCounter(char * counter) {
|
for (int i = 15; i >= 0; i--){
|
||||||
for (int i = 15; i >= 0; i--) {
|
if (++counter[i]){return;}
|
||||||
if (++counter[i]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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],
|
||||||
|
char ecount_buf[16], unsigned int &num){
|
||||||
unsigned int l = 0;
|
unsigned int l = 0;
|
||||||
|
|
||||||
while (l < len) {
|
while (l < len){
|
||||||
if ((num % 16) == 0) {
|
if ((num % 16) == 0){
|
||||||
num = 0;
|
num = 0;
|
||||||
AES_encrypt(ivec, ecount_buf, 128, key);
|
AES_encrypt(ivec, ecount_buf, 128, key);
|
||||||
increaseCounter(ivec);
|
increaseCounter(ivec);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,8 +41,7 @@ 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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
86
lib/rtp.cpp
86
lib/rtp.cpp
|
@ -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] |=
|
data[headerSize] |= (isStartOfPartition) ? 0x10 : 0x00; // first chunk is always start of a partition.
|
||||||
(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.
|
||||||
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) /
|
|
||||||
(sTrk.sorter.lostCurrent + sTrk.sorter.packCurrent); // fraction lost since prev RR
|
|
||||||
Bit::htob24(rtcpData + 13, sTrk.sorter.lostTotal); // cumulative packets lost since start
|
Bit::htob24(rtcpData + 13, sTrk.sorter.lostTotal); // cumulative packets lost since start
|
||||||
Bit::htobl(rtcpData + 16, sTrk.sorter.rtpSeq | (sTrk.sorter.packTotal &
|
Bit::htobl(rtcpData + 16, sTrk.sorter.rtpSeq | (sTrk.sorter.packTotal & 0xFFFF0000ul)); // highest sequence received
|
||||||
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
|
||||||
|
|
||||||
|
|
18
lib/rtp.h
18
lib/rtp.h
|
@ -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
|
|
||||||
vp8FrameBuffer; ///< Stores successive VP8 payload data. We always start with the first
|
|
||||||
///< partition; but we might be missing other partitions when they were
|
///< partition; but we might be missing other partitions when they were
|
||||||
///< lost. (a partition is basically what's called a slice in H264).
|
///< lost. (a partition is basically what's called a slice in H264).
|
||||||
bool vp8BufferHasKeyframe;
|
bool vp8BufferHasKeyframe;
|
||||||
};
|
};
|
||||||
}// namespace RTP
|
}// namespace RTP
|
||||||
|
|
||||||
|
|
241
lib/rtp_fec.cpp
241
lib/rtp_fec.cpp
|
@ -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,18 +521,17 @@ 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.");
|
||||||
|
@ -550,12 +543,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, 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) /
|
|
||||||
(sorter.lostCurrent + sorter.packCurrent); // fraction lost since prev RR
|
|
||||||
Bit::htob24(rtcpData + 13, sorter.lostTotal); // cumulative packets lost since start
|
Bit::htob24(rtcpData + 13, sorter.lostTotal); // cumulative packets lost since start
|
||||||
Bit::htobl(rtcpData + 16, sorter.rtpSeq | (sorter.packTotal &
|
Bit::htobl(rtcpData + 16, sorter.rtpSeq | (sorter.packTotal & 0xFFFF0000ul)); // highest sequence received
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,12 @@ 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
|
||||||
|
@ -44,13 +42,11 @@ 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(
|
||||||
|
@ -61,17 +57,14 @@ 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>
|
|
||||||
receivedSeqNums; ///< We keep track of sequence numbers that were received (at some higher
|
|
||||||
///< level). We can only recover 1 media packet and this is used to check
|
///< level). We can only recover 1 media packet and this is used to check
|
||||||
///< if this `PacketFEC` instance is capable of recovering anything.
|
///< if this `PacketFEC` instance is capable of recovering anything.
|
||||||
};
|
};
|
||||||
|
@ -97,4 +90,3 @@ namespace RTP{
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace RTP
|
}// namespace RTP
|
||||||
|
|
||||||
|
|
63
lib/sdp.cpp
63
lib/sdp.cpp
|
@ -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,8 +272,7 @@ 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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 ¶m) const;
|
std::string getParamString(const std::string ¶m) const;
|
||||||
uint64_t getParamInt(const std::string ¶m) const;
|
uint64_t getParamInt(const std::string ¶m) 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
|
||||||
|
|
||||||
|
|
|
@ -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,29 +70,25 @@ 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(
|
static bool sdp_get_name_value_from_varval(const std::string &str, std::string &var,
|
||||||
const std::string &str, std::string &var,
|
|
||||||
std::string &value); // Extracts the `name` and `value` from a string like `<name>=<value>`.
|
std::string &value); // Extracts the `name` and `value` from a string like `<name>=<value>`.
|
||||||
// The `name` will always be converted to lowercase!.
|
// The `name` will always be converted to lowercase!.
|
||||||
static void sdp_get_all_name_values_from_string(
|
static void
|
||||||
const std::string &str, std::map<std::string, std::string>
|
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:
|
||||||
&result); // Extracts all the name/value pairs from a string like:
|
|
||||||
// `<name>=<value>;<name>=<value>`. The `name` part will
|
// `<name>=<value>;<name>=<value>`. The `name` part will
|
||||||
// always be converted to lowercase.
|
// always be converted to lowercase.
|
||||||
static bool
|
static bool sdp_get_attribute_value(const std::string &str,
|
||||||
sdp_get_attribute_value(const std::string &str,
|
|
||||||
std::string &result); // Extract an "attribute" value, which is formatted
|
std::string &result); // Extract an "attribute" value, which is formatted
|
||||||
// like: `a=something:<attribute-value>`
|
// 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);
|
||||||
|
@ -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
|
|
||||||
&& fmtULPFEC)
|
|
||||||
{
|
|
||||||
supportedPayloadTypes.push_back(fmtRED->payloadType);
|
supportedPayloadTypes.push_back(fmtRED->payloadType);
|
||||||
supportedPayloadTypes.push_back(fmtULPFEC->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
|
|
||||||
&& fmtULPFEC)
|
|
||||||
{
|
|
||||||
addLine("a=rtpmap:%u ulpfec/90000", fmtULPFEC->payloadType);
|
addLine("a=rtpmap:%u ulpfec/90000", fmtULPFEC->payloadType);
|
||||||
addLine("a=rtpmap:%u red/90000", fmtRED->payloadType);
|
addLine("a=rtpmap:%u red/90000", fmtRED->payloadType);
|
||||||
}
|
}
|
||||||
if (videoLossPrevention & SDP_LOSS_PREVENTION_NACK) {
|
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
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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,28 +32,23 @@ 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()
|
|
||||||
const; ///< Returns the audio sample rate. When `audioSampleRate` has been set this will be
|
|
||||||
///< returned, otherwise we use the `payloadType` to determine the samplerate or
|
///< returned, otherwise we use the `payloadType` to determine the samplerate or
|
||||||
///< return 0 when we fail to determine to samplerate.
|
///< return 0 when we fail to determine to samplerate.
|
||||||
uint32_t getAudioNumChannels()
|
uint32_t
|
||||||
const; ///< Returns the number of audio channels. When `audioNumChannels` has been set this
|
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
|
///< 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.
|
///< the samplerate or we return 0 when we can't determine the number of channels.
|
||||||
uint32_t getAudioBitSize()
|
uint32_t getAudioBitSize() const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be
|
||||||
const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be
|
|
||||||
///< returned, othwerise we use the `encodingName` to determine the right
|
///< returned, othwerise we use the `encodingName` to determine the right
|
||||||
///< `audioBitSize` or 0 when we can't determine the `audioBitSize`
|
///< `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
|
||||||
getVideoRate() const; ///< Returns the video time base. When `videoRate` has been set this will
|
|
||||||
///< be returned, otherwise we use the `encodingName` to determine the
|
///< be returned, otherwise we use the `encodingName` to determine the
|
||||||
///< right value or 0 when we can't determine the video rate.
|
///< 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.
|
||||||
|
|
||||||
|
@ -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>
|
std::set<std::string> rtcpFormats; ///< Stores the `fb-val` from the line with `a=rtcp-fb:<fmt> <fb-val>`.
|
||||||
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(
|
|
||||||
const std::string
|
|
||||||
&sdpLine); ///< Parses `a=fingerprint:<hash-func> <value>`. See
|
|
||||||
///< https://tools.ietf.org/html/rfc8122#section-5, used with WebRTC
|
///< 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
|
|
||||||
&sdpLine); ///< Returns the track to which this SDP line applies. This means that the
|
|
||||||
///< SDP line should be formatteed like: `a=something:[payloadtype]`.
|
///< SDP line should be formatteed like: `a=something:[payloadtype]`.
|
||||||
MediaFormat *getFormatForPayloadType(
|
MediaFormat *
|
||||||
uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no
|
getFormatForPayloadType(uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no
|
||||||
///< format was found for the given payload type. .
|
///< format was found for the given payload type. .
|
||||||
MediaFormat *getFormatForEncodingName(
|
MediaFormat *getFormatForEncodingName(const std::string &encName); ///< Finds the `MediaFormats in `formats`. Returns NULL when no format was
|
||||||
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`
|
///< 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
|
|
||||||
&fmt); ///< The `a=ice-pwd` can be session global or media specific. This function will
|
|
||||||
///< check if the `SDP::MediaFormat` has a ice-pwd that we should use.
|
///< check if the `SDP::MediaFormat` has a ice-pwd that we should use.
|
||||||
uint32_t
|
uint32_t getSSRC() const; ///< Returns the first SSRC `a=ssrc:<value>` value found for the media.
|
||||||
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,8 +119,7 @@ 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.
|
||||||
|
@ -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>
|
|
||||||
formats; ///< Formats indexed by payload type. Payload type is the number in the <fmt>
|
|
||||||
///< field(s) from the `m=` line.
|
///< 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,
|
MediaFormat *getMediaFormatByEncodingName(const std::string &mediaType, const std::string &encodingName);
|
||||||
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,8 +150,7 @@ 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.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
@ -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,18 +12,18 @@
|
||||||
#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);
|
||||||
|
@ -46,6 +46,7 @@ namespace IPC {
|
||||||
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)
|
||||||
|
@ -59,17 +60,17 @@ namespace IPC {
|
||||||
/// - 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();
|
||||||
|
@ -78,13 +79,14 @@ namespace IPC {
|
||||||
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;
|
||||||
|
@ -92,27 +94,26 @@ namespace IPC {
|
||||||
};
|
};
|
||||||
|
|
||||||
///\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:
|
private:
|
||||||
///\brief The semaphore to guard.
|
///\brief The semaphore to guard.
|
||||||
semaphore * mySemaphore;
|
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 close();
|
||||||
void unmap();
|
void unmap();
|
||||||
bool exists();
|
bool exists();
|
||||||
|
@ -125,7 +126,7 @@ namespace IPC {
|
||||||
///\brief Whether this class should unlink the shared file upon deletion or not
|
///\brief Whether this class should unlink the shared file upon deletion or not
|
||||||
bool master;
|
bool master;
|
||||||
///\brief A pointer to the payload of the file file
|
///\brief A pointer to the payload of the file file
|
||||||
char * mapped;
|
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,42 +162,44 @@ 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);
|
||||||
|
char *getIndex(unsigned int id);
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
///\brief The amount of connected clients
|
///\brief The amount of connected clients
|
||||||
unsigned int amount;
|
unsigned int amount;
|
||||||
unsigned int connectedUsers;
|
unsigned int connectedUsers;
|
||||||
void finishEach();
|
void finishEach();
|
||||||
void abandon();
|
void abandon();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isInUse(unsigned int id);
|
bool isInUse(unsigned int id);
|
||||||
void newPage();
|
void newPage();
|
||||||
|
@ -217,27 +218,28 @@ namespace IPC {
|
||||||
|
|
||||||
///\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:
|
private:
|
||||||
///\brief The basename of the shared pages.
|
///\brief The basename of the shared pages.
|
||||||
std::string baseName;
|
std::string baseName;
|
||||||
|
@ -253,14 +255,15 @@ namespace IPC {
|
||||||
bool hasCounter;
|
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:
|
private:
|
||||||
char * data;
|
char *data;
|
||||||
};
|
};
|
||||||
}
|
}// namespace IPC
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
281
lib/srtp.cpp
281
lib/srtp.cpp
|
@ -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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
lib/srtp.h
18
lib/srtp.h
|
@ -1,8 +1,8 @@
|
||||||
#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
|
||||||
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
/* --------------------------------------- */
|
/* --------------------------------------- */
|
||||||
|
|
||||||
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;
|
||||||
|
|
240
lib/stream.cpp
240
lib/stream.cpp
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -235,14 +240,14 @@ JSON::Value Util::getGlobalConfig(const std::string &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,10 +1113,9 @@ 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);
|
||||||
|
@ -1080,7 +1123,7 @@ 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){continue;}
|
if (problems){continue;}
|
||||||
if (noSelAudio && Trk.type == "audio"){continue;}
|
if (noSelAudio && Trk.type == "audio"){continue;}
|
||||||
if (noSelVideo && Trk.type == "video"){continue;}
|
if (noSelVideo && Trk.type == "video"){continue;}
|
||||||
|
@ -1091,7 +1134,6 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
|
||||||
}
|
}
|
||||||
/*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;
|
||||||
|
|
52
lib/stream.h
52
lib/stream.h
|
@ -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:
|
private:
|
||||||
IPC::sharedPage rPage;
|
IPC::sharedPage rPage;
|
||||||
Util::RelAccX rAcc;
|
Util::RelAccX rAcc;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}// namespace Util
|
||||||
|
|
||||||
|
|
636
lib/stun.cpp
636
lib/stun.cpp
File diff suppressed because it is too large
Load diff
89
lib/stun.h
89
lib/stun.h
|
@ -1,8 +1,8 @@
|
||||||
#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>
|
||||||
|
|
||||||
/* --------------------------------------- */
|
/* --------------------------------------- */
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
163
lib/theora.cpp
163
lib/theora.cpp
|
@ -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();
|
||||||
|
@ -282,8 +221,7 @@ namespace theora {
|
||||||
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,7 +280,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
@ -350,16 +288,11 @@ namespace theora {
|
||||||
long long unsigned int header::parseGranuleLower(long long unsigned int granPos){
|
long long unsigned int header::parseGranuleLower(long long unsigned int granPos){
|
||||||
return (granPos & ((1 << getKFGShift()) - 1));
|
return (granPos & ((1 << getKFGShift()) - 1));
|
||||||
}*/
|
}*/
|
||||||
/*
|
/*
|
||||||
std::string frame::toPrettyString(size_t indent){
|
std::string frame::toPrettyString(size_t indent){
|
||||||
std::stringstream result;
|
std::stringstream result;
|
||||||
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();
|
||||||
}*/
|
}*/
|
||||||
}
|
}// namespace theora
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
38
lib/theora.h
38
lib/theora.h
|
@ -1,27 +1,27 @@
|
||||||
#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();
|
||||||
|
@ -33,24 +33,25 @@ namespace theora {
|
||||||
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:
|
private:
|
||||||
char * data;
|
char *data;
|
||||||
bool checkDataSize(unsigned int size);
|
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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,8 @@
|
||||||
#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.
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
290
lib/tinythread.h
290
lib/tinythread.h
|
@ -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
|
||||||
|
|
||||||
|
@ -106,12 +106,12 @@ 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,20 +143,19 @@ 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()
|
||||||
|
@ -172,7 +171,7 @@ namespace tthread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
~mutex() {
|
~mutex(){
|
||||||
#if defined(_TTHREAD_WIN32_)
|
#if defined(_TTHREAD_WIN32_)
|
||||||
DeleteCriticalSection(&mHandle);
|
DeleteCriticalSection(&mHandle);
|
||||||
#else
|
#else
|
||||||
|
@ -184,7 +183,7 @@ namespace tthread {
|
||||||
/// 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...
|
||||||
|
@ -199,10 +198,10 @@ namespace tthread {
|
||||||
/// 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);
|
LeaveCriticalSection(&mHandle);
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +214,7 @@ namespace tthread {
|
||||||
/// 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_)
|
||||||
mAlreadyLocked = false;
|
mAlreadyLocked = false;
|
||||||
LeaveCriticalSection(&mHandle);
|
LeaveCriticalSection(&mHandle);
|
||||||
|
@ -237,16 +236,16 @@ namespace tthread {
|
||||||
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
|
||||||
|
@ -258,7 +257,7 @@ namespace tthread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
~recursive_mutex() {
|
~recursive_mutex(){
|
||||||
#if defined(_TTHREAD_WIN32_)
|
#if defined(_TTHREAD_WIN32_)
|
||||||
DeleteCriticalSection(&mHandle);
|
DeleteCriticalSection(&mHandle);
|
||||||
#else
|
#else
|
||||||
|
@ -270,7 +269,7 @@ namespace tthread {
|
||||||
/// 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
|
||||||
|
@ -283,7 +282,7 @@ namespace tthread {
|
||||||
/// 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
|
||||||
|
@ -294,7 +293,7 @@ namespace tthread {
|
||||||
/// 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
|
||||||
|
@ -314,87 +313,81 @@ namespace tthread {
|
||||||
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.
|
||||||
|
@ -402,12 +395,11 @@ namespace tthread {
|
||||||
/// 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
|
||||||
|
@ -428,9 +420,7 @@ namespace tthread {
|
||||||
#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.
|
||||||
|
@ -441,9 +431,7 @@ namespace tthread {
|
||||||
#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)
|
||||||
|
@ -459,9 +447,8 @@ namespace tthread {
|
||||||
#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;
|
||||||
|
@ -474,11 +461,14 @@ namespace tthread {
|
||||||
/// 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.
|
||||||
|
@ -488,7 +478,7 @@ namespace tthread {
|
||||||
/// @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()
|
||||||
|
@ -519,9 +509,7 @@ namespace tthread {
|
||||||
/// 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
|
||||||
|
@ -536,63 +524,51 @@ namespace tthread {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -601,39 +577,34 @@ namespace tthread {
|
||||||
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:
|
public:
|
||||||
typedef _Rep rep;
|
typedef _Rep rep;
|
||||||
typedef _Period period;
|
typedef _Period period;
|
||||||
|
|
||||||
/// Construct a duration object with the given duration.
|
/// Construct a duration object with the given duration.
|
||||||
template <class _Rep2>
|
template <class _Rep2> explicit duration(const _Rep2 &r) : rep_(r){};
|
||||||
explicit duration(const _Rep2 & r) : rep_(r) {};
|
|
||||||
|
|
||||||
/// Return the value of the duration object.
|
/// Return the value of the duration object.
|
||||||
rep count() const {
|
rep count() const{return rep_;}
|
||||||
return rep_;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Standard duration types.
|
// Standard duration types.
|
||||||
|
@ -643,18 +614,18 @@ namespace tthread {
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
1108
lib/ts_packet.cpp
1108
lib/ts_packet.cpp
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
Loading…
Add table
Reference in a new issue