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;
|
||||
}
|
||||
long long int trackID;
|
||||
long long int size;
|
||||
long long int time;
|
||||
long long int len;
|
||||
std::deque<DTSC::Part> parts;
|
||||
long long int partsize;
|
||||
long unsigned int trackID;
|
||||
long unsigned int size;
|
||||
long long unsigned int time;
|
||||
long long unsigned int endTime;
|
||||
long unsigned int index;
|
||||
};
|
||||
|
||||
class DTSC2MP4Converter{
|
||||
public:
|
||||
std::string DTSCMeta2MP4Header(DTSC::Meta & metaData);
|
||||
void parseDTSC(JSON::Value mediaPart);
|
||||
bool sendReady();
|
||||
std::string sendString();
|
||||
std::string purgeBuffer();
|
||||
std::set <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{
|
||||
|
@ -89,7 +78,7 @@ namespace MP4 {
|
|||
bool reserve(size_t position, size_t current, size_t wanted);
|
||||
//internal variables
|
||||
char * data; ///< Holds the data of this box
|
||||
int data_size; ///< Currently reserved size
|
||||
unsigned int data_size; ///< Currently reserved size
|
||||
bool managed; ///< If false, will not attempt to resize/free the data pointer.
|
||||
int payloadOffset; ///<The offset of the payload with regards to the data
|
||||
};
|
||||
|
@ -112,7 +101,6 @@ namespace MP4 {
|
|||
void setContent(Box & newContent, uint32_t no);
|
||||
Box & getContent(uint32_t no);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
std::string toPrettyContainerString(uint32_t indent, std::string boxName);
|
||||
};
|
||||
|
||||
class containerFullBox: public fullBox{
|
||||
|
@ -122,860 +110,4 @@ namespace MP4 {
|
|||
Box & getContent(uint32_t no);
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
|
278
lib/mp4_conv.cpp
278
lib/mp4_conv.cpp
|
@ -1,4 +1,4 @@
|
|||
#include "mp4.h"
|
||||
#include "mp4_generic.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace MP4{
|
||||
|
@ -17,21 +17,22 @@ namespace MP4{
|
|||
|
||||
uint64_t mdatSize = 0;
|
||||
//moov box
|
||||
MP4::MOOV moovBox;
|
||||
MP4::MOOV moovBox;{
|
||||
//calculating longest duration
|
||||
long long int fileDuration = 0;
|
||||
/// \todo lastms and firstms fix
|
||||
for ( std::map<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;
|
||||
mvhdBox.setVersion(0);
|
||||
mvhdBox.setCreationTime(0);
|
||||
mvhdBox.setModificationTime(0);
|
||||
mvhdBox.setTimeScale(1000);
|
||||
mvhdBox.setRate(0x10000);
|
||||
//calculating longest duration
|
||||
int fileDuration = 0;
|
||||
///\ odo lastms and firstms fixen
|
||||
for ( std::map<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.setTrackID(0);
|
||||
mvhdBox.setVolume(256);
|
||||
|
@ -45,50 +46,11 @@ namespace MP4{
|
|||
mvhdBox.setMatrix(0,7);
|
||||
mvhdBox.setMatrix(0x40000000,8);
|
||||
moovBox.setContent(mvhdBox, 0);
|
||||
|
||||
}
|
||||
{//start arbitrary track addition for header
|
||||
int boxOffset = 1;
|
||||
bool seenAudio = false;
|
||||
bool seenVideo = false;
|
||||
|
||||
//calculate interleaving
|
||||
//putting all metadata in a huge, auto-sorting vector 'keyParts'
|
||||
//sort by time on keyframes for interleaving
|
||||
keyParts.clear();
|
||||
for ( std::map<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 ++) {
|
||||
if (it->second.codec != "AAC" && it->second.codec != "H264"){continue;}
|
||||
if (it->second.type == "audio"){
|
||||
|
@ -102,11 +64,13 @@ namespace MP4{
|
|||
if (it->first > 0){
|
||||
int timescale = 0;
|
||||
MP4::TRAK trakBox;
|
||||
{
|
||||
{
|
||||
MP4::TKHD tkhdBox;
|
||||
tkhdBox.setVersion(0);
|
||||
tkhdBox.setFlags(15);
|
||||
tkhdBox.setTrackID(it->second.trackID);
|
||||
///\ odo duration firstms and lastms fix
|
||||
/// \todo duration firstms and lastms fix
|
||||
tkhdBox.setDuration(it->second.lastms + it->second.firstms);
|
||||
|
||||
if (it->second.type == "video"){
|
||||
|
@ -127,41 +91,40 @@ namespace MP4{
|
|||
tkhdBox.setMatrix(0,7);
|
||||
tkhdBox.setMatrix(0x40000000,8);
|
||||
trakBox.setContent(tkhdBox, 0);
|
||||
|
||||
}{
|
||||
MP4::MDIA mdiaBox;
|
||||
{
|
||||
MP4::MDHD mdhdBox(0);/// \todo fix constructor mdhd in lib
|
||||
mdhdBox.setCreationTime(0);
|
||||
mdhdBox.setModificationTime(0);
|
||||
//Calculating media time based on sampledelta. Probably cheating, but it works...
|
||||
int tmpParts = 0;
|
||||
for (std::deque< DTSC::Key>::iterator tmpIt = it->second.keys.begin(); tmpIt != it->second.keys.end(); tmpIt ++) {
|
||||
tmpParts += tmpIt->getParts();
|
||||
}
|
||||
timescale = ((double)(42 * tmpParts) / (it->second.lastms + it->second.firstms)) * 1000;
|
||||
timescale = ((double)(42 * it->second.parts.size() ) / (it->second.lastms + it->second.firstms)) * 1000;
|
||||
mdhdBox.setTimeScale(timescale);
|
||||
///\ odo fix lastms, firstms
|
||||
/// \todo fix lastms, firstms
|
||||
mdhdBox.setDuration((it->second.lastms + it->second.firstms) * ((double)timescale / 1000));
|
||||
mdiaBox.setContent(mdhdBox, 0);
|
||||
|
||||
std::string tmpStr = it->second.type;
|
||||
}//MDHD box
|
||||
{
|
||||
MP4::HDLR hdlrBox;/// \todo fix constructor hdlr in lib
|
||||
if (tmpStr == "video"){
|
||||
if (it->second.type == "video"){
|
||||
hdlrBox.setHandlerType(0x76696465);//vide
|
||||
}else if (tmpStr == "audio"){
|
||||
}else if (it->second.type == "audio"){
|
||||
hdlrBox.setHandlerType(0x736F756E);//soun
|
||||
}
|
||||
hdlrBox.setName(it->second.getIdentifier());
|
||||
mdiaBox.setContent(hdlrBox, 1);
|
||||
|
||||
}//hdlr box
|
||||
{
|
||||
MP4::MINF minfBox;
|
||||
if (tmpStr == "video"){
|
||||
if (it->second.type== "video"){
|
||||
MP4::VMHD vmhdBox;
|
||||
vmhdBox.setFlags(1);
|
||||
minfBox.setContent(vmhdBox,0);
|
||||
}else if (tmpStr == "audio"){
|
||||
}else if (it->second.type == "audio"){
|
||||
MP4::SMHD smhdBox;
|
||||
minfBox.setContent(smhdBox,0);
|
||||
}
|
||||
}//type box
|
||||
{
|
||||
MP4::DINF dinfBox;
|
||||
MP4::DREF drefBox;/// \todo fix constructor dref in lib
|
||||
drefBox.setVersion(0);
|
||||
|
@ -170,14 +133,15 @@ namespace MP4{
|
|||
drefBox.setDataEntry(urlBox,0);
|
||||
dinfBox.setContent(drefBox,0);
|
||||
minfBox.setContent(dinfBox,1);
|
||||
|
||||
}//dinf box
|
||||
{
|
||||
MP4::STBL stblBox;
|
||||
{
|
||||
MP4::STSD stsdBox;
|
||||
stsdBox.setVersion(0);
|
||||
if (tmpStr == "video"){//boxname = codec
|
||||
if (it->second.type == "video"){//boxname = codec
|
||||
MP4::VisualSampleEntry vse;
|
||||
std::string tmpStr2 = it->second.codec;
|
||||
if (tmpStr2 == "H264"){
|
||||
if (it->second.codec == "H264"){
|
||||
vse.setCodec("avc1");
|
||||
}
|
||||
vse.setDataReferenceIndex(1);
|
||||
|
@ -187,17 +151,22 @@ namespace MP4{
|
|||
avccBox.setPayload(it->second.init);
|
||||
vse.setCLAP(avccBox);
|
||||
stsdBox.setEntry(vse,0);
|
||||
}else if(tmpStr == "audio"){//boxname = codec
|
||||
}else if(it->second.type == "audio"){//boxname = codec
|
||||
MP4::AudioSampleEntry ase;
|
||||
std::string tmpStr2 = it->second.codec;
|
||||
if (tmpStr2 == "AAC"){
|
||||
if (it->second.codec == "AAC"){
|
||||
ase.setCodec("mp4a");
|
||||
ase.setDataReferenceIndex(1);
|
||||
}
|
||||
ase.setSampleRate(it->second.rate);
|
||||
ase.setChannelCount(it->second.channels);
|
||||
ase.setSampleSize(it->second.size);
|
||||
//MP4::ESDS esdsBox(it->second.init, it->second.bps);
|
||||
MP4::ESDS esdsBox;
|
||||
|
||||
//outputting these values first, so malloc isn't called as often.
|
||||
esdsBox.setESHeaderStartCodes(it->second.init);
|
||||
esdsBox.setSLValue(2);
|
||||
|
||||
esdsBox.setESDescriptorTypeLength(32+it->second.init.size());
|
||||
esdsBox.setESID(2);
|
||||
esdsBox.setStreamPriority(0);
|
||||
|
@ -209,26 +178,25 @@ namespace MP4{
|
|||
esdsBox.setMaximumBitRate(10000000);
|
||||
esdsBox.setAverageBitRate(it->second.bps * 8);
|
||||
esdsBox.setConfigDescriptorTypeLength(5);
|
||||
esdsBox.setESHeaderStartCodes(it->second.init);
|
||||
esdsBox.setSLConfigDescriptorTypeTag(0x6);
|
||||
esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080);
|
||||
esdsBox.setSLDescriptorTypeLength(1);
|
||||
esdsBox.setSLValue(2);
|
||||
ase.setCodecBox(esdsBox);
|
||||
stsdBox.setEntry(ase,0);
|
||||
}
|
||||
stblBox.setContent(stsdBox,0);
|
||||
|
||||
/// \ odo update following stts lines
|
||||
}//stsd box
|
||||
/// \todo update following stts lines
|
||||
{
|
||||
MP4::STTS sttsBox;//current version probably causes problems
|
||||
sttsBox.setVersion(0);
|
||||
MP4::STTSEntry newEntry;
|
||||
newEntry.sampleCount = tmpParts;
|
||||
newEntry.sampleCount = it->second.parts.size();
|
||||
//42, Used as magic number for timescale calculation
|
||||
newEntry.sampleDelta = 42;
|
||||
sttsBox.setSTTSEntry(newEntry, 0);
|
||||
stblBox.setContent(sttsBox,1);
|
||||
|
||||
}//stts box
|
||||
if (it->second.type == "video"){
|
||||
//STSS Box here
|
||||
MP4::STSS stssBox;
|
||||
|
@ -241,21 +209,21 @@ namespace MP4{
|
|||
tmpItCount ++;
|
||||
}
|
||||
stblBox.setContent(stssBox,2);
|
||||
}
|
||||
}//stss box
|
||||
|
||||
int offset = (it->second.type == "video");
|
||||
|
||||
|
||||
{
|
||||
MP4::STSC stscBox;
|
||||
stscBox.setVersion(0);
|
||||
uint32_t total = 0;
|
||||
MP4::STSCEntry stscEntry;
|
||||
stscEntry.firstChunk = 1;
|
||||
stscEntry.samplesPerChunk = 1;
|
||||
stscEntry.sampleDescriptionIndex = 1;
|
||||
stscBox.setSTSCEntry(stscEntry, 0);
|
||||
stblBox.setContent(stscBox,2 + offset);
|
||||
|
||||
}//stsc box
|
||||
{
|
||||
uint32_t total = 0;
|
||||
MP4::STSZ stszBox;
|
||||
stszBox.setVersion(0);
|
||||
total = 0;
|
||||
|
@ -264,49 +232,41 @@ namespace MP4{
|
|||
total++;
|
||||
}
|
||||
stblBox.setContent(stszBox,3 + offset);
|
||||
|
||||
}//stsz box
|
||||
//add STCO boxes here
|
||||
{
|
||||
MP4::STCO stcoBox;
|
||||
stcoBox.setVersion(1);
|
||||
total = 0;
|
||||
long long unsigned int totalByteOffset = 0;
|
||||
//Inserting wrong values on purpose here, will be fixed later.
|
||||
//Current values are actual byte offset without header-sized offset
|
||||
for (std::set<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();
|
||||
//Inserting empty values on purpose here, will be fixed later.
|
||||
if (it->second.parts.size() != 0){
|
||||
stcoBox.setChunkOffset(0, it->second.parts.size() - 1);//this inserts all empty entries at once
|
||||
}
|
||||
}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);
|
||||
}//stco box
|
||||
minfBox.setContent(stblBox,2);
|
||||
}//stbl box
|
||||
mdiaBox.setContent(minfBox, 2);
|
||||
}//minf box
|
||||
trakBox.setContent(mdiaBox, 1);
|
||||
}
|
||||
}//trak Box
|
||||
moovBox.setContent(trakBox, boxOffset);
|
||||
boxOffset++;
|
||||
}
|
||||
}
|
||||
//end arbitrary
|
||||
}//end arbitrary track addition
|
||||
//initial offset length ftyp, length moov + 8
|
||||
unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
||||
//update all STCO
|
||||
//for tracks
|
||||
//update all STCO from the following map;
|
||||
std::map <int, MP4::STCO> checkStcoBoxes;
|
||||
//for all tracks
|
||||
for (unsigned int i = 1; i < moovBox.getContentCount(); i++){
|
||||
//10 lines to get the STCO box.
|
||||
MP4::TRAK checkTrakBox;
|
||||
MP4::MDIA checkMdiaBox;
|
||||
MP4::MINF checkMinfBox;
|
||||
MP4::STBL checkStblBox;
|
||||
MP4::STCO checkStcoBox;
|
||||
//MP4::STCO checkStcoBox;
|
||||
checkTrakBox = ((MP4::TRAK&)moovBox.getContent(i));
|
||||
for (unsigned int j = 0; j < checkTrakBox.getContentCount(); j++){
|
||||
if (checkTrakBox.getContent(j).isType("mdia")){
|
||||
|
@ -328,15 +288,46 @@ namespace MP4{
|
|||
}
|
||||
for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){
|
||||
if (checkStblBox.getContent(j).isType("stco")){
|
||||
checkStcoBox = ((MP4::STCO&)checkStblBox.getContent(j));
|
||||
checkStcoBoxes.insert( std::pair<int, MP4::STCO>(i, ((MP4::STCO&)checkStblBox.getContent(j)) ));
|
||||
break;
|
||||
}
|
||||
}
|
||||
//got the STCO box, fixing values with MP4 header offset
|
||||
for (unsigned int j = 0; j < checkStcoBox.getEntryCount(); j++){
|
||||
checkStcoBox.setChunkOffset(checkStcoBox.getChunkOffset(j) + byteOffset, j);
|
||||
}
|
||||
//inserting right values in the STCO box header
|
||||
//total = 0;
|
||||
long long unsigned int totalByteOffset = 0;
|
||||
//Current values are actual byte offset without header-sized offset
|
||||
std::set <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 << (char)((mdatSize>>24) & 0x000000FF) << (char)((mdatSize>>16) & 0x000000FF) << (char)((mdatSize>>8) & 0x000000FF) << (char)(mdatSize & 0x000000FF) << "mdat";
|
||||
|
@ -345,64 +336,5 @@ namespace MP4{
|
|||
return header.str();
|
||||
}
|
||||
|
||||
void DTSC2MP4Converter::parseDTSC(JSON::Value mediaPart){
|
||||
static std::set<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