LTS Commits

This commit is contained in:
Thulinma 2015-04-05 21:38:36 +02:00
parent f24d97b510
commit 4bdbd82f66
72 changed files with 8245 additions and 105 deletions

View file

@ -356,6 +356,11 @@ void DTSC::Stream::cutOneBuffer() {
metadata.tracks[trid].fragments.clear();
}
}
/*LTS-START*/
if (!recordPath.empty()) {
recordPacket(buffers.begin()->second);
}
/*LTS-END*/
deletionCallback(buffers.begin()->first);
buffers.erase(buffers.begin());
}
@ -453,6 +458,35 @@ DTSC::Ring * DTSC::Stream::getRing() {
return new DTSC::Ring(tmp);
}
/*LTS-START*/
/// Sets the recording path and writes the file header in preperation for the recording.
/// If the file cannot be opened the path is assumed to be invalid and an error is written.
void DTSC::Stream::setRecord(std::string path) {
if (path.empty()) {
return;
}
recordFile = new File(path, true);
if (!recordFile) {
DEBUG_MSG(DLVL_ERROR, "Failed to create file: %s", path.c_str());
}
headerRecorded = false;
recordPath = path;
}
/*LTS-END*/
/*LTS-START*/
/// Writes a packet to file, if the header was not yet written it writes that first.
void DTSC::Stream::recordPacket(JSON::Value & packet) {
if (!headerRecorded) {
metadata.moreheader = 0;
std::string header = metadata.toJSON().toPacked();
recordFile->writeHeader(header, true);
headerRecorded = true;
}
recordFile->writePacket(packet);
}
/*LTS-END*/
/// Deletes a given out Ring class from memory and internal Ring list.
/// Checks for NULL pointers and invalid pointers, silently discarding them.
void DTSC::Stream::dropRing(DTSC::Ring * ptr) {
@ -764,16 +798,13 @@ void DTSC::File::seekNext() {
myPack.null();
return;
}
fseek(F, currentPositions.begin()->bytePos, SEEK_SET);
seekPos thisPos = *currentPositions.begin();
fseek(F, thisPos.bytePos, SEEK_SET);
if (reachedEOF()) {
myPack.null();
return;
}
clearerr(F);
if (!metadata.merged) {
seek_time(currentPositions.begin()->seekTime + 1, currentPositions.begin()->trackID);
fseek(F, currentPositions.begin()->bytePos, SEEK_SET);
}
currentPositions.erase(currentPositions.begin());
lastreadpos = ftell(F);
if (fread(buffer, 4, 1, F) != 1) {
@ -786,7 +817,7 @@ void DTSC::File::seekNext() {
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) == 0) {
seek_time(myPack.getTime() + 1, myPack.getTrackId(), true);
seek_time(myPack.getTime(), myPack.getTrackId(), true);
return seekNext();
}
long long unsigned int version = 0;
@ -864,9 +895,12 @@ void DTSC::File::seekNext() {
}
currentPositions.insert(tmpPos);
} else {
seek_time(myPack.getTime() + 1, myPack.getTrackId(), true);
seek_time(myPack.getTime(), myPack.getTrackId(), true);
}
seek_bpos(tempLoc);
}else{
seek_time(thisPos.seekTime, thisPos.trackID);
fseek(F, thisPos.bytePos, SEEK_SET);
}
}
@ -954,9 +988,14 @@ DTSC::Packet & DTSC::File::getPacket() {
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();
/*
if (trackNo == myPack.getTrackId()){
tmpPos.bytePos += myPack.getDataLen();
}
*/
} else {
tmpPos.seekTime = 0;
tmpPos.bytePos = 0;

View file

@ -179,6 +179,26 @@ namespace DTSC {
volatile int playCount;
};
/*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(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 {
@ -270,6 +290,7 @@ namespace DTSC {
std::deque<Key> keys;
std::deque<unsigned long> keySizes;
std::deque<Part> parts;
std::deque<Ivec> ivecs; /*LTS*/
Key & getKey(unsigned int keyNum);
unsigned int timeToKeynum(unsigned int timestamp);
unsigned int timeToFragnum(unsigned int timestamp);
@ -394,6 +415,7 @@ namespace DTSC {
std::string & outPacket(livePos num);
std::string & outHeader();
Ring * getRing();
void setRecord(std::string path); /*LTS*/
unsigned int getTime();
void dropRing(Ring * ptr);
int canSeekms(unsigned int ms);
@ -411,9 +433,13 @@ namespace DTSC {
std::map<int, std::set<livePos> > keyframes;
virtual void addPacket(JSON::Value & newPack);
virtual void addMeta(JSON::Value & newMeta);
void recordPacket(JSON::Value & packet); /*LTS*/
datatype datapointertype;
unsigned int buffercount;
unsigned int buffertime;
std::string recordPath; /*LTS*/
File * recordFile; /*LTS*/
bool headerRecorded; /*LTS*/
std::map<unsigned int, std::string> trackMapping;
virtual void deletionCallback(livePos deleting);
};

View file

@ -790,7 +790,37 @@ namespace DTSC {
}
}
/*LTS-START*/
Ivec::Ivec() {
setIvec(0);
}
Ivec::Ivec(long long int iVec) {
setIvec(iVec);
}
void Ivec::setIvec(long long int iVec) {
Bit::htobll(data, iVec);
}
void Ivec::setIvec(std::string iVec) {
memset(data, 0, 8);
memcpy(data, iVec.data(), std::min(8, (int)iVec.size()));
}
void Ivec::setIvec(char * iVec, int len) {
memset(data, 0, 8);
memcpy(data, iVec, std::min(8, len));
}
long long int Ivec::asInt() {
return Bit::btohll(data);
}
char * Ivec::getData() {
return data;
}
/*LTS-END*/
///\brief Returns the payloadsize of a part
long Part::getSize() {
@ -978,6 +1008,12 @@ namespace DTSC {
Part * tmp = (Part *)trackRef["parts"].asStringRef().data();
parts = std::deque<Part>(tmp, tmp + (trackRef["parts"].asStringRef().size() / 9));
}
/*LTS-START*/
if (trackRef.isMember("ivecs") && trackRef["ivecs"].isString()) {
Ivec * tmp = (Ivec *)trackRef["ivecs"].asString().data();
ivecs = std::deque<Ivec>(tmp, tmp + (trackRef["ivecs"].asString().size() / 8));
}
/*LTS-END*/
trackID = trackRef["trackid"].asInt();
firstms = trackRef["firstms"].asInt();
lastms = trackRef["lastms"].asInt();
@ -1024,6 +1060,14 @@ namespace DTSC {
trackRef.getMember("parts").getString(tmp, tmplen);
parts = std::deque<Part>((Part *)tmp, ((Part *)tmp) + (tmplen / 9));
}
/*LTS-START*/
if (trackRef.getMember("ivecs").getType() == DTSC_STR) {
char * tmp = 0;
unsigned int tmplen = 0;
trackRef.getMember("ivecs").getString(tmp, tmplen);
ivecs = std::deque<Ivec>((Ivec *)tmp, ((Ivec *)tmp) + (tmplen / 8));
}
/*LTS-END*/
trackID = trackRef.getMember("trackid").asInt();
firstms = trackRef.getMember("firstms").asInt();
lastms = trackRef.getMember("lastms").asInt();
@ -1086,6 +1130,13 @@ namespace DTSC {
} else {
newKey.setBpos(0);
}
/*LTS-START
if (pack.isMember("ivec")) {
Ivec newIvec;
newIvec.setIvec((char *)pack["ivec"].asString().data(), 8);
ivecs.push_back(newIvec);
}
LTS-END*/
keys.push_back(newKey);
keySizes.push_back(0);
firstms = keys[0].getTime();
@ -1376,6 +1427,7 @@ namespace DTSC {
result += 11 + (keySizes.size() * 4) + 4;
}
result += parts.size() * 9;
result += (ivecs.size() * 8) + 12; /*LTS*/
if (type == "audio") {
result += 49;
} else if (type == "video") {
@ -1433,6 +1485,13 @@ namespace DTSC {
for (std::deque<Part>::iterator it = parts.begin(); it != parts.end(); it++) {
writePointer(p, it->getData(), 9);
}
/*LTS-START*/
writePointer(p, "\000\005ivecs\002", 8);
writePointer(p, convertInt(ivecs.size() * 8), 4);
for (std::deque<Ivec>::iterator it = ivecs.begin(); it != ivecs.end(); it++) {
writePointer(p, it->getData(), 8);
}
/*LTS-END*/
writePointer(p, "\000\007trackid\001", 10);
writePointer(p, convertLongLong(trackID), 8);
if (missedFrags) {
@ -1503,6 +1562,13 @@ namespace DTSC {
for (std::deque<Part>::iterator it = parts.begin(); it != parts.end(); it++) {
conn.SendNow(it->getData(), 9);
}
/*LTS-START*/
conn.SendNow("\000\005ivecs\002", 8);
conn.SendNow(convertInt(ivecs.size() * 8), 4);
for (std::deque<Ivec>::iterator it = ivecs.begin(); it != ivecs.end(); it++) {
conn.SendNow(it->getData(), 8);
}
/*LTS-END*/
conn.SendNow("\000\007trackid\001", 10);
conn.SendNow(convertLongLong(trackID), 8);
if (missedFrags) {
@ -1643,6 +1709,14 @@ namespace DTSC {
tmp.append(it->getData(), 9);
}
result["parts"] = tmp;
/*LTS-START*/
tmp = "";
tmp.reserve(ivecs.size() * 8);
for (std::deque<Ivec>::iterator it = ivecs.begin(); it != ivecs.end(); it++) {
tmp.append(it->getData(), 8);
}
result["ivecs"] = tmp;
/*LTS-END*/
result["trackid"] = trackID;
result["firstms"] = (long long)firstms;
result["lastms"] = (long long)lastms;

62
lib/encryption.cpp Normal file
View file

@ -0,0 +1,62 @@
#include "encryption.h"
#include "auth.h"
//#include <openssl/aes.h>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <cstdio>
#include <cstdio>
namespace Encryption {
std::string AES_Crypt(const std::string & data, const std::string & key, std::string & ivec) {
unsigned char * outData = (unsigned char *)malloc(data.size() * sizeof(char));
//unsigned int stateNum = 0;
unsigned char stateEcount[16];
unsigned char stateIvec[16];
memset(stateEcount, 0, 16);
memcpy(stateIvec, ivec.c_str(), 8);
memset(stateIvec + 8, 0, 8);
/// \todo Implement this ^_^
//AES_KEY cryptKey;
//if (AES_set_encrypt_key((unsigned char *)key.c_str(), 128, &cryptKey)) {
// abort();
//}
/// \todo loop per 128 bytes....
//AES_ctr128_encrypt((unsigned char *)data.c_str(), outData, data.size(), &cryptKey, stateIvec, stateEcount, &stateNum);
std::string result = std::string((char *)outData, data.size());
free(outData);
return result;
}
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.c_str(), 30);
memcpy(dataBlob+30, keyidBytes.data(), 16);
memcpy(dataBlob+46, keyseed.c_str(), 30);
memcpy(dataBlob+76, keyidBytes.data(), 16);
Secure::sha256bin(dataBlob, 46, keyA);
Secure::sha256bin(dataBlob, 76, keyB);
Secure::sha256bin(dataBlob, 92, keyC);
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);
}
std::string PR_GuidToByteArray(std::string & guid) {
std::string result;
result = guid[3];
result += guid[2];
result += guid[1];
result += guid[0];
result += guid[5];
result += guid[4];
result += guid[7];
result += guid[6];
result += guid.substr(8);
return result;
}
}

8
lib/encryption.h Normal file
View file

@ -0,0 +1,8 @@
#include <string>
namespace Encryption {
std::string AES_Crypt(const std::string & data, const std::string & key, std::string & ivec);
std::string PR_GenerateContentKey(std::string & keyseed, std::string & keyid);
std::string PR_GuidToByteArray(std::string & guid);
}

View file

@ -4,7 +4,9 @@
#include "mp4.h"
#include "mp4_adobe.h"
#include "mp4_ms.h"
#include "mp4_dash.h"
#include "mp4_generic.h"
#include "mp4_encryption.h" // /*LTS*/
#include "json.h"
#include "defines.h"
@ -104,6 +106,7 @@ namespace MP4 {
}
} else if (size == 0) {
fseek(newData, 0, SEEK_END);
return true;
}
DONTEVEN_MSG("skipping size 0x%.8lX", size);
if (fseek(newData, pos + size, SEEK_SET) == 0) {
@ -132,6 +135,10 @@ namespace MP4 {
return false;
}
}
if (size == 0){//no else if, because the extended size MAY be 0...
fseek(newData, 0, SEEK_END);
size = ftell(newData) - pos;
}
fseek(newData, pos, SEEK_SET);
data = (char *)realloc(data, size);
data_size = size;
@ -160,6 +167,9 @@ namespace MP4 {
return false;
}
}
if (size == 0){
size = newData.size();
}
if (newData.size() >= size) {
data = (char *)realloc(data, size);
data_size = size;
@ -243,6 +253,9 @@ namespace MP4 {
case 0x74666864:
return ((TFHD *)this)->toPrettyString(indent);
break;
case 0x68766343:
return ((HVCC *)this)->toPrettyString(indent);
break;
case 0x61766343:
return ((AVCC *)this)->toPrettyString(indent);
break;
@ -252,6 +265,9 @@ namespace MP4 {
case 0x66747970:
return ((FTYP *)this)->toPrettyString(indent);
break;
case 0x73747970:
return ((STYP*)this)->toPrettyString(indent);
break;
case 0x6D6F6F76:
return ((MOOV *)this)->toPrettyString(indent);
break;
@ -344,11 +360,18 @@ namespace MP4 {
break;
case 0x6D703461://mp4a
case 0x656E6361://enca
case 0x61632D33://ac-3
return ((MP4A *)this)->toPrettyString(indent);
break;
case 0x64616333:
return ((DAC3 *)this)->toPrettyString(indent);
break;
case 0x61616320:
return ((AAC *)this)->toPrettyString(indent);
break;
case 0x68657631:
return ((HEV1 *)this)->toPrettyString(indent);
break;
case 0x61766331:
return ((AVC1 *)this)->toPrettyString(indent);
break;
@ -356,6 +379,15 @@ namespace MP4 {
case 0x656E6376://encv
return ((H264 *)this)->toPrettyString(indent);
break;
case 0x6669656C:
return ((FIEL *)this)->toPrettyString(indent);
break;
case 0x74726566:
return ((TREF *)this)->toPrettyString(indent);
break;
case 0x676D6864:
return ((GMHD *)this)->toPrettyString(indent);
break;
case 0x65647473:
return ((EDTS *)this)->toPrettyString(indent);
break;
@ -377,12 +409,36 @@ namespace MP4 {
case 0x75756964:
return ((UUID *)this)->toPrettyString(indent);
break;
case 0x73696478:
return ((SIDX*)this)->toPrettyString(indent);
break;
case 0x74666474:
return ((TFDT*)this)->toPrettyString(indent);
break;
case 0x696F6473:
return ((IODS*)this)->toPrettyString(indent);
break;
/*LTS-START*/
case 0x73696E66:
return ((SINF *)this)->toPrettyString(indent);
break;
case 0x66726D61:
return ((FRMA *)this)->toPrettyString(indent);
break;
case 0x7363686D:
return ((SCHM *)this)->toPrettyString(indent);
break;
case 0x73636869:
return ((SCHI *)this)->toPrettyString(indent);
break;
/*LTS-END*/
default:
break;
}
std::string retval = std::string(indent, ' ') + "Unimplemented pretty-printing for box " + std::string(data + 4, 4) + "\n";
std::stringstream retval;
retval << std::string(indent, ' ') << "Unimplemented pretty-printing for box " << std::string(data + 4, 4) << " (" << ntohl(((int*)data)[0]) << ")\n";
/// \todo Implement hexdump for unimplemented boxes?
return retval;
return retval.str();
}
/// Sets the 8 bits integer at the given index.
@ -804,4 +860,5 @@ namespace MP4 {
}
return r.str();
}
}

240
lib/mp4_dash.cpp Normal file
View file

@ -0,0 +1,240 @@
#include "mp4_dash.h"
#include "defines.h"
namespace MP4 {
SIDX::SIDX() {
memcpy(data + 4, "sidx", 4);
setVersion(0);
setFlags(0);
}
void SIDX::setReferenceID(uint32_t newReferenceID) {
setInt32(newReferenceID, 4);
}
uint32_t SIDX::getReferenceID() {
return getInt32(4);
}
void SIDX::setTimescale(uint32_t newTimescale) {
setInt32(newTimescale, 8);
}
uint32_t SIDX::getTimescale() {
return getInt32(8);
}
void SIDX::setEarliestPresentationTime(uint64_t newEarliestPresentationTime) {
if (getVersion() == 0) {
setInt32(newEarliestPresentationTime, 12);
} else {
setInt64(newEarliestPresentationTime, 12);
}
}
uint64_t SIDX::getEarliestPresentationTime() {
if (getVersion() == 0) {
return getInt32(12);
}
return getInt64(12);
}
void SIDX::setFirstOffset(uint64_t newFirstOffset) {
if (getVersion() == 0) {
setInt32(newFirstOffset, 16);
} else {
setInt64(newFirstOffset, 20);
}
}
uint64_t SIDX::getFirstOffset() {
if (getVersion() == 0) {
return getInt32(16);
}
return getInt64(20);
}
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));
}
uint32_t offset = 24 + (index * 12) + (getVersion() == 0 ? 0 : 8);
uint32_t tmp = (newRef.referenceType ? 0x80000000 : 0) | newRef.referencedSize;
setInt32(tmp, offset);
setInt32(newRef.subSegmentDuration, offset + 4);
tmp = (newRef.sapStart ? 0x80000000 : 0) | ((newRef.sapType & 0x7) << 24) | newRef.sapDeltaTime;
setInt32(tmp, offset + 8);
}
sidxReference SIDX::getReference(size_t index) {
sidxReference result;
if (index >= getReferenceCount()) {
DEBUG_MSG(DLVL_DEVEL, "Warning, attempt to obtain reference out of bounds");
return result;
}
uint32_t offset = 24 + (index * 12) + (getVersion() == 0 ? 0 : 8);
uint32_t tmp = getInt32(offset);
result.referenceType = tmp & 0x80000000;
result.referencedSize = tmp & 0x7FFFFFFF;
result.subSegmentDuration = getInt32(offset + 4);
tmp = getInt32(offset + 8);
result.sapStart = tmp & 0x80000000;
result.sapType = (tmp & 0x70000000) >> 24;
result.sapDeltaTime = (tmp & 0x0FFFFFFF);
return result;
}
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++) {
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;
}
return r.str();
}
TFDT::TFDT() {
memcpy(data + 4, "tfdt", 4);
setVersion(0);
setFlags(0);
}
void TFDT::setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime) {
if (getVersion() == 1) {
setInt64(newBaseMediaDecodeTime, 4);
} else {
setInt32(newBaseMediaDecodeTime, 4);
}
}
uint64_t TFDT::getBaseMediaDecodeTime() {
if (getVersion() == 1) {
return getInt64(4);
}
return getInt32(4);
}
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 << fullBox::toPrettyString(indent);
r << std::string(indent + 1, ' ') << "BaseMediaDecodeTime " << getBaseMediaDecodeTime() << std::endl;
return r.str();
}
IODS::IODS() {
memcpy(data + 4, "iods", 4);
setVersion(0);
setFlags(0);
setIODTypeTag(0x10);
setDescriptorTypeLength(0x07);
setODID(0x004F);
setODProfileLevel(0xFF);
setODSceneLevel(0xFF);
setODAudioLevel(0xFF);
setODVideoLevel(0xFF);
setODGraphicsLevel(0xFF);
}
void IODS::setIODTypeTag(char value) {
setInt8(value, 4);
}
char IODS::getIODTypeTag() {
return getInt8(4);
}
void IODS::setDescriptorTypeLength(char length) {
setInt8(length, 5);
}
char IODS::getDescriptorTypeLength() {
return getInt8(5);
}
void IODS::setODID(short id) {
setInt16(id, 6);
}
short IODS::getODID() {
return getInt16(6);
}
void IODS::setODProfileLevel(char value) {
setInt8(value, 8);
}
char IODS::getODProfileLevel() {
return getInt8(8);
}
void IODS::setODSceneLevel(char value) {
setInt8(value, 9);
}
char IODS::getODSceneLevel() {
return getInt8(9);
}
void IODS::setODAudioLevel(char value) {
setInt8(value, 10);
}
char IODS::getODAudioLevel() {
return getInt8(10);
}
void IODS::setODVideoLevel(char value) {
setInt8(value, 11);
}
char IODS::getODVideoLevel() {
return getInt8(11);
}
void IODS::setODGraphicsLevel(char value) {
setInt8(value, 12);
}
char IODS::getODGraphicsLevel() {
return getInt8(12);
}
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;
return r.str();
}
}

