diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp index 954e85e6..3d37f522 100644 --- a/lib/mp4_generic.cpp +++ b/lib/mp4_generic.cpp @@ -125,7 +125,7 @@ namespace MP4{ if (getSampleInformationCount() < no + 1){setInt32(no + 1, 4);} } - trunSampleInformation TRUN::getSampleInformation(uint32_t no, TFHD * tfhd) const{ + trunSampleInformation TRUN::getSampleInformation(uint32_t no, TFHD * tfhd, TREX * trex) const{ trunSampleInformation ret; ret.sampleDuration = 0; ret.sampleSize = 0; @@ -148,22 +148,34 @@ namespace MP4{ if (flags & trunsampleDuration){ ret.sampleDuration = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; - }else if (tfhd){ + }else if (tfhd && (tfhd->getFlags() & tfhdSampleDura)){ ret.sampleDuration = tfhd->getDefaultSampleDuration(); + }else if (trex){ + ret.sampleDuration = trex->getDefaultSampleDuration(); + }else{ + WARN_MSG("Could not get sample duration from TRUN, TFHD or TREX box(es)!"); } if (flags & trunsampleSize){ ret.sampleSize = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; - }else if (tfhd){ + }else if (tfhd && (tfhd->getFlags() & tfhdSampleSize)){ ret.sampleSize = tfhd->getDefaultSampleSize(); + }else if (trex){ + ret.sampleSize = trex->getDefaultSampleSize(); + }else{ + WARN_MSG("Could not get sample size from TRUN, TFHD or TREX box(es)!"); } if (flags & trunsampleFlags){ ret.sampleFlags = getInt32(offset + no * sampInfoSize + innerOffset); innerOffset += 4; }else if ((flags & trunfirstSampleFlags) && !no){ ret.sampleFlags = getFirstSampleFlags(); - }else if (tfhd){ + }else if (tfhd && (tfhd->getFlags() & tfhdSampleFlag)){ ret.sampleFlags = tfhd->getDefaultSampleFlags(); + }else if (trex){ + ret.sampleFlags = trex->getDefaultSampleFlags(); + }else{ + WARN_MSG("Could not get sample flags from TRUN, TFHD or TREX box(es)!"); } if (flags & trunsampleOffsets){ ret.sampleOffset = getInt32(offset + no * sampInfoSize + innerOffset); diff --git a/lib/mp4_generic.h b/lib/mp4_generic.h index 449cf340..a5f7eec9 100644 --- a/lib/mp4_generic.h +++ b/lib/mp4_generic.h @@ -69,6 +69,23 @@ namespace MP4{ std::string toPrettyString(uint32_t indent = 0); }; + class TREX : public fullBox{ + public: + TREX(unsigned int trackId = 0); + 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); + }; + + struct trunSampleInformation { uint32_t sampleDuration; uint32_t sampleSize; @@ -106,7 +123,7 @@ namespace MP4{ uint32_t getFirstSampleFlags() const; uint32_t getSampleInformationCount() const; void setSampleInformation(trunSampleInformation newSample, uint32_t no); - trunSampleInformation getSampleInformation(uint32_t no, TFHD * tfhd = 0) const; + trunSampleInformation getSampleInformation(uint32_t no, TFHD * tfhd = 0, TREX * trex = 0) const; std::string toPrettyString(uint32_t indent = 0) const; }; @@ -312,22 +329,6 @@ namespace MP4{ MVEX(); }; - class TREX : public fullBox{ - public: - TREX(unsigned int trackId = 0); - 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(); diff --git a/lib/mp4_stream.cpp b/lib/mp4_stream.cpp index 3a200dd1..551ed842 100644 --- a/lib/mp4_stream.cpp +++ b/lib/mp4_stream.cpp @@ -69,6 +69,8 @@ namespace MP4{ co64Box.clear(); stscBox.clear(); stssBox.clear(); + trexBox.clear(); + trexPtr = 0; stco64 = false; trafMode = false; trackId = 0; @@ -94,6 +96,11 @@ namespace MP4{ trafs.clear(); } + void TrackHeader::read(TREX &_trexBox){ + trexBox.copyFrom(_trexBox); + if (trexBox.isType("trex")){trexPtr = &trexBox;} + } + void TrackHeader::read(TRAK &trakBox){ vidWidth = vidHeight = audChannels = audRate = audSize = 0; codec.clear(); @@ -428,7 +435,7 @@ namespace MP4{ // Okay, our index is inside this TRUN! // Let's pull the TFHD box into this as well... TFHD tfhd = ((TRAF)(*t)).getChild(); - trunSampleInformation si = r->getSampleInformation(index - skipped, &tfhd); + trunSampleInformation si = r->getSampleInformation(index - skipped, &tfhd, trexPtr); if (byteOffset){ size_t offset = 0; if (tfhd.getDefaultBaseIsMoof()){ @@ -438,7 +445,7 @@ namespace MP4{ offset += r->getDataOffset(); size_t target = index - skipped; for (size_t i = 0; i < target; ++i){ - offset += r->getSampleInformation(i, &tfhd).sampleSize; + offset += r->getSampleInformation(i, &tfhd, trexPtr).sampleSize; } }else{ FAIL_MSG("Unimplemented: trun box does not contain a data offset!"); @@ -458,7 +465,7 @@ namespace MP4{ while (timeSample < index){ // Most common case: timeSample is in the current TRUN box if (timeSample >= skipped && timeSample < skipped + count){ - trunSampleInformation i = r->getSampleInformation(timeSample - skipped, &tfhd); + trunSampleInformation i = r->getSampleInformation(timeSample - skipped, &tfhd, trexPtr); increaseTime(i.sampleDuration); continue; } @@ -475,7 +482,7 @@ namespace MP4{ break; } // Cool, now we know it's valid, increase the time accordingly. - trunSampleInformation i = runIt->getSampleInformation(timeSample - locSkipped, &tfhd); + trunSampleInformation i = runIt->getSampleInformation(timeSample - locSkipped, &tfhd, trexPtr); increaseTime(i.sampleDuration); } *time = (timeTotal * 1000) / timeScale; diff --git a/lib/mp4_stream.h b/lib/mp4_stream.h index 7625760e..58ae7c2e 100644 --- a/lib/mp4_stream.h +++ b/lib/mp4_stream.h @@ -31,6 +31,8 @@ namespace MP4{ /// Reads (new) track header information for processing void read(TRAK &trakBox); /// Reads (new) track header information for processing + void read(TREX &trexBox); + /// Reads (new) track header information for processing void read(TRAF &trafBox); /// Signal that we're going to be reading the next moof box now. @@ -87,6 +89,8 @@ namespace MP4{ STTS sttsBox; ///< packet durations CTTS cttsBox; ///< packet time offsets (optional) STSC stscBox; ///< packet count per chunk + TREX trexBox; ///< packet count per chunk + TREX * trexPtr; ///< Either 0 or pointer to trexBox member std::deque trafs; ///< Current traf boxes, if any bool stco64; // 64 bit chunk offsets? bool hasOffsets; ///< Are time offsets present? diff --git a/lib/segmentreader.cpp b/lib/segmentreader.cpp index 6b8a5c51..2669a8af 100644 --- a/lib/segmentreader.cpp +++ b/lib/segmentreader.cpp @@ -200,6 +200,12 @@ namespace Mist{ mp4Headers.rbegin()->read(*trakIt); mp4PacksLeft += mp4Headers.rbegin()->size(); } + std::deque trex = ((MP4::MOOV*)&moovBox)->getChild().getChildren(); + for (std::deque::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){ + for (std::deque::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){ + if (it->trackId == trexIt->getTrackID()){it->read(*trexIt);} + } + } MEDIUM_MSG("Read moov box"); } if (boxType == "moof"){ @@ -262,6 +268,12 @@ namespace Mist{ mp4Headers.rbegin()->read(*trakIt); mp4PacksLeft += mp4Headers.rbegin()->size(); } + std::deque trex = ((MP4::MOOV*)&moovBox)->getChild().getChildren(); + for (std::deque::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){ + for (std::deque::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){ + if (it->trackId == trexIt->getTrackID()){it->read(*trexIt);} + } + } MEDIUM_MSG("Read moov box"); } offset += boxSize; diff --git a/src/analysers/analyser_mp4.cpp b/src/analysers/analyser_mp4.cpp index 30d4fa2b..d4e0bd84 100644 --- a/src/analysers/analyser_mp4.cpp +++ b/src/analysers/analyser_mp4.cpp @@ -97,6 +97,10 @@ bool AnalyserMP4::parsePacket(){ // Regardless of support, we now put it in our track header array (after all, even unsupported tracks can be analysed!) hdrs[tHdr.trackId].read(*trakIt); } + std::deque trex = ((MP4::MOOV*)&mp4Data)->getChild().getChildren(); + for (std::deque::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){ + hdrs[trexIt->getTrackID()].read(*trexIt); + } // If we stored an mdat earlier, we can now analyse and then wipe it if (mdat.size()){ MP4::Box mdatBox(mdat, false); diff --git a/src/input/input_mp4.cpp b/src/input/input_mp4.cpp index 9ad361f9..a735dc23 100644 --- a/src/input/input_mp4.cpp +++ b/src/input/input_mp4.cpp @@ -130,6 +130,12 @@ namespace Mist{ trackHeaders.push_back(MP4::TrackHeader()); trackHeaders.rbegin()->read(*trakIt); } + std::deque trex = ((MP4::MOOV*)&moovBox)->getChild().getChildren(); + for (std::deque::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){ + for (std::deque::iterator it = trackHeaders.begin(); it != trackHeaders.end(); it++){ + if (it->trackId == trexIt->getTrackID()){it->read(*trexIt);} + } + } hasMoov = true; } activityCounter = Util::bootSecs();