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
This commit is contained in:
parent
df273e99b7
commit
88fa62c19c
9 changed files with 4997 additions and 5107 deletions
4075
lib/mp4.cpp
4075
lib/mp4.cpp
File diff suppressed because it is too large
Load diff
880
lib/mp4.h
880
lib/mp4.h
|
@ -28,27 +28,16 @@ namespace MP4 {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long long int trackID;
|
long unsigned int trackID;
|
||||||
long long int size;
|
long unsigned int size;
|
||||||
long long int time;
|
long long unsigned int time;
|
||||||
long long int len;
|
long long unsigned int endTime;
|
||||||
std::deque<DTSC::Part> parts;
|
long unsigned int index;
|
||||||
long long int partsize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DTSC2MP4Converter{
|
class DTSC2MP4Converter{
|
||||||
public:
|
public:
|
||||||
std::string DTSCMeta2MP4Header(DTSC::Meta & metaData);
|
std::string DTSCMeta2MP4Header(DTSC::Meta & metaData);
|
||||||
void parseDTSC(JSON::Value mediaPart);
|
|
||||||
bool sendReady();
|
|
||||||
std::string sendString();
|
|
||||||
std::string purgeBuffer();
|
|
||||||
std::set <keyPart> 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 <long long unsigned int, std::deque<JSON::Value> > trackBuffer;
|
|
||||||
std::string stringBuffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Box{
|
class Box{
|
||||||
|
@ -89,7 +78,7 @@ namespace MP4 {
|
||||||
bool reserve(size_t position, size_t current, size_t wanted);
|
bool reserve(size_t position, size_t current, size_t wanted);
|
||||||
//internal variables
|
//internal variables
|
||||||
char * data; ///< Holds the data of this box
|
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.
|
bool managed; ///< If false, will not attempt to resize/free the data pointer.
|
||||||
int payloadOffset; ///<The offset of the payload with regards to the data
|
int payloadOffset; ///<The offset of the payload with regards to the data
|
||||||
};
|
};
|
||||||
|
@ -112,7 +101,6 @@ namespace MP4 {
|
||||||
void setContent(Box & newContent, uint32_t no);
|
void setContent(Box & newContent, uint32_t no);
|
||||||
Box & getContent(uint32_t no);
|
Box & getContent(uint32_t no);
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
std::string toPrettyContainerString(uint32_t indent, std::string boxName);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class containerFullBox: public fullBox{
|
class containerFullBox: public fullBox{
|
||||||
|
@ -122,860 +110,4 @@ namespace MP4 {
|
||||||
Box & getContent(uint32_t no);
|
Box & getContent(uint32_t no);
|
||||||
std::string toPrettyCFBString(uint32_t indent, std::string boxName);
|
std::string toPrettyCFBString(uint32_t indent, std::string boxName);
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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 Box{
|
|
||||||
public:
|
|
||||||
MOOF();
|
|
||||||
uint32_t getContentCount();
|
|
||||||
void setContent(Box & newContent, uint32_t no);
|
|
||||||
Box & getContent(uint32_t no);
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};*/
|
|
||||||
|
|
||||||
class MOOF: public containerBox{
|
|
||||||
public:
|
|
||||||
MOOF();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
//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;
|
|
||||||
int32_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);
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
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 fromAnnexB(std::string annexBFormatted);
|
|
||||||
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();
|
|
||||||
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 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 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();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class MVEX: public containerBox{
|
|
||||||
public:
|
|
||||||
MVEX();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class TRAK: public containerBox{
|
|
||||||
public:
|
|
||||||
TRAK();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class MDIA: public containerBox{
|
|
||||||
public:
|
|
||||||
MDIA();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class MINF: public containerBox{
|
|
||||||
public:
|
|
||||||
MINF();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class DINF: public containerBox{
|
|
||||||
public:
|
|
||||||
DINF();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
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();
|
|
||||||
uint16_t toAACInit();
|
|
||||||
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();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class UDTA: public containerBox{
|
|
||||||
public:
|
|
||||||
UDTA();
|
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
928
lib/mp4_adobe.cpp
Normal file
928
lib/mp4_adobe.cpp
Normal file
|
@ -0,0 +1,928 @@
|
||||||
|
#include "mp4_adobe.h"
|
||||||
|
|
||||||
|
namespace MP4 {
|
||||||
|
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(uint64_t newTime){
|
||||||
|
setInt64(newTime, 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ABST::getCurrentMediaTime(){
|
||||||
|
return getInt64(13);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABST::setSmpteTimeCodeOffset(uint64_t newTime){
|
||||||
|
setInt64(newTime, 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t 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();
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
139
lib/mp4_adobe.h
Normal file
139
lib/mp4_adobe.h
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#pragma once
|
||||||
|
#include "mp4.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
280
lib/mp4_conv.cpp
280
lib/mp4_conv.cpp
|
@ -1,4 +1,4 @@
|
||||||
#include "mp4.h"
|
#include "mp4_generic.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace MP4{
|
namespace MP4{
|
||||||
|
@ -17,21 +17,22 @@ namespace MP4{
|
||||||
|
|
||||||
uint64_t mdatSize = 0;
|
uint64_t mdatSize = 0;
|
||||||
//moov box
|
//moov box
|
||||||
MP4::MOOV moovBox;
|
MP4::MOOV moovBox;{
|
||||||
|
//calculating longest duration
|
||||||
|
long long int fileDuration = 0;
|
||||||
|
/// \todo lastms and firstms fix
|
||||||
|
for ( std::map<int,DTSC::Track>::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;
|
MP4::MVHD mvhdBox;
|
||||||
mvhdBox.setVersion(0);
|
mvhdBox.setVersion(0);
|
||||||
mvhdBox.setCreationTime(0);
|
mvhdBox.setCreationTime(0);
|
||||||
mvhdBox.setModificationTime(0);
|
mvhdBox.setModificationTime(0);
|
||||||
mvhdBox.setTimeScale(1000);
|
mvhdBox.setTimeScale(1000);
|
||||||
mvhdBox.setRate(0x10000);
|
mvhdBox.setRate(0x10000);
|
||||||
//calculating longest duration
|
|
||||||
int fileDuration = 0;
|
|
||||||
///\ odo lastms and firstms fixen
|
|
||||||
for ( std::map<int,DTSC::Track>::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.setDuration(fileDuration);
|
||||||
mvhdBox.setTrackID(0);
|
mvhdBox.setTrackID(0);
|
||||||
mvhdBox.setVolume(256);
|
mvhdBox.setVolume(256);
|
||||||
|
@ -45,50 +46,11 @@ namespace MP4{
|
||||||
mvhdBox.setMatrix(0,7);
|
mvhdBox.setMatrix(0,7);
|
||||||
mvhdBox.setMatrix(0x40000000,8);
|
mvhdBox.setMatrix(0x40000000,8);
|
||||||
moovBox.setContent(mvhdBox, 0);
|
moovBox.setContent(mvhdBox, 0);
|
||||||
|
}
|
||||||
|
{//start arbitrary track addition for header
|
||||||
|
int boxOffset = 1;
|
||||||
bool seenAudio = false;
|
bool seenAudio = false;
|
||||||
bool seenVideo = 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<int,DTSC::Track>::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<DTSC::Part> (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<int,DTSC::Track>::iterator it = metaData.tracks.begin(); it != metaData.tracks.end(); it ++) {
|
for ( std::map<int,DTSC::Track>::iterator it = metaData.tracks.begin(); it != metaData.tracks.end(); it ++) {
|
||||||
if (it->second.codec != "AAC" && it->second.codec != "H264"){continue;}
|
if (it->second.codec != "AAC" && it->second.codec != "H264"){continue;}
|
||||||
if (it->second.type == "audio"){
|
if (it->second.type == "audio"){
|
||||||
|
@ -102,11 +64,13 @@ namespace MP4{
|
||||||
if (it->first > 0){
|
if (it->first > 0){
|
||||||
int timescale = 0;
|
int timescale = 0;
|
||||||
MP4::TRAK trakBox;
|
MP4::TRAK trakBox;
|
||||||
|
{
|
||||||
|
{
|
||||||
MP4::TKHD tkhdBox;
|
MP4::TKHD tkhdBox;
|
||||||
tkhdBox.setVersion(0);
|
tkhdBox.setVersion(0);
|
||||||
tkhdBox.setFlags(15);
|
tkhdBox.setFlags(15);
|
||||||
tkhdBox.setTrackID(it->second.trackID);
|
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);
|
tkhdBox.setDuration(it->second.lastms + it->second.firstms);
|
||||||
|
|
||||||
if (it->second.type == "video"){
|
if (it->second.type == "video"){
|
||||||
|
@ -127,41 +91,40 @@ namespace MP4{
|
||||||
tkhdBox.setMatrix(0,7);
|
tkhdBox.setMatrix(0,7);
|
||||||
tkhdBox.setMatrix(0x40000000,8);
|
tkhdBox.setMatrix(0x40000000,8);
|
||||||
trakBox.setContent(tkhdBox, 0);
|
trakBox.setContent(tkhdBox, 0);
|
||||||
|
}{
|
||||||
MP4::MDIA mdiaBox;
|
MP4::MDIA mdiaBox;
|
||||||
|
{
|
||||||
MP4::MDHD mdhdBox(0);/// \todo fix constructor mdhd in lib
|
MP4::MDHD mdhdBox(0);/// \todo fix constructor mdhd in lib
|
||||||
mdhdBox.setCreationTime(0);
|
mdhdBox.setCreationTime(0);
|
||||||
mdhdBox.setModificationTime(0);
|
mdhdBox.setModificationTime(0);
|
||||||
//Calculating media time based on sampledelta. Probably cheating, but it works...
|
//Calculating media time based on sampledelta. Probably cheating, but it works...
|
||||||
int tmpParts = 0;
|
timescale = ((double)(42 * it->second.parts.size() ) / (it->second.lastms + it->second.firstms)) * 1000;
|
||||||
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;
|
|
||||||
mdhdBox.setTimeScale(timescale);
|
mdhdBox.setTimeScale(timescale);
|
||||||
///\ odo fix lastms, firstms
|
/// \todo fix lastms, firstms
|
||||||
mdhdBox.setDuration((it->second.lastms + it->second.firstms) * ((double)timescale / 1000));
|
mdhdBox.setDuration((it->second.lastms + it->second.firstms) * ((double)timescale / 1000));
|
||||||
mdiaBox.setContent(mdhdBox, 0);
|
mdiaBox.setContent(mdhdBox, 0);
|
||||||
|
}//MDHD box
|
||||||
std::string tmpStr = it->second.type;
|
{
|
||||||
MP4::HDLR hdlrBox;/// \todo fix constructor hdlr in lib
|
MP4::HDLR hdlrBox;/// \todo fix constructor hdlr in lib
|
||||||
if (tmpStr == "video"){
|
if (it->second.type == "video"){
|
||||||
hdlrBox.setHandlerType(0x76696465);//vide
|
hdlrBox.setHandlerType(0x76696465);//vide
|
||||||
}else if (tmpStr == "audio"){
|
}else if (it->second.type == "audio"){
|
||||||
hdlrBox.setHandlerType(0x736F756E);//soun
|
hdlrBox.setHandlerType(0x736F756E);//soun
|
||||||
}
|
}
|
||||||
hdlrBox.setName(it->second.getIdentifier());
|
hdlrBox.setName(it->second.getIdentifier());
|
||||||
mdiaBox.setContent(hdlrBox, 1);
|
mdiaBox.setContent(hdlrBox, 1);
|
||||||
|
}//hdlr box
|
||||||
|
{
|
||||||
MP4::MINF minfBox;
|
MP4::MINF minfBox;
|
||||||
if (tmpStr == "video"){
|
if (it->second.type== "video"){
|
||||||
MP4::VMHD vmhdBox;
|
MP4::VMHD vmhdBox;
|
||||||
vmhdBox.setFlags(1);
|
vmhdBox.setFlags(1);
|
||||||
minfBox.setContent(vmhdBox,0);
|
minfBox.setContent(vmhdBox,0);
|
||||||
}else if (tmpStr == "audio"){
|
}else if (it->second.type == "audio"){
|
||||||
MP4::SMHD smhdBox;
|
MP4::SMHD smhdBox;
|
||||||
minfBox.setContent(smhdBox,0);
|
minfBox.setContent(smhdBox,0);
|
||||||
}
|
}//type box
|
||||||
|
{
|
||||||
MP4::DINF dinfBox;
|
MP4::DINF dinfBox;
|
||||||
MP4::DREF drefBox;/// \todo fix constructor dref in lib
|
MP4::DREF drefBox;/// \todo fix constructor dref in lib
|
||||||
drefBox.setVersion(0);
|
drefBox.setVersion(0);
|
||||||
|
@ -170,14 +133,15 @@ namespace MP4{
|
||||||
drefBox.setDataEntry(urlBox,0);
|
drefBox.setDataEntry(urlBox,0);
|
||||||
dinfBox.setContent(drefBox,0);
|
dinfBox.setContent(drefBox,0);
|
||||||
minfBox.setContent(dinfBox,1);
|
minfBox.setContent(dinfBox,1);
|
||||||
|
}//dinf box
|
||||||
|
{
|
||||||
MP4::STBL stblBox;
|
MP4::STBL stblBox;
|
||||||
|
{
|
||||||
MP4::STSD stsdBox;
|
MP4::STSD stsdBox;
|
||||||
stsdBox.setVersion(0);
|
stsdBox.setVersion(0);
|
||||||
if (tmpStr == "video"){//boxname = codec
|
if (it->second.type == "video"){//boxname = codec
|
||||||
MP4::VisualSampleEntry vse;
|
MP4::VisualSampleEntry vse;
|
||||||
std::string tmpStr2 = it->second.codec;
|
if (it->second.codec == "H264"){
|
||||||
if (tmpStr2 == "H264"){
|
|
||||||
vse.setCodec("avc1");
|
vse.setCodec("avc1");
|
||||||
}
|
}
|
||||||
vse.setDataReferenceIndex(1);
|
vse.setDataReferenceIndex(1);
|
||||||
|
@ -187,21 +151,26 @@ namespace MP4{
|
||||||
avccBox.setPayload(it->second.init);
|
avccBox.setPayload(it->second.init);
|
||||||
vse.setCLAP(avccBox);
|
vse.setCLAP(avccBox);
|
||||||
stsdBox.setEntry(vse,0);
|
stsdBox.setEntry(vse,0);
|
||||||
}else if(tmpStr == "audio"){//boxname = codec
|
}else if(it->second.type == "audio"){//boxname = codec
|
||||||
MP4::AudioSampleEntry ase;
|
MP4::AudioSampleEntry ase;
|
||||||
std::string tmpStr2 = it->second.codec;
|
if (it->second.codec == "AAC"){
|
||||||
if (tmpStr2 == "AAC"){
|
|
||||||
ase.setCodec("mp4a");
|
ase.setCodec("mp4a");
|
||||||
ase.setDataReferenceIndex(1);
|
ase.setDataReferenceIndex(1);
|
||||||
}
|
}
|
||||||
ase.setSampleRate(it->second.rate);
|
ase.setSampleRate(it->second.rate);
|
||||||
ase.setChannelCount(it->second.channels);
|
ase.setChannelCount(it->second.channels);
|
||||||
ase.setSampleSize(it->second.size);
|
ase.setSampleSize(it->second.size);
|
||||||
|
//MP4::ESDS esdsBox(it->second.init, it->second.bps);
|
||||||
MP4::ESDS esdsBox;
|
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.setESDescriptorTypeLength(32+it->second.init.size());
|
||||||
esdsBox.setESID(2);
|
esdsBox.setESID(2);
|
||||||
esdsBox.setStreamPriority(0);
|
esdsBox.setStreamPriority(0);
|
||||||
esdsBox.setDecoderConfigDescriptorTypeLength(18+it->second.init.size());
|
esdsBox.setDecoderConfigDescriptorTypeLength(18 + it->second.init.size());
|
||||||
esdsBox.setByteObjectTypeID(0x40);
|
esdsBox.setByteObjectTypeID(0x40);
|
||||||
esdsBox.setStreamType(5);
|
esdsBox.setStreamType(5);
|
||||||
esdsBox.setReservedFlag(1);
|
esdsBox.setReservedFlag(1);
|
||||||
|
@ -209,26 +178,25 @@ namespace MP4{
|
||||||
esdsBox.setMaximumBitRate(10000000);
|
esdsBox.setMaximumBitRate(10000000);
|
||||||
esdsBox.setAverageBitRate(it->second.bps * 8);
|
esdsBox.setAverageBitRate(it->second.bps * 8);
|
||||||
esdsBox.setConfigDescriptorTypeLength(5);
|
esdsBox.setConfigDescriptorTypeLength(5);
|
||||||
esdsBox.setESHeaderStartCodes(it->second.init);
|
|
||||||
esdsBox.setSLConfigDescriptorTypeTag(0x6);
|
esdsBox.setSLConfigDescriptorTypeTag(0x6);
|
||||||
esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080);
|
esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080);
|
||||||
esdsBox.setSLDescriptorTypeLength(1);
|
esdsBox.setSLDescriptorTypeLength(1);
|
||||||
esdsBox.setSLValue(2);
|
|
||||||
ase.setCodecBox(esdsBox);
|
ase.setCodecBox(esdsBox);
|
||||||
stsdBox.setEntry(ase,0);
|
stsdBox.setEntry(ase,0);
|
||||||
}
|
}
|
||||||
stblBox.setContent(stsdBox,0);
|
stblBox.setContent(stsdBox,0);
|
||||||
|
}//stsd box
|
||||||
/// \ odo update following stts lines
|
/// \todo update following stts lines
|
||||||
|
{
|
||||||
MP4::STTS sttsBox;//current version probably causes problems
|
MP4::STTS sttsBox;//current version probably causes problems
|
||||||
sttsBox.setVersion(0);
|
sttsBox.setVersion(0);
|
||||||
MP4::STTSEntry newEntry;
|
MP4::STTSEntry newEntry;
|
||||||
newEntry.sampleCount = tmpParts;
|
newEntry.sampleCount = it->second.parts.size();
|
||||||
//42, Used as magic number for timescale calculation
|
//42, Used as magic number for timescale calculation
|
||||||
newEntry.sampleDelta = 42;
|
newEntry.sampleDelta = 42;
|
||||||
sttsBox.setSTTSEntry(newEntry, 0);
|
sttsBox.setSTTSEntry(newEntry, 0);
|
||||||
stblBox.setContent(sttsBox,1);
|
stblBox.setContent(sttsBox,1);
|
||||||
|
}//stts box
|
||||||
if (it->second.type == "video"){
|
if (it->second.type == "video"){
|
||||||
//STSS Box here
|
//STSS Box here
|
||||||
MP4::STSS stssBox;
|
MP4::STSS stssBox;
|
||||||
|
@ -241,21 +209,21 @@ namespace MP4{
|
||||||
tmpItCount ++;
|
tmpItCount ++;
|
||||||
}
|
}
|
||||||
stblBox.setContent(stssBox,2);
|
stblBox.setContent(stssBox,2);
|
||||||
}
|
}//stss box
|
||||||
|
|
||||||
int offset = (it->second.type == "video");
|
int offset = (it->second.type == "video");
|
||||||
|
{
|
||||||
|
|
||||||
MP4::STSC stscBox;
|
MP4::STSC stscBox;
|
||||||
stscBox.setVersion(0);
|
stscBox.setVersion(0);
|
||||||
uint32_t total = 0;
|
|
||||||
MP4::STSCEntry stscEntry;
|
MP4::STSCEntry stscEntry;
|
||||||
stscEntry.firstChunk = 1;
|
stscEntry.firstChunk = 1;
|
||||||
stscEntry.samplesPerChunk = 1;
|
stscEntry.samplesPerChunk = 1;
|
||||||
stscEntry.sampleDescriptionIndex = 1;
|
stscEntry.sampleDescriptionIndex = 1;
|
||||||
stscBox.setSTSCEntry(stscEntry, 0);
|
stscBox.setSTSCEntry(stscEntry, 0);
|
||||||
stblBox.setContent(stscBox,2 + offset);
|
stblBox.setContent(stscBox,2 + offset);
|
||||||
|
}//stsc box
|
||||||
|
{
|
||||||
|
uint32_t total = 0;
|
||||||
MP4::STSZ stszBox;
|
MP4::STSZ stszBox;
|
||||||
stszBox.setVersion(0);
|
stszBox.setVersion(0);
|
||||||
total = 0;
|
total = 0;
|
||||||
|
@ -264,49 +232,41 @@ namespace MP4{
|
||||||
total++;
|
total++;
|
||||||
}
|
}
|
||||||
stblBox.setContent(stszBox,3 + offset);
|
stblBox.setContent(stszBox,3 + offset);
|
||||||
|
}//stsz box
|
||||||
|
//add STCO boxes here
|
||||||
|
{
|
||||||
MP4::STCO stcoBox;
|
MP4::STCO stcoBox;
|
||||||
stcoBox.setVersion(1);
|
stcoBox.setVersion(1);
|
||||||
total = 0;
|
//Inserting empty values on purpose here, will be fixed later.
|
||||||
long long unsigned int totalByteOffset = 0;
|
if (it->second.parts.size() != 0){
|
||||||
//Inserting wrong values on purpose here, will be fixed later.
|
stcoBox.setChunkOffset(0, it->second.parts.size() - 1);//this inserts all empty entries at once
|
||||||
//Current values are actual byte offset without header-sized offset
|
|
||||||
for (std::set<keyPart>::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<DTSC::Part> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//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);
|
stblBox.setContent(stcoBox,4 + offset);
|
||||||
|
}//stco box
|
||||||
minfBox.setContent(stblBox,2);
|
minfBox.setContent(stblBox,2);
|
||||||
|
}//stbl box
|
||||||
mdiaBox.setContent(minfBox, 2);
|
mdiaBox.setContent(minfBox, 2);
|
||||||
|
}//minf box
|
||||||
trakBox.setContent(mdiaBox, 1);
|
trakBox.setContent(mdiaBox, 1);
|
||||||
|
}
|
||||||
|
}//trak Box
|
||||||
moovBox.setContent(trakBox, boxOffset);
|
moovBox.setContent(trakBox, boxOffset);
|
||||||
boxOffset++;
|
boxOffset++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//end arbitrary
|
}//end arbitrary track addition
|
||||||
//initial offset length ftyp, length moov + 8
|
//initial offset length ftyp, length moov + 8
|
||||||
unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
||||||
//update all STCO
|
//update all STCO from the following map;
|
||||||
//for tracks
|
std::map <int, MP4::STCO> checkStcoBoxes;
|
||||||
|
//for all tracks
|
||||||
for (unsigned int i = 1; i < moovBox.getContentCount(); i++){
|
for (unsigned int i = 1; i < moovBox.getContentCount(); i++){
|
||||||
//10 lines to get the STCO box.
|
//10 lines to get the STCO box.
|
||||||
MP4::TRAK checkTrakBox;
|
MP4::TRAK checkTrakBox;
|
||||||
MP4::MDIA checkMdiaBox;
|
MP4::MDIA checkMdiaBox;
|
||||||
MP4::MINF checkMinfBox;
|
MP4::MINF checkMinfBox;
|
||||||
MP4::STBL checkStblBox;
|
MP4::STBL checkStblBox;
|
||||||
MP4::STCO checkStcoBox;
|
//MP4::STCO checkStcoBox;
|
||||||
checkTrakBox = ((MP4::TRAK&)moovBox.getContent(i));
|
checkTrakBox = ((MP4::TRAK&)moovBox.getContent(i));
|
||||||
for (unsigned int j = 0; j < checkTrakBox.getContentCount(); j++){
|
for (unsigned int j = 0; j < checkTrakBox.getContentCount(); j++){
|
||||||
if (checkTrakBox.getContent(j).isType("mdia")){
|
if (checkTrakBox.getContent(j).isType("mdia")){
|
||||||
|
@ -328,15 +288,46 @@ namespace MP4{
|
||||||
}
|
}
|
||||||
for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){
|
for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){
|
||||||
if (checkStblBox.getContent(j).isType("stco")){
|
if (checkStblBox.getContent(j).isType("stco")){
|
||||||
checkStcoBox = ((MP4::STCO&)checkStblBox.getContent(j));
|
checkStcoBoxes.insert( std::pair<int, MP4::STCO>(i, ((MP4::STCO&)checkStblBox.getContent(j)) ));
|
||||||
break;
|
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 <keyPart> sortSet;//filling sortset for interleaving parts
|
||||||
|
for ( std::map<int,DTSC::Track>::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 << std::string(moovBox.asBox(),moovBox.boxedSize());
|
||||||
|
|
||||||
header << (char)((mdatSize>>24) & 0x000000FF) << (char)((mdatSize>>16) & 0x000000FF) << (char)((mdatSize>>8) & 0x000000FF) << (char)(mdatSize & 0x000000FF) << "mdat";
|
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();
|
return header.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTSC2MP4Converter::parseDTSC(JSON::Value mediaPart){
|
|
||||||
static std::set<keyPart>::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 <long long unsigned int, std::deque<JSON::Value> >::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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2878
lib/mp4_generic.cpp
Normal file
2878
lib/mp4_generic.cpp
Normal file
File diff suppressed because it is too large
Load diff
674
lib/mp4_generic.h
Normal file
674
lib/mp4_generic.h
Normal file
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
208
lib/mp4_ms.cpp
Normal file
208
lib/mp4_ms.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
40
lib/mp4_ms.h
Normal file
40
lib/mp4_ms.h
Normal file
|
@ -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);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue