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

View file

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

View file

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

View file

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

View file

@ -130,8 +130,6 @@ namespace AMF{
/// Parses a std::string to a valid AMF::Object3.
Object3 parse3(std::string data);
/// Parses a single AMF3 type - used recursively by the AMF::parse3() functions.
Object3 parseOne3(const unsigned char *&data, unsigned int &len, unsigned int &i,
std::string name);
Object3 parseOne3(const unsigned char *&data, unsigned int &len, unsigned int &i, std::string name);
}// namespace AMF

View file

@ -1,19 +1,17 @@
#include "auth.h"
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#include <sstream>
#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.
std::string md5(std::string input) {
return md5(input.data(), input.size());
}
std::string md5(std::string input){return md5(input.data(), input.size());}
/// 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];
md5bin(input, in_len, output);
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.
std::string sha256(std::string input) {
return sha256(input.data(), input.size());
}
std::string sha256(std::string input){return sha256(input.data(), input.size());}
/// 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];
sha256bin(input, in_len, output);
std::stringstream outStr;
@ -42,14 +38,28 @@ namespace Secure {
/// Adds 64 bytes of data to the current MD5 hash.
/// hash is the current hash, represented by 4 unsigned longs.
/// data is the 64 bytes of data that need to be added.
static inline void md5_add64(uint32_t * hash, const char * data){
//Inspired by the pseudocode as available on Wikipedia on March 2nd, 2015.
static inline void md5_add64(uint32_t *hash, const char *data){
// Inspired by the pseudocode as available on Wikipedia on March 2nd, 2015.
uint32_t M[16];
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 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};
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 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 B = hash[1];
uint32_t C = hash[2];
@ -61,19 +71,19 @@ namespace Secure {
g = i;
}else if (i < 32){
F = (D & B) | ((~D) & C);
g = (5*i + 1) % 16;
g = (5 * i + 1) % 16;
}else if (i < 48){
F = B ^ C ^ D;
g = (3*i + 5) % 16;
g = (3 * i + 5) % 16;
}else{
F = C ^ (B | (~D));
g = (7*i) % 16;
g = (7 * i) % 16;
}
uint32_t dTemp = D;
D = C;
C = B;
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;
}
hash[0] += A;
@ -84,31 +94,31 @@ namespace Secure {
/// Calculates a MD5 digest as per rfc1321, returning it as binary.
/// Assumes output is big enough to contain 16 bytes of data.
void md5bin(const char * input, const unsigned int in_len, char * output){
//Initialize the hash, according to MD5 spec.
uint32_t hash[] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
//Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left.
void md5bin(const char *input, const unsigned int in_len, char *output){
// Initialize the hash, according to MD5 spec.
uint32_t hash[] ={0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
// Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left.
unsigned int offset = 0;
while (offset+64 <= in_len){
md5_add64(hash, input+offset);
while (offset + 64 <= in_len){
md5_add64(hash, input + offset);
offset += 64;
}
//now, copy the remainder to a 64 byte buffer.
// now, copy the remainder to a 64 byte buffer.
char buffer[64];
memcpy(buffer, input+offset, in_len-offset);
//Calculate how much we've filled in that buffer
memcpy(buffer, input + offset, in_len - offset);
// Calculate how much we've filled in that buffer
offset = in_len - offset;
//We know at least 1 byte must be empty, so we can safely do this
buffer[offset] = 0x80;//append 0x80
//fill to the end of the buffer with zeroes
memset(buffer+offset+1, 0, 64-offset-1);
// We know at least 1 byte must be empty, so we can safely do this
buffer[offset] = 0x80; // append 0x80
// fill to the end of the buffer with zeroes
memset(buffer + offset + 1, 0, 64 - offset - 1);
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);
memset(buffer, 0, 64);
}
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[57] = (bit_len >> 8) & 0xff;
buffer[58] = (bit_len >> 16) & 0xff;
@ -117,24 +127,24 @@ namespace Secure {
buffer[61] = (bit_len >> 40) & 0xff;
buffer[62] = (bit_len >> 48) & 0xff;
buffer[63] = (bit_len >> 54) & 0xff;
//Add the last bit of buffer
// Add the last bit of buffer
md5_add64(hash, buffer);
//Write to output
//convert hash to hexadecimal string
output[0 ] = (hash[0] >> 0 ) & 0xff;
output[1 ] = (hash[0] >> 8 ) & 0xff;
output[2 ] = (hash[0] >> 16) & 0xff;
output[3 ] = (hash[0] >> 24) & 0xff;
output[4 ] = (hash[1] >> 0 ) & 0xff;
output[5 ] = (hash[1] >> 8 ) & 0xff;
output[6 ] = (hash[1] >> 16) & 0xff;
output[7 ] = (hash[1] >> 24) & 0xff;
output[8 ] = (hash[2] >> 0 ) & 0xff;
output[9 ] = (hash[2] >> 8 ) & 0xff;
// Write to output
// convert hash to hexadecimal string
output[0] = (hash[0] >> 0) & 0xff;
output[1] = (hash[0] >> 8) & 0xff;
output[2] = (hash[0] >> 16) & 0xff;
output[3] = (hash[0] >> 24) & 0xff;
output[4] = (hash[1] >> 0) & 0xff;
output[5] = (hash[1] >> 8) & 0xff;
output[6] = (hash[1] >> 16) & 0xff;
output[7] = (hash[1] >> 24) & 0xff;
output[8] = (hash[2] >> 0) & 0xff;
output[9] = (hash[2] >> 8) & 0xff;
output[10] = (hash[2] >> 16) & 0xff;
output[11] = (hash[2] >> 24) & 0xff;
output[12] = (hash[3] >> 0 ) & 0xff;
output[13] = (hash[3] >> 8 ) & 0xff;
output[12] = (hash[3] >> 0) & 0xff;
output[13] = (hash[3] >> 8) & 0xff;
output[14] = (hash[3] >> 16) & 0xff;
output[15] = (hash[3] >> 24) & 0xff;
}
@ -147,20 +157,31 @@ namespace Secure {
/// Adds 64 bytes of data to the current SHA256 hash.
/// hash is the current hash, represented by 8 unsigned longs.
/// data is the 64 bytes of data that need to be added.
static inline void sha256_add64(uint32_t * hash, const char * data){
//Inspired by the pseudocode as available on Wikipedia on March 3rd, 2015.
static inline void sha256_add64(uint32_t *hash, const char *data){
// Inspired by the pseudocode as available on Wikipedia on March 3rd, 2015.
uint32_t w[64];
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){
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);
w[i] = w[i-16] + s0 + w[i-7] + s1;
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);
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 b = hash[1];
uint32_t c = hash[2];
@ -170,8 +191,8 @@ namespace Secure {
uint32_t g = hash[6];
uint32_t h = hash[7];
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 temp2 = (rr(a, 2) ^ rr(a, 13) ^ rr(a, 22)) + ((a&b)|(c&(a|b)));
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)));
h = g;
g = f;
f = e;
@ -193,31 +214,32 @@ namespace Secure {
/// Calculates a SHA256 digest as per NSAs SHA-2, returning it as binary.
/// Assumes output is big enough to contain 16 bytes of data.
void sha256bin(const char * input, const unsigned int in_len, char * output){
//Initialize the hash, according to MD5 spec.
uint32_t hash[] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
//Add as many whole blocks of 64 bytes as possible from the input, until < 64 are left.
void sha256bin(const char *input, const unsigned int in_len, char *output){
// Initialize the hash, according to MD5 spec.
uint32_t hash[] ={0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
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;
while (offset+64 <= in_len){
sha256_add64(hash, input+offset);
while (offset + 64 <= in_len){
sha256_add64(hash, input + offset);
offset += 64;
}
//now, copy the remainder to a 64 byte buffer.
// now, copy the remainder to a 64 byte buffer.
char buffer[64];
memcpy(buffer, input+offset, in_len-offset);
//Calculate how much we've filled in that buffer
memcpy(buffer, input + offset, in_len - offset);
// Calculate how much we've filled in that buffer
offset = in_len - offset;
//We know at least 1 byte must be empty, so we can safely do this
buffer[offset] = 0x80;//append 0x80
//fill to the end of the buffer with zeroes
memset(buffer+offset+1, 0, 64-offset-1);
// We know at least 1 byte must be empty, so we can safely do this
buffer[offset] = 0x80; // append 0x80
// fill to the end of the buffer with zeroes
memset(buffer + offset + 1, 0, 64 - offset - 1);
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);
memset(buffer, 0, 64);
}
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[57] = (bit_len >> 48) & 0xff;
buffer[58] = (bit_len >> 40) & 0xff;
@ -226,9 +248,9 @@ namespace Secure {
buffer[61] = (bit_len >> 16) & 0xff;
buffer[62] = (bit_len >> 8) & 0xff;
buffer[63] = (bit_len >> 0) & 0xff;
//Add the last bit of buffer
// Add the last bit of buffer
sha256_add64(hash, buffer);
//Write result to output
// Write result to output
output[3] = hash[0] & 0xff;
output[2] = (hash[0] >> 8) & 0xff;
output[1] = (hash[0] >> 16) & 0xff;
@ -263,13 +285,12 @@ namespace Secure {
output[28] = (hash[7] >> 24) & 0xff;
}
/// Performs HMAC on msg with given key.
/// Uses given hasher function, requires hashSize to be set accordingly.
/// Output is returned as hexadecimal alphanumeric string.
/// 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);
}
@ -277,7 +298,9 @@ namespace Secure {
/// Uses given hasher function, requires hashSize to be set accordingly.
/// Output is returned as hexadecimal alphanumeric string.
/// 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];
hmacbin(msg, msg_len, key, key_len, hashSize, hasher, blockSize, output);
std::stringstream outStr;
@ -291,30 +314,32 @@ namespace Secure {
/// 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.
/// 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){
char key_data[blockSize];//holds key as used in HMAC algorithm
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){
char key_data[blockSize]; // holds key as used in HMAC algorithm
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);
memset(key_data+hashSize, 0, blockSize-hashSize);
memset(key_data + hashSize, 0, blockSize - hashSize);
}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);
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.
char inner[blockSize+msg_len];//holds data for inner hash
char outer[blockSize+hashSize];//holds data for outer hash
// key_data now contains hashSize bytes of key data, treated as per spec.
char inner[blockSize + msg_len]; // holds data for inner hash
char outer[blockSize + hashSize]; // holds data for outer hash
for (unsigned int i = 0; i < blockSize; ++i){
inner[i] = key_data[i] ^ 0x36;
outer[i] = key_data[i] ^ 0x5c;
}
//Copy the message to the inner hash data buffer
memcpy(inner+blockSize, msg, msg_len);
//Calculate the inner hash
hasher(inner, blockSize+msg_len, outer+blockSize);
//Calculate the outer hash
hasher(outer, blockSize+hashSize, output);
// Copy the message to the inner hash data buffer
memcpy(inner + blockSize, msg, msg_len);
// Calculate the inner hash
hasher(inner, blockSize + msg_len, outer + blockSize);
// Calculate the outer hash
hasher(outer, blockSize + hashSize, output);
}
/// 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
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);
}
/// 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.
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);
}
}
}// namespace Secure

View file

@ -1,25 +1,30 @@
#pragma once
#include <string>
namespace Secure {
//MD5 hashing functions
namespace Secure{
// MD5 hashing functions
std::string md5(std::string input);
std::string md5(const char * input, const unsigned int in_len);
void md5bin(const char * input, const unsigned int in_len, char * output);
std::string md5(const char *input, const unsigned int in_len);
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(const char * input, const unsigned int in_len);
void sha256bin(const char * input, const unsigned int in_len, char * output);
std::string sha256(const char *input, const unsigned int in_len);
void sha256bin(const char *input, const unsigned int in_len, char *output);
//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(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 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
// 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(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 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(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);
}
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);
}// namespace Secure

View file

@ -35,8 +35,7 @@ unsigned long long Bit::getMSB(char *pointer, unsigned int offsetBits, unsigned
/// This function assumes Most Significant Bits first.
/// WARNING: UNFINISHED. DO NOT USE.
/// \todo Finish writing this - untested atm.
void Bit::setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits,
unsigned long long value){
void Bit::setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits, unsigned long long value){
// Set the pointer to the last byte we need to be setting
pointer += (offsetBits + dataBits) >> 3;
// 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 ||
strncmp(tmp.c_str(), "true", 4) == 0 || strncmp(tmp.c_str(), "cont", 4) == 0);
}

View file

