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:
Oswald Auguste de Bruin 2013-12-09 15:43:24 +01:00 committed by Thulinma
parent df273e99b7
commit 88fa62c19c
9 changed files with 4997 additions and 5107 deletions

File diff suppressed because it is too large Load diff

880
lib/mp4.h
View file

@ -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
View 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
View 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);
};
}

View file

@ -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,21 +151,26 @@ namespace MP4{
avccBox.setPayload(it->second.init);
vse.setCLAP(avccBox);
stsdBox.setEntry(vse,0);
}else if(tmpStr == "audio"){//boxname = codec
}else if(it->second.type == "audio"){//boxname = codec
MP4::AudioSampleEntry ase;
std::string tmpStr2 = it->second.codec;
if (tmpStr2 == "AAC"){
if (it->second.codec == "AAC"){
ase.setCodec("mp4a");
ase.setDataReferenceIndex(1);
}
ase.setSampleRate(it->second.rate);
ase.setChannelCount(it->second.channels);
ase.setSampleSize(it->second.size);
//MP4::ESDS esdsBox(it->second.init, it->second.bps);
MP4::ESDS esdsBox;
//outputting these values first, so malloc isn't called as often.
esdsBox.setESHeaderStartCodes(it->second.init);
esdsBox.setSLValue(2);
esdsBox.setESDescriptorTypeLength(32+it->second.init.size());
esdsBox.setESID(2);
esdsBox.setStreamPriority(0);
esdsBox.setDecoderConfigDescriptorTypeLength(18+it->second.init.size());
esdsBox.setDecoderConfigDescriptorTypeLength(18 + it->second.init.size());
esdsBox.setByteObjectTypeID(0x40);
esdsBox.setStreamType(5);
esdsBox.setReservedFlag(1);
@ -209,26 +178,25 @@ namespace MP4{
esdsBox.setMaximumBitRate(10000000);
esdsBox.setAverageBitRate(it->second.bps * 8);
esdsBox.setConfigDescriptorTypeLength(5);
esdsBox.setESHeaderStartCodes(it->second.init);
esdsBox.setSLConfigDescriptorTypeTag(0x6);
esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080);
esdsBox.setSLDescriptorTypeLength(1);
esdsBox.setSLValue(2);
ase.setCodecBox(esdsBox);
stsdBox.setEntry(ase,0);
}
stblBox.setContent(stsdBox,0);
/// \ odo update following stts lines
}//stsd box
/// \todo update following stts lines
{
MP4::STTS sttsBox;//current version probably causes problems
sttsBox.setVersion(0);
MP4::STTSEntry newEntry;
newEntry.sampleCount = tmpParts;
newEntry.sampleCount = it->second.parts.size();
//42, Used as magic number for timescale calculation
newEntry.sampleDelta = 42;
sttsBox.setSTTSEntry(newEntry, 0);
stblBox.setContent(sttsBox,1);
}//stts box
if (it->second.type == "video"){
//STSS Box here
MP4::STSS stssBox;
@ -241,21 +209,21 @@ namespace MP4{
tmpItCount ++;
}
stblBox.setContent(stssBox,2);
}
}//stss box
int offset = (it->second.type == "video");
{
MP4::STSC stscBox;
stscBox.setVersion(0);
uint32_t total = 0;
MP4::STSCEntry stscEntry;
stscEntry.firstChunk = 1;
stscEntry.samplesPerChunk = 1;
stscEntry.sampleDescriptionIndex = 1;
stscBox.setSTSCEntry(stscEntry, 0);
stblBox.setContent(stscBox,2 + offset);
}//stsc box
{
uint32_t total = 0;
MP4::STSZ stszBox;
stszBox.setVersion(0);
total = 0;
@ -264,49 +232,41 @@ namespace MP4{
total++;
}
stblBox.setContent(stszBox,3 + offset);
}//stsz box
//add STCO boxes here
{
MP4::STCO stcoBox;
stcoBox.setVersion(1);
total = 0;
long long unsigned int totalByteOffset = 0;
//Inserting wrong values on purpose here, will be fixed later.
//Current values are actual byte offset without header-sized offset
for (std::set<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

File diff suppressed because it is too large Load diff

674
lib/mp4_generic.h Normal file
View 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
View 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
View 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);
};
}