From e53b14365c5cb1953a3791f4b0790da004679419 Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Tue, 8 May 2018 15:28:33 +0200 Subject: [PATCH] Fixed ELST box in mp4, and use it to fix track desync issues. --- lib/mp4_generic.cpp | 28 ++++++++++---------- src/output/output_progressive_mp4.cpp | 37 +++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp index b211eea1..3f0398b7 100644 --- a/lib/mp4_generic.cpp +++ b/lib/mp4_generic.cpp @@ -3763,57 +3763,57 @@ namespace MP4 { void ELST::setSegmentDuration(uint32_t cnt, uint64_t newVal) { if (getVersion() == 1) { - setInt64(newVal, 28*cnt+8); + setInt64(newVal, 20*cnt+8); } else { - setInt32(newVal, 20*cnt+8); + setInt32(newVal, 12*cnt+8); } } uint64_t ELST::getSegmentDuration(uint32_t cnt) { if (getVersion() == 1) { - return getInt64(28*cnt+8); + return getInt64(20*cnt+8); } else { - return getInt32(20*cnt+8); + return getInt32(12*cnt+8); } } void ELST::setMediaTime(uint32_t cnt, uint64_t newVal) { if (getVersion() == 1) { - setInt64(newVal, 28*cnt+16); + setInt64(newVal, 20*cnt+16); } else { - setInt32(newVal, 20*cnt+12); + setInt32(newVal, 12*cnt+12); } } uint64_t ELST::getMediaTime(uint32_t cnt) { if (getVersion() == 1) { - return getInt64(28*cnt+16); + return getInt64(20*cnt+16); } else { - return getInt32(20*cnt+12); + return getInt32(12*cnt+12); } } void ELST::setMediaRateInteger(uint32_t cnt, uint16_t newVal) { if (getVersion() == 1) { - setInt16(newVal, 28*cnt+24); + setInt16(newVal, 20*cnt+24); } else { - setInt16(newVal, 20*cnt+16); + setInt16(newVal, 12*cnt+16); } } uint16_t ELST::getMediaRateInteger(uint32_t cnt) { if (getVersion() == 1) { - return getInt16(28*cnt+24); + return getInt16(20*cnt+24); } else { - return getInt16(20*cnt+16); + return getInt16(12*cnt+16); } } void ELST::setMediaRateFraction(uint32_t cnt, uint16_t newVal) { if (getVersion() == 1) { - setInt16(newVal, 28*cnt+26); + setInt16(newVal, 20*cnt+26); } else { - setInt16(newVal, 20*cnt+18); + setInt16(newVal, 12*cnt+18); } } diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index dd0b77f2..762943f4 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -45,6 +45,12 @@ namespace Mist{ uint64_t res = 36 // FTYP Box + 8 //MOOV box + 108; //MVHD Box + uint64_t firstms = 0xFFFFFFFFFFFFFFFFull; + for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){ + if (myMeta.tracks[*it].firstms < firstms){ + firstms = myMeta.tracks[*it].firstms; + } + } for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){ DTSC::Track & thisTrack = myMeta.tracks[*it]; uint64_t tmpRes = 0; @@ -59,6 +65,9 @@ namespace Mist{ + 8 //MINF Box + 36 //DINF Box + 8; // STBL Box + if (thisTrack.firstms != firstms){ + tmpRes += 12;// EDTS entry extra + } //These boxes are empty when generating fragmented output tmpRes += 20 + (fragmented ? 0 : (partCount * 4));//STSZ @@ -168,6 +177,7 @@ namespace Mist{ //Construct with duration of -1, as this is the default for fragmented MP4::MVHD mvhdBox(-1); //Then override it only when we are not sending a fragmented file + uint64_t fms; if (!fragmented){ //calculating longest duration uint64_t firstms = 0xFFFFFFFFFFFFFFull; @@ -177,6 +187,7 @@ namespace Mist{ firstms = std::min(firstms, (uint64_t)myMeta.tracks[*it].firstms); } mvhdBox.setDuration(lastms - firstms); + fms = firstms; } //Set the trackid for the first "empty" track within the file. mvhdBox.setTrackID(selectedTracks.size() + 1); @@ -202,11 +213,27 @@ namespace Mist{ MP4::ELST elstBox; elstBox.setVersion(0); elstBox.setFlags(0); - elstBox.setCount(1); - elstBox.setSegmentDuration(0, fragmented ? -1 : tDuration); - elstBox.setMediaTime(0, 0); - elstBox.setMediaRateInteger(0, 1); - elstBox.setMediaRateFraction(0, 0); + if (thisTrack.firstms != fms){ + elstBox.setCount(2); + + elstBox.setSegmentDuration(0, fragmented ? -1 : thisTrack.firstms - fms); + elstBox.setMediaTime(0, 0xFFFFFFFFull); + elstBox.setMediaRateInteger(0, 0); + elstBox.setMediaRateFraction(0, 0); + + elstBox.setSegmentDuration(1, tDuration); + elstBox.setMediaTime(1, 0); + elstBox.setMediaRateInteger(1, 1); + elstBox.setMediaRateFraction(1, 0); + }else{ + elstBox.setCount(1); + + elstBox.setSegmentDuration(0, tDuration); + elstBox.setMediaTime(0, 0); + elstBox.setMediaRateInteger(0, 1); + elstBox.setMediaRateFraction(0, 0); + } + edtsBox.setContent(elstBox, 0); trakBox.setContent(edtsBox, trakOffset++);