@ -11,8 +11,7 @@ namespace Bit{
unsigned long long getMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits);
unsigned long long getByName(char *pointer);
// bitfield setters
void setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits,
unsigned long long value);
void setMSB(char *pointer, unsigned int offsetBits, unsigned int dataBits, unsigned long long value);
void setByName(char *pointer);
// 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.
inline unsigned long btohl_le(const char *p){
return ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) |
p[0];
return ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
}
/// Stores a long value of val in little endian to the pointer p.
@ -171,8 +169,7 @@ namespace Bit{
inline unsigned long long btohll_le(const char *p){
return ((unsigned long long)p[7] << 56) | ((unsigned long long)p[6] << 48) |
((unsigned long long)p[5] << 40) | ((unsigned long long)p[4] << 32) |
((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) |
p[0];
((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
}
/// Stores a long value of val in little endian to the pointer p.
@ -188,4 +185,3 @@ namespace Bit{
}
}// namespace Bit

View file

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

View file

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

View file

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

View file

@ -10,25 +10,25 @@
*/
#include <string>
#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_csr.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/md.h>
#include <mbedtls/error.h>
#include <mbedtls/sha256.h>
#include <string>
class Certificate {
class Certificate{
public:
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();
std::string getFingerprintSha256();
public:
mbedtls_x509_crt cert;
mbedtls_pk_context key; /* key context, stores private and public key. */
mbedtls_rsa_context* rsa_ctx; /* rsa context, stored in key_ctx */
mbedtls_pk_context key; /* key context, stores private and public key. */
mbedtls_rsa_context *rsa_ctx; /* rsa context, stored in key_ctx */
};

View file

@ -1,75 +1,48 @@
#include <stddef.h>
namespace checksum {
inline unsigned int crc32c(unsigned int crc, const char * data, size_t len) {
static const unsigned int table[256] = {
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U,
0x130476DCU, 0x17C56B6BU, 0x1A864DB2U, 0x1E475005U,
0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U,
0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU,
0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U,
0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U,
0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU,
0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U,
0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U,
0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U,
0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU,
0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U,
0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U,
0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU,
0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU,
0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U,
0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U,
0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU,
0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U,
0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U, 0x53DC6066U,
0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU,
0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU,
0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U,
0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U,
0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU,
0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U,
0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U,
0xD5B88683U, 0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU,
0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U,
0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU,
0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U,
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,
namespace checksum{
inline unsigned int crc32c(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] ={
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x130476DCU, 0x17C56B6BU, 0x1A864DB2U,
0x1E475005U, 0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, 0x350C9B64U, 0x31CD86D3U,
0x3C8EA00AU, 0x384FBDBDU, 0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, 0x5F15ADACU,
0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU,
0x95609039U, 0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xBE2B5B58U, 0xBAEA46EFU,
0xB7A96036U, 0xB3687D81U, 0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0xD4326D90U,
0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, 0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU,
0xEC7DD02DU, 0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0x278206ABU, 0x23431B1CU,
0x2E003DC5U, 0x2AC12072U, 0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0x018AEB13U,
0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, 0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U,
0x53DC6066U, 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, 0xACA5C697U, 0xA864DB20U,
0xA527FDF9U, 0xA1E6E04EU, 0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0x8AAD2B2FU,
0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, 0xF3B06B3BU, 0xF771768CU, 0xFA325055U,
0xFEF34DE2U, 0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0xD5B88683U, 0xD1799B34U,
0xDC3ABDEDU, 0xD8FBA05AU, 0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, 0x7A089632U,
0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 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,
};
while (len > 0) {
while (len > 0){
crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
data++;
len--;
@ -77,75 +50,47 @@ namespace checksum {
return crc;
}
inline unsigned int crc32LE(unsigned int crc, const char * data, size_t len) {
static const unsigned int table[256] = {
0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU,
0x076dc419U, 0x706af48fU, 0xe963a535U, 0x9e6495a3U,
0x0edb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d988U,
0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 0x90bf1d91U,
0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U,
0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU,
0x14015c4fU, 0x63066cd9U, 0xfa0f3d63U, 0x8d080df5U,
0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 0xa2677172U,
0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U,
0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U,
0x26d930acU, 0x51de003aU, 0xc8d75180U, 0xbfd06116U,
0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 0xb8bda50fU,
0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU,
0x76dc4190U, 0x01db7106U, 0x98d220bcU, 0xefd5102aU,
0x71b18589U, 0x06b6b51fU, 0x9fbfe4a5U, 0xe8b8d433U,
0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 0xe10e9818U,
0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU,
0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U,
0x65b0d9c6U, 0x12b7e950U, 0x8bbeb8eaU, 0xfcb9887cU,
0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd44c65U,
0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU,
0x4369e96aU, 0x346ed9fcU, 0xad678846U, 0xda60b8d0U,
0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U,
0x5005713cU, 0x270241aaU, 0xbe0b1010U, 0xc90c2086U,
0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U,
0x59b33d17U, 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU,
0xedb88320U, 0x9abfb3b6U, 0x03b6e20cU, 0x74b1d29aU,
0xead54739U, 0x9dd277afU, 0x04db2615U, 0x73dc1683U,
0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U,
0xf00f9344U, 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU,
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
};
inline unsigned int crc32LE(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] ={
0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, 0x706af48fU, 0xe963a535U,
0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU,
0xe7b82d07U, 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 0x1adad47dU,
0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU,
0x14015c4fU, 0x63066cd9U, 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 0x35b5a8faU, 0x42b2986cU,
0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU,
0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 0xb8bda50fU,
0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU,
0xb6662d3dU, 0x76dc4190U, 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 0xe10e9818U, 0x7f6a0dbbU,
0x086d3d2dU, 0x91646c97U, 0xe6635c01U, 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU,
0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, 0x8bbeb8eaU,
0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU,
0xa3bc0074U, 0xd4bb30e2U, 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U,
0x5005713cU, 0x270241aaU, 0xbe0b1010U, 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U,
0xce61e49fU, 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 0x2eb40d81U,
0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 0x03b6e20cU, 0x74b1d29aU, 0xead54739U,
0x9dd277afU, 0x04db2615U, 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, 0x8708a3d2U, 0x1e01f268U,
0x6906c2feU, 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);
data++;
len--;
@ -153,79 +98,49 @@ namespace checksum {
return crc;
}
inline unsigned int crc32(unsigned int crc, const char * data, size_t len) {
static const unsigned int table[256] = {
0x00000000U, 0xB71DC104U, 0x6E3B8209U, 0xD926430DU,
0xDC760413U, 0x6B6BC517U, 0xB24D861AU, 0x0550471EU,
0xB8ED0826U, 0x0FF0C922U, 0xD6D68A2FU, 0x61CB4B2BU,
0x649B0C35U, 0xD386CD31U, 0x0AA08E3CU, 0xBDBD4F38U,
0x70DB114CU, 0xC7C6D048U, 0x1EE09345U, 0xA9FD5241U,
0xACAD155FU, 0x1BB0D45BU, 0xC2969756U, 0x758B5652U,
0xC836196AU, 0x7F2BD86EU, 0xA60D9B63U, 0x11105A67U,
0x14401D79U, 0xA35DDC7DU, 0x7A7B9F70U, 0xCD665E74U,
0xE0B62398U, 0x57ABE29CU, 0x8E8DA191U, 0x39906095U,
0x3CC0278BU, 0x8BDDE68FU, 0x52FBA582U, 0xE5E66486U,
0x585B2BBEU, 0xEF46EABAU, 0x3660A9B7U, 0x817D68B3U,
0x842D2FADU, 0x3330EEA9U, 0xEA16ADA4U, 0x5D0B6CA0U,
0x906D32D4U, 0x2770F3D0U, 0xFE56B0DDU, 0x494B71D9U,
0x4C1B36C7U, 0xFB06F7C3U, 0x2220B4CEU, 0x953D75CAU,
0x28803AF2U, 0x9F9DFBF6U, 0x46BBB8FBU, 0xF1A679FFU,
0xF4F63EE1U, 0x43EBFFE5U, 0x9ACDBCE8U, 0x2DD07DECU,
0x77708634U, 0xC06D4730U, 0x194B043DU, 0xAE56C539U,
0xAB068227U, 0x1C1B4323U, 0xC53D002EU, 0x7220C12AU,
0xCF9D8E12U, 0x78804F16U, 0xA1A60C1BU, 0x16BBCD1FU,
0x13EB8A01U, 0xA4F64B05U, 0x7DD00808U, 0xCACDC90CU,
0x07AB9778U, 0xB0B6567CU, 0x69901571U, 0xDE8DD475U,
0xDBDD936BU, 0x6CC0526FU, 0xB5E61162U, 0x02FBD066U,
0xBF469F5EU, 0x085B5E5AU, 0xD17D1D57U, 0x6660DC53U,
0x63309B4DU, 0xD42D5A49U, 0x0D0B1944U, 0xBA16D840U,
0x97C6A5ACU, 0x20DB64A8U, 0xF9FD27A5U, 0x4EE0E6A1U,
0x4BB0A1BFU, 0xFCAD60BBU, 0x258B23B6U, 0x9296E2B2U,
0x2F2BAD8AU, 0x98366C8EU, 0x41102F83U, 0xF60DEE87U,
0xF35DA999U, 0x4440689DU, 0x9D662B90U, 0x2A7BEA94U,
0xE71DB4E0U, 0x500075E4U, 0x892636E9U, 0x3E3BF7EDU,
0x3B6BB0F3U, 0x8C7671F7U, 0x555032FAU, 0xE24DF3FEU,
0x5FF0BCC6U, 0xE8ED7DC2U, 0x31CB3ECFU, 0x86D6FFCBU,
0x8386B8D5U, 0x349B79D1U, 0xEDBD3ADCU, 0x5AA0FBD8U,
0xEEE00C69U, 0x59FDCD6DU, 0x80DB8E60U, 0x37C64F64U,
0x3296087AU, 0x858BC97EU, 0x5CAD8A73U, 0xEBB04B77U,
0x560D044FU, 0xE110C54BU, 0x38368646U, 0x8F2B4742U,
0x8A7B005CU, 0x3D66C158U, 0xE4408255U, 0x535D4351U,
0x9E3B1D25U, 0x2926DC21U, 0xF0009F2CU, 0x471D5E28U,
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
};
inline unsigned int crc32(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] ={
0x00000000U, 0xB71DC104U, 0x6E3B8209U, 0xD926430DU, 0xDC760413U, 0x6B6BC517U, 0xB24D861AU,
0x0550471EU, 0xB8ED0826U, 0x0FF0C922U, 0xD6D68A2FU, 0x61CB4B2BU, 0x649B0C35U, 0xD386CD31U,
0x0AA08E3CU, 0xBDBD4F38U, 0x70DB114CU, 0xC7C6D048U, 0x1EE09345U, 0xA9FD5241U, 0xACAD155FU,
0x1BB0D45BU, 0xC2969756U, 0x758B5652U, 0xC836196AU, 0x7F2BD86EU, 0xA60D9B63U, 0x11105A67U,
0x14401D79U, 0xA35DDC7DU, 0x7A7B9F70U, 0xCD665E74U, 0xE0B62398U, 0x57ABE29CU, 0x8E8DA191U,
0x39906095U, 0x3CC0278BU, 0x8BDDE68FU, 0x52FBA582U, 0xE5E66486U, 0x585B2BBEU, 0xEF46EABAU,
0x3660A9B7U, 0x817D68B3U, 0x842D2FADU, 0x3330EEA9U, 0xEA16ADA4U, 0x5D0B6CA0U, 0x906D32D4U,
0x2770F3D0U, 0xFE56B0DDU, 0x494B71D9U, 0x4C1B36C7U, 0xFB06F7C3U, 0x2220B4CEU, 0x953D75CAU,
0x28803AF2U, 0x9F9DFBF6U, 0x46BBB8FBU, 0xF1A679FFU, 0xF4F63EE1U, 0x43EBFFE5U, 0x9ACDBCE8U,
0x2DD07DECU, 0x77708634U, 0xC06D4730U, 0x194B043DU, 0xAE56C539U, 0xAB068227U, 0x1C1B4323U,
0xC53D002EU, 0x7220C12AU, 0xCF9D8E12U, 0x78804F16U, 0xA1A60C1BU, 0x16BBCD1FU, 0x13EB8A01U,
0xA4F64B05U, 0x7DD00808U, 0xCACDC90CU, 0x07AB9778U, 0xB0B6567CU, 0x69901571U, 0xDE8DD475U,
0xDBDD936BU, 0x6CC0526FU, 0xB5E61162U, 0x02FBD066U, 0xBF469F5EU, 0x085B5E5AU, 0xD17D1D57U,
0x6660DC53U, 0x63309B4DU, 0xD42D5A49U, 0x0D0B1944U, 0xBA16D840U, 0x97C6A5ACU, 0x20DB64A8U,
0xF9FD27A5U, 0x4EE0E6A1U, 0x4BB0A1BFU, 0xFCAD60BBU, 0x258B23B6U, 0x9296E2B2U, 0x2F2BAD8AU,
0x98366C8EU, 0x41102F83U, 0xF60DEE87U, 0xF35DA999U, 0x4440689DU, 0x9D662B90U, 0x2A7BEA94U,
0xE71DB4E0U, 0x500075E4U, 0x892636E9U, 0x3E3BF7EDU, 0x3B6BB0F3U, 0x8C7671F7U, 0x555032FAU,
0xE24DF3FEU, 0x5FF0BCC6U, 0xE8ED7DC2U, 0x31CB3ECFU, 0x86D6FFCBU, 0x8386B8D5U, 0x349B79D1U,
0xEDBD3ADCU, 0x5AA0FBD8U, 0xEEE00C69U, 0x59FDCD6DU, 0x80DB8E60U, 0x37C64F64U, 0x3296087AU,
0x858BC97EU, 0x5CAD8A73U, 0xEBB04B77U, 0x560D044FU, 0xE110C54BU, 0x38368646U, 0x8F2B4742U,
0x8A7B005CU, 0x3D66C158U, 0xE4408255U, 0x535D4351U, 0x9E3B1D25U, 0x2926DC21U, 0xF0009F2CU,
0x471D5E28U, 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 * end = tmpData + len;
while(tmpData < end){
crc = table[((unsigned char) crc) ^ *tmpData++] ^ (crc >> 8);
}
const char *tmpData = data;
const char *end = tmpData + len;
while (tmpData < end){crc = table[((unsigned char)crc) ^ *tmpData++] ^ (crc >> 8);}
return crc;
}
}
}// namespace checksum

View file

@ -132,8 +132,7 @@ void Util::Config::printHelp(std::ostream &output){
}
while (f.size() < longest){f.append(" ");}
if (it->isMember("arg")){
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString()
<< std::endl;
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() << std::endl;
}else{
output << f << (*it)["help"].asString() << std::endl;
}
@ -141,8 +140,7 @@ void Util::Config::printHelp(std::ostream &output){
if (it->isMember("arg_num")){
f = it.key();
while (f.size() < longest){f.append(" ");}
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString()
<< std::endl;
output << f << "(" << (*it)["arg"].asString() << ") " << (*it)["help"].asString() << std::endl;
}
}
}
@ -188,9 +186,9 @@ bool Util::Config::parseArgs(int &argc, char **&argv){
<< std::endl;
#endif
#ifdef WITH_THREADNAMES
std::cout
<< "- Flag: With threadnames. Debuggers will show sensible human-readable thread names."
<< std::endl;
std::cout << "- Flag: With threadnames. Debuggers will show sensible human-readable thread "
"names."
<< std::endl;
#endif
/*LTS-START*/
#ifndef UPDATER
@ -210,9 +208,8 @@ bool Util::Config::parseArgs(int &argc, char **&argv){
#endif
#ifdef STATS_DELAY
if (STATS_DELAY != 15){
std::cout << "- Setting: Stats delay " << STATS_DELAY
<< ". Statistics of viewer counts are delayed by " << STATS_DELAY
<< " seconds as opposed to the default of 15 seconds. ";
std::cout << "- Setting: Stats delay " << STATS_DELAY << ". Statistics of viewer counts are delayed by "
<< STATS_DELAY << " seconds as opposed to the default of 15 seconds. ";
if (STATS_DELAY > 15){
std::cout << "This makes them more accurate." << std::endl;
}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.
JSON::Value &Util::Config::getOption(std::string optname, bool asArray){
if (!vals.isMember(optname)){
std::cout << "Fatal error: a non-existent option '" << optname << "' was accessed."
<< std::endl;
std::cout << "Fatal error: a non-existent option '" << optname << "' was accessed." << std::endl;
exit(37);
}
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);
}
int Util::Config::threadServer(Socket::Server &server_socket,
int (*callback)(Socket::Connection &)){
int Util::Config::threadServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &)){
Util::Procs::socketList.insert(server_socket.getSocket());
while (is_active && server_socket.connected()){
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());
if (!is_restarting){
server_socket.close();
}
if (!is_restarting){server_socket.close();}
return 0;
}
@ -366,7 +359,7 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
server_socket = Socket::Server(0);
}else if (vals.isMember("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);
}
if (!server_socket.connected()){
@ -394,7 +387,7 @@ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){
server_socket = Socket::Server(0);
}else if (vals.isMember("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);
}
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_ASYNCIO:
case SI_MESGQ:
INFO_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum,
sigInfo->si_pid);
INFO_MSG("Received signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid);
break;
default: INFO_MSG("Received signal %s (%d)", strsignal(signum), signum); break;
}
@ -653,4 +645,3 @@ void Util::setUser(std::string username){
}
}
}

View file

@ -23,7 +23,7 @@ namespace Util{
public:
// variables
static bool is_active; ///< Set to true by activate(), set to false by the signal handler.
static bool is_active; ///< Set to true by activate(), set to false by the signal handler.
static bool is_restarting; ///< Set to true when restarting, set to false on boot.
static uint32_t printDebugLevel;
static std::string streamName; ///< Used by debug messages to identify the stream name
@ -64,4 +64,3 @@ namespace Util{
void setUser(std::string user);
}// namespace Util

View file

@ -2,31 +2,33 @@
// Defines to print debug messages.
#ifndef MIST_DEBUG
#define MIST_DEBUG 1
#define DLVL_NONE 0 // All debugging disabled.
#define DLVL_FAIL 1 // Only messages about failed operations.
#define DLVL_ERROR 2 // Only messages about errors and failed operations.
#define DLVL_WARN 3 // Warnings, errors, and fail messages.
#define DLVL_DEVEL 4 // All of the above, plus status messages handy during development.
#define DLVL_INFO 4 // All of the above, plus status messages handy during development.
#define DLVL_MEDIUM 5 // Slightly more than just development-level messages.
#define DLVL_HIGH 6 // Verbose debugging messages.
#define DLVL_VERYHIGH 7 // Very verbose debugging messages.
#define DLVL_EXTREME 8 // Everything is reported in extreme detail.
#define DLVL_INSANE 9 // Everything is reported in insane detail.
#define DLVL_NONE 0 // All debugging disabled.
#define DLVL_FAIL 1 // Only messages about failed operations.
#define DLVL_ERROR 2 // Only messages about errors and failed operations.
#define DLVL_WARN 3 // Warnings, errors, and fail messages.
#define DLVL_DEVEL 4 // All of the above, plus status messages handy during development.
#define DLVL_INFO 4 // All of the above, plus status messages handy during development.
#define DLVL_MEDIUM 5 // Slightly more than just development-level messages.
#define DLVL_HIGH 6 // Verbose debugging messages.
#define DLVL_VERYHIGH 7 // Very verbose debugging messages.
#define DLVL_EXTREME 8 // Everything is reported in extreme detail.
#define DLVL_INSANE 9 // Everything is reported in insane detail.
#define DLVL_DONTEVEN 10 // All messages enabled, even pointless ones.
#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_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
#define __STDC_FORMAT_MACROS 1
#include <stdio.h>
#include <unistd.h>
#include "config.h"
#include <inttypes.h>
#include <stdint.h>
#include "config.h"
static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "MEDIUM", "HIGH", "VERYHIGH", "EXTREME", "INSANE", "DONTEVEN"};
#include <stdio.h>
#include <unistd.h>
static const char *DBG_LVL_LIST[] ={"NONE", "FAIL", "ERROR", "WARN", "INFO", "MEDIUM",
"HIGH", "VERYHIGH", "EXTREME", "INSANE", "DONTEVEN"};
#if !defined(PRIu64)
#define PRIu64 "llu"
@ -40,15 +42,31 @@ static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "
#include <errno.h>
#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
#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
#else
#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
#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
@ -56,18 +74,16 @@ static const char * DBG_LVL_LIST[] = {"NONE", "FAIL", "ERROR", "WARN", "INFO", "
static inline void show_stackframe(){}
#else
#include <execinfo.h>
static inline void show_stackframe() {
static inline void show_stackframe(){
void *trace[16];
char **messages = 0;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
for (i=1; i<trace_size; ++i){
for (i = 1; i < trace_size; ++i){
size_t p = 0;
while(messages[i][p] != '(' && messages[i][p] != ' ' && messages[i][p] != 0){
++p;
}
DEBUG_MSG(0, "Backtrace[%d]: %s", i, messages[i]+p);
while (messages[i][p] != '(' && messages[i][p] != ' ' && messages[i][p] != 0){++p;}
DEBUG_MSG(0, "Backtrace[%d]: %s", i, messages[i] + p);
}
}
#endif
@ -94,12 +110,12 @@ static inline void show_stackframe(){}
#endif
#ifndef SHM_DATASIZE
#define SHM_DATASIZE 20
#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
#define STATS_DELAY 15
@ -107,7 +123,7 @@ static inline void show_stackframe(){}
#define STATS_INPUT_DELAY 2
#ifndef INPUT_TIMEOUT
#define INPUT_TIMEOUT STATS_DELAY*2
#define INPUT_TIMEOUT STATS_DELAY * 2
#endif
/// The size used for stream headers for live streams
@ -130,9 +146,9 @@ static inline void show_stackframe(){}
/// Interval where the input refreshes the user data for stats etc.
#define INPUT_USER_INTERVAL 1000
#define SHM_STREAM_INDEX "MstSTRM%s" //%s stream name
#define SHM_STREAM_INDEX "MstSTRM%s" //%s stream name
#define SHM_STREAM_STATE "MstSTATE%s" //%s stream name
#define SHM_STREAM_CONF "MstSCnf%s" //%s stream name
#define SHM_STREAM_CONF "MstSCnf%s" //%s stream name
#define SHM_GLOBAL_CONF "MstGlobalConfig"
#define STRMSTAT_OFF 0
#define STRMSTAT_INIT 1
@ -141,15 +157,15 @@ static inline void show_stackframe(){}
#define STRMSTAT_READY 4
#define STRMSTAT_SHUTDOWN 5
#define STRMSTAT_INVALID 255
#define SHM_TRACK_META "MstTRAK%s@%lu" //%s stream name, %lu track ID
#define SHM_TRACK_META "MstTRAK%s@%lu" //%s stream name, %lu track ID
#define SHM_TRACK_INDEX "MstTRID%s@%lu" //%s stream name, %lu track ID
#define SHM_TRACK_INDEX_SIZE 8192
#define SHM_TRACK_DATA "MstDATA%s@%lu_%lu" //%s stream name, %lu track ID, %lu page #
#define SHM_STATISTICS "MstSTAT"
#define SHM_USERS "MstUSER%s" //%s stream name
#define SHM_USERS "MstUSER%s" //%s stream name
#define SHM_TRIGGER "MstTRGR%s" //%s trigger name
#define SEM_LIVE "/MstLIVE%s" //%s stream name
#define SEM_INPUT "/MstInpt%s" //%s stream name
#define SEM_LIVE "/MstLIVE%s" //%s stream name
#define SEM_INPUT "/MstInpt%s" //%s stream name
#define SEM_SESSCACHE "/MstSessCacheLock"
#define SHM_CAPA "MstCapa"
#define SHM_PROTO "MstProt"
@ -157,16 +173,15 @@ static inline void show_stackframe(){}
#define SHM_STATE_LOGS "MstStateLogs"
#define SHM_STATE_ACCS "MstStateAccs"
#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_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_ITEM 165 // 4 byte crc, 100b streamname, 20b connector, 40b host, 1b sync
#define SHM_SESSIONS_SIZE 5248000 // 5MiB = almost 32k sessions
#define SHM_STREAM_ENCRYPT "MstCRYP%s" //%s stream name
#define SIMUL_TRACKS 20
#ifndef UDP_API_HOST
#define UDP_API_HOST "localhost"
#endif
@ -177,7 +192,6 @@ static inline void show_stackframe(){}
#define INVALID_TRACK_ID 0
//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.
// 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.
#define SIMULATED_LIVE_BUFFER 7000

View file

@ -1,5 +1,5 @@
#include "downloader.h"
#include "defines.h"
#include "downloader.h"
#include "encode.h"
#include "timing.h"
@ -136,7 +136,8 @@ namespace HTTP{
}
/// 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);
H.sendRequest(getSocket(), body, bodyLen, false);
H.Clean();
@ -147,7 +148,6 @@ namespace HTTP{
doRequest(link, method, body.data(), body.size());
}
/// Do a HEAD request to download the HTTP headers only, returns true on success
bool Downloader::head(const HTTP::URL &link, uint8_t maxRecursiveDepth){
if (!canRequest(link)){return false;}
@ -190,9 +190,7 @@ namespace HTTP{
}
}
if(H.protocol == "HTTP/1.0"){
getSocket().close();
}
if (H.protocol == "HTTP/1.0"){getSocket().close();}
H.headerOnly = false;
return true; // Success!
@ -218,9 +216,11 @@ namespace HTTP{
getSocket().close();
}else{
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{
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();
}
@ -230,7 +230,8 @@ namespace HTTP{
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];
if (byteEnd <= 0){// get range from byteStart til eof
sprintf(tmp, "bytes=%zu-", byteStart);
@ -277,9 +278,7 @@ namespace HTTP{
return true;
}
const HTTP::URL & Downloader::lastURL(){
return nbLink;
}
const HTTP::URL &Downloader::lastURL(){return nbLink;}
// continue handling a request, originally set up by the getNonBlocking() function
// returns true if the request is complete
@ -368,14 +367,15 @@ namespace HTTP{
}
}
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){
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;}
size_t loop = retryCount; // max 5 attempts
while (--loop){// loop while we are unsuccessful
@ -499,4 +499,3 @@ namespace HTTP{
}
}// namespace HTTP

View file

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

View file

@ -1,61 +1,54 @@
#include <algorithm>
#include "defines.h"
#include "dtls_srtp_handshake.h"
#include <algorithm>
/* Write mbedtls into a log file. */
#define LOG_TO_FILE 0
#if LOG_TO_FILE
# include <fstream>
#include <fstream>
#endif
/* ----------------------------------------- */
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 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_write(void* user, const unsigned char* buf, size_t len); /* Called when mbedtls wants to write data to e.g. a socket. */
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_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);
/* ----------------------------------------- */
DTLSSRTPHandshake::DTLSSRTPHandshake()
:write_callback(NULL)
,cert(NULL)
,key(NULL)
{
memset((void*)&entropy_ctx, 0x00, sizeof(entropy_ctx));
memset((void*)&rand_ctx, 0x00, sizeof(rand_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));
DTLSSRTPHandshake::DTLSSRTPHandshake() : write_callback(NULL), cert(NULL), key(NULL){
memset((void *)&entropy_ctx, 0x00, sizeof(entropy_ctx));
memset((void *)&rand_ctx, 0x00, sizeof(rand_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,
mbedtls_pk_context* privateKey,
int(*writeCallback)(const uint8_t* data, int* nbytes)
)
{
int DTLSSRTPHandshake::init(mbedtls_x509_crt *certificate, mbedtls_pk_context *privateKey,
int (*writeCallback)(const uint8_t *data, int *nbytes)){
int r = 0;
mbedtls_ssl_srtp_profile srtp_profiles[] = {
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80,
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32
};
mbedtls_ssl_srtp_profile srtp_profiles[] ={MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80,
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32};
if (!writeCallback) {
if (!writeCallback){
FAIL_MSG("No writeCallack function given.");
r = -3;
goto error;
}
if (!certificate) {
if (!certificate){
FAIL_MSG("Given certificate is null.");
r = -5;
goto error;
}
if (!privateKey) {
if (!privateKey){
FAIL_MSG("Given key is null.");
r = -10;
goto error;
@ -72,16 +65,18 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
mbedtls_ssl_cookie_init(&cookie_ctx);
/* 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);
if (0 != r) {
r = mbedtls_ctr_drbg_seed(&rand_ctx, mbedtls_entropy_func, &entropy_ctx,
(const unsigned char *)"mist-srtp", 9);
if (0 != r){
print_mbedtls_error(r);
r = -20;
goto error;
}
/* 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);
if (0 != r) {
r = mbedtls_ssl_config_defaults(&ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (0 != r){
print_mbedtls_error(r);
r = -30;
goto error;
@ -95,8 +90,9 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
mbedtls_debug_set_threshold(10);
/* enable SRTP */
r = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles, sizeof(srtp_profiles) / sizeof(srtp_profiles[0]));
if (0 != r) {
r = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&ssl_conf, srtp_profiles,
sizeof(srtp_profiles) / sizeof(srtp_profiles[0]));
if (0 != r){
print_mbedtls_error(r);
r = -40;
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 */
r = mbedtls_ssl_conf_own_cert(&ssl_conf, cert, key);
if (0 != r) {
if (0 != r){
print_mbedtls_error(r);
r = -50;
goto error;
@ -112,7 +108,7 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
/* cookie setup (e.g. to prevent ddos). */
r = mbedtls_ssl_cookie_setup(&cookie_ctx, mbedtls_ctr_drbg_random, &rand_ctx);
if (0 != r) {
if (0 != r){
print_mbedtls_error(r);
r = -60;
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. */
r = mbedtls_ssl_setup(&ssl_ctx, &ssl_conf);
if (0 != r) {
if (0 != r){
print_mbedtls_error(r);
r = -70;
goto error;
}
/* 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 */
{
std::string remote_id = "mist";
r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char*)remote_id.c_str(), remote_id.size());
if (0 != r) {
r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char *)remote_id.c_str(),
remote_id.size());
if (0 != r){
print_mbedtls_error(r);
r = -80;
goto error;
@ -148,16 +145,14 @@ int DTLSSRTPHandshake::init(mbedtls_x509_crt* certificate,
write_callback = writeCallback;
error:
error:
if (r < 0) {
shutdown();
}
if (r < 0){shutdown();}
return r;
}
int DTLSSRTPHandshake::shutdown() {
int DTLSSRTPHandshake::shutdown(){
/* cleanup the refs from the settings. */
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.");
return -1;
}
if (0 == nbytes) {
if (0 == nbytes){
ERROR_MSG("Given nbytes is 0.");
return -2;
}
if (MBEDTLS_SSL_HANDSHAKE_OVER == ssl_ctx.state) {
if (MBEDTLS_SSL_HANDSHAKE_OVER == ssl_ctx.state){
ERROR_MSG("Already finished the handshake.");
return -3;
}
@ -202,58 +197,60 @@ int DTLSSRTPHandshake::parse(const uint8_t* data, size_t nbytes) {
int r = 0;
std::copy(data, data + nbytes, std::back_inserter(buffer));
do {
do{
r = mbedtls_ssl_handshake(&ssl_ctx);
switch (r) {
/* 0 = handshake done. */
case 0: {
if (0 != extractKeyingMaterial()) {
ERROR_MSG("Failed to extract keying material after handshake was done.");
return -2;
}
return 0;
}
/* see the dtls server example; this is used to prevent certain attacks (ddos) */
case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: {
if (0 != resetSession()) {
ERROR_MSG("Failed to reset the session which is necessary when we need to verify the HELLO.");
return -3;
}
break;
}
case MBEDTLS_ERR_SSL_WANT_READ: {
DONTEVEN_MSG("mbedtls wants a bit more data before it can continue parsing the DTLS handshake.");
break;
}
default: {
ERROR_MSG("A serious mbedtls error occured.");
print_mbedtls_error(r);
switch (r){
/* 0 = handshake done. */
case 0:{
if (0 != extractKeyingMaterial()){
ERROR_MSG("Failed to extract keying material after handshake was done.");
return -2;
}
return 0;
}
}
while (MBEDTLS_ERR_SSL_WANT_WRITE == r);
/* see the dtls server example; this is used to prevent certain attacks (ddos) */
case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED:{
if (0 != resetSession()){
ERROR_MSG(
"Failed to reset the session which is necessary when we need to verify the HELLO.");
return -3;
}
break;
}
case MBEDTLS_ERR_SSL_WANT_READ:{
DONTEVEN_MSG(
"mbedtls wants a bit more data before it can continue parsing the DTLS handshake.");
break;
}
default:{
ERROR_MSG("A serious mbedtls error occured.");
print_mbedtls_error(r);
return -2;
}
}
}while (MBEDTLS_ERR_SSL_WANT_WRITE == r);
return 0;
}
/* ----------------------------------------- */
int DTLSSRTPHandshake::resetSession() {
int DTLSSRTPHandshake::resetSession(){
std::string remote_id = "mist"; /* @todo for now we hardcoded this... */
int r = 0;
r = mbedtls_ssl_session_reset(&ssl_ctx);
if (0 != r) {
if (0 != r){
print_mbedtls_error(r);
return -1;
}
r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char*)remote_id.c_str(), remote_id.size());
if (0 != r) {
r = mbedtls_ssl_set_client_transport_id(&ssl_ctx, (const unsigned char *)remote_id.c_str(),
remote_id.size());
if (0 != r){
print_mbedtls_error(r);
return -2;
}
@ -267,39 +264,39 @@ int DTLSSRTPHandshake::resetSession() {
master key is 128 bits => 16 bytes.
master salt is 112 bits => 14 bytes
*/
int DTLSSRTPHandshake::extractKeyingMaterial() {
int DTLSSRTPHandshake::extractKeyingMaterial(){
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);
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);
return -1;
}
/* @todo following code is for server mode only */
mbedtls_ssl_srtp_profile srtp_profile = mbedtls_ssl_get_dtls_srtp_protection_profile(&ssl_ctx);
switch (srtp_profile) {
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80: {
cipher = "SRTP_AES128_CM_SHA1_80";
break;
}
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32: {
cipher = "SRTP_AES128_CM_SHA1_32";
break;
}
default: {
ERROR_MSG("Unhandled SRTP profile, cannot extract keying material.");
return -6;
}
switch (srtp_profile){
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80:{
cipher = "SRTP_AES128_CM_SHA1_80";
break;
}
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32:{
cipher = "SRTP_AES128_CM_SHA1_32";
break;
}
default:{
ERROR_MSG("Unhandled SRTP profile, cannot extract keying material.");
return -6;
}
}
remote_key.assign((char*)(&keying_material[0]) + 0, 16);
local_key.assign((char*)(&keying_material[0]) + 16, 16);
remote_salt.assign((char*)(&keying_material[0]) + 32, 14);
local_salt.assign((char*)(&keying_material[0]) + 46, 14);
remote_key.assign((char *)(&keying_material[0]) + 0, 16);
local_key.assign((char *)(&keying_material[0]) + 16, 16);
remote_salt.assign((char *)(&keying_material[0]) + 32, 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("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
*/
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);
if (NULL == hs) {
DTLSSRTPHandshake *hs = static_cast<DTLSSRTPHandshake *>(user);
if (NULL == hs){
ERROR_MSG("Failed to cast the user pointer into a DTLSSRTPHandshake.");
return -1;
}
/* figure out how much we can read. */
if (hs->buffer.size() == 0) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
if (hs->buffer.size() == 0){return MBEDTLS_ERR_SSL_WANT_READ;}
size_t nbytes = hs->buffer.size();
if (nbytes > len) {
nbytes = len;
}
if (nbytes > len){nbytes = len;}
/* "read" into the given buffer. */
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;
}
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);
if (!hs) {
DTLSSRTPHandshake *hs = static_cast<DTLSSRTPHandshake *>(user);
if (!hs){
FAIL_MSG("Failed to cast the user pointer into a DTLSSRTPHandshake.");
return -1;
}
if (!hs->write_callback) {
if (!hs->write_callback){
FAIL_MSG("The `write_callback` member is NULL.");
return -2;
}
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.");
return -3;
}
if (nwritten != (int)len) {
if (nwritten != (int)len){
FAIL_MSG("The DTLS-SRTP handshake listener MUST write all the data.");
return -4;
}
@ -381,40 +374,37 @@ static int on_mbedtls_wants_to_write(void* user, const unsigned char* buf, size_
/* ----------------------------------------- */
static void print_mbedtls_error(int r) {
char buf[1024] = {};
static void print_mbedtls_error(int r){
char buf[1024] ={};
mbedtls_strerror(r, buf, sizeof(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);
#if LOG_TO_FILE
static std::ofstream ofs;
if (!ofs.is_open()) {
ofs.open("mbedtls.log", std::ios::out);
}
if (!ofs.is_open()) {
return;
}
if (!ofs.is_open()){ofs.open("mbedtls.log", std::ios::out);}
if (!ofs.is_open()){return;}
ofs << str;
ofs.flush();
#endif
}
static std::string mbedtls_err_to_string(int r) {
switch (r) {
case MBEDTLS_ERR_SSL_WANT_READ: { return "MBEDTLS_ERR_SSL_WANT_READ"; }
case MBEDTLS_ERR_SSL_WANT_WRITE: { return "MBEDTLS_ERR_SSL_WANT_WRITE"; }
default: {
print_mbedtls_error(r);
return "UNKNOWN";
}
static std::string mbedtls_err_to_string(int r){
switch (r){
case MBEDTLS_ERR_SSL_WANT_READ:{
return "MBEDTLS_ERR_SSL_WANT_READ";
}
case MBEDTLS_ERR_SSL_WANT_WRITE:{
return "MBEDTLS_ERR_SSL_WANT_WRITE";
}
default:{
print_mbedtls_error(r);
return "UNKNOWN";
}
}
}
/* ---------------------------------------- */

View file

@ -1,26 +1,27 @@
#pragma once
#include <stdint.h>
#include <deque>
#include <mbedtls/config.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.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_cookie.h>
#include <mbedtls/error.h>
#include <mbedtls/debug.h>
#include <mbedtls/timing.h>
#include <mbedtls/x509.h>
#include <stdint.h>
/* ----------------------------------------- */
class DTLSSRTPHandshake {
class DTLSSRTPHandshake{
public:
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 parse(const uint8_t* data, size_t nbytes);
int parse(const uint8_t *data, size_t nbytes);
bool hasKeyingMaterial();
private:
@ -28,8 +29,8 @@ private:
int resetSession();
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_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_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_entropy_context entropy_ctx;
mbedtls_ctr_drbg_context rand_ctx;
mbedtls_ssl_context ssl_ctx;
@ -38,9 +39,9 @@ private:
mbedtls_timing_delay_context timer_ctx;
public:
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::string cipher; /* selected SRTP cipher. */
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::string cipher; /* selected SRTP cipher. */
std::string remote_key;
std::string remote_salt;
std::string local_key;
@ -49,11 +50,9 @@ public:
/* ----------------------------------------- */
inline bool DTLSSRTPHandshake::hasKeyingMaterial() {
return (0 != remote_key.size()
&& 0 != remote_salt.size()
&& 0 != local_key.size()
&& 0 != local_salt.size());
inline bool DTLSSRTPHandshake::hasKeyingMaterial(){
return (0 != remote_key.size() && 0 != remote_salt.size() && 0 != local_key.size() &&
0 != local_salt.size());
}
/* ----------------------------------------- */

View file

@ -1,38 +1,36 @@
/// \file dtsc.cpp
/// Holds all code for DDVTECH Stream Container parsing/generation.
#include "dtsc.h"
#include "defines.h"
#include "dtsc.h"
#include <arpa/inet.h> //for htonl/ntohl
#include <stdlib.h>
#include <string.h> //for memcmp
#include <arpa/inet.h> //for htonl/ntohl
char DTSC::Magic_Header[] = "DTSC";
char DTSC::Magic_Packet[] = "DTPD";
char DTSC::Magic_Packet2[] = "DTP2";
char DTSC::Magic_Command[] = "DTCM";
DTSC::File::File() {
DTSC::File::File(){
F = 0;
buffer = malloc(4);
endPos = 0;
}
DTSC::File::File(const File & rhs) {
DTSC::File::File(const File &rhs){
buffer = malloc(4);
*this = rhs;
}
DTSC::File & DTSC::File::operator =(const File & rhs) {
DTSC::File &DTSC::File::operator=(const File &rhs){
created = rhs.created;
if (rhs.F) {
if (rhs.F){
F = fdopen(dup(fileno(rhs.F)), (created ? "w+b" : "r+b"));
} else {
}else{
F = 0;
}
endPos = rhs.endPos;
if (rhs.myPack) {
myPack = rhs.myPack;
}
if (rhs.myPack){myPack = rhs.myPack;}
metadata = rhs.metadata;
currtime = rhs.currtime;
lastreadpos = rhs.lastreadpos;
@ -42,31 +40,31 @@ DTSC::File & DTSC::File::operator =(const File & rhs) {
return *this;
}
DTSC::File::operator bool() const {
DTSC::File::operator bool() const{
return F;
}
/// Open a filename for DTSC reading/writing.
/// 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);
if (create) {
if (create){
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));
return;
}
//write an empty header
// write an empty header
fseek(F, 0, SEEK_SET);
fwrite(DTSC::Magic_Header, 4, 1, F);
memset(buffer, 0, 4);
fwrite(buffer, 4, 1, F); //write 4 zero-bytes
fwrite(buffer, 4, 1, F); // write 4 zero-bytes
headerSize = 0;
} else {
}else{
F = fopen(filename.c_str(), "r+b");
}
created = create;
if (!F) {
if (!F){
HIGH_MSG("Could not open file %s", filename.c_str());
return;
}
@ -74,62 +72,59 @@ DTSC::File::File(std::string filename, bool create) {
endPos = ftell(F);
bool sepHeader = false;
if (!create) {
if (!create){
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());
fclose(F);
F = 0;
return;
}
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_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){
DEBUG_MSG(DLVL_ERROR, "%s is not a valid DTSC file", filename.c_str());
fclose(F);
F = 0;
return;
} else {
}else{
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);
if (fread(buffer, 4, 1, F) != 1) {
if (fread(buffer, 4, 1, F) != 1){
fseek(F, 4, SEEK_SET);
memset(buffer, 0, 4);
fwrite(buffer, 4, 1, F); //write 4 zero-bytes
} else {
fwrite(buffer, 4, 1, F); // write 4 zero-bytes
}else{
headerSize = ntohl(((uint32_t *)buffer)[0]);
}
if (metadata.moreheader != -1) {
if (!sepHeader) {
if (metadata.moreheader != -1){
if (!sepHeader){
readHeader(0);
fseek(F, 8 + headerSize, SEEK_SET);
} else {
}else{
fseek(F, 0, SEEK_SET);
}
} else {
}else{
fseek(F, 0, SEEK_SET);
File Fhead(filename + ".dtsh");
if (Fhead) {
metadata = Fhead.metadata;
}
if (Fhead){metadata = Fhead.metadata;}
}
currframe = 0;
}
/// Returns the header metadata for this file as JSON::Value.
DTSC::Meta & DTSC::File::getMeta() {
DTSC::Meta &DTSC::File::getMeta(){
return metadata;
}
/// (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.
bool DTSC::File::writeHeader(std::string & header, bool force) {
if (headerSize != header.size() && !force) {
bool DTSC::File::writeHeader(std::string &header, bool force){
if (headerSize != header.size() && !force){
DEBUG_MSG(DLVL_ERROR, "Could not overwrite header - not equal size");
return false;
}
@ -137,9 +132,7 @@ bool DTSC::File::writeHeader(std::string & header, bool force) {
int pSize = htonl(header.size());
fseek(F, 4, SEEK_SET);
int tmpret = fwrite((void *)(&pSize), 4, 1, F);
if (tmpret != 1) {
return false;
}
if (tmpret != 1){return false;}
fseek(F, 8, SEEK_SET);
int ret = fwrite(header.c_str(), headerSize, 1, F);
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.
/// \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);
long long int writePos = ftell(F);
int hSize = htonl(header.size());
int ret = fwrite(DTSC::Magic_Header, 4, 1, F); //write header
if (ret != 1) {
return 0;
}
ret = fwrite((void *)(&hSize), 4, 1, F); //write size
if (ret != 1) {
return 0;
}
ret = fwrite(header.c_str(), header.size(), 1, F); //write contents
if (ret != 1) {
return 0;
}
int ret = fwrite(DTSC::Magic_Header, 4, 1, F); // write header
if (ret != 1){return 0;}
ret = fwrite((void *)(&hSize), 4, 1, F); // write size
if (ret != 1){return 0;}
ret = fwrite(header.c_str(), header.size(), 1, F); // write contents
if (ret != 1){return 0;}
fseek(F, 0, SEEK_END);
endPos = ftell(F);
return writePos; //return position written at
return writePos; // return position written at
}
/// Reads the header at the given file position.
/// 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.
void DTSC::File::readHeader(int pos) {
void DTSC::File::readHeader(int pos){
fseek(F, pos, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1) {
if (feof(F)) {
if (fread(buffer, 4, 1, F) != 1){
if (feof(F)){
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);
}
metadata = Meta();
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);
metadata = Meta();
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);
metadata = Meta();
return;
@ -196,96 +183,91 @@ void DTSC::File::readHeader(int pos) {
long packSize = ntohl(((unsigned long *)buffer)[0]) + 8;
std::string strBuffer;
strBuffer.resize(packSize);
if (packSize) {
if (packSize){
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);
metadata = Meta();
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 (metadata.moreheader) {
if (metadata.moreheader < getBytePosEOF()) {
// if there is another header, read it and replace metadata with that one.
if (metadata.moreheader){
if (metadata.moreheader < getBytePosEOF()){
readHeader(metadata.moreheader);
return;
}
}
if (!metadata.live){
metadata.vod = true;
}
if (!metadata.live){metadata.vod = true;}
}
long int DTSC::File::getBytePosEOF() {
long int DTSC::File::getBytePosEOF(){
return endPos;
}
long int DTSC::File::getBytePos() {
long int DTSC::File::getBytePos(){
return ftell(F);
}
bool DTSC::File::reachedEOF() {
bool DTSC::File::reachedEOF(){
return feof(F);
}
/// Reads the packet available at the current file position.
/// 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.
void DTSC::File::seekNext() {
if (!currentPositions.size()) {
void DTSC::File::seekNext(){
if (!currentPositions.size()){
DEBUG_MSG(DLVL_WARN, "No seek positions set - returning empty packet.");
myPack.null();
return;
}
seekPos thisPos = *currentPositions.begin();
fseek(F, thisPos.bytePos, SEEK_SET);
if (reachedEOF()) {
if (reachedEOF()){
myPack.null();
return;
}
clearerr(F);
currentPositions.erase(currentPositions.begin());
lastreadpos = ftell(F);
if (fread(buffer, 4, 1, F) != 1) {
if (feof(F)) {
if (fread(buffer, 4, 1, F) != 1){
if (feof(F)){
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);
}
myPack.null();
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) == 0) {
if (memcmp(buffer, DTSC::Magic_Header, 4) == 0){
seek_time(myPack.getTime(), myPack.getTrackId(), true);
return seekNext();
}
long long unsigned int version = 0;
if (memcmp(buffer, DTSC::Magic_Packet, 4) == 0) {
version = 1;
}
if (memcmp(buffer, DTSC::Magic_Packet2, 4) == 0) {
version = 2;
}
if (version == 0) {
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d", (unsigned int)lastreadpos, (char *)buffer, DTSC::Magic_Packet2, (int)lastreadpos);
if (memcmp(buffer, DTSC::Magic_Packet, 4) == 0){version = 1;}
if (memcmp(buffer, DTSC::Magic_Packet2, 4) == 0){version = 2;}
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();
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);
myPack.null();
return;
}
long packSize = ntohl(((unsigned long *)buffer)[0]);
char * packBuffer = (char *)malloc(packSize + 8);
if (version == 1) {
char *packBuffer = (char *)malloc(packSize + 8);
if (version == 1){
memcpy(packBuffer, "DTPD", 4);
} else {
}else{
memcpy(packBuffer, "DTP2", 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);
myPack.null();
free(packBuffer);
@ -293,24 +275,24 @@ void DTSC::File::seekNext() {
}
myPack.reInit(packBuffer, packSize + 8);
free(packBuffer);
if (metadata.merged) {
if (metadata.merged){
int tempLoc = getBytePos();
char newHeader[20];
bool insert = false;
seekPos tmpPos;
if (fread((void *)newHeader, 20, 1, F) == 1) {
if (memcmp(newHeader, DTSC::Magic_Packet2, 4) == 0) {
if (fread((void *)newHeader, 20, 1, F) == 1){
if (memcmp(newHeader, DTSC::Magic_Packet2, 4) == 0){
tmpPos.bytePos = tempLoc;
tmpPos.trackID = ntohl(((int *)newHeader)[2]);
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 += ntohl(((int *)newHeader)[4]);
insert = true;
} else {
}else{
long tid = myPack.getTrackId();
for (unsigned int i = 0; i != metadata.tracks[tid].keys.size(); i++) {
if ((unsigned long long)metadata.tracks[tid].keys[i].getTime() > myPack.getTime()) {
for (unsigned int i = 0; i != metadata.tracks[tid].keys.size(); i++){
if ((unsigned long long)metadata.tracks[tid].keys[i].getTime() > myPack.getTime()){
tmpPos.seekTime = metadata.tracks[tid].keys[i].getTime();
tmpPos.bytePos = metadata.tracks[tid].keys[i].getBpos();
tmpPos.trackID = tid;
@ -319,9 +301,10 @@ void DTSC::File::seekNext() {
}
}
}
if (currentPositions.size()) {
for (std::set<seekPos>::iterator curPosIter = currentPositions.begin(); curPosIter != currentPositions.end(); curPosIter++) {
if ((*curPosIter).trackID == tmpPos.trackID && (*curPosIter).seekTime >= tmpPos.seekTime) {
if (currentPositions.size()){
for (std::set<seekPos>::iterator curPosIter = currentPositions.begin();
curPosIter != currentPositions.end(); curPosIter++){
if ((*curPosIter).trackID == tmpPos.trackID && (*curPosIter).seekTime >= tmpPos.seekTime){
insert = false;
break;
}
@ -330,11 +313,9 @@ void DTSC::File::seekNext() {
}
}
if (insert){
if (tmpPos.seekTime > 0xffffffffffffff00ll){
tmpPos.seekTime = 0;
}
if (tmpPos.seekTime > 0xffffffffffffff00ll){tmpPos.seekTime = 0;}
currentPositions.insert(tmpPos);
} else {
}else{
seek_time(myPack.getTime(), myPack.getTrackId(), true);
}
seek_bpos(tempLoc);
@ -345,39 +326,38 @@ void DTSC::File::seekNext() {
}
void DTSC::File::parseNext(){
char header_buffer[4] = {0, 0, 0, 0};
char header_buffer[4] ={0, 0, 0, 0};
lastreadpos = ftell(F);
if (fread(header_buffer, 4, 1, F) != 1) {
if (feof(F)) {
if (fread(header_buffer, 4, 1, F) != 1){
if (feof(F)){
DEBUG_MSG(DLVL_DEVEL, "End of file reached @ %d", (int)lastreadpos);
} else {
}else{
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
}
myPack.null();
return;
}
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;
}
if (memcmp(header_buffer, DTSC::Magic_Packet2, 4) == 0) {
version = 2;
}
if (version == 0) {
if (memcmp(header_buffer, DTSC::Magic_Packet2, 4) == 0){version = 2;}
if (version == 0){
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x: %.4s", (unsigned int)lastreadpos, (char *)buffer);
myPack.null();
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);
myPack.null();
return;
}
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 + 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);
myPack.null();
free(packBuffer);
@ -388,19 +368,19 @@ void DTSC::File::parseNext(){
}
/// 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;
}
/// 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;
}
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;
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.bytePos = getBytePos();
/*
@ -408,135 +388,124 @@ bool DTSC::File::seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek
tmpPos.bytePos += myPack.getDataLen();
}
*/
} else {
}else{
tmpPos.seekTime = 0;
tmpPos.bytePos = 0;
}
if (reachedEOF()) {
if (reachedEOF()){
clearerr(F);
seek_bpos(0);
tmpPos.bytePos = 0;
tmpPos.seekTime = 0;
}
DTSC::Track & trackRef = metadata.tracks[trackNo];
for (unsigned int i = 0; i < trackRef.keys.size(); i++) {
DTSC::Track &trackRef = metadata.tracks[trackNo];
for (unsigned int i = 0; i < trackRef.keys.size(); i++){
long keyTime = trackRef.keys[i].getTime();
if (keyTime > ms) {
break;
}
if ((long long unsigned int)keyTime > tmpPos.seekTime) {
if (keyTime > ms){break;}
if ((long long unsigned int)keyTime > tmpPos.seekTime){
tmpPos.seekTime = keyTime;
tmpPos.bytePos = trackRef.keys[i].getBpos();
}
}
bool foundPacket = false;
while (!foundPacket) {
while (!foundPacket){
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);
return false;
}
//Seek to first packet after ms.
// Seek to first packet after ms.
seek_bpos(tmpPos.bytePos);
//read the header
// read the header
char header[20];
if (fread((void *)header, 20, 1, F) != 1){
DEBUG_MSG(DLVL_WARN, "Could not read header from file. Much sadface.");
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]);
unsigned int packID = ntohl(((int *)header)[2]);
if (memcmp(header, Magic_Packet2, 4) != 0 || packID != trackNo) {
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);
if (memcmp(header, Magic_Packet2, 4) != 0 || packID != trackNo){
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);
tmpPos.bytePos = 0;
continue;
}
tmpPos.bytePos += 8 + packSize;
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);
myTime += ntohl(((int *)header)[4]);
tmpPos.seekTime = myTime;
if (myTime >= ms) {
if (myTime >= ms){
foundPacket = true;
} else {
}else{
tmpPos.bytePos += 8 + packSize;
continue;
}
}
//DEBUG_MSG(DLVL_HIGH, "Seek to %u:%d resulted in %lli", trackNo, ms, tmpPos.seekTime);
if (tmpPos.seekTime > 0xffffffffffffff00ll){
tmpPos.seekTime = 0;
}
// DEBUG_MSG(DLVL_HIGH, "Seek to %u:%d resulted in %lli", trackNo, ms, tmpPos.seekTime);
if (tmpPos.seekTime > 0xffffffffffffff00ll){tmpPos.seekTime = 0;}
currentPositions.insert(tmpPos);
return true;
}
/// Attempts to seek to the given time in ms within the file.
/// Returns true if successful, false otherwise.
bool DTSC::File::seek_time(unsigned int ms) {
bool DTSC::File::seek_time(unsigned int ms){
currentPositions.clear();
if (selectedTracks.size()) {
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) {
if (selectedTracks.size()){
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
seek_time(ms, (*it), true);
}
}
return true;
}
bool DTSC::File::seek_bpos(int bpos) {
if (fseek(F, bpos, SEEK_SET) == 0) {
return true;
}
bool DTSC::File::seek_bpos(int bpos){
if (fseek(F, bpos, SEEK_SET) == 0){return true;}
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);
fwrite(newPacket.c_str(), newPacket.size(), 1, F);
fseek(F, 0, SEEK_END);
if (ftell(F) > endPos) {
endPos = ftell(F);
}
if (ftell(F) > endPos){endPos = ftell(F);}
}
void DTSC::File::writePacket(std::string & newPacket) {
void DTSC::File::writePacket(std::string &newPacket){
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);
endPos = ftell(F);
}
void DTSC::File::writePacket(JSON::Value & newPacket) {
void DTSC::File::writePacket(JSON::Value &newPacket){
writePacket(newPacket.toNetPacked());
}
bool DTSC::File::atKeyframe() {
if (myPack.getFlag("keyframe")) {
return true;
}
bool DTSC::File::atKeyframe(){
if (myPack.getFlag("keyframe")){return true;}
long long int bTime = myPack.getTime();
DTSC::Track & trackRef = metadata.tracks[myPack.getTrackId()];
for (unsigned int i = 0; i < trackRef.keys.size(); i++) {
if (trackRef.keys[i].getTime() >= bTime) {
return (trackRef.keys[i].getTime() == bTime);
}
DTSC::Track &trackRef = metadata.tracks[myPack.getTrackId()];
for (unsigned int i = 0; i < trackRef.keys.size(); i++){
if (trackRef.keys[i].getTime() >= bTime){return (trackRef.keys[i].getTime() == bTime);}
}
return false;
}
void DTSC::File::selectTracks(std::set<unsigned long> & tracks) {
void DTSC::File::selectTracks(std::set<unsigned long> &tracks){
selectedTracks = tracks;
currentPositions.clear();
seek_time(0);
}
/// Close the file if open
DTSC::File::~File() {
if (F) {
DTSC::File::~File(){
if (F){
fclose(F);
F = 0;
}

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -121,4 +121,3 @@ namespace EBML{
virtual std::string toPrettyString(const uint8_t indent = 0, const uint8_t detail = 3) const;
};
}// namespace EBML

View file

@ -118,8 +118,7 @@ namespace EBML{
void sendElemInfo(Socket::Connection &C, const std::string &appName, double duration){
sendElemHead(C, EID_INFO,
13 + 2 * appName.size() +
(duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
13 + 2 * appName.size() + (duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
sendElemUInt(C, EID_TIMECODESCALE, 1000000);
if (duration > 0){sendElemDbl(C, EID_DURATION, duration);}
sendElemStr(C, EID_MUXINGAPP, appName);
@ -136,8 +135,7 @@ namespace EBML{
(duration > 0 ? sizeElemDbl(EID_DURATION, duration) : 0));
}
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime,
bool forceKeyframe){
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime, bool forceKeyframe){
size_t dataLen = 0;
char *dataPointer = 0;
pkt.getString("data", dataPointer, dataLen);
@ -170,8 +168,7 @@ namespace EBML{
return sizeElemHead(EID_SEEK, elems) + elems;
}
void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos,
uint64_t relaPos){
void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos){
uint32_t elemsA = 0, elemsB = 0;
elemsA += sizeElemUInt(EID_CUETRACK, track);
elemsA += sizeElemUInt(EID_CUECLUSTERPOSITION, clusterPos);
@ -196,4 +193,3 @@ namespace EBML{
}
}// namespace EBML

View file

@ -17,8 +17,7 @@ namespace EBML{
void sendElemSeek(Socket::Connection &C, uint32_t ID, uint64_t bytePos);
uint32_t sizeElemSeek(uint32_t ID, uint64_t bytePos);
void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos,
uint64_t relaPos);
void sendElemCuePoint(Socket::Connection &C, uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos);
uint32_t sizeElemCuePoint(uint64_t time, uint64_t track, uint64_t clusterPos, uint64_t relaPos);
uint8_t sizeUInt(const uint64_t val);
@ -28,8 +27,6 @@ namespace EBML{
uint32_t sizeElemDbl(uint32_t ID, const double val);
uint32_t sizeElemStr(uint32_t ID, const std::string &val);
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime,
bool forceKeyframe = false);
void sendSimpleBlock(Socket::Connection &C, DTSC::Packet &pkt, uint64_t clusterTime, bool forceKeyframe = false);
uint32_t sizeSimpleBlock(uint64_t trackId, uint32_t dataSize);
}// namespace EBML

View file

@ -101,11 +101,9 @@ namespace Encodings{
std::string escaped = "";
int max = c.length();
for (int i = 0; i < max; i++){
if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') ||
('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') ||
(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)){
escaped.append(&c[i], 1);
}else{
@ -143,4 +141,3 @@ namespace Encodings{
}
}// namespace Encodings

View file

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

View file

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

View file

@ -1,34 +1,35 @@
#pragma once
#include <string>
#include "dtsc.h"
#include <string>
namespace Encryption {
class verimatrixData {
public:
void read(const char * shmPage);
void write(char * shmPage);
std::string url;
std::string name;
std::string key;
std::string keyid;
std::string keyseed;
std::string laurl;
std::string lauurl;
namespace Encryption{
class verimatrixData{
public:
void read(const char *shmPage);
void write(char *shmPage);
std::string url;
std::string name;
std::string key;
std::string keyid;
std::string keyseed;
std::string laurl;
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 char * data, int dataLen, const char * key, const char * 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);
//These functions are dangerous for your data
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);
// These functions are dangerous for your data
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);
std::string PR_GenerateContentKey(std::string & keyseed, std::string & keyid);
std::string PR_GuidToByteArray(std::string & guid);
std::string PR_GenerateContentKey(std::string &keyseed, std::string &keyid);
std::string PR_GuidToByteArray(std::string &guid);
void encryptPlayReady(DTSC::Packet & pack, std::string & codec, const char * iVec, const char * key);
void encryptPlayReady(DTSC::Packet &pack, std::string &codec, const char *iVec, const char *key);
void fillVerimatrix(verimatrixData & vmData);
}
void fillVerimatrix(verimatrixData &vmData);
}// namespace Encryption

View file

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

View file

@ -18,8 +18,7 @@ namespace FLV{
extern char Header[13]; ///< Holds the last FLV header parsed.
extern bool Parse_Error; ///< This variable is set to true if a problem is encountered while
///< parsing the FLV.
extern std::string
Error_Str; ///< This variable is set if a problem is encountered while parsing the FLV.
extern std::string Error_Str; ///< This variable is set if a problem is encountered while parsing the FLV.
// functions
bool check_header(char *header); ///< Checks a FLV Header for validness.
@ -43,10 +42,9 @@ namespace FLV{
void tagTime(uint64_t T);
int64_t offset();
void offset(int64_t o);
Tag(); ///< Constructor for a new, empty, tag.
Tag(const Tag &O); ///< Copy constructor, copies the contents of an existing tag.
Tag &
operator=(const Tag &O); ///< Assignment operator - works exactly like the copy constructor.
Tag(); ///< Constructor for a new, empty, tag.
Tag(const Tag &O); ///< Copy constructor, copies the contents of an existing tag.
Tag &operator=(const Tag &O); ///< Assignment operator - works exactly like the copy constructor.
Tag(const RTMPStream::Chunk &O); ///< Copy constructor from a RTMP chunk.
~Tag(); ///< Generic destructor.
// loader functions
@ -76,4 +74,3 @@ namespace FLV{
// Tag
}// namespace FLV

View file

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

View file

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

View file

@ -1,6 +1,6 @@
#include "h265.h"
#include "bitfields.h"
#include "defines.h"
#include "h265.h"
namespace h265{
const char *typeToStr(uint8_t type){
@ -64,8 +64,7 @@ namespace h265{
hvccBox.setPayload(hvccData);
std::deque<MP4::HVCCArrayEntry> arrays = hvccBox.getArrays();
for (std::deque<MP4::HVCCArrayEntry>::iterator it = arrays.begin(); it != arrays.end(); it++){
for (std::deque<std::string>::iterator nalIt = it->nalUnits.begin();
nalIt != it->nalUnits.end(); nalIt++){
for (std::deque<std::string>::iterator nalIt = it->nalUnits.begin(); nalIt != it->nalUnits.end(); nalIt++){
nalUnits[it->nalUnitType].insert(*nalIt);
}
}
@ -156,8 +155,7 @@ namespace h265{
metaInfo initData::getMeta(){
metaInfo res;
if (!nalUnits.count(33)){
return res;}
if (!nalUnits.count(33)){return res;}
spsUnit sps(*nalUnits[33].begin());
sps.getMeta(res);
return res;
@ -195,8 +193,7 @@ namespace h265{
}
}
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned int maxSubLayersMinus1,
size_t indent){
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned int maxSubLayersMinus1, size_t indent){
std::stringstream r;
r << std::string(indent, ' ') << "general_profile_space: " << bs.get(2) << 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;
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_non_packed_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_non_packed_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_level_idc: " << bs.get(8) << std::endl;
std::deque<bool> profilePresent;
@ -226,8 +221,7 @@ namespace h265{
if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){
r << std::string(indent + 1, ' ') << "reserved_zero_2_bits[" << i << "]: " << bs.get(2)
<< std::endl;
r << std::string(indent + 1, ' ') << "reserved_zero_2_bits[" << i << "]: " << bs.get(2) << std::endl;
}
}
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_compatibility_flags: " << std::hex
<< bs.get(32) << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_interlaced_source_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_non_packed_constraint_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_frame_only_constraint_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_reserved_zero_44bits: " << bs.get(44)
<< std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_interlaced_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_non_packed_constraint_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_frame_only_constraint_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_reserved_zero_44bits: " << bs.get(44) << std::endl;
}
if (levelPresent[i]){
r << std::string(indent + 2, ' ') << "sub_layer_level_idc: " << bs.get(8) << std::endl;
@ -256,17 +245,13 @@ namespace h265{
return r.str();
}
void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox,
unsigned int maxSubLayersMinus1){
void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox, unsigned int maxSubLayersMinus1){
hvccBox.setGeneralProfileSpace(bs.get(2));
unsigned int tierFlag = bs.get(1);
hvccBox.setGeneralProfileIdc(
std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5)));
hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() &
bs.get(32));
hvccBox.setGeneralConstraintIndicatorFlags(hvccBox.getGeneralConstraintIndicatorFlags() &
bs.get(48));
hvccBox.setGeneralProfileIdc(std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5)));
hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() & bs.get(32));
hvccBox.setGeneralConstraintIndicatorFlags(hvccBox.getGeneralConstraintIndicatorFlags() & bs.get(48));
unsigned int levelIdc = bs.get(8);
if (tierFlag && !hvccBox.getGeneralTierFlag()){
@ -309,8 +294,7 @@ namespace h265{
unsigned int maxSubLayers = bs.get(3) + 1;
hvccBox.setNumberOfTemporalLayers(
std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
bs.skip(17);
@ -326,8 +310,7 @@ namespace h265{
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;
unsigned int maxSubLayersMinus1 = bs.get(3);
r << std::string(indent, ' ') << "vps_max_sub_layers_minus1: " << maxSubLayersMinus1
<< std::endl;
r << std::string(indent, ' ') << "vps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl;
r << std::string(indent, ' ') << "vps_temporal_id_nesting_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "vps_reserved_0xffff_16bits: " << std::hex << bs.get(16)
<< std::dec << std::endl;
@ -347,8 +330,7 @@ namespace h265{
unsigned int vps_max_layer_id = bs.get(6);
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_num_layer_sets_minus1: " << vps_num_layer_sets_minus1
<< std::endl;
r << std::string(indent, ' ') << "vps_num_layer_sets_minus1: " << vps_num_layer_sets_minus1 << std::endl;
for (int i = 1; i <= vps_num_layer_sets_minus1; i++){
for (int j = 0; j < vps_max_layer_id; j++){
r << std::string(indent, ' ') << "layer_id_included_flag[" << i << "][" << j
@ -356,8 +338,7 @@ namespace h265{
}
}
bool vps_timing_info = bs.get(1);
r << std::string(indent, ' ') << "vps_timing_info_present_flag: " << (vps_timing_info ? 1 : 0)
<< std::endl;
r << std::string(indent, ' ') << "vps_timing_info_present_flag: " << (vps_timing_info ? 1 : 0) << std::endl;
return r.str();
}
@ -420,15 +401,14 @@ namespace h265{
deltaIdxMinus1 = bs.getUExpGolomb();
r << std::string(indent, ' ') << "delta_idx_minus_1: " << deltaIdxMinus1 << std::endl;
}
r << std::string(indent, ' ')
<< "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, ' ') << "delta_rps_sign: " << (int)bs.get(1) << std::endl;
r << std::string(indent, ' ') << "abs_delta_rps_minus1: " << bs.getUExpGolomb() << std::endl;
uint64_t refRpsIdx = idx - deltaIdxMinus1 - 1;
uint64_t deltaPocs = negativePics[refRpsIdx] + positivePics[refRpsIdx];
for (int j = 0; j < deltaPocs; j++){
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){
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::stringstream r;
bool aspectRatio = bs.get(1);
r << std::string(indent, ' ') << "aspect_ratio_info_present_flag: " << (aspectRatio ? 1 : 0)
<< std::endl;
r << std::string(indent, ' ') << "aspect_ratio_info_present_flag: " << (aspectRatio ? 1 : 0) << std::endl;
if (aspectRatio){
uint16_t aspectRatioIdc = bs.get(8);
r << std::string(indent, ' ') << "aspect_ratio_idc: " << aspectRatioIdc << std::endl;
@ -595,39 +574,29 @@ namespace h265{
std::stringstream r;
r << std::string(indent, ' ') << "sps_video_parameter_set_id: " << bs.get(4) << std::endl;
unsigned int maxSubLayersMinus1 = bs.get(3);
r << std::string(indent, ' ') << "sps_max_sub_layers_minus1: " << maxSubLayersMinus1
<< std::endl;
r << std::string(indent, ' ') << "sps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl;
r << std::string(indent, ' ') << "sps_temporal_id_nesting_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl
<< printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1);
r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb() << std::endl;
uint64_t chromaFormatIdc = bs.getUExpGolomb();
r << std::string(indent, ' ') << "chroma_format_idc: " << chromaFormatIdc << std::endl;
if (chromaFormatIdc == 3){
r << std::string(indent, ' ') << "separate_colour_plane_flag: " << bs.get(1) << std::endl;
}
r << std::string(indent, ' ') << "pic_width_in_luma_samples: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "pic_height_in_luma_samples: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "pic_width_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);
r << std::string(indent, ' ') << "conformance_window_flag: " << conformance_window_flag
<< std::endl;
r << std::string(indent, ' ') << "conformance_window_flag: " << conformance_window_flag << std::endl;
if (conformance_window_flag){
r << std::string(indent, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "conf_window_right_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, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "conf_window_right_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_chroma_minus8: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb() << std::endl;
bool subLayerOrdering = bs.get(1);
r << std::string(indent, ' ')
<< "sps_sub_layer_ordering_info_present_flag: " << subLayerOrdering << std::endl;
@ -647,23 +616,18 @@ namespace h265{
<< std::endl;
r << std::string(indent, ' ')
<< "log2_diff_max_min_transform_block_size: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_intra: " << bs.getUExpGolomb()
<< std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_intra: " << bs.getUExpGolomb() << std::endl;
bool scalingListEnabled = bs.get(1);
r << std::string(indent, ' ') << "scaling_list_enabled_flag: " << scalingListEnabled
<< std::endl;
r << std::string(indent, ' ') << "scaling_list_enabled_flag: " << scalingListEnabled << std::endl;
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, ' ') << "sample_adaptive_offset_enabled_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent, ' ') << "sample_adaptive_offset_enabled_flag: " << bs.get(1) << std::endl;
bool pcmEnabled = bs.get(1);
r << std::string(indent, ' ') << "pcm_enabled_flag: " << pcmEnabled << std::endl;
if (pcmEnabled){WARN_MSG("Not implemented pcm_enabled in HEVC sps");}
uint64_t shortTermPicSets = bs.getUExpGolomb();
r << std::string(indent, ' ') << "num_short_term_ref_pic_sets: " << shortTermPicSets
<< std::endl;
r << std::string(indent, ' ') << "num_short_term_ref_pic_sets: " << shortTermPicSets << std::endl;
for (int i = 0; i < shortTermPicSets; i++){
r << std::string(indent, ' ') << "short_term_ref_pic_set(" << i << "):" << std::endl
<< printShortTermRefPicSet(bs, i, shortTermPicSets, indent + 1);
@ -673,12 +637,10 @@ namespace h265{
<< "long_term_ref_pics_present_flag: " << (longTermRefPics ? 1 : 0) << std::endl;
if (longTermRefPics){WARN_MSG("Implement longTermRefPics");}
r << std::string(indent, ' ') << "sps_temporal_mvp_enabled_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "strong_intra_smoothing_enabled_flag: " << bs.get(1)
<< std::endl;
r << std::string(indent, ' ') << "strong_intra_smoothing_enabled_flag: " << bs.get(1) << std::endl;
bool vuiParams = bs.get(1);
r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0)
<< std::endl;
r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0) << std::endl;
if (vuiParams){
r << std::string(indent, ' ') << "vui_parameters:" << std::endl
<< printVuiParameters(bs, indent + 1);
@ -694,8 +656,7 @@ namespace h265{
unsigned int maxSubLayers = bs.get(3) + 1;
hvccBox.setNumberOfTemporalLayers(
std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
hvccBox.setTemporalIdNested(bs.get(1));
updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1);
@ -858,8 +819,7 @@ namespace h265{
if (bs.get(1)){
bs.skip(3);
int spatialSegmentIdc = bs.getUExpGolomb();
hvccBox.setMinSpatialSegmentationIdc(
std::min((int)hvccBox.getMinSpatialSegmentationIdc(), spatialSegmentIdc));
hvccBox.setMinSpatialSegmentationIdc(std::min((int)hvccBox.getMinSpatialSegmentationIdc(), spatialSegmentIdc));
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
@ -868,4 +828,3 @@ namespace h265{
}
}
}// namespace h265

View file

@ -13,10 +13,8 @@ namespace h265{
const char *typeToStr(uint8_t type);
bool isKeyframe(const char *data, uint32_t len);
void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox,
unsigned long maxSubLayersMinus1);
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned long maxSubLayersMinus1,
size_t indent);
void updateProfileTierLevel(Utils::bitstream &bs, MP4::HVCC &hvccBox, unsigned long maxSubLayersMinus1);
std::string printProfileTierLevel(Utils::bitstream &bs, unsigned long maxSubLayersMinus1, size_t indent);
struct metaInfo{
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
// 0 for 'unknown'
}// namespace h265

View file

@ -8,8 +8,8 @@
#include "timing.h"
#include "url.h"
#include "util.h"
#include <strings.h>
#include <iomanip>
#include <strings.h>
/// This constructor creates an empty HTTP::Parser, ready for use for either reading or writing.
/// 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);
}
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?
if (allAtOnce){
/// \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";
if (reqbodyLen){
builder += std::string((char*)reqbody, reqbodyLen);
builder += std::string((char *)reqbody, reqbodyLen);
}else{
builder += body;
}
@ -203,7 +204,7 @@ void HTTP::Parser::sendRequest(Socket::Connection &conn, const void * reqbody, c
}
conn.SendNow("\r\n", 2);
if (reqbodyLen){
conn.SendNow((char*)reqbody, reqbodyLen);
conn.SendNow((char *)reqbody, reqbodyLen);
}else{
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);}
for (std::map<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it){
if (it->first.length() != i.length()){continue;}
if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){
return it->second;
}
if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){return it->second;}
}
//Return empty string if not found
// Return empty string if not found
static const std::string empty;
return empty;
}
@ -435,9 +434,7 @@ bool HTTP::Parser::hasHeader(const std::string &i) const{
if (headers.count(i)){return true;}
for (std::map<std::string, std::string>::const_iterator it = headers.begin(); it != headers.end(); ++it){
if (it->first.length() != i.length()){continue;}
if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){
return true;
}
if (strncasecmp(it->first.c_str(), i.c_str(), i.length()) == 0){return true;}
}
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
/// 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){
//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()){
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;
}else{
if (protocol.substr(0, 4) == "RTSP" || method.substr(0,4) == "RTSP"){
return true;
}
if (protocol.substr(0, 4) == "RTSP" || method.substr(0, 4) == "RTSP"){return true;}
unsigned int toappend = HTTPbuffer.size();
bool shouldAppend = true;
if (bodyCallback){

View file

@ -39,7 +39,8 @@ namespace HTTP{
std::string &BuildResponse();
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 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 StartResponse(std::string code, std::string message, Parser &request,
Socket::Connection &conn, bool bufferAllChunks = false);

View file

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

View file

@ -159,4 +159,3 @@ namespace JSON{
#define jsonForEach(val, i) for (JSON::Iter i(val); i; ++i)
#define jsonForEachConst(val, i) for (JSON::ConstIter i(val); i; ++i)
}// namespace JSON

View file

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

View file

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

File diff suppressed because it is too large Load diff

227
lib/mp4.h
View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -42,4 +42,3 @@ namespace Mpeg{
void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo);
MPEG2Info parseMPEG2Headers(const char *hdr, uint32_t len);
}// namespace Mpeg

View file

@ -34,8 +34,7 @@ namespace nalu{
size_t dataLen = data.size();
size_t resPtr = 2;
while (dataPtr + 2 < dataLen){
if (!data[dataPtr] && !data[dataPtr + 1] &&
data[dataPtr + 2] == 3){// We have found an emulation prevention
if (!data[dataPtr] && !data[dataPtr + 1] && data[dataPtr + 2] == 3){// We have found an emulation prevention
result[resPtr++] = data[dataPtr++];
result[resPtr++] = data[dataPtr++];
dataPtr++; // Skip the emulation prevention byte
@ -129,4 +128,3 @@ namespace nalu{
return newOffset;
}
}// namespace nalu

View file

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

View file

@ -1,13 +1,13 @@
#include "ogg.h"
#include "bitstream.h"
#include "defines.h"
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include "ogg.h"
#include <arpa/inet.h>
#include <iomanip>
#include "bitstream.h"
#include <sstream>
#include <stdlib.h>
#include <string.h>
namespace OGG {
namespace OGG{
oggSegment::oggSegment(){
isKeyframe = 0;
@ -16,21 +16,17 @@ namespace OGG {
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;
res.push_back(0);
for (unsigned int i = 0; i < len; i++){
*res.rbegin() += data[i];
if (data[i] != 0xFF){
res.push_back(0);
}
}
if (*res.rbegin() == 0){
res.resize(res.size() - 1);
if (data[i] != 0xFF){res.push_back(0);}
}
if (*res.rbegin() == 0){res.resize(res.size() - 1);}
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;
for (int i = 7; i >= 0; --i){
temp <<= 8;
@ -39,7 +35,7 @@ namespace OGG {
return temp;
}
inline long unsigned int get_32(char * data){
inline long unsigned int get_32(char *data){
long unsigned int temp = 0;
for (int i = 3; i >= 0; --i){
temp <<= 8;
@ -48,22 +44,20 @@ namespace OGG {
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){
data[i] = val & 0xFF;
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){
data[i] = val & 0xFF;
val >>= 8;
}
}
Page::Page(){
framesSeen = 0;
lastKeyFrame = 0;
@ -74,66 +68,60 @@ namespace OGG {
memset(data, 0, 282);
}
Page::Page(const Page & rhs){
framesSeen=rhs.framesSeen;
Page::Page(const Page &rhs){
framesSeen = rhs.framesSeen;
pageSequenceNumber = rhs.pageSequenceNumber;
lastKeyFrame = rhs.lastKeyFrame;
sampleRate = rhs.sampleRate;
firstSample = rhs.firstSample;
totalFrames= rhs.totalFrames;
totalFrames = rhs.totalFrames;
memcpy(data, rhs.data, 282);
segments = rhs.segments;
}
void Page::operator = (const Page & rhs){
framesSeen=rhs.framesSeen;
void Page::operator=(const Page &rhs){
framesSeen = rhs.framesSeen;
pageSequenceNumber = rhs.pageSequenceNumber;
lastKeyFrame = rhs.lastKeyFrame;
firstSample = rhs.firstSample;
sampleRate = rhs.sampleRate;
totalFrames= rhs.totalFrames;
totalFrames = rhs.totalFrames;
memcpy(data, rhs.data, 282);
segments = rhs.segments;
}
unsigned int Page::calcPayloadSize(){
unsigned int retVal = 0;
for (unsigned int i = 0; i < segments.size(); i++){
retVal += segments[i].size();
}
for (unsigned int i = 0; i < segments.size(); i++){retVal += segments[i].size();}
return retVal;
}
/// 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 total = 0;
segments.clear();
if (newData.size() < 27){
return false;
}
if (newData.size() < 27){return false;}
if (newData.substr(0, 4) != "OggS"){
FAIL_MSG("Invalid Ogg page encountered (magic number wrong: %s) - cannot continue", newData.c_str());
return false;
}
memcpy(data, newData.c_str(), 27);//copying the header, always 27 bytes
if (newData.size() < 27u + getPageSegments()){ //check input size
memcpy(data, newData.c_str(), 27); // copying the header, always 27 bytes
if (newData.size() < 27u + getPageSegments()){// check input size
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());
for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
total += *it;
}
total += 27;
//return false if the segment is not complete
// return false if the segment is not complete
total += getPageSegments();
if(total >= len){
return false;
}
if (total >= len){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++){
segments.push_back(std::string(newData.data(), *it));
newData.erase(0, *it);
@ -143,11 +131,10 @@ namespace OGG {
return true;
}
bool Page::read(FILE * inFile){
bool Page::read(FILE *inFile){
segments.clear();
int oriPos = ftell(inFile);
//INFO_MSG("pos: %d", oriPos);
// INFO_MSG("pos: %d", oriPos);
if (!fread(data, 27, 1, inFile)){
fseek(inFile, oriPos, SEEK_SET);
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());
for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
if (*it){
char * thisSeg = (char *)malloc(*it * sizeof(char));
if (!thisSeg){
WARN_MSG("malloc failed");
}
char *thisSeg = (char *)malloc(*it * sizeof(char));
if (!thisSeg){WARN_MSG("malloc failed");}
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);
return false;
}
@ -179,13 +165,12 @@ namespace OGG {
}else{
segments.push_back(std::string("", 0));
}
}
return true;
}
bool Page::getSegment(unsigned int index, std::string & ret){
bool Page::getSegment(unsigned int index, std::string &ret){
if (index >= segments.size()){
ret.clear();
return false;
@ -194,94 +179,60 @@ namespace OGG {
return true;
}
const char * Page::getSegment(unsigned int index){
if (index >= segments.size()){
return 0;
}
const char *Page::getSegment(unsigned int index){
if (index >= segments.size()){return 0;}
return segments[index].data();
}
unsigned long Page::getSegmentLen(unsigned int index){
if (index >= segments.size()){
return 0;
}
if (index >= segments.size()){return 0;}
return segments[index].size();
}
void Page::setMagicNumber(){
memcpy(data, "OggS", 4);
}
void Page::setMagicNumber(){memcpy(data, "OggS", 4);}
char Page::getVersion(){
return data[4];
}
char Page::getVersion(){return data[4];}
void Page::setVersion(char newVal){
data[4] = newVal;
}
void Page::setVersion(char newVal){data[4] = newVal;}
char Page::getHeaderType(){
return data[5];
}
char Page::getHeaderType(){return data[5];}
void Page::setHeaderType(char newVal){
data[5] = newVal;
}
void Page::setHeaderType(char newVal){data[5] = newVal;}
long long unsigned int Page::getGranulePosition(){
return get_64(data + 6);
}
long long unsigned int Page::getGranulePosition(){return get_64(data + 6);}
void Page::setGranulePosition(long long unsigned int newVal){
set_64(data + 6, newVal);
}
void Page::setGranulePosition(long long unsigned int newVal){set_64(data + 6, newVal);}
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);
}
void Page::setBitstreamSerialNumber(long unsigned int newVal){
set_32(data + 14, newVal);
}
void Page::setBitstreamSerialNumber(long unsigned int newVal){set_32(data + 14, newVal);}
long unsigned int Page::getPageSequenceNumber(){
return get_32(data + 18);
}
long unsigned int Page::getPageSequenceNumber(){return get_32(data + 18);}
void Page::setPageSequenceNumber(long unsigned int newVal){
set_32(data + 18, newVal);
}
void Page::setPageSequenceNumber(long unsigned int newVal){set_32(data + 18, newVal);}
long unsigned int Page::getCRCChecksum(){
return get_32(data + 22);
}
long unsigned int Page::getCRCChecksum(){return get_32(data + 22);}
void Page::setCRCChecksum(long unsigned int newVal){
set_32(data + 22, newVal);
}
void Page::setCRCChecksum(long unsigned int newVal){set_32(data + 22, newVal);}
char Page::getPageSegments(){
return data[26];
}
char Page::getPageSegments(){return data[26];}
inline void Page::setPageSegments(char newVal){
data[26] = newVal;
}
inline void Page::setPageSegments(char newVal){data[26] = newVal;}
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;
} else {
}else{
return false;
}
}
bool Page::possiblyContinued(){
if (getPageSegments() == 255){
if (data[281] == 255){
return true;
}
if (data[281] == 255){return true;}
}
return false;
}
@ -293,99 +244,65 @@ namespace OGG {
r << std::string(indent + 2, ' ') << "Header type:";
if (!getHeaderType()){
r << " Normal";
} else {
if (getHeaderType() & Continued){
r << " Continued";
}
if (getHeaderType() & BeginOfStream){
r << " BeginOfStream";
}
if (getHeaderType() & EndOfStream){
r << " EndOfStream";
}
}else{
if (getHeaderType() & Continued){r << " Continued";}
if (getHeaderType() & BeginOfStream){r << " BeginOfStream";}
if (getHeaderType() & EndOfStream){r << " EndOfStream";}
}
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, ' ') << "Sequence number: " << getPageSequenceNumber() << std::endl;
r << std::string(indent + 2, ' ') << "Checksum Correct: " << verifyChecksum() << std::endl;
//r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "Checksum Correct: " << verifyChecksum() << 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, ' ') << (int)getPageSegments() << " segments:" << std::endl;
r << std::string(indent + 3, ' ');
for (unsigned int i = 0; i < segments.size(); i++){
r << " " << segments[i].size();
}
for (unsigned int i = 0; i < segments.size(); i++){r << " " << segments[i].size();}
r << std::endl;
return r.str();
}
inline unsigned int crc32(unsigned int crc, const char * data, size_t len){
static const unsigned int table[256] = {
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U,
0x130476DCU, 0x17C56B6BU, 0x1A864DB2U, 0x1E475005U,
0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U,
0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU,
0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U,
0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U,
0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU,
0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U,
0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U,
0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U,
0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU,
0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U,
0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U,
0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU,
0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU,
0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U,
0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U,
0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU,
0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U,
0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U, 0x53DC6066U,
0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU,
0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU,
0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U,
0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U,
0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU,
0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U,
0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U,
0xD5B88683U, 0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU,
0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U,
0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU,
0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U,
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,
inline unsigned int crc32(unsigned int crc, const char *data, size_t len){
static const unsigned int table[256] ={
0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x130476DCU, 0x17C56B6BU, 0x1A864DB2U,
0x1E475005U, 0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, 0x350C9B64U, 0x31CD86D3U,
0x3C8EA00AU, 0x384FBDBDU, 0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, 0x5F15ADACU,
0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U,
0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU,
0x95609039U, 0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, 0xBE2B5B58U, 0xBAEA46EFU,
0xB7A96036U, 0xB3687D81U, 0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0xD4326D90U,
0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, 0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U,
0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, 0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU,
0xEC7DD02DU, 0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0x278206ABU, 0x23431B1CU,
0x2E003DC5U, 0x2AC12072U, 0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, 0x018AEB13U,
0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, 0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU,
0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U,
0x53DC6066U, 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, 0xACA5C697U, 0xA864DB20U,
0xA527FDF9U, 0xA1E6E04EU, 0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0x8AAD2B2FU,
0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU,
0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, 0xF3B06B3BU, 0xF771768CU, 0xFA325055U,
0xFEF34DE2U, 0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0xD5B88683U, 0xD1799B34U,
0xDC3ABDEDU, 0xD8FBA05AU, 0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, 0x7A089632U,
0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, 0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 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,
};
while (len > 0){
@ -396,7 +313,7 @@ namespace OGG {
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 oldChecksum = getCRCChecksum();
@ -417,19 +334,15 @@ namespace OGG {
int Page::getPayloadSize(){
size_t res = 0;
for (unsigned int i = 0; i < segments.size(); i++){
res += segments[i].size();
}
for (unsigned int i = 0; i < segments.size(); i++){res += segments[i].size();}
return res;
}
const std::deque<std::string> & Page::getAllSegments(){
return segments;
}
const std::deque<std::string> &Page::getAllSegments(){return segments;}
void Page::prepareNext(bool continueMe){
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);
}
}
@ -444,27 +357,27 @@ namespace OGG {
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);
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));
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 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;
for (unsigned int i = 0; i < segments.size(); i++){
segAmount = (segments[i].size() / 255) + 1;
if (segAmount + curSegNum > 255){
retVal += ((segAmount - (255 - curSegNum + 1)) * 255) + (segments[i].size() % 255);//calculate the extra bytes that overflow
curSegNum = 255;//making sure the segment numbers are at maximum
} else {
retVal += ((segAmount - (255 - curSegNum + 1)) * 255) +
(segments[i].size() % 255); // calculate the extra bytes that overflow
curSegNum = 255; // making sure the segment numbers are at maximum
}else{
curSegNum += segAmount;
}
}
@ -473,7 +386,7 @@ namespace OGG {
void Page::vorbisStuff(){
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;
long long unsigned int packetType = packet.get(1);
if (packetType == 0){
@ -484,45 +397,38 @@ namespace OGG {
if (prevBlockFlag != -1){
if (curBlockFlag == prevBlockFlag){
curPCMSamples /= 2;
} else {
}else{
curPCMSamples -= (1 << blockSize[0]) / 4 + (1 << blockSize[1]) / 4;
}
}
prevBlockFlag = curBlockFlag;
} else {
ERROR_MSG("Error, Vorbis packet type !=0 actual type: %llu",packetType );
}else{
ERROR_MSG("Error, Vorbis packet type !=0 actual type: %llu", packetType);
}
//add to granule position
// add to granule position
lastKeyFrame += curPCMSamples;
oggSegments.rbegin()->lastKeyFrameSeen = lastKeyFrame;
}
///this calculates the granule position for a DTSC packet
long long unsigned int Page::calculateGranule(oggSegment & currentSegment){
/// this calculates the granule position for a DTSC packet
long long unsigned int Page::calculateGranule(oggSegment &currentSegment){
long long unsigned int tempGranule = 0;
if (codec == OGG::THEORA){
tempGranule = (currentSegment.lastKeyFrameSeen << split) | currentSegment.framesSinceKeyFrame;
} else if (codec == OGG::VORBIS){
}else if (codec == OGG::VORBIS){
tempGranule = currentSegment.lastKeyFrameSeen;
} else if (codec == OGG::OPUS){
tempGranule = currentSegment.timeStamp*48;
}else if (codec == OGG::OPUS){
tempGranule = currentSegment.timeStamp * 48;
}
return tempGranule;
}
bool Page::shouldSend(){
unsigned int totalSegmentSize = 0;
if (!oggSegments.size()){
return false;
}
if (oggSegments.rbegin()->isKeyframe){
return true;
}
if (!oggSegments.size()){return false;}
if (oggSegments.rbegin()->isKeyframe){return true;}
if (codec == OGG::VORBIS){
if (lastKeyFrame - firstSample >= sampleRate){
return true;
}
if (lastKeyFrame - firstSample >= sampleRate){return true;}
}
for (unsigned int i = 0; i < oggSegments.size(); i++){
@ -534,79 +440,75 @@ namespace OGG {
}
///\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()){
HIGH_MSG("!segments.size()");
return;
}
if (codec == OGG::VORBIS){
firstSample = lastKeyFrame;
}
if (codec == OGG::VORBIS){firstSample = lastKeyFrame;}
int temp = 0;
long unsigned int checksum = 0; //reset checksum
long unsigned int checksum = 0; // reset checksum
setCRCChecksum(0);
unsigned int numSegments = oggSegments.size();
int tableIndex = 0;
char tableSize = 0;
//char table[255];
char * table = (char *)malloc(255);
// char table[255];
char *table = (char *)malloc(255);
unsigned int bytesLeft = 0;
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);
//if everything still fits in the table
// if everything still fits in the table
if ((temp + tableIndex + 1) <= 255){
//set the 255 bytes
// set the 255 bytes
memset(table + tableIndex, 255, temp);
//increment tableIndex with 255 byte count
// increment tableIndex with 255 byte count
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);
//update tableSize to be equal to tableIndex
// update tableSize to be equal to tableIndex
tableSize = tableIndex;
bytesLeft = 0;
} else {
//stuff doesn't fit
//set the rest of the table to 255s
}else{
// stuff doesn't fit
// set the rest of the table to 255s
memset(table + tableIndex, 255, (255 - tableIndex));
//table size is full table in use
// table size is full table in use
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;
if (oggSegments[i].dataString.size() == bytesLeft){
bytesLeft = 0; //segment barely fits.
bytesLeft = 0; // segment barely fits.
}
break;
}
}
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;
} else {
}else{
unsigned int tempIndex = numSegments - 1;
if (bytesLeft != 0){
tempIndex = numSegments - 2;
}
if (bytesLeft != 0){tempIndex = numSegments - 2;}
granules = calculateGranule(oggSegments[tempIndex]);
}
} else {
granules = calcGranule; //force granule
}else{
granules = calcGranule; // force granule
}
setGranulePosition(granules);
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, table, tableSize);//calculating the checksum over the segment Table
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, table, tableSize); // calculating the checksum over the segment Table
DONTEVEN_MSG("numSegments: %d", numSegments);
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)){
checksum = crc32(checksum, oggSegments[i].dataString.data(), bytesLeft);
//take only part of this segment
} else { //take the entire segment
// take only part of this segment
}else{// take the entire segment
checksum = crc32(checksum, oggSegments[i].dataString.data(), oggSegments[i].dataString.size());
}
}
@ -617,35 +519,27 @@ namespace OGG {
destination.SendNow(&tableSize, 1);
destination.SendNow(table, tableSize);
for (unsigned int i = 0; i < numSegments; i++){
if (bytesLeft != 0 && ((i + 1) == numSegments)){
destination.SendNow(oggSegments.begin()->dataString.data(), bytesLeft);
oggSegments.begin()->dataString.erase(0, bytesLeft);
setHeaderType(OGG::Continued);//set continuation flag
setHeaderType(OGG::Continued); // set continuation flag
break;
//for loop WILL exit after this.
} else {
// for loop WILL exit after this.
}else{
destination.SendNow(oggSegments.begin()->dataString.data(), oggSegments.begin()->dataString.size());
//this segment WILL be deleted
// this segment WILL be deleted
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++;
setPageSequenceNumber(pageSequenceNumber);
//granule still requires setting!
// granule still requires setting!
free(table);
return;
}
}
}// namespace OGG

242
lib/ogg.h
View file

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

View file

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

View file

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

View file

@ -1,57 +1,54 @@
/// \file procs.cpp
/// Contains generic functions for managing processes.
#include "procs.h"
#include "defines.h"
#include "procs.h"
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
#include <sys/wait.h>
#else
#include <wait.h>
#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 <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<int> Util::Procs::socketList;
bool Util::Procs::handler_set = false;
bool Util::Procs::thread_handler = false;
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.
bool Util::Procs::childRunning(pid_t p) {
bool Util::Procs::childRunning(pid_t p){
int status;
pid_t ret = waitpid(p, &status, WNOHANG);
if (ret == p) {
if (ret == p){
tthread::lock_guard<tthread::mutex> guard(plistMutex);
int exitcode = -1;
if (WIFEXITED(status)) {
if (WIFEXITED(status)){
exitcode = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
}else if (WIFSIGNALED(status)){
exitcode = -WTERMSIG(status);
}
if (plist.count(ret)) {
if (plist.count(ret)){
HIGH_MSG("Process %d fully terminated with code %d", ret, exitcode);
plist.erase(ret);
} else {
}else{
HIGH_MSG("Child process %d exited with code %d", ret, exitcode);
}
return false;
}
if (ret < 0 && errno == EINTR) {
return childRunning(p);
}
if (ret < 0 && errno == EINTR){return childRunning(p);}
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.
/// 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.
void Util::Procs::exit_handler() {
void Util::Procs::exit_handler(){
if (!handler_set){return;}
int waiting = 0;
std::set<pid_t> listcopy;
@ -79,42 +76,39 @@ void Util::Procs::exit_handler() {
reaper_thread = 0;
}
std::set<pid_t>::iterator it;
if (listcopy.empty()) {
return;
}
if (listcopy.empty()){return;}
//wait up to 0.5 second for applications to shut down
while (!listcopy.empty() && waiting <= 25) {
for (it = listcopy.begin(); it != listcopy.end(); it++) {
if (!childRunning(*it)) {
// wait up to 0.5 second for applications to shut down
while (!listcopy.empty() && waiting <= 25){
for (it = listcopy.begin(); it != listcopy.end(); it++){
if (!childRunning(*it)){
listcopy.erase(it);
break;
}
if (!listcopy.empty()) {
if (!listcopy.empty()){
Util::wait(20);
++waiting;
}
}
}
if (listcopy.empty()) {
return;
}
if (listcopy.empty()){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;
//wait up to 10 seconds for applications to shut down
while (!listcopy.empty() && waiting <= 500) {
// wait up to 10 seconds for applications to shut down
while (!listcopy.empty() && waiting <= 500){
bool doWait = true;
for (it = listcopy.begin(); it != listcopy.end(); it++) {
if (!childRunning(*it)) {
for (it = listcopy.begin(); it != listcopy.end(); it++){
if (!childRunning(*it)){
listcopy.erase(it);
doWait = false;
break;
}
}
if (doWait && !listcopy.empty()) {
if (doWait && !listcopy.empty()){
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);
kill(*it, SIGINT);
}
@ -123,14 +117,12 @@ void Util::Procs::exit_handler() {
++waiting;
}
}
if (listcopy.empty()) {
return;
}
if (listcopy.empty()){return;}
ERROR_MSG("Sending SIGKILL to remaining %d children", (int)listcopy.size());
//send sigkill to all remaining
if (!listcopy.empty()) {
for (it = listcopy.begin(); it != listcopy.end(); it++) {
// send sigkill to all remaining
if (!listcopy.empty()){
for (it = listcopy.begin(); it != listcopy.end(); it++){
INFO_MSG("SIGKILL %d", *it);
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());
waiting = 0;
//wait up to 1 second for applications to shut down
while (!listcopy.empty() && waiting <= 50) {
for (it = listcopy.begin(); it != listcopy.end(); it++) {
if (!childRunning(*it)) {
// wait up to 1 second for applications to shut down
while (!listcopy.empty() && waiting <= 50){
for (it = listcopy.begin(); it != listcopy.end(); it++){
if (!childRunning(*it)){
listcopy.erase(it);
break;
}
if (!listcopy.empty()) {
if (!listcopy.empty()){
Util::wait(20);
++waiting;
}
}
}
if (listcopy.empty()) {
return;
}
if (listcopy.empty()){return;}
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.
/// Spawns grim_reaper. exit handler despawns grim_reaper
/// Called by every Start* function.
void Util::Procs::setHandler() {
void Util::Procs::setHandler(){
tthread::lock_guard<tthread::mutex> guard(plistMutex);
if (!handler_set) {
if (!handler_set){
thread_handler = true;
reaper_thread = new tthread::thread(grim_reaper, 0);
struct sigaction new_action;
@ -197,36 +187,34 @@ void Util::Procs::setHandler() {
}
}
///Thread that loops until thread_handler is false.
///Reaps available children and then sleeps for a second.
///Not done in signal handler so we can use a mutex to prevent race conditions.
void Util::Procs::grim_reaper(void * n){
/// Thread that loops until thread_handler is false.
/// Reaps available children and then sleeps for a second.
/// Not done in signal handler so we can use a mutex to prevent race conditions.
void Util::Procs::grim_reaper(void *n){
VERYHIGH_MSG("Grim reaper start");
while (thread_handler){
{
tthread::lock_guard<tthread::mutex> guard(plistMutex);
int status;
pid_t ret = -1;
while (ret != 0) {
while (ret != 0){
ret = waitpid(-1, &status, WNOHANG);
if (ret <= 0) { //ignore, would block otherwise
if (ret == 0 || errno != EINTR) {
break;
}
if (ret <= 0){// ignore, would block otherwise
if (ret == 0 || errno != EINTR){break;}
continue;
}
int exitcode;
if (WIFEXITED(status)) {
if (WIFEXITED(status)){
exitcode = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
}else if (WIFSIGNALED(status)){
exitcode = -WTERMSIG(status);
} else { // not possible
}else{// not possible
break;
}
if (plist.count(ret)) {
if (plist.count(ret)){
HIGH_MSG("Process %d fully terminated with code %d", ret, exitcode);
plist.erase(ret);
} else {
}else{
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.
void Util::Procs::childsig_handler(int signum) {
void Util::Procs::childsig_handler(int signum){
return;
}
/// 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;
int fin = 0, fout = -1, ferr = 0;
pid_t myProc = StartPiped(argv, &fin, &fout, &ferr);
while (childRunning(myProc)) {
Util::sleep(100);
}
FILE * outFile = fdopen(fout, "r");
char * fileBuf = 0;
while (childRunning(myProc)){Util::sleep(100);}
FILE *outFile = fdopen(fout, "r");
char *fileBuf = 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;
}
fclose(outFile);
@ -261,27 +246,24 @@ std::string Util::Procs::getOutputOf(char * const * argv) {
return ret;
}
///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** ret = (char**)malloc((argDeq.size()+1)*sizeof(char*));
for (int i = 0; i<argDeq.size(); i++){
ret[i] = (char*)argDeq[i].c_str();
}
/// 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 **ret = (char **)malloc((argDeq.size() + 1) * sizeof(char *));
for (int i = 0; i < argDeq.size(); i++){ret[i] = (char *)argDeq[i].c_str();}
ret[argDeq.size()] = NULL;
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;
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);
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;
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);
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.
/// \return 0 if process was not started, process PID otherwise.
/// \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 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) {
/// \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 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 pid;
int pipein[2], pipeout[2], pipeerr[2];
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));
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));
if (*fdin == -1) {
if (*fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
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));
if (*fdin == -1) {
if (*fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
if (*fdout == -1) {
if (*fdout == -1){
close(pipeout[0]);
close(pipeout[1]);
}
return 0;
}
int devnull = -1;
if (!fdin || !fdout || !fderr) {
if (!fdin || !fdout || !fderr){
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));
if (*fdin == -1) {
if (*fdin == -1){
close(pipein[0]);
close(pipein[1]);
}
if (*fdout == -1) {
if (*fdout == -1){
close(pipeout[0]);
close(pipeout[1]);
}
if (*fderr == -1) {
if (*fderr == -1){
close(pipeerr[0]);
close(pipeerr[1]);
}
@ -341,55 +323,48 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
}
}
pid = fork();
if (pid == 0) { //child
if (pid == 0){// child
handler_set = false;
//Close all sockets in the socketList
for (std::set<int>::iterator it = Util::Procs::socketList.begin(); it != Util::Procs::socketList.end(); ++it){
// Close all sockets in the socketList
for (std::set<int>::iterator it = Util::Procs::socketList.begin();
it != Util::Procs::socketList.end(); ++it){
close(*it);
}
if (!fdin) {
if (!fdin){
dup2(devnull, STDIN_FILENO);
} else if (*fdin == -1) {
}else if (*fdin == -1){
close(pipein[1]); // close unused write end
dup2(pipein[0], STDIN_FILENO);
close(pipein[0]);
} else if (*fdin != STDIN_FILENO) {
}else if (*fdin != STDIN_FILENO){
dup2(*fdin, STDIN_FILENO);
}
if (!fdout) {
if (!fdout){
dup2(devnull, STDOUT_FILENO);
} else if (*fdout == -1) {
}else if (*fdout == -1){
close(pipeout[0]); // close unused read end
dup2(pipeout[1], STDOUT_FILENO);
close(pipeout[1]);
} else if (*fdout != STDOUT_FILENO) {
}else if (*fdout != STDOUT_FILENO){
dup2(*fdout, STDOUT_FILENO);
}
if (!fderr) {
if (!fderr){
dup2(devnull, STDERR_FILENO);
} else if (*fderr == -1) {
}else if (*fderr == -1){
close(pipeerr[0]); // close unused read end
dup2(pipeerr[1], STDERR_FILENO);
close(pipeerr[1]);
} else if (*fderr != STDERR_FILENO) {
}else if (*fderr != STDERR_FILENO){
dup2(*fderr, STDERR_FILENO);
}
if (fdin && *fdin != -1 && *fdin != STDIN_FILENO) {
close(*fdin);
}
if (fdout && *fdout != -1 && *fdout != STDOUT_FILENO) {
close(*fdout);
}
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);
if (fdin && *fdin != -1 && *fdin != STDIN_FILENO){close(*fdin);}
if (fdout && *fdout != -1 && *fdout != STDOUT_FILENO){close(*fdout);}
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*/
char * trggr = getenv("MIST_TRIGGER");
char *trggr = getenv("MIST_TRIGGER");
if (trggr && strlen(trggr)){
ERROR_MSG("%s trigger failed to execute %s: %s", trggr, argv[0], strerror(errno));
JSON::Value j;
@ -403,42 +378,38 @@ pid_t Util::Procs::StartPiped(const char * const * argv, int * fdin, int * fdout
/*LTS-END*/
ERROR_MSG("execvp failed for process %s, reason: %s", argv[0], strerror(errno));
exit(42);
} else if (pid == -1) {
}else if (pid == -1){
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[1]);
}
if (fdout && *fdout == -1) {
if (fdout && *fdout == -1){
close(pipeout[0]);
close(pipeout[1]);
}
if (fderr && *fderr == -1) {
if (fderr && *fderr == -1){
close(pipeerr[0]);
close(pipeerr[1]);
}
if (devnull != -1) {
close(devnull);
}
if (devnull != -1){close(devnull);}
return 0;
} else { //parent
}else{// parent
{
tthread::lock_guard<tthread::mutex> guard(plistMutex);
plist.insert(pid);
}
HIGH_MSG("Piped process %s started, PID %d", argv[0], pid);
if (devnull != -1) {
close(devnull);
}
if (fdin && *fdin == -1) {
if (devnull != -1){close(devnull);}
if (fdin && *fdin == -1){
close(pipein[0]); // close unused end end
*fdin = pipein[1];
}
if (fdout && *fdout == -1) {
if (fdout && *fdout == -1){
close(pipeout[1]); // close unused write end
*fdout = pipeout[0];
}
if (fderr && *fderr == -1) {
if (fderr && *fderr == -1){
close(pipeerr[1]); // close unused write end
*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.
/// \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);
}
/// Stops the process with this pid, if running.
/// \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);
}
/// (Attempts to) stop all running child processes.
void Util::Procs::StopAll() {
void Util::Procs::StopAll(){
std::set<pid_t> listcopy;
{
tthread::lock_guard<tthread::mutex> guard(plistMutex);
listcopy = plist;
}
std::set<pid_t>::iterator it;
for (it = listcopy.begin(); it != listcopy.end(); it++) {
Stop(*it);
}
for (it = listcopy.begin(); it != listcopy.end(); it++){Stop(*it);}
}
/// Returns the number of active child processes.
int Util::Procs::Count() {
int Util::Procs::Count(){
tthread::lock_guard<tthread::mutex> guard(plistMutex);
return plist.size();
}
/// 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);
return (kill(name, 0) == 0);
}
/// 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);
plist.erase(pid);
}
/// 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);
plist.insert(pid);
}

View file

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

View file

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

View file

@ -10,7 +10,7 @@ namespace RIFF{
class Chunk{
public:
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 std::string getType() const{
if (!p){return "";}
@ -41,7 +41,8 @@ namespace RIFF{
/// WAVE "fmt " class.
class fmt : public Chunk{
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){}
uint16_t getFormat() const;
std::string getCodec() const;
@ -58,7 +59,7 @@ namespace RIFF{
};
/// WAVE fact class.
class fact : public Chunk {
class fact : public Chunk{
public:
static std::string generate(uint32_t samples);
fact(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
@ -67,13 +68,11 @@ namespace RIFF{
};
/// ISFT class. Contains software name.
class ISFT : public Chunk {
class ISFT : public Chunk{
public:
ISFT(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
std::string getSoftware() const;
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
};
}
}// namespace RIFF

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,10 @@
#pragma once
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_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);
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 printInverted(const unsigned int * data, unsigned int len);
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_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);
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 printInverted(const unsigned int *data, unsigned int len);

View file

@ -1,10 +1,10 @@
/// \file rtmpchunks.cpp
/// Holds all code for the RTMPStream namespace.
#include "rtmpchunks.h"
#include "auth.h"
#include "defines.h"
#include "flv_tag.h"
#include "rtmpchunks.h"
#include "timing.h"
std::string RTMPStream::handshake_in; ///< Input for the handshake.
@ -41,13 +41,12 @@ char genuineFMSKey[] ={
0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68
char genuineFPKey[] ={
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65,
0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x50, 0x6c, 0x61,
0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe,
0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d,
0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62
char genuineFPKey[] ={0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65,
0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x50, 0x6c, 0x61,
0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe,
0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d,
0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62
inline uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){
if (scheme == 0){
@ -61,8 +60,7 @@ bool ValidateClientScheme(uint8_t *pBuffer, uint8_t scheme){
uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);
uint8_t pTempBuffer[1536 - 32];
memcpy(pTempBuffer, pBuffer, clientDigestOffset);
memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32,
1536 - clientDigestOffset - 32);
memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32);
char pTempHash[32];
Secure::hmac_sha256bin((char *)pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
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 len Length of the media data, in bytes.
/// \param ts Timestamp of the media data, relative to current system time.
std::string &RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char *data, int len,
unsigned int ts){
std::string &RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char *data, int len, unsigned int ts){
static RTMPStream::Chunk ch;
ch.cs_id = msg_type_id + 42;
ch.timestamp = ts;
@ -353,8 +350,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer &buffer){
// process the rest of the header, for each chunk type
headertype = chunktype & 0xC0;
DONTEVEN_MSG("Parsing RTMP chunk header (%#.2hhX) at offset %#zx", chunktype,
RTMPStream::rec_cnt);
DONTEVEN_MSG("Parsing RTMP chunk header (%#.2hhX) at offset %#zx", chunktype, RTMPStream::rec_cnt);
switch (headertype){
case 0x00:
@ -512,8 +508,7 @@ bool RTMPStream::doHandshake(){
// FIRST 1536 bytes for server response
char pTempBuffer[1504];
memcpy(pTempBuffer, Server, serverDigestOffset);
memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32,
1504 - serverDigestOffset);
memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1504 - serverDigestOffset);
Secure::hmac_sha256bin(pTempBuffer, 1504, genuineFMSKey, 36, (char *)Server + serverDigestOffset);
// SECOND 1536 bytes for server response
@ -523,12 +518,10 @@ bool RTMPStream::doHandshake(){
}else{
char pTempHash[32];
Secure::hmac_sha256bin((char *)Client + keyChallengeIndex, 32, genuineFMSKey, 68, pTempHash);
Secure::hmac_sha256bin((char *)Server + 1536, 1536 - 32, pTempHash, 32,
(char *)Server + 1536 * 2 - 32);
Secure::hmac_sha256bin((char *)Server + 1536, 1536 - 32, pTempHash, 32, (char *)Server + 1536 * 2 - 32);
}
Server[-1] = Version;
RTMPStream::snd_cnt += 3073;
return true;
}

View file

@ -86,4 +86,3 @@ namespace RTMPStream{
/// Does the handshake. Expects handshake_in to be filled, and fills handshake_out.
bool doHandshake();
}// namespace RTMPStream

View file

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

View file

@ -33,8 +33,8 @@ namespace RTP{
class Packet{
private:
bool managed;
char *data; ///< The actual RTP packet that is being sent
uint32_t maxDataLen; ///< Amount of reserved bytes for the packet(s)
char *data; ///< The actual RTP packet that is being sent
uint32_t maxDataLen; ///< Amount of reserved bytes for the packet(s)
int sentPackets;
int sentBytes; // Because ugly is beautiful
public:
@ -65,23 +65,20 @@ namespace RTP{
void sendMPEG2(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
const char *payload, unsigned int payloadlen, unsigned int channel);
void sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
const char *payload, unsigned int payloadlen, unsigned int channel,
std::string codec);
const char *payload, unsigned int payloadlen, unsigned int channel, std::string codec);
void sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata,
void callBack(void *, char *, unsigned int, unsigned int));
void sendRTCP_RR(long long &connectedAt, SDP::Track &sTrk, unsigned int tid,
DTSC::Meta &metadata,
void callBack(void *, char *, unsigned int, unsigned int));
DTSC::Meta &metadata, void callBack(void *, char *, unsigned int, unsigned int));
Packet();
Packet(unsigned int pt, unsigned int seq, unsigned int ts, unsigned int ssr,
unsigned int csrcCount = 0);
Packet(unsigned int pt, unsigned int seq, unsigned int ts, unsigned int ssr, unsigned int csrcCount = 0);
Packet(const Packet &o);
void operator=(const Packet &o);
~Packet();
Packet(const char *dat, unsigned int len);
char *getData();
char *ptr() const { return data; }
char *ptr() const{return data;}
};
/// 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);
std::string spsData; ///< SPS for H264
std::string ppsData; ///< PPS for H264
void handleVP8(uint64_t msTime, const char *buffer, const uint32_t len, bool missed,
bool hasPadding);
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
///< lost. (a partition is basically what's called a slice in H264).
void handleVP8(uint64_t msTime, const char *buffer, const uint32_t len, bool missed, bool hasPadding);
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
///< lost. (a partition is basically what's called a slice in H264).
bool vp8BufferHasKeyframe;
};
}// namespace RTP

View file

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

View file

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

View file

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

View file

@ -13,8 +13,7 @@ namespace SDP{
class Track{
public:
Track();
std::string generateTransport(uint32_t trackNo, const std::string &dest = "",
bool TCPmode = true);
std::string generateTransport(uint32_t trackNo, const std::string &dest = "", bool TCPmode = true);
std::string getParamString(const std::string &param) const;
uint64_t getParamInt(const std::string &param) const;
bool parseTransport(const std::string &transport, const std::string &host,
@ -54,12 +53,12 @@ namespace SDP{
uint32_t getTrackNoForChannel(uint8_t chan);
uint32_t parseSetup(HTTP::Parser &H, const std::string &host, const std::string &source);
void handleIncomingRTP(const uint64_t track, const RTP::Packet &pkt);
public:
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::string mediaDescription(const DTSC::Track &trk);
}// namespace SDP

View file

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

View file

@ -1,14 +1,16 @@
#pragma once
#include <string>
#include "dtsc.h"
#include <map>
#include <set>
#include <string>
#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_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_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.
#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_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{
@ -30,36 +32,31 @@ namespace SDP{
class MediaFormat{
public:
MediaFormat();
std::string getFormatParameterForName(
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
///< returned, otherwise we use the `payloadType` to determine the samplerate or
///< return 0 when we fail to determine to samplerate.
uint32_t getAudioNumChannels()
const; ///< Returns the number of audio channels. When `audioNumChannels` has been set this
///< will be returned, otherwise we use the `payloadType` when it's set to determine
///< the samplerate or we return 0 when we can't determine the number of channels.
uint32_t getAudioBitSize()
const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be
///< returned, othwerise we use the `encodingName` to determine the right
///< `audioBitSize` or 0 when we can't determine the `audioBitSize`
std::string getFormatParameterForName(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
///< returned, otherwise we use the `payloadType` to determine the samplerate or
///< return 0 when we fail to determine to samplerate.
uint32_t
getVideoRate() const; ///< Returns the video time base. When `videoRate` has been set this will
///< be returned, otherwise we use the `encodingName` to determine the
///< right value or 0 when we can't determine the video rate.
getAudioNumChannels() const; ///< Returns the number of audio channels. When `audioNumChannels` has been set this
///< will be returned, otherwise we use the `payloadType` when it's set to determine
///< the samplerate or we return 0 when we can't determine the number of channels.
uint32_t getAudioBitSize() const; ///< Returns the audio bitsize. When `audioBitSize` has been set this will be
///< returned, othwerise we use the `encodingName` to determine the right
///< `audioBitSize` or 0 when we can't determine the `audioBitSize`
uint32_t getVideoRate() const; ///< Returns the video time base. When `videoRate` has been set this will
///< be returned, otherwise we use the `encodingName` to determine the
///< right value or 0 when we can't determine the video rate.
uint32_t getVideoOrAudioRate() const; ///< Returns whichever rate has been set.
uint64_t getPayloadType() const; ///< Returns the `payloadType` member.
int32_t
getPacketizationModeForH264(); ///< When this represents a h264 format this will return the
///< packetization mode when it was provided in the SDP
int32_t getPacketizationModeForH264(); ///< When this represents a h264 format this will return the
///< 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.
operator bool() const;
public:
uint64_t payloadType; ///< The payload type as set in the media line (the <fmt> is -the-
///< payloadType).
uint64_t payloadType; ///< The payload type as set in the media line (the <fmt> is -the-
///< payloadType).
uint64_t associatedPayloadType; ///< From `a=fmtp:<pt> apt=<apt>`; maps this format to another payload type.
int32_t audioSampleRate; ///< Samplerate of the audio type.
int32_t audioNumChannels; ///< Number of audio channels extracted from the `a=fmtp` or set in
@ -72,12 +69,10 @@ namespace SDP{
std::string iceUFrag; ///< From `a=ice-ufrag:<ufrag>, used with WebRTC / STUN.
std::string icePwd; ///< From `a=ice-pwd:<pwd>`, used with WebRTC / STUN
std::string rtpmap; ///< The `a=<rtpmap:...> value; value between brackets.
std::map<std::string, std::string>
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==`
///< */
std::set<std::string>
rtcpFormats; ///< Stores the `fb-val` from the line with `a=rtcp-fb:<fmt> <fb-val>`.
std::map<std::string, std::string> 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==`
///< */
std::set<std::string> rtcpFormats; ///< Stores the `fb-val` from the line with `a=rtcp-fb:<fmt> <fb-val>`.
};
class Media{
@ -85,40 +80,32 @@ namespace SDP{
Media();
bool parseMediaLine(const std::string &sdpLine); ///< Parses `m=` line. Creates a `MediaFormat`
///< entry for each of the found <fmt> values.
bool parseRtpMapLine(
const std::string &sdpLine); ///< Parses `a=rtpmap:` line which contains the some codec
///< specific info. When this line contains the samplerate and
///< number of audio channels they will be extracted.
bool parseRtpMapLine(const std::string &sdpLine); ///< Parses `a=rtpmap:` line which contains the some codec
///< specific info. When this line contains the samplerate and
///< number of audio channels they will be extracted.
bool parseRtspControlLine(const std::string &sdpLine); ///< Parses `a=control:`
bool parseFrameRateLine(const std::string &sdpLine); ///< Parses `a=framerate:`
bool parseFormatParametersLine(const std::string &sdpLine); ///< Parses `a=fmtp:<payload-type>`.
bool parseRtcpFeedbackLine(
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
///< https://tools.ietf.org/html/rfc8122#section-5, used with WebRTC
bool parseRtcpFeedbackLine(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
///< https://tools.ietf.org/html/rfc8122#section-5, used with WebRTC
bool parseSSRCLine(const std::string &sdpLine); ///< Parses `a=ssrc:<ssrc>`.
MediaFormat *getFormatForSdpLine(
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]`.
MediaFormat *getFormatForPayloadType(
uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no
///< format was found for the given payload type. .
MediaFormat *getFormatForEncodingName(
const std::string
&encName); ///< Finds the `MediaFormats in `formats`. Returns NULL when no format was
///< found for the given encoding name. E.g. `VP8`, `VP9`, `H264`
MediaFormat *getFormatForSdpLine(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]`.
MediaFormat *
getFormatForPayloadType(uint64_t &payloadType); ///< Finds the `MediaFormat` in `formats`. Returns NULL when no
///< format was found for the given payload type. .
MediaFormat *getFormatForEncodingName(const std::string &encName); ///< Finds the `MediaFormats in `formats`. Returns NULL when no format was
///< found for the given encoding name. E.g. `VP8`, `VP9`, `H264`
std::vector<SDP::MediaFormat *> getFormatsForEncodingName(const std::string &encName);
std::string getIcePwdForFormat(
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.
uint32_t
getSSRC() const; ///< Returns the first SSRC `a=ssrc:<value>` value found for the media.
std::string getIcePwdForFormat(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.
uint32_t getSSRC() const; ///< Returns the first SSRC `a=ssrc:<value>` value found for the media.
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:
std::string type; ///< The `media` field of the media line: `m=<media> <port> <proto> <fmt>`,
@ -132,9 +119,8 @@ namespace SDP{
std::string setupMethod; ///< From `a=setup:<passive, active, actpass>, used with WebRTC / STUN
std::string fingerprintHash; ///< From `a=fingerprint:<hash> <value>`, e.g. sha-256, used with
///< WebRTC / STUN
std::string
fingerprintValue; ///< From `a=fingerprint:<hash> <value>`, the actual fingerprint, used
///< with WebRTC / STUN, see https://tools.ietf.org/html/rfc8122#section-5
std::string fingerprintValue; ///< From `a=fingerprint:<hash> <value>`, the actual fingerprint, used
///< 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
///< be the same as in the offer.
std::string candidateIP; ///< Used when we generate a WebRTC answer.
@ -144,21 +130,17 @@ namespace SDP{
bool supportsRTCPMux; ///< From `a=rtcp-mux`, indicates if it can mux RTP and RTCP on one
///< transport channel.
bool supportsRTCPReducedSize; ///< From `a=rtcp-rsize`, reduced size RTCP packets.
std::string
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>
///< field(s) from the `m=` line.
std::string 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>
///< field(s) from the `m=` line.
};
class Session{
public:
bool parseSDP(const std::string &sdp);
Media *getMediaForType(
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.
MediaFormat *getMediaFormatByEncodingName(const std::string &mediaType,
const std::string &encodingName);
Media *getMediaForType(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.
MediaFormat *getMediaFormatByEncodingName(const std::string &mediaType, const std::string &encodingName);
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
///< wants to receive or also sent data. */
@ -168,9 +150,8 @@ namespace SDP{
///< stream specific infomration is stored in a `MediaFormat`
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.
std::string
iceUFrag; ///< From `a=ice-ufag`, this property can be session-wide or media specific. Used
///< with WebRTC and STUN when calculating the message-integrity.
std::string iceUFrag; ///< From `a=ice-ufag`, this property can be session-wide or media specific. Used
///< with WebRTC and STUN when calculating the message-integrity.
};
class Answer{
@ -216,5 +197,4 @@ namespace SDP{
uint8_t videoLossPrevention; ///< See the SDP_LOSS_PREVENTION_* values at the top of this header.
};
}
}// namespace SDP

File diff suppressed because it is too large Load diff

View file

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

View file

@ -34,7 +34,7 @@ static const char *addrFam(int f){
}
/// Calls gai_strerror with the given argument, calling regular strerror on the global errno as needed
static const char * gai_strmagic(int errcode){
static const char *gai_strmagic(int errcode){
if (errcode == EAI_SYSTEM){
return strerror(errno);
}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.
/// 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;
socklen_t len = sizeof(tmpaddr);
if (getsockname(fd, (sockaddr *)&tmpaddr, &len)){
return false;
}
if (getsockname(fd, (sockaddr *)&tmpaddr, &len)){return false;}
static char addrconv[INET6_ADDRSTRLEN];
if (tmpaddr.sin6_family == AF_INET6){
host = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN);
@ -480,18 +478,18 @@ void Socket::Buffer::clear(){
}
void Socket::Connection::setBoundAddr(){
//If a bound address was set through environment (e.g. HTTPS output), restore it from there.
char * envbound = getenv("MIST_BOUND_ADDR");
// If a bound address was set through environment (e.g. HTTPS output), restore it from there.
char *envbound = getenv("MIST_BOUND_ADDR");
if (envbound){
boundaddr = envbound;
return;
}
//If we can't read the address, don't try
// If we can't read the address, don't try
if (!isTrueSocket){
boundaddr = "";
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;
getSocketName(getSocket(), boundaddr, boundport);
}
@ -1184,9 +1182,7 @@ void Socket::Connection::setHost(std::string host){
hints.ai_next = NULL;
int s = getaddrinfo(host.c_str(), 0, &hints, &result);
if (s != 0){return;}
if (result){
memcpy(&remoteaddr, result->ai_addr, result->ai_addrlen);
}
if (result){memcpy(&remoteaddr, result->ai_addr, result->ai_addrlen);}
freeaddrinfo(result);
}

View file

@ -44,7 +44,7 @@ namespace Socket{
bool checkTrueSocket(int sock);
std::string resolveHostToBestExternalAddrGuess(const std::string &host, int family = AF_UNSPEC,
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.
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 iwrite(std::string &buffer); ///< Write call that is compatible with std::string.
void setBoundAddr();
protected:
std::string lastErr; ///< Stores last error, if any.
#ifdef SSL
@ -139,10 +140,10 @@ namespace Socket{
bool isAddress(const std::string &addr);
bool isLocal(); ///< Returns true if remote address is a local address.
// buffered i/o methods
bool spool(); ///< Updates the downbufferinternal variables.
bool peek(); ///< Clears the downbuffer and fills it with peek
Buffer &Received(); ///< Returns a reference to the download buffer.
const Buffer &Received() const; ///< Returns a reference to the download buffer.
bool spool(); ///< Updates the downbufferinternal variables.
bool peek(); ///< Clears the downbuffer and fills it with peek
Buffer &Received(); ///< Returns a reference to the download buffer.
const Buffer &Received() const; ///< Returns a reference to the download buffer.
void SendNow(const std::string &data); ///< Will not buffer anything but always send right away. Blocks.
void SendNow(const char *data); ///< Will not buffer anything but always send right away. Blocks.
void SendNow(const char *data,

View file

@ -1,6 +1,6 @@
#include <algorithm>
#include "defines.h"
#include "srtp.h"
#include <algorithm>
/* --------------------------------------- */
@ -8,34 +8,34 @@ static std::string srtp_status_to_string(uint32_t status);
/* --------------------------------------- */
SRTPReader::SRTPReader() {
memset((void*)&session, 0x00, sizeof(session));
memset((void*)&policy, 0x00, sizeof(policy));
SRTPReader::SRTPReader(){
memset((void *)&session, 0x00, sizeof(session));
memset((void *)&policy, 0x00, sizeof(policy));
}
/*
Before initializing the srtp library we shut it down first
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;
srtp_err_status_t status = srtp_err_status_ok;
srtp_profile_t profile;
memset((void*) &profile, 0x00, sizeof(profile));
memset((void *)&profile, 0x00, sizeof(profile));
/* validate input */
if (cipher.empty()) {
if (cipher.empty()){
FAIL_MSG("Given `cipher` is empty.");
r = -1;
goto error;
}
if (key.empty()) {
if (key.empty()){
FAIL_MSG("Given `key` is empty.");
r = -2;
goto error;
}
if (salt.empty()) {
if (salt.empty()){
FAIL_MSG("Given `salt` is empty.");
r = -3;
goto error;
@ -43,27 +43,25 @@ int SRTPReader::init(const std::string& cipher, const std::string& key, const st
/* re-initialize the srtp library. */
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());
r = -1;
goto error;
}
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());
r = -2;
goto error;
}
/* 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;
}
else if ("SRTP_AES128_CM_SHA1_32" == cipher) {
}else if ("SRTP_AES128_CM_SHA1_32" == cipher){
profile = srtp_profile_aes128_cm_sha1_32;
}
else {
}else{
ERROR_MSG("Unsupported SRTP cipher used: %s.", cipher.c_str());
r = -2;
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. */
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());
r = -3;
goto error;
}
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());
r = -4;
goto error;
@ -87,7 +85,7 @@ int SRTPReader::init(const std::string& cipher, const std::string& key, const st
/* set the keying material. */
std::copy(key.begin(), key.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. */
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. */
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());
r = -3;
goto error;
}
error:
if (r < 0) {
shutdown();
}
error:
if (r < 0){shutdown();}
return r;
}
int SRTPReader::shutdown() {
int SRTPReader::shutdown(){
int r = 0;
srtp_err_status_t status = srtp_dealloc(session);
if (srtp_err_status_ok != status) {
ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s", srtp_status_to_string(status).c_str());
if (srtp_err_status_ok != status){
ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s",
srtp_status_to_string(status).c_str());
r -= 5;
}
memset((void*)&policy, 0x00, sizeof(policy));
memset((char*)&session, 0x00, sizeof(session));
memset((void *)&policy, 0x00, sizeof(policy));
memset((char *)&session, 0x00, sizeof(session));
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.");
return -1;
}
if (NULL == nbytes) {
if (NULL == nbytes){
ERROR_MSG("Cannot unprotect the given SRTP, becuase nbytes is NULL.");
return -2;
}
if (0 == (*nbytes)) {
if (0 == (*nbytes)){
ERROR_MSG("Cannot unprotect the given SRTP, because nbytes is 0.");
return -3;
}
if (NULL == policy.key) {
if (NULL == policy.key){
ERROR_MSG("Cannot unprotect the SRTP packet, it seems we're not initialized.");
return -4;
}
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());
return -5;
}
@ -161,30 +158,30 @@ int SRTPReader::unprotectRtp(uint8_t* data, int* nbytes) {
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.");
return -1;
}
if (NULL == nbytes) {
if (NULL == nbytes){
ERROR_MSG("Cannot unprotect the given SRTCP, becuase nbytes is NULL.");
return -2;
}
if (0 == (*nbytes)) {
if (0 == (*nbytes)){
ERROR_MSG("Cannot unprotect the given SRTCP, because nbytes is 0.");
return -3;
}
if (NULL == policy.key) {
if (NULL == policy.key){
ERROR_MSG("Cannot unprotect the SRTCP packet, it seems we're not initialized.");
return -4;
}
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());
return -5;
}
@ -194,34 +191,34 @@ int SRTPReader::unprotectRtcp(uint8_t* data, int* nbytes) {
/* --------------------------------------- */
SRTPWriter::SRTPWriter() {
memset((void*)&session, 0x00, sizeof(session));
memset((void*)&policy, 0x00, sizeof(policy));
SRTPWriter::SRTPWriter(){
memset((void *)&session, 0x00, sizeof(session));
memset((void *)&policy, 0x00, sizeof(policy));
}
/*
Before initializing the srtp library we shut it down first
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;
srtp_err_status_t status = srtp_err_status_ok;
srtp_profile_t profile;
memset((void*)&profile, 0x00, sizeof(profile));
memset((void *)&profile, 0x00, sizeof(profile));
/* validate input */
if (cipher.empty()) {
if (cipher.empty()){
FAIL_MSG("Given `cipher` is empty.");
r = -1;
goto error;
}
if (key.empty()) {
if (key.empty()){
FAIL_MSG("Given `key` is empty.");
r = -2;
goto error;
}
if (salt.empty()) {
if (salt.empty()){
FAIL_MSG("Given `salt` is empty.");
r = -3;
goto error;
@ -229,27 +226,25 @@ int SRTPWriter::init(const std::string& cipher, const std::string& key, const st
/* re-initialize the srtp library. */
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());
r = -1;
goto error;
}
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());
r = -2;
goto error;
}
/* 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;
}
else if ("SRTP_AES128_CM_SHA1_32" == cipher) {
}else if ("SRTP_AES128_CM_SHA1_32" == cipher){
profile = srtp_profile_aes128_cm_sha1_32;
}
else {
}else{
ERROR_MSG("Unsupported SRTP cipher used: %s.", cipher.c_str());
r = -2;
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. */
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());
r = -3;
goto error;
}
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());
r = -4;
goto error;
@ -273,7 +268,7 @@ int SRTPWriter::init(const std::string& cipher, const std::string& key, const st
/* set the keying material. */
std::copy(key.begin(), key.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. */
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. */
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());
r = -3;
goto error;
}
error:
if (r < 0) {
shutdown();
}
error:
if (r < 0){shutdown();}
return r;
}
int SRTPWriter::shutdown() {
int SRTPWriter::shutdown(){
int r = 0;
srtp_err_status_t status = srtp_dealloc(session);
if (srtp_err_status_ok != status) {
ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s", srtp_status_to_string(status).c_str());
if (srtp_err_status_ok != status){
ERROR_MSG("Failed to cleanly shutdown the SRTP session. Status: %s",
srtp_status_to_string(status).c_str());
r -= 5;
}
memset((char*)&policy, 0x00, sizeof(policy));
memset((char*)&session, 0x00, sizeof(session));
memset((char *)&policy, 0x00, sizeof(policy));
memset((char *)&session, 0x00, sizeof(session));
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.");
return -1;
}
if (NULL == nbytes) {
if (NULL == nbytes){
ERROR_MSG("Cannot protect the RTP packet because the given nbytes is NULL.");
return -2;
}
if ((*nbytes) <= 0) {
if ((*nbytes) <= 0){
ERROR_MSG("Cannot protect the RTP packet because the given nbytes has a value <= 0.");
return -3;
}
if (NULL == policy.key) {
if (NULL == policy.key){
ERROR_MSG("Cannot protect the RTP packet because we're not initialized.");
return -4;
}
srtp_err_status_t status = srtp_protect(session, (void*)data, nbytes);
if (srtp_err_status_ok != status) {
srtp_err_status_t status = srtp_protect(session, (void *)data, nbytes);
if (srtp_err_status_ok != status){
ERROR_MSG("Failed to protect the RTP packet. %s.", srtp_status_to_string(status).c_str());
return -5;
}
@ -350,30 +344,30 @@ int SRTPWriter::protectRtp(uint8_t* data, int* nbytes) {
of bytes at the into which libsrtp can write the
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.");
return -1;
}
if (NULL == nbytes) {
if (NULL == nbytes){
ERROR_MSG("Cannot protect the RTCP packet because nbytes is NULL.");
return -2;
}
if ((*nbytes) <= 0) {
if ((*nbytes) <= 0){
ERROR_MSG("Cannot protect the RTCP packet because *nbytes is <= 0.");
return -3;
}
if (NULL == policy.key) {
if (NULL == policy.key){
ERROR_MSG("Not initialized cannot protect the RTCP packet.");
return -4;
}
srtp_err_status_t status = srtp_protect_rtcp(session, (void*)data, nbytes);
if (srtp_err_status_ok != status) {
srtp_err_status_t status = srtp_protect_rtcp(session, (void *)data, nbytes);
if (srtp_err_status_ok != status){
ERROR_MSG("Failed to protect the RTCP packet. %s.", srtp_status_to_string(status).c_str());
return -3;
}
@ -381,41 +375,98 @@ int SRTPWriter::protectRtcp(uint8_t* data, int* nbytes) {
return 0;
}
/* --------------------------------------- */
static std::string srtp_status_to_string(uint32_t status) {
static std::string srtp_status_to_string(uint32_t status){
switch (status) {
case srtp_err_status_ok: { return "srtp_err_status_ok"; }
case srtp_err_status_fail: { return "srtp_err_status_fail"; }
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_dealloc_fail: { return "srtp_err_status_dealloc_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_auth_fail: { return "srtp_err_status_auth_fail"; }
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_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"; }
switch (status){
case srtp_err_status_ok:{
return "srtp_err_status_ok";
}
case srtp_err_status_fail:{
return "srtp_err_status_fail";
}
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_dealloc_fail:{
return "srtp_err_status_dealloc_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_auth_fail:{
return "srtp_err_status_auth_fail";
}
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_replay_old:{
return "srtp_err_status_replay_old";
}
case srtp_err_status_algo_fail:{
return "srtp_err_status_algo_fail";
}
case srtp_err_status_no_such_op:{
return "srtp_err_status_no_such_op";
}
case srtp_err_status_no_ctx:{
return "srtp_err_status_no_ctx";
}
case srtp_err_status_cant_check:{
return "srtp_err_status_cant_check";
}
case srtp_err_status_key_expired:{
return "srtp_err_status_key_expired";
}
case srtp_err_status_socket_err:{
return "srtp_err_status_socket_err";
}
case srtp_err_status_signal_err:{
return "srtp_err_status_signal_err";
}
case srtp_err_status_nonce_bad:{
return "srtp_err_status_nonce_bad";
}
case srtp_err_status_read_fail:{
return "srtp_err_status_read_fail";
}
case srtp_err_status_write_fail:{
return "srtp_err_status_write_fail";
}
case srtp_err_status_parse_err:{
return "srtp_err_status_parse_err";
}
case srtp_err_status_encode_err:{
return "srtp_err_status_encode_err";
}
case srtp_err_status_semaphore_err:{
return "srtp_err_status_semaphore_err";
}
case srtp_err_status_pfkey_err:{
return "srtp_err_status_pfkey_err";
}
case srtp_err_status_bad_mki:{
return "srtp_err_status_bad_mki";
}
case srtp_err_status_pkt_idx_old:{
return "srtp_err_status_pkt_idx_old";
}
case srtp_err_status_pkt_idx_adv:{
return "srtp_err_status_pkt_idx_adv";
}
default:{
return "UNKNOWN";
}
}
}

View file

@ -1,22 +1,22 @@
#pragma once
#include <srtp2/srtp.h>
#include <stdint.h>
#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_LEN (SRTP_PARSER_MASTER_KEY_LEN + SRTP_PARSER_MASTER_SALT_LEN)
#define SRTP_PARSER_MASTER_LEN (SRTP_PARSER_MASTER_KEY_LEN + SRTP_PARSER_MASTER_SALT_LEN)
/* --------------------------------------- */
class SRTPReader {
class SRTPReader{
public:
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 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 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. */
private:
srtp_t session;
@ -26,13 +26,13 @@ private:
/* --------------------------------------- */
class SRTPWriter {
class SRTPWriter{
public:
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 protectRtp(uint8_t* data, int* nbytes);
int protectRtcp(uint8_t* data, int* nbytes);
int protectRtp(uint8_t *data, int *nbytes);
int protectRtcp(uint8_t *data, int *nbytes);
private:
srtp_t session;

View file

@ -1,19 +1,19 @@
/// \file stream.cpp
/// Utilities for handling streams.
#include "stream.h"
#include "config.h"
#include "defines.h"
#include "dtsc.h"
#include "h265.h"
#include "http_parser.h"
#include "json.h"
#include "langcodes.h"
#include "mp4_generic.h"
#include "procs.h"
#include "shared_memory.h"
#include "socket.h"
#include "stream.h"
#include "triggers.h" //LTS
#include "h265.h"
#include "mp4_generic.h"
#include "langcodes.h"
#include "http_parser.h"
#include <semaphore.h>
#include <stdlib.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"){
std::stringstream r;
MP4::AVCC avccBox;
@ -58,10 +58,10 @@ std::string Util::codecString(const std::string & codec, const std::string & ini
std::stringstream r;
r << "hev1.";
switch (mInfo.general_profile_space){
case 0: break;
case 1: r << 'A'; break;
case 2: r << 'B'; break;
case 3: r << 'C'; break;
case 0: break;
case 1: r << 'A'; break;
case 2: r << 'B'; break;
case 3: r << 'C'; break;
}
r << (unsigned long)mInfo.general_profile_idc << '.';
uint32_t mappedFlags = 0;
@ -98,7 +98,11 @@ std::string Util::codecString(const std::string & codec, const std::string & ini
if (mInfo.general_profile_compatflags & 0x40000000ul){mappedFlags += 0x00000002ul;}
if (mInfo.general_profile_compatflags & 0x80000000ul){mappedFlags += 0x00000001ul;}
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;
if (mInfo.constraint_flags[0]){
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.
void Util::streamVariables(std::string &str, const std::string &streamname,
const std::string &source){
void Util::streamVariables(std::string &str, const std::string &streamname, const std::string &source){
replace(str, "$source", source);
replace(str, "$datetime", "$year.$month.$day.$hour.$minute.$second");
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, "$minute", strftime_now("%M"));
replace(str, "$second", strftime_now("%S"));
replace(str, "$wday", strftime_now("%u"));//weekday, 1-7, monday=1
replace(str, "$yday", strftime_now("%j"));//yearday, 001-366
replace(str, "$week", strftime_now("%V"));//week number, 01-53
replace(str, "$wday", strftime_now("%u")); // weekday, 1-7, monday=1
replace(str, "$yday", strftime_now("%j")); // yearday, 001-366
replace(str, "$week", strftime_now("%V")); // week number, 01-53
replace(str, "$stream", streamname);
if (streamname.find('+') != std::string::npos){
std::string strbase = streamname.substr(0, streamname.find('+'));
@ -213,7 +216,9 @@ JSON::Value Util::getStreamConfig(const std::string &streamname){
if (!Util::getGlobalConfig("defaultStream")){
WARN_MSG("Could not get stream '%s' config!", smp.c_str());
}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;
}
@ -233,18 +238,18 @@ JSON::Value Util::getGlobalConfig(const std::string &optionName){
}
Util::RelAccXFieldData dataField = cfgData.getFieldData(optionName);
switch (dataField.type & 0xF0){
case RAX_INT:
case RAX_UINT:
//Integer types, return JSON::Value integer
return JSON::Value(cfgData.getInt(dataField));
case RAX_RAW:
case RAX_STRING:
//String types, return JSON::Value string
return JSON::Value(std::string(cfgData.getPointer(dataField), cfgData.getSize(optionName)));
default:
//Unimplemented types
FAIL_MSG("Global configuration setting for '%s' is not an implemented datatype!", optionName.c_str());
return JSON::Value();
case RAX_INT:
case RAX_UINT:
// Integer types, return JSON::Value integer
return JSON::Value(cfgData.getInt(dataField));
case RAX_RAW:
case RAX_STRING:
// String types, return JSON::Value string
return JSON::Value(std::string(cfgData.getPointer(dataField), cfgData.getSize(optionName)));
default:
// Unimplemented types
FAIL_MSG("Global configuration setting for '%s' is not an implemented datatype!", optionName.c_str());
return JSON::Value();
}
}
@ -447,7 +452,8 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
}
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);
}
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(),
tmp_input.getMember("name").asString().c_str(), source.c_str());
if (tmpFn.substr(0, front.size()) == front &&
tmpFn.substr(tmpFn.size() - back.size()) == back){
if (tmpFn.substr(0, front.size()) == front && tmpFn.substr(tmpFn.size() - back.size()) == back){
if (tmp_input.getMember("non-provider") && !isProvider){
noProviderNoPick = true;
continue;
@ -569,7 +574,7 @@ pid_t Util::startPush(const std::string &streamname, std::string &target){
return 0;
}
//Set original target string in environment
// Set original target string in environment
setenv("MST_ORIG_TARGET", target.c_str(), 1);
// 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};
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);
//Clean up environment
// Clean up environment
unsetenv("MST_ORIG_TARGET");
//Actually return the resulting PID
// Actually return the resulting PID
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.
bool Util::checkException(const JSON::Value & ex, const std::string & useragent){
//No user agent? Always allow everything.
bool Util::checkException(const JSON::Value &ex, const std::string &useragent){
// No user agent? Always allow everything.
if (!useragent.size()){return true;}
if (!ex.isArray() || !ex.size()){return 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;}
bool setTo = false;
bool except = false;
//whitelist makes the return value true if any value is contained in the UA, blacklist makes it 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_except"){setTo = true; except = true;}
if ((*e)[0u].asStringRef() == "blacklist"){setTo = false; except = false;}
if ((*e)[0u].asStringRef() == "blacklist_except"){setTo = false; except = true;}
// whitelist makes the return value true if any value is contained in the UA, blacklist makes it
// 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_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){
ret = setTo;
continue;
@ -658,7 +675,7 @@ bool Util::checkException(const JSON::Value & ex, const std::string & useragent)
jsonForEachConst((*e)[1u], i){
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;}
}
return ret;
@ -679,9 +696,12 @@ DTSC::Scan Util::DTSCShmReader::getScan(){
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;
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){
// Comma-separated list, recurse.
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();
if (trackVal == JSON::Value((uint64_t)trackNo).asString()){
//It's an integer number
// It's an integer number
if (!M.tracks.count(trackNo)){
INFO_MSG("Track %zd does not exist in stream, cannot select", trackNo);
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){
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;
}
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);
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
std::set<size_t> validTracks = getSupportedTracks(M, capa);
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
const DTSC::Track & Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){result.insert(*it);}
const DTSC::Track &Trk = M.tracks.at(*it);
if (!trackType.size() || Trk.type == trackType || Trk.codec == trackType){
result.insert(*it);
}
}
return result;
}
@ -727,7 +751,7 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint32_t currRate = 0;
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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 (currRate < Trk.bps){
currVal = *it;
@ -744,7 +768,7 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint32_t currRate = 0xFFFFFFFFul;
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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 (currRate > Trk.bps){
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);}
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] == '>'){
unsigned int bpsVal;
uint64_t targetBps = 0;
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 (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 (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 (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){
targetBps >>= 3;
// select all tracks of this type that match the requirements
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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 (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;
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){
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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){
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);}
}
@ -795,13 +831,19 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
return result;
}
}
//approx bitrate matching
// approx bitrate matching
{
unsigned int bpsVal;
uint64_t targetBps = 0;
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 (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){
targetBps >>= 3;
// 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;
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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 (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;
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;
}
}
//audio channel matching
// audio channel matching
if (!trackType.size() || trackType == "audio"){
if (trackLow == "surround"){
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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 (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 == "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){
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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 (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;
}
}
//approx resolution matching
// approx resolution matching
if (!trackType.size() || trackType == "video"){
if (trackLow == "highres" || trackLow == "bestres" || trackLow == "maxres"){
// 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;
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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){
uint64_t trackRes = Trk.width*Trk.height;
uint64_t trackRes = Trk.width * Trk.height;
if (currRes < trackRes){
currVal = *it;
currRes = trackRes;
@ -876,9 +921,9 @@ std::set<size_t> Util::findTracks(const DTSC::Meta &M, const JSON::Value &capa,
uint64_t currRes = 0xFFFFFFFFFFFFFFFFull;
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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){
uint64_t trackRes = Trk.width*Trk.height;
uint64_t trackRes = Trk.width * Trk.height;
if (currRes > trackRes){
currVal = *it;
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
size_t currVal = INVALID_TRACK_ID;
uint64_t currDist = 0;
uint64_t targetArea = resX*resY;
uint64_t targetArea = resX * resY;
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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){
uint64_t trackArea = Trk.width*Trk.height;
if (currVal == INVALID_TRACK_ID || (trackArea >= targetArea && currDist > (trackArea-targetArea)) || (trackArea < targetArea && currDist > (targetArea-trackArea))){
uint64_t trackArea = Trk.width * Trk.height;
if (currVal == INVALID_TRACK_ID || (trackArea >= targetArea && currDist > (trackArea - targetArea)) ||
(trackArea < targetArea && currDist > (targetArea - trackArea))){
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;
}
}
}//video track specific
}// video track specific
// attempt to do language/codec matching
// convert 2-character language codes into 3-character language codes
if (trackLow.size() == 2){trackLow = Encodings::ISO639::twoToThree(trackLow);}
std::set<size_t> validTracks = getSupportedTracks(M, capa);
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){
std::string codecLow = Trk.codec;
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 == "5k" && Trk.width == 5120 && Trk.height == 2880){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 (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){
std::set<size_t> validTracks;
for (std::map<unsigned int, DTSC::Track>::const_iterator it = M.tracks.begin(); it != M.tracks.end(); it++){
const DTSC::Track & Trk = it->second;
if (type != "" && type != Trk.type){
continue;
}
const DTSC::Track &Trk = it->second;
if (type != "" && type != Trk.type){continue;}
// Remove tracks for which we don't have codec support
if (capa.isMember("codecs")){
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);
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){
toRemove.insert(*it);
}
@ -1069,29 +1113,27 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
/*LTS-START*/
if (!capa.isMember("codecs")){
for (std::set<size_t>::iterator trit = validTracks.begin(); trit != validTracks.end(); trit++){
const DTSC::Track & Trk = M.tracks.at(*trit);
bool problems = false;
if (capa.isMember("exceptions") && capa["exceptions"].isObject() &&
capa["exceptions"].size()){
jsonForEachConst(capa["exceptions"], ex){
if (ex.key() == "codec:" + Trk.codec){
problems = !Util::checkException(*ex, UA);
break;
}
const DTSC::Track &Trk = M.tracks.at(*trit);
bool problems = false;
if (capa.isMember("exceptions") && capa["exceptions"].isObject() && capa["exceptions"].size()){
jsonForEachConst(capa["exceptions"], ex){
if (ex.key() == "codec:" + Trk.codec){
problems = !Util::checkException(*ex, UA);
break;
}
}
//if (!allowBFrames && M.hasBFrames(*trit)){problems = true;}
if (problems){continue;}
if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelVideo && Trk.type == "video"){continue;}
if (noSelSub && (Trk.type == "subtitle" || Trk.codec == "subtitle")){continue;}
result.insert(*trit);
}
// if (!allowBFrames && M.hasBFrames(*trit)){problems = true;}
if (problems){continue;}
if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelVideo && Trk.type == "video"){continue;}
if (noSelSub && (Trk.type == "subtitle" || Trk.codec == "subtitle")){continue;}
result.insert(*trit);
}
return result;
}
/*LTS-END*/
jsonForEachConst(capa["codecs"], it){
unsigned int selCounter = 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;
}
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)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// user-agent-check
@ -1166,7 +1208,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
++shift;
}
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)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// 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){
for (std::set<size_t>::reverse_iterator trit = validTracks.rbegin();
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)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// 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;}
/*LTS-START*/
if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelVideo && Trk.type == "video"){continue;}
if (noSelSub &&
(Trk.type == "subtitle" || Trk.codec == "subtitle")){
continue;
}
if (noSelSub && (Trk.type == "subtitle" || Trk.codec == "subtitle")){continue;}
/*LTS-END*/
result.insert(*trit);
found = true;
@ -1234,7 +1273,7 @@ std::set<size_t> Util::wouldSelect(const DTSC::Meta &M, const std::map<std::stri
}
}else{
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)) ||
(byType && Trk.type == strRef.substr(shift)) || strRef.substr(shift) == "*"){
// 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;}
/*LTS-START*/
if (noSelAudio && Trk.type == "audio"){continue;}
if (noSelVideo && Trk.type == "video"){continue;}
if (noSelSub &&
(Trk.type == "subtitle" || Trk.type == "subtitle")){
continue;
}
if (noSelSub && (Trk.type == "subtitle" || Trk.type == "subtitle")){continue;}
/*LTS-END*/
result.insert(*trit);
found = true;

View file

@ -2,44 +2,52 @@
/// Utilities for handling streams.
#pragma once
#include <string>
#include "socket.h"
#include "json.h"
#include "dtsc.h"
#include "json.h"
#include "shared_memory.h"
#include "socket.h"
#include "util.h"
#include <string>
const JSON::Value empty;
namespace Util {
void streamVariables(std::string &str, const std::string & streamname, const std::string & source = "");
namespace Util{
void streamVariables(std::string &str, const std::string &streamname, const std::string &source = "");
std::string getTmpFolder();
void sanitizeName(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);
int startPush(const std::string & streamname, std::string & target);
JSON::Value getStreamConfig(const std::string & streamname);
JSON::Value getGlobalConfig(const std::string & optionName);
JSON::Value getInputBySource(const std::string & filename, bool isProvider = false);
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 = "");
void sanitizeName(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);
int startPush(const std::string &streamname, std::string &target);
JSON::Value getStreamConfig(const std::string &streamname);
JSON::Value getGlobalConfig(const std::string &optionName);
JSON::Value getInputBySource(const std::string &filename, bool isProvider = false);
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> 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> 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);
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> 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> 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{
public:
DTSCShmReader(const std::string &pageName);
DTSC::Scan getMember(const std::string &indice);
DTSC::Scan getScan();
private:
IPC::sharedPage rPage;
Util::RelAccX rAcc;
public:
DTSCShmReader(const std::string &pageName);
DTSC::Scan getMember(const std::string &indice);
DTSC::Scan getScan();
private:
IPC::sharedPage rPage;
Util::RelAccX rAcc;
};
}
}// namespace Util

File diff suppressed because it is too large Load diff

View file

@ -1,51 +1,51 @@
#pragma once
#include <stdint.h>
#include <netinet/in.h>
#include <vector>
#include <stdint.h>
#include <string>
#include <vector>
/* --------------------------------------- */
#define STUN_IP4 0x01
#define STUN_IP6 0x02
#define STUN_MSG_TYPE_NONE 0x0000
#define STUN_MSG_TYPE_BINDING_REQUEST 0x0001
#define STUN_MSG_TYPE_NONE 0x0000
#define STUN_MSG_TYPE_BINDING_REQUEST 0x0001
#define STUN_MSG_TYPE_BINDING_RESPONSE_SUCCESS 0x0101
#define STUN_MSG_TYPE_BINDING_RESPONSE_ERROR 0x0111
#define STUN_MSG_TYPE_BINDING_INDICATION 0x0011
#define STUN_MSG_TYPE_BINDING_RESPONSE_ERROR 0x0111
#define STUN_MSG_TYPE_BINDING_INDICATION 0x0011
#define STUN_ATTR_TYPE_NONE 0x0000
#define STUN_ATTR_TYPE_MAPPED_ADDR 0x0001
#define STUN_ATTR_TYPE_CHANGE_REQ 0x0003
#define STUN_ATTR_TYPE_USERNAME 0x0006
#define STUN_ATTR_TYPE_MESSAGE_INTEGRITY 0x0008
#define STUN_ATTR_TYPE_ERR_CODE 0x0009
#define STUN_ATTR_TYPE_UNKNOWN_ATTRIBUTES 0x000a
#define STUN_ATTR_TYPE_CHANNEL_NUMBER 0x000c
#define STUN_ATTR_TYPE_LIFETIME 0x000d
#define STUN_ATTR_TYPE_XOR_PEER_ADDR 0x0012
#define STUN_ATTR_TYPE_DATA 0x0013
#define STUN_ATTR_TYPE_REALM 0x0014
#define STUN_ATTR_TYPE_NONCE 0x0015
#define STUN_ATTR_TYPE_XOR_RELAY_ADDRESS 0x0016
#define STUN_ATTR_TYPE_REQ_ADDRESS_FAMILY 0x0017
#define STUN_ATTR_TYPE_EVEN_PORT 0x0018
#define STUN_ATTR_TYPE_REQUESTED_TRANSPORT 0x0019
#define STUN_ATTR_TYPE_DONT_FRAGMENT 0x001a
#define STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS 0x0020
#define STUN_ATTR_TYPE_RESERVATION_TOKEN 0x0022
#define STUN_ATTR_TYPE_PRIORITY 0x0024
#define STUN_ATTR_TYPE_USE_CANDIDATE 0x0025
#define STUN_ATTR_TYPE_PADDING 0x0026
#define STUN_ATTR_TYPE_RESPONSE_PORT 0x0027
#define STUN_ATTR_TYPE_SOFTWARE 0x8022
#define STUN_ATTR_TYPE_ALTERNATE_SERVER 0x8023
#define STUN_ATTR_TYPE_FINGERPRINT 0x8028
#define STUN_ATTR_TYPE_ICE_CONTROLLED 0x8029
#define STUN_ATTR_TYPE_ICE_CONTROLLING 0x802a
#define STUN_ATTR_TYPE_RESPONSE_ORIGIN 0x802b
#define STUN_ATTR_TYPE_OTHER_ADDRESS 0x802c
#define STUN_ATTR_TYPE_NONE 0x0000
#define STUN_ATTR_TYPE_MAPPED_ADDR 0x0001
#define STUN_ATTR_TYPE_CHANGE_REQ 0x0003
#define STUN_ATTR_TYPE_USERNAME 0x0006
#define STUN_ATTR_TYPE_MESSAGE_INTEGRITY 0x0008
#define STUN_ATTR_TYPE_ERR_CODE 0x0009
#define STUN_ATTR_TYPE_UNKNOWN_ATTRIBUTES 0x000a
#define STUN_ATTR_TYPE_CHANNEL_NUMBER 0x000c
#define STUN_ATTR_TYPE_LIFETIME 0x000d
#define STUN_ATTR_TYPE_XOR_PEER_ADDR 0x0012
#define STUN_ATTR_TYPE_DATA 0x0013
#define STUN_ATTR_TYPE_REALM 0x0014
#define STUN_ATTR_TYPE_NONCE 0x0015
#define STUN_ATTR_TYPE_XOR_RELAY_ADDRESS 0x0016
#define STUN_ATTR_TYPE_REQ_ADDRESS_FAMILY 0x0017
#define STUN_ATTR_TYPE_EVEN_PORT 0x0018
#define STUN_ATTR_TYPE_REQUESTED_TRANSPORT 0x0019
#define STUN_ATTR_TYPE_DONT_FRAGMENT 0x001a
#define STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS 0x0020
#define STUN_ATTR_TYPE_RESERVATION_TOKEN 0x0022
#define STUN_ATTR_TYPE_PRIORITY 0x0024
#define STUN_ATTR_TYPE_USE_CANDIDATE 0x0025
#define STUN_ATTR_TYPE_PADDING 0x0026
#define STUN_ATTR_TYPE_RESPONSE_PORT 0x0027
#define STUN_ATTR_TYPE_SOFTWARE 0x8022
#define STUN_ATTR_TYPE_ALTERNATE_SERVER 0x8023
#define STUN_ATTR_TYPE_FINGERPRINT 0x8028
#define STUN_ATTR_TYPE_ICE_CONTROLLED 0x8029
#define STUN_ATTR_TYPE_ICE_CONTROLLING 0x802a
#define STUN_ATTR_TYPE_RESPONSE_ORIGIN 0x802b
#define STUN_ATTR_TYPE_OTHER_ADDRESS 0x802c
/* --------------------------------------- */
@ -60,7 +60,7 @@ std::string stun_family_type_to_string(uint8_t type);
std::string key: key to use for hmac
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.
@ -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
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.
@ -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.
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 */
class StunAttribSoftware {
class StunAttribSoftware{
public:
char* value;
char *value;
};
class StunAttribFingerprint {
class StunAttribFingerprint{
public:
uint32_t value;
};
/* https://tools.ietf.org/html/rfc5389#section-15.4 */
class StunAttribMessageIntegrity {
class StunAttribMessageIntegrity{
public:
uint8_t* sha1;
uint8_t *sha1;
};
/* https://tools.ietf.org/html/rfc5245#section-19.1 */
class StunAttribPriority {
class StunAttribPriority{
public:
uint32_t value;
};
/* https://tools.ietf.org/html/rfc5245#section-19.1 */
class StunAttribIceControllling {
class StunAttribIceControllling{
public:
uint64_t tie_breaker;
};
/* https://tools.ietf.org/html/rfc3489#section-11.2.6 */
class StunAttribUsername {
class StunAttribUsername{
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 */
class StunAttribXorMappedAddress {
class StunAttribXorMappedAddress{
public:
uint8_t family;
uint16_t port;
@ -127,7 +127,7 @@ public:
/* --------------------------------------- */
class StunAttribute {
class StunAttribute{
public:
StunAttribute();
void print();
@ -135,7 +135,7 @@ public:
public:
uint16_t type;
uint16_t length;
union {
union{
StunAttribXorMappedAddress xor_address;
StunAttribUsername username;
StunAttribIceControllling ice_controlling;
@ -148,15 +148,15 @@ public:
/* --------------------------------------- */
class StunMessage {
class StunMessage{
public:
StunMessage();
void setType(uint16_t type);
void setTransactionId(uint32_t a, uint32_t b, uint32_t c);
void print();
void addAttribute(StunAttribute& attr);
void addAttribute(StunAttribute &attr);
void removeAttributes();
StunAttribute* getAttributeByType(uint16_t type);
StunAttribute *getAttributeByType(uint16_t type);
public:
uint16_t type;
@ -168,19 +168,19 @@ public:
/* --------------------------------------- */
class StunReader {
class StunReader{
public:
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:
int parseXorMappedAddress(StunAttribute& attr);
int parseUsername(StunAttribute& attr);
int parseIceControlling(StunAttribute& attr);
int parsePriority(StunAttribute& attr);
int parseSoftware(StunAttribute& attr);
int parseMessageIntegrity(StunAttribute& attr);
int parseFingerprint(StunAttribute& attr);
int parseXorMappedAddress(StunAttribute &attr);
int parseUsername(StunAttribute &attr);
int parseIceControlling(StunAttribute &attr);
int parsePriority(StunAttribute &attr);
int parseSoftware(StunAttribute &attr);
int parseMessageIntegrity(StunAttribute &attr);
int parseFingerprint(StunAttribute &attr);
uint8_t readU8();
uint16_t readU16();
@ -188,32 +188,35 @@ private:
uint64_t readU64();
private:
uint8_t* buffer_data;
uint8_t *buffer_data;
size_t buffer_size;
size_t read_dx;
};
/* --------------------------------------- */
class StunWriter {
class StunWriter{
public:
StunWriter();
/* 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();
/* write attributes */
int writeXorMappedAddress(sockaddr_in addr);
int writeXorMappedAddress(uint8_t family, uint16_t port, uint32_t ip);
int writeXorMappedAddress(uint8_t family, uint16_t port, const std::string& ip);
int writeUsername(const std::string& username);
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 writeXorMappedAddress(uint8_t family, uint16_t port, const std::string &ip);
int writeUsername(const std::string &username);
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 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 */
uint8_t* getBufferPtr();
uint8_t *getBufferPtr();
size_t getBufferSize();
private:
@ -223,9 +226,9 @@ private:
void writeU64(uint64_t v);
void rewriteU16(size_t dx, uint16_t v);
void rewriteU32(size_t dx, uint32_t v);
void writeString(const std::string& str);
void writeString(const std::string &str);
void writePadding();
int convertIp4StringToInt(const std::string& ip, uint32_t& result);
int convertIp4StringToInt(const std::string &ip, uint32_t &result);
private:
std::vector<uint8_t> buffer;
@ -234,16 +237,14 @@ private:
/* --------------------------------------- */
inline uint8_t* StunWriter::getBufferPtr() {
inline uint8_t *StunWriter::getBufferPtr(){
if (0 == buffer.size()) {
return NULL;
}
if (0 == buffer.size()){return NULL;}
return &buffer[0];
}
inline size_t StunWriter::getBufferSize() {
inline size_t StunWriter::getBufferSize(){
return buffer.size();
}

View file

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

View file

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

View file

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

View file

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

View file

@ -2,18 +2,18 @@
/// Utilities for handling time and timestamps.
#include "timing.h"
#include <sys/time.h>//for gettimeofday
#include <time.h>//for time and nanosleep
#include <cstring>
#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__)
#include <mach/clock.h>
#include <mach/mach.h>
#define CLOCK_REALTIME CALENDAR_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;
mach_timespec_t mts;
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.
/// Can be slightly off (in positive direction only) depending on OS accuracy.
void Util::wait(int64_t ms){
if (ms < 0) {
return;
}
if (ms > 600000) {
ms = 600000;
}
if (ms < 0){return;}
if (ms > 600000){ms = 600000;}
uint64_t start = getMS();
uint64_t now = start;
while (now < start+ms){
sleep(start+ms-now);
while (now < start + ms){
sleep(start + ms - now);
now = getMS();
}
}
@ -49,39 +45,35 @@ void Util::wait(int64_t ms){
/// Will not sleep for longer than 100 seconds (100000ms).
/// Can be interrupted early by a signal, no guarantee of minimum sleep time.
/// Can be slightly off depending on OS accuracy.
void Util::sleep(int64_t ms) {
if (ms < 0) {
return;
}
if (ms > 100000) {
ms = 100000;
}
void Util::sleep(int64_t ms){
if (ms < 0){return;}
if (ms > 100000){ms = 100000;}
struct timespec T;
T.tv_sec = ms / 1000;
T.tv_nsec = 1000000 * (ms % 1000);
nanosleep(&T, 0);
}
uint64_t Util::getNTP() {
uint64_t Util::getNTP(){
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return ((uint64_t)(t.tv_sec + 2208988800ull) << 32) + (t.tv_nsec * 4.2949);
}
/// Gets the current time in milliseconds.
uint64_t Util::getMS() {
uint64_t Util::getMS(){
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return (uint64_t)t.tv_sec * 1000 + t.tv_nsec / 1000000;
}
uint64_t Util::bootSecs() {
uint64_t Util::bootSecs(){
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec;
}
uint64_t Util::bootMS() {
uint64_t Util::bootMS(){
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
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.
uint64_t Util::getMicros() {
uint64_t Util::getMicros(){
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return (uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000;
}
/// Gets the time difference in microseconds.
uint64_t Util::getMicros(uint64_t previous) {
uint64_t Util::getMicros(uint64_t previous){
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return (uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000 - previous;
}
/// Gets the amount of seconds since 01/01/1970.
uint64_t Util::epoch() {
uint64_t Util::epoch(){
return time(0);
}
std::string Util::getUTCString(uint64_t epoch){
if (!epoch){epoch = time(0);}
time_t rawtime = epoch;
struct tm * ptm;
struct tm *ptm;
ptm = gmtime(&rawtime);
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);
}

View file

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

View file

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

View file

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

View file

@ -1,35 +1,37 @@
/// \page triggers Triggers
/// \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.
/// 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
/// POST body.
/// 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
/// standard input.
/// Triggers may be handled by a URL or an executable. If the handler contains ://, a HTTP URL is
/// assumed. Otherwise, an executable is assumed. 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 POST
/// body. 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 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 "defines.h" //for FAIL_MSG and INFO_MSG
#include "bitfields.h" //for strToBool
#include "defines.h" //for FAIL_MSG and INFO_MSG
#include "downloader.h" //for sending http request
#include "procs.h" //for StartPiped
#include "procs.h" //for StartPiped
#include "shared_memory.h"
#include "util.h"
#include "timing.h"
#include "triggers.h"
#include "util.h"
#include <string.h> //for strncmp
namespace Triggers{
static void submitTriggerStat(const std::string trigger, uint64_t millis, bool ok){
JSON::Value j;
j["trigger_stat"]["name"] = trigger;
j["trigger_stat"]["ms"] = Util::bootMS()-millis;
j["trigger_stat"]["ms"] = Util::bootMS() - millis;
j["trigger_stat"]["ok"] = ok;
Socket::UDPConnection uSock;
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 sync If true, handler is executed blocking and uses the response data.
///\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();
if (!value.size()){
WARN_MSG("Trigger requested with empty destination");
@ -58,7 +61,8 @@ namespace Triggers{
submitTriggerStat(trigger, tStartMs, true);
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);
return defaultResponse;
}else{// send payload to stdin of newly forked process
@ -90,9 +94,7 @@ namespace Triggers{
Util::sleep(100);
++counter;
if (counter >= 150){
if (counter == 150){
FAIL_MSG("Trigger taking too long - killing process");
}
if (counter == 150){FAIL_MSG("Trigger taking too long - killing process");}
if (counter >= 250){
Util::Procs::Stop(myProc);
}else{
@ -104,7 +106,9 @@ namespace Triggers{
FILE *outFile = fdopen(fdOut, "r");
char *fileBuf = 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);
free(fileBuf);
close(fdOut);
@ -124,14 +128,14 @@ namespace Triggers{
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)
///\param type Trigger event type.
///\param streamName the stream to be handled
///\brief returns true if a trigger of the specified type should be handled for a specified stream
///(, or entire server) \param type Trigger event type. \param streamName the stream to be handled
///\return returns true if so
/// calls doTrigger with dryRun set to true
/// returns true if a trigger of the specified type should be
/// 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();
return doTrigger(type, empty, streamName, true, usually_empty, paramsCB, extraParam);
}
@ -142,7 +146,7 @@ namespace Triggers{
///\param streamName The name of a stream.
///\returns Boolean, false if further processing should be aborted.
/// 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();
return doTrigger(type, payload, streamName, false, usually_empty);
}
@ -158,11 +162,13 @@ namespace Triggers{
/// defined for that trigger event type.
/// 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
///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.
///-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.
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){
/// 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){
// open SHM page for this type:
char thisPageName[NAME_BUFFER_SIZE];
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));
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 bPos = 0;
bool isHandled = !streamName.size();
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 ((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;
}
bPos += stringLen + 4;
}
// no streams explicitly defined for this trigger, return true for all streams.
if (bPos <= 4){
isHandled = true;
}
if (bPos <= 4){isHandled = true;}
if (isHandled && paramsCB){
isHandled = paramsCB(trigs.getPointer("params", i), extraParam);
@ -227,5 +232,4 @@ namespace Triggers{
return retVal;
}
}
}
}// namespace Triggers

View file

@ -5,11 +5,15 @@ namespace Triggers{
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);
std::string handleTrigger(const std::string &triggerType, const std::string &value, const std::string &payload, int sync, const std::string &defaultResponse);
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);
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:
bool shouldTrigger(const std::string & triggerType, 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);
}
bool shouldTrigger(const std::string &triggerType, const std::string &streamName = empty,
bool paramsCB(const char *, const void *) = 0, const void *extraParam = 0);
bool doTrigger(const std::string &triggerType, const std::string &payload = empty,
const std::string &streamName = empty);
}// namespace Triggers

File diff suppressed because it is too large Load diff

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