From b0b4a5d10dc28b8d3bba7f886444702d30104c64 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 3 Sep 2015 20:15:10 +0200 Subject: [PATCH 1/4] Added Track::finalize call to finish (live) tracks and record their complete duration, by Oswald de Bruin. --- lib/dtsc.h | 1 + lib/dtscmeta.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/dtsc.h b/lib/dtsc.h index 4326c588..7f617a22 100644 --- a/lib/dtsc.h +++ b/lib/dtsc.h @@ -275,6 +275,7 @@ namespace DTSC { unsigned int timeToFragnum(unsigned int timestamp); void reset(); void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); + void finalize(); std::string getIdentifier(); std::string getWritableIdentifier(); diff --git a/lib/dtscmeta.cpp b/lib/dtscmeta.cpp index e1f62386..45c3815a 100644 --- a/lib/dtscmeta.cpp +++ b/lib/dtscmeta.cpp @@ -1114,6 +1114,10 @@ namespace DTSC { fragments.rbegin()->setSize(fragments.rbegin()->getSize() + packDataSize); } + void Track::finalize(){ + keys.rbegin()->setLength(lastms - keys.rbegin()->getTime() + parts.rbegin()->getDuration()); + } + ///\brief Returns a key given its number, or an empty key if the number is out of bounds Key & Track::getKey(unsigned int keyNum) { static Key empty; From c254085579de68586099752a15f1dcd50132421b Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 3 Sep 2015 20:23:20 +0200 Subject: [PATCH 2/4] Added PASP MP4 box pretty printing. --- lib/mp4.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mp4.cpp b/lib/mp4.cpp index 2ff3f469..307bac7d 100644 --- a/lib/mp4.cpp +++ b/lib/mp4.cpp @@ -377,6 +377,9 @@ namespace MP4 { case 0x75756964: return ((UUID *)this)->toPrettyString(indent); break; + case 0x70617370: + return ((PASP*)this)->toPrettyString(indent); + break; default: break; } From 17f3a37454decd020363e2c29ea68812499d23cc Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 3 Sep 2015 20:18:12 +0200 Subject: [PATCH 3/4] Added ability for outputs to elect to only receive completed (i.e.: whole) keyframes, by Oswald de Bruin. --- src/output/output.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/output/output.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/src/output/output.cpp b/src/output/output.cpp index 20de4ede..9537b7b3 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -39,10 +39,12 @@ namespace Mist { sought = false; isInitialized = false; isBlocking = false; + completeKeysOnly = false; lastStats = 0; maxSkipAhead = 7500; minSkipAhead = 5000; realTime = 1000; + completeKeyReadyTimeOut = false; if (myConn){ setBlocking(true); }else{ @@ -584,6 +586,47 @@ namespace Mist { Util::sleep(nxt.time - (((Util::getMS() - firstTime)*1000)+minSkipAhead)/realTime); } } + //delay the stream until its current keyframe is complete + if (completeKeysOnly){ + bool completeKeyReady = false; + int timeoutTries = 40;//attempts to updateMeta before timeOut and moving on; default is approximately 10 seconds + for (std::map::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){ + if (it->second.keys.size() >1){ + int thisTimeoutTries = ((it->second.lastms - it->second.firstms) / (it->second.keys.size()-1)) / 125; + if (thisTimeoutTries > timeoutTries) timeoutTries = thisTimeoutTries; + } + } + while(!completeKeyReady && timeoutTries>0){ + completeKeyReady = true; + for (std::map::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){ + if (!it->second.keys.size() || it->second.keys.rbegin()->getTime() + it->second.keys.rbegin()->getLength() <= nxt.time ){ + completeKeyReady = false; + break; + } + } + if (!completeKeyReady){ + if (completeKeyReadyTimeOut){ + INSANE_MSG("Complete Key not ready and time-out is being skipped"); + timeoutTries = 0; + }else{ + INSANE_MSG("Timeout: %d",timeoutTries); + timeoutTries--;//we count down + stats(); + Util::wait(250); + updateMeta(); + } + } + } + if (timeoutTries<=0){ + if (!completeKeyReadyTimeOut){ + INFO_MSG("Wait for keyframe Timeout triggered! Ended to avoid endless loops"); + } + completeKeyReadyTimeOut = true; + }else{ + //untimeout handling + completeKeyReadyTimeOut = false; + } + } if (curPage[nxt.tid]){ if (nxt.offset < curPage[nxt.tid].len){ unsigned long long nextTime = getDTSCTime(curPage[nxt.tid].mapped, nxt.offset); diff --git a/src/output/output.h b/src/output/output.h index f8a67632..e8c08477 100644 --- a/src/output/output.h +++ b/src/output/output.h @@ -73,6 +73,7 @@ namespace Mist { std::map nxtKeyNum;///< Contains the number of the next key, for page seeking purposes. std::set buffer;///< A sorted list of next-to-be-loaded packets. bool sought;/// Date: Thu, 3 Sep 2015 21:36:09 +0200 Subject: [PATCH 4/4] Fixes and improvements to various MP4 library functions, by Oswald de Bruin. --- lib/mp4_generic.cpp | 335 ++++++++++++++++++++++++++++++++++---------- lib/mp4_generic.h | 51 ++++++- 2 files changed, 305 insertions(+), 81 deletions(-) diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp index bf9d4bc3..bb3b90a2 100644 --- a/lib/mp4_generic.cpp +++ b/lib/mp4_generic.cpp @@ -764,9 +764,10 @@ namespace MP4 { char * p = getData(); char * max_p = p + getDataSize(); r << std::string(indent+1, ' ') << "ES ID: " << (unsigned int)(((unsigned int)p[0] << 8) | (unsigned int)p[1]) << std::endl; - bool dep = (p[2] & 0x80); + bool dep = (p[2] & 0x80);//check pagina 28 ISO 1449-1 2001 bool url = (p[2] & 0x40); bool ocr = (p[2] & 0x20); + //6 & 86 r << std::string(indent+1, ' ') << "Priority: " << int(p[2] & 0x1f) << std::endl; p += 3; if (dep){ @@ -907,7 +908,7 @@ namespace MP4 { ESDS::ESDS(std::string init) { ///\todo Do this better, in a non-hardcoded way. memcpy(data + 4, "esds", 4); - reserve(payloadOffset, 0, init.size() ? init.size()+29 : 26); + reserve(payloadOffset, 0, init.size() ? init.size()+28 : 26); unsigned int i = 12; data[i++] = 3;//ES_DescrTag data[i++] = init.size() ? init.size()+23 : 21;//size @@ -941,7 +942,7 @@ namespace MP4 { } data[i++] = 6;//SLConfigDescriptor data[i++] = 1;//size - data[i++] = 2;//predefined, reserverd for use in MP4 files + data[i++] = 2;//predefined, reserved for use in MP4 files } bool ESDS::isAAC(){ @@ -967,14 +968,108 @@ namespace MP4 { return r.str(); } - FTYP::FTYP() { + DAC3::DAC3(unsigned int rate, unsigned int channels){ + memcpy(data + 4, "dac3", 4); + setInt24(0,0); + + setBitStreamIdentification(8);///\todo This is right now a default value. check the docs, this is a weird property + setBitStreamMode(0);//main, mixed audio + setAudioConfigMode(2); + + switch (rate) { + case 48000: + setSampleRateCode(0); + break; + case 44100: + setSampleRateCode(1); + break; + case 32000: + setSampleRateCode(2); + break; + default: + setSampleRateCode(3); + break; + } + + if (channels > 4) { + setLowFrequencyEffectsChannelOn(1); + } else { + setLowFrequencyEffectsChannelOn(0); + } + setFrameSizeCode(20);//should be OK, but test this. + } + + char DAC3::getSampleRateCode(){ + return getInt8(0) >> 6; + } + + void DAC3::setSampleRateCode(char newVal){ + setInt8(((newVal << 6) & 0xC0) | (getInt8(0) & 0x3F), 0); + } + + char DAC3::getBitStreamIdentification(){ + return (getInt8(0) >> 1) & 0x1F; + } + + void DAC3::setBitStreamIdentification(char newVal){ + setInt8(((newVal << 1) & 0x3E) | (getInt8(0) & 0xC1), 0); + } + + char DAC3::getBitStreamMode(){ + return (getInt16(0) >> 6) & 0x7; + } + + void DAC3::setBitStreamMode(char newVal){ + setInt16(((newVal & 0x7) << 6) | (getInt16(0) & 0xFE3F), 0); + } + + char DAC3::getAudioConfigMode(){ + return (getInt8(1) >> 3) & 0x7; + } + + void DAC3::setAudioConfigMode(char newVal){ + setInt8(((newVal & 0x7) << 3) | (getInt8(1) & 0x38),1); + } + + bool DAC3::getLowFrequencyEffectsChannelOn(){ + return (getInt8(1) >> 2) & 0x1; + } + + void DAC3::setLowFrequencyEffectsChannelOn(bool newVal){ + setInt8(((unsigned int)(newVal & 0x1) << 2) | (getInt8(1) & 0x4),1); + } + + char DAC3::getFrameSizeCode(){ + return ((getInt8(1) & 0x3) << 4) | ((getInt8(2) & 0xF0) >> 4); + } + + void DAC3::setFrameSizeCode(char newVal){ + setInt16(((newVal & 0x3F) << 4) | (getInt16(1) & 0x03F0),1); + } + + std::string DAC3::toPrettyString(uint32_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "[dac3] D-AC3 box (" << boxedSize() << ")" << std::endl; + r << std::string(indent + 1, ' ') << "FSCOD: " << (int)getSampleRateCode() << std::endl; + r << std::string(indent + 1, ' ') << "BSID: " << (int)getBitStreamIdentification() << std::endl; + r << std::string(indent + 1, ' ') << "BSMOD: " << (int)getBitStreamMode() << std::endl; + r << std::string(indent + 1, ' ') << "ACMOD: " << (int)getAudioConfigMode() << std::endl; + r << std::string(indent + 1, ' ') << "LFEON: " << (int)getLowFrequencyEffectsChannelOn() << std::endl; + r << std::string(indent + 1, ' ') << "FrameSizeCode: " << (int)getFrameSizeCode() << std::endl; + return r.str(); + } + + FTYP::FTYP(bool fillDefaults){ memcpy(data + 4, "ftyp", 4); - setMajorBrand("mp41"); - setMinorVersion("Mist"); - setCompatibleBrands("isom", 0); - setCompatibleBrands("iso2", 1); - setCompatibleBrands("avc1", 2); - setCompatibleBrands("mp41", 3); + if (fillDefaults){ + setMajorBrand("isom"); + setMinorVersion("\000\000\002\000"); + setCompatibleBrands("isom",0); + setCompatibleBrands("iso2",1); + setCompatibleBrands("avc1",2); + setCompatibleBrands("mp41",3); + setCompatibleBrands("Mist",4); + } } void FTYP::setMajorBrand(const char * newMajorBrand) { @@ -1043,48 +1138,53 @@ namespace MP4 { memcpy(data + 4, "mvex", 4); } - TREX::TREX() { + TREX::TREX(unsigned int trackId){ memcpy(data + 4, "trex", 4); + setTrackID(trackId); + setDefaultSampleDescriptionIndex(1); + setDefaultSampleDuration(0); + setDefaultSampleSize(0); + setDefaultSampleFlags(0); } void TREX::setTrackID(uint32_t newTrackID) { - setInt32(newTrackID, 0); + setInt32(newTrackID, 4); } uint32_t TREX::getTrackID() { - return getInt32(0); - } - - void TREX::setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex) { - setInt32(newDefaultSampleDescriptionIndex, 4); - } - - uint32_t TREX::getDefaultSampleDescriptionIndex() { return getInt32(4); } - void TREX::setDefaultSampleDuration(uint32_t newDefaultSampleDuration) { - setInt32(newDefaultSampleDuration, 8); + void TREX::setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex) { + setInt32(newDefaultSampleDescriptionIndex,8); } - uint32_t TREX::getDefaultSampleDuration() { + uint32_t TREX::getDefaultSampleDescriptionIndex() { return getInt32(8); } - void TREX::setDefaultSampleSize(uint32_t newDefaultSampleSize) { - setInt32(newDefaultSampleSize, 12); + void TREX::setDefaultSampleDuration(uint32_t newDefaultSampleDuration) { + setInt32(newDefaultSampleDuration,12); } - uint32_t TREX::getDefaultSampleSize() { + uint32_t TREX::getDefaultSampleDuration() { return getInt32(12); } + void TREX::setDefaultSampleSize(uint32_t newDefaultSampleSize) { + setInt32(newDefaultSampleSize,16); + } + + uint32_t TREX::getDefaultSampleSize() { + return getInt32(16); + } + void TREX::setDefaultSampleFlags(uint32_t newDefaultSampleFlags) { - setInt32(newDefaultSampleFlags, 16); + setInt32(newDefaultSampleFlags,20); } uint32_t TREX::getDefaultSampleFlags() { - return getInt32(16); + return getInt32(20); } std::string TREX::toPrettyString(uint32_t indent) { @@ -1448,7 +1548,7 @@ namespace MP4 { memcpy(data + 4, "mvhd", 4); //reserve an entire version 0 box - if (!reserve(0, 8, 108)) { + if (!reserve(0, 9, 108)) { return;//on fail, cancel all the things } memset(data + payloadOffset, 0, 100); //set all bytes (108 - 8) to zeroes @@ -1577,9 +1677,9 @@ namespace MP4 { int32_t MVHD::getMatrix(size_t index) { int offset = 0; if (getVersion() == 0) { - offset = 24 + 2 + 10; + offset = 36; } else { - offset = 36 + 2 + 10; + offset = 48; } return getInt32(offset + index * 4); } @@ -1587,17 +1687,17 @@ namespace MP4 { //24 bytes of pre-defined in between void MVHD::setTrackID(uint32_t newTrackID) { if (getVersion() == 0) { - setInt32(newTrackID, 86); + setInt32(newTrackID, 96); } else { - setInt32(newTrackID, 98); + setInt32(newTrackID, 108); } } uint32_t MVHD::getTrackID() { if (getVersion() == 0) { - return getInt32(86); + return getInt32(96); } else { - return getInt32(98); + return getInt32(108); } } @@ -1829,26 +1929,41 @@ namespace MP4 { return r.str(); } + TKHD::TKHD(uint32_t trackId, uint64_t duration, uint32_t width, uint32_t height) { + initialize(); + setTrackID(trackId); + setDuration(duration); + setWidth(width << 16); + setHeight(height << 16); + } + + TKHD::TKHD(DTSC::Track & track, bool fragmented) { + initialize(); + setTrackID(track.trackID); + setDuration(-1); + if (!fragmented) { + setDuration(track.lastms - track.firstms); + } + if (track.type == "video") { + setWidth(track.width << 16); + setHeight(track.height << 16); + } + } + + void TKHD::initialize(){ memcpy(data + 4, "tkhd", 4); //reserve an entire version 0 box - if (!reserve(0, 8, 92)) { + if (!reserve(0, 9, 92)) { return;//on fail, cancel all the things } memset(data + payloadOffset, 0, 84); //set all bytes (92 - 8) to zeroes - - setFlags(15);//ENABLED | IN_MOVIE | IN_PREVIEW | IN_POSTER - setTrackID(trackId); - setDuration(duration); - if (width == 0 || height == 0) { - setVolume(0x0100); - } + setFlags(3);//ENABLED | IN_MOVIE setMatrix(0x00010000, 0); setMatrix(0x00010000, 4); setMatrix(0x40000000, 8); - setWidth(width << 16); - setHeight(height << 16); + setVolume(0x0100); } void TKHD::setCreationTime(uint64_t newCreationTime) { @@ -2046,7 +2161,7 @@ namespace MP4 { MDHD::MDHD(uint64_t duration) { memcpy(data + 4, "mdhd", 4); //reserve an entire version 0 box - if (!reserve(0, 8, 32)) { + if (!reserve(0, 9, 32)) { return;//on fail, cancel all the things } memset(data + payloadOffset, 0, 24); //set all bytes (32 - 8) to zeroes @@ -2250,6 +2365,12 @@ namespace MP4 { } + STSCEntry::STSCEntry(unsigned int _first, unsigned int _count, unsigned int _index){ + firstChunk = _first; + samplesPerChunk = _count; + sampleDescriptionIndex = _index; + } + STSC::STSC(char v, uint32_t f) { memcpy(data + 4, "stsc", 4); setVersion(v); @@ -2574,6 +2695,8 @@ namespace MP4 { PASP::PASP() { memcpy(data + 4, "pasp", 4); + setHSpacing(1); + setVSpacing(1); } void PASP::setHSpacing(uint32_t newVal) { @@ -2601,6 +2724,25 @@ namespace MP4 { } VisualSampleEntry::VisualSampleEntry() { + initialize(); + } + + VisualSampleEntry::VisualSampleEntry(DTSC::Track & track){ + initialize(); + setDataReferenceIndex(1); + setWidth(track.width); + setHeight(track.height); + if (track.codec == "H264") { + setCodec("avc1"); + MP4::AVCC avccBox; + avccBox.setPayload(track.init); + setCLAP(avccBox); + } + MP4::PASP paspBox; + setPASP(paspBox); + } + + void VisualSampleEntry::initialize(){ memcpy(data + 4, "erro", 4); setHorizResolution(0x00480000); setVertResolution(0x00480000); @@ -2654,7 +2796,9 @@ namespace MP4 { } void VisualSampleEntry::setCompressorName(std::string newCompressorName) { - newCompressorName.resize(32, ' '); + if (newCompressorName.size() > 32){ + newCompressorName.resize(32, ' '); + } setString(newCompressorName, 42); } @@ -2683,6 +2827,15 @@ namespace MP4 { return ret; } + void VisualSampleEntry::setPASP(Box & pasp) { + int writePlace = 78; + Box tmpBox = getBox(78); + if (tmpBox.getType () != "erro"){ + writePlace = 78 + getBoxLen(78); + } + setBox(pasp, writePlace); + } + Box & VisualSampleEntry::getPASP() { static Box ret = Box((char *)"\000\000\000\010erro", false); if (payloadSize() < 84) { //if the EntryBox is not big enough to hold a CLAP/PASP @@ -2717,6 +2870,31 @@ namespace MP4 { } AudioSampleEntry::AudioSampleEntry() { + initialize(); + } + + AudioSampleEntry::AudioSampleEntry(DTSC::Track & track) { + initialize(); + if (track.codec == "AAC" || track.codec == "MP3") { + setCodec("mp4a"); + } + if (track.codec == "AC3") { + setCodec("ac-3"); + } + setDataReferenceIndex(1); + setSampleRate(track.rate); + setChannelCount(track.channels); + setSampleSize(track.size); + if (track.codec == "AC3") { + MP4::DAC3 dac3Box(track.rate, track.channels); + setCodecBox(dac3Box); + } else { //other codecs use the ESDS box + MP4::ESDS esdsBox(track.init); + setCodecBox(esdsBox); + } + } + + void AudioSampleEntry::initialize() { memcpy(data + 4, "erro", 4); setChannelCount(2); setSampleSize(16); @@ -2947,67 +3125,75 @@ namespace MP4 { memcpy(data + 4, "elst", 4); } + void ELST::setCount(uint32_t newVal){ + setInt32(newVal, 4); + } + + uint32_t ELST::getCount(){ + return getInt32(4); + } + void ELST::setSegmentDuration(uint64_t newVal) { if (getVersion() == 1) { - setInt64(newVal, 4); - } else { - setInt32(newVal, 4); - } - } - - uint64_t ELST::getSegmentDuration() { - if (getVersion() == 1) { - return getInt64(4); - } else { - return getInt32(4); - } - } - - void ELST::setMediaTime(uint64_t newVal) { - if (getVersion() == 1) { - setInt64(newVal, 12); + setInt64(newVal, 8); } else { setInt32(newVal, 8); } } - uint64_t ELST::getMediaTime() { + uint64_t ELST::getSegmentDuration() { if (getVersion() == 1) { - return getInt64(12); + return getInt64(8); } else { return getInt32(8); } } + void ELST::setMediaTime(uint64_t newVal) { + if (getVersion() == 1) { + setInt64(newVal, 16); + } else { + setInt32(newVal, 12); + } + } + + uint64_t ELST::getMediaTime() { + if (getVersion() == 1) { + return getInt64(16); + } else { + return getInt32(12); + } + } + void ELST::setMediaRateInteger(uint16_t newVal) { if (getVersion() == 1) { - setInt16(newVal, 20); + setInt16(newVal, 24); } else { - setInt16(newVal, 12); + setInt16(newVal, 16); } } uint16_t ELST::getMediaRateInteger() { if (getVersion() == 1) { - return getInt16(20); + return getInt16(24); } else { - return getInt16(12); + return getInt16(16); } } void ELST::setMediaRateFraction(uint16_t newVal) { if (getVersion() == 1) { - setInt16(newVal, 22); + setInt16(newVal, 26); } else { - setInt16(newVal, 14); + setInt16(newVal, 18); } } uint16_t ELST::getMediaRateFraction() { if (getVersion() == 1) { - return getInt16(22); + return getInt16(26); } else { - return getInt16(14); + return getInt16(18); } } @@ -3015,6 +3201,7 @@ namespace MP4 { std::stringstream r; r << std::string(indent, ' ') << "[elst] Edit List Box (" << boxedSize() << ")" << std::endl; r << fullBox::toPrettyString(indent); + r << std::string(indent + 1, ' ') << "Count: " << getCount() << std::endl; r << std::string(indent + 1, ' ') << "SegmentDuration: " << getSegmentDuration() << std::endl; r << std::string(indent + 1, ' ') << "MediaTime: " << getMediaTime() << std::endl; r << std::string(indent + 1, ' ') << "MediaRateInteger: " << getMediaRateInteger() << std::endl; diff --git a/lib/mp4_generic.h b/lib/mp4_generic.h index b11cb7e7..acdc52b4 100644 --- a/lib/mp4_generic.h +++ b/lib/mp4_generic.h @@ -182,9 +182,27 @@ namespace MP4 { std::string toPrettyString(uint32_t indent = 0); }; + class DAC3: public Box { + public: + DAC3(unsigned int rate, unsigned int channels); + char getSampleRateCode();//2bits + void setSampleRateCode(char newVal);//2bits + char getBitStreamIdentification();//5bits + void setBitStreamIdentification(char newVal);//5bits + char getBitStreamMode();//3 bits + void setBitStreamMode(char newVal);//3 bits + char getAudioConfigMode();//3 bits + void setAudioConfigMode(char newVal);//3 bits + bool getLowFrequencyEffectsChannelOn();//1bit + void setLowFrequencyEffectsChannelOn(bool newVal);//1bit + char getFrameSizeCode();//6bits + void setFrameSizeCode(char newVal);//6bits + std::string toPrettyString(uint32_t indent = 0); + }; + class FTYP: public Box { public: - FTYP(); + FTYP(bool fillDefaults = true); void setMajorBrand(const char * newMajorBrand); std::string getMajorBrand(); void setMinorVersion(const char * newMinorVersion); @@ -195,6 +213,12 @@ namespace MP4 { std::string toPrettyString(uint32_t indent = 0); }; + class STYP: public FTYP { + public: + STYP(bool fillDefaults = true); + std::string toPrettyString(uint32_t indent = 0); + }; + class MOOV: public containerBox { public: MOOV(); @@ -205,9 +229,9 @@ namespace MP4 { MVEX(); }; - class TREX: public Box { + class TREX: public fullBox { public: - TREX(); + TREX(unsigned int trackId = 0); void setTrackID(uint32_t newTrackID); uint32_t getTrackID(); void setDefaultSampleDescriptionIndex(uint32_t newDefaultSampleDescriptionIndex); @@ -397,6 +421,8 @@ namespace MP4 { class TKHD: public fullBox { public: TKHD(uint32_t trackId, uint64_t duration, uint32_t width, uint32_t height); + TKHD(DTSC::Track & track, bool fragmented); + void setCreationTime(uint64_t newCreationTime); uint64_t getCreationTime(); void setModificationTime(uint64_t newModificationTime); @@ -422,6 +448,8 @@ namespace MP4 { void setHeight(uint32_t newHeight); uint32_t getHeight(); std::string toPrettyString(uint32_t indent = 0); + protected: + void initialize(); }; class MDHD: public fullBox { @@ -471,10 +499,12 @@ namespace MP4 { std::string toPrettyString(uint32_t indent = 0); }; - struct STSCEntry { - uint32_t firstChunk; - uint32_t samplesPerChunk; - uint32_t sampleDescriptionIndex; + class STSCEntry { + public: + STSCEntry(unsigned int _first = 0, unsigned int _count = 0, unsigned int _index = 0); + uint32_t firstChunk; + uint32_t samplesPerChunk; + uint32_t sampleDescriptionIndex; }; class STSC: public fullBox { @@ -563,6 +593,8 @@ namespace MP4 { ///\todo set default values public: VisualSampleEntry(); + VisualSampleEntry(DTSC::Track & track); + void initialize(); void setCodec(const char * newCodec); void setWidth(uint16_t newWidth); uint16_t getWidth(); @@ -581,6 +613,7 @@ namespace MP4 { Box & getCLAP(); void setCLAP(Box & clap); Box & getPASP(); + void setPASP(Box & pasp); std::string toPrettyVisualString(uint32_t index = 0, std::string = ""); }; @@ -588,6 +621,8 @@ namespace MP4 { public: ///\todo set default values AudioSampleEntry(); + AudioSampleEntry(DTSC::Track & track); + void initialize(); void setCodec(const char * newCodec); void setChannelCount(uint16_t newChannelCount); uint16_t getChannelCount(); @@ -666,6 +701,8 @@ namespace MP4 { class ELST: public fullBox { public: ELST(); + void setCount(uint32_t newVal); + uint32_t getCount(); void setSegmentDuration(uint64_t newVal); uint64_t getSegmentDuration(); void setMediaTime(uint64_t newVal);