diff --git a/lib/mp4.cpp b/lib/mp4.cpp index 5ebb70d7..a6f48de1 100644 --- a/lib/mp4.cpp +++ b/lib/mp4.cpp @@ -217,6 +217,12 @@ namespace MP4 { case 0x6D766864: return ((MVHD*)this)->toPrettyString(indent); break; + case 0x74667261: + return ((TFRA*)this)->toPrettyString(indent); + break; + case 0x746B6864: + return ((TKHD*)this)->toPrettyString(indent); + break; case 0x75756964: return ((UUID*)this)->toPrettyString(indent); break; @@ -2717,7 +2723,7 @@ namespace MP4 { } MVHD::MVHD(){ - memcpy(data + 4, "dref", 4); + memcpy(data + 4, "mvhd", 4); } void MVHD::setCreationTime(uint64_t newCreationTime){ @@ -2878,7 +2884,409 @@ namespace MP4 { r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; return r.str(); } - + + TFRA::TFRA(){ + memcpy(data + 4, "dref", 4); + } + + //note, fullbox starts at byte 4 + void TFRA::setTrackID(uint32_t newTrackID){ + setInt32(newTrackID, 4); + } + + uint32_t TFRA::getTrackID(){ + getInt32(4); + } + + void TFRA::setLengthSizeOfTrafNum(char newVal){ + char part = getInt8(11); + setInt8(((newVal & 0x03)<<4) + (part & 0xCF),11); + } + + char TFRA::getLengthSizeOfTrafNum(){ + return (getInt8(11)>>4) & 0x03; + } + + void TFRA::setLengthSizeOfTrunNum(char newVal){ + char part = getInt8(11); + setInt8(((newVal & 0x03)<<2) + (part & 0xF3),11); + } + + char TFRA::getLengthSizeOfTrunNum(){ + return (getInt8(11)>>2) & 0x03; + } + + void TFRA::setLengthSizeOfSampleNum(char newVal){ + char part = getInt8(11); + setInt8(((newVal & 0x03)) + (part & 0xFC),11); + } + + char TFRA::getLengthSizeOfSampleNum(){ + return (getInt8(11)) & 0x03; + } + + void TFRA::setNumberOfEntry(uint32_t newNumberOfEntry){ + setInt32(newNumberOfEntry,12); + } + + uint32_t TFRA::getNumberOfEntry(){ + return getInt32(12); + } + + uint32_t TFRA::getTFRAEntrySize(){ + int EntrySize= (getVersion()==1 ? 16 : 8); + EntrySize += getLengthSizeOfTrafNum()+1; + EntrySize += getLengthSizeOfTrunNum()+1; + EntrySize += getLengthSizeOfSampleNum()+1; + return EntrySize; + } + + void TFRA::setTFRAEntry(TFRAEntry newTFRAEntry, uint32_t no){ + if (no + 1 > getNumberOfEntry()){//if a new entry is issued + uint32_t offset = 16 + getTFRAEntrySize() * getNumberOfEntry();//start of filler in bytes + uint32_t fillsize = (no + 1 - getNumberOfEntry())*getTFRAEntrySize();//filler in bytes + if ( !reserve(offset, 0, fillsize)){//filling space + return; + } + setNumberOfEntry(no+1); + } + uint32_t loc = 16 + no * getTFRAEntrySize(); + if (getVersion() == 1){ + setInt64(newTFRAEntry.time, loc); + setInt64(newTFRAEntry.moofOffset, loc+8); + loc += 16; + }else{ + setInt32(newTFRAEntry.time, loc); + setInt32(newTFRAEntry.moofOffset, loc+4); + loc += 8; + } + switch (getLengthSizeOfTrafNum()){ + case 0: + setInt8(newTFRAEntry.trafNumber, loc); + break; + case 1: + setInt16(newTFRAEntry.trafNumber, loc); + break; + case 2: + setInt24(newTFRAEntry.trafNumber, loc); + break; + case 3: + setInt32(newTFRAEntry.trafNumber, loc); + break; + } + loc += getLengthSizeOfTrafNum() + 1; + switch (getLengthSizeOfTrunNum()){ + case 0: + setInt8(newTFRAEntry.trunNumber, loc); + break; + case 1: + setInt16(newTFRAEntry.trunNumber, loc); + break; + case 2: + setInt24(newTFRAEntry.trunNumber, loc); + break; + case 3: + setInt32(newTFRAEntry.trunNumber, loc); + break; + } + loc += getLengthSizeOfTrunNum() + 1; + switch (getLengthSizeOfSampleNum()){ + case 0: + setInt8(newTFRAEntry.sampleNumber, loc); + break; + case 1: + setInt16(newTFRAEntry.sampleNumber, loc); + break; + case 2: + setInt24(newTFRAEntry.sampleNumber, loc); + break; + case 3: + setInt32(newTFRAEntry.sampleNumber, loc); + break; + } + } + + TFRAEntry & TFRA::getTFRAEntry(uint32_t no){ + static TFRAEntry retval; + if (no >= getNumberOfEntry()){ + static TFRAEntry inval; + return inval; + } + uint32_t loc = 16 + no * getTFRAEntrySize(); + if (getVersion() == 1){ + retval.time = getInt64(loc); + retval.moofOffset = getInt64(loc + 8); + loc += 16; + }else{ + retval.time = getInt32(loc); + retval.moofOffset = getInt32(loc + 4); + loc += 8; + } + switch (getLengthSizeOfTrafNum()){ + case 0: + retval.trafNumber = getInt8(loc); + break; + case 1: + retval.trafNumber = getInt16(loc); + break; + case 2: + retval.trafNumber = getInt24(loc); + break; + case 3: + retval.trafNumber = getInt32(loc); + break; + } + loc += getLengthSizeOfTrafNum() + 1; + switch (getLengthSizeOfTrunNum()){ + case 0: + retval.trunNumber = getInt8(loc); + break; + case 1: + retval.trunNumber = getInt16(loc); + break; + case 2: + retval.trunNumber = getInt24(loc); + break; + case 3: + retval.trunNumber = getInt32(loc); + break; + } + loc += getLengthSizeOfTrunNum() + 1; + switch (getLengthSizeOfSampleNum()){ + case 0: + retval.sampleNumber = getInt8(loc); + break; + case 1: + retval.sampleNumber = getInt16(loc); + break; + case 2: + retval.sampleNumber = getInt24(loc); + break; + case 3: + retval.sampleNumber = getInt32(loc); + break; + } + return retval; + } + + std::string TFRA::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[tfra] Track Fragment Random Access Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; + r << std::string(indent + 1, ' ') << "lengthSizeOfTrafNum: " << (int)getLengthSizeOfTrafNum() << std::endl; + r << std::string(indent + 1, ' ') << "lengthSizeOfTrunNum: " << (int)getLengthSizeOfTrunNum() << std::endl; + r << std::string(indent + 1, ' ') << "lengthSizeOfSampleNum: " << (int)getLengthSizeOfSampleNum() << std::endl; + r << std::string(indent + 1, ' ') << "NumberOfEntry: " << getNumberOfEntry() << std::endl; + for (int i = 0; i < getNumberOfEntry(); i++){ + static TFRAEntry temp; + temp = getTFRAEntry(i); + r << std::string(indent + 1, ' ') << "Entry[" << i <<"]:"<< std::endl; + r << std::string(indent + 2, ' ') << "Time: " << temp.time << std::endl; + r << std::string(indent + 2, ' ') << "MoofOffset: " << temp.moofOffset << std::endl; + r << std::string(indent + 2, ' ') << "TrafNumber: " << temp.trafNumber << std::endl; + r << std::string(indent + 2, ' ') << "TrunNumber: " << temp.trunNumber << std::endl; + r << std::string(indent + 2, ' ') << "SampleNumber: " << temp.sampleNumber << std::endl; + } + return r.str(); + } + + TKHD::TKHD(){ + memcpy(data + 4, "tkhd", 4); + } + + void TKHD::setCreationTime(uint64_t newCreationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newCreationTime, 4); + }else{ + setInt64(newCreationTime, 4); + } + } + + uint64_t TKHD::getCreationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(4); + }else{ + return getInt64(4); + } + } + + void TKHD::setModificationTime(uint64_t newModificationTime){ + if (getVersion() == 0){ + setInt32((uint32_t) newModificationTime, 8); + }else{ + setInt64(newModificationTime, 12); + } + } + + uint64_t TKHD::getModificationTime(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(8); + }else{ + return getInt64(12); + } + } + + void TKHD::setTrackID(uint32_t newTrackID){ + if (getVersion() == 0){ + setInt32((uint32_t) newTrackID, 12); + }else{ + setInt32(newTrackID, 20); + } + } + + uint32_t TKHD::getTrackID(){ + if (getVersion() == 0){ + return getInt32(12); + }else{ + return getInt32(20); + } + } + //note 4 bytes reserved in between + void TKHD::setDuration(uint64_t newDuration){ + if (getVersion() == 0){ + setInt32(newDuration, 20); + }else{ + setInt64(newDuration, 28); + } + } + + uint64_t TKHD::getDuration(){ + if (getVersion() == 0){ + return (uint64_t)getInt32(20); + }else{ + return getInt64(28); + } + } + //8 bytes reserved in between + void TKHD::setLayer(uint16_t newLayer){ + if (getVersion() == 0){ + setInt16(newLayer, 32); + }else{ + setInt16(newLayer, 44); + } + } + + uint16_t TKHD::getLayer(){ + if (getVersion() == 0){ + return getInt16(32); + }else{ + return getInt16(44); + } + } + + void TKHD::setAlternateGroup(uint16_t newAlternateGroup){ + if (getVersion() == 0){ + setInt16(newAlternateGroup, 34); + }else{ + setInt16(newAlternateGroup, 46); + } + } + + uint16_t TKHD::getAlternateGroup(){ + if (getVersion() == 0){ + return getInt16(34); + }else{ + return getInt16(46); + } + } + + void TKHD::setVolume(uint16_t newVolume){ + if (getVersion() == 0){ + setInt16(newVolume, 36); + }else{ + setInt16(newVolume, 48); + } + } + + uint16_t TKHD::getVolume(){ + if (getVersion() == 0){ + return getInt16(36); + }else{ + return getInt16(48); + } + } + //2 bytes reserved in between + uint32_t TKHD::getMatrixCount(){ + return 9; + } + + void TKHD::setMatrix(int32_t newMatrix, size_t index){ + int offset = 0; + if (getVersion() == 0){ + offset = 36 + 2 + 2; + }else{ + offset = 48 + 2 + 2; + } + setInt32(newMatrix, offset + index * 4); + } + + int32_t TKHD::getMatrix(size_t index){ + int offset = 0; + if (getVersion() == 0){ + offset = 36 + 2 + 2; + }else{ + offset = 48 + 2 + 2; + } + return getInt32(offset + index * 4); + } + + void TKHD::setWidth(uint32_t newWidth){ + if (getVersion() == 0){ + setInt32(newWidth, 76); + }else{ + setInt32(newWidth, 88); + } + } + + uint32_t TKHD::getWidth(){ + if (getVersion() == 0){ + return getInt32(76); + }else{ + return getInt32(88); + } + } + + void TKHD::setHeight(uint32_t newHeight){ + if (getVersion() == 0){ + setInt32(newHeight, 80); + }else{ + setInt32(newHeight, 92); + } + } + + uint32_t TKHD::getHeight(){ + if (getVersion() == 0){ + return getInt32(80); + }else{ + return getInt32(92); + } + } + + std::string TKHD::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[tkhd] Track Header Box (" << boxedSize() << ")" << std::endl; + r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "CreationTime: " << getCreationTime() << std::endl; + r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; + r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl; + r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; + r << std::string(indent + 1, ' ') << "Layer: " << getLayer() << std::endl; + r << std::string(indent + 1, ' ') << "AlternateGroup: " << getAlternateGroup() << std::endl; + r << std::string(indent + 1, ' ') << "Volume: " << getVolume() << std::endl; + r << std::string(indent + 1, ' ') << "Matrix: "; + for (int32_t i = 0; i< getMatrixCount(); i++){ + r << getMatrix(i); + if (i!=getMatrixCount()-1){ + r << ", "; + } + } + r << std::endl; + r << std::string(indent + 1, ' ') << "Width: " << (getWidth() >> 16) << "." << (getWidth() & 0xFFFF) << std::endl; + r << std::string(indent + 1, ' ') << "Height: " << (getHeight() >> 16) << "." << (getHeight() & 0xFFFF) << std::endl; + return r.str(); + } + static char c2hex(int c){ if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; diff --git a/lib/mp4.h b/lib/mp4.h index b030eaec..5e10b584 100644 --- a/lib/mp4.h +++ b/lib/mp4.h @@ -534,6 +534,7 @@ namespace MP4 { 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); @@ -542,6 +543,64 @@ namespace MP4 { 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(); + 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 UUID: public Box{ public: UUID();