Support for TREX boxes in MP4::Stream parser and all binaries that use it
This commit is contained in:
parent
57655f1b21
commit
0e26d49bec
7 changed files with 71 additions and 25 deletions
|
@ -125,7 +125,7 @@ namespace MP4{
|
||||||
if (getSampleInformationCount() < no + 1){setInt32(no + 1, 4);}
|
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;
|
trunSampleInformation ret;
|
||||||
ret.sampleDuration = 0;
|
ret.sampleDuration = 0;
|
||||||
ret.sampleSize = 0;
|
ret.sampleSize = 0;
|
||||||
|
@ -148,22 +148,34 @@ namespace MP4{
|
||||||
if (flags & trunsampleDuration){
|
if (flags & trunsampleDuration){
|
||||||
ret.sampleDuration = getInt32(offset + no * sampInfoSize + innerOffset);
|
ret.sampleDuration = getInt32(offset + no * sampInfoSize + innerOffset);
|
||||||
innerOffset += 4;
|
innerOffset += 4;
|
||||||
}else if (tfhd){
|
}else if (tfhd && (tfhd->getFlags() & tfhdSampleDura)){
|
||||||
ret.sampleDuration = tfhd->getDefaultSampleDuration();
|
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){
|
if (flags & trunsampleSize){
|
||||||
ret.sampleSize = getInt32(offset + no * sampInfoSize + innerOffset);
|
ret.sampleSize = getInt32(offset + no * sampInfoSize + innerOffset);
|
||||||
innerOffset += 4;
|
innerOffset += 4;
|
||||||
}else if (tfhd){
|
}else if (tfhd && (tfhd->getFlags() & tfhdSampleSize)){
|
||||||
ret.sampleSize = tfhd->getDefaultSampleSize();
|
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){
|
if (flags & trunsampleFlags){
|
||||||
ret.sampleFlags = getInt32(offset + no * sampInfoSize + innerOffset);
|
ret.sampleFlags = getInt32(offset + no * sampInfoSize + innerOffset);
|
||||||
innerOffset += 4;
|
innerOffset += 4;
|
||||||
}else if ((flags & trunfirstSampleFlags) && !no){
|
}else if ((flags & trunfirstSampleFlags) && !no){
|
||||||
ret.sampleFlags = getFirstSampleFlags();
|
ret.sampleFlags = getFirstSampleFlags();
|
||||||
}else if (tfhd){
|
}else if (tfhd && (tfhd->getFlags() & tfhdSampleFlag)){
|
||||||
ret.sampleFlags = tfhd->getDefaultSampleFlags();
|
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){
|
if (flags & trunsampleOffsets){
|
||||||
ret.sampleOffset = getInt32(offset + no * sampInfoSize + innerOffset);
|
ret.sampleOffset = getInt32(offset + no * sampInfoSize + innerOffset);
|
||||||
|
|
|
@ -69,6 +69,23 @@ namespace MP4{
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
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 {
|
struct trunSampleInformation {
|
||||||
uint32_t sampleDuration;
|
uint32_t sampleDuration;
|
||||||
uint32_t sampleSize;
|
uint32_t sampleSize;
|
||||||
|
@ -106,7 +123,7 @@ namespace MP4{
|
||||||
uint32_t getFirstSampleFlags() const;
|
uint32_t getFirstSampleFlags() const;
|
||||||
uint32_t getSampleInformationCount() const;
|
uint32_t getSampleInformationCount() const;
|
||||||
void setSampleInformation(trunSampleInformation newSample, uint32_t no);
|
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;
|
std::string toPrettyString(uint32_t indent = 0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -312,22 +329,6 @@ namespace MP4{
|
||||||
MVEX();
|
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{
|
class MFRA : public containerBox{
|
||||||
public:
|
public:
|
||||||
MFRA();
|
MFRA();
|
||||||
|
|
|
@ -69,6 +69,8 @@ namespace MP4{
|
||||||
co64Box.clear();
|
co64Box.clear();
|
||||||
stscBox.clear();
|
stscBox.clear();
|
||||||
stssBox.clear();
|
stssBox.clear();
|
||||||
|
trexBox.clear();
|
||||||
|
trexPtr = 0;
|
||||||
stco64 = false;
|
stco64 = false;
|
||||||
trafMode = false;
|
trafMode = false;
|
||||||
trackId = 0;
|
trackId = 0;
|
||||||
|
@ -94,6 +96,11 @@ namespace MP4{
|
||||||
trafs.clear();
|
trafs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TrackHeader::read(TREX &_trexBox){
|
||||||
|
trexBox.copyFrom(_trexBox);
|
||||||
|
if (trexBox.isType("trex")){trexPtr = &trexBox;}
|
||||||
|
}
|
||||||
|
|
||||||
void TrackHeader::read(TRAK &trakBox){
|
void TrackHeader::read(TRAK &trakBox){
|
||||||
vidWidth = vidHeight = audChannels = audRate = audSize = 0;
|
vidWidth = vidHeight = audChannels = audRate = audSize = 0;
|
||||||
codec.clear();
|
codec.clear();
|
||||||
|
@ -428,7 +435,7 @@ namespace MP4{
|
||||||
// Okay, our index is inside this TRUN!
|
// Okay, our index is inside this TRUN!
|
||||||
// Let's pull the TFHD box into this as well...
|
// Let's pull the TFHD box into this as well...
|
||||||
TFHD tfhd = ((TRAF)(*t)).getChild<TFHD>();
|
TFHD tfhd = ((TRAF)(*t)).getChild<TFHD>();
|
||||||
trunSampleInformation si = r->getSampleInformation(index - skipped, &tfhd);
|
trunSampleInformation si = r->getSampleInformation(index - skipped, &tfhd, trexPtr);
|
||||||
if (byteOffset){
|
if (byteOffset){
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
if (tfhd.getDefaultBaseIsMoof()){
|
if (tfhd.getDefaultBaseIsMoof()){
|
||||||
|
@ -438,7 +445,7 @@ namespace MP4{
|
||||||
offset += r->getDataOffset();
|
offset += r->getDataOffset();
|
||||||
size_t target = index - skipped;
|
size_t target = index - skipped;
|
||||||
for (size_t i = 0; i < target; ++i){
|
for (size_t i = 0; i < target; ++i){
|
||||||
offset += r->getSampleInformation(i, &tfhd).sampleSize;
|
offset += r->getSampleInformation(i, &tfhd, trexPtr).sampleSize;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
FAIL_MSG("Unimplemented: trun box does not contain a data offset!");
|
FAIL_MSG("Unimplemented: trun box does not contain a data offset!");
|
||||||
|
@ -458,7 +465,7 @@ namespace MP4{
|
||||||
while (timeSample < index){
|
while (timeSample < index){
|
||||||
// Most common case: timeSample is in the current TRUN box
|
// Most common case: timeSample is in the current TRUN box
|
||||||
if (timeSample >= skipped && timeSample < skipped + count){
|
if (timeSample >= skipped && timeSample < skipped + count){
|
||||||
trunSampleInformation i = r->getSampleInformation(timeSample - skipped, &tfhd);
|
trunSampleInformation i = r->getSampleInformation(timeSample - skipped, &tfhd, trexPtr);
|
||||||
increaseTime(i.sampleDuration);
|
increaseTime(i.sampleDuration);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -475,7 +482,7 @@ namespace MP4{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Cool, now we know it's valid, increase the time accordingly.
|
// 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);
|
increaseTime(i.sampleDuration);
|
||||||
}
|
}
|
||||||
*time = (timeTotal * 1000) / timeScale;
|
*time = (timeTotal * 1000) / timeScale;
|
||||||
|
|
|
@ -31,6 +31,8 @@ namespace MP4{
|
||||||
/// Reads (new) track header information for processing
|
/// Reads (new) track header information for processing
|
||||||
void read(TRAK &trakBox);
|
void read(TRAK &trakBox);
|
||||||
/// Reads (new) track header information for processing
|
/// Reads (new) track header information for processing
|
||||||
|
void read(TREX &trexBox);
|
||||||
|
/// Reads (new) track header information for processing
|
||||||
void read(TRAF &trafBox);
|
void read(TRAF &trafBox);
|
||||||
|
|
||||||
/// Signal that we're going to be reading the next moof box now.
|
/// Signal that we're going to be reading the next moof box now.
|
||||||
|
@ -87,6 +89,8 @@ namespace MP4{
|
||||||
STTS sttsBox; ///< packet durations
|
STTS sttsBox; ///< packet durations
|
||||||
CTTS cttsBox; ///< packet time offsets (optional)
|
CTTS cttsBox; ///< packet time offsets (optional)
|
||||||
STSC stscBox; ///< packet count per chunk
|
STSC stscBox; ///< packet count per chunk
|
||||||
|
TREX trexBox; ///< packet count per chunk
|
||||||
|
TREX * trexPtr; ///< Either 0 or pointer to trexBox member
|
||||||
std::deque<TRAF> trafs; ///< Current traf boxes, if any
|
std::deque<TRAF> trafs; ///< Current traf boxes, if any
|
||||||
bool stco64; // 64 bit chunk offsets?
|
bool stco64; // 64 bit chunk offsets?
|
||||||
bool hasOffsets; ///< Are time offsets present?
|
bool hasOffsets; ///< Are time offsets present?
|
||||||
|
|
|
@ -200,6 +200,12 @@ namespace Mist{
|
||||||
mp4Headers.rbegin()->read(*trakIt);
|
mp4Headers.rbegin()->read(*trakIt);
|
||||||
mp4PacksLeft += mp4Headers.rbegin()->size();
|
mp4PacksLeft += mp4Headers.rbegin()->size();
|
||||||
}
|
}
|
||||||
|
std::deque<MP4::TREX> trex = ((MP4::MOOV*)&moovBox)->getChild<MP4::MVEX>().getChildren<MP4::TREX>();
|
||||||
|
for (std::deque<MP4::TREX>::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
if (it->trackId == trexIt->getTrackID()){it->read(*trexIt);}
|
||||||
|
}
|
||||||
|
}
|
||||||
MEDIUM_MSG("Read moov box");
|
MEDIUM_MSG("Read moov box");
|
||||||
}
|
}
|
||||||
if (boxType == "moof"){
|
if (boxType == "moof"){
|
||||||
|
@ -262,6 +268,12 @@ namespace Mist{
|
||||||
mp4Headers.rbegin()->read(*trakIt);
|
mp4Headers.rbegin()->read(*trakIt);
|
||||||
mp4PacksLeft += mp4Headers.rbegin()->size();
|
mp4PacksLeft += mp4Headers.rbegin()->size();
|
||||||
}
|
}
|
||||||
|
std::deque<MP4::TREX> trex = ((MP4::MOOV*)&moovBox)->getChild<MP4::MVEX>().getChildren<MP4::TREX>();
|
||||||
|
for (std::deque<MP4::TREX>::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = mp4Headers.begin(); it != mp4Headers.end(); ++it){
|
||||||
|
if (it->trackId == trexIt->getTrackID()){it->read(*trexIt);}
|
||||||
|
}
|
||||||
|
}
|
||||||
MEDIUM_MSG("Read moov box");
|
MEDIUM_MSG("Read moov box");
|
||||||
}
|
}
|
||||||
offset += boxSize;
|
offset += boxSize;
|
||||||
|
|
|
@ -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!)
|
// 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);
|
hdrs[tHdr.trackId].read(*trakIt);
|
||||||
}
|
}
|
||||||
|
std::deque<MP4::TREX> trex = ((MP4::MOOV*)&mp4Data)->getChild<MP4::MVEX>().getChildren<MP4::TREX>();
|
||||||
|
for (std::deque<MP4::TREX>::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 we stored an mdat earlier, we can now analyse and then wipe it
|
||||||
if (mdat.size()){
|
if (mdat.size()){
|
||||||
MP4::Box mdatBox(mdat, false);
|
MP4::Box mdatBox(mdat, false);
|
||||||
|
|
|
@ -130,6 +130,12 @@ namespace Mist{
|
||||||
trackHeaders.push_back(MP4::TrackHeader());
|
trackHeaders.push_back(MP4::TrackHeader());
|
||||||
trackHeaders.rbegin()->read(*trakIt);
|
trackHeaders.rbegin()->read(*trakIt);
|
||||||
}
|
}
|
||||||
|
std::deque<MP4::TREX> trex = ((MP4::MOOV*)&moovBox)->getChild<MP4::MVEX>().getChildren<MP4::TREX>();
|
||||||
|
for (std::deque<MP4::TREX>::iterator trexIt = trex.begin(); trexIt != trex.end(); trexIt++){
|
||||||
|
for (std::deque<MP4::TrackHeader>::iterator it = trackHeaders.begin(); it != trackHeaders.end(); it++){
|
||||||
|
if (it->trackId == trexIt->getTrackID()){it->read(*trexIt);}
|
||||||
|
}
|
||||||
|
}
|
||||||
hasMoov = true;
|
hasMoov = true;
|
||||||
}
|
}
|
||||||
activityCounter = Util::bootSecs();
|
activityCounter = Util::bootSecs();
|
||||||
|
|
Loading…
Add table
Reference in a new issue