From 88fa62c19cf3263f296b1f0503244f22508f62d5 Mon Sep 17 00:00:00 2001 From: Oswald Auguste de Bruin Date: Mon, 9 Dec 2013 15:43:24 +0100 Subject: [PATCH] MP4 convert optimised. MP4 code sanitised Fixed metadata FLV bug Sanitised code MP4 reorganisation in lib MP4 STCO sorting only needs 1 loop now Starting big scope overhaul for memory efficiency --- lib/mp4.cpp | 4075 +------------------------------------------ lib/mp4.h | 880 +--------- lib/mp4_adobe.cpp | 928 ++++++++++ lib/mp4_adobe.h | 139 ++ lib/mp4_conv.cpp | 282 ++- lib/mp4_generic.cpp | 2878 ++++++++++++++++++++++++++++++ lib/mp4_generic.h | 674 +++++++ lib/mp4_ms.cpp | 208 +++ lib/mp4_ms.h | 40 + 9 files changed, 4997 insertions(+), 5107 deletions(-) create mode 100644 lib/mp4_adobe.cpp create mode 100644 lib/mp4_adobe.h create mode 100644 lib/mp4_generic.cpp create mode 100644 lib/mp4_generic.h create mode 100644 lib/mp4_ms.cpp create mode 100644 lib/mp4_ms.h diff --git a/lib/mp4.cpp b/lib/mp4.cpp index 93bd5b96..cec0c5a6 100644 --- a/lib/mp4.cpp +++ b/lib/mp4.cpp @@ -2,10 +2,10 @@ #include //for memcpy #include //for htonl and friends #include "mp4.h" +#include "mp4_adobe.h" +#include "mp4_ms.h" +#include "mp4_generic.h" #include "json.h" -#include "defines.h" - -#define Int64 uint64_t /// Contains all MP4 format related code. namespace MP4 { @@ -119,7 +119,7 @@ namespace MP4 { } /// Attempts to typecast this Box to a more specific type and call the toPrettyString() function of that type. - /// If this failed, it will print out a message saying pretty-printing is not implemented for that boxtype. + /// If this failed, it will print out a message saying pretty-printing is not implemented for boxtype. std::string Box::toPrettyString(uint32_t indent){ switch (ntohl( *((int*)(data + 4)))){ //type is at this address case 0x6D666864: @@ -285,7 +285,6 @@ namespace MP4 { } std::string retval = std::string(indent, ' ') + "Unimplemented pretty-printing for box " + std::string(data + 4, 4) + "\n"; /// \todo Implement hexdump for unimplemented boxes? - //retval += return retval; } @@ -413,7 +412,7 @@ namespace MP4 { /// Sets the 64 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Fails silently if resizing failed. - void Box::setInt64(Int64 newData, size_t index){ + void Box::setInt64(uint64_t newData, size_t index){ index += payloadOffset; if (index + 7 >= boxedSize()){ if ( !reserve(index, 0, 8)){ @@ -427,7 +426,7 @@ namespace MP4 { /// Gets the 64 bits integer at the given index. /// Attempts to resize the data pointer if the index is out of range. /// Returns zero if resizing failed. - Int64 Box::getInt64(size_t index){ + uint64_t Box::getInt64(size_t index){ index += payloadOffset; if (index + 7 >= boxedSize()){ if ( !reserve(index, 0, 8)){ @@ -435,7 +434,7 @@ namespace MP4 { } setInt64(0, index - payloadOffset); } - Int64 result = ntohl(((int*)(data + index))[0]); + uint64_t result = ntohl(((int*)(data + index))[0]); result <<= 32; result += ntohl(((int*)(data + index))[1]); return result; @@ -542,7 +541,7 @@ namespace MP4 { } if (current < wanted){ //make bigger - if (boxedSize() + (wanted - current) > (size_t)data_size){ + if (boxedSize() + (wanted - current) > data_size){ //realloc if managed, otherwise fail if ( !managed){ return false; @@ -640,12 +639,16 @@ namespace MP4 { return getBox(tempLoc); } - std::string containerBox::toPrettyContainerString(uint32_t indent, std::string boxName){ + std::string containerBox::toPrettyString(uint32_t indent){ std::stringstream r; - r << std::string(indent, ' ') << boxName <<" (" << boxedSize() << ")" << std::endl; - for (unsigned int i = 0; i < getContentCount(); i++){ - Box curBox = MP4::Box(getContent(i).asBox(), false); + r << std::string(indent, ' ') << "[" << getType() <<"] Container Box (" << boxedSize() << ")" << std::endl; + Box curBox; + int tempLoc = 0; + int contentCount = getContentCount(); + for (int i = 0; i < contentCount; i++){ + curBox = getContent(i); r << curBox.toPrettyString(indent + 1); + tempLoc += getBoxLen(tempLoc); } return r.str(); } @@ -684,7 +687,7 @@ namespace MP4 { return ret; } unsigned int i = 0; - unsigned int tempLoc = 4; + int tempLoc = 4; while (i < no){ tempLoc += getBoxLen(tempLoc); i++; @@ -706,4048 +709,4 @@ namespace MP4 { } return r.str(); } - - ABST::ABST(){ - memcpy(data + 4, "abst", 4); - setVersion(0); - setFlags(0); - setBootstrapinfoVersion(0); - setProfile(0); - setLive(1); - setUpdate(0); - setTimeScale(1000); - setCurrentMediaTime(0); - setSmpteTimeCodeOffset(0); - std::string empty; - setMovieIdentifier(empty); - setInt8(0, 30); //set serverentrycount to 0 - setInt8(0, 31); //set qualityentrycount to 0 - setDrmData(empty); - setMetaData(empty); - } - - void ABST::setVersion(char newVersion){ - setInt8(newVersion, 0); - } - - char ABST::getVersion(){ - return getInt8(0); - } - - void ABST::setFlags(uint32_t newFlags){ - setInt24(newFlags, 1); - } - - uint32_t ABST::getFlags(){ - return getInt24(1); - } - - void ABST::setBootstrapinfoVersion(uint32_t newVersion){ - setInt32(newVersion, 4); - } - - uint32_t ABST::getBootstrapinfoVersion(){ - return getInt32(4); - } - - void ABST::setProfile(char newProfile){ - //profile = bit 1 and 2 of byte 8. - setInt8((getInt8(8) & 0x3F) + ((newProfile & 0x03) << 6), 8); - } - - char ABST::getProfile(){ - return (getInt8(8) & 0xC0); - } - ; - - void ABST::setLive(bool newLive){ - //live = bit 4 of byte 8. - setInt8((getInt8(8) & 0xDF) + (newLive ? 0x10 : 0), 8); - } - - bool ABST::getLive(){ - return (getInt8(8) & 0x10); - } - - void ABST::setUpdate(bool newUpdate){ - //update = bit 5 of byte 8. - setInt8((getInt8(8) & 0xEF) + (newUpdate ? 0x08 : 0), 8); - } - - bool ABST::getUpdate(){ - return (getInt8(8) & 0x08); - } - - void ABST::setTimeScale(uint32_t newScale){ - setInt32(newScale, 9); - } - - uint32_t ABST::getTimeScale(){ - return getInt32(9); - } - - void ABST::setCurrentMediaTime(Int64 newTime){ - setInt64(newTime, 13); - } - - Int64 ABST::getCurrentMediaTime(){ - return getInt64(13); - } - - void ABST::setSmpteTimeCodeOffset(Int64 newTime){ - setInt64(newTime, 21); - } - - Int64 ABST::getSmpteTimeCodeOffset(){ - return getInt64(21); - } - - void ABST::setMovieIdentifier(std::string & newIdentifier){ - setString(newIdentifier, 29); - } - - char* ABST::getMovieIdentifier(){ - return getString(29); - } - - uint32_t ABST::getServerEntryCount(){ - int countLoc = 29 + getStringLen(29) + 1; - return getInt8(countLoc); - } - - void ABST::setServerEntry(std::string & newEntry, uint32_t no){ - int countLoc = 29 + getStringLen(29) + 1; - int tempLoc = countLoc + 1; - //attempt to reach the wanted position - unsigned int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no + 1 > getInt8(countLoc)){ - int amount = no + 1 - getInt8(countLoc); - if ( !reserve(payloadOffset + tempLoc, 0, amount)){ - return; - }; - memset(data + payloadOffset + tempLoc, 0, amount); - setInt8(no + 1, countLoc); //set new qualityEntryCount - tempLoc += no - i; - } - //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. - setString(newEntry, tempLoc); - } - - ///\return Empty string if no > serverEntryCount(), serverEntry[no] otherwise. - const char* ABST::getServerEntry(uint32_t no){ - if (no + 1 > getServerEntryCount()){ - return ""; - } - int tempLoc = 29 + getStringLen(29) + 1 + 1; //position of first entry - for (unsigned int i = 0; i < no; i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getString(tempLoc); - } - - uint32_t ABST::getQualityEntryCount(){ - int countLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - countLoc += getStringLen(countLoc) + 1; - } - return getInt8(countLoc); - } - - void ABST::setQualityEntry(std::string & newEntry, uint32_t no){ - int countLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - countLoc += getStringLen(countLoc) + 1; - } - int tempLoc = countLoc + 1; - //attempt to reach the wanted position - unsigned int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no + 1 > getInt8(countLoc)){ - int amount = no + 1 - getInt8(countLoc); - if ( !reserve(payloadOffset + tempLoc, 0, amount)){ - return; - }; - memset(data + payloadOffset + tempLoc, 0, amount); - setInt8(no + 1, countLoc); //set new qualityEntryCount - tempLoc += no - i; - } - //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. - setString(newEntry, tempLoc); - } - - const char* ABST::getQualityEntry(uint32_t no){ - if (no > getQualityEntryCount()){ - return ""; - } - int tempLoc = 29 + getStringLen(29) + 1 + 1; //position of serverentries; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += 1; //first qualityentry - for (unsigned int i = 0; i < no; i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getString(tempLoc); - } - - void ABST::setDrmData(std::string newDrm){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - setString(newDrm, tempLoc); - } - - char* ABST::getDrmData(){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getString(tempLoc); - } - - void ABST::setMetaData(std::string newMetaData){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; - setString(newMetaData, tempLoc); - } - - char* ABST::getMetaData(){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; - return getString(tempLoc); - } - - uint32_t ABST::getSegmentRunTableCount(){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; //DrmData - tempLoc += getStringLen(tempLoc) + 1; //MetaData - return getInt8(tempLoc); - } - - void ABST::setSegmentRunTable(ASRT & newSegment, uint32_t no){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; //DrmData - tempLoc += getStringLen(tempLoc) + 1; //MetaData - int countLoc = tempLoc; - tempLoc++; //skip segmentRuntableCount - //attempt to reach the wanted position - unsigned int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){ - tempLoc += getBoxLen(tempLoc); - } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no + 1 > getInt8(countLoc)){ - int amount = no + 1 - getInt8(countLoc); - if ( !reserve(payloadOffset + tempLoc, 0, amount * 8)){ - return; - }; - //set empty erro boxes as contents - for (int j = 0; j < amount; ++j){ - memcpy(data + payloadOffset + tempLoc + j * 8, "\000\000\000\010erro", 8); - } - setInt8(no + 1, countLoc); //set new count - tempLoc += (no - i) * 8; - } - //now, tempLoc is at position for string number no, and we have at least an erro box reserved. - setBox(newSegment, tempLoc); - } - - ASRT & ABST::getSegmentRunTable(uint32_t no){ - static Box result; - if (no > getSegmentRunTableCount()){ - static Box res; - return (ASRT&)res; - } - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; //DrmData - tempLoc += getStringLen(tempLoc) + 1; //MetaData - tempLoc++; //segmentRuntableCount - for (unsigned int i = 0; i < no; ++i){ - tempLoc += getBoxLen(tempLoc); - } - return (ASRT&)getBox(tempLoc); - } - - uint32_t ABST::getFragmentRunTableCount(){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; //DrmData - tempLoc += getStringLen(tempLoc) + 1; //MetaData - for (unsigned int i = getInt8(tempLoc++); i != 0; --i){ - tempLoc += getBoxLen(tempLoc); - } - return getInt8(tempLoc); - } - - void ABST::setFragmentRunTable(AFRT & newFragment, uint32_t no){ - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; //DrmData - tempLoc += getStringLen(tempLoc) + 1; //MetaData - for (unsigned int i = getInt8(tempLoc++); i != 0; --i){ - tempLoc += getBoxLen(tempLoc); - } - int countLoc = tempLoc; - tempLoc++; - //attempt to reach the wanted position - unsigned int i; - for (i = 0; i < getInt8(countLoc) && i < no; ++i){ - tempLoc += getBoxLen(tempLoc); - } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no + 1 > getInt8(countLoc)){ - unsigned int amount = no + 1 - getInt8(countLoc); - if ( !reserve(payloadOffset + tempLoc, 0, amount * 8)){ - return; - }; - //set empty erro boxes as contents - for (unsigned int j = 0; j < amount; ++j){ - memcpy(data + payloadOffset + tempLoc + j * 8, "\000\000\000\010erro", 8); - } - setInt8(no + 1, countLoc); //set new count - tempLoc += (no - i) * 8; - } - //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. - setBox(newFragment, tempLoc); - } - - AFRT & ABST::getFragmentRunTable(uint32_t no){ - static Box result; - if (no >= getFragmentRunTableCount()){ - static Box res; - return (AFRT&)res; - } - uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc++; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += getStringLen(tempLoc) + 1; //DrmData - tempLoc += getStringLen(tempLoc) + 1; //MetaData - for (unsigned int i = getInt8(tempLoc++); i != 0; --i){ - tempLoc += getBoxLen(tempLoc); - } - tempLoc++; - for (unsigned int i = 0; i < no; i++){ - tempLoc += getBoxLen(tempLoc); - } - return (AFRT&)getBox(tempLoc); - } - - std::string ABST::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[abst] Bootstrap Info (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version " << (int)getVersion() << std::endl; - r << std::string(indent + 1, ' ') << "BootstrapinfoVersion " << getBootstrapinfoVersion() << std::endl; - r << std::string(indent + 1, ' ') << "Profile " << (int)getProfile() << std::endl; - if (getLive()){ - r << std::string(indent + 1, ' ') << "Live" << std::endl; - }else{ - r << std::string(indent + 1, ' ') << "Recorded" << std::endl; - } - if (getUpdate()){ - r << std::string(indent + 1, ' ') << "Update" << std::endl; - }else{ - r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; - } - r << std::string(indent + 1, ' ') << "Timescale " << getTimeScale() << std::endl; - r << std::string(indent + 1, ' ') << "CurrMediaTime " << getCurrentMediaTime() << std::endl; - r << std::string(indent + 1, ' ') << "SmpteTimeCodeOffset " << getSmpteTimeCodeOffset() << std::endl; - r << std::string(indent + 1, ' ') << "MovieIdentifier " << getMovieIdentifier() << std::endl; - r << std::string(indent + 1, ' ') << "ServerEntryTable (" << getServerEntryCount() << ")" << std::endl; - for (unsigned int i = 0; i < getServerEntryCount(); i++){ - r << std::string(indent + 2, ' ') << i << ": " << getServerEntry(i) << std::endl; - } - r << std::string(indent + 1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; - } - r << std::string(indent + 1, ' ') << "DrmData " << getDrmData() << std::endl; - r << std::string(indent + 1, ' ') << "MetaData " << getMetaData() << std::endl; - r << std::string(indent + 1, ' ') << "SegmentRunTableEntries (" << getSegmentRunTableCount() << ")" << std::endl; - for (uint32_t i = 0; i < getSegmentRunTableCount(); i++){ - r << ((Box)getSegmentRunTable(i)).toPrettyString(indent + 2); - } - r << std::string(indent + 1, ' ') + "FragmentRunTableEntries (" << getFragmentRunTableCount() << ")" << std::endl; - for (uint32_t i = 0; i < getFragmentRunTableCount(); i++){ - r << ((Box)getFragmentRunTable(i)).toPrettyString(indent + 2); - } - return r.str(); - } - - AFRT::AFRT(){ - memcpy(data + 4, "afrt", 4); - setVersion(0); - setUpdate(0); - setTimeScale(1000); - } - - void AFRT::setVersion(char newVersion){ - setInt8(newVersion, 0); - } - - uint32_t AFRT::getVersion(){ - return getInt8(0); - } - - void AFRT::setUpdate(uint32_t newUpdate){ - setInt24(newUpdate, 1); - } - - uint32_t AFRT::getUpdate(){ - return getInt24(1); - } - - void AFRT::setTimeScale(uint32_t newScale){ - setInt32(newScale, 4); - } - - uint32_t AFRT::getTimeScale(){ - return getInt32(4); - } - - uint32_t AFRT::getQualityEntryCount(){ - return getInt8(8); - } - - void AFRT::setQualityEntry(std::string & newEntry, uint32_t no){ - int countLoc = 8; - int tempLoc = countLoc + 1; - //attempt to reach the wanted position - unsigned int i; - for (i = 0; i < getQualityEntryCount() && i < no; ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no + 1 > getQualityEntryCount()){ - int amount = no + 1 - getQualityEntryCount(); - if ( !reserve(payloadOffset + tempLoc, 0, amount)){ - return; - }; - memset(data + payloadOffset + tempLoc, 0, amount); - setInt8(no + 1, countLoc); //set new qualityEntryCount - tempLoc += no - i; - } - //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. - setString(newEntry, tempLoc); - } - - const char* AFRT::getQualityEntry(uint32_t no){ - if (no + 1 > getQualityEntryCount()){ - return ""; - } - int tempLoc = 9; //position of first quality entry - for (unsigned int i = 0; i < no; i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getString(tempLoc); - } - - uint32_t AFRT::getFragmentRunCount(){ - int tempLoc = 9; - for (unsigned int i = 0; i < getQualityEntryCount(); ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getInt32(tempLoc); - } - - void AFRT::setFragmentRun(afrt_runtable newRun, uint32_t no){ - int tempLoc = 9; - for (unsigned int i = 0; i < getQualityEntryCount(); ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - int countLoc = tempLoc; - tempLoc += 4; - for (unsigned int i = 0; i < no; i++){ - if (i + 1 > getInt32(countLoc)){ - setInt32(0, tempLoc); - setInt64(0, tempLoc + 4); - setInt32(1, tempLoc + 12); - } - if (getInt32(tempLoc + 12) == 0){ - tempLoc += 17; - }else{ - tempLoc += 16; - } - } - setInt32(newRun.firstFragment, tempLoc); - setInt64(newRun.firstTimestamp, tempLoc + 4); - setInt32(newRun.duration, tempLoc + 12); - if (newRun.duration == 0){ - setInt8(newRun.discontinuity, tempLoc + 16); - } - if (getInt32(countLoc) < no + 1){ - setInt32(no + 1, countLoc); - } - } - - afrt_runtable AFRT::getFragmentRun(uint32_t no){ - afrt_runtable res; - if (no > getFragmentRunCount()){ - return res; - } - int tempLoc = 9; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += 4; - for (unsigned int i = 0; i < no; i++){ - if (getInt32(tempLoc + 12) == 0){ - tempLoc += 17; - }else{ - tempLoc += 16; - } - } - res.firstFragment = getInt32(tempLoc); - res.firstTimestamp = getInt64(tempLoc + 4); - res.duration = getInt32(tempLoc + 12); - if (res.duration){ - res.discontinuity = getInt8(tempLoc + 16); - }else{ - res.discontinuity = 0; - } - return res; - } - - std::string AFRT::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[afrt] Fragment Run Table (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version " << (int)getVersion() << std::endl; - if (getUpdate()){ - r << std::string(indent + 1, ' ') << "Update" << std::endl; - }else{ - r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; - } - r << std::string(indent + 1, ' ') << "Timescale " << getTimeScale() << std::endl; - r << std::string(indent + 1, ' ') << "QualitySegmentUrlModifiers (" << getQualityEntryCount() << ")" << std::endl; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; - } - r << std::string(indent + 1, ' ') << "FragmentRunEntryTable (" << getFragmentRunCount() << ")" << std::endl; - for (unsigned int i = 0; i < getFragmentRunCount(); i++){ - afrt_runtable myRun = getFragmentRun(i); - if (myRun.duration){ - r << std::string(indent + 2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) - << "s, " << ((double)myRun.duration / (double)getTimeScale()) << "s per fragment." << std::endl; - }else{ - r << std::string(indent + 2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) - << "s, discontinuity type " << myRun.discontinuity << std::endl; - } - } - return r.str(); - } - - ASRT::ASRT(){ - memcpy(data + 4, "asrt", 4); - setVersion(0); - setUpdate(0); - } - - void ASRT::setVersion(char newVersion){ - setInt8(newVersion, 0); - } - - uint32_t ASRT::getVersion(){ - return getInt8(0); - } - - void ASRT::setUpdate(uint32_t newUpdate){ - setInt24(newUpdate, 1); - } - - uint32_t ASRT::getUpdate(){ - return getInt24(1); - } - - uint32_t ASRT::getQualityEntryCount(){ - return getInt8(4); - } - - void ASRT::setQualityEntry(std::string & newEntry, uint32_t no){ - int countLoc = 4; - int tempLoc = countLoc + 1; - //attempt to reach the wanted position - unsigned int i; - for (i = 0; i < getQualityEntryCount() && i < no; ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - //we are now either at the end, or at the right position - //let's reserve any unreserved space... - if (no + 1 > getQualityEntryCount()){ - int amount = no + 1 - getQualityEntryCount(); - if ( !reserve(payloadOffset + tempLoc, 0, amount)){ - return; - }; - memset(data + payloadOffset + tempLoc, 0, amount); - setInt8(no + 1, countLoc); //set new qualityEntryCount - tempLoc += no - i; - } - //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. - setString(newEntry, tempLoc); - } - - const char* ASRT::getQualityEntry(uint32_t no){ - if (no > getQualityEntryCount()){ - return ""; - } - int tempLoc = 5; //position of qualityentry count; - for (unsigned int i = 0; i < no; i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getString(tempLoc); - } - - uint32_t ASRT::getSegmentRunEntryCount(){ - int tempLoc = 5; //position of qualityentry count; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - return getInt32(tempLoc); - } - - void ASRT::setSegmentRun(uint32_t firstSegment, uint32_t fragmentsPerSegment, uint32_t no){ - int tempLoc = 5; //position of qualityentry count; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - tempLoc += getStringLen(tempLoc) + 1; - } - int countLoc = tempLoc; - tempLoc += 4 + no * 8; - if (no + 1 > getInt32(countLoc)){ - setInt32(no + 1, countLoc); //set new qualityEntryCount - } - setInt32(firstSegment, tempLoc); - setInt32(fragmentsPerSegment, tempLoc + 4); - } - - asrt_runtable ASRT::getSegmentRun(uint32_t no){ - asrt_runtable res; - if (no >= getSegmentRunEntryCount()){ - return res; - } - int tempLoc = 5; //position of qualityentry count; - for (unsigned int i = 0; i < getQualityEntryCount(); ++i){ - tempLoc += getStringLen(tempLoc) + 1; - } - tempLoc += 4 + 8 * no; - res.firstSegment = getInt32(tempLoc); - res.fragmentsPerSegment = getInt32(tempLoc + 4); - return res; - } - - std::string ASRT::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[asrt] Segment Run Table (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version " << getVersion() << std::endl; - if (getUpdate()){ - r << std::string(indent + 1, ' ') << "Update" << std::endl; - }else{ - r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; - } - r << std::string(indent + 1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; - for (unsigned int i = 0; i < getQualityEntryCount(); i++){ - r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; - } - r << std::string(indent + 1, ' ') << "SegmentRunEntryTable (" << getSegmentRunEntryCount() << ")" << std::endl; - for (unsigned int i = 0; i < getSegmentRunEntryCount(); i++){ - r << std::string(indent + 2, ' ') << i << ": First=" << getSegmentRun(i).firstSegment << ", FragmentsPerSegment=" - << getSegmentRun(i).fragmentsPerSegment << std::endl; - } - return r.str(); - } - - MFHD::MFHD(){ - memcpy(data + 4, "mfhd", 4); - setInt32(0, 0); - } - - void MFHD::setSequenceNumber(uint32_t newSequenceNumber){ - setInt32(newSequenceNumber, 4); - } - - uint32_t MFHD::getSequenceNumber(){ - return getInt32(4); - } - - std::string MFHD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[mfhd] Movie Fragment Header (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "SequenceNumber " << getSequenceNumber() << std::endl; - return r.str(); - } - - MOOF::MOOF(){ - memcpy(data + 4, "moof", 4); - } - - std::string MOOF::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[moof] Movie Fragment Box")); - } - - TRAF::TRAF(){ - memcpy(data + 4, "traf", 4); - } - - uint32_t TRAF::getContentCount(){ - int res = 0; - unsigned int tempLoc = 0; - while (tempLoc < boxedSize() - 8){ - res++; - tempLoc += getBoxLen(tempLoc); - } - return res; - } - - void TRAF::setContent(Box & newContent, uint32_t no){ - int tempLoc = 0; - unsigned int contentCount = getContentCount(); - for (unsigned int i = 0; i < no; i++){ - if (i < contentCount){ - tempLoc += getBoxLen(tempLoc); - }else{ - if ( !reserve(tempLoc, 0, (no - contentCount) * 8)){ - return; - }; - memset(data + tempLoc, 0, (no - contentCount) * 8); - tempLoc += (no - contentCount) * 8; - break; - } - } - setBox(newContent, tempLoc); - } - - Box & TRAF::getContent(uint32_t no){ - static Box ret = Box((char*)"\000\000\000\010erro", false); - if (no > getContentCount()){ - return ret; - } - unsigned int i = 0; - int tempLoc = 0; - while (i < no){ - tempLoc += getBoxLen(tempLoc); - i++; - } - return getBox(tempLoc); - } - - std::string TRAF::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[traf] Track Fragment Box (" << boxedSize() << ")" << std::endl; - int contentCount = getContentCount(); - for (int i = 0; i < contentCount; i++){ - Box curBox = Box(getContent(i).asBox(),false); - r << curBox.toPrettyString(indent + 1); - } - return r.str(); - } - - TRUN::TRUN(){ - memcpy(data + 4, "trun", 4); - } - - void TRUN::setFlags(uint32_t newFlags){ - setInt24(newFlags, 1); - } - - uint32_t TRUN::getFlags(){ - return getInt24(1); - } - - void TRUN::setDataOffset(uint32_t newOffset){ - if (getFlags() & trundataOffset){ - setInt32(newOffset, 8); - } - } - - uint32_t TRUN::getDataOffset(){ - if (getFlags() & trundataOffset){ - return getInt32(8); - }else{ - return 0; - } - } - - void TRUN::setFirstSampleFlags(uint32_t newSampleFlags){ - if ( !(getFlags() & trunfirstSampleFlags)){ - return; - } - if (getFlags() & trundataOffset){ - setInt32(newSampleFlags, 12); - }else{ - setInt32(newSampleFlags, 8); - } - } - - uint32_t TRUN::getFirstSampleFlags(){ - if ( !(getFlags() & trunfirstSampleFlags)){ - return 0; - } - if (getFlags() & trundataOffset){ - return getInt32(12); - }else{ - return getInt32(8); - } - } - - uint32_t TRUN::getSampleInformationCount(){ - return getInt32(4); - } - - void TRUN::setSampleInformation(trunSampleInformation newSample, uint32_t no){ - uint32_t flags = getFlags(); - uint32_t sampInfoSize = 0; - if (flags & trunsampleDuration){ - sampInfoSize += 4; - } - if (flags & trunsampleSize){ - sampInfoSize += 4; - } - if (flags & trunsampleFlags){ - sampInfoSize += 4; - } - if (flags & trunsampleOffsets){ - sampInfoSize += 4; - } - uint32_t offset = 8; - if (flags & trundataOffset){ - offset += 4; - } - if (flags & trunfirstSampleFlags){ - offset += 4; - } - uint32_t innerOffset = 0; - if (flags & trunsampleDuration){ - setInt32(newSample.sampleDuration, offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (flags & trunsampleSize){ - setInt32(newSample.sampleSize, offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (flags & trunsampleFlags){ - setInt32(newSample.sampleFlags, offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (flags & trunsampleOffsets){ - setInt32(newSample.sampleOffset, offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (getSampleInformationCount() < no + 1){ - setInt32(no + 1, 4); - } - } - - trunSampleInformation TRUN::getSampleInformation(uint32_t no){ - trunSampleInformation ret; - ret.sampleDuration = 0; - ret.sampleSize = 0; - ret.sampleFlags = 0; - ret.sampleOffset = 0; - if (getSampleInformationCount() < no + 1){ - return ret; - } - uint32_t flags = getFlags(); - uint32_t sampInfoSize = 0; - if (flags & trunsampleDuration){ - sampInfoSize += 4; - } - if (flags & trunsampleSize){ - sampInfoSize += 4; - } - if (flags & trunsampleFlags){ - sampInfoSize += 4; - } - if (flags & trunsampleOffsets){ - sampInfoSize += 4; - } - uint32_t offset = 8; - if (flags & trundataOffset){ - offset += 4; - } - if (flags & trunfirstSampleFlags){ - offset += 4; - } - uint32_t innerOffset = 0; - if (flags & trunsampleDuration){ - ret.sampleDuration = getInt32(offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (flags & trunsampleSize){ - ret.sampleSize = getInt32(offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (flags & trunsampleFlags){ - ret.sampleFlags = getInt32(offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - if (flags & trunsampleOffsets){ - ret.sampleOffset = getInt32(offset + no * sampInfoSize + innerOffset); - innerOffset += 4; - } - return ret; - } - - std::string TRUN::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[trun] Track Fragment Run (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version " << (int)getInt8(0) << std::endl; - - uint32_t flags = getFlags(); - r << std::string(indent + 1, ' ') << "Flags"; - if (flags & trundataOffset){ - r << " dataOffset"; - } - if (flags & trunfirstSampleFlags){ - r << " firstSampleFlags"; - } - if (flags & trunsampleDuration){ - r << " sampleDuration"; - } - if (flags & trunsampleSize){ - r << " sampleSize"; - } - if (flags & trunsampleFlags){ - r << " sampleFlags"; - } - if (flags & trunsampleOffsets){ - r << " sampleOffsets"; - } - r << std::endl; - - if (flags & trundataOffset){ - r << std::string(indent + 1, ' ') << "Data Offset " << getDataOffset() << std::endl; - } - if (flags & trundataOffset){ - r << std::string(indent + 1, ' ') << "Sample Flags" << prettySampleFlags(getFirstSampleFlags()) << std::endl; - } - - r << std::string(indent + 1, ' ') << "SampleInformation (" << getSampleInformationCount() << "):" << std::endl; - for (unsigned int i = 0; i < getSampleInformationCount(); ++i){ - r << std::string(indent + 2, ' ') << "[" << i << "] "; - trunSampleInformation samp = getSampleInformation(i); - if (flags & trunsampleDuration){ - r << "Duration=" << samp.sampleDuration << " "; - } - if (flags & trunsampleSize){ - r << "Size=" << samp.sampleSize << " "; - } - if (flags & trunsampleFlags){ - r << "Flags=" << prettySampleFlags(samp.sampleFlags) << " "; - } - if (flags & trunsampleOffsets){ - r << "Offset=" << samp.sampleOffset << " "; - } - r << std::endl; - } - - return r.str(); - } - - std::string prettySampleFlags(uint32_t flag){ - std::stringstream r; - if (flag & noIPicture){ - r << " noIPicture"; - } - if (flag & isIPicture){ - r << " isIPicture"; - } - if (flag & noDisposable){ - r << " noDisposable"; - } - if (flag & isDisposable){ - r << " isDisposable"; - } - if (flag & isRedundant){ - r << " isRedundant"; - } - if (flag & noRedundant){ - r << " noRedundant"; - } - if (flag & noKeySample){ - r << " noKeySample"; - }else{ - r << " isKeySample"; - } - return r.str(); - } - - TFHD::TFHD(){ - memcpy(data + 4, "tfhd", 4); - } - - void TFHD::setFlags(uint32_t newFlags){ - setInt24(newFlags, 1); - } - - uint32_t TFHD::getFlags(){ - return getInt24(1); - } - - void TFHD::setTrackID(uint32_t newID){ - setInt32(newID, 4); - } - - uint32_t TFHD::getTrackID(){ - return getInt32(4); - } - - void TFHD::setBaseDataOffset(uint64_t newOffset){ - if (getFlags() & tfhdBaseOffset){ - setInt64(newOffset, 8); - } - } - - uint64_t TFHD::getBaseDataOffset(){ - if (getFlags() & tfhdBaseOffset){ - return getInt64(8); - }else{ - return 0; - } - } - - void TFHD::setSampleDescriptionIndex(uint32_t newIndex){ - if ( !(getFlags() & tfhdSampleDesc)){ - return; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - setInt32(newIndex, offset); - } - - uint32_t TFHD::getSampleDescriptionIndex(){ - if ( !(getFlags() & tfhdSampleDesc)){ - return 0; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - return getInt32(offset); - } - - void TFHD::setDefaultSampleDuration(uint32_t newDuration){ - if ( !(getFlags() & tfhdSampleDura)){ - return; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - if (getFlags() & tfhdSampleDesc){ - offset += 4; - } - setInt32(newDuration, offset); - } - - uint32_t TFHD::getDefaultSampleDuration(){ - if ( !(getFlags() & tfhdSampleDura)){ - return 0; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - if (getFlags() & tfhdSampleDesc){ - offset += 4; - } - return getInt32(offset); - } - - void TFHD::setDefaultSampleSize(uint32_t newSize){ - if ( !(getFlags() & tfhdSampleSize)){ - return; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - if (getFlags() & tfhdSampleDesc){ - offset += 4; - } - if (getFlags() & tfhdSampleDura){ - offset += 4; - } - setInt32(newSize, offset); - } - - uint32_t TFHD::getDefaultSampleSize(){ - if ( !(getFlags() & tfhdSampleSize)){ - return 0; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - if (getFlags() & tfhdSampleDesc){ - offset += 4; - } - if (getFlags() & tfhdSampleDura){ - offset += 4; - } - return getInt32(offset); - } - - void TFHD::setDefaultSampleFlags(uint32_t newFlags){ - if ( !(getFlags() & tfhdSampleFlag)){ - return; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - if (getFlags() & tfhdSampleDesc){ - offset += 4; - } - if (getFlags() & tfhdSampleDura){ - offset += 4; - } - if (getFlags() & tfhdSampleSize){ - offset += 4; - } - setInt32(newFlags, offset); - } - - uint32_t TFHD::getDefaultSampleFlags(){ - if ( !(getFlags() & tfhdSampleFlag)){ - return 0; - } - int offset = 8; - if (getFlags() & tfhdBaseOffset){ - offset += 8; - } - if (getFlags() & tfhdSampleDesc){ - offset += 4; - } - if (getFlags() & tfhdSampleDura){ - offset += 4; - } - if (getFlags() & tfhdSampleSize){ - offset += 4; - } - return getInt32(offset); - } - - std::string TFHD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[tfhd] Track Fragment Header (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version " << (int)getInt8(0) << std::endl; - - uint32_t flags = getFlags(); - r << std::string(indent + 1, ' ') << "Flags"; - if (flags & tfhdBaseOffset){ - r << " BaseOffset"; - } - if (flags & tfhdSampleDesc){ - r << " SampleDesc"; - } - if (flags & tfhdSampleDura){ - r << " SampleDura"; - } - if (flags & tfhdSampleSize){ - r << " SampleSize"; - } - if (flags & tfhdSampleFlag){ - r << " SampleFlag"; - } - if (flags & tfhdNoDuration){ - r << " NoDuration"; - } - r << std::endl; - - r << std::string(indent + 1, ' ') << "TrackID " << getTrackID() << std::endl; - - if (flags & tfhdBaseOffset){ - r << std::string(indent + 1, ' ') << "Base Offset " << getBaseDataOffset() << std::endl; - } - if (flags & tfhdSampleDesc){ - r << std::string(indent + 1, ' ') << "Sample Description Index " << getSampleDescriptionIndex() << std::endl; - } - if (flags & tfhdSampleDura){ - r << std::string(indent + 1, ' ') << "Default Sample Duration " << getDefaultSampleDuration() << std::endl; - } - if (flags & tfhdSampleSize){ - r << std::string(indent + 1, ' ') << "Default Same Size " << getDefaultSampleSize() << std::endl; - } - if (flags & tfhdSampleFlag){ - r << std::string(indent + 1, ' ') << "Default Sample Flags " << prettySampleFlags(getDefaultSampleFlags()) << std::endl; - } - - return r.str(); - } - - AFRA::AFRA(){ - memcpy(data + 4, "afra", 4); - setInt32(0, 9); //entrycount = 0 - setFlags(0); - } - - void AFRA::setVersion(uint32_t newVersion){ - setInt8(newVersion, 0); - } - - uint32_t AFRA::getVersion(){ - return getInt8(0); - } - - void AFRA::setFlags(uint32_t newFlags){ - setInt24(newFlags, 1); - } - - uint32_t AFRA::getFlags(){ - return getInt24(1); - } - - void AFRA::setLongIDs(bool newVal){ - if (newVal){ - setInt8((getInt8(4) & 0x7F) + 0x80, 4); - }else{ - setInt8((getInt8(4) & 0x7F), 4); - } - } - - bool AFRA::getLongIDs(){ - return getInt8(4) & 0x80; - } - - void AFRA::setLongOffsets(bool newVal){ - if (newVal){ - setInt8((getInt8(4) & 0xBF) + 0x40, 4); - }else{ - setInt8((getInt8(4) & 0xBF), 4); - } - } - - bool AFRA::getLongOffsets(){ - return getInt8(4) & 0x40; - } - - void AFRA::setGlobalEntries(bool newVal){ - if (newVal){ - setInt8((getInt8(4) & 0xDF) + 0x20, 4); - }else{ - setInt8((getInt8(4) & 0xDF), 4); - } - } - - bool AFRA::getGlobalEntries(){ - return getInt8(4) & 0x20; - } - - void AFRA::setTimeScale(uint32_t newVal){ - setInt32(newVal, 5); - } - - uint32_t AFRA::getTimeScale(){ - return getInt32(5); - } - - uint32_t AFRA::getEntryCount(){ - return getInt32(9); - } - - void AFRA::setEntry(afraentry newEntry, uint32_t no){ - int entrysize = 12; - if (getLongOffsets()){ - entrysize = 16; - } - setInt64(newEntry.time, 13 + entrysize * no); - if (getLongOffsets()){ - setInt64(newEntry.offset, 21 + entrysize * no); - }else{ - setInt32(newEntry.offset, 21 + entrysize * no); - } - if (no + 1 > getEntryCount()){ - setInt32(no + 1, 9); - } - } - - afraentry AFRA::getEntry(uint32_t no){ - afraentry ret; - int entrysize = 12; - if (getLongOffsets()){ - entrysize = 16; - } - ret.time = getInt64(13 + entrysize * no); - if (getLongOffsets()){ - ret.offset = getInt64(21 + entrysize * no); - }else{ - ret.offset = getInt32(21 + entrysize * no); - } - return ret; - } - - uint32_t AFRA::getGlobalEntryCount(){ - if ( !getGlobalEntries()){ - return 0; - } - int entrysize = 12; - if (getLongOffsets()){ - entrysize = 16; - } - return getInt32(13 + entrysize * getEntryCount()); - } - - void AFRA::setGlobalEntry(globalafraentry newEntry, uint32_t no){ - int offset = 13 + 12 * getEntryCount() + 4; - if (getLongOffsets()){ - offset = 13 + 16 * getEntryCount() + 4; - } - int entrysize = 20; - if (getLongIDs()){ - entrysize += 4; - } - if (getLongOffsets()){ - entrysize += 8; - } - - setInt64(newEntry.time, offset + entrysize * no); - if (getLongIDs()){ - setInt32(newEntry.segment, offset + entrysize * no + 8); - setInt32(newEntry.fragment, offset + entrysize * no + 12); - }else{ - setInt16(newEntry.segment, offset + entrysize * no + 8); - setInt16(newEntry.fragment, offset + entrysize * no + 10); - } - if (getLongOffsets()){ - setInt64(newEntry.afraoffset, offset + entrysize * no + entrysize - 16); - setInt64(newEntry.offsetfromafra, offset + entrysize * no + entrysize - 8); - }else{ - setInt32(newEntry.afraoffset, offset + entrysize * no + entrysize - 8); - setInt32(newEntry.offsetfromafra, offset + entrysize * no + entrysize - 4); - } - - if (getInt32(offset - 4) < no + 1){ - setInt32(no + 1, offset - 4); - } - } - - globalafraentry AFRA::getGlobalEntry(uint32_t no){ - globalafraentry ret; - int offset = 13 + 12 * getEntryCount() + 4; - if (getLongOffsets()){ - offset = 13 + 16 * getEntryCount() + 4; - } - int entrysize = 20; - if (getLongIDs()){ - entrysize += 4; - } - if (getLongOffsets()){ - entrysize += 8; - } - - ret.time = getInt64(offset + entrysize * no); - if (getLongIDs()){ - ret.segment = getInt32(offset + entrysize * no + 8); - ret.fragment = getInt32(offset + entrysize * no + 12); - }else{ - ret.segment = getInt16(offset + entrysize * no + 8); - ret.fragment = getInt16(offset + entrysize * no + 10); - } - if (getLongOffsets()){ - ret.afraoffset = getInt64(offset + entrysize * no + entrysize - 16); - ret.offsetfromafra = getInt64(offset + entrysize * no + entrysize - 8); - }else{ - ret.afraoffset = getInt32(offset + entrysize * no + entrysize - 8); - ret.offsetfromafra = getInt32(offset + entrysize * no + entrysize - 4); - } - return ret; - } - - std::string AFRA::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[afra] Fragment Random Access (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version " << getVersion() << std::endl; - r << std::string(indent + 1, ' ') << "Flags " << getFlags() << std::endl; - r << std::string(indent + 1, ' ') << "Long IDs " << getLongIDs() << std::endl; - r << std::string(indent + 1, ' ') << "Long Offsets " << getLongOffsets() << std::endl; - r << std::string(indent + 1, ' ') << "Global Entries " << getGlobalEntries() << std::endl; - r << std::string(indent + 1, ' ') << "TimeScale " << getTimeScale() << std::endl; - - uint32_t count = getEntryCount(); - r << std::string(indent + 1, ' ') << "Entries (" << count << ") " << std::endl; - for (uint32_t i = 0; i < count; ++i){ - afraentry tmpent = getEntry(i); - r << std::string(indent + 1, ' ') << i << ": Time " << tmpent.time << ", Offset " << tmpent.offset << std::endl; - } - - if (getGlobalEntries()){ - count = getGlobalEntryCount(); - r << std::string(indent + 1, ' ') << "Global Entries (" << count << ") " << std::endl; - for (uint32_t i = 0; i < count; ++i){ - globalafraentry tmpent = getGlobalEntry(i); - r << std::string(indent + 1, ' ') << i << ": T " << tmpent.time << ", S" << tmpent.segment << "F" << tmpent.fragment << ", " - << tmpent.afraoffset << "/" << tmpent.offsetfromafra << std::endl; - } - } - - return r.str(); - } - - AVCC::AVCC(){ - memcpy(data + 4, "avcC", 4); - setInt8(0xFF, 4); //reserved + 4-bytes NAL length - } - - void AVCC::setVersion(uint32_t newVersion){ - setInt8(newVersion, 0); - } - - uint32_t AVCC::getVersion(){ - return getInt8(0); - } - - void AVCC::setProfile(uint32_t newProfile){ - setInt8(newProfile, 1); - } - - uint32_t AVCC::getProfile(){ - return getInt8(1); - } - - void AVCC::setCompatibleProfiles(uint32_t newCompatibleProfiles){ - setInt8(newCompatibleProfiles, 2); - } - - uint32_t AVCC::getCompatibleProfiles(){ - return getInt8(2); - } - - void AVCC::setLevel(uint32_t newLevel){ - setInt8(newLevel, 3); - } - - uint32_t AVCC::getLevel(){ - return getInt8(3); - } - - void AVCC::setSPSNumber(uint32_t newSPSNumber){ - setInt8(newSPSNumber, 5); - } - - uint32_t AVCC::getSPSNumber(){ - return getInt8(5); - } - - void AVCC::setSPS(std::string newSPS){ - setInt16(newSPS.size(), 6); - for (unsigned int i = 0; i < newSPS.size(); i++){ - setInt8(newSPS[i], 8 + i); - } //not null-terminated - } - - uint32_t AVCC::getSPSLen(){ - return getInt16(6); - } - - char* AVCC::getSPS(){ - return payload() + 8; - } - - void AVCC::setPPSNumber(uint32_t newPPSNumber){ - int offset = 8 + getSPSLen(); - setInt8(newPPSNumber, offset); - } - - uint32_t AVCC::getPPSNumber(){ - int offset = 8 + getSPSLen(); - return getInt8(offset); - } - - void AVCC::setPPS(std::string newPPS){ - int offset = 8 + getSPSLen() + 1; - setInt16(newPPS.size(), offset); - for (unsigned int i = 0; i < newPPS.size(); i++){ - setInt8(newPPS[i], offset + 2 + i); - } //not null-terminated - } - - uint32_t AVCC::getPPSLen(){ - int offset = 8 + getSPSLen() + 1; - return getInt16(offset); - } - - char* AVCC::getPPS(){ - int offset = 8 + getSPSLen() + 3; - return payload() + offset; - } - - std::string AVCC::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[avcC] H.264 Init Data (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl; - r << std::string(indent + 1, ' ') << "Profile: " << getProfile() << std::endl; - r << std::string(indent + 1, ' ') << "Compatible Profiles: " << getCompatibleProfiles() << std::endl; - r << std::string(indent + 1, ' ') << "Level: " << getLevel() << std::endl; - r << std::string(indent + 1, ' ') << "SPS Number: " << getSPSNumber() << std::endl; - r << std::string(indent + 2, ' ') << getSPSLen() << " of SPS data" << std::endl; - r << std::string(indent + 1, ' ') << "PPS Number: " << getPPSNumber() << std::endl; - r << std::string(indent + 2, ' ') << getPPSLen() << " of PPS data" << std::endl; - return r.str(); - } - - std::string AVCC::asAnnexB(){ - std::stringstream r; - r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; - r.write(getSPS(), getSPSLen()); - r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; - r.write(getPPS(), getPPSLen()); - return r.str(); - } - - void AVCC::fromAnnexB(std::string annexBFormatted){ - ///\todo fix correct data :p - setVersion(0x01); - setProfile(0x4D); - setCompatibleProfiles(0x40); - setLevel(0x1F); - setSPSNumber(0xE1); - static char annexBHeader[] = {0x00,0x00,0x00,0x01}; - if (memcmp(annexBFormatted.c_str(), annexBHeader, 4)){ - return; - } - annexBFormatted.erase(0,4); - int separator = annexBFormatted.find(annexBHeader, 0, 4); - setSPS(annexBFormatted.substr(0,separator)); - setPPSNumber(0x01); - annexBFormatted.erase(0,separator+4); - setPPS(annexBFormatted); - } - - void AVCC::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()); - } - - //fullbox, start at 4 - ESDS::ESDS(){ - memcpy(data + 4, "esds", 4); - setESDescriptorType(0x03); - setExtendedESDescriptorType(0x808080); - setStreamPriority(16); - setDecoderConfigDescriptorTag(0x04); - setExtendedDecoderConfigDescriptorTag(0x808080); - setReservedFlag(true); - setDecoderDescriptorTypeTag(0x05); - setExtendedDecoderDescriptorTypeTag(0x808080); - setSLConfigDescriptorTypeTag(0x06); - setSLConfigExtendedDescriptorTypeTag(0x808010); - setSLValue(0x02); - } - - char ESDS::getESDescriptorType(){ - return getInt8(4); - } - - void ESDS::setESDescriptorType(char newVal){ - setInt8(newVal,4); - } - - uint32_t ESDS::getExtendedESDescriptorType(){ - return getInt24(5); - } - //3 bytes - void ESDS::setExtendedESDescriptorType(uint32_t newVal){ - setInt24(newVal,5); - } - //3 bytes - char ESDS::getESDescriptorTypeLength(){ - return getInt8(8); - } - - void ESDS::setESDescriptorTypeLength(char newVal){ - setInt8(newVal,8); - } - //ESID 2 bytes - uint16_t ESDS::getESID(){ - return getInt16(9); - } - - void ESDS::setESID(uint16_t newVal){ - setInt16(newVal, 9); - } - - //stream priority 1 byte - char ESDS::getStreamPriority(){ - return getInt8(11); - } - - void ESDS::setStreamPriority(char newVal){ - setInt8(newVal, 11); - } - - //decoder config descriptor tag 1byte - char ESDS::getDecoderConfigDescriptorTag(){ - return getInt8(12); - } - - void ESDS::setDecoderConfigDescriptorTag(char newVal){ - setInt8(newVal, 12); - } - - //extended decoder config descriptor tag 3 bytes - uint32_t ESDS::getExtendedDecoderConfigDescriptorTag(){ - return getInt24(13); - } - //3 bytes - void ESDS::setExtendedDecoderConfigDescriptorTag(uint32_t newVal){ - setInt24(newVal, 13); - } - //3 bytes - //decoder config descriptor type length - char ESDS::getDecoderConfigDescriptorTypeLength(){ - return getInt8(16); - } - - void ESDS::setDecoderConfigDescriptorTypeLength(char newVal){ - setInt8(newVal, 16); - } - //Note: tel 8 bytes op bij de volgende functies - char ESDS::getByteObjectTypeID(){ - return getInt8(17); - } - - void ESDS::setByteObjectTypeID(char newVal){ - setInt8(newVal,17); - } - - char ESDS::getStreamType(){ - return getInt8(18) >> 2; - } - //6 bits - void ESDS::setStreamType(char newVal){ - setInt8(((newVal << 2) & 0xFC) + (getInt8(18) & 0x03), 18); - } - //6 bits - bool ESDS::getUpstreamFlag(){ - return (((getInt8(18) >> 1) & 0x01) == 1); - } - - void ESDS::setUpstreamFlag(bool newVal){ - setInt8((getStreamType()<<2) + ((uint8_t)newVal << 1) + (uint8_t)getReservedFlag() , 18); - } - - bool ESDS::getReservedFlag(){ - return ((getInt8(18) & 0x01) == 1); - } - - void ESDS::setReservedFlag(bool newVal){ - setInt8((getInt8(18) & 0xFE) + (int)newVal, 18); - } - - uint32_t ESDS::getBufferSize(){ - return getInt24(19); - } - //3 bytes - void ESDS::setBufferSize(uint32_t newVal){ - setInt24(newVal,19); - } - //3 bytes - uint32_t ESDS::getMaximumBitRate(){ - return getInt32(22); - } - - void ESDS::setMaximumBitRate(uint32_t newVal){ - setInt32(newVal,22); - } - - uint32_t ESDS::getAverageBitRate(){ - return getInt32(26); - } - - void ESDS::setAverageBitRate(uint32_t newVal){ - setInt32(newVal,26); - } - - char ESDS::getDecoderDescriptorTypeTag(){ - return getInt8(30); - } - - void ESDS::setDecoderDescriptorTypeTag(char newVal){ - setInt8(newVal,30); - } - - uint32_t ESDS::getExtendedDecoderDescriptorTypeTag(){ - return getInt24(31); - } - - //3 bytes - void ESDS::setExtendedDecoderDescriptorTypeTag(uint32_t newVal){ - setInt24(newVal, 31); - } - - //3 bytes - char ESDS::getConfigDescriptorTypeLength(){ - return getInt8(34); - } - - void ESDS::setConfigDescriptorTypeLength(char newVal){ - setInt8(newVal, 34); - } - - std::string ESDS::getESHeaderStartCodes(){ - std::string result; - for (int i = 0; i < getInt8(34); i++){ - result += getInt8(35 + i); - } - return result; - } - - void ESDS::setESHeaderStartCodes(std::string newVal){ - setConfigDescriptorTypeLength(newVal.size()); - for (unsigned int i = 0; i < newVal.size(); i++){ - setInt8(newVal[i],35+i); - } - } - - char ESDS::getSLConfigDescriptorTypeTag(){ - return getInt8(35 + getInt8(34)); - } - - void ESDS::setSLConfigDescriptorTypeTag(char newVal){ - setInt8(newVal, 35 + getInt8(34)); - } - - uint32_t ESDS::getSLConfigExtendedDescriptorTypeTag(){ - return getInt24(36 + getInt8(34)); - } - //3 bytes - void ESDS::setSLConfigExtendedDescriptorTypeTag(uint32_t newVal){ - setInt24(newVal, 36 + getInt8(34)); - } - //3 bytes - char ESDS::getSLDescriptorTypeLength(){ - return getInt8(39 + getInt8(34)); - } - - void ESDS::setSLDescriptorTypeLength(char newVal){ - setInt8(newVal, 39 + getInt8(34)); - } - - char ESDS::getSLValue(){ - return getInt8(40 + getInt8(34)); - } - - void ESDS::setSLValue(char newVal){ - setInt8(newVal, 40 + getInt8(34)); - } - - std::string ESDS::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[esds] ES Descriptor Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "ESDescriptorType: 0x" << std::hex << (int)getESDescriptorType() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "ExtendedESDescriptorType: 0x" << std::hex << (int)getExtendedESDescriptorType() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "ESDescriptorTypeLength:" << (int)getESDescriptorTypeLength() << std::endl; - r << std::string(indent + 1, ' ') << "ESID: 0x" << std::hex << (int)getESID() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "StreamPriority: 0x" << std::hex << (int)getStreamPriority() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "DecoderConfigDescriptorTag: 0x" << std::hex << (int)getDecoderConfigDescriptorTag() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "ExtendedDecoderConfigDescriptorTag: 0x" << std::hex << (int)getExtendedDecoderConfigDescriptorTag() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "DecoderConfigDescriptorTypeLength: " << (int)getDecoderConfigDescriptorTypeLength() << std::endl; - r << std::string(indent + 1, ' ') << "ByteObjectTypeID: 0x" << std::hex << (int)getByteObjectTypeID() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "StreamType: 0x" << std::hex << (int)getStreamType() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "UpstreamFlag: 0x" << std::hex << (int)getUpstreamFlag() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "BufferSize: 0x" << std::hex << (int)getBufferSize() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "MaximumBitRate: 0x" << std::hex << (int)getMaximumBitRate() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "AverageBitRate: 0x" << std::hex << (int)getAverageBitRate() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "DecoderDescriptorTypeTag: 0x" << std::hex << (int)getDecoderDescriptorTypeTag() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "ExtendedDecoderDescriptorTypeTag: 0x" << std::hex << (int)getExtendedDecoderDescriptorTypeTag() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "ConfigDescriptorTypeLength: 0x" << std::hex << (int)getConfigDescriptorTypeLength() << std::dec << std::endl; - r << std::string(indent + 1, ' ') << "ESHeaderStartCodes: 0x"; - for (unsigned int i = 0; i= getCompatibleBrandsCount()){ - return 0; - } - return getInt32(8 + (index * 4)); - } - - std::string FTYP::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[ftyp] File Type (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "MajorBrand: 0x" << std::hex << getMajorBrand() << std::dec << 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: 0x" << std::hex << getCompatibleBrands(i) << std::dec << std::endl; - } - return r.str(); - } - - MOOV::MOOV(){ - memcpy(data + 4, "moov", 4); - } - - std::string MOOV::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[moov] Movie Box")); - } - - MVEX::MVEX(){ - memcpy(data + 4, "mvex", 4); - } - - std::string MVEX::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[mvex] Movie Extends Header Box")); - } - - TREX::TREX(){ - memcpy(data + 4, "trex", 4); - } - - void TREX::setTrackID(uint32_t newTrackID){ - setInt32(newTrackID, 0); - } - - uint32_t TREX::getTrackID(){ - return getInt32(0); - } - - void TREX::setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex){ - setInt32(newDefaultSampleDescriptionIndex,4); - } - - uint32_t TREX::getDefaultSampleDescriptionIndex(){ - return getInt32(4); - } - - void TREX::setDefaultSampleDuration(uint32_t newDefaultSampleDuration){ - setInt32(newDefaultSampleDuration,8); - } - - uint32_t TREX::getDefaultSampleDuration(){ - return getInt32(8); - } - - void TREX::setDefaultSampleSize(uint32_t newDefaultSampleSize){ - setInt32(newDefaultSampleSize,12); - } - - uint32_t TREX::getDefaultSampleSize(){ - return getInt32(12); - } - - void TREX::setDefaultSampleFlags(uint32_t newDefaultSampleFlags){ - setInt32(newDefaultSampleFlags,16); - } - - uint32_t TREX::getDefaultSampleFlags(){ - return getInt32(16); - } - - std::string TREX::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[trex] Track Extends (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; - r << std::string(indent + 1, ' ') << "DefaultSampleDescriptionIndex : " << getDefaultSampleDescriptionIndex() << std::endl; - r << std::string(indent + 1, ' ') << "DefaultSampleDuration : " << getDefaultSampleDuration() << std::endl; - r << std::string(indent + 1, ' ') << "DefaultSampleSize : " << getDefaultSampleSize() << std::endl; - r << std::string(indent + 1, ' ') << "DefaultSampleFlags : " << getDefaultSampleFlags() << std::endl; - return r.str(); - } - - TRAK::TRAK(){ - memcpy(data + 4, "trak", 4); - } - - std::string TRAK::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[trak] Track Structure")); - } - - MDIA::MDIA(){ - memcpy(data + 4, "mdia", 4); - } - - std::string MDIA::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[mdia] Track Media Structure")); - } - - MINF::MINF(){ - memcpy(data + 4, "minf", 4); - } - - std::string MINF::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[minf] Media Information")); - } - - DINF::DINF(){ - memcpy(data + 4, "dinf", 4); - } - - std::string DINF::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[dinf] Data Information")); - } - - MFRA::MFRA(){ - memcpy(data + 4, "mfra", 4); - } - - std::string MFRA::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[mfra] Movie Fragment Random Acces Box")); - } - - MFRO::MFRO(){ - memcpy(data + 4, "mfro", 4); - } - - void MFRO::setSize(uint32_t newSize){ - setInt32(newSize,0); - } - - uint32_t MFRO::getSize(){ - return getInt32(0); - } - - std::string MFRO::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[mfro] Movie Fragment Random Access Offset (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "Size: " << getSize() << std::endl; - return r.str(); - } - - HDLR::HDLR(){ - memcpy(data + 4, "hdlr", 4); - setName(""); - } - - void HDLR::setSize(uint32_t newSize){ - setInt32(newSize,0); - } - - uint32_t HDLR::getSize(){ - return getInt32(0); - } - - void HDLR::setPreDefined(uint32_t newPreDefined){ - setInt32(newPreDefined,4); - } - - uint32_t HDLR::getPreDefined(){ - return getInt32(4); - } - - void HDLR::setHandlerType(uint32_t newHandlerType){ - setInt32(newHandlerType, 8); - } - - uint32_t HDLR::getHandlerType(){ - return getInt32(8); - } - - void HDLR::setName(std::string newName){ - setString(newName, 24); - } - - std::string HDLR::getName(){ - return getString(24); - } - - std::string HDLR::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[hdlr] Handler Reference (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "PreDefined: " << getPreDefined() << std::endl; - r << std::string(indent + 1, ' ') << "HandlerType: " << - (char)((getHandlerType() & 0xFF000000) >> 24) << (char)((getHandlerType() & 0x00FF0000) >> 16) << - (char)((getHandlerType() & 0x0000FF00) >> 8) << (char)(getHandlerType() & 0x000000FF) << std::endl; - r << std::string(indent + 1, ' ') << "Name: " << getName() << std::endl; - return r.str(); - } - - //Note: next 4 headers inherit from fullBox, start at byte 4. - VMHD::VMHD(){ - memcpy(data + 4, "vmhd", 4); - setGraphicsMode(0); - setOpColor(0,0); - setOpColor(0,1); - setOpColor(0,2); - } - - void VMHD::setGraphicsMode(uint16_t newGraphicsMode){ - setInt16(newGraphicsMode,4); - } - - uint16_t VMHD::getGraphicsMode(){ - return getInt16(4); - } - - uint32_t VMHD::getOpColorCount(){ - return 3; - } - - void VMHD::setOpColor(uint16_t newOpColor, size_t index){ - if (index <3){ - setInt16(newOpColor, 6 + (2 * index)); - } - } - - uint16_t VMHD::getOpColor(size_t index){ - if (index < 3){ - return getInt16(6 + (index * 2)); - }else{ - return 0; - } - } - - std::string VMHD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[vmhd] Video Media Header Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "GraphicsMode: " << getGraphicsMode() << std::endl; - for (unsigned int i = 0; i < getOpColorCount(); i++){ - r << std::string(indent + 1, ' ') << "OpColor["< getEntryCount()){ - int amount = index + 1 - getEntryCount(); - if ( !reserve(payloadOffset + offset, 0, amount * 8)){ - return; - } - for (int j = 0; j < amount; ++j){ - memcpy(data + payloadOffset + offset + j * 8, "\000\000\000\010erro", 8); - } - setInt32(index + 1, 4); - offset += (index - i) * 8; - } - setBox(newDataEntry, offset); - } - - Box & DREF::getDataEntry(size_t index){ - uint32_t offset = 8; - if (index > getEntryCount()){ - static Box res; - return (Box &)res; - } - - for (unsigned int i=0; i < index; i++){ - offset += getBoxLen(offset); - } - return (Box &)getBox(offset); - } - - std::string DREF::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[dref] Data Reference Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i< getEntryCount(); i++){ - r << getDataEntry(i).toPrettyString(indent+1); - } - return r.str(); - } - - MVHD::MVHD(char v, uint32_t f){ - memcpy(data + 4, "mvhd", 4); - setVersion(v); - setFlags(f); - setCreationTime(0); - setModificationTime(0); - setTimeScale(1000); - setDuration(0); - setRate(0x00010000); - setVolume(0x0100); - setMatrix(0x40000000,0); - setMatrix(0x00010000,4); - setMatrix(0x00010000,8); - setTrackID(1); - } - - void MVHD::setCreationTime(uint64_t newCreationTime){ - if (getVersion() == 0){ - setInt32((uint32_t) newCreationTime, 4); - }else{ - setInt64(newCreationTime, 4); - } - } - - uint64_t MVHD::getCreationTime(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(4); - }else{ - return getInt64(4); - } - } - - void MVHD::setModificationTime(uint64_t newModificationTime){ - if (getVersion() == 0){ - setInt32((uint32_t) newModificationTime, 8); - }else{ - setInt64(newModificationTime, 12); - } - } - - uint64_t MVHD::getModificationTime(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(8); - }else{ - return getInt64(12); - } - } - - void MVHD::setTimeScale(uint32_t newTimeScale){ - if (getVersion() == 0){ - setInt32((uint32_t) newTimeScale, 12); - }else{ - setInt32(newTimeScale, 20); - } - } - - uint32_t MVHD::getTimeScale(){ - if (getVersion() == 0){ - return getInt32(12); - }else{ - return getInt32(20); - } - } - - void MVHD::setDuration(uint64_t newDuration){ - if (getVersion() == 0){ - setInt32((uint32_t) newDuration, 16); - }else{ - setInt64(newDuration, 24); - } - } - - uint64_t MVHD::getDuration(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(16); - }else{ - return getInt64(24); - } - } - - void MVHD::setRate(uint32_t newRate){ - if (getVersion() == 0){ - setInt32( newRate, 20); - }else{ - setInt32(newRate, 32); - } - } - - uint32_t MVHD::getRate(){ - if (getVersion() == 0){ - return getInt32(20); - }else{ - return getInt32(32); - } - } - - void MVHD::setVolume(uint16_t newVolume){ - if (getVersion() == 0){ - setInt16(newVolume, 24); - }else{ - setInt16(newVolume, 36); - } - } - - uint16_t MVHD::getVolume(){ - if (getVersion() == 0){ - return getInt16(24); - }else{ - return getInt16(36); - } - } - //10 bytes reserverd in between - uint32_t MVHD::getMatrixCount(){ - return 9; - } - - void MVHD::setMatrix(int32_t newMatrix, size_t index){ - int offset = 0; - if (getVersion() == 0){ - offset = 24 + 2 + 10; - }else{ - offset = 36 + 2 + 10; - } - setInt32(newMatrix, offset + index * 4); - } - - int32_t MVHD::getMatrix(size_t index){ - int offset = 0; - if (getVersion() == 0){ - offset = 24 + 2 + 10; - }else{ - offset = 36 + 2 + 10; - } - 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); - } - } - - uint32_t MVHD::getTrackID(){ - if (getVersion() == 0){ - return getInt32(86); - }else{ - return getInt32(98); - } - } - - std::string MVHD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[mvhd] Movie Header Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; - r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; - r << std::string(indent + 1, ' ') << "TimeScale: " << getTimeScale() << std::endl; - r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; - r << std::string(indent + 1, ' ') << "Rate: " << getRate() << std::endl; - r << std::string(indent + 1, ' ') << "Volume: " << getVolume() << std::endl; - r << std::string(indent + 1, ' ') << "Matrix: "; - for (unsigned int i = 0; i< getMatrixCount(); i++){ - r << getMatrix(i); - if (i!=getMatrixCount()-1){ - r << ", "; - } - } - r << std::endl; - r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; - return r.str(); - } - - TFRA::TFRA(){ - memcpy(data + 4, "dref", 4); - } - - //note, fullbox starts at byte 4 - void TFRA::setTrackID(uint32_t newTrackID){ - setInt32(newTrackID, 4); - } - - uint32_t TFRA::getTrackID(){ - return getInt32(4); - } - - void TFRA::setLengthSizeOfTrafNum(char newVal){ - char part = getInt8(11); - setInt8(((newVal & 0x03)<<4) + (part & 0xCF),11); - } - - char TFRA::getLengthSizeOfTrafNum(){ - return (getInt8(11)>>4) & 0x03; - } - - void TFRA::setLengthSizeOfTrunNum(char newVal){ - char part = getInt8(11); - setInt8(((newVal & 0x03)<<2) + (part & 0xF3),11); - } - - char TFRA::getLengthSizeOfTrunNum(){ - return (getInt8(11)>>2) & 0x03; - } - - void TFRA::setLengthSizeOfSampleNum(char newVal){ - char part = getInt8(11); - setInt8(((newVal & 0x03)) + (part & 0xFC),11); - } - - char TFRA::getLengthSizeOfSampleNum(){ - return (getInt8(11)) & 0x03; - } - - void TFRA::setNumberOfEntry(uint32_t newNumberOfEntry){ - setInt32(newNumberOfEntry,12); - } - - uint32_t TFRA::getNumberOfEntry(){ - return getInt32(12); - } - - uint32_t TFRA::getTFRAEntrySize(){ - int EntrySize= (getVersion()==1 ? 16 : 8); - EntrySize += getLengthSizeOfTrafNum()+1; - EntrySize += getLengthSizeOfTrunNum()+1; - EntrySize += getLengthSizeOfSampleNum()+1; - return EntrySize; - } - - void TFRA::setTFRAEntry(TFRAEntry newTFRAEntry, uint32_t no){ - if (no + 1 > getNumberOfEntry()){//if a new entry is issued - uint32_t offset = 16 + getTFRAEntrySize() * getNumberOfEntry();//start of filler in bytes - uint32_t fillsize = (no + 1 - getNumberOfEntry())*getTFRAEntrySize();//filler in bytes - if ( !reserve(offset, 0, fillsize)){//filling space - return; - } - setNumberOfEntry(no+1); - } - uint32_t loc = 16 + no * getTFRAEntrySize(); - if (getVersion() == 1){ - setInt64(newTFRAEntry.time, loc); - setInt64(newTFRAEntry.moofOffset, loc+8); - loc += 16; - }else{ - setInt32(newTFRAEntry.time, loc); - setInt32(newTFRAEntry.moofOffset, loc+4); - loc += 8; - } - switch (getLengthSizeOfTrafNum()){ - case 0: - setInt8(newTFRAEntry.trafNumber, loc); - break; - case 1: - setInt16(newTFRAEntry.trafNumber, loc); - break; - case 2: - setInt24(newTFRAEntry.trafNumber, loc); - break; - case 3: - setInt32(newTFRAEntry.trafNumber, loc); - break; - } - loc += getLengthSizeOfTrafNum() + 1; - switch (getLengthSizeOfTrunNum()){ - case 0: - setInt8(newTFRAEntry.trunNumber, loc); - break; - case 1: - setInt16(newTFRAEntry.trunNumber, loc); - break; - case 2: - setInt24(newTFRAEntry.trunNumber, loc); - break; - case 3: - setInt32(newTFRAEntry.trunNumber, loc); - break; - } - loc += getLengthSizeOfTrunNum() + 1; - switch (getLengthSizeOfSampleNum()){ - case 0: - setInt8(newTFRAEntry.sampleNumber, loc); - break; - case 1: - setInt16(newTFRAEntry.sampleNumber, loc); - break; - case 2: - setInt24(newTFRAEntry.sampleNumber, loc); - break; - case 3: - setInt32(newTFRAEntry.sampleNumber, loc); - break; - } - } - - TFRAEntry & TFRA::getTFRAEntry(uint32_t no){ - static TFRAEntry retval; - if (no >= getNumberOfEntry()){ - static TFRAEntry inval; - return inval; - } - uint32_t loc = 16 + no * getTFRAEntrySize(); - if (getVersion() == 1){ - retval.time = getInt64(loc); - retval.moofOffset = getInt64(loc + 8); - loc += 16; - }else{ - retval.time = getInt32(loc); - retval.moofOffset = getInt32(loc + 4); - loc += 8; - } - switch (getLengthSizeOfTrafNum()){ - case 0: - retval.trafNumber = getInt8(loc); - break; - case 1: - retval.trafNumber = getInt16(loc); - break; - case 2: - retval.trafNumber = getInt24(loc); - break; - case 3: - retval.trafNumber = getInt32(loc); - break; - } - loc += getLengthSizeOfTrafNum() + 1; - switch (getLengthSizeOfTrunNum()){ - case 0: - retval.trunNumber = getInt8(loc); - break; - case 1: - retval.trunNumber = getInt16(loc); - break; - case 2: - retval.trunNumber = getInt24(loc); - break; - case 3: - retval.trunNumber = getInt32(loc); - break; - } - loc += getLengthSizeOfTrunNum() + 1; - switch (getLengthSizeOfSampleNum()){ - case 0: - retval.sampleNumber = getInt8(loc); - break; - case 1: - retval.sampleNumber = getInt16(loc); - break; - case 2: - retval.sampleNumber = getInt24(loc); - break; - case 3: - retval.sampleNumber = getInt32(loc); - break; - } - return retval; - } - - std::string TFRA::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[tfra] Track Fragment Random Access Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; - r << std::string(indent + 1, ' ') << "lengthSizeOfTrafNum: " << (int)getLengthSizeOfTrafNum() << std::endl; - r << std::string(indent + 1, ' ') << "lengthSizeOfTrunNum: " << (int)getLengthSizeOfTrunNum() << std::endl; - r << std::string(indent + 1, ' ') << "lengthSizeOfSampleNum: " << (int)getLengthSizeOfSampleNum() << std::endl; - r << std::string(indent + 1, ' ') << "NumberOfEntry: " << getNumberOfEntry() << std::endl; - for (unsigned int i = 0; i < getNumberOfEntry(); i++){ - static TFRAEntry temp; - temp = getTFRAEntry(i); - r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; - r << std::string(indent + 2, ' ') << "Time: " << temp.time << std::endl; - r << std::string(indent + 2, ' ') << "MoofOffset: " << temp.moofOffset << std::endl; - r << std::string(indent + 2, ' ') << "TrafNumber: " << temp.trafNumber << std::endl; - r << std::string(indent + 2, ' ') << "TrunNumber: " << temp.trunNumber << std::endl; - r << std::string(indent + 2, ' ') << "SampleNumber: " << temp.sampleNumber << std::endl; - } - return r.str(); - } - - TKHD::TKHD(char v, uint32_t f){ - memcpy(data + 4, "tkhd", 4); - setVersion(v); - setFlags(f); - setCreationTime(0); - setModificationTime(0); - setTrackID(0); - setDuration(0); - setLayer(0); - setAlternateGroup(0); - setVolume(0x0100); - setMatrix(0x00010000,0); - setMatrix(0x00010000,4); - //fills automatically with zero's - setMatrix(0x40000000,8); - setWidth(0); - setHeight(0); - } - - void TKHD::setCreationTime(uint64_t newCreationTime){ - if (getVersion() == 0){ - setInt32((uint32_t) newCreationTime, 4); - }else{ - setInt64(newCreationTime, 4); - } - } - - uint64_t TKHD::getCreationTime(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(4); - }else{ - return getInt64(4); - } - } - - void TKHD::setModificationTime(uint64_t newModificationTime){ - if (getVersion() == 0){ - setInt32((uint32_t) newModificationTime, 8); - }else{ - setInt64(newModificationTime, 12); - } - } - - uint64_t TKHD::getModificationTime(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(8); - }else{ - return getInt64(12); - } - } - - void TKHD::setTrackID(uint32_t newTrackID){ - if (getVersion() == 0){ - setInt32((uint32_t) newTrackID, 12); - }else{ - setInt32(newTrackID, 20); - } - } - - uint32_t TKHD::getTrackID(){ - if (getVersion() == 0){ - return getInt32(12); - }else{ - return getInt32(20); - } - } - //note 4 bytes reserved in between - void TKHD::setDuration(uint64_t newDuration){ - if (getVersion() == 0){ - setInt32(newDuration, 20); - }else{ - setInt64(newDuration, 28); - } - } - - uint64_t TKHD::getDuration(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(20); - }else{ - return getInt64(28); - } - } - //8 bytes reserved in between - void TKHD::setLayer(uint16_t newLayer){ - if (getVersion() == 0){ - setInt16(newLayer, 32); - }else{ - setInt16(newLayer, 44); - } - } - - uint16_t TKHD::getLayer(){ - if (getVersion() == 0){ - return getInt16(32); - }else{ - return getInt16(44); - } - } - - void TKHD::setAlternateGroup(uint16_t newAlternateGroup){ - if (getVersion() == 0){ - setInt16(newAlternateGroup, 34); - }else{ - setInt16(newAlternateGroup, 46); - } - } - - uint16_t TKHD::getAlternateGroup(){ - if (getVersion() == 0){ - return getInt16(34); - }else{ - return getInt16(46); - } - } - - void TKHD::setVolume(uint16_t newVolume){ - if (getVersion() == 0){ - setInt16(newVolume, 36); - }else{ - setInt16(newVolume, 48); - } - } - - uint16_t TKHD::getVolume(){ - if (getVersion() == 0){ - return getInt16(36); - }else{ - return getInt16(48); - } - } - //2 bytes reserved in between - uint32_t TKHD::getMatrixCount(){ - return 9; - } - - void TKHD::setMatrix(int32_t newMatrix, size_t index){ - int offset = 0; - if (getVersion() == 0){ - offset = 36 + 2 + 2; - }else{ - offset = 48 + 2 + 2; - } - setInt32(newMatrix, offset + index * 4); - } - - int32_t TKHD::getMatrix(size_t index){ - int offset = 0; - if (getVersion() == 0){ - offset = 36 + 2 + 2; - }else{ - offset = 48 + 2 + 2; - } - return getInt32(offset + index * 4); - } - - void TKHD::setWidth(uint32_t newWidth){ - if (getVersion() == 0){ - setInt32(newWidth, 76); - }else{ - setInt32(newWidth, 88); - } - } - - uint32_t TKHD::getWidth(){ - if (getVersion() == 0){ - return getInt32(76); - }else{ - return getInt32(88); - } - } - - void TKHD::setHeight(uint32_t newHeight){ - if (getVersion() == 0){ - setInt32(newHeight, 80); - }else{ - setInt32(newHeight, 92); - } - } - - uint32_t TKHD::getHeight(){ - if (getVersion() == 0){ - return getInt32(80); - }else{ - return getInt32(92); - } - } - - std::string TKHD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[tkhd] Track Header Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; - r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; - r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; - r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; - r << std::string(indent + 1, ' ') << "Layer: " << getLayer() << std::endl; - r << std::string(indent + 1, ' ') << "AlternateGroup: " << getAlternateGroup() << std::endl; - r << std::string(indent + 1, ' ') << "Volume: " << getVolume() << std::endl; - r << std::string(indent + 1, ' ') << "Matrix: "; - for (unsigned int i = 0; i< getMatrixCount(); i++){ - r << getMatrix(i); - if (i!=getMatrixCount()-1){ - r << ", "; - } - } - r << std::endl; - r << std::string(indent + 1, ' ') << "Width: " << (getWidth() >> 16) << "." << (getWidth() & 0xFFFF) << std::endl; - r << std::string(indent + 1, ' ') << "Height: " << (getHeight() >> 16) << "." << (getHeight() & 0xFFFF) << std::endl; - return r.str(); - } - - MDHD::MDHD(char v, uint32_t f){ - memcpy(data + 4, "mdhd", 4); - setVersion(v); - setFlags(f); - setCreationTime(0); - setModificationTime(0); - setTimeScale(1000); - setDuration(0); - setLanguage(0); - if (v==0){ - setInt16(0,22); - }else{ - setInt16(0,34); - } - } - - void MDHD::setCreationTime(uint64_t newCreationTime){ - if (getVersion() == 0){ - setInt32((uint32_t) newCreationTime, 4); - }else{ - setInt64(newCreationTime, 4); - } - } - - uint64_t MDHD::getCreationTime(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(4); - }else{ - return getInt64(4); - } - } - - void MDHD::setModificationTime(uint64_t newModificationTime){ - if (getVersion() == 0){ - setInt32((uint32_t) newModificationTime, 8); - }else{ - setInt64(newModificationTime, 12); - } - } - - uint64_t MDHD::getModificationTime(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(8); - }else{ - return getInt64(12); - } - } - - void MDHD::setTimeScale(uint32_t newTimeScale){ - if (getVersion() == 0){ - setInt32((uint32_t) newTimeScale, 12); - }else{ - setInt32(newTimeScale, 20); - } - } - - uint32_t MDHD::getTimeScale(){ - if (getVersion() == 0){ - return getInt32(12); - }else{ - return getInt32(20); - } - } - - void MDHD::setDuration(uint64_t newDuration){ - if (getVersion() == 0){ - setInt32((uint32_t) newDuration, 16); - }else{ - setInt64(newDuration, 24); - } - } - - uint64_t MDHD::getDuration(){ - if (getVersion() == 0){ - return (uint64_t)getInt32(16); - }else{ - return getInt64(24); - } - } - - void MDHD::setLanguage (uint16_t newLanguage){ - if (getVersion() == 0){ - setInt16(newLanguage & 0x7F, 20); - }else{ - setInt16(newLanguage & 0x7F, 32); - } - } - - uint16_t MDHD::getLanguage(){ - if (getVersion() == 0){ - return getInt16(20) & 0x7F; - }else{ - return getInt16(32) & 0x7F; - } - } - - std::string MDHD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[mdhd] Media Header Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; - r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; - r << std::string(indent + 1, ' ') << "TimeScale: " << getTimeScale() << std::endl; - r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; - r << std::string(indent + 1, ' ') << "Language: 0x" << std::hex << getLanguage() << std::dec<< std::endl; - return r.str(); - } - - STTS::STTS(char v, uint32_t f){ - memcpy(data + 4, "stts", 4); - setVersion(v); - setFlags(f); - setEntryCount(0); - } - - void STTS::setEntryCount(uint32_t newEntryCount){ - setInt32(newEntryCount, 4); - } - - uint32_t STTS::getEntryCount(){ - return getInt32(4); - } - - void STTS::setSTTSEntry(STTSEntry newSTTSEntry, uint32_t no){ - if(no + 1 > getEntryCount()){ - setEntryCount(no + 1); - for (unsigned int i = getEntryCount(); i < no; i++){ - setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits - } - } - setInt32(newSTTSEntry.sampleCount, 8 + no * 8); - setInt32(newSTTSEntry.sampleDelta, 8 + (no * 8) + 4); - } - - STTSEntry STTS::getSTTSEntry(uint32_t no){ - static STTSEntry retval; - if (no >= getEntryCount()){ - static STTSEntry inval; - return inval; - } - retval.sampleCount = getInt32(8 + (no * 8)); - retval.sampleDelta = getInt32(8 + (no * 8) + 4); - return retval; - } - - std::string STTS::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i < getEntryCount(); i++){ - static STTSEntry temp; - temp = getSTTSEntry(i); - r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; - r << std::string(indent + 2, ' ') << "SampleCount: " << temp.sampleCount << std::endl; - r << std::string(indent + 2, ' ') << "SampleDelta: " << temp.sampleDelta << std::endl; - } - return r.str(); - - } - - CTTS::CTTS(){ - memcpy(data + 4, "ctts", 4); - } - - void CTTS::setEntryCount(uint32_t newEntryCount){ - setInt32(newEntryCount, 4); - } - - uint32_t CTTS::getEntryCount(){ - return getInt32(4); - } - - void CTTS::setCTTSEntry(CTTSEntry newCTTSEntry, uint32_t no){ - if(no + 1 > getEntryCount()){ - for (unsigned int i = getEntryCount(); i < no; i++){ - setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits - } - } - setInt32(newCTTSEntry.sampleCount, 8 + no * 8); - setInt32(newCTTSEntry.sampleOffset, 8 + (no * 8) + 4); - } - - CTTSEntry CTTS::getCTTSEntry(uint32_t no){ - static CTTSEntry retval; - if (no >= getEntryCount()){ - static CTTSEntry inval; - return inval; - } - retval.sampleCount = getInt32(8 + (no * 8)); - retval.sampleOffset = getInt32(8 + (no * 8) + 4); - return retval; - } - - std::string CTTS::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i < getEntryCount(); i++){ - static CTTSEntry temp; - temp = getCTTSEntry(i); - r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; - r << std::string(indent + 2, ' ') << "SampleCount: " << temp.sampleCount << std::endl; - r << std::string(indent + 2, ' ') << "SampleOffset: " << temp.sampleOffset << std::endl; - } - return r.str(); - - } - - STSC::STSC(char v, uint32_t f){ - memcpy(data + 4, "stsc", 4); - setVersion(v); - setFlags(f); - setEntryCount(0); - } - - void STSC::setEntryCount(uint32_t newEntryCount){ - setInt32(newEntryCount, 4); - } - - uint32_t STSC::getEntryCount(){ - return getInt32(4); - } - - void STSC::setSTSCEntry(STSCEntry newSTSCEntry, uint32_t no){ - if(no + 1 > getEntryCount()){ - setEntryCount(no+1); - for (unsigned int i = getEntryCount(); i < no; i++){ - setInt64(0, 8 + (i * 12));//filling up undefined entries of 64 bits - setInt32(0, 8 + (i * 12) + 8); - } - } - setInt32(newSTSCEntry.firstChunk, 8 + no * 12); - setInt32(newSTSCEntry.samplesPerChunk, 8 + (no * 12) + 4); - setInt32(newSTSCEntry.sampleDescriptionIndex, 8 + (no * 12) + 8); - } - - STSCEntry STSC::getSTSCEntry(uint32_t no){ - static STSCEntry retval; - if (no >= getEntryCount()){ - static STSCEntry inval; - return inval; - } - retval.firstChunk = getInt32(8 + (no * 12)); - retval.samplesPerChunk = getInt32(8 + (no * 12) + 4); - retval.sampleDescriptionIndex = getInt32(8 + (no * 12) + 8); - return retval; - } - - std::string STSC::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stsc] Sample To Chunk Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i < getEntryCount(); i++){ - static STSCEntry temp; - temp = getSTSCEntry(i); - r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; - r << std::string(indent + 2, ' ') << "FirstChunk: " << temp.firstChunk << std::endl; - r << std::string(indent + 2, ' ') << "SamplesPerChunk: " << temp.samplesPerChunk << std::endl; - r << std::string(indent + 2, ' ') << "SampleDescriptionIndex: " << temp.sampleDescriptionIndex << std::endl; - } - return r.str(); - } - - STCO::STCO(char v, uint32_t f){ - memcpy(data + 4, "stco", 4); - setVersion(v); - setFlags(f); - setEntryCount(0); - } - - void STCO::setEntryCount(uint32_t newEntryCount){ - setInt32(newEntryCount, 4); - } - - uint32_t STCO::getEntryCount(){ - return getInt32(4); - } - - void STCO::setChunkOffset(uint32_t newChunkOffset, uint32_t no){ - if (no + 1 > getEntryCount()){ - for (unsigned int i = getEntryCount(); i < no; i++){ - setInt32(0, 8 + i * 4);//filling undefined entries - } - setEntryCount(no+1); - } - setInt32(newChunkOffset, 8 + no * 4); - } - - uint32_t STCO::getChunkOffset(uint32_t no){ - if (no >= getEntryCount()){ - return 0; - } - return getInt32(8 + no * 4); - } - - std::string STCO::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stco] Chunk Offset Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i < getEntryCount(); i++){ - r << std::string(indent + 1, ' ') << "ChunkOffset[" << i <<"]: " << getChunkOffset(i) << std::endl; - } - return r.str(); - } - - STSZ::STSZ(char v, uint32_t f){ - memcpy(data + 4, "stsz", 4); - setVersion(v); - setFlags(f); - setSampleCount(0); - } - - void STSZ::setSampleSize(uint32_t newSampleSize){ - setInt32(newSampleSize, 4); - } - - uint32_t STSZ::getSampleSize(){ - return getInt32(4); - } - - void STSZ::setSampleCount(uint32_t newSampleCount){ - setInt32(newSampleCount, 8); - } - - uint32_t STSZ::getSampleCount(){ - return getInt32(8); - } - - void STSZ::setEntrySize(uint32_t newEntrySize, uint32_t no){ - if (no + 1 > getSampleCount()){ - setSampleCount(no + 1); - for (unsigned int i = getSampleCount(); i < no; i++){ - setInt32(0, 12 + i * 4);//filling undefined entries - } - } - setInt32(newEntrySize, 12 + no * 4); - } - - uint32_t STSZ::getEntrySize(uint32_t no){ - if (no >= getSampleCount()){ - return 0; - } - return getInt32(12 + no * 4); - } - - std::string STSZ::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stsz] Sample Size Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "SampleSize: " << getSampleSize() << std::endl; - r << std::string(indent + 1, ' ') << "SampleCount: " << getSampleCount() << std::endl; - for (unsigned int i = 0; i < getSampleCount(); i++){ - r << std::string(indent + 1, ' ') << "EntrySize[" << i <<"]: " << getEntrySize(i) << std::endl; - } - return r.str(); - } - - SampleEntry::SampleEntry(){ - memcpy(data + 4, "erro", 4); - } - - void SampleEntry::setDataReferenceIndex(uint16_t newDataReferenceIndex){ - setInt16(newDataReferenceIndex, 6); - } - - uint16_t SampleEntry::getDataReferenceIndex(){ - return getInt16(6); - } - - std::string SampleEntry::toPrettySampleString(uint32_t indent){ - std::stringstream r; - r << std::string(indent + 1, ' ') << "DataReferenceIndex: " << getDataReferenceIndex() << std::endl; - return r.str(); - } - - CLAP::CLAP(){ - memcpy(data + 4, "clap", 4); - setHorizOffN(0); - setHorizOffD(0); - setVertOffN(0); - setVertOffD(0); - } - - void CLAP::setCleanApertureWidthN(uint32_t newVal){ - setInt32(newVal,0); - } - - uint32_t CLAP::getCleanApertureWidthN(){ - return getInt32(0); - } - - void CLAP::setCleanApertureWidthD(uint32_t newVal){ - setInt32(newVal,4); - } - - uint32_t CLAP::getCleanApertureWidthD(){ - return getInt32(4); - } - - void CLAP::setCleanApertureHeightN(uint32_t newVal){ - setInt32(newVal,8); - } - - uint32_t CLAP::getCleanApertureHeightN(){ - return getInt32(8); - } - - void CLAP::setCleanApertureHeightD(uint32_t newVal){ - setInt32(newVal, 12); - } - - uint32_t CLAP::getCleanApertureHeightD(){ - return getInt32(12); - } - - void CLAP::setHorizOffN(uint32_t newVal){ - setInt32(newVal, 16); - } - - uint32_t CLAP::getHorizOffN(){ - return getInt32(16); - } - - void CLAP::setHorizOffD(uint32_t newVal){ - setInt32(newVal, 20); - } - - uint32_t CLAP::getHorizOffD(){ - return getInt32(20); - } - - void CLAP::setVertOffN(uint32_t newVal){ - setInt32(newVal, 24); - } - - uint32_t CLAP::getVertOffN(){ - return getInt32(24); - } - - void CLAP::setVertOffD(uint32_t newVal){ - setInt32(newVal, 28); - } - - uint32_t CLAP::getVertOffD(){ - return getInt32(32); - } - - std::string CLAP::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[clap] Clean Aperture Box (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "CleanApertureWidthN: " << getCleanApertureWidthN() << std::endl; - r << std::string(indent + 1, ' ') << "CleanApertureWidthD: " << getCleanApertureWidthD() << std::endl; - r << std::string(indent + 1, ' ') << "CleanApertureHeightN: " << getCleanApertureHeightN() << std::endl; - r << std::string(indent + 1, ' ') << "CleanApertureHeightD: " << getCleanApertureHeightD() << std::endl; - r << std::string(indent + 1, ' ') << "HorizOffN: " << getHorizOffN() << std::endl; - r << std::string(indent + 1, ' ') << "HorizOffD: " << getHorizOffD() << std::endl; - r << std::string(indent + 1, ' ') << "VertOffN: " << getVertOffN() << std::endl; - r << std::string(indent + 1, ' ') << "VertOffD: " << getVertOffD() << std::endl; - return r.str(); - } - - PASP::PASP(){ - memcpy(data + 4, "pasp", 4); - } - - void PASP::setHSpacing(uint32_t newVal){ - setInt32(newVal, 0); - } - - uint32_t PASP::getHSpacing(){ - return getInt32(0); - } - - void PASP::setVSpacing(uint32_t newVal){ - setInt32(newVal, 4); - } - - uint32_t PASP::getVSpacing(){ - return getInt32(4); - } - - std::string PASP::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[pasp] Pixel Aspect Ratio Box (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "HSpacing: " << getHSpacing() << std::endl; - r << std::string(indent + 1, ' ') << "VSpacing: " << getVSpacing() << std::endl; - return r.str(); - } - - VisualSampleEntry::VisualSampleEntry(){ - memcpy(data + 4, "erro", 4); - setHorizResolution(0x00480000); - setVertResolution(0x00480000); - setFrameCount(1); - setCompressorName(""); - setDepth(0x0018); - } - - void VisualSampleEntry::setCodec(const char* newCodec){ - memcpy(data + 4, newCodec, 4); - } - - void VisualSampleEntry::setWidth(uint16_t newWidth){ - setInt16(newWidth,24); - } - - uint16_t VisualSampleEntry::getWidth(){ - return getInt16(24); - } - - void VisualSampleEntry::setHeight(uint16_t newHeight){ - setInt16(newHeight, 26); - } - - uint16_t VisualSampleEntry::getHeight(){ - return getInt16(26); - } - - void VisualSampleEntry::setHorizResolution (uint32_t newHorizResolution){ - setInt32(newHorizResolution, 28); - } - - uint32_t VisualSampleEntry::getHorizResolution(){ - return getInt32(28); - } - - void VisualSampleEntry::setVertResolution (uint32_t newVertResolution){ - setInt32(newVertResolution,32); - } - - uint32_t VisualSampleEntry::getVertResolution(){ - return getInt32(32); - } - - void VisualSampleEntry::setFrameCount(uint16_t newFrameCount){ - setInt16(newFrameCount, 40); - } - - uint16_t VisualSampleEntry::getFrameCount(){ - return getInt16(40); - } - - void VisualSampleEntry::setCompressorName(std::string newCompressorName){ - newCompressorName.resize(32, ' '); - setString(newCompressorName,42); - } - - std::string VisualSampleEntry::getCompressorName(){ - return getString(42); - } - - void VisualSampleEntry::setDepth(uint16_t newDepth){ - setInt16(newDepth, 74); - } - - uint16_t VisualSampleEntry::getDepth(){ - return getInt16(74); - } - - void VisualSampleEntry::setCLAP(Box& clap){ - setBox(clap,78); - } - - Box & VisualSampleEntry::getCLAP(){ - static Box ret = Box((char*)"\000\000\000\010erro", false); - if(payloadSize() <84){//if the EntryBox is not big enough to hold a CLAP/PASP - ret = Box((char*)"\000\000\000\010erro", false); - return ret; - } - ret = Box(getBox(78).asBox(), false); - return ret; - } - - Box & VisualSampleEntry::getPASP(){ - static Box ret = Box((char*)"\000\000\000\010erro", false); - if(payloadSize() <84){//if the EntryBox is not big enough to hold a CLAP/PASP - ret = Box((char*)"\000\000\000\010erro", false); - return ret; - } - if (payloadSize() < 78 + getBoxLen(78) + 8){ - ret = Box((char*)"\000\000\000\010erro", false); - return ret; - } - ret = Box(getBox(78 + getBoxLen(78)).asBox(), false); - return ret; - } - - std::string VisualSampleEntry::toPrettyVisualString(uint32_t indent, std::string name){ - std::stringstream r; - r << std::string(indent, ' ') << name << " (" << boxedSize() << ")" << std::endl; - r << toPrettySampleString(indent); - r << std::string(indent + 1, ' ') << "Width: " << getWidth() << std::endl; - r << std::string(indent + 1, ' ') << "Height: " << getHeight() << std::endl; - r << std::string(indent + 1, ' ') << "HorizResolution: " << getHorizResolution() << std::endl; - r << std::string(indent + 1, ' ') << "VertResolution: " << getVertResolution() << std::endl; - r << std::string(indent + 1, ' ') << "FrameCount: " << getFrameCount() << std::endl; - r << std::string(indent + 1, ' ') << "CompressorName: " << getCompressorName() << std::endl; - r << std::string(indent + 1, ' ') << "Depth: " << getDepth() << std::endl; - if (!getCLAP().isType("erro")){ - r << getCLAP().toPrettyString(indent+1); - } - if (!getPASP().isType("erro")){ - r << getPASP().toPrettyString(indent+1); - } - return r.str(); - } - - AudioSampleEntry::AudioSampleEntry(){ - memcpy(data + 4, "erro", 4); - setChannelCount(2); - setSampleSize(16); - setSampleRate(44100); - } - - void AudioSampleEntry::setCodec(const char* newCodec){ - memcpy(data + 4, newCodec, 4); - } - - void AudioSampleEntry::setChannelCount(uint16_t newChannelCount){ - setInt16(newChannelCount,16); - } - - uint16_t AudioSampleEntry::getChannelCount(){ - return getInt16(16); - } - - void AudioSampleEntry::setSampleSize(uint16_t newSampleSize){ - setInt16(newSampleSize,18); - } - - uint16_t AudioSampleEntry::getSampleSize(){ - return getInt16(18); - } - - void AudioSampleEntry::setPreDefined(uint16_t newPreDefined){ - setInt16(newPreDefined,20); - } - - uint16_t AudioSampleEntry::getPreDefined(){ - return getInt16(20); - } - - void AudioSampleEntry::setSampleRate(uint32_t newSampleRate){ - setInt32(newSampleRate << 16, 24); - } - - uint32_t AudioSampleEntry::getSampleRate(){ - return getInt32(24) >> 16; - } - - uint16_t AudioSampleEntry::toAACInit(){ - uint16_t result = 0; - result |= (2 & 0x1F) << 11; - result |= (getSampleRate() & 0x0F) << 7; - result |= (getChannelCount() & 0x0F) << 3; - return result; - } - - void AudioSampleEntry::setCodecBox(Box& newBox){ - setBox(newBox, 28); - } - - Box & AudioSampleEntry::getCodecBox(){ - return getBox(28); - } - - std::string AudioSampleEntry::toPrettyAudioString(uint32_t indent, std::string name){ - std::stringstream r; - r << std::string(indent, ' ') << name << " (" << boxedSize() << ")" << std::endl; - r << toPrettySampleString(indent); - r << std::string(indent + 1, ' ') << "ChannelCount: " << getChannelCount() << std::endl; - r << std::string(indent + 1, ' ') << "SampleSize: " << getSampleSize() << std::endl; - r << std::string(indent + 1, ' ') << "PreDefined: " << getPreDefined() << std::endl; - r << std::string(indent + 1, ' ') << "SampleRate: " << getSampleRate() << std::endl; - r << getCodecBox().toPrettyString(indent + 1); - return r.str(); - } - - MP4A::MP4A(){ - memcpy(data + 4, "mp4a", 4); - } - - std::string MP4A::toPrettyString(uint32_t indent){ - return toPrettyAudioString(indent, "[mp4a] MPEG-4 Audio"); - } - - AAC::AAC(){ - memcpy(data + 4, "aac ", 4); - } - - std::string AAC::toPrettyString(uint32_t indent){ - return toPrettyAudioString(indent, "[aac ] Advanced Audio Codec"); - } - - AVC1::AVC1(){ - memcpy(data + 4, "avc1", 4); - } - - std::string AVC1::toPrettyString(uint32_t indent){ - return toPrettyVisualString(indent, "[avc1] Advanced Video Codec 1"); - } - - H264::H264(){ - memcpy(data + 4, "h264", 4); - } - - std::string H264::toPrettyString(uint32_t indent){ - return toPrettyVisualString(indent, "[h264] H.264/MPEG-4 AVC"); - } - - STSD::STSD(char v, uint32_t f){ - memcpy(data + 4, "stsd", 4); - setVersion(v); - setFlags(f); - setEntryCount(0); - } - - void STSD::setEntryCount (uint32_t newEntryCount){ - setInt32(newEntryCount, 4); - } - - uint32_t STSD::getEntryCount(){ - return getInt32(4); - } - - void STSD::setEntry(Box & newContent, uint32_t no){ - int tempLoc = 8; - unsigned int entryCount = getEntryCount(); - for (unsigned int i = 0; i < no; i++){ - if (i < entryCount){ - tempLoc += getBoxLen(tempLoc); - }else{ - if ( !reserve(tempLoc, 0, (no - entryCount) * 8)){ - return; - } - memset(data + tempLoc, 0, (no - entryCount) * 8); - tempLoc += (no - entryCount) * 8; - break; - } - } - setBox(newContent, tempLoc); - if (getEntryCount() < no+1){ - setEntryCount(no+1); - } - } - - Box & STSD::getEntry(uint32_t no){ - static Box ret = Box((char*)"\000\000\000\010erro", false); - if (no > getEntryCount()){ - return ret; - } - unsigned int i = 0; - int tempLoc = 8; - while (i < no){ - tempLoc += getBoxLen(tempLoc); - i++; - } - return getBox(tempLoc); - } - - std::string STSD::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stsd] Sample Description Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntrySize: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i < getEntryCount(); i++){ - Box curBox = Box(getEntry(i).asBox(), false); - r << curBox.toPrettyString(indent + 1); - } - return r.str(); - } - - EDTS::EDTS(){ - memcpy(data + 4, "edts", 4); - } - - std::string EDTS::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[edts] Edit Box")); - } - - UDTA::UDTA(){ - memcpy(data + 4, "udta", 4); - } - - std::string UDTA::toPrettyString(uint32_t indent){ - return toPrettyContainerString(indent, std::string("[udta] User Data Box")); - } - - STSS::STSS(char v, uint32_t f){ - memcpy(data + 4, "stss", 4); - setVersion(v); - setFlags(f); - setEntryCount(0); - } - - void STSS::setEntryCount(uint32_t newVal){ - setInt32(newVal, 4); - } - - uint32_t STSS::getEntryCount(){ - return getInt32(4); - } - - void STSS::setSampleNumber(uint32_t newVal, uint32_t index){ - if (index >= getEntryCount()){ - setEntryCount(index + 1); - } - setInt32(newVal, 8 + (index * 4)); - } - - uint32_t STSS::getSampleNumber(uint32_t index){ - if (index >= getEntryCount()){ - return 0; - } - return getInt32(8 + (index * 4)); - } - - std::string STSS::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[stss] Sync Sample Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; - for (unsigned int i = 0; i < getEntryCount(); i++){ - r << std::string(indent + 1, ' ') << "SampleNumber[" << i <<"] : " << getSampleNumber(i) << std::endl; - } - return r.str(); - } - - META::META(){ - memcpy(data + 4, "meta", 4); - } - - std::string META::toPrettyString(uint32_t indent){ - return toPrettyCFBString(indent, "[meta] Meta Box"); - } - - ELST::ELST(){ - memcpy(data + 4, "elst", 4); - } - - void ELST::setSegmentDuration(uint64_t newVal){ - if (getVersion() == 1){ - setInt64(newVal, 4); - }else{ - setInt32(newVal, 4); - } - } - - uint64_t ELST::getSegmentDuration(){ - if (getVersion() == 1){ - return getInt64(4); - }else{ - return getInt32(4); - } - } - - void ELST::setMediaTime(uint64_t newVal){ - if (getVersion() == 1){ - setInt64(newVal, 12); - }else{ - setInt32(newVal, 8); - } - } - - uint64_t ELST::getMediaTime(){ - if (getVersion() == 1){ - return getInt64(12); - }else{ - return getInt32(8); - } - } - - void ELST::setMediaRateInteger(uint16_t newVal){ - if (getVersion() == 1){ - setInt16(newVal, 20); - }else{ - setInt16(newVal, 12); - } - } - - uint16_t ELST::getMediaRateInteger(){ - if (getVersion() == 1){ - return getInt16(20); - }else{ - return getInt16(12); - } - } - - void ELST::setMediaRateFraction(uint16_t newVal){ - if (getVersion() == 1){ - setInt16(newVal, 22); - }else{ - setInt16(newVal, 14); - } - } - - uint16_t ELST::getMediaRateFraction(){ - if (getVersion() == 1){ - return getInt16(22); - }else{ - return getInt16(14); - } - } - - std::string ELST::toPrettyString(uint32_t indent){ - std::stringstream r; - r << std::string(indent, ' ') << "[elst] Edit List Box (" << boxedSize() << ")" << std::endl; - r << fullBox::toPrettyString(indent); - r << std::string(indent + 1, ' ') << "SegmentDuration: " << getSegmentDuration() << std::endl; - r << std::string(indent + 1, ' ') << "MediaTime: " << getMediaTime() << std::endl; - r << std::string(indent + 1, ' ') << "MediaRateInteger: " << getMediaRateInteger() << std::endl; - r << std::string(indent + 1, ' ') << "MediaRateFraction: " << getMediaRateFraction() << std::endl; - return r.str(); - } - - 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; - } - - UUID::UUID(){ - memcpy(data + 4, "uuid", 4); - setInt64(0, 0); - setInt64(0, 8); - } - - 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 << "-"; - } - 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 - int i = 0; - 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); - } - - std::string UUID::toPrettyString(uint32_t indent){ - std::string UUID = getUUID(); - if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f"){ - return ((UUID_TrackFragmentReference*)this)->toPrettyString(indent); - } - std::stringstream r; - r << std::string(indent, ' ') << "[uuid] Extension box (" << boxedSize() << ")" << std::endl; - r << std::string(indent + 1, ' ') << "UUID: " << UUID << std::endl; - r << std::string(indent + 1, ' ') << "Unknown UUID - ignoring contents." << std::endl; - return r.str(); - } - - UUID_TrackFragmentReference::UUID_TrackFragmentReference(){ - setUUID((std::string)"d4807ef2-ca39-4695-8e54-26cb9e46a79f"); - } - - void UUID_TrackFragmentReference::setVersion(uint32_t newVersion){ - setInt8(newVersion, 16); - } - - uint32_t UUID_TrackFragmentReference::getVersion(){ - return getInt8(16); - } - - void UUID_TrackFragmentReference::setFlags(uint32_t newFlags){ - setInt24(newFlags, 17); - } - - uint32_t UUID_TrackFragmentReference::getFlags(){ - return getInt24(17); - } - - void UUID_TrackFragmentReference::setFragmentCount(uint32_t newCount){ - setInt8(newCount, 20); - } - - uint32_t UUID_TrackFragmentReference::getFragmentCount(){ - return getInt8(20); - } - - void UUID_TrackFragmentReference::setTime(size_t num, uint64_t newTime){ - if (getVersion() == 0){ - setInt32(newTime, 21+(num*8)); - }else{ - setInt64(newTime, 21+(num*16)); - } - } - - uint64_t UUID_TrackFragmentReference::getTime(size_t num){ - if (getVersion() == 0){ - return getInt32(21+(num*8)); - }else{ - return getInt64(21+(num*16)); - } - } - - void UUID_TrackFragmentReference::setDuration(size_t num, uint64_t newDuration){ - if (getVersion() == 0){ - setInt32(newDuration, 21+(num*8)+4); - }else{ - setInt64(newDuration, 21+(num*16)+8); - } - } - - uint64_t UUID_TrackFragmentReference::getDuration(size_t num){ - if (getVersion() == 0){ - return getInt32(21+(num*8)+4); - }else{ - return getInt64(21+(num*16)+8); - } - } - - 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 + 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; - } - return r.str(); - } - - } diff --git a/lib/mp4.h b/lib/mp4.h index 0715171e..4eeb18de 100644 --- a/lib/mp4.h +++ b/lib/mp4.h @@ -28,27 +28,16 @@ namespace MP4 { } return false; } - long long int trackID; - long long int size; - long long int time; - long long int len; - std::deque parts; - long long int partsize; + long unsigned int trackID; + long unsigned int size; + long long unsigned int time; + long long unsigned int endTime; + long unsigned int index; }; class DTSC2MP4Converter{ public: std::string DTSCMeta2MP4Header(DTSC::Meta & metaData); - void parseDTSC(JSON::Value mediaPart); - bool sendReady(); - std::string sendString(); - std::string purgeBuffer(); - std::set keyParts; - private: - //long long unsigned int curKey;//the key chunk we are currently searching for in keyParts - //long long unsigned int curPart;//current part in current key - std::map > trackBuffer; - std::string stringBuffer; }; class Box{ @@ -89,7 +78,7 @@ namespace MP4 { bool reserve(size_t position, size_t current, size_t wanted); //internal variables char * data; ///< Holds the data of this box - int data_size; ///< Currently reserved size + unsigned int data_size; ///< Currently reserved size bool managed; ///< If false, will not attempt to resize/free the data pointer. int payloadOffset; /// getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; + } + //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. + setString(newEntry, tempLoc); + } + + ///\return Empty string if no > serverEntryCount(), serverEntry[no] otherwise. + const char* ABST::getServerEntry(uint32_t no){ + if (no + 1 > getServerEntryCount()){ + return ""; + } + int tempLoc = 29 + getStringLen(29) + 1 + 1; //position of first entry + for (unsigned int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + uint32_t ABST::getQualityEntryCount(){ + int countLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + countLoc += getStringLen(countLoc) + 1; + } + return getInt8(countLoc); + } + + void ABST::setQualityEntry(std::string & newEntry, uint32_t no){ + int countLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + countLoc += getStringLen(countLoc) + 1; + } + int tempLoc = countLoc + 1; + //attempt to reach the wanted position + unsigned int i; + for (i = 0; i < getInt8(countLoc) && i < no; ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + //we are now either at the end, or at the right position + //let's reserve any unreserved space... + if (no + 1 > getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; + } + //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. + setString(newEntry, tempLoc); + } + + const char* ABST::getQualityEntry(uint32_t no){ + if (no > getQualityEntryCount()){ + return ""; + } + int tempLoc = 29 + getStringLen(29) + 1 + 1; //position of serverentries; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += 1; //first qualityentry + for (unsigned int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + void ABST::setDrmData(std::string newDrm){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + setString(newDrm, tempLoc); + } + + char* ABST::getDrmData(){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + void ABST::setMetaData(std::string newMetaData){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; + setString(newMetaData, tempLoc); + } + + char* ABST::getMetaData(){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; + return getString(tempLoc); + } + + uint32_t ABST::getSegmentRunTableCount(){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + return getInt8(tempLoc); + } + + void ABST::setSegmentRunTable(ASRT & newSegment, uint32_t no){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + int countLoc = tempLoc; + tempLoc++; //skip segmentRuntableCount + //attempt to reach the wanted position + unsigned int i; + for (i = 0; i < getInt8(countLoc) && i < no; ++i){ + tempLoc += getBoxLen(tempLoc); + } + //we are now either at the end, or at the right position + //let's reserve any unreserved space... + if (no + 1 > getInt8(countLoc)){ + int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount * 8)){ + return; + }; + //set empty erro boxes as contents + for (int j = 0; j < amount; ++j){ + memcpy(data + payloadOffset + tempLoc + j * 8, "\000\000\000\010erro", 8); + } + setInt8(no + 1, countLoc); //set new count + tempLoc += (no - i) * 8; + } + //now, tempLoc is at position for string number no, and we have at least an erro box reserved. + setBox(newSegment, tempLoc); + } + + ASRT & ABST::getSegmentRunTable(uint32_t no){ + static Box result; + if (no > getSegmentRunTableCount()){ + static Box res; + return (ASRT&)res; + } + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + tempLoc++; //segmentRuntableCount + for (unsigned int i = 0; i < no; ++i){ + tempLoc += getBoxLen(tempLoc); + } + return (ASRT&)getBox(tempLoc); + } + + uint32_t ABST::getFragmentRunTableCount(){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + for (unsigned int i = getInt8(tempLoc++); i != 0; --i){ + tempLoc += getBoxLen(tempLoc); + } + return getInt8(tempLoc); + } + + void ABST::setFragmentRunTable(AFRT & newFragment, uint32_t no){ + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + for (unsigned int i = getInt8(tempLoc++); i != 0; --i){ + tempLoc += getBoxLen(tempLoc); + } + int countLoc = tempLoc; + tempLoc++; + //attempt to reach the wanted position + unsigned int i; + for (i = 0; i < getInt8(countLoc) && i < no; ++i){ + tempLoc += getBoxLen(tempLoc); + } + //we are now either at the end, or at the right position + //let's reserve any unreserved space... + if (no + 1 > getInt8(countLoc)){ + unsigned int amount = no + 1 - getInt8(countLoc); + if ( !reserve(payloadOffset + tempLoc, 0, amount * 8)){ + return; + }; + //set empty erro boxes as contents + for (unsigned int j = 0; j < amount; ++j){ + memcpy(data + payloadOffset + tempLoc + j * 8, "\000\000\000\010erro", 8); + } + setInt8(no + 1, countLoc); //set new count + tempLoc += (no - i) * 8; + } + //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. + setBox(newFragment, tempLoc); + } + + AFRT & ABST::getFragmentRunTable(uint32_t no){ + static Box result; + if (no >= getFragmentRunTableCount()){ + static Box res; + return (AFRT&)res; + } + uint32_t tempLoc = 29 + getStringLen(29) + 1 + 1; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc++; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += getStringLen(tempLoc) + 1; //DrmData + tempLoc += getStringLen(tempLoc) + 1; //MetaData + for (unsigned int i = getInt8(tempLoc++); i != 0; --i){ + tempLoc += getBoxLen(tempLoc); + } + tempLoc++; + for (unsigned int i = 0; i < no; i++){ + tempLoc += getBoxLen(tempLoc); + } + return (AFRT&)getBox(tempLoc); + } + + std::string ABST::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[abst] Bootstrap Info (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "BootstrapinfoVersion " << getBootstrapinfoVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Profile " << (int)getProfile() << std::endl; + if (getLive()){ + r << std::string(indent + 1, ' ') << "Live" << std::endl; + }else{ + r << std::string(indent + 1, ' ') << "Recorded" << std::endl; + } + if (getUpdate()){ + r << std::string(indent + 1, ' ') << "Update" << std::endl; + }else{ + r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; + } + r << std::string(indent + 1, ' ') << "Timescale " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "CurrMediaTime " << getCurrentMediaTime() << std::endl; + r << std::string(indent + 1, ' ') << "SmpteTimeCodeOffset " << getSmpteTimeCodeOffset() << std::endl; + r << std::string(indent + 1, ' ') << "MovieIdentifier " << getMovieIdentifier() << std::endl; + r << std::string(indent + 1, ' ') << "ServerEntryTable (" << getServerEntryCount() << ")" << std::endl; + for (unsigned int i = 0; i < getServerEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getServerEntry(i) << std::endl; + } + r << std::string(indent + 1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; + } + r << std::string(indent + 1, ' ') << "DrmData " << getDrmData() << std::endl; + r << std::string(indent + 1, ' ') << "MetaData " << getMetaData() << std::endl; + r << std::string(indent + 1, ' ') << "SegmentRunTableEntries (" << getSegmentRunTableCount() << ")" << std::endl; + for (uint32_t i = 0; i < getSegmentRunTableCount(); i++){ + r << ((Box)getSegmentRunTable(i)).toPrettyString(indent + 2); + } + r << std::string(indent + 1, ' ') + "FragmentRunTableEntries (" << getFragmentRunTableCount() << ")" << std::endl; + for (uint32_t i = 0; i < getFragmentRunTableCount(); i++){ + r << ((Box)getFragmentRunTable(i)).toPrettyString(indent + 2); + } + return r.str(); + } + + AFRT::AFRT(){ + memcpy(data + 4, "afrt", 4); + setVersion(0); + setUpdate(0); + setTimeScale(1000); + } + + void AFRT::setVersion(char newVersion){ + setInt8(newVersion, 0); + } + + uint32_t AFRT::getVersion(){ + return getInt8(0); + } + + void AFRT::setUpdate(uint32_t newUpdate){ + setInt24(newUpdate, 1); + } + + uint32_t AFRT::getUpdate(){ + return getInt24(1); + } + + void AFRT::setTimeScale(uint32_t newScale){ + setInt32(newScale, 4); + } + + uint32_t AFRT::getTimeScale(){ + return getInt32(4); + } + + uint32_t AFRT::getQualityEntryCount(){ + return getInt8(8); + } + + void AFRT::setQualityEntry(std::string & newEntry, uint32_t no){ + int countLoc = 8; + int tempLoc = countLoc + 1; + //attempt to reach the wanted position + unsigned int i; + for (i = 0; i < getQualityEntryCount() && i < no; ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + //we are now either at the end, or at the right position + //let's reserve any unreserved space... + if (no + 1 > getQualityEntryCount()){ + int amount = no + 1 - getQualityEntryCount(); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; + } + //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. + setString(newEntry, tempLoc); + } + + const char* AFRT::getQualityEntry(uint32_t no){ + if (no + 1 > getQualityEntryCount()){ + return ""; + } + int tempLoc = 9; //position of first quality entry + for (unsigned int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + uint32_t AFRT::getFragmentRunCount(){ + int tempLoc = 9; + for (unsigned int i = 0; i < getQualityEntryCount(); ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getInt32(tempLoc); + } + + void AFRT::setFragmentRun(afrt_runtable newRun, uint32_t no){ + int tempLoc = 9; + for (unsigned int i = 0; i < getQualityEntryCount(); ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + int countLoc = tempLoc; + tempLoc += 4; + for (unsigned int i = 0; i < no; i++){ + if (i + 1 > getInt32(countLoc)){ + setInt32(0, tempLoc); + setInt64(0, tempLoc + 4); + setInt32(1, tempLoc + 12); + } + if (getInt32(tempLoc + 12) == 0){ + tempLoc += 17; + }else{ + tempLoc += 16; + } + } + setInt32(newRun.firstFragment, tempLoc); + setInt64(newRun.firstTimestamp, tempLoc + 4); + setInt32(newRun.duration, tempLoc + 12); + if (newRun.duration == 0){ + setInt8(newRun.discontinuity, tempLoc + 16); + } + if (getInt32(countLoc) < no + 1){ + setInt32(no + 1, countLoc); + } + } + + afrt_runtable AFRT::getFragmentRun(uint32_t no){ + afrt_runtable res; + if (no > getFragmentRunCount()){ + return res; + } + int tempLoc = 9; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += 4; + for (unsigned int i = 0; i < no; i++){ + if (getInt32(tempLoc + 12) == 0){ + tempLoc += 17; + }else{ + tempLoc += 16; + } + } + res.firstFragment = getInt32(tempLoc); + res.firstTimestamp = getInt64(tempLoc + 4); + res.duration = getInt32(tempLoc + 12); + if (res.duration){ + res.discontinuity = getInt8(tempLoc + 16); + }else{ + res.discontinuity = 0; + } + return res; + } + + std::string AFRT::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[afrt] Fragment Run Table (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getVersion() << std::endl; + if (getUpdate()){ + r << std::string(indent + 1, ' ') << "Update" << std::endl; + }else{ + r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; + } + r << std::string(indent + 1, ' ') << "Timescale " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "QualitySegmentUrlModifiers (" << getQualityEntryCount() << ")" << std::endl; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; + } + r << std::string(indent + 1, ' ') << "FragmentRunEntryTable (" << getFragmentRunCount() << ")" << std::endl; + for (unsigned int i = 0; i < getFragmentRunCount(); i++){ + afrt_runtable myRun = getFragmentRun(i); + if (myRun.duration){ + r << std::string(indent + 2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) + << "s, " << ((double)myRun.duration / (double)getTimeScale()) << "s per fragment." << std::endl; + }else{ + r << std::string(indent + 2, ' ') << i << ": " << myRun.firstFragment << " is at " << ((double)myRun.firstTimestamp / (double)getTimeScale()) + << "s, discontinuity type " << myRun.discontinuity << std::endl; + } + } + return r.str(); + } + + ASRT::ASRT(){ + memcpy(data + 4, "asrt", 4); + setVersion(0); + setUpdate(0); + } + + void ASRT::setVersion(char newVersion){ + setInt8(newVersion, 0); + } + + uint32_t ASRT::getVersion(){ + return getInt8(0); + } + + void ASRT::setUpdate(uint32_t newUpdate){ + setInt24(newUpdate, 1); + } + + uint32_t ASRT::getUpdate(){ + return getInt24(1); + } + + uint32_t ASRT::getQualityEntryCount(){ + return getInt8(4); + } + + void ASRT::setQualityEntry(std::string & newEntry, uint32_t no){ + int countLoc = 4; + int tempLoc = countLoc + 1; + //attempt to reach the wanted position + unsigned int i; + for (i = 0; i < getQualityEntryCount() && i < no; ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + //we are now either at the end, or at the right position + //let's reserve any unreserved space... + if (no + 1 > getQualityEntryCount()){ + int amount = no + 1 - getQualityEntryCount(); + if ( !reserve(payloadOffset + tempLoc, 0, amount)){ + return; + }; + memset(data + payloadOffset + tempLoc, 0, amount); + setInt8(no + 1, countLoc); //set new qualityEntryCount + tempLoc += no - i; + } + //now, tempLoc is at position for string number no, and we have at least 1 byte reserved. + setString(newEntry, tempLoc); + } + + const char* ASRT::getQualityEntry(uint32_t no){ + if (no > getQualityEntryCount()){ + return ""; + } + int tempLoc = 5; //position of qualityentry count; + for (unsigned int i = 0; i < no; i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getString(tempLoc); + } + + uint32_t ASRT::getSegmentRunEntryCount(){ + int tempLoc = 5; //position of qualityentry count; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + return getInt32(tempLoc); + } + + void ASRT::setSegmentRun(uint32_t firstSegment, uint32_t fragmentsPerSegment, uint32_t no){ + int tempLoc = 5; //position of qualityentry count; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + tempLoc += getStringLen(tempLoc) + 1; + } + int countLoc = tempLoc; + tempLoc += 4 + no * 8; + if (no + 1 > getInt32(countLoc)){ + setInt32(no + 1, countLoc); //set new qualityEntryCount + } + setInt32(firstSegment, tempLoc); + setInt32(fragmentsPerSegment, tempLoc + 4); + } + + asrt_runtable ASRT::getSegmentRun(uint32_t no){ + asrt_runtable res; + if (no >= getSegmentRunEntryCount()){ + return res; + } + int tempLoc = 5; //position of qualityentry count; + for (unsigned int i = 0; i < getQualityEntryCount(); ++i){ + tempLoc += getStringLen(tempLoc) + 1; + } + tempLoc += 4 + 8 * no; + res.firstSegment = getInt32(tempLoc); + res.fragmentsPerSegment = getInt32(tempLoc + 4); + return res; + } + + std::string ASRT::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[asrt] Segment Run Table (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << getVersion() << std::endl; + if (getUpdate()){ + r << std::string(indent + 1, ' ') << "Update" << std::endl; + }else{ + r << std::string(indent + 1, ' ') << "Replacement or new table" << std::endl; + } + r << std::string(indent + 1, ' ') << "QualityEntryTable (" << getQualityEntryCount() << ")" << std::endl; + for (unsigned int i = 0; i < getQualityEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": " << getQualityEntry(i) << std::endl; + } + r << std::string(indent + 1, ' ') << "SegmentRunEntryTable (" << getSegmentRunEntryCount() << ")" << std::endl; + for (unsigned int i = 0; i < getSegmentRunEntryCount(); i++){ + r << std::string(indent + 2, ' ') << i << ": First=" << getSegmentRun(i).firstSegment << ", FragmentsPerSegment=" + << getSegmentRun(i).fragmentsPerSegment << std::endl; + } + return r.str(); + } + AFRA::AFRA(){ + memcpy(data + 4, "afra", 4); + setInt32(0, 9); //entrycount = 0 + setFlags(0); + } + + void AFRA::setVersion(uint32_t newVersion){ + setInt8(newVersion, 0); + } + + uint32_t AFRA::getVersion(){ + return getInt8(0); + } + + void AFRA::setFlags(uint32_t newFlags){ + setInt24(newFlags, 1); + } + + uint32_t AFRA::getFlags(){ + return getInt24(1); + } + + void AFRA::setLongIDs(bool newVal){ + if (newVal){ + setInt8((getInt8(4) & 0x7F) + 0x80, 4); + }else{ + setInt8((getInt8(4) & 0x7F), 4); + } + } + + bool AFRA::getLongIDs(){ + return getInt8(4) & 0x80; + } + + void AFRA::setLongOffsets(bool newVal){ + if (newVal){ + setInt8((getInt8(4) & 0xBF) + 0x40, 4); + }else{ + setInt8((getInt8(4) & 0xBF), 4); + } + } + + bool AFRA::getLongOffsets(){ + return getInt8(4) & 0x40; + } + + void AFRA::setGlobalEntries(bool newVal){ + if (newVal){ + setInt8((getInt8(4) & 0xDF) + 0x20, 4); + }else{ + setInt8((getInt8(4) & 0xDF), 4); + } + } + + bool AFRA::getGlobalEntries(){ + return getInt8(4) & 0x20; + } + + void AFRA::setTimeScale(uint32_t newVal){ + setInt32(newVal, 5); + } + + uint32_t AFRA::getTimeScale(){ + return getInt32(5); + } + + uint32_t AFRA::getEntryCount(){ + return getInt32(9); + } + + void AFRA::setEntry(afraentry newEntry, uint32_t no){ + int entrysize = 12; + if (getLongOffsets()){ + entrysize = 16; + } + setInt64(newEntry.time, 13 + entrysize * no); + if (getLongOffsets()){ + setInt64(newEntry.offset, 21 + entrysize * no); + }else{ + setInt32(newEntry.offset, 21 + entrysize * no); + } + if (no + 1 > getEntryCount()){ + setInt32(no + 1, 9); + } + } + + afraentry AFRA::getEntry(uint32_t no){ + afraentry ret; + int entrysize = 12; + if (getLongOffsets()){ + entrysize = 16; + } + ret.time = getInt64(13 + entrysize * no); + if (getLongOffsets()){ + ret.offset = getInt64(21 + entrysize * no); + }else{ + ret.offset = getInt32(21 + entrysize * no); + } + return ret; + } + + uint32_t AFRA::getGlobalEntryCount(){ + if ( !getGlobalEntries()){ + return 0; + } + int entrysize = 12; + if (getLongOffsets()){ + entrysize = 16; + } + return getInt32(13 + entrysize * getEntryCount()); + } + + void AFRA::setGlobalEntry(globalafraentry newEntry, uint32_t no){ + int offset = 13 + 12 * getEntryCount() + 4; + if (getLongOffsets()){ + offset = 13 + 16 * getEntryCount() + 4; + } + int entrysize = 20; + if (getLongIDs()){ + entrysize += 4; + } + if (getLongOffsets()){ + entrysize += 8; + } + + setInt64(newEntry.time, offset + entrysize * no); + if (getLongIDs()){ + setInt32(newEntry.segment, offset + entrysize * no + 8); + setInt32(newEntry.fragment, offset + entrysize * no + 12); + }else{ + setInt16(newEntry.segment, offset + entrysize * no + 8); + setInt16(newEntry.fragment, offset + entrysize * no + 10); + } + if (getLongOffsets()){ + setInt64(newEntry.afraoffset, offset + entrysize * no + entrysize - 16); + setInt64(newEntry.offsetfromafra, offset + entrysize * no + entrysize - 8); + }else{ + setInt32(newEntry.afraoffset, offset + entrysize * no + entrysize - 8); + setInt32(newEntry.offsetfromafra, offset + entrysize * no + entrysize - 4); + } + + if (getInt32(offset - 4) < no + 1){ + setInt32(no + 1, offset - 4); + } + } + + globalafraentry AFRA::getGlobalEntry(uint32_t no){ + globalafraentry ret; + int offset = 13 + 12 * getEntryCount() + 4; + if (getLongOffsets()){ + offset = 13 + 16 * getEntryCount() + 4; + } + int entrysize = 20; + if (getLongIDs()){ + entrysize += 4; + } + if (getLongOffsets()){ + entrysize += 8; + } + + ret.time = getInt64(offset + entrysize * no); + if (getLongIDs()){ + ret.segment = getInt32(offset + entrysize * no + 8); + ret.fragment = getInt32(offset + entrysize * no + 12); + }else{ + ret.segment = getInt16(offset + entrysize * no + 8); + ret.fragment = getInt16(offset + entrysize * no + 10); + } + if (getLongOffsets()){ + ret.afraoffset = getInt64(offset + entrysize * no + entrysize - 16); + ret.offsetfromafra = getInt64(offset + entrysize * no + entrysize - 8); + }else{ + ret.afraoffset = getInt32(offset + entrysize * no + entrysize - 8); + ret.offsetfromafra = getInt32(offset + entrysize * no + entrysize - 4); + } + return ret; + } + + std::string AFRA::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[afra] Fragment Random Access (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Flags " << getFlags() << std::endl; + r << std::string(indent + 1, ' ') << "Long IDs " << getLongIDs() << std::endl; + r << std::string(indent + 1, ' ') << "Long Offsets " << getLongOffsets() << std::endl; + r << std::string(indent + 1, ' ') << "Global Entries " << getGlobalEntries() << std::endl; + r << std::string(indent + 1, ' ') << "TimeScale " << getTimeScale() << std::endl; + + uint32_t count = getEntryCount(); + r << std::string(indent + 1, ' ') << "Entries (" << count << ") " << std::endl; + for (uint32_t i = 0; i < count; ++i){ + afraentry tmpent = getEntry(i); + r << std::string(indent + 1, ' ') << i << ": Time " << tmpent.time << ", Offset " << tmpent.offset << std::endl; + } + + if (getGlobalEntries()){ + count = getGlobalEntryCount(); + r << std::string(indent + 1, ' ') << "Global Entries (" << count << ") " << std::endl; + for (uint32_t i = 0; i < count; ++i){ + globalafraentry tmpent = getGlobalEntry(i); + r << std::string(indent + 1, ' ') << i << ": T " << tmpent.time << ", S" << tmpent.segment << "F" << tmpent.fragment << ", " + << tmpent.afraoffset << "/" << tmpent.offsetfromafra << std::endl; + } + } + return r.str(); + } +} diff --git a/lib/mp4_adobe.h b/lib/mp4_adobe.h new file mode 100644 index 00000000..3ab14fcc --- /dev/null +++ b/lib/mp4_adobe.h @@ -0,0 +1,139 @@ +#pragma once +#include "mp4.h" +#include + +namespace MP4 { + //class Box; + + struct afrt_runtable{ + uint32_t firstFragment; + uint64_t firstTimestamp; + uint32_t duration; + uint32_t discontinuity; + }; + //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); + }; + //AFRT Box + + 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); + }; + //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); + }; + //ABST Box + + struct afraentry{ + uint64_t time; + uint64_t offset; + }; + 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); + }; + +} + diff --git a/lib/mp4_conv.cpp b/lib/mp4_conv.cpp index 7810e6f4..4b249359 100644 --- a/lib/mp4_conv.cpp +++ b/lib/mp4_conv.cpp @@ -1,4 +1,4 @@ -#include "mp4.h" +#include "mp4_generic.h" #include namespace MP4{ @@ -17,21 +17,22 @@ namespace MP4{ uint64_t mdatSize = 0; //moov box - MP4::MOOV moovBox; + MP4::MOOV moovBox;{ + //calculating longest duration + long long int fileDuration = 0; + /// \todo lastms and firstms fix + for ( std::map::iterator trackIt = metaData.tracks.begin(); trackIt != metaData.tracks.end(); trackIt ++) { + if (trackIt->second.lastms - trackIt->second.firstms > fileDuration){ + fileDuration = trackIt->second.lastms - trackIt->second.firstms; + } + } + //MP4::MVHD mvhdBox(fileDuration); MP4::MVHD mvhdBox; mvhdBox.setVersion(0); mvhdBox.setCreationTime(0); mvhdBox.setModificationTime(0); mvhdBox.setTimeScale(1000); mvhdBox.setRate(0x10000); - //calculating longest duration - int fileDuration = 0; - ///\ odo lastms and firstms fixen - for ( std::map::iterator trackIt = metaData.tracks.begin(); trackIt != metaData.tracks.end(); trackIt ++) { - if (trackIt->second.lastms - trackIt->second.firstms > fileDuration){ - fileDuration = trackIt->second.lastms - trackIt->second.firstms; - } - } mvhdBox.setDuration(fileDuration); mvhdBox.setTrackID(0); mvhdBox.setVolume(256); @@ -45,50 +46,11 @@ namespace MP4{ mvhdBox.setMatrix(0,7); mvhdBox.setMatrix(0x40000000,8); moovBox.setContent(mvhdBox, 0); - + } + {//start arbitrary track addition for header + int boxOffset = 1; bool seenAudio = false; bool seenVideo = false; - - //calculate interleaving - //putting all metadata in a huge, auto-sorting vector 'keyParts' - //sort by time on keyframes for interleaving - keyParts.clear(); - for ( std::map::iterator trackIt = metaData.tracks.begin(); trackIt != metaData.tracks.end(); trackIt ++) { - if (trackIt->second.codec != "AAC" && trackIt->second.codec != "H264"){continue;} - if (trackIt->second.type == "audio"){ - if (seenAudio){continue;} - seenAudio = true; - } - if (trackIt->second.type == "video"){ - if (seenVideo){continue;} - seenVideo = true; - } - if (trackIt->first>0){ - int partItNumber = 0; - for ( std::deque< DTSC::Key>::iterator keyIt = trackIt->second.keys.begin(); keyIt != trackIt->second.keys.end(); keyIt ++) { - keyPart temp; - temp.trackID = trackIt->second.trackID; - temp.time = keyIt->getTime();//timeplaats van keyframe - temp.len = keyIt->getLength();//duration van keyframe - temp.parts = std::deque (trackIt->second.parts.begin() + partItNumber,trackIt->second.parts.begin() + partItNumber + keyIt->getParts() );//array met bytegrootte van elke aparte part - //calculate total size of parts - int tempSize = 0; - for (unsigned int di = 0; di < temp.parts.size(); di++){ - tempSize += temp.parts[di].getSize(); - } - temp.size = tempSize;//bytegrootte van keyframe (alle parts bij elkaar) - temp.partsize = keyIt->getParts();//amount of parts in this keyframe - - keyParts.insert(temp); - partItNumber += keyIt->getParts(); - } - } - } - - //start arbitrary track addition for header - int boxOffset = 1; - seenAudio = false; - seenVideo = false; for ( std::map::iterator it = metaData.tracks.begin(); it != metaData.tracks.end(); it ++) { if (it->second.codec != "AAC" && it->second.codec != "H264"){continue;} if (it->second.type == "audio"){ @@ -102,11 +64,13 @@ namespace MP4{ if (it->first > 0){ int timescale = 0; MP4::TRAK trakBox; + { + { MP4::TKHD tkhdBox; tkhdBox.setVersion(0); tkhdBox.setFlags(15); tkhdBox.setTrackID(it->second.trackID); - ///\ odo duration firstms and lastms fix + /// \todo duration firstms and lastms fix tkhdBox.setDuration(it->second.lastms + it->second.firstms); if (it->second.type == "video"){ @@ -127,41 +91,40 @@ namespace MP4{ tkhdBox.setMatrix(0,7); tkhdBox.setMatrix(0x40000000,8); trakBox.setContent(tkhdBox, 0); - + }{ MP4::MDIA mdiaBox; + { MP4::MDHD mdhdBox(0);/// \todo fix constructor mdhd in lib mdhdBox.setCreationTime(0); mdhdBox.setModificationTime(0); //Calculating media time based on sampledelta. Probably cheating, but it works... - int tmpParts = 0; - for (std::deque< DTSC::Key>::iterator tmpIt = it->second.keys.begin(); tmpIt != it->second.keys.end(); tmpIt ++) { - tmpParts += tmpIt->getParts(); - } - timescale = ((double)(42 * tmpParts) / (it->second.lastms + it->second.firstms)) * 1000; + timescale = ((double)(42 * it->second.parts.size() ) / (it->second.lastms + it->second.firstms)) * 1000; mdhdBox.setTimeScale(timescale); - ///\ odo fix lastms, firstms + /// \todo fix lastms, firstms mdhdBox.setDuration((it->second.lastms + it->second.firstms) * ((double)timescale / 1000)); mdiaBox.setContent(mdhdBox, 0); - - std::string tmpStr = it->second.type; + }//MDHD box + { MP4::HDLR hdlrBox;/// \todo fix constructor hdlr in lib - if (tmpStr == "video"){ + if (it->second.type == "video"){ hdlrBox.setHandlerType(0x76696465);//vide - }else if (tmpStr == "audio"){ + }else if (it->second.type == "audio"){ hdlrBox.setHandlerType(0x736F756E);//soun } hdlrBox.setName(it->second.getIdentifier()); mdiaBox.setContent(hdlrBox, 1); - + }//hdlr box + { MP4::MINF minfBox; - if (tmpStr == "video"){ + if (it->second.type== "video"){ MP4::VMHD vmhdBox; vmhdBox.setFlags(1); minfBox.setContent(vmhdBox,0); - }else if (tmpStr == "audio"){ + }else if (it->second.type == "audio"){ MP4::SMHD smhdBox; minfBox.setContent(smhdBox,0); - } + }//type box + { MP4::DINF dinfBox; MP4::DREF drefBox;/// \todo fix constructor dref in lib drefBox.setVersion(0); @@ -170,14 +133,15 @@ namespace MP4{ drefBox.setDataEntry(urlBox,0); dinfBox.setContent(drefBox,0); minfBox.setContent(dinfBox,1); - + }//dinf box + { MP4::STBL stblBox; + { MP4::STSD stsdBox; stsdBox.setVersion(0); - if (tmpStr == "video"){//boxname = codec + if (it->second.type == "video"){//boxname = codec MP4::VisualSampleEntry vse; - std::string tmpStr2 = it->second.codec; - if (tmpStr2 == "H264"){ + if (it->second.codec == "H264"){ vse.setCodec("avc1"); } vse.setDataReferenceIndex(1); @@ -187,21 +151,26 @@ namespace MP4{ avccBox.setPayload(it->second.init); vse.setCLAP(avccBox); stsdBox.setEntry(vse,0); - }else if(tmpStr == "audio"){//boxname = codec + }else if(it->second.type == "audio"){//boxname = codec MP4::AudioSampleEntry ase; - std::string tmpStr2 = it->second.codec; - if (tmpStr2 == "AAC"){ + if (it->second.codec == "AAC"){ ase.setCodec("mp4a"); ase.setDataReferenceIndex(1); } ase.setSampleRate(it->second.rate); ase.setChannelCount(it->second.channels); ase.setSampleSize(it->second.size); + //MP4::ESDS esdsBox(it->second.init, it->second.bps); MP4::ESDS esdsBox; + + //outputting these values first, so malloc isn't called as often. + esdsBox.setESHeaderStartCodes(it->second.init); + esdsBox.setSLValue(2); + esdsBox.setESDescriptorTypeLength(32+it->second.init.size()); esdsBox.setESID(2); esdsBox.setStreamPriority(0); - esdsBox.setDecoderConfigDescriptorTypeLength(18+it->second.init.size()); + esdsBox.setDecoderConfigDescriptorTypeLength(18 + it->second.init.size()); esdsBox.setByteObjectTypeID(0x40); esdsBox.setStreamType(5); esdsBox.setReservedFlag(1); @@ -209,26 +178,25 @@ namespace MP4{ esdsBox.setMaximumBitRate(10000000); esdsBox.setAverageBitRate(it->second.bps * 8); esdsBox.setConfigDescriptorTypeLength(5); - esdsBox.setESHeaderStartCodes(it->second.init); esdsBox.setSLConfigDescriptorTypeTag(0x6); esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080); esdsBox.setSLDescriptorTypeLength(1); - esdsBox.setSLValue(2); ase.setCodecBox(esdsBox); stsdBox.setEntry(ase,0); } stblBox.setContent(stsdBox,0); - - /// \ odo update following stts lines + }//stsd box + /// \todo update following stts lines + { MP4::STTS sttsBox;//current version probably causes problems sttsBox.setVersion(0); MP4::STTSEntry newEntry; - newEntry.sampleCount = tmpParts; + newEntry.sampleCount = it->second.parts.size(); //42, Used as magic number for timescale calculation newEntry.sampleDelta = 42; sttsBox.setSTTSEntry(newEntry, 0); stblBox.setContent(sttsBox,1); - + }//stts box if (it->second.type == "video"){ //STSS Box here MP4::STSS stssBox; @@ -241,21 +209,21 @@ namespace MP4{ tmpItCount ++; } stblBox.setContent(stssBox,2); - } + }//stss box int offset = (it->second.type == "video"); - - + { MP4::STSC stscBox; stscBox.setVersion(0); - uint32_t total = 0; MP4::STSCEntry stscEntry; stscEntry.firstChunk = 1; stscEntry.samplesPerChunk = 1; stscEntry.sampleDescriptionIndex = 1; stscBox.setSTSCEntry(stscEntry, 0); stblBox.setContent(stscBox,2 + offset); - + }//stsc box + { + uint32_t total = 0; MP4::STSZ stszBox; stszBox.setVersion(0); total = 0; @@ -264,49 +232,41 @@ namespace MP4{ total++; } stblBox.setContent(stszBox,3 + offset); - + }//stsz box + //add STCO boxes here + { MP4::STCO stcoBox; stcoBox.setVersion(1); - total = 0; - long long unsigned int totalByteOffset = 0; - //Inserting wrong values on purpose here, will be fixed later. - //Current values are actual byte offset without header-sized offset - for (std::set::iterator i = keyParts.begin(); i != keyParts.end(); i++){//for all keypart size - if(i->trackID == it->second.trackID){//if keypart is of current trackID - std::deque tempArr = i->parts; - for (unsigned int o = 0; o < tempArr.size(); o++){//add all parts to STCO - stcoBox.setChunkOffset(totalByteOffset, total); - total++; - totalByteOffset += tempArr[o].getSize(); - } - }else{ - totalByteOffset += i->size; - } + //Inserting empty values on purpose here, will be fixed later. + if (it->second.parts.size() != 0){ + stcoBox.setChunkOffset(0, it->second.parts.size() - 1);//this inserts all empty entries at once } - //calculating the offset where the STCO box will be in the main MOOV box - //needed for probable optimise - mdatSize = totalByteOffset; - stblBox.setContent(stcoBox,4 + offset); + }//stco box minfBox.setContent(stblBox,2); + }//stbl box mdiaBox.setContent(minfBox, 2); + }//minf box trakBox.setContent(mdiaBox, 1); + } + }//trak Box moovBox.setContent(trakBox, boxOffset); boxOffset++; } } - //end arbitrary + }//end arbitrary track addition //initial offset length ftyp, length moov + 8 unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8; - //update all STCO - //for tracks + //update all STCO from the following map; + std::map checkStcoBoxes; + //for all tracks for (unsigned int i = 1; i < moovBox.getContentCount(); i++){ //10 lines to get the STCO box. MP4::TRAK checkTrakBox; MP4::MDIA checkMdiaBox; MP4::MINF checkMinfBox; MP4::STBL checkStblBox; - MP4::STCO checkStcoBox; + //MP4::STCO checkStcoBox; checkTrakBox = ((MP4::TRAK&)moovBox.getContent(i)); for (unsigned int j = 0; j < checkTrakBox.getContentCount(); j++){ if (checkTrakBox.getContent(j).isType("mdia")){ @@ -328,15 +288,46 @@ namespace MP4{ } for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){ if (checkStblBox.getContent(j).isType("stco")){ - checkStcoBox = ((MP4::STCO&)checkStblBox.getContent(j)); + checkStcoBoxes.insert( std::pair(i, ((MP4::STCO&)checkStblBox.getContent(j)) )); break; } } - //got the STCO box, fixing values with MP4 header offset - for (unsigned int j = 0; j < checkStcoBox.getEntryCount(); j++){ - checkStcoBox.setChunkOffset(checkStcoBox.getChunkOffset(j) + byteOffset, j); - } } + //inserting right values in the STCO box header + //total = 0; + long long unsigned int totalByteOffset = 0; + //Current values are actual byte offset without header-sized offset + std::set sortSet;//filling sortset for interleaving parts + for ( std::map::iterator subIt = metaData.tracks.begin(); subIt != metaData.tracks.end(); subIt ++) { + keyPart temp; + temp.trackID = subIt->second.trackID; + temp.time = subIt->second.firstms;//timeplace of frame + temp.endTime = subIt->second.firstms + subIt->second.parts[0].getDuration(); + temp.size = subIt->second.parts[0].getSize();//bytesize of frame (alle parts all together) + temp.index = 0; + sortSet.insert(temp); + } + while (!sortSet.empty()){ + //setting the right STCO size in the STCO box + checkStcoBoxes[sortSet.begin()->trackID].setChunkOffset(totalByteOffset + byteOffset, sortSet.begin()->index); + totalByteOffset += sortSet.begin()->size; + //add keyPart to sortSet + keyPart temp; + temp.index = sortSet.begin()->index + 1; + temp.trackID = sortSet.begin()->trackID; + if(temp.index < metaData.tracks[temp.trackID].parts.size() ){//only insert when there are parts left + temp.time = sortSet.begin()->endTime;//timeplace of frame + temp.endTime = sortSet.begin()->endTime + metaData.tracks[temp.trackID].parts[temp.index].getDuration(); + temp.size = metaData.tracks[temp.trackID].parts[temp.index].getSize();//bytesize of frame + sortSet.insert(temp); + } + //remove highest keyPart + sortSet.erase(sortSet.begin()); + } + //calculating the offset where the STCO box will be in the main MOOV box + //needed for probable optimise + mdatSize = totalByteOffset; + header << std::string(moovBox.asBox(),moovBox.boxedSize()); header << (char)((mdatSize>>24) & 0x000000FF) << (char)((mdatSize>>16) & 0x000000FF) << (char)((mdatSize>>8) & 0x000000FF) << (char)(mdatSize & 0x000000FF) << "mdat"; @@ -345,64 +336,5 @@ namespace MP4{ return header.str(); } - void DTSC2MP4Converter::parseDTSC(JSON::Value mediaPart){ - static std::set::iterator curKey = keyParts.begin();//the key chunk we are currently searching for in keyParts - static long long unsigned int curPart = 0;//current part in current key - //mdat output here - //output cleanout buffer first - //while there are requested packets in the trackBuffer:... - while (!trackBuffer[curKey->trackID].empty()){ - //output requested packages - stringBuffer += trackBuffer[curKey->trackID].front()["data"].asString(); - trackBuffer[curKey->trackID].pop_front(); - curPart++; - if(curPart >= curKey->parts.size()){ - curPart = 0; - curKey++; - } - } - //after that, try to put out the JSON data directly - if(curKey->trackID == mediaPart["trackid"].asInt()){ - //output JSON packet - stringBuffer += mediaPart["data"].asStringRef(); - curPart++; - if(curPart >= curKey->parts.size()){ - curPart = 0; - curKey++; - } - }else{ - //buffer for later - trackBuffer[mediaPart["trackid"].asInt()].push_back(mediaPart); - } - } - - bool DTSC2MP4Converter::sendReady(){ - if (stringBuffer.length() > 0){ - return true; - }else{ - return false; - } - } - - std::string DTSC2MP4Converter::sendString(){ - std::string temp = stringBuffer; - stringBuffer = ""; - return temp; - } - - std::string DTSC2MP4Converter::purgeBuffer(){ - std::string retval = stringBuffer; - stringBuffer = ""; - for (std::map >::iterator it = trackBuffer.begin(); it !=trackBuffer.end(); it++){ - while (!it->second.empty()){ - //output requested packages - if (it->second.front()["data"].asString() != ""){ - retval += it->second.front()["data"].asString(); - } - it->second.pop_front(); - } - } - return retval; - } } diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp new file mode 100644 index 00000000..61373ac1 --- /dev/null +++ b/lib/mp4_generic.cpp @@ -0,0 +1,2878 @@ +#include "mp4_generic.h" +#include "defines.h" + +namespace MP4{ + MFHD::MFHD(){ + memcpy(data + 4, "mfhd", 4); + setInt32(0, 0); + } + + void MFHD::setSequenceNumber(uint32_t newSequenceNumber){ + setInt32(newSequenceNumber, 4); + } + + uint32_t MFHD::getSequenceNumber(){ + return getInt32(4); + } + + std::string MFHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[mfhd] Movie Fragment Header (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "SequenceNumber " << getSequenceNumber() << std::endl; + return r.str(); + } + + MOOF::MOOF(){ + memcpy(data + 4, "moof", 4); + } + + TRAF::TRAF(){ + memcpy(data + 4, "traf", 4); + } + + uint32_t TRAF::getContentCount(){ + int res = 0; + unsigned int tempLoc = 0; + while (tempLoc < boxedSize() - 8){ + res++; + tempLoc += getBoxLen(tempLoc); + } + return res; + } + + void TRAF::setContent(Box & newContent, uint32_t no){ + int tempLoc = 0; + unsigned int contentCount = getContentCount(); + for (unsigned int i = 0; i < no; i++){ + if (i < contentCount){ + tempLoc += getBoxLen(tempLoc); + }else{ + if ( !reserve(tempLoc, 0, (no - contentCount) * 8)){ + return; + }; + memset(data + tempLoc, 0, (no - contentCount) * 8); + tempLoc += (no - contentCount) * 8; + break; + } + } + setBox(newContent, tempLoc); + } + + Box & TRAF::getContent(uint32_t no){ + static Box ret = Box((char*)"\000\000\000\010erro", false); + if (no > getContentCount()){ + return ret; + } + unsigned int i = 0; + int tempLoc = 0; + while (i < no){ + tempLoc += getBoxLen(tempLoc); + i++; + } + return getBox(tempLoc); + } + + std::string TRAF::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[traf] Track Fragment Box (" << boxedSize() << ")" << std::endl; + int contentCount = getContentCount(); + for (int i = 0; i < contentCount; i++){ + Box curBox = Box(getContent(i).asBox(),false); + r << curBox.toPrettyString(indent + 1); + } + return r.str(); + } + + TRUN::TRUN(){ + memcpy(data + 4, "trun", 4); + } + + void TRUN::setFlags(uint32_t newFlags){ + setInt24(newFlags, 1); + } + + uint32_t TRUN::getFlags(){ + return getInt24(1); + } + + void TRUN::setDataOffset(uint32_t newOffset){ + if (getFlags() & trundataOffset){ + setInt32(newOffset, 8); + } + } + + uint32_t TRUN::getDataOffset(){ + if (getFlags() & trundataOffset){ + return getInt32(8); + }else{ + return 0; + } + } + + void TRUN::setFirstSampleFlags(uint32_t newSampleFlags){ + if ( !(getFlags() & trunfirstSampleFlags)){ + return; + } + if (getFlags() & trundataOffset){ + setInt32(newSampleFlags, 12); + }else{ + setInt32(newSampleFlags, 8); + } + } + + uint32_t TRUN::getFirstSampleFlags(){ + if ( !(getFlags() & trunfirstSampleFlags)){ + return 0; + } + if (getFlags() & trundataOffset){ + return getInt32(12); + }else{ + return getInt32(8); + } + } + + uint32_t TRUN::getSampleInformationCount(){ + return getInt32(4); + } + + void TRUN::setSampleInformation(trunSampleInformation newSample, uint32_t no){ + uint32_t flags = getFlags(); + uint32_t sampInfoSize = 0; + if (flags & trunsampleDuration){ + sampInfoSize += 4; + } + if (flags & trunsampleSize){ + sampInfoSize += 4; + } + if (flags & trunsampleFlags){ + sampInfoSize += 4; + } + if (flags & trunsampleOffsets){ + sampInfoSize += 4; + } + uint32_t offset = 8; + if (flags & trundataOffset){ + offset += 4; + } + if (flags & trunfirstSampleFlags){ + offset += 4; + } + uint32_t innerOffset = 0; + if (flags & trunsampleDuration){ + setInt32(newSample.sampleDuration, offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (flags & trunsampleSize){ + setInt32(newSample.sampleSize, offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (flags & trunsampleFlags){ + setInt32(newSample.sampleFlags, offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (flags & trunsampleOffsets){ + setInt32(newSample.sampleOffset, offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (getSampleInformationCount() < no + 1){ + setInt32(no + 1, 4); + } + } + + trunSampleInformation TRUN::getSampleInformation(uint32_t no){ + trunSampleInformation ret; + ret.sampleDuration = 0; + ret.sampleSize = 0; + ret.sampleFlags = 0; + ret.sampleOffset = 0; + if (getSampleInformationCount() < no + 1){ + return ret; + } + uint32_t flags = getFlags(); + uint32_t sampInfoSize = 0; + if (flags & trunsampleDuration){ + sampInfoSize += 4; + } + if (flags & trunsampleSize){ + sampInfoSize += 4; + } + if (flags & trunsampleFlags){ + sampInfoSize += 4; + } + if (flags & trunsampleOffsets){ + sampInfoSize += 4; + } + uint32_t offset = 8; + if (flags & trundataOffset){ + offset += 4; + } + if (flags & trunfirstSampleFlags){ + offset += 4; + } + uint32_t innerOffset = 0; + if (flags & trunsampleDuration){ + ret.sampleDuration = getInt32(offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (flags & trunsampleSize){ + ret.sampleSize = getInt32(offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (flags & trunsampleFlags){ + ret.sampleFlags = getInt32(offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + if (flags & trunsampleOffsets){ + ret.sampleOffset = getInt32(offset + no * sampInfoSize + innerOffset); + innerOffset += 4; + } + return ret; + } + + std::string TRUN::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[trun] Track Fragment Run (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getInt8(0) << std::endl; + + uint32_t flags = getFlags(); + r << std::string(indent + 1, ' ') << "Flags"; + if (flags & trundataOffset){ + r << " dataOffset"; + } + if (flags & trunfirstSampleFlags){ + r << " firstSampleFlags"; + } + if (flags & trunsampleDuration){ + r << " sampleDuration"; + } + if (flags & trunsampleSize){ + r << " sampleSize"; + } + if (flags & trunsampleFlags){ + r << " sampleFlags"; + } + if (flags & trunsampleOffsets){ + r << " sampleOffsets"; + } + r << std::endl; + + if (flags & trundataOffset){ + r << std::string(indent + 1, ' ') << "Data Offset " << getDataOffset() << std::endl; + } + if (flags & trundataOffset){ + r << std::string(indent + 1, ' ') << "Sample Flags" << prettySampleFlags(getFirstSampleFlags()) << std::endl; + } + + r << std::string(indent + 1, ' ') << "SampleInformation (" << getSampleInformationCount() << "):" << std::endl; + for (unsigned int i = 0; i < getSampleInformationCount(); ++i){ + r << std::string(indent + 2, ' ') << "[" << i << "] "; + trunSampleInformation samp = getSampleInformation(i); + if (flags & trunsampleDuration){ + r << "Duration=" << samp.sampleDuration << " "; + } + if (flags & trunsampleSize){ + r << "Size=" << samp.sampleSize << " "; + } + if (flags & trunsampleFlags){ + r << "Flags=" << prettySampleFlags(samp.sampleFlags) << " "; + } + if (flags & trunsampleOffsets){ + r << "Offset=" << samp.sampleOffset << " "; + } + r << std::endl; + } + + return r.str(); + } + + std::string prettySampleFlags(uint32_t flag){ + std::stringstream r; + if (flag & noIPicture){ + r << " noIPicture"; + } + if (flag & isIPicture){ + r << " isIPicture"; + } + if (flag & noDisposable){ + r << " noDisposable"; + } + if (flag & isDisposable){ + r << " isDisposable"; + } + if (flag & isRedundant){ + r << " isRedundant"; + } + if (flag & noRedundant){ + r << " noRedundant"; + } + if (flag & noKeySample){ + r << " noKeySample"; + }else{ + r << " isKeySample"; + } + return r.str(); + } + + TFHD::TFHD(){ + memcpy(data + 4, "tfhd", 4); + } + + void TFHD::setFlags(uint32_t newFlags){ + setInt24(newFlags, 1); + } + + uint32_t TFHD::getFlags(){ + return getInt24(1); + } + + void TFHD::setTrackID(uint32_t newID){ + setInt32(newID, 4); + } + + uint32_t TFHD::getTrackID(){ + return getInt32(4); + } + + void TFHD::setBaseDataOffset(uint64_t newOffset){ + if (getFlags() & tfhdBaseOffset){ + setInt64(newOffset, 8); + } + } + + uint64_t TFHD::getBaseDataOffset(){ + if (getFlags() & tfhdBaseOffset){ + return getInt64(8); + }else{ + return 0; + } + } + + void TFHD::setSampleDescriptionIndex(uint32_t newIndex){ + if ( !(getFlags() & tfhdSampleDesc)){ + return; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + setInt32(newIndex, offset); + } + + uint32_t TFHD::getSampleDescriptionIndex(){ + if ( !(getFlags() & tfhdSampleDesc)){ + return 0; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + return getInt32(offset); + } + + void TFHD::setDefaultSampleDuration(uint32_t newDuration){ + if ( !(getFlags() & tfhdSampleDura)){ + return; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + setInt32(newDuration, offset); + } + + uint32_t TFHD::getDefaultSampleDuration(){ + if ( !(getFlags() & tfhdSampleDura)){ + return 0; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + return getInt32(offset); + } + + void TFHD::setDefaultSampleSize(uint32_t newSize){ + if ( !(getFlags() & tfhdSampleSize)){ + return; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } + setInt32(newSize, offset); + } + + uint32_t TFHD::getDefaultSampleSize(){ + if ( !(getFlags() & tfhdSampleSize)){ + return 0; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } + return getInt32(offset); + } + + void TFHD::setDefaultSampleFlags(uint32_t newFlags){ + if ( !(getFlags() & tfhdSampleFlag)){ + return; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } + if (getFlags() & tfhdSampleSize){ + offset += 4; + } + setInt32(newFlags, offset); + } + + uint32_t TFHD::getDefaultSampleFlags(){ + if ( !(getFlags() & tfhdSampleFlag)){ + return 0; + } + int offset = 8; + if (getFlags() & tfhdBaseOffset){ + offset += 8; + } + if (getFlags() & tfhdSampleDesc){ + offset += 4; + } + if (getFlags() & tfhdSampleDura){ + offset += 4; + } + if (getFlags() & tfhdSampleSize){ + offset += 4; + } + return getInt32(offset); + } + + std::string TFHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[tfhd] Track Fragment Header (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version " << (int)getInt8(0) << std::endl; + + uint32_t flags = getFlags(); + r << std::string(indent + 1, ' ') << "Flags"; + if (flags & tfhdBaseOffset){ + r << " BaseOffset"; + } + if (flags & tfhdSampleDesc){ + r << " SampleDesc"; + } + if (flags & tfhdSampleDura){ + r << " SampleDura"; + } + if (flags & tfhdSampleSize){ + r << " SampleSize"; + } + if (flags & tfhdSampleFlag){ + r << " SampleFlag"; + } + if (flags & tfhdNoDuration){ + r << " NoDuration"; + } + r << std::endl; + + r << std::string(indent + 1, ' ') << "TrackID " << getTrackID() << std::endl; + + if (flags & tfhdBaseOffset){ + r << std::string(indent + 1, ' ') << "Base Offset " << getBaseDataOffset() << std::endl; + } + if (flags & tfhdSampleDesc){ + r << std::string(indent + 1, ' ') << "Sample Description Index " << getSampleDescriptionIndex() << std::endl; + } + if (flags & tfhdSampleDura){ + r << std::string(indent + 1, ' ') << "Default Sample Duration " << getDefaultSampleDuration() << std::endl; + } + if (flags & tfhdSampleSize){ + r << std::string(indent + 1, ' ') << "Default Same Size " << getDefaultSampleSize() << std::endl; + } + if (flags & tfhdSampleFlag){ + r << std::string(indent + 1, ' ') << "Default Sample Flags " << prettySampleFlags(getDefaultSampleFlags()) << std::endl; + } + + return r.str(); + } + + + AVCC::AVCC(){ + memcpy(data + 4, "avcC", 4); + setInt8(0xFF, 4); //reserved + 4-bytes NAL length + } + + void AVCC::setVersion(uint32_t newVersion){ + setInt8(newVersion, 0); + } + + uint32_t AVCC::getVersion(){ + return getInt8(0); + } + + void AVCC::setProfile(uint32_t newProfile){ + setInt8(newProfile, 1); + } + + uint32_t AVCC::getProfile(){ + return getInt8(1); + } + + void AVCC::setCompatibleProfiles(uint32_t newCompatibleProfiles){ + setInt8(newCompatibleProfiles, 2); + } + + uint32_t AVCC::getCompatibleProfiles(){ + return getInt8(2); + } + + void AVCC::setLevel(uint32_t newLevel){ + setInt8(newLevel, 3); + } + + uint32_t AVCC::getLevel(){ + return getInt8(3); + } + + void AVCC::setSPSNumber(uint32_t newSPSNumber){ + setInt8(newSPSNumber, 5); + } + + uint32_t AVCC::getSPSNumber(){ + return getInt8(5); + } + + void AVCC::setSPS(std::string newSPS){ + setInt16(newSPS.size(), 6); + for (unsigned int i = 0; i < newSPS.size(); i++){ + setInt8(newSPS[i], 8 + i); + } //not null-terminated + } + + uint32_t AVCC::getSPSLen(){ + return getInt16(6); + } + + char* AVCC::getSPS(){ + return payload() + 8; + } + + void AVCC::setPPSNumber(uint32_t newPPSNumber){ + int offset = 8 + getSPSLen(); + setInt8(newPPSNumber, offset); + } + + uint32_t AVCC::getPPSNumber(){ + int offset = 8 + getSPSLen(); + return getInt8(offset); + } + + void AVCC::setPPS(std::string newPPS){ + int offset = 8 + getSPSLen() + 1; + setInt16(newPPS.size(), offset); + for (unsigned int i = 0; i < newPPS.size(); i++){ + setInt8(newPPS[i], offset + 2 + i); + } //not null-terminated + } + + uint32_t AVCC::getPPSLen(){ + int offset = 8 + getSPSLen() + 1; + return getInt16(offset); + } + + char* AVCC::getPPS(){ + int offset = 8 + getSPSLen() + 3; + return payload() + offset; + } + + std::string AVCC::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[avcC] H.264 Init Data (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Version: " << getVersion() << std::endl; + r << std::string(indent + 1, ' ') << "Profile: " << getProfile() << std::endl; + r << std::string(indent + 1, ' ') << "Compatible Profiles: " << getCompatibleProfiles() << std::endl; + r << std::string(indent + 1, ' ') << "Level: " << getLevel() << std::endl; + r << std::string(indent + 1, ' ') << "SPS Number: " << getSPSNumber() << std::endl; + r << std::string(indent + 2, ' ') << getSPSLen() << " of SPS data" << std::endl; + r << std::string(indent + 1, ' ') << "PPS Number: " << getPPSNumber() << std::endl; + r << std::string(indent + 2, ' ') << getPPSLen() << " of PPS data" << std::endl; + return r.str(); + } + + std::string AVCC::asAnnexB(){ + std::stringstream r; + r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; + r.write(getSPS(), getSPSLen()); + r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; + r.write(getPPS(), getPPSLen()); + return r.str(); + } + + void AVCC::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()); + } + + //fullbox, start at 4 + ESDS::ESDS(){ + memcpy(data + 4, "esds", 4); + setESDescriptorType(0x03); + setExtendedESDescriptorType(0x808080); + setStreamPriority(16); + setDecoderConfigDescriptorTag(0x04); + setExtendedDecoderConfigDescriptorTag(0x808080); + setReservedFlag(true); + setDecoderDescriptorTypeTag(0x05); + setExtendedDecoderDescriptorTypeTag(0x808080); + setSLConfigDescriptorTypeTag(0x06); + setSLConfigExtendedDescriptorTypeTag(0x808010); + setSLValue(0x02); + } + + ESDS::ESDS(std::string init, uint32_t bps){ + memcpy(data + 4, "esds", 4); + char temp[] = {0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x80, 0x00, 0x00, 0x02, 0x10, 0x04, 0x80, 0x80, 0x80, 0x00, 0x40, 0x15, 0x13, 0x12, 0xD0, 0x00, 0x98, 0x96, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x80, 0x80, 0x05}; + setString(temp, 0x23,0); + setESDescriptorTypeLength(32 + init.size()); + setDecoderConfigDescriptorTypeLength(18 + init.size()); + setAverageBitRate(bps * 8); + setESHeaderStartCodes(init); + char temp2[] = {0x05, 0x80, 0x80, 0x10, 0x01, 0x02}; + setString(temp2, 0x06, 0x23 + 32 + init.size()); + } + + char ESDS::getESDescriptorType(){ + return getInt8(4); + } + + void ESDS::setESDescriptorType(char newVal){ + setInt8(newVal,4); + } + + uint32_t ESDS::getExtendedESDescriptorType(){ + return getInt24(5); + } + //3 bytes + void ESDS::setExtendedESDescriptorType(uint32_t newVal){ + setInt24(newVal,5); + } + //3 bytes + char ESDS::getESDescriptorTypeLength(){ + return getInt8(8); + } + + void ESDS::setESDescriptorTypeLength(char newVal){ + setInt8(newVal,8); + } + //ESID 2 bytes + uint16_t ESDS::getESID(){ + return getInt16(9); + } + + void ESDS::setESID(uint16_t newVal){ + setInt16(newVal, 9); + } + + //stream priority 1 byte + char ESDS::getStreamPriority(){ + return getInt8(11); + } + + void ESDS::setStreamPriority(char newVal){ + setInt8(newVal, 11); + } + + //decoder config descriptor tag 1byte + char ESDS::getDecoderConfigDescriptorTag(){ + return getInt8(12); + } + + void ESDS::setDecoderConfigDescriptorTag(char newVal){ + setInt8(newVal, 12); + } + + //extended decoder config descriptor tag 3 bytes + uint32_t ESDS::getExtendedDecoderConfigDescriptorTag(){ + return getInt24(13); + } + //3 bytes + void ESDS::setExtendedDecoderConfigDescriptorTag(uint32_t newVal){ + setInt24(newVal, 13); + } + //3 bytes + //decoder config descriptor type length + char ESDS::getDecoderConfigDescriptorTypeLength(){ + return getInt8(16); + } + + void ESDS::setDecoderConfigDescriptorTypeLength(char newVal){ + setInt8(newVal, 16); + } + //Note: count 8 bytes extra in the next four functions + char ESDS::getByteObjectTypeID(){ + return getInt8(17); + } + + void ESDS::setByteObjectTypeID(char newVal){ + setInt8(newVal,17); + } + + char ESDS::getStreamType(){ + return getInt8(18) >> 2; + } + //6 bits + void ESDS::setStreamType(char newVal){ + setInt8(((newVal << 2) & 0xFC) + (getInt8(18) & 0x03), 18); + } + //6 bits + bool ESDS::getUpstreamFlag(){ + return (((getInt8(18) >> 1) & 0x01) == 1); + } + + void ESDS::setUpstreamFlag(bool newVal){ + setInt8((getStreamType()<<2) + ((uint8_t)newVal << 1) + (uint8_t)getReservedFlag() , 18); + } + + bool ESDS::getReservedFlag(){ + return ((getInt8(18) & 0x01) == 1); + } + + void ESDS::setReservedFlag(bool newVal){ + setInt8((getInt8(18) & 0xFE) + (int)newVal, 18); + } + + uint32_t ESDS::getBufferSize(){ + return getInt24(19); + } + //3 bytes + void ESDS::setBufferSize(uint32_t newVal){ + setInt24(newVal,19); + } + //3 bytes + uint32_t ESDS::getMaximumBitRate(){ + return getInt32(22); + } + + void ESDS::setMaximumBitRate(uint32_t newVal){ + setInt32(newVal,22); + } + + uint32_t ESDS::getAverageBitRate(){ + return getInt32(26); + } + + void ESDS::setAverageBitRate(uint32_t newVal){ + setInt32(newVal,26); + } + + char ESDS::getDecoderDescriptorTypeTag(){ + return getInt8(30); + } + + void ESDS::setDecoderDescriptorTypeTag(char newVal){ + setInt8(newVal,30); + } + + uint32_t ESDS::getExtendedDecoderDescriptorTypeTag(){ + return getInt24(31); + } + + //3 bytes + void ESDS::setExtendedDecoderDescriptorTypeTag(uint32_t newVal){ + setInt24(newVal, 31); + } + + //3 bytes + char ESDS::getConfigDescriptorTypeLength(){ + return getInt8(34); + } + + void ESDS::setConfigDescriptorTypeLength(char newVal){ + setInt8(newVal, 34); + } + + std::string ESDS::getESHeaderStartCodes(){ + std::string result; + for (int i = 0; i < getInt8(34); i++){ + result += getInt8(35 + i); + } + return result; + } + + void ESDS::setESHeaderStartCodes(std::string newVal){ + setConfigDescriptorTypeLength(newVal.size()); + for (unsigned int i = 0; i < newVal.size(); i++){ + setInt8(newVal[i],35+i); + } + } + + char ESDS::getSLConfigDescriptorTypeTag(){ + return getInt8(35 + getInt8(34)); + } + + void ESDS::setSLConfigDescriptorTypeTag(char newVal){ + setInt8(newVal, 35 + getInt8(34)); + } + + uint32_t ESDS::getSLConfigExtendedDescriptorTypeTag(){ + return getInt24(36 + getInt8(34)); + } + //3 bytes + void ESDS::setSLConfigExtendedDescriptorTypeTag(uint32_t newVal){ + setInt24(newVal, 36 + getInt8(34)); + } + //3 bytes + char ESDS::getSLDescriptorTypeLength(){ + return getInt8(39 + getInt8(34)); + } + + void ESDS::setSLDescriptorTypeLength(char newVal){ + setInt8(newVal, 39 + getInt8(34)); + } + + char ESDS::getSLValue(){ + return getInt8(40 + getInt8(34)); + } + + void ESDS::setSLValue(char newVal){ + setInt8(newVal, 40 + getInt8(34)); + } + + std::string ESDS::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[esds] ES Descriptor Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "ESDescriptorType: 0x" << std::hex << (int)getESDescriptorType() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "ExtendedESDescriptorType: 0x" << std::hex << (int)getExtendedESDescriptorType() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "ESDescriptorTypeLength:" << (int)getESDescriptorTypeLength() << std::endl; + r << std::string(indent + 1, ' ') << "ESID: 0x" << std::hex << (int)getESID() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "StreamPriority: 0x" << std::hex << (int)getStreamPriority() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "DecoderConfigDescriptorTag: 0x" << std::hex << (int)getDecoderConfigDescriptorTag() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "ExtendedDecoderConfigDescriptorTag: 0x" << std::hex << (int)getExtendedDecoderConfigDescriptorTag() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "DecoderConfigDescriptorTypeLength: " << (int)getDecoderConfigDescriptorTypeLength() << std::endl; + r << std::string(indent + 1, ' ') << "ByteObjectTypeID: 0x" << std::hex << (int)getByteObjectTypeID() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "StreamType: 0x" << std::hex << (int)getStreamType() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "UpstreamFlag: 0x" << std::hex << (int)getUpstreamFlag() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "BufferSize: 0x" << std::hex << (int)getBufferSize() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "MaximumBitRate: 0x" << std::hex << (int)getMaximumBitRate() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "AverageBitRate: 0x" << std::hex << (int)getAverageBitRate() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "DecoderDescriptorTypeTag: 0x" << std::hex << (int)getDecoderDescriptorTypeTag() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "ExtendedDecoderDescriptorTypeTag: 0x" << std::hex << (int)getExtendedDecoderDescriptorTypeTag() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "ConfigDescriptorTypeLength: 0x" << std::hex << (int)getConfigDescriptorTypeLength() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "ESHeaderStartCodes: 0x"; + for (unsigned int i = 0; i= getCompatibleBrandsCount()){ + return 0; + } + return getInt32(8 + (index * 4)); + } + + std::string FTYP::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[ftyp] File Type (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "MajorBrand: 0x" << std::hex << getMajorBrand() << std::dec << 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: 0x" << std::hex << getCompatibleBrands(i) << std::dec << std::endl; + } + return r.str(); + } + + MOOV::MOOV(){ + memcpy(data + 4, "moov", 4); + } + + MVEX::MVEX(){ + memcpy(data + 4, "mvex", 4); + } + + TREX::TREX(){ + memcpy(data + 4, "trex", 4); + } + + void TREX::setTrackID(uint32_t newTrackID){ + setInt32(newTrackID, 0); + } + + uint32_t TREX::getTrackID(){ + return getInt32(0); + } + + void TREX::setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex){ + setInt32(newDefaultSampleDescriptionIndex,4); + } + + uint32_t TREX::getDefaultSampleDescriptionIndex(){ + return getInt32(4); + } + + void TREX::setDefaultSampleDuration(uint32_t newDefaultSampleDuration){ + setInt32(newDefaultSampleDuration,8); + } + + uint32_t TREX::getDefaultSampleDuration(){ + return getInt32(8); + } + + void TREX::setDefaultSampleSize(uint32_t newDefaultSampleSize){ + setInt32(newDefaultSampleSize,12); + } + + uint32_t TREX::getDefaultSampleSize(){ + return getInt32(12); + } + + void TREX::setDefaultSampleFlags(uint32_t newDefaultSampleFlags){ + setInt32(newDefaultSampleFlags,16); + } + + uint32_t TREX::getDefaultSampleFlags(){ + return getInt32(16); + } + + std::string TREX::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[trex] Track Extends (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; + r << std::string(indent + 1, ' ') << "DefaultSampleDescriptionIndex : " << getDefaultSampleDescriptionIndex() << std::endl; + r << std::string(indent + 1, ' ') << "DefaultSampleDuration : " << getDefaultSampleDuration() << std::endl; + r << std::string(indent + 1, ' ') << "DefaultSampleSize : " << getDefaultSampleSize() << std::endl; + r << std::string(indent + 1, ' ') << "DefaultSampleFlags : " << getDefaultSampleFlags() << std::endl; + return r.str(); + } + + TRAK::TRAK(){ + memcpy(data + 4, "trak", 4); + } + + MDIA::MDIA(){ + memcpy(data + 4, "mdia", 4); + } + + MINF::MINF(){ + memcpy(data + 4, "minf", 4); + } + + DINF::DINF(){ + memcpy(data + 4, "dinf", 4); + } + + MFRA::MFRA(){ + memcpy(data + 4, "mfra", 4); + } + + MFRO::MFRO(){ + memcpy(data + 4, "mfro", 4); + } + + void MFRO::setSize(uint32_t newSize){ + setInt32(newSize,0); + } + + uint32_t MFRO::getSize(){ + return getInt32(0); + } + + std::string MFRO::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[mfro] Movie Fragment Random Access Offset (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "Size: " << getSize() << std::endl; + return r.str(); + } + + HDLR::HDLR(){ + memcpy(data + 4, "hdlr", 4); + setName(""); + } + + void HDLR::setSize(uint32_t newSize){ + setInt32(newSize,0); + } + + uint32_t HDLR::getSize(){ + return getInt32(0); + } + + void HDLR::setPreDefined(uint32_t newPreDefined){ + setInt32(newPreDefined,4); + } + + uint32_t HDLR::getPreDefined(){ + return getInt32(4); + } + + void HDLR::setHandlerType(uint32_t newHandlerType){ + setInt32(newHandlerType, 8); + } + + uint32_t HDLR::getHandlerType(){ + return getInt32(8); + } + + void HDLR::setName(std::string newName){ + setString(newName, 24); + } + + std::string HDLR::getName(){ + return getString(24); + } + + std::string HDLR::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[hdlr] Handler Reference (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "PreDefined: " << getPreDefined() << std::endl; + r << std::string(indent + 1, ' ') << "HandlerType: " << + (char)((getHandlerType() & 0xFF000000) >> 24) << (char)((getHandlerType() & 0x00FF0000) >> 16) << + (char)((getHandlerType() & 0x0000FF00) >> 8) << (char)(getHandlerType() & 0x000000FF) << std::endl; + r << std::string(indent + 1, ' ') << "Name: " << getName() << std::endl; + return r.str(); + } + + //Note: next 4 headers inherit from fullBox, start at byte 4. + VMHD::VMHD(){ + memcpy(data + 4, "vmhd", 4); + setGraphicsMode(0); + setOpColor(0,0); + setOpColor(0,1); + setOpColor(0,2); + } + + void VMHD::setGraphicsMode(uint16_t newGraphicsMode){ + setInt16(newGraphicsMode,4); + } + + uint16_t VMHD::getGraphicsMode(){ + return getInt16(4); + } + + uint32_t VMHD::getOpColorCount(){ + return 3; + } + + void VMHD::setOpColor(uint16_t newOpColor, size_t index){ + if (index <3){ + setInt16(newOpColor, 6 + (2 * index)); + } + } + + uint16_t VMHD::getOpColor(size_t index){ + if (index < 3){ + return getInt16(6 + (index * 2)); + }else{ + return 0; + } + } + + std::string VMHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[vmhd] Video Media Header Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "GraphicsMode: " << getGraphicsMode() << std::endl; + for (unsigned int i = 0; i < getOpColorCount(); i++){ + r << std::string(indent + 1, ' ') << "OpColor["< getEntryCount()){ + int amount = index + 1 - getEntryCount(); + if ( !reserve(payloadOffset + offset, 0, amount * 8)){ + return; + } + for (int j = 0; j < amount; ++j){ + memcpy(data + payloadOffset + offset + j * 8, "\000\000\000\010erro", 8); + } + setInt32(index + 1, 4); + offset += (index - i) * 8; + } + setBox(newDataEntry, offset); + } + + Box & DREF::getDataEntry(size_t index){ + uint32_t offset = 8; + if (index > getEntryCount()){ + static Box res; + return (Box &)res; + } + + for (unsigned int i=0; i < index; i++){ + offset += getBoxLen(offset); + } + return (Box &)getBox(offset); + } + + std::string DREF::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[dref] Data Reference Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i< getEntryCount(); i++){ + r << getDataEntry(i).toPrettyString(indent+1); + } + return r.str(); + } + + MVHD::MVHD(char v, uint32_t f){ + memcpy(data + 4, "mvhd", 4); + setVersion(v); + setFlags(f); + setCreationTime(0); + setModificationTime(0); + setTimeScale(1000); + setDuration(0); + setRate(0x00010000); + setVolume(0x0100); + setMatrix(0x40000000,0); + setMatrix(0x00010000,4); + setMatrix(0x00010000,8); + setTrackID(1); + } + + MVHD::MVHD(long long unsigned int duration){ + //memcpy(data + 4, "mvhd", 4); + //char temp[] = {00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x03, 0xE8, 0x10, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 40, 00, 00, 00}; + //char temp[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x3d, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + //setString(temp, 0x4F, 0); + //setDuration(duration); + + memcpy(data + 4, "mvhd", 4); + setVersion(0); + setFlags(0); + setTrackID(1); + setTimeScale(1000); + + setRate(0x00010000); + setVolume(0x0100); + setMatrix(0x40000000,0); + setMatrix(0x00010000,4); + setMatrix(0x00010000,8); + setTimeScale(1000); + setRate(0x10000); + + setDuration(duration); + } + + void MVHD::setCreationTime(uint64_t newCreationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newCreationTime, 4); + }else{ + setInt64(newCreationTime, 4); + } + } + + uint64_t MVHD::getCreationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(4); + }else{ + return getInt64(4); + } + } + + void MVHD::setModificationTime(uint64_t newModificationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newModificationTime, 8); + }else{ + setInt64(newModificationTime, 12); + } + } + + uint64_t MVHD::getModificationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(8); + }else{ + return getInt64(12); + } + } + + void MVHD::setTimeScale(uint32_t newTimeScale){ + if (getVersion() == 0){ + setInt32((uint32_t) newTimeScale, 12); + }else{ + setInt32(newTimeScale, 20); + } + } + + uint32_t MVHD::getTimeScale(){ + if (getVersion() == 0){ + return getInt32(12); + }else{ + return getInt32(20); + } + } + + void MVHD::setDuration(uint64_t newDuration){ + if (getVersion() == 0){ + setInt32((uint32_t) newDuration, 16); + }else{ + setInt64(newDuration, 24); + } + } + + uint64_t MVHD::getDuration(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(16); + }else{ + return getInt64(24); + } + } + + void MVHD::setRate(uint32_t newRate){ + if (getVersion() == 0){ + setInt32( newRate, 20); + }else{ + setInt32(newRate, 32); + } + } + + uint32_t MVHD::getRate(){ + if (getVersion() == 0){ + return getInt32(20); + }else{ + return getInt32(32); + } + } + + void MVHD::setVolume(uint16_t newVolume){ + if (getVersion() == 0){ + setInt16(newVolume, 24); + }else{ + setInt16(newVolume, 36); + } + } + + uint16_t MVHD::getVolume(){ + if (getVersion() == 0){ + return getInt16(24); + }else{ + return getInt16(36); + } + } + //10 bytes reserved in between + uint32_t MVHD::getMatrixCount(){ + return 9; + } + + void MVHD::setMatrix(int32_t newMatrix, size_t index){ + int offset = 0; + if (getVersion() == 0){ + offset = 24 + 2 + 10; + }else{ + offset = 36 + 2 + 10; + } + setInt32(newMatrix, offset + index * 4); + } + + int32_t MVHD::getMatrix(size_t index){ + int offset = 0; + if (getVersion() == 0){ + offset = 24 + 2 + 10; + }else{ + offset = 36 + 2 + 10; + } + 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); + } + } + + uint32_t MVHD::getTrackID(){ + if (getVersion() == 0){ + return getInt32(86); + }else{ + return getInt32(98); + } + } + + std::string MVHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[mvhd] Movie Header Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; + r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; + r << std::string(indent + 1, ' ') << "TimeScale: " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; + r << std::string(indent + 1, ' ') << "Rate: " << getRate() << std::endl; + r << std::string(indent + 1, ' ') << "Volume: " << getVolume() << std::endl; + r << std::string(indent + 1, ' ') << "Matrix: "; + for (unsigned int i = 0; i< getMatrixCount(); i++){ + r << getMatrix(i); + if (i!=getMatrixCount()-1){ + r << ", "; + } + } + r << std::endl; + r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; + return r.str(); + } + + TFRA::TFRA(){ + memcpy(data + 4, "dref", 4); + } + + //note, fullbox starts at byte 4 + void TFRA::setTrackID(uint32_t newTrackID){ + setInt32(newTrackID, 4); + } + + uint32_t TFRA::getTrackID(){ + return getInt32(4); + } + + void TFRA::setLengthSizeOfTrafNum(char newVal){ + char part = getInt8(11); + setInt8(((newVal & 0x03)<<4) + (part & 0xCF),11); + } + + char TFRA::getLengthSizeOfTrafNum(){ + return (getInt8(11)>>4) & 0x03; + } + + void TFRA::setLengthSizeOfTrunNum(char newVal){ + char part = getInt8(11); + setInt8(((newVal & 0x03)<<2) + (part & 0xF3),11); + } + + char TFRA::getLengthSizeOfTrunNum(){ + return (getInt8(11)>>2) & 0x03; + } + + void TFRA::setLengthSizeOfSampleNum(char newVal){ + char part = getInt8(11); + setInt8(((newVal & 0x03)) + (part & 0xFC),11); + } + + char TFRA::getLengthSizeOfSampleNum(){ + return (getInt8(11)) & 0x03; + } + + void TFRA::setNumberOfEntry(uint32_t newNumberOfEntry){ + setInt32(newNumberOfEntry,12); + } + + uint32_t TFRA::getNumberOfEntry(){ + return getInt32(12); + } + + uint32_t TFRA::getTFRAEntrySize(){ + int EntrySize= (getVersion()==1 ? 16 : 8); + EntrySize += getLengthSizeOfTrafNum()+1; + EntrySize += getLengthSizeOfTrunNum()+1; + EntrySize += getLengthSizeOfSampleNum()+1; + return EntrySize; + } + + void TFRA::setTFRAEntry(TFRAEntry newTFRAEntry, uint32_t no){ + if (no + 1 > getNumberOfEntry()){//if a new entry is issued + uint32_t offset = 16 + getTFRAEntrySize() * getNumberOfEntry();//start of filler in bytes + uint32_t fillsize = (no + 1 - getNumberOfEntry())*getTFRAEntrySize();//filler in bytes + if ( !reserve(offset, 0, fillsize)){//filling space + return; + } + setNumberOfEntry(no+1); + } + uint32_t loc = 16 + no * getTFRAEntrySize(); + if (getVersion() == 1){ + setInt64(newTFRAEntry.time, loc); + setInt64(newTFRAEntry.moofOffset, loc+8); + loc += 16; + }else{ + setInt32(newTFRAEntry.time, loc); + setInt32(newTFRAEntry.moofOffset, loc+4); + loc += 8; + } + switch (getLengthSizeOfTrafNum()){ + case 0: + setInt8(newTFRAEntry.trafNumber, loc); + break; + case 1: + setInt16(newTFRAEntry.trafNumber, loc); + break; + case 2: + setInt24(newTFRAEntry.trafNumber, loc); + break; + case 3: + setInt32(newTFRAEntry.trafNumber, loc); + break; + } + loc += getLengthSizeOfTrafNum() + 1; + switch (getLengthSizeOfTrunNum()){ + case 0: + setInt8(newTFRAEntry.trunNumber, loc); + break; + case 1: + setInt16(newTFRAEntry.trunNumber, loc); + break; + case 2: + setInt24(newTFRAEntry.trunNumber, loc); + break; + case 3: + setInt32(newTFRAEntry.trunNumber, loc); + break; + } + loc += getLengthSizeOfTrunNum() + 1; + switch (getLengthSizeOfSampleNum()){ + case 0: + setInt8(newTFRAEntry.sampleNumber, loc); + break; + case 1: + setInt16(newTFRAEntry.sampleNumber, loc); + break; + case 2: + setInt24(newTFRAEntry.sampleNumber, loc); + break; + case 3: + setInt32(newTFRAEntry.sampleNumber, loc); + break; + } + } + + TFRAEntry & TFRA::getTFRAEntry(uint32_t no){ + static TFRAEntry retval; + if (no >= getNumberOfEntry()){ + static TFRAEntry inval; + return inval; + } + uint32_t loc = 16 + no * getTFRAEntrySize(); + if (getVersion() == 1){ + retval.time = getInt64(loc); + retval.moofOffset = getInt64(loc + 8); + loc += 16; + }else{ + retval.time = getInt32(loc); + retval.moofOffset = getInt32(loc + 4); + loc += 8; + } + switch (getLengthSizeOfTrafNum()){ + case 0: + retval.trafNumber = getInt8(loc); + break; + case 1: + retval.trafNumber = getInt16(loc); + break; + case 2: + retval.trafNumber = getInt24(loc); + break; + case 3: + retval.trafNumber = getInt32(loc); + break; + } + loc += getLengthSizeOfTrafNum() + 1; + switch (getLengthSizeOfTrunNum()){ + case 0: + retval.trunNumber = getInt8(loc); + break; + case 1: + retval.trunNumber = getInt16(loc); + break; + case 2: + retval.trunNumber = getInt24(loc); + break; + case 3: + retval.trunNumber = getInt32(loc); + break; + } + loc += getLengthSizeOfTrunNum() + 1; + switch (getLengthSizeOfSampleNum()){ + case 0: + retval.sampleNumber = getInt8(loc); + break; + case 1: + retval.sampleNumber = getInt16(loc); + break; + case 2: + retval.sampleNumber = getInt24(loc); + break; + case 3: + retval.sampleNumber = getInt32(loc); + break; + } + return retval; + } + + std::string TFRA::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[tfra] Track Fragment Random Access Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; + r << std::string(indent + 1, ' ') << "lengthSizeOfTrafNum: " << (int)getLengthSizeOfTrafNum() << std::endl; + r << std::string(indent + 1, ' ') << "lengthSizeOfTrunNum: " << (int)getLengthSizeOfTrunNum() << std::endl; + r << std::string(indent + 1, ' ') << "lengthSizeOfSampleNum: " << (int)getLengthSizeOfSampleNum() << std::endl; + r << std::string(indent + 1, ' ') << "NumberOfEntry: " << getNumberOfEntry() << std::endl; + for (unsigned int i = 0; i < getNumberOfEntry(); i++){ + static TFRAEntry temp; + temp = getTFRAEntry(i); + r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; + r << std::string(indent + 2, ' ') << "Time: " << temp.time << std::endl; + r << std::string(indent + 2, ' ') << "MoofOffset: " << temp.moofOffset << std::endl; + r << std::string(indent + 2, ' ') << "TrafNumber: " << temp.trafNumber << std::endl; + r << std::string(indent + 2, ' ') << "TrunNumber: " << temp.trunNumber << std::endl; + r << std::string(indent + 2, ' ') << "SampleNumber: " << temp.sampleNumber << std::endl; + } + return r.str(); + } + + TKHD::TKHD(char v, uint32_t f){ + memcpy(data + 4, "tkhd", 4); + setVersion(v); + setFlags(f); + setCreationTime(0); + setModificationTime(0); + setTrackID(0); + setDuration(0); + setLayer(0); + setAlternateGroup(0); + setVolume(0x0100); + setMatrix(0x00010000,0); + setMatrix(0x00010000,4); + //fills automatically with zero's + setMatrix(0x40000000,8); + setWidth(0); + setHeight(0); + } + + void TKHD::setCreationTime(uint64_t newCreationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newCreationTime, 4); + }else{ + setInt64(newCreationTime, 4); + } + } + + uint64_t TKHD::getCreationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(4); + }else{ + return getInt64(4); + } + } + + void TKHD::setModificationTime(uint64_t newModificationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newModificationTime, 8); + }else{ + setInt64(newModificationTime, 12); + } + } + + uint64_t TKHD::getModificationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(8); + }else{ + return getInt64(12); + } + } + + void TKHD::setTrackID(uint32_t newTrackID){ + if (getVersion() == 0){ + setInt32((uint32_t) newTrackID, 12); + }else{ + setInt32(newTrackID, 20); + } + } + + uint32_t TKHD::getTrackID(){ + if (getVersion() == 0){ + return getInt32(12); + }else{ + return getInt32(20); + } + } + //note 4 bytes reserved in between + void TKHD::setDuration(uint64_t newDuration){ + if (getVersion() == 0){ + setInt32(newDuration, 20); + }else{ + setInt64(newDuration, 28); + } + } + + uint64_t TKHD::getDuration(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(20); + }else{ + return getInt64(28); + } + } + //8 bytes reserved in between + void TKHD::setLayer(uint16_t newLayer){ + if (getVersion() == 0){ + setInt16(newLayer, 32); + }else{ + setInt16(newLayer, 44); + } + } + + uint16_t TKHD::getLayer(){ + if (getVersion() == 0){ + return getInt16(32); + }else{ + return getInt16(44); + } + } + + void TKHD::setAlternateGroup(uint16_t newAlternateGroup){ + if (getVersion() == 0){ + setInt16(newAlternateGroup, 34); + }else{ + setInt16(newAlternateGroup, 46); + } + } + + uint16_t TKHD::getAlternateGroup(){ + if (getVersion() == 0){ + return getInt16(34); + }else{ + return getInt16(46); + } + } + + void TKHD::setVolume(uint16_t newVolume){ + if (getVersion() == 0){ + setInt16(newVolume, 36); + }else{ + setInt16(newVolume, 48); + } + } + + uint16_t TKHD::getVolume(){ + if (getVersion() == 0){ + return getInt16(36); + }else{ + return getInt16(48); + } + } + //2 bytes reserved in between + uint32_t TKHD::getMatrixCount(){ + return 9; + } + + void TKHD::setMatrix(int32_t newMatrix, size_t index){ + int offset = 0; + if (getVersion() == 0){ + offset = 36 + 2 + 2; + }else{ + offset = 48 + 2 + 2; + } + setInt32(newMatrix, offset + index * 4); + } + + int32_t TKHD::getMatrix(size_t index){ + int offset = 0; + if (getVersion() == 0){ + offset = 36 + 2 + 2; + }else{ + offset = 48 + 2 + 2; + } + return getInt32(offset + index * 4); + } + + void TKHD::setWidth(uint32_t newWidth){ + if (getVersion() == 0){ + setInt32(newWidth, 76); + }else{ + setInt32(newWidth, 88); + } + } + + uint32_t TKHD::getWidth(){ + if (getVersion() == 0){ + return getInt32(76); + }else{ + return getInt32(88); + } + } + + void TKHD::setHeight(uint32_t newHeight){ + if (getVersion() == 0){ + setInt32(newHeight, 80); + }else{ + setInt32(newHeight, 92); + } + } + + uint32_t TKHD::getHeight(){ + if (getVersion() == 0){ + return getInt32(80); + }else{ + return getInt32(92); + } + } + + std::string TKHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[tkhd] Track Header Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; + r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; + r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; + r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; + r << std::string(indent + 1, ' ') << "Layer: " << getLayer() << std::endl; + r << std::string(indent + 1, ' ') << "AlternateGroup: " << getAlternateGroup() << std::endl; + r << std::string(indent + 1, ' ') << "Volume: " << getVolume() << std::endl; + r << std::string(indent + 1, ' ') << "Matrix: "; + for (unsigned int i = 0; i< getMatrixCount(); i++){ + r << getMatrix(i); + if (i!=getMatrixCount()-1){ + r << ", "; + } + } + r << std::endl; + r << std::string(indent + 1, ' ') << "Width: " << (getWidth() >> 16) << "." << (getWidth() & 0xFFFF) << std::endl; + r << std::string(indent + 1, ' ') << "Height: " << (getHeight() >> 16) << "." << (getHeight() & 0xFFFF) << std::endl; + return r.str(); + } + + MDHD::MDHD(char v, uint32_t f){ + memcpy(data + 4, "mdhd", 4); + setVersion(v); + setFlags(f); + setCreationTime(0); + setModificationTime(0); + setTimeScale(1000); + setDuration(0); + setLanguage(0); + if (v==0){ + setInt16(0,22); + }else{ + setInt16(0,34); + } + } + + void MDHD::setCreationTime(uint64_t newCreationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newCreationTime, 4); + }else{ + setInt64(newCreationTime, 4); + } + } + + uint64_t MDHD::getCreationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(4); + }else{ + return getInt64(4); + } + } + + void MDHD::setModificationTime(uint64_t newModificationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newModificationTime, 8); + }else{ + setInt64(newModificationTime, 12); + } + } + + uint64_t MDHD::getModificationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(8); + }else{ + return getInt64(12); + } + } + + void MDHD::setTimeScale(uint32_t newTimeScale){ + if (getVersion() == 0){ + setInt32((uint32_t) newTimeScale, 12); + }else{ + setInt32(newTimeScale, 20); + } + } + + uint32_t MDHD::getTimeScale(){ + if (getVersion() == 0){ + return getInt32(12); + }else{ + return getInt32(20); + } + } + + void MDHD::setDuration(uint64_t newDuration){ + if (getVersion() == 0){ + setInt32((uint32_t) newDuration, 16); + }else{ + setInt64(newDuration, 24); + } + } + + uint64_t MDHD::getDuration(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(16); + }else{ + return getInt64(24); + } + } + + void MDHD::setLanguage (uint16_t newLanguage){ + if (getVersion() == 0){ + setInt16(newLanguage & 0x7F, 20); + }else{ + setInt16(newLanguage & 0x7F, 32); + } + } + + uint16_t MDHD::getLanguage(){ + if (getVersion() == 0){ + return getInt16(20) & 0x7F; + }else{ + return getInt16(32) & 0x7F; + } + } + + std::string MDHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[mdhd] Media Header Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; + r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; + r << std::string(indent + 1, ' ') << "TimeScale: " << getTimeScale() << std::endl; + r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; + r << std::string(indent + 1, ' ') << "Language: 0x" << std::hex << getLanguage() << std::dec<< std::endl; + return r.str(); + } + + STTS::STTS(char v, uint32_t f){ + memcpy(data + 4, "stts", 4); + setVersion(v); + setFlags(f); + setEntryCount(0); + } + + void STTS::setEntryCount(uint32_t newEntryCount){ + setInt32(newEntryCount, 4); + } + + uint32_t STTS::getEntryCount(){ + return getInt32(4); + } + + void STTS::setSTTSEntry(STTSEntry newSTTSEntry, uint32_t no){ + if(no + 1 > getEntryCount()){ + setEntryCount(no + 1); + for (unsigned int i = getEntryCount(); i < no; i++){ + setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits + } + } + setInt32(newSTTSEntry.sampleCount, 8 + no * 8); + setInt32(newSTTSEntry.sampleDelta, 8 + (no * 8) + 4); + } + + STTSEntry STTS::getSTTSEntry(uint32_t no){ + static STTSEntry retval; + if (no >= getEntryCount()){ + static STTSEntry inval; + return inval; + } + retval.sampleCount = getInt32(8 + (no * 8)); + retval.sampleDelta = getInt32(8 + (no * 8) + 4); + return retval; + } + + std::string STTS::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i < getEntryCount(); i++){ + static STTSEntry temp; + temp = getSTTSEntry(i); + r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; + r << std::string(indent + 2, ' ') << "SampleCount: " << temp.sampleCount << std::endl; + r << std::string(indent + 2, ' ') << "SampleDelta: " << temp.sampleDelta << std::endl; + } + return r.str(); + + } + + CTTS::CTTS(){ + memcpy(data + 4, "ctts", 4); + } + + void CTTS::setEntryCount(uint32_t newEntryCount){ + setInt32(newEntryCount, 4); + } + + uint32_t CTTS::getEntryCount(){ + return getInt32(4); + } + + void CTTS::setCTTSEntry(CTTSEntry newCTTSEntry, uint32_t no){ + if(no + 1 > getEntryCount()){ + for (unsigned int i = getEntryCount(); i < no; i++){ + setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits + } + } + setInt32(newCTTSEntry.sampleCount, 8 + no * 8); + setInt32(newCTTSEntry.sampleOffset, 8 + (no * 8) + 4); + } + + CTTSEntry CTTS::getCTTSEntry(uint32_t no){ + static CTTSEntry retval; + if (no >= getEntryCount()){ + static CTTSEntry inval; + return inval; + } + retval.sampleCount = getInt32(8 + (no * 8)); + retval.sampleOffset = getInt32(8 + (no * 8) + 4); + return retval; + } + + std::string CTTS::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i < getEntryCount(); i++){ + static CTTSEntry temp; + temp = getCTTSEntry(i); + r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; + r << std::string(indent + 2, ' ') << "SampleCount: " << temp.sampleCount << std::endl; + r << std::string(indent + 2, ' ') << "SampleOffset: " << temp.sampleOffset << std::endl; + } + return r.str(); + + } + + STSC::STSC(char v, uint32_t f){ + memcpy(data + 4, "stsc", 4); + setVersion(v); + setFlags(f); + setEntryCount(0); + } + + void STSC::setEntryCount(uint32_t newEntryCount){ + setInt32(newEntryCount, 4); + } + + uint32_t STSC::getEntryCount(){ + return getInt32(4); + } + + void STSC::setSTSCEntry(STSCEntry newSTSCEntry, uint32_t no){ + if(no + 1 > getEntryCount()){ + setEntryCount(no+1); + for (unsigned int i = getEntryCount(); i < no; i++){ + setInt64(0, 8 + (i * 12));//filling up undefined entries of 64 bits + setInt32(0, 8 + (i * 12) + 8); + } + } + setInt32(newSTSCEntry.firstChunk, 8 + no * 12); + setInt32(newSTSCEntry.samplesPerChunk, 8 + (no * 12) + 4); + setInt32(newSTSCEntry.sampleDescriptionIndex, 8 + (no * 12) + 8); + } + + STSCEntry STSC::getSTSCEntry(uint32_t no){ + static STSCEntry retval; + if (no >= getEntryCount()){ + static STSCEntry inval; + return inval; + } + retval.firstChunk = getInt32(8 + (no * 12)); + retval.samplesPerChunk = getInt32(8 + (no * 12) + 4); + retval.sampleDescriptionIndex = getInt32(8 + (no * 12) + 8); + return retval; + } + + std::string STSC::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stsc] Sample To Chunk Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i < getEntryCount(); i++){ + static STSCEntry temp; + temp = getSTSCEntry(i); + r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; + r << std::string(indent + 2, ' ') << "FirstChunk: " << temp.firstChunk << std::endl; + r << std::string(indent + 2, ' ') << "SamplesPerChunk: " << temp.samplesPerChunk << std::endl; + r << std::string(indent + 2, ' ') << "SampleDescriptionIndex: " << temp.sampleDescriptionIndex << std::endl; + } + return r.str(); + } + + STCO::STCO(char v, uint32_t f){ + memcpy(data + 4, "stco", 4); + setVersion(v); + setFlags(f); + setEntryCount(0); + } + + void STCO::setEntryCount(uint32_t newEntryCount){ + setInt32(newEntryCount, 4); + } + + uint32_t STCO::getEntryCount(){ + return getInt32(4); + } + + void STCO::setChunkOffset(uint32_t newChunkOffset, uint32_t no){ + if (no + 1 > getEntryCount()){ + for (unsigned int i = getEntryCount(); i < no; i++){ + setInt32(0, 8 + i * 4);//filling undefined entries + } + setEntryCount(no+1); + } + setInt32(newChunkOffset, 8 + no * 4); + } + + uint32_t STCO::getChunkOffset(uint32_t no){ + if (no >= getEntryCount()){ + return 0; + } + return getInt32(8 + no * 4); + } + + std::string STCO::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stco] Chunk Offset Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i < getEntryCount(); i++){ + r << std::string(indent + 1, ' ') << "ChunkOffset[" << i <<"]: " << getChunkOffset(i) << std::endl; + } + return r.str(); + } + + STSZ::STSZ(char v, uint32_t f){ + memcpy(data + 4, "stsz", 4); + setVersion(v); + setFlags(f); + setSampleCount(0); + } + + void STSZ::setSampleSize(uint32_t newSampleSize){ + setInt32(newSampleSize, 4); + } + + uint32_t STSZ::getSampleSize(){ + return getInt32(4); + } + + void STSZ::setSampleCount(uint32_t newSampleCount){ + setInt32(newSampleCount, 8); + } + + uint32_t STSZ::getSampleCount(){ + return getInt32(8); + } + + void STSZ::setEntrySize(uint32_t newEntrySize, uint32_t no){ + if (no + 1 > getSampleCount()){ + setSampleCount(no + 1); + for (unsigned int i = getSampleCount(); i < no; i++){ + setInt32(0, 12 + i * 4);//filling undefined entries + } + } + setInt32(newEntrySize, 12 + no * 4); + } + + uint32_t STSZ::getEntrySize(uint32_t no){ + if (no >= getSampleCount()){ + return 0; + } + return getInt32(12 + no * 4); + } + + std::string STSZ::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stsz] Sample Size Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "SampleSize: " << getSampleSize() << std::endl; + r << std::string(indent + 1, ' ') << "SampleCount: " << getSampleCount() << std::endl; + for (unsigned int i = 0; i < getSampleCount(); i++){ + r << std::string(indent + 1, ' ') << "EntrySize[" << i <<"]: " << getEntrySize(i) << std::endl; + } + return r.str(); + } + + SampleEntry::SampleEntry(){ + memcpy(data + 4, "erro", 4); + } + + void SampleEntry::setDataReferenceIndex(uint16_t newDataReferenceIndex){ + setInt16(newDataReferenceIndex, 6); + } + + uint16_t SampleEntry::getDataReferenceIndex(){ + return getInt16(6); + } + + std::string SampleEntry::toPrettySampleString(uint32_t indent){ + std::stringstream r; + r << std::string(indent + 1, ' ') << "DataReferenceIndex: " << getDataReferenceIndex() << std::endl; + return r.str(); + } + + CLAP::CLAP(){ + memcpy(data + 4, "clap", 4); + setHorizOffN(0); + setHorizOffD(0); + setVertOffN(0); + setVertOffD(0); + } + + void CLAP::setCleanApertureWidthN(uint32_t newVal){ + setInt32(newVal,0); + } + + uint32_t CLAP::getCleanApertureWidthN(){ + return getInt32(0); + } + + void CLAP::setCleanApertureWidthD(uint32_t newVal){ + setInt32(newVal,4); + } + + uint32_t CLAP::getCleanApertureWidthD(){ + return getInt32(4); + } + + void CLAP::setCleanApertureHeightN(uint32_t newVal){ + setInt32(newVal,8); + } + + uint32_t CLAP::getCleanApertureHeightN(){ + return getInt32(8); + } + + void CLAP::setCleanApertureHeightD(uint32_t newVal){ + setInt32(newVal, 12); + } + + uint32_t CLAP::getCleanApertureHeightD(){ + return getInt32(12); + } + + void CLAP::setHorizOffN(uint32_t newVal){ + setInt32(newVal, 16); + } + + uint32_t CLAP::getHorizOffN(){ + return getInt32(16); + } + + void CLAP::setHorizOffD(uint32_t newVal){ + setInt32(newVal, 20); + } + + uint32_t CLAP::getHorizOffD(){ + return getInt32(20); + } + + void CLAP::setVertOffN(uint32_t newVal){ + setInt32(newVal, 24); + } + + uint32_t CLAP::getVertOffN(){ + return getInt32(24); + } + + void CLAP::setVertOffD(uint32_t newVal){ + setInt32(newVal, 28); + } + + uint32_t CLAP::getVertOffD(){ + return getInt32(32); + } + + std::string CLAP::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[clap] Clean Aperture Box (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "CleanApertureWidthN: " << getCleanApertureWidthN() << std::endl; + r << std::string(indent + 1, ' ') << "CleanApertureWidthD: " << getCleanApertureWidthD() << std::endl; + r << std::string(indent + 1, ' ') << "CleanApertureHeightN: " << getCleanApertureHeightN() << std::endl; + r << std::string(indent + 1, ' ') << "CleanApertureHeightD: " << getCleanApertureHeightD() << std::endl; + r << std::string(indent + 1, ' ') << "HorizOffN: " << getHorizOffN() << std::endl; + r << std::string(indent + 1, ' ') << "HorizOffD: " << getHorizOffD() << std::endl; + r << std::string(indent + 1, ' ') << "VertOffN: " << getVertOffN() << std::endl; + r << std::string(indent + 1, ' ') << "VertOffD: " << getVertOffD() << std::endl; + return r.str(); + } + + PASP::PASP(){ + memcpy(data + 4, "pasp", 4); + } + + void PASP::setHSpacing(uint32_t newVal){ + setInt32(newVal, 0); + } + + uint32_t PASP::getHSpacing(){ + return getInt32(0); + } + + void PASP::setVSpacing(uint32_t newVal){ + setInt32(newVal, 4); + } + + uint32_t PASP::getVSpacing(){ + return getInt32(4); + } + + std::string PASP::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[pasp] Pixel Aspect Ratio Box (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "HSpacing: " << getHSpacing() << std::endl; + r << std::string(indent + 1, ' ') << "VSpacing: " << getVSpacing() << std::endl; + return r.str(); + } + + VisualSampleEntry::VisualSampleEntry(){ + memcpy(data + 4, "erro", 4); + setHorizResolution(0x00480000); + setVertResolution(0x00480000); + setFrameCount(1); + setCompressorName(""); + setDepth(0x0018); + } + + void VisualSampleEntry::setCodec(const char* newCodec){ + memcpy(data + 4, newCodec, 4); + } + + void VisualSampleEntry::setWidth(uint16_t newWidth){ + setInt16(newWidth,24); + } + + uint16_t VisualSampleEntry::getWidth(){ + return getInt16(24); + } + + void VisualSampleEntry::setHeight(uint16_t newHeight){ + setInt16(newHeight, 26); + } + + uint16_t VisualSampleEntry::getHeight(){ + return getInt16(26); + } + + void VisualSampleEntry::setHorizResolution (uint32_t newHorizResolution){ + setInt32(newHorizResolution, 28); + } + + uint32_t VisualSampleEntry::getHorizResolution(){ + return getInt32(28); + } + + void VisualSampleEntry::setVertResolution (uint32_t newVertResolution){ + setInt32(newVertResolution,32); + } + + uint32_t VisualSampleEntry::getVertResolution(){ + return getInt32(32); + } + + void VisualSampleEntry::setFrameCount(uint16_t newFrameCount){ + setInt16(newFrameCount, 40); + } + + uint16_t VisualSampleEntry::getFrameCount(){ + return getInt16(40); + } + + void VisualSampleEntry::setCompressorName(std::string newCompressorName){ + newCompressorName.resize(32, ' '); + setString(newCompressorName,42); + } + + std::string VisualSampleEntry::getCompressorName(){ + return getString(42); + } + + void VisualSampleEntry::setDepth(uint16_t newDepth){ + setInt16(newDepth, 74); + } + + uint16_t VisualSampleEntry::getDepth(){ + return getInt16(74); + } + + void VisualSampleEntry::setCLAP(Box& clap){ + setBox(clap,78); + } + + Box & VisualSampleEntry::getCLAP(){ + static Box ret = Box((char*)"\000\000\000\010erro", false); + if(payloadSize() <84){//if the EntryBox is not big enough to hold a CLAP/PASP + return ret; + } + ret = getBox(78); + return ret; + } + + Box & VisualSampleEntry::getPASP(){ + static Box ret = Box((char*)"\000\000\000\010erro", false); + if(payloadSize() <84){//if the EntryBox is not big enough to hold a CLAP/PASP + return ret; + } + if (payloadSize() < 78 + getBoxLen(78) + 8){ + return ret; + }else{ + return getBox(78+getBoxLen(78)); + } + + } + + std::string VisualSampleEntry::toPrettyVisualString(uint32_t indent, std::string name){ + std::stringstream r; + r << std::string(indent, ' ') << name << " (" << boxedSize() << ")" << std::endl; + r << toPrettySampleString(indent); + r << std::string(indent + 1, ' ') << "Width: " << getWidth() << std::endl; + r << std::string(indent + 1, ' ') << "Height: " << getHeight() << std::endl; + r << std::string(indent + 1, ' ') << "HorizResolution: " << getHorizResolution() << std::endl; + r << std::string(indent + 1, ' ') << "VertResolution: " << getVertResolution() << std::endl; + r << std::string(indent + 1, ' ') << "FrameCount: " << getFrameCount() << std::endl; + r << std::string(indent + 1, ' ') << "CompressorName: " << getCompressorName() << std::endl; + r << std::string(indent + 1, ' ') << "Depth: " << getDepth() << std::endl; + if (!getCLAP().isType("erro")){ + r << getCLAP().toPrettyString(indent+1); + } + if (!getPASP().isType("erro")){ + r << getPASP().toPrettyString(indent+1); + } + return r.str(); + } + + AudioSampleEntry::AudioSampleEntry(){ + memcpy(data + 4, "erro", 4); + setChannelCount(2); + setSampleSize(16); + setSampleRate(44100); + } + + void AudioSampleEntry::setCodec(const char* newCodec){ + memcpy(data + 4, newCodec, 4); + } + + void AudioSampleEntry::setChannelCount(uint16_t newChannelCount){ + setInt16(newChannelCount,16); + } + + uint16_t AudioSampleEntry::getChannelCount(){ + return getInt16(16); + } + + void AudioSampleEntry::setSampleSize(uint16_t newSampleSize){ + setInt16(newSampleSize,18); + } + + uint16_t AudioSampleEntry::getSampleSize(){ + return getInt16(18); + } + + void AudioSampleEntry::setPreDefined(uint16_t newPreDefined){ + setInt16(newPreDefined,20); + } + + uint16_t AudioSampleEntry::getPreDefined(){ + return getInt16(20); + } + + void AudioSampleEntry::setSampleRate(uint32_t newSampleRate){ + setInt32(newSampleRate << 16, 24); + } + + uint32_t AudioSampleEntry::getSampleRate(){ + return getInt32(24) >> 16; + } + + void AudioSampleEntry::setCodecBox(Box& newBox){ + setBox(newBox, 28); + } + + Box & AudioSampleEntry::getCodecBox(){ + return getBox(28); + } + + std::string AudioSampleEntry::toPrettyAudioString(uint32_t indent, std::string name){ + std::stringstream r; + r << std::string(indent, ' ') << name << " (" << boxedSize() << ")" << std::endl; + r << toPrettySampleString(indent); + r << std::string(indent + 1, ' ') << "ChannelCount: " << getChannelCount() << std::endl; + r << std::string(indent + 1, ' ') << "SampleSize: " << getSampleSize() << std::endl; + 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; + return r.str(); + } + + MP4A::MP4A(){ + memcpy(data + 4, "mp4a", 4); + } + + std::string MP4A::toPrettyString(uint32_t indent){ + return toPrettyAudioString(indent, "[mp4a] MPEG-4 Audio"); + } + + AAC::AAC(){ + memcpy(data + 4, "aac ", 4); + } + + std::string AAC::toPrettyString(uint32_t indent){ + return toPrettyAudioString(indent, "[aac ] Advanced Audio Codec"); + } + + AVC1::AVC1(){ + memcpy(data + 4, "avc1", 4); + } + + std::string AVC1::toPrettyString(uint32_t indent){ + return toPrettyVisualString(indent, "[avc1] Advanced Video Codec 1"); + } + + H264::H264(){ + memcpy(data + 4, "h264", 4); + } + + std::string H264::toPrettyString(uint32_t indent){ + return toPrettyVisualString(indent, "[h264] H.264/MPEG-4 AVC"); + } + + STSD::STSD(char v, uint32_t f){ + memcpy(data + 4, "stsd", 4); + setVersion(v); + setFlags(f); + setEntryCount(0); + } + + void STSD::setEntryCount (uint32_t newEntryCount){ + setInt32(newEntryCount, 4); + } + + uint32_t STSD::getEntryCount(){ + return getInt32(4); + } + + void STSD::setEntry(Box & newContent, uint32_t no){ + int tempLoc = 8; + unsigned int entryCount = getEntryCount(); + for (unsigned int i = 0; i < no; i++){ + if (i < entryCount){ + tempLoc += getBoxLen(tempLoc); + }else{ + if ( !reserve(tempLoc, 0, (no - entryCount) * 8)){ + return; + } + memset(data + tempLoc, 0, (no - entryCount) * 8); + tempLoc += (no - entryCount) * 8; + break; + } + } + setBox(newContent, tempLoc); + if (getEntryCount() < no+1){ + setEntryCount(no+1); + } + } + + Box & STSD::getEntry(uint32_t no){ + static Box ret = Box((char*)"\000\000\000\010erro", false); + if (no > getEntryCount()){ + return ret; + } + unsigned int i = 0; + int tempLoc = 8; + while (i < no){ + tempLoc += getBoxLen(tempLoc); + i++; + } + return getBox(tempLoc); + } + + std::string STSD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stsd] Sample Description Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntrySize: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i < getEntryCount(); i++){ + Box curBox = Box(getEntry(i).asBox(), false); + r << curBox.toPrettyString(indent + 1); + } + return r.str(); + } + + EDTS::EDTS(){ + memcpy(data + 4, "edts", 4); + } + + UDTA::UDTA(){ + memcpy(data + 4, "udta", 4); + } + + STSS::STSS(char v, uint32_t f){ + memcpy(data + 4, "stss", 4); + setVersion(v); + setFlags(f); + setEntryCount(0); + } + + void STSS::setEntryCount(uint32_t newVal){ + setInt32(newVal, 4); + } + + uint32_t STSS::getEntryCount(){ + return getInt32(4); + } + + void STSS::setSampleNumber(uint32_t newVal, uint32_t index){ + if (index >= getEntryCount()){ + setEntryCount(index + 1); + } + setInt32(newVal, 8 + (index * 4)); + } + + uint32_t STSS::getSampleNumber(uint32_t index){ + if (index >= getEntryCount()){ + return 0; + } + return getInt32(8 + (index * 4)); + } + + std::string STSS::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[stss] Sync Sample Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; + for (unsigned int i = 0; i < getEntryCount(); i++){ + r << std::string(indent + 1, ' ') << "SampleNumber[" << i <<"] : " << getSampleNumber(i) << std::endl; + } + return r.str(); + } + + META::META(){ + memcpy(data + 4, "meta", 4); + } + + std::string META::toPrettyString(uint32_t indent){ + return toPrettyCFBString(indent, "[meta] Meta Box"); + } + + ELST::ELST(){ + memcpy(data + 4, "elst", 4); + } + + void ELST::setSegmentDuration(uint64_t newVal){ + if (getVersion() == 1){ + setInt64(newVal, 4); + }else{ + setInt32(newVal, 4); + } + } + + uint64_t ELST::getSegmentDuration(){ + if (getVersion() == 1){ + return getInt64(4); + }else{ + return getInt32(4); + } + } + + void ELST::setMediaTime(uint64_t newVal){ + if (getVersion() == 1){ + setInt64(newVal, 12); + }else{ + setInt32(newVal, 8); + } + } + + uint64_t ELST::getMediaTime(){ + if (getVersion() == 1){ + return getInt64(12); + }else{ + return getInt32(8); + } + } + + void ELST::setMediaRateInteger(uint16_t newVal){ + if (getVersion() == 1){ + setInt16(newVal, 20); + }else{ + setInt16(newVal, 12); + } + } + + uint16_t ELST::getMediaRateInteger(){ + if (getVersion() == 1){ + return getInt16(20); + }else{ + return getInt16(12); + } + } + + void ELST::setMediaRateFraction(uint16_t newVal){ + if (getVersion() == 1){ + setInt16(newVal, 22); + }else{ + setInt16(newVal, 14); + } + } + + uint16_t ELST::getMediaRateFraction(){ + if (getVersion() == 1){ + return getInt16(22); + }else{ + return getInt16(14); + } + } + + std::string ELST::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[elst] Edit List Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "SegmentDuration: " << getSegmentDuration() << std::endl; + r << std::string(indent + 1, ' ') << "MediaTime: " << getMediaTime() << std::endl; + r << std::string(indent + 1, ' ') << "MediaRateInteger: " << getMediaRateInteger() << std::endl; + r << std::string(indent + 1, ' ') << "MediaRateFraction: " << getMediaRateFraction() << std::endl; + return r.str(); + } +} diff --git a/lib/mp4_generic.h b/lib/mp4_generic.h new file mode 100644 index 00000000..f66667bc --- /dev/null +++ b/lib/mp4_generic.h @@ -0,0 +1,674 @@ +#include "mp4.h" + +namespace MP4{ + class MFHD: public Box{ + public: + MFHD(); + void setSequenceNumber(uint32_t newSequenceNumber); + uint32_t getSequenceNumber(); + std::string toPrettyString(uint32_t indent = 0); + }; + //MFHD Box + + class MOOF: public containerBox{ + public: + MOOF(); + }; + //MOOF Box + + class TRAF: public Box{ + public: + TRAF(); + uint32_t getContentCount(); + void setContent(Box & newContent, uint32_t no); + Box & getContent(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + //TRAF Box + + struct trunSampleInformation{ + uint32_t sampleDuration; + uint32_t sampleSize; + uint32_t sampleFlags; + uint32_t sampleOffset; + }; + enum trunflags{ + trundataOffset = 0x00000001, + trunfirstSampleFlags = 0x00000004, + trunsampleDuration = 0x00000100, + trunsampleSize = 0x00000200, + trunsampleFlags = 0x00000400, + trunsampleOffsets = 0x00000800 + }; + enum sampleflags{ + noIPicture = 0x01000000, + isIPicture = 0x02000000, + noDisposable = 0x00400000, + isDisposable = 0x00800000, + isRedundant = 0x00100000, + noRedundant = 0x00200000, + noKeySample = 0x00010000, + isKeySample = 0x00000000, + MUST_BE_PRESENT = 0x1 + }; + std::string prettySampleFlags(uint32_t flag); + class TRUN: public Box{ + public: + TRUN(); + void setFlags(uint32_t newFlags); + uint32_t getFlags(); + void setDataOffset(uint32_t newOffset); + uint32_t getDataOffset(); + void setFirstSampleFlags(uint32_t newSampleFlags); + uint32_t getFirstSampleFlags(); + uint32_t getSampleInformationCount(); + void setSampleInformation(trunSampleInformation newSample, uint32_t no); + trunSampleInformation getSampleInformation(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + enum tfhdflags{ + tfhdBaseOffset = 0x000001, + tfhdSampleDesc = 0x000002, + tfhdSampleDura = 0x000008, + tfhdSampleSize = 0x000010, + tfhdSampleFlag = 0x000020, + tfhdNoDuration = 0x010000, + }; + class TFHD: public Box{ + public: + TFHD(); + void setFlags(uint32_t newFlags); + uint32_t getFlags(); + void setTrackID(uint32_t newID); + uint32_t getTrackID(); + void setBaseDataOffset(uint64_t newOffset); + uint64_t getBaseDataOffset(); + void setSampleDescriptionIndex(uint32_t newIndex); + uint32_t getSampleDescriptionIndex(); + void setDefaultSampleDuration(uint32_t newDuration); + uint32_t getDefaultSampleDuration(); + void setDefaultSampleSize(uint32_t newSize); + uint32_t getDefaultSampleSize(); + void setDefaultSampleFlags(uint32_t newFlags); + uint32_t getDefaultSampleFlags(); + std::string toPrettyString(uint32_t indent = 0); + }; + + + class AVCC: public Box{ + public: + AVCC(); + void setVersion(uint32_t newVersion); + uint32_t getVersion(); + void setProfile(uint32_t newProfile); + uint32_t getProfile(); + void setCompatibleProfiles(uint32_t newCompatibleProfiles); + uint32_t getCompatibleProfiles(); + void setLevel(uint32_t newLevel); + uint32_t getLevel(); + void setSPSNumber(uint32_t newSPSNumber); + uint32_t getSPSNumber(); + void setSPS(std::string newSPS); + uint32_t getSPSLen(); + char* getSPS(); + void setPPSNumber(uint32_t newPPSNumber); + uint32_t getPPSNumber(); + void setPPS(std::string newPPS); + uint32_t getPPSLen(); + char* getPPS(); + std::string asAnnexB(); + void setPayload(std::string newPayload); + std::string toPrettyString(uint32_t indent = 0); + }; + + ///\todo : ESDS is filthy implemented, clean up when optimising + class ESDS: public fullBox{ + public: + ESDS(); + ESDS(std::string init, uint32_t bps); + char getESDescriptorType(); + void setESDescriptorType(char newVal); + uint32_t getExtendedESDescriptorType();//3 bytes + void setExtendedESDescriptorType(uint32_t newVal);//3 bytes + char getESDescriptorTypeLength(); + void setESDescriptorTypeLength(char newVal); + //ESID 2 bytes + uint16_t getESID(); + void setESID(uint16_t newVal); + //stream priority 1 byte + char getStreamPriority(); + void setStreamPriority(char newVal); + //decoder config descriptor tag 1byte + char getDecoderConfigDescriptorTag(); + void setDecoderConfigDescriptorTag(char newVal); + //extended decoder config descriptor tag 3 bytes + uint32_t getExtendedDecoderConfigDescriptorTag(); + void setExtendedDecoderConfigDescriptorTag(uint32_t newVal);//3 bytes + //decoder config descriptor type length + char getDecoderConfigDescriptorTypeLength(); + void setDecoderConfigDescriptorTypeLength(char newVal); + char getByteObjectTypeID(); + void setByteObjectTypeID(char newVal); + char getStreamType();//6 bits + void setStreamType(char newVal);//6 bits + bool getUpstreamFlag(); + void setUpstreamFlag(bool newVal); + bool getReservedFlag(); + void setReservedFlag(bool newVal); + uint32_t getBufferSize();//3 bytes + void setBufferSize(uint32_t newVal);//3 bytes + uint32_t getMaximumBitRate(); + void setMaximumBitRate(uint32_t newVal); + uint32_t getAverageBitRate(); + void setAverageBitRate(uint32_t newVal); + char getDecoderDescriptorTypeTag(); + void setDecoderDescriptorTypeTag(char newVal); + uint32_t getExtendedDecoderDescriptorTypeTag();//3 bytes + void setExtendedDecoderDescriptorTypeTag(uint32_t newVal);//3 bytes + char getConfigDescriptorTypeLength(); + void setConfigDescriptorTypeLength(char newVal); + std::string getESHeaderStartCodes(); + void setESHeaderStartCodes(std::string newVal); + char getSLConfigDescriptorTypeTag(); + void setSLConfigDescriptorTypeTag(char newVal); + uint32_t getSLConfigExtendedDescriptorTypeTag();//3 bytes + void setSLConfigExtendedDescriptorTypeTag(uint32_t newVal);//3 bytes + char getSLDescriptorTypeLength(); + void setSLDescriptorTypeLength(char newVal); + char getSLValue(); + void setSLValue(char newVal); + std::string toPrettyString(uint32_t indent = 0); + }; + + class FTYP: public Box{ + public: + FTYP(); + void setMajorBrand(uint32_t newMajorBrand); + uint32_t getMajorBrand(); + void setMinorVersion(uint32_t newMinorVersion); + uint32_t getMinorVersion(); + uint32_t getCompatibleBrandsCount(); + void setCompatibleBrands(uint32_t newCompatibleBrand, size_t index); + uint32_t getCompatibleBrands(size_t index); + std::string toPrettyString(uint32_t indent = 0); + }; + + class MOOV: public containerBox{ + public: + MOOV(); + }; + + class MVEX: public containerBox{ + public: + MVEX(); + }; + + class TREX: public Box{ + public: + TREX(); + void setTrackID(uint32_t newTrackID); + uint32_t getTrackID(); + void setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex); + uint32_t getDefaultSampleDescriptionIndex(); + void setDefaultSampleDuration(uint32_t newDefaultSampleDuration); + uint32_t getDefaultSampleDuration(); + void setDefaultSampleSize(uint32_t newDefaultSampleSize); + uint32_t getDefaultSampleSize(); + void setDefaultSampleFlags(uint32_t newDefaultSampleFlags); + uint32_t getDefaultSampleFlags(); + std::string toPrettyString(uint32_t indent = 0); + }; + + + class MFRA: public containerBox{ + public: + MFRA(); + }; + + class TRAK: public containerBox{ + public: + TRAK(); + }; + + class MDIA: public containerBox{ + public: + MDIA(); + }; + + class MINF: public containerBox{ + public: + MINF(); + }; + + class DINF: public containerBox{ + public: + DINF(); + }; + + class MFRO: public Box{ + public: + MFRO(); + void setSize(uint32_t newSize); + uint32_t getSize(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class HDLR: public Box{ + public: + HDLR(); + void setSize(uint32_t newSize); + uint32_t getSize(); + void setPreDefined(uint32_t newPreDefined); + uint32_t getPreDefined(); + void setHandlerType(uint32_t newHandlerType); + uint32_t getHandlerType(); + void setName(std::string newName); + std::string getName(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class VMHD: public fullBox{ + public: + VMHD(); + void setGraphicsMode(uint16_t newGraphicsMode); + uint16_t getGraphicsMode(); + uint32_t getOpColorCount(); + void setOpColor(uint16_t newOpColor, size_t index); + uint16_t getOpColor(size_t index); + std::string toPrettyString(uint32_t indent = 0); + }; + + class SMHD: public fullBox{ + public: + SMHD(); + void setBalance(int16_t newBalance); + int16_t getBalance(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class HMHD: public fullBox{ + public: + HMHD(); + void setMaxPDUSize(uint16_t newMaxPDUSize); + uint16_t getMaxPDUSize(); + void setAvgPDUSize(uint16_t newAvgPDUSize); + uint16_t getAvgPDUSize(); + void setMaxBitRate(uint32_t newMaxBitRate); + uint32_t getMaxBitRate(); + void setAvgBitRate(uint32_t newAvgBitRate); + uint32_t getAvgBitRate(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class NMHD: public fullBox{ + public: + NMHD(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class MEHD: public fullBox{ + public: + MEHD(); + void setFragmentDuration(uint64_t newFragmentDuration); + uint64_t getFragmentDuration(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class STBL: public containerBox{ + public: + STBL(); + }; + + class URL: public fullBox{ + public: + URL(); + void setLocation(std::string newLocation); + std::string getLocation(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class URN: public fullBox{ + public: + URN(); + void setName(std::string newName); + std::string getName(); + void setLocation(std::string newLocation); + std::string getLocation(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class DREF: public fullBox{ + public: + DREF(char v = 1, uint32_t = 0); + uint32_t getEntryCount(); + void setDataEntry(fullBox & newDataEntry, size_t index); + Box & getDataEntry(size_t index); + std::string toPrettyString(uint32_t indent = 0); + }; + + class MVHD: public fullBox{ + public: + MVHD(char v = 1, uint32_t f = 0); + MVHD(long long unsigned int duration); + void setCreationTime(uint64_t newCreationTime); + uint64_t getCreationTime(); + void setModificationTime(uint64_t newModificationTime); + uint64_t getModificationTime(); + void setTimeScale(uint32_t newTimeScale); + uint32_t getTimeScale(); + void setDuration(uint64_t newDuration); + uint64_t getDuration(); + void setRate(uint32_t newRate); + uint32_t getRate(); + void setVolume(uint16_t newVolume); + uint16_t getVolume(); + ///\todo fix default values + uint32_t getMatrixCount(); + void setMatrix(int32_t newMatrix, size_t index); + int32_t getMatrix(size_t index); + void setTrackID(uint32_t newTrackID); + uint32_t getTrackID(); + std::string toPrettyString(uint32_t indent = 0); + }; + + struct TFRAEntry{ + uint64_t time; + uint64_t moofOffset; + uint32_t trafNumber; + uint32_t trunNumber; + uint32_t sampleNumber; + }; + + class TFRA: public fullBox{ + public: + TFRA(); + void setTrackID(uint32_t newTrackID); + uint32_t getTrackID(); + void setLengthSizeOfTrafNum(char newVal); + char getLengthSizeOfTrafNum(); + void setLengthSizeOfTrunNum(char newVal); + char getLengthSizeOfTrunNum(); + void setLengthSizeOfSampleNum(char newVal); + char getLengthSizeOfSampleNum(); + void setNumberOfEntry(uint32_t newNumberOfEntry); + uint32_t getNumberOfEntry(); + void setTFRAEntry(TFRAEntry newTFRAEntry, uint32_t no); + TFRAEntry & getTFRAEntry(uint32_t no); + uint32_t getTFRAEntrySize(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class TKHD: public fullBox{ + public: + TKHD(char v = 1, uint32_t f = 0); + void setCreationTime(uint64_t newCreationTime); + uint64_t getCreationTime(); + void setModificationTime(uint64_t newModificationTime); + uint64_t getModificationTime(); + void setTrackID(uint32_t newTrackID); + uint32_t getTrackID(); + void setDuration(uint64_t newDuration); + uint64_t getDuration(); + + void setLayer(uint16_t newLayer); + uint16_t getLayer(); + void setAlternateGroup(uint16_t newAlternateGroup); + uint16_t getAlternateGroup(); + + void setVolume(uint16_t newVolume); + uint16_t getVolume(); + ///\todo fix default values + uint32_t getMatrixCount(); + void setMatrix(int32_t newMatrix, size_t index); + int32_t getMatrix(size_t index); + + void setWidth(uint32_t newWidth); + uint32_t getWidth(); + void setHeight(uint32_t newHeight); + uint32_t getHeight(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class MDHD: public fullBox{ + public: + MDHD(char v = 1, uint32_t f = 0); + void setCreationTime(uint64_t newCreationTime); + uint64_t getCreationTime(); + void setModificationTime(uint64_t newModificationTime); + uint64_t getModificationTime(); + void setTimeScale(uint32_t newTimeScale); + uint32_t getTimeScale(); + void setDuration(uint64_t newDuration); + uint64_t getDuration(); + ///\todo return language properly + void setLanguage(uint16_t newLanguage); + uint16_t getLanguage(); + std::string toPrettyString(uint32_t indent = 0); + }; + + struct STTSEntry{ + uint32_t sampleCount; + uint32_t sampleDelta; + }; + + class STTS: public fullBox{ + public: + STTS(char v = 1, uint32_t f = 0); + void setEntryCount(uint32_t newEntryCount); + uint32_t getEntryCount(); + void setSTTSEntry(STTSEntry newSTTSEntry, uint32_t no); + STTSEntry getSTTSEntry(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + struct CTTSEntry{ + uint32_t sampleCount; + uint32_t sampleOffset; + }; + + class CTTS: public fullBox{ + public: + CTTS(); + void setEntryCount(uint32_t newEntryCount); + uint32_t getEntryCount(); + void setCTTSEntry(CTTSEntry newCTTSEntry, uint32_t no); + CTTSEntry getCTTSEntry(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + struct STSCEntry{ + uint32_t firstChunk; + uint32_t samplesPerChunk; + uint32_t sampleDescriptionIndex; + }; + + class STSC: public fullBox{ + public: + STSC(char v = 1, uint32_t f = 0); + void setEntryCount(uint32_t newEntryCount); + uint32_t getEntryCount(); + void setSTSCEntry(STSCEntry newSTSCEntry, uint32_t no); + STSCEntry getSTSCEntry(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + class STCO: public fullBox{ + public: + STCO(char v = 1, uint32_t f = 0); + void setEntryCount(uint32_t newEntryCount); + uint32_t getEntryCount(); + void setChunkOffset(uint32_t newChunkOffset, uint32_t no); + uint32_t getChunkOffset(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + class STSZ: public fullBox{ + public: + STSZ(char v = 1, uint32_t f = 0); + void setSampleSize(uint32_t newSampleSize); + uint32_t getSampleSize(); + void setSampleCount(uint32_t newSampleCount); + uint32_t getSampleCount(); + void setEntrySize(uint32_t newEntrySize, uint32_t no); + uint32_t getEntrySize(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + class SampleEntry: public Box{ + public: + SampleEntry(); + void setDataReferenceIndex(uint16_t newDataReferenceIndex); + uint16_t getDataReferenceIndex(); + std::string toPrettySampleString(uint32_t index); + }; + + class CLAP: public Box{//CleanApertureBox + public: + CLAP(); + void setCleanApertureWidthN(uint32_t newVal); + uint32_t getCleanApertureWidthN(); + void setCleanApertureWidthD(uint32_t newVal); + uint32_t getCleanApertureWidthD(); + void setCleanApertureHeightN(uint32_t newVal); + uint32_t getCleanApertureHeightN(); + void setCleanApertureHeightD(uint32_t newVal); + uint32_t getCleanApertureHeightD(); + void setHorizOffN(uint32_t newVal); + uint32_t getHorizOffN(); + void setHorizOffD(uint32_t newVal); + uint32_t getHorizOffD(); + void setVertOffN(uint32_t newVal); + uint32_t getVertOffN(); + void setVertOffD(uint32_t newVal); + uint32_t getVertOffD(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class PASP: public Box{ //PixelAspectRatioBox + public: + PASP(); + void setHSpacing(uint32_t newVal); + uint32_t getHSpacing(); + void setVSpacing(uint32_t newVal); + uint32_t getVSpacing(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class VisualSampleEntry: public SampleEntry{ + ///\todo set default values + public: + VisualSampleEntry(); + void setCodec(const char* newCodec); + void setWidth(uint16_t newWidth); + uint16_t getWidth(); + void setHeight(uint16_t newHeight); + uint16_t getHeight(); + void setHorizResolution (uint32_t newHorizResolution); + uint32_t getHorizResolution(); + void setVertResolution (uint32_t newVertResolution); + uint32_t getVertResolution(); + void setFrameCount(uint16_t newFrameCount); + uint16_t getFrameCount(); + void setCompressorName(std::string newCompressorName); + std::string getCompressorName(); + void setDepth(uint16_t newDepth); + uint16_t getDepth(); + Box & getCLAP(); + void setCLAP(Box& clap); + Box & getPASP(); + std::string toPrettyVisualString(uint32_t index = 0, std::string = ""); + }; + + class AudioSampleEntry: public SampleEntry{ + public: + ///\todo set default values + AudioSampleEntry(); + void setCodec(const char* newCodec); + void setChannelCount(uint16_t newChannelCount); + uint16_t getChannelCount(); + void setSampleSize(uint16_t newSampleSize); + uint16_t getSampleSize(); + void setPreDefined(uint16_t newPreDefined); + uint16_t getPreDefined(); + void setSampleRate(uint32_t newSampleRate); + uint32_t getSampleRate(); + void setCodecBox(Box& newBox); + Box & getCodecBox(); + std::string toPrettyAudioString(uint32_t indent = 0, std::string name = ""); + }; + + class MP4A: public AudioSampleEntry{ + public: + MP4A(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class AAC: public AudioSampleEntry{ + public: + AAC(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class AVC1: public VisualSampleEntry{ + public: + AVC1(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class H264: public VisualSampleEntry{ + public: + H264(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class STSD: public fullBox{ + public: + STSD(char v = 1, uint32_t f = 0); + void setEntryCount (uint32_t newEntryCount); + uint32_t getEntryCount(); + void setEntry(Box & newContent, uint32_t no); + Box & getEntry(uint32_t no); + std::string toPrettyString(uint32_t indent = 0); + }; + + class EDTS: public containerBox{ + public: + EDTS(); + }; + + class UDTA: public containerBox{ + public: + UDTA(); + }; + + class STSS: public fullBox{ + public: + STSS(char v = 1, uint32_t f = 0); + void setEntryCount(uint32_t newVal); + uint32_t getEntryCount(); + void setSampleNumber(uint32_t newVal, uint32_t index); + uint32_t getSampleNumber(uint32_t index); + std::string toPrettyString(uint32_t indent = 0); + }; + + class META: public containerFullBox{ + public: + META(); + std::string toPrettyString(uint32_t indent = 0); + }; + + class ELST: public fullBox{ + public: + ELST(); + void setSegmentDuration(uint64_t newVal); + uint64_t getSegmentDuration(); + void setMediaTime(uint64_t newVal); + uint64_t getMediaTime(); + void setMediaRateInteger(uint16_t newVal); + uint16_t getMediaRateInteger(); + void setMediaRateFraction(uint16_t newVal); + uint16_t getMediaRateFraction(); + std::string toPrettyString(uint32_t indent = 0); + }; +} diff --git a/lib/mp4_ms.cpp b/lib/mp4_ms.cpp new file mode 100644 index 00000000..f96c346e --- /dev/null +++ b/lib/mp4_ms.cpp @@ -0,0 +1,208 @@ +#include "mp4_ms.h" + +namespace MP4{ + + 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); + } + + void SDTP::setVersion(uint32_t newVersion){ + setInt8(newVersion, 0); + } + + uint32_t SDTP::getVersion(){ + return getInt8(0); + } + + void SDTP::setValue(uint32_t newValue, size_t index){ + setInt8(newValue, index); + } + + uint32_t SDTP::getValue(size_t index){ + return getInt8(index); + } + + 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){ + 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 & 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; + } + r << "(" << val << ")" << std::endl; + } + return r.str(); + } + + UUID::UUID(){ + memcpy(data + 4, "uuid", 4); + setInt64(0, 0); + setInt64(0, 8); + } + + 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 << "-"; + } + 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 + int i = 0; + 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); + } + + std::string UUID::toPrettyString(uint32_t indent){ + std::string UUID = getUUID(); + if (UUID == "d4807ef2-ca39-4695-8e54-26cb9e46a79f"){ + return ((UUID_TrackFragmentReference*)this)->toPrettyString(indent); + } + std::stringstream r; + r << std::string(indent, ' ') << "[uuid] Extension box (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "UUID: " << UUID << std::endl; + r << std::string(indent + 1, ' ') << "Unknown UUID - ignoring contents." << std::endl; + return r.str(); + } + + UUID_TrackFragmentReference::UUID_TrackFragmentReference(){ + setUUID((std::string)"d4807ef2-ca39-4695-8e54-26cb9e46a79f"); + } + + void UUID_TrackFragmentReference::setVersion(uint32_t newVersion){ + setInt8(newVersion, 16); + } + + uint32_t UUID_TrackFragmentReference::getVersion(){ + return getInt8(16); + } + + void UUID_TrackFragmentReference::setFlags(uint32_t newFlags){ + setInt24(newFlags, 17); + } + + uint32_t UUID_TrackFragmentReference::getFlags(){ + return getInt24(17); + } + + void UUID_TrackFragmentReference::setFragmentCount(uint32_t newCount){ + setInt8(newCount, 20); + } + + uint32_t UUID_TrackFragmentReference::getFragmentCount(){ + return getInt8(20); + } + + void UUID_TrackFragmentReference::setTime(size_t num, uint64_t newTime){ + if (getVersion() == 0){ + setInt32(newTime, 21+(num*8)); + }else{ + setInt64(newTime, 21+(num*16)); + } + } + + uint64_t UUID_TrackFragmentReference::getTime(size_t num){ + if (getVersion() == 0){ + return getInt32(21+(num*8)); + }else{ + return getInt64(21+(num*16)); + } + } + + void UUID_TrackFragmentReference::setDuration(size_t num, uint64_t newDuration){ + if (getVersion() == 0){ + setInt32(newDuration, 21+(num*8)+4); + }else{ + setInt64(newDuration, 21+(num*16)+8); + } + } + + uint64_t UUID_TrackFragmentReference::getDuration(size_t num){ + if (getVersion() == 0){ + return getInt32(21+(num*8)+4); + }else{ + return getInt64(21+(num*16)+8); + } + } + + 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 + 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; + } + return r.str(); + } +} diff --git a/lib/mp4_ms.h b/lib/mp4_ms.h new file mode 100644 index 00000000..d9c809ae --- /dev/null +++ b/lib/mp4_ms.h @@ -0,0 +1,40 @@ +#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); + }; + + 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); + }; + +}