73
lib/mp4_dash.h Normal file
View file

@ -0,0 +1,73 @@
#pragma once
#include "mp4.h"
namespace MP4 {
struct sidxReference {
bool referenceType;
uint32_t referencedSize;
uint32_t subSegmentDuration;
bool sapStart;
uint8_t sapType;
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();
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);
std::string toPrettyString(uint32_t indent = 0);
};
class TFDT: public fullBox {
public:
TFDT();
void setBaseMediaDecodeTime(uint64_t newBaseMediaDecodeTime);
uint64_t getBaseMediaDecodeTime();
std::string toPrettyString(uint32_t indent = 0);
};
class IODS: public fullBox {
public:
IODS();
void setIODTypeTag(char value);
char getIODTypeTag();
void setDescriptorTypeLength(char length);
char getDescriptorTypeLength();
void setODID(short id);
short getODID();
void setODProfileLevel(char value);
char getODProfileLevel();
void setODSceneLevel(char value);
char getODSceneLevel();
void setODAudioLevel(char value);
char getODAudioLevel();
void setODVideoLevel(char value);
char getODVideoLevel();
void setODGraphicsLevel(char value);
char getODGraphicsLevel();
std::string toPrettyString(uint32_t indent = 0);
};
}

456
lib/mp4_encryption.cpp Normal file
View file

@ -0,0 +1,456 @@
#include "mp4_encryption.h"
namespace MP4 {
UUID_SampleEncryption::UUID_SampleEncryption() {
setUUID((std::string)"a2394f52-5a9b-4f14-a244-6c427c648df4");
}
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::getAlgorithmID() {
if (getFlags() & 0x01) {
return getInt24(20);
}
return -1;
}
void UUID_SampleEncryption::setIVSize(uint32_t newIVSize) {
if (getFlags() & 0x01) {
setInt8(newIVSize, 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);
}
}
}
std::string UUID_SampleEncryption::getKID() {
if (getFlags() & 0x01) {
std::string result;
for (int i = 0; i < 16; i++) {
result += (char)getInt8(24 + i);
}
return result;
}
return "";
}
uint32_t UUID_SampleEncryption::getSampleCount() {
int 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) {
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 += IV_SIZE;
if (getFlags() & 0x02) {
int entryCount = getInt16(myOffset);
myOffset += 2 + (entryCount * 6);
}
}
if (index >= getSampleCount()) {
//we are now at the end of currently reserved space, reserve more and adapt offset accordingly.
int reserveSize = ((index - getSampleCount())) * (IV_SIZE + (getFlags() & 0x02));
reserveSize += IV_SIZE;
if (getFlags() & 0x02) {
reserveSize += 2 + newSample.Entries.size();
}
if (!reserve(myOffset, 0, reserveSize)) {
return;//Memory errors...
}
myOffset += (index - getSampleCount()) * (IV_SIZE + (getFlags() & 0x02));
}
//write box.
for (int i = 0; i < IV_SIZE; i++) {
setInt8(newSample.InitializationVector[i], myOffset ++);//set and skip
}
if (getFlags() & 0x02) {
setInt16(newSample.Entries.size(), myOffset);
myOffset += 2;
for (std::vector<UUID_SampleEncryption_Sample_Entry>::iterator it = newSample.Entries.begin(); it != newSample.Entries.end(); it++) {
setInt16(it->BytesClear, myOffset);
myOffset += 2;
setInt32(it->BytesEncrypted, myOffset);
myOffset += 4;
}
}
if (index >= getSampleCount()) {
setInt32(index + 1, 20 + (20 * (getFlags() & 0x01)));
}
}
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 += IV_SIZE;
if (getFlags() & 0x02) {
int entryCount = getInt16(myOffset);
myOffset += 2;//skip over entrycount
myOffset += entryCount * 6;//skip entryCount sample entries
}
}
UUID_SampleEncryption_Sample result;
for (int i = 0; i < IV_SIZE; i++) {
result.InitializationVector += getInt8(myOffset++);//read and skip
}
if (getFlags() & 0x02) {
result.NumberOfEntries = getInt16(myOffset);
myOffset += 2;
for (unsigned int i = 0; i < result.NumberOfEntries; i++) {
result.Entries.push_back(UUID_SampleEncryption_Sample_Entry());
result.Entries[i].BytesClear = getInt16(myOffset);
myOffset += 2;
result.Entries[i].BytesEncrypted = getInt32(myOffset);
myOffset += 4;
}
}
return result;
}
std::string 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 + 1, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 1, ' ') << "Flags: " << getFlags() << std::endl;
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++) {
UUID_SampleEncryption_Sample tmpSample = getSample(i);
r << std::string(indent + 1, ' ') << "[" << i << "]" << std::endl;
r << std::string(indent + 3, ' ') << "Initialization Vector: 0x";
for (unsigned int j = 0; j < tmpSample.InitializationVector.size(); j++) {
r << std::hex << std::setw(2) << std::setfill('0') << (int)tmpSample.InitializationVector[j] << std::dec;
}
r << std::endl;
if (getFlags() & 0x02) {
r << std::string(indent + 3, ' ') << "Number of entries: " << tmpSample.NumberOfEntries << std::endl;
for (unsigned int j = 0; j < tmpSample.NumberOfEntries; j++) {
r << std::string(indent + 3, ' ') << "[" << j << "]" << std::endl;
r << std::string(indent + 5, ' ') << "Bytes clear: " << tmpSample.Entries[j].BytesClear << std::endl;
r << std::string(indent + 5, ' ') << "Bytes encrypted: " << tmpSample.Entries[j].BytesEncrypted << std::endl;
}
}
}
return r.str();
}
UUID_TrackEncryption::UUID_TrackEncryption() {
setUUID((std::string)"8974dbce-7be7-4c51-84f9-7148f9882554");
}
void UUID_TrackEncryption::setVersion(uint32_t newVersion) {
setInt8(newVersion, 16);
}
uint32_t UUID_TrackEncryption::getVersion() {
return getInt8(16);
}
void UUID_TrackEncryption::setFlags(uint32_t newFlags) {
setInt24(newFlags, 17);
}
uint32_t UUID_TrackEncryption::getFlags() {
return getInt24(17);
}
void UUID_TrackEncryption::setDefaultAlgorithmID(uint32_t newID) {
setInt24(newID, 20);
}
uint32_t UUID_TrackEncryption::getDefaultAlgorithmID() {
return getInt24(20);
}
void UUID_TrackEncryption::setDefaultIVSize(uint8_t newIVSize) {
setInt8(newIVSize, 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()) {
setInt8(newKID[i], 24 + i);
} else {
setInt8(0x00, 24 + i);
}
}
}
std::string UUID_TrackEncryption::getDefaultKID() {
std::string result;
for (int i = 0; i < 16; i++) {
result += getInt8(24 + i);
}
return result;
}
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 + 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 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");
}
void UUID_ProtectionSystemSpecificHeader::setVersion(uint32_t newVersion) {
setInt8(newVersion, 16);
}
uint32_t UUID_ProtectionSystemSpecificHeader::getVersion() {
return getInt8(16);
}
void UUID_ProtectionSystemSpecificHeader::setFlags(uint32_t newFlags) {
setInt24(newFlags, 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()) {
setInt8(newID[i], 20 + i);
} else {
setInt8(0x00, 20 + i);
}
}
}
std::string UUID_ProtectionSystemSpecificHeader::getSystemID() {
std::string result;
for (int i = 0; i < 16; i++) {
result += getInt8(20 + i);
}
return result;
}
uint32_t UUID_ProtectionSystemSpecificHeader::getDataSize() {
return getInt32(36);
}
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);
}
}
std::string UUID_ProtectionSystemSpecificHeader::getData() {
std::string result;
for (unsigned int i = 0; i < getDataSize(); i++) {
result += getInt8(40 + i);
}
return result;
}
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 + 2, ' ') << "Version: " << getVersion() << std::endl;
r << std::string(indent + 2, ' ') << "Flags: " << getFlags() << std::endl;
r << std::string(indent + 2, ' ') << "System ID: " << getSystemID() << std::endl;
r << std::string(indent + 2, ' ') << "Data Size: " << getDataSize() << std::endl;
r << std::string(indent + 2, ' ') << "Data: " << getData().size() << " bytes of data." << std::endl;
return r.str();
}
SINF::SINF() {
memcpy(data + 4, "sinf", 4);
}
void SINF::setEntry(Box & newEntry, uint32_t no) {
if (no > 4) {
return;
}
int tempLoc = 0;
for (unsigned int i = 0; i < no; i++) {
tempLoc += Box(getBox(tempLoc).asBox(), false).boxedSize();
}
setBox(newEntry, tempLoc);
}
Box & SINF::getEntry(uint32_t no) {
static Box ret = Box((char *)"\000\000\000\010erro", false);
if (no > 4) {
ret = Box((char *)"\000\000\000\010erro", false);
return ret;
}
int tempLoc = 0;
for (unsigned int i = 0; i < no; i++) {
tempLoc += Box(getBox(tempLoc).asBox(), false).boxedSize();
}
ret = Box(getBox(tempLoc).asBox(), false);
return ret;
}
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);
}
}
r << std::endl;
return r.str();
}
FRMA::FRMA() {
memcpy(data + 4, "frma", 4);
}
void FRMA::setOriginalFormat(std::string newFormat) {
for (unsigned int i = 0; i < 4; i++) {
if (i < newFormat.size()) {
setInt8(newFormat[i], i);
} else {
setInt8(0x00, i);
}
}
}
std::string FRMA::getOriginalFormat() {
return std::string(payload(), 4);
}
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;
return r.str();
}
SCHM::SCHM() {
memcpy(data + 4, "schm", 4);
}
void SCHM::setSchemeType(uint32_t newType) {
setInt32(htonl(newType), 4);
}
uint32_t SCHM::getSchemeType() {
return ntohl(getInt32(4));
}
void SCHM::setSchemeVersion(uint32_t newVersion) {
setInt32(htonl(newVersion), 8);
}
uint32_t SCHM::getSchemeVersion() {
return ntohl(getInt32(8));
}
void SCHM::setSchemeURI(std::string newURI) {
setFlags(getFlags() | 0x01);
setString(newURI, 12);
}
std::string SCHM::getSchemeURI() {
if (getFlags() & 0x01) {
return getString(12);
}
return "";
}
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, ' ') << "SchemeURI: " << getSchemeURI() << std::endl;
}
return r.str();
}
SCHI::SCHI() {
memcpy(data + 4, "schi", 4);
}
void SCHI::setContent(Box & newContent) {
setBox(newContent, 0);
}
Box & SCHI::getContent() {
return getBox(0);
}
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();
}
}

104
lib/mp4_encryption.h Normal file
View file

@ -0,0 +1,104 @@
#include "mp4.h"
#include "mp4_ms.h"
namespace MP4 {
struct UUID_SampleEncryption_Sample_Entry {
uint32_t BytesClear;
uint32_t BytesEncrypted;
};
struct UUID_SampleEncryption_Sample {
std::string InitializationVector;
uint32_t NumberOfEntries;
std::vector<UUID_SampleEncryption_Sample_Entry> Entries;
};
class UUID_SampleEncryption: public UUID {
public:
UUID_SampleEncryption();
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_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 FRMA: public Box {
public:
FRMA();
void setOriginalFormat(std::string newFormat);
std::string getOriginalFormat();
std::string toPrettyString(uint32_t indent = 0);
};
class SCHM: public fullBox {
public:
SCHM();
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);
};
}

View file

@ -639,6 +639,192 @@ namespace MP4 {
memcpy((char *)payload(), (char *)newPayload.c_str(), newPayload.size());
}
HVCC::HVCC() {
memcpy(data + 4, "hvcC", 4);
}
void HVCC::setConfigurationVersion(char newVersion) {
setInt8(newVersion, 0);
}
char HVCC::getConfigurationVersion() {
return getInt8(0);
}
void HVCC::setGeneralProfileSpace(char newGeneral) {
setInt8(((newGeneral << 6) & 0xC0) | (getInt8(1) & 0x3F), 1);
}
char HVCC::getGeneralProfileSpace(){
return ((getInt8(1) >> 6) & 0x03);
}
void HVCC::setGeneralTierFlag(char newGeneral){
setInt8(((newGeneral << 5) & 0x20) | (getInt8(1) & 0xDF), 1);
}
char HVCC::getGeneralTierFlag(){
return ((getInt8(1) >> 5) & 0x01);
}
void HVCC::setGeneralProfileIdc(char newGeneral){
setInt8((newGeneral & 0x1F) | (getInt8(1) & 0xE0), 1);
}
char HVCC::getGeneralProfileIdc(){
return getInt8(1) & 0x1F;
}
void HVCC::setGeneralProfileCompatibilityFlags(unsigned long newGeneral){
setInt32(newGeneral, 2);
}
unsigned long HVCC::getGeneralProfileCompatibilityFlags(){
return getInt32(2);
}
void HVCC::setGeneralConstraintIndicatorFlags(unsigned long long newGeneral){
setInt32((newGeneral >> 16) & 0x0000FFFF,6);
setInt16(newGeneral & 0xFFFFFF, 10);
}
unsigned long long HVCC::getGeneralConstraintIndicatorFlags(){
unsigned long long result = getInt32(6);
result <<= 16;
return result | getInt16(10);
}
void HVCC::setGeneralLevelIdc(char newGeneral){
setInt8(newGeneral, 12);
}
char HVCC::getGeneralLevelIdc(){
return getInt8(12);
}
void HVCC::setMinSpatialSegmentationIdc(short newIdc){
setInt16(newIdc | 0xF000, 13);
}
short HVCC::getMinSpatialSegmentationIdc(){
return getInt16(13) & 0x0FFF;
}
void HVCC::setParallelismType(char newType){
setInt8(newType | 0xFC, 15);
}
char HVCC::getParallelismType(){
return getInt8(15) & 0x03;
}
void HVCC::setChromaFormat(char newFormat){
setInt8(newFormat | 0xFC, 16);
}
char HVCC::getChromaFormat(){
return getInt8(16) & 0x03;
}
void HVCC::setBitDepthLumaMinus8(char newBitDepthLumaMinus8){
setInt8(newBitDepthLumaMinus8 | 0xF8, 17);
}
char HVCC::getBitDepthLumaMinus8(){
return getInt8(17) & 0x07;
}
void HVCC::setBitDepthChromaMinus8(char newBitDepthChromaMinus8){
setInt8(newBitDepthChromaMinus8 | 0xF8, 18);
}
char HVCC::getBitDepthChromaMinus8(){
return getInt8(18) & 0x07;
}
void setAverageFramerate(short newFramerate);
short HVCC::getAverageFramerate(){
return getInt16(19);
}
void setConstantFramerate(char newFramerate);
char HVCC::getConstantFramerate(){
return (getInt8(21) >> 6) & 0x03;
}
void setNumberOfTemporalLayers(char newNumber);
char HVCC::getNumberOfTemporalLayers(){
return (getInt8(21) >> 3) & 0x07;
}
void setTemporalIdNested(char newNested);
char HVCC::getTemporalIdNested(){
return (getInt8(21) >> 2) & 0x01;
}
void setLengthSizeMinus1(char newLengthSizeMinus1);
char HVCC::getLengthSizeMinus1(){
return getInt8(21) & 0x03;
}
std::deque<HVCCArrayEntry> HVCC::getArrays(){
std::deque<HVCCArrayEntry> r;
char arrayCount = getInt8(22);
int offset = 23;
for(int i = 0; i < arrayCount; i++){
HVCCArrayEntry entry;
entry.arrayCompleteness = ((getInt8(offset) >> 7) & 0x01);
entry.nalUnitType = (getInt8(offset) & 0x3F);
offset++;
short naluCount = getInt16(offset);
offset += 2;
for (int j = 0; j < naluCount; j++){
short naluSize = getInt16(offset);
offset += 2;
std::string nalu;
for (int k = 0; k < naluSize; k++){
nalu += (char)getInt8(offset++);
}
entry.nalUnits.push_back(nalu);
}
r.push_back(entry);
}
return r;
}
std::string HVCC::toPrettyString(uint32_t indent) {
std::stringstream r;
r << std::string(indent, ' ') << "[hvcC] H.265 Init Data (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "Configuration Version: " << (int)getConfigurationVersion() << std::endl;
r << std::string(indent + 1, ' ') << "General Profile Space: " << (int)getGeneralProfileSpace() << std::endl;
r << std::string(indent + 1, ' ') << "General Tier Flag: " << (int)getGeneralTierFlag() << std::endl;
r << std::string(indent + 1, ' ') << "General Profile IDC: " << (int)getGeneralProfileIdc() << std::endl;
r << std::string(indent + 1, ' ') << "General Profile Compatibility Flags: 0x" << std::hex << std::setw(8) << std::setfill('0') << getGeneralProfileCompatibilityFlags() << std::dec << std::endl;
r << std::string(indent + 1, ' ') << "General Constraint Indicator Flags: 0x" << std::hex << std::setw(12) << std::setfill('0') << getGeneralConstraintIndicatorFlags() << std::dec << std::endl;
r << std::string(indent + 1, ' ') << "General Level IDC: " << (int)getGeneralLevelIdc() << std::endl;
r << std::string(indent + 1, ' ') << "Minimum Spatial Segmentation IDC: " << (int)getMinSpatialSegmentationIdc() << std::endl;
r << std::string(indent + 1, ' ') << "Parallelism Type: " << (int)getParallelismType() << std::endl;
r << std::string(indent + 1, ' ') << "Chroma Format: " << (int)getChromaFormat() << std::endl;
r << std::string(indent + 1, ' ') << "Bit Depth Luma - 8: " << (int)getBitDepthLumaMinus8() << std::endl;
r << std::string(indent + 1, ' ') << "Average Framerate: " << (int)getAverageFramerate() << std::endl;
r << std::string(indent + 1, ' ') << "Constant Framerate: " << (int)getConstantFramerate() << std::endl;
r << std::string(indent + 1, ' ') << "Number of Temporal Layers: " << (int)getNumberOfTemporalLayers() << std::endl;
r << std::string(indent + 1, ' ') << "Temporal ID Nested: " << (int)getTemporalIdNested() << std::endl;
r << std::string(indent + 1, ' ') << "Length Size - 1: " << (int)getLengthSizeMinus1() << std::endl;
r << std::string(indent + 1, ' ') << "Arrays:" << std::endl;
std::deque<HVCCArrayEntry> arrays = getArrays();
for (unsigned int i = 0; i < arrays.size(); i++){
r << std::string(indent + 2, ' ') << "Array with type " << (int)arrays[i].nalUnitType << std::endl;
for (unsigned int j = 0; j < arrays[i].nalUnits.size(); j++){
r << std::string(indent + 3, ' ') << "Nal unit of " << arrays[i].nalUnits[j].size() << " bytes" << std::endl;
}
}
return r.str();
}
void HVCC::setPayload(std::string newPayload) {
if (!reserve(0, payloadSize(), newPayload.size())) {
DEBUG_MSG(DLVL_ERROR, "Cannot allocate enough memory for payload");
return;
}
memcpy((char *)payload(), (char *)newPayload.c_str(), newPayload.size());
}
std::string HVCC::asAnnexB() {
std::deque<HVCCArrayEntry> arrays = getArrays();
std::stringstream r;
for (unsigned int i = 0; i < arrays.size(); i++){
for (unsigned int j = 0; j < arrays[i].nalUnits.size(); j++){
r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01 << arrays[i].nalUnits[j];
}
}
return r.str();
}
Descriptor::Descriptor(){
data = (char*)malloc(2);
data[0] = 0;
@ -967,19 +1153,85 @@ namespace MP4 {
return r.str();
}
FTYP::FTYP() {
memcpy(data + 4, "ftyp", 4);
setMajorBrand("mp41");
setMinorVersion("Mist");
setCompatibleBrands("isom", 0);
setCompatibleBrands("iso2", 1);
setCompatibleBrands("avc1", 2);
setCompatibleBrands("mp41", 3);
DAC3::DAC3(){
memcpy(data + 4, "dac3", 4);
setInt24(0,0);
}
void FTYP::setMajorBrand(const char * newMajorBrand) {
if (payloadOffset + 3 >= boxedSize()) {
if (!reserve(payloadOffset, 0, 4)) {
char DAC3::getSampleRateCode(){
return getInt8(0) >> 6;
}
void DAC3::setSampleRateCode(char newVal){
setInt8(((newVal << 6) & 0xC0) | (getInt8(0) & 0x3F), 0);
}
char DAC3::getBitStreamIdentification(){
return (getInt8(0) >> 1) & 0x1F;
}
void DAC3::setBitStreamIdentification(char newVal){
setInt8(((newVal << 1) & 0x3E) | (getInt8(0) & 0xC1), 0);
}
char DAC3::getBitStreamMode(){
return (getInt16(0) >> 6) & 0x7;
}
void DAC3::setBitStreamMode(char newVal){
setInt16(((newVal & 0x7) << 6) | (getInt16(0) & 0xFE3F), 0);
}
char DAC3::getAudioConfigMode(){
return (getInt8(1) >> 3) & 0x7;
}
void DAC3::setAudioConfigMode(char newVal){
setInt8(((newVal & 0x7) << 3) | (getInt8(1) & 0x38),1);
}
bool DAC3::getLowFrequencyEffectsChannelOn(){
return (getInt8(1) >> 2) & 0x1;
}
void DAC3::setLowFrequencyEffectsChannelOn(bool newVal){
setInt8(((unsigned int)(newVal & 0x1) << 2) | (getInt8(1) & 0x4),1);
}
char DAC3::getFrameSizeCode(){
return ((getInt8(1) & 0x3) << 4) | ((getInt8(2) & 0xF0) >> 4);
}
void DAC3::setFrameSizeCode(char newVal){
setInt16(((newVal & 0x3F) << 4) | (getInt16(1) & 0x03F0),1);
}
std::string DAC3::toPrettyString(uint32_t indent){
std::stringstream r;
r << std::string(indent, ' ') << "[dac3] D-AC3 box (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "FSCOD: " << (int)getSampleRateCode() << std::endl;
r << std::string(indent + 1, ' ') << "BSID: " << (int)getBitStreamIdentification() << std::endl;
r << std::string(indent + 1, ' ') << "BSMOD: " << (int)getBitStreamMode() << std::endl;
r << std::string(indent + 1, ' ') << "ACMOD: " << (int)getAudioConfigMode() << std::endl;
r << std::string(indent + 1, ' ') << "LFEON: " << (int)getLowFrequencyEffectsChannelOn() << std::endl;
r << std::string(indent + 1, ' ') << "FrameSizeCode: " << (int)getFrameSizeCode() << std::endl;
return r.str();
}
FTYP::FTYP(bool fillDefaults){
memcpy(data + 4, "ftyp", 4);
if (fillDefaults){
setMajorBrand("mp41");
setMinorVersion("Mist");
setCompatibleBrands("isom",0);
setCompatibleBrands("iso2",1);
setCompatibleBrands("avc1",2);
}
}
void FTYP::setMajorBrand(const char * newMajorBrand){
if (payloadOffset + 3 >= boxedSize()){
if ( !reserve(payloadOffset, 0, 4)){
return;
}
}
@ -996,11 +1248,16 @@ namespace MP4 {
return;
}
}
memset(data + payloadOffset + 4, 0, 4);
memcpy(data + payloadOffset + 4, newMinorVersion, 4);
}
std::string FTYP::getMinorVersion() {
return std::string(data + payloadOffset + 4, 4);
std::string FTYP::getMinorVersion(){
static char zero[4] = {0,0,0,0};
if (memcmp(zero, data+payloadOffset+4, 4) == 0){
return "";
}
return std::string(data+payloadOffset+4, 4);
}
size_t FTYP::getCompatibleBrandsCount() {
@ -1035,6 +1292,22 @@ namespace MP4 {
return r.str();
}
STYP::STYP(bool fillDefaults) : FTYP(fillDefaults) {
memcpy(data + 4, "styp", 4);
}
std::string STYP::toPrettyString(uint32_t indent){
std::stringstream r;
r << std::string(indent, ' ') << "[styp] Fragment Type (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "MajorBrand: " << getMajorBrand() << std::endl;
r << std::string(indent + 1, ' ') << "MinorVersion: " << getMinorVersion() << std::endl;
r << std::string(indent + 1, ' ') << "CompatibleBrands (" << getCompatibleBrandsCount() << "):" << std::endl;
for (unsigned int i = 0; i < getCompatibleBrandsCount(); i++){
r << std::string(indent + 2, ' ') << "[" << i << "] CompatibleBrand: " << getCompatibleBrands(i) << std::endl;
}
return r.str();
}
MOOV::MOOV() {
memcpy(data + 4, "moov", 4);
}
@ -1045,47 +1318,52 @@ namespace MP4 {
TREX::TREX() {
memcpy(data + 4, "trex", 4);
setTrackID(0);
setDefaultSampleDescriptionIndex(1);
setDefaultSampleDuration(0);
setDefaultSampleSize(0);
setDefaultSampleFlags(0);
}
void TREX::setTrackID(uint32_t newTrackID) {
setInt32(newTrackID, 0);
void TREX::setTrackID(uint32_t newTrackID){
setInt32(newTrackID, 4);
}
uint32_t TREX::getTrackID() {
return getInt32(0);
}
void TREX::setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex) {
setInt32(newDefaultSampleDescriptionIndex, 4);
}
uint32_t TREX::getDefaultSampleDescriptionIndex() {
uint32_t TREX::getTrackID(){
return getInt32(4);
}
void TREX::setDefaultSampleDuration(uint32_t newDefaultSampleDuration) {
setInt32(newDefaultSampleDuration, 8);
void TREX::setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex){
setInt32(newDefaultSampleDescriptionIndex,8);
}
uint32_t TREX::getDefaultSampleDuration() {
uint32_t TREX::getDefaultSampleDescriptionIndex(){
return getInt32(8);
}
void TREX::setDefaultSampleSize(uint32_t newDefaultSampleSize) {
setInt32(newDefaultSampleSize, 12);
void TREX::setDefaultSampleDuration(uint32_t newDefaultSampleDuration){
setInt32(newDefaultSampleDuration,12);
}
uint32_t TREX::getDefaultSampleSize() {
uint32_t TREX::getDefaultSampleDuration(){
return getInt32(12);
}
void TREX::setDefaultSampleFlags(uint32_t newDefaultSampleFlags) {
setInt32(newDefaultSampleFlags, 16);
void TREX::setDefaultSampleSize(uint32_t newDefaultSampleSize){
setInt32(newDefaultSampleSize,16);
}
uint32_t TREX::getDefaultSampleFlags() {
uint32_t TREX::getDefaultSampleSize(){
return getInt32(16);
}
void TREX::setDefaultSampleFlags(uint32_t newDefaultSampleFlags){
setInt32(newDefaultSampleFlags,20);
}
uint32_t TREX::getDefaultSampleFlags(){
return getInt32(20);
}
std::string TREX::toPrettyString(uint32_t indent) {
std::stringstream r;
@ -1576,28 +1854,28 @@ namespace MP4 {
int32_t MVHD::getMatrix(size_t index) {
int offset = 0;
if (getVersion() == 0) {
offset = 24 + 2 + 10;
} else {
offset = 36 + 2 + 10;
if (getVersion() == 0){
offset = 36;
}else{
offset = 48;
}
return getInt32(offset + index * 4);
}
//24 bytes of pre-defined in between
void MVHD::setTrackID(uint32_t newTrackID) {
if (getVersion() == 0) {
setInt32(newTrackID, 86);
} else {
setInt32(newTrackID, 98);
void MVHD::setTrackID(uint32_t newTrackID){
if (getVersion() == 0){
setInt32(newTrackID, 96);
}else{
setInt32(newTrackID, 108);
}
}
uint32_t MVHD::getTrackID() {
if (getVersion() == 0) {
return getInt32(86);
} else {
return getInt32(98);
uint32_t MVHD::getTrackID(){
if (getVersion() == 0){
return getInt32(96);
}else{
return getInt32(108);
}
}
@ -2775,6 +3053,13 @@ namespace MP4 {
return getBox(28);
}
/*LTS-START*/
Box & AudioSampleEntry::getSINFBox() {
static Box ret = Box(getBox(28 + getBoxLen(28)).asBox(), false);
return ret;
}
/*LTS-END*/
std::string AudioSampleEntry::toPrettyAudioString(uint32_t indent, std::string name) {
std::stringstream r;
r << std::string(indent, ' ') << name << " (" << boxedSize() << ")" << std::endl;
@ -2784,6 +3069,11 @@ namespace MP4 {
r << std::string(indent + 1, ' ') << "PreDefined: " << getPreDefined() << std::endl;
r << std::string(indent + 1, ' ') << "SampleRate: " << getSampleRate() << std::endl;
r << getCodecBox().toPrettyString(indent + 1) << std::endl;
/*LTS-START*/
if (isType("enca")) {
r << getSINFBox().toPrettyString(indent + 1);
}
/*LTS-END*/
return r.str();
}
@ -2803,6 +3093,14 @@ namespace MP4 {
return toPrettyAudioString(indent, "[aac ] Advanced Audio Codec");
}
HEV1::HEV1() {
memcpy(data + 4, "hev1", 4);
}
std::string HEV1::toPrettyString(uint32_t indent) {
return toPrettyVisualString(indent, "[hev1] High Efficiency Video Codec 1");
}
AVC1::AVC1() {
memcpy(data + 4, "avc1", 4);
}
@ -2819,6 +3117,34 @@ namespace MP4 {
return toPrettyVisualString(indent, "[h264] H.264/MPEG-4 AVC");
}
FIEL::FIEL(){
memcpy(data + 4, "fiel", 4);
}
void FIEL::setTotal(char newTotal){
setInt8(newTotal, 0);
}
char FIEL::getTotal(){
return getInt8(0);
}
void FIEL::setOrder(char newOrder){
setInt8(newOrder, 1);
}
char FIEL::getOrder(){
return getInt8(1);
}
std::string FIEL::toPrettyString(uint32_t indent) {
std::stringstream r;
r << std::string(indent, ' ') << "[fiel] Video Field Order Box (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "Total: " << (int)getTotal() << std::endl;
r << std::string(indent + 1, ' ') << "Order: " << (int)getOrder() << std::endl;
return r.str();
}
STSD::STSD(char v, uint32_t f) {
memcpy(data + 4, "stsd", 4);
setVersion(v);
@ -2881,6 +3207,14 @@ namespace MP4 {
return r.str();
}
GMHD::GMHD() {
memcpy(data + 4, "gmhd", 4);
}
TREF::TREF() {
memcpy(data + 4, "tref", 4);
}
EDTS::EDTS() {
memcpy(data + 4, "edts", 4);
}
@ -3022,3 +3356,4 @@ namespace MP4 {
return r.str();
}
}

View file

@ -1,3 +1,4 @@
#pragma once
#include "mp4.h"
namespace MP4 {
@ -122,6 +123,56 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
struct HVCCArrayEntry {
char arrayCompleteness;
char nalUnitType;
std::deque<std::string> nalUnits;
};
class HVCC: public Box {
public:
HVCC();
void setConfigurationVersion(char newVersion);
char getConfigurationVersion();
void setGeneralProfileSpace(char newGeneral);
char getGeneralProfileSpace();
void setGeneralTierFlag(char newGeneral);
char getGeneralTierFlag();
void setGeneralProfileIdc(char newGeneral);
char getGeneralProfileIdc();
void setGeneralProfileCompatibilityFlags(unsigned long newGeneral);
unsigned long getGeneralProfileCompatibilityFlags();
void setGeneralConstraintIndicatorFlags(unsigned long long newGeneral);
unsigned long long getGeneralConstraintIndicatorFlags();
void setGeneralLevelIdc(char newGeneral);
char getGeneralLevelIdc();
void setMinSpatialSegmentationIdc(short newIdc);
short getMinSpatialSegmentationIdc();
void setParallelismType(char newType);
char getParallelismType();
void setChromaFormat(char newFormat);
char getChromaFormat();
void setBitDepthLumaMinus8(char newBitDepthLumaMinus8);
char getBitDepthLumaMinus8();
void setBitDepthChromaMinus8(char newBitDepthChromaMinus8);
char getBitDepthChromaMinus8();
void setAverageFramerate(short newFramerate);
short getAverageFramerate();
void setConstantFramerate(char newFramerate);
char getConstantFramerate();
void setNumberOfTemporalLayers(char newNumber);
char getNumberOfTemporalLayers();
void setTemporalIdNested(char newNested);
char getTemporalIdNested();
void setLengthSizeMinus1(char newLengthSizeMinus1);
char getLengthSizeMinus1();
///\todo Add setter for the array entries
std::deque<HVCCArrayEntry> getArrays();
std::string asAnnexB();
void setPayload(std::string newPayload);
std::string toPrettyString(uint32_t indent = 0);
};
class Descriptor{
public:
Descriptor();
@ -182,9 +233,27 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
class DAC3: public Box {
public:
DAC3();
char getSampleRateCode();//2bits
void setSampleRateCode(char newVal);//2bits
char getBitStreamIdentification();//5bits
void setBitStreamIdentification(char newVal);//5bits
char getBitStreamMode();//3 bits
void setBitStreamMode(char newVal);//3 bits
char getAudioConfigMode();//3 bits
void setAudioConfigMode(char newVal);//3 bits
bool getLowFrequencyEffectsChannelOn();//1bit
void setLowFrequencyEffectsChannelOn(bool newVal);//1bit
char getFrameSizeCode();//6bits
void setFrameSizeCode(char newVal);//6bits
std::string toPrettyString(uint32_t indent = 0);
};
class FTYP: public Box {
public:
FTYP();
FTYP(bool fillDefaults = true);
void setMajorBrand(const char * newMajorBrand);
std::string getMajorBrand();
void setMinorVersion(const char * newMinorVersion);
@ -195,6 +264,12 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
class STYP: public FTYP {
public:
STYP(bool fillDefaults = true);
std::string toPrettyString(uint32_t indent = 0);
};
class MOOV: public containerBox {
public:
MOOV();
@ -205,7 +280,7 @@ namespace MP4 {
MVEX();
};
class TREX: public Box {
class TREX: public fullBox {
public:
TREX();
void setTrackID(uint32_t newTrackID);
@ -600,6 +675,7 @@ namespace MP4 {
uint32_t getSampleRate();
void setCodecBox(Box & newBox);
Box & getCodecBox();
Box & getSINFBox(); /*LTS*/
std::string toPrettyAudioString(uint32_t indent = 0, std::string name = "");
};
@ -615,6 +691,12 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
class HEV1: public VisualSampleEntry {
public:
HEV1();
std::string toPrettyString(uint32_t indent = 0);
};
class AVC1: public VisualSampleEntry {
public:
AVC1();
@ -627,6 +709,16 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
class FIEL: public Box {
public:
FIEL();
void setTotal(char newTotal);
char getTotal();
void setOrder(char newOrder);
char getOrder();
std::string toPrettyString(uint32_t indent = 0);
};
class STSD: public fullBox {
public:
STSD(char v = 1, uint32_t f = 0);
@ -637,6 +729,16 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
class GMHD: public containerBox {
public:
GMHD();
};
class TREF: public containerBox {
public:
TREF();
};
class EDTS: public containerBox {
public:
EDTS();
@ -677,3 +779,4 @@ namespace MP4 {
std::string toPrettyString(uint32_t indent = 0);
};
}

View file

@ -1,4 +1,5 @@
#include "mp4_ms.h"
#include "mp4_encryption.h" /*LTS*/
namespace MP4 {
@ -127,6 +128,17 @@ namespace MP4 {
if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f") {
return ((UUID_TrackFragmentReference *)this)->toPrettyString(indent);
}
/*LTS-START*/
if (UUID == "a2394f52-5a9b-4f14-a244-6c427c648df4") {
return ((UUID_SampleEncryption *)this)->toPrettyString(indent);
}
if (UUID == "8974dbce-7be7-4c51-84f9-7148f9882554") {
return ((UUID_TrackEncryption *)this)->toPrettyString(indent);
}
if (UUID == "d08a4f18-10f3-4a82-b6c8-32d8aba183d3") {
return ((UUID_ProtectionSystemSpecificHeader *)this)->toPrettyString(indent);
}
/*LTS-END*/
std::stringstream r;
r << std::string(indent, ' ') << "[uuid] Extension box (" << boxedSize() << ")" << std::endl;
r << std::string(indent + 1, ' ') << "UUID: " << UUID << std::endl;

239
lib/rtp.cpp Normal file
View file

@ -0,0 +1,239 @@
#include <arpa/inet.h>
#include "rtp.h"
#include "timing.h"
#include "defines.h"
#define MAX_SEND 1024*4
namespace RTP {
double Packet::startRTCP = 0;
unsigned int Packet::getHsize() const {
return 12 + 4 * getContribCount();
}
unsigned int Packet::getVersion() const {
return (data[0] >> 6) & 0x3;
}
unsigned int Packet::getPadding() const {
return (data[0] >> 5) & 0x1;
}
unsigned int Packet::getExtension() const {
return (data[0] >> 4) & 0x1;
}
unsigned int Packet::getContribCount() const {
return (data[0]) & 0xE;
}
unsigned int Packet::getMarker() const {
return (data[1] >> 7) & 0x1;
}
unsigned int Packet::getPayloadType() const {
return (data[1]) & 0x7F;
}
unsigned int Packet::getSequence() const {
return (((((unsigned int)data[2]) << 8) + data[3]));
}
unsigned int Packet::getTimeStamp() const {
return ntohl(*((unsigned int *)(data + 4)));
}
unsigned int Packet::getSSRC() const {
return ntohl(*((unsigned int *)(data + 8)));
}
char * Packet::getData() {
return data + 8 + 4 * getContribCount() + getExtension();
}
void Packet::setTimestamp(unsigned int t) {
*((unsigned int *)(data + 4)) = htonl(t);
}
void Packet::setSequence(unsigned int seq) {
*((short *)(data + 2)) = htons(seq);
}
void Packet::setSSRC(unsigned long ssrc) {
*((int *)(data + 8)) = htonl(ssrc);
}
void Packet::increaseSequence() {
*((short *)(data + 2)) = htons(getSequence() + 1);
}
void Packet::sendH264(void * socket, void callBack(void *, char *, unsigned int, unsigned int), const char * payload, unsigned int payloadlen, unsigned int channel) {
/// \todo This function probably belongs in DMS somewhere.
if (payloadlen <= MAX_SEND) {
data[1] |= 0x80;//setting the RTP marker bit to 1
memcpy(data + getHsize(), payload, payloadlen);
callBack(socket, data, getHsize() + payloadlen, channel);
sentPackets++;
sentBytes += payloadlen;
increaseSequence();
} else {
data[1] &= 0x7F;//setting the RTP marker bit to 0
unsigned int sent = 0;
unsigned int sending = MAX_SEND;//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;
while (sent < payloadlen) {
if (sent == 0) {
serByte |= 0x80;//set first bit to 1
} else {
serByte &= 0x7F;//set first bit to 0
}
if (sent + MAX_SEND >= payloadlen) {
//last package
serByte |= 0x40;
sending = payloadlen - sent;
data[1] |= 0x80;//setting the RTP marker bit to 1
}
data[getHsize() + 1] = serByte;
memcpy(data + getHsize() + 2, payload + 1 + sent, sending); //+1 because
callBack(socket, data, getHsize() + 2 + sending, channel);
sentPackets++;
sentBytes += sending;
sent += sending;
increaseSequence();
}
}
}
void Packet::sendAAC(void * socket, void callBack(void *, char *, unsigned int, unsigned int), const char * payload, unsigned int payloadlen, unsigned int channel) {
/// \todo This function probably belongs in DMS somewhere.
data[1] |= 0x80;//setting the RTP marker bit to 1
/// \todo This 0x100000 value - What is it? Why is it hardcoded?
/// \todo The least significant 3 bits are used to signal some stuff from RFC 3640. Why do we send them always as 000?
*((int *)(data + getHsize())) = htonl(((payloadlen << 3) & 0x0010fff8) | 0x00100000);
memcpy(data + getHsize() + 4, payload, payloadlen);
callBack(socket, data, getHsize() + 4 + payloadlen, channel);
sentPackets++;
sentBytes += payloadlen;
increaseSequence();
}
void Packet::sendRaw(void * socket, void callBack(void *, char *, unsigned int, unsigned int), const char * payload, unsigned int payloadlen, unsigned int channel) {
/// \todo This function probably belongs in DMS somewhere.
data[1] |= 0x80;//setting the RTP marker bit to 1
memcpy(data + getHsize(), payload, payloadlen);
callBack(socket, data, getHsize() + payloadlen, channel);
sentPackets++;
sentBytes += payloadlen;
increaseSequence();
}
/// Stores a long long (64 bits) value of val in network order to the pointer p.
inline void Packet::htobll(char * p, long long val) {
p[0] = (val >> 56) & 0xFF;
p[1] = (val >> 48) & 0xFF;
p[2] = (val >> 40) & 0xFF;
p[3] = (val >> 32) & 0xFF;
p[4] = (val >> 24) & 0xFF;
p[5] = (val >> 16) & 0xFF;
p[6] = (val >> 8) & 0xFF;
p[7] = val & 0xFF;
}
void Packet::sendRTCP(long long & connectedAt, void * socket, unsigned int tid , DTSC::Meta & metadata, void callBack(void *, char *, unsigned int, unsigned int)) {
void * rtcpData = malloc(32);
if (!rtcpData){
FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up.");
return;
}
((int *)rtcpData)[0] = htonl(0x80C80006);
((int *)rtcpData)[1] = htonl(getSSRC());
// unsigned int tid = packet["trackid"].asInt();
//timestamp in ms
double ntpTime = 2208988800UL + Util::epoch() + (Util::getMS() % 1000) / 1000.0;
if (startRTCP < 1 && startRTCP > -1) {
startRTCP = ntpTime;
}
ntpTime -= startRTCP;
((int *)rtcpData)[2] = htonl(2208988800UL + Util::epoch()); //epoch is in seconds
((int *)rtcpData)[3] = htonl((Util::getMS() % 1000) * 4294967.295);
if (metadata.tracks[tid].codec == "H264") {
((int *)rtcpData)[4] = htonl((ntpTime - 0) * 90000); //rtpts
} else if (metadata.tracks[tid].codec == "AAC") {
((int *)rtcpData)[4] = htonl((ntpTime - 0) * metadata.tracks[tid].rate); //rtpts
} else {
DEBUG_MSG(DLVL_FAIL, "Unsupported codec");
return;
}
//it should be the time packet was sent maybe, after all?
//*((int *)(rtcpData+16) ) = htonl(getTimeStamp());//rtpts
((int *)rtcpData)[5] = htonl(sentPackets);//packet
((int *)rtcpData)[6] = htonl(sentBytes);//octet
callBack(socket, (char*)rtcpData , 28 , 0);
free(rtcpData);
}
Packet::Packet() {
managed = false;
data = 0;
}
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[0] = ((2) << 6) | ((0 & 1) << 5) | ((0 & 1) << 4) | (csrcCount & 15); //version, padding, extension, csrc count
data[1] = payloadType & 0x7F; //marker and payload type
setSequence(sequence - 1); //we automatically increase the sequence each time when p
setTimestamp(timestamp);
setSSRC(ssrc);
sentBytes = 0;
sentPackets = 0;
}
Packet::Packet(const Packet & o) {
managed = true;
if (o.data) {
data = new char[o.getHsize() + 2 + MAX_SEND]; //headerSize, 2 for FU-A, MAX_SEND for maximum sent size
if (data) {
memcpy(data, o.data, o.getHsize() + 2 + MAX_SEND);
}
} else {
data = new char[14 + MAX_SEND];//headerSize, 2 for FU-A, MAX_SEND for maximum sent size
if (data) {
memset(data, 0, 14 + MAX_SEND);
}
}
sentBytes = o.sentBytes;
sentPackets = o.sentPackets;
}
void Packet::operator=(const Packet & o) {
managed = true;
if (data) {
delete[] data;
}
data = new char[o.getHsize() + 2 + MAX_SEND];
if (data) {
memcpy(data, o.data, o.getHsize() + 2 + MAX_SEND);
}
sentBytes = o.sentBytes;
sentPackets = o.sentPackets;
}
Packet::~Packet() {
if (managed) {
delete [] data;
}
}
Packet::Packet(const char * dat, unsigned int len) {
managed = false;
datalen = len;
data = (char *) dat;
}
}

62
lib/rtp.h Normal file
View file

@ -0,0 +1,62 @@
#pragma once
#include <string>
#include <vector>
#include <set>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <stdint.h>
#include <sstream>
#include <deque>
#include <algorithm>
#include "socket.h"
#include "json.h"
#include "dtsc.h"
#include "mp4.h"
#include "mp4_generic.h"
/// This namespace holds all RTP-parsing and sending related functionality.
namespace RTP {
/// This class is used to make RTP packets. Currently, H264, and AAC are supported. RTP mechanisms, like increasing sequence numbers and setting timestamps are all taken care of in here.
class Packet {
private:
bool managed;
char * data; ///<The actual RTP packet that is being sent
unsigned int datalen; ///<Size of rtp packet
int sentPackets;
int sentBytes;//Because ugly is beautiful
inline void htobll(char * p, long long val);
public:
static double startRTCP;
unsigned int getHsize() const;
unsigned int getVersion() const;
unsigned int getPadding() const;
unsigned int getExtension() const;
unsigned int getContribCount() const;
unsigned int getMarker() const;
unsigned int getPayloadType() const;
unsigned int getSequence() const;
unsigned int getTimeStamp() const;
void setSequence(unsigned int seq);
unsigned int getSSRC() const;
void setSSRC(unsigned long ssrc);
void setTimestamp(unsigned int t);
void increaseSequence();
void sendH264(void * socket, void callBack(void *, char *, unsigned int, unsigned int), const char * payload, unsigned int payloadlen, unsigned int channel);
void sendAAC(void * socket, void callBack(void *, char *, unsigned int, unsigned int), const char * payload, unsigned int payloadlen, unsigned int channel);
void sendRaw(void * socket, void callBack(void *, char *, unsigned int, unsigned int), const char * payload, unsigned int payloadlen, unsigned int channel);
void sendRTCP(long long & connectedAt, void * socket, unsigned int tid, 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(const Packet & o);
void operator=(const Packet & o);
~Packet();
Packet(const char * dat, unsigned int len);
char * getData();
};
}

View file

@ -79,6 +79,12 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
IPC::semaphore configLock("!mistConfLock", O_CREAT | O_RDWR, ACCESSPERMS, 1);
configLock.wait();
DTSC::Scan config = DTSC::Scan(mistConfOut.mapped, mistConfOut.len);
/*LTS-START*/
if (config.getMember("hardlimit_active")) {
return false;
}
/*LTS-END*/
sanitizeName(streamname);
std::string smp = streamname.substr(0, streamname.find_first_of("+ "));
@ -89,6 +95,13 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
configLock.post();//unlock the config semaphore
return false;
}
/*LTS-START*/
if (stream_cfg.getMember("hardlimit_active")) {
return false;
}
/*LTS-END*/
//If starting without filename parameter, check if the stream is already active.
//If yes, don't activate again to prevent duplicate inputs.

View file

@ -157,14 +157,14 @@ namespace tthread {
// Get thread startup information
_thread_start_info * ti = (_thread_start_info *) aArg;
try {
//try {
// Call the actual client thread function
ti->mFunction(ti->mArg);
} catch (...) {
//} catch (...) {
// Uncaught exceptions will terminate the application (default behavior
// according to C++11)
std::terminate();
}
//std::terminate();
//}
// The thread is no longer executing
if (ti->mThread) {

View file

@ -1022,10 +1022,14 @@ namespace TS {
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
if (myMeta.tracks[*it].codec == "H264"){
PMT.setStreamType(0x1B,id);
}else if (myMeta.tracks[*it].codec == "HEVC"){
PMT.setStreamType(0x06,id);
}else if (myMeta.tracks[*it].codec == "AAC"){
PMT.setStreamType(0x0F,id);
}else if (myMeta.tracks[*it].codec == "MP3"){
PMT.setStreamType(0x03,id);
}else if (myMeta.tracks[*it].codec == "AC3"){
PMT.setStreamType(0x81,id);
}
PMT.setElementaryPID(0x100 + (*it) - 1, id);
PMT.setESInfoLength(0,id);