Bug Fix: CMAF DASH playback works
- syntax error fixed - removed unnecessary track id simplification
This commit is contained in:
		
							parent
							
								
									e9d5920a80
								
							
						
					
					
						commit
						ccee512b3d
					
				
					 2 changed files with 43 additions and 49 deletions
				
			
		
							
								
								
									
										46
									
								
								lib/cmaf.cpp
									
										
									
									
									
								
							
							
						
						
									
										46
									
								
								lib/cmaf.cpp
									
										
									
									
									
								
							| 
						 | 
					@ -13,14 +13,6 @@ namespace CMAF{
 | 
				
			||||||
    return payloadSize;
 | 
					    return payloadSize;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  size_t simplifiedTrackId(const DTSC::Meta & M, size_t idx) {
 | 
					 | 
				
			||||||
    std::string type = M.getType(idx);
 | 
					 | 
				
			||||||
    if (type == "video") {return 1;}
 | 
					 | 
				
			||||||
    if (type == "audio") {return 2;}
 | 
					 | 
				
			||||||
    if (type == "meta") {return 3;}
 | 
					 | 
				
			||||||
    return idx;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::string trackHeader(const DTSC::Meta &M, size_t track, bool simplifyTrackIds){
 | 
					  std::string trackHeader(const DTSC::Meta &M, size_t track, bool simplifyTrackIds){
 | 
				
			||||||
    std::string tType = M.getType(track);
 | 
					    std::string tType = M.getType(track);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,9 +35,6 @@ namespace CMAF{
 | 
				
			||||||
    MP4::TRAK trakBox;
 | 
					    MP4::TRAK trakBox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MP4::TKHD tkhdBox(M, track);
 | 
					    MP4::TKHD tkhdBox(M, track);
 | 
				
			||||||
    if (simplifyTrackIds){
 | 
					 | 
				
			||||||
      tkhdBox.setTrackID(simplifiedTrackId(M, track));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    tkhdBox.setDuration(0);
 | 
					    tkhdBox.setDuration(0);
 | 
				
			||||||
    trakBox.setContent(tkhdBox, 0);
 | 
					    trakBox.setContent(tkhdBox, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -131,9 +120,6 @@ namespace CMAF{
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MP4::TREX trexBox(track + 1);
 | 
					    MP4::TREX trexBox(track + 1);
 | 
				
			||||||
    if (simplifyTrackIds){
 | 
					 | 
				
			||||||
      trexBox.setTrackID(simplifiedTrackId(M, track));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    trexBox.setDefaultSampleDuration(1000);
 | 
					    trexBox.setDefaultSampleDuration(1000);
 | 
				
			||||||
    mvexBox.setContent(trexBox, M.getVod() ? 1 : 0);
 | 
					    mvexBox.setContent(trexBox, M.getVod() ? 1 : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,7 +134,8 @@ namespace CMAF{
 | 
				
			||||||
      MP4::SIDX sidxBox;
 | 
					      MP4::SIDX sidxBox;
 | 
				
			||||||
      sidxBox.setReferenceID(track + 1);
 | 
					      sidxBox.setReferenceID(track + 1);
 | 
				
			||||||
      sidxBox.setTimescale(1000);
 | 
					      sidxBox.setTimescale(1000);
 | 
				
			||||||
      sidxBox.setEarliestPresentationTime(keys.getTime(0) + parts.getOffset(0) - M.getFirstms(track));
 | 
					      sidxBox.setEarliestPresentationTime(keys.getTime(0) + parts.getOffset(0) -
 | 
				
			||||||
 | 
					                                          M.getFirstms(track));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (size_t i = 0; i < fragments.getEndValid(); i++){
 | 
					      for (size_t i = 0; i < fragments.getEndValid(); i++){
 | 
				
			||||||
        size_t firstKey = fragments.getFirstKey(i);
 | 
					        size_t firstKey = fragments.getFirstKey(i);
 | 
				
			||||||
| 
						 | 
					@ -156,9 +143,12 @@ namespace CMAF{
 | 
				
			||||||
            ((i + 1 < fragments.getEndValid()) ? fragments.getFirstKey(i + 1) : keys.getEndValid());
 | 
					            ((i + 1 < fragments.getEndValid()) ? fragments.getFirstKey(i + 1) : keys.getEndValid());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MP4::sidxReference refItem;
 | 
					        MP4::sidxReference refItem;
 | 
				
			||||||
        refItem.referencedSize = payloadSize(M, track, keys.getTime(firstKey), keys.getTime(endKey)) + keyHeaderSize(M, track, i) + 8;
 | 
					        refItem.referencedSize =
 | 
				
			||||||
 | 
					            payloadSize(M, track, keys.getTime(firstKey), keys.getTime(endKey)) +
 | 
				
			||||||
 | 
					            keyHeaderSize(M, track, i) + 8;
 | 
				
			||||||
        refItem.subSegmentDuration =
 | 
					        refItem.subSegmentDuration =
 | 
				
			||||||
            (endKey == keys.getEndValid() ? M.getLastms(track) : keys.getTime(endKey)) - keys.getTime(firstKey);
 | 
					            (endKey == keys.getEndValid() ? M.getLastms(track) : keys.getTime(endKey)) -
 | 
				
			||||||
 | 
					            keys.getTime(firstKey);
 | 
				
			||||||
        refItem.sapStart = true;
 | 
					        refItem.sapStart = true;
 | 
				
			||||||
        refItem.sapType = 16;
 | 
					        refItem.sapType = 16;
 | 
				
			||||||
        refItem.sapDeltaTime = 0;
 | 
					        refItem.sapDeltaTime = 0;
 | 
				
			||||||
| 
						 | 
					@ -209,7 +199,8 @@ namespace CMAF{
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Generates the 'moof' box for a DTSC::Key based CMAF fragment.
 | 
					  /// Generates the 'moof' box for a DTSC::Key based CMAF fragment.
 | 
				
			||||||
  std::string keyHeader(const DTSC::Meta &M, size_t track, uint64_t startTime, uint64_t endTime, uint64_t segmentNum, bool simplifyTrackIds, bool UTCTime){
 | 
					  std::string keyHeader(const DTSC::Meta &M, size_t track, uint64_t startTime, uint64_t endTime,
 | 
				
			||||||
 | 
					                        uint64_t segmentNum, bool simplifyTrackIds, bool UTCTime){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t firstPart = M.getPartIndex(startTime, track);
 | 
					    size_t firstPart = M.getPartIndex(startTime, track);
 | 
				
			||||||
    size_t endPart = M.getPartIndex(endTime, track);
 | 
					    size_t endPart = M.getPartIndex(endTime, track);
 | 
				
			||||||
| 
						 | 
					@ -218,7 +209,6 @@ namespace CMAF{
 | 
				
			||||||
    MP4::MFHD mfhdBox(segmentNum);
 | 
					    MP4::MFHD mfhdBox(segmentNum);
 | 
				
			||||||
    moofBox.setContent(mfhdBox, 0);
 | 
					    moofBox.setContent(mfhdBox, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::set<sortPart> trunOrder;
 | 
					    std::set<sortPart> trunOrder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // We use keyHeaderSize here to determine the relative offsets of the data in the 'mdat' box.
 | 
					    // We use keyHeaderSize here to determine the relative offsets of the data in the 'mdat' box.
 | 
				
			||||||
| 
						 | 
					@ -242,12 +232,10 @@ namespace CMAF{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tfhdBox.setFlags(MP4::tfhdSampleFlag | MP4::tfhdBaseIsMoof | MP4::tfhdSampleDesc);
 | 
					    tfhdBox.setFlags(MP4::tfhdSampleFlag | MP4::tfhdBaseIsMoof | MP4::tfhdSampleDesc);
 | 
				
			||||||
    tfhdBox.setTrackID(track + 1);
 | 
					    tfhdBox.setTrackID(track + 1);
 | 
				
			||||||
    if (simplifyTrackIds){
 | 
					 | 
				
			||||||
      tfhdBox.setTrackID(simplifiedTrackId(M, track));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    tfhdBox.setDefaultSampleDuration(444);
 | 
					    tfhdBox.setDefaultSampleDuration(444);
 | 
				
			||||||
    tfhdBox.setDefaultSampleSize(444);
 | 
					    tfhdBox.setDefaultSampleSize(444);
 | 
				
			||||||
    tfhdBox.setDefaultSampleFlags((M.getType(track) == "video") ? (MP4::noIPicture | MP4::noKeySample)
 | 
					    tfhdBox.setDefaultSampleFlags((M.getType(track) == "video")
 | 
				
			||||||
 | 
					                                      ? (MP4::noIPicture | MP4::noKeySample)
 | 
				
			||||||
                                      : (MP4::isIPicture | MP4::isKeySample));
 | 
					                                      : (MP4::isIPicture | MP4::isKeySample));
 | 
				
			||||||
    tfhdBox.setSampleDescriptionIndex(1);
 | 
					    tfhdBox.setSampleDescriptionIndex(1);
 | 
				
			||||||
    trafBox.setContent(tfhdBox, 0);
 | 
					    trafBox.setContent(tfhdBox, 0);
 | 
				
			||||||
| 
						 | 
					@ -256,7 +244,8 @@ namespace CMAF{
 | 
				
			||||||
    if (M.getVod()){
 | 
					    if (M.getVod()){
 | 
				
			||||||
      tfdtBox.setBaseMediaDecodeTime(startTime - M.getFirstms(track));
 | 
					      tfdtBox.setBaseMediaDecodeTime(startTime - M.getFirstms(track));
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      tfdtBox.setBaseMediaDecodeTime((UTCTime ? startTime + M.getBootMsOffset() + unixBootDiff : startTime));
 | 
					      tfdtBox.setBaseMediaDecodeTime(
 | 
				
			||||||
 | 
					          (UTCTime ? startTime + M.getBootMsOffset() + unixBootDiff : startTime));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    trafBox.setContent(tfdtBox, 1);
 | 
					    trafBox.setContent(tfdtBox, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -277,15 +266,14 @@ namespace CMAF{
 | 
				
			||||||
        MP4::trunSampleInformation sampleInfo;
 | 
					        MP4::trunSampleInformation sampleInfo;
 | 
				
			||||||
        sampleInfo.sampleSize = parts.getSize(it->partIndex);
 | 
					        sampleInfo.sampleSize = parts.getSize(it->partIndex);
 | 
				
			||||||
        sampleInfo.sampleDuration = parts.getDuration(it->partIndex);
 | 
					        sampleInfo.sampleDuration = parts.getDuration(it->partIndex);
 | 
				
			||||||
        if (it == lastOne){
 | 
					        if (it == lastOne){sampleInfo.sampleDuration = endTime - it->time;}
 | 
				
			||||||
          sampleInfo.sampleDuration = endTime - it->time;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        sampleInfo.sampleOffset = parts.getOffset(it->partIndex);
 | 
					        sampleInfo.sampleOffset = parts.getOffset(it->partIndex);
 | 
				
			||||||
        trunBox.setSampleInformation(sampleInfo, trunOffset++);
 | 
					        trunBox.setSampleInformation(sampleInfo, trunOffset++);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      WARN_MSG("Empty CMAF header for track %zu: %" PRIu64 "-%" PRIu64 " contains no packets (first: %" PRIu64
 | 
					      WARN_MSG("Empty CMAF header for track %zu: %" PRIu64 "-%" PRIu64
 | 
				
			||||||
               ", last: %" PRIu64 "), firstPart=%zu, lastPart=%zu",
 | 
					               " contains no packets (first: %" PRIu64 ", last: %" PRIu64
 | 
				
			||||||
 | 
					               "), firstPart=%zu, lastPart=%zu",
 | 
				
			||||||
               track, startTime, endTime, M.getFirstms(track), M.getLastms(track), firstPart,
 | 
					               track, startTime, endTime, M.getFirstms(track), M.getLastms(track), firstPart,
 | 
				
			||||||
               endPart);
 | 
					               endPart);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -489,32 +489,32 @@ namespace Mist{
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void OutCMAF::generateSegmentlist(size_t idx, std::stringstream &s,
 | 
					  void OutCMAF::generateSegmentlist(size_t idx, std::stringstream &s,
 | 
				
			||||||
                                    void callBack(uint64_t, uint64_t, std::stringstream &, bool)){
 | 
					                                    void dashSegmentCallBack(uint64_t, uint64_t,
 | 
				
			||||||
    DTSC::Fragments fragments(M.fragments(idx));
 | 
					                                                             std::stringstream &, bool)){
 | 
				
			||||||
 | 
					    // NOTE: Weirdly making the 0th track as the reference track fixed everything.
 | 
				
			||||||
 | 
					    // Looks like a nomenclature issue.
 | 
				
			||||||
 | 
					    // TODO: Investigate with spec and refactor stuff appropriately.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t mainTrack = *M.getValidTracks().begin(); // M.mainTrack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mainTrack == INVALID_TRACK_ID){return;}
 | 
				
			||||||
 | 
					    DTSC::Fragments fragments(M.fragments(mainTrack));
 | 
				
			||||||
    uint32_t firstFragment = fragments.getFirstValid();
 | 
					    uint32_t firstFragment = fragments.getFirstValid();
 | 
				
			||||||
    uint32_t lastFragment = fragments.getEndValid();
 | 
					    uint32_t lastFragment = fragments.getEndValid();
 | 
				
			||||||
    bool first = true;
 | 
					    bool first = true;
 | 
				
			||||||
    // skip the first two fragments if live
 | 
					    // skip the first two fragments if live
 | 
				
			||||||
    if (M.getLive() && (lastFragment - firstFragment) > 6){firstFragment += 2;}
 | 
					    if (M.getLive() && (lastFragment - firstFragment) > 6){firstFragment += 2;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (M.getType(idx) == "audio"){
 | 
					    DTSC::Keys keys(M.keys(mainTrack));
 | 
				
			||||||
      uint32_t mainTrack = M.mainTrack();
 | 
					 | 
				
			||||||
      if (mainTrack == INVALID_TRACK_ID){return;}
 | 
					 | 
				
			||||||
      DTSC::Fragments f(M.fragments(mainTrack));
 | 
					 | 
				
			||||||
      uint64_t firstVidTime = M.getTimeForFragmentIndex(mainTrack, f.getFirstValid());
 | 
					 | 
				
			||||||
      firstFragment = M.getFragmentIndexForTime(idx, firstVidTime);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DTSC::Keys keys(M.keys(idx));
 | 
					 | 
				
			||||||
    for (; firstFragment < lastFragment; ++firstFragment){
 | 
					    for (; firstFragment < lastFragment; ++firstFragment){
 | 
				
			||||||
      uint32_t duration = fragments.getDuration(firstFragment);
 | 
					      uint32_t duration = fragments.getDuration(firstFragment);
 | 
				
			||||||
      uint64_t starttime = keys.getTime(fragments.getFirstKey(firstFragment));
 | 
					      uint64_t starttime = keys.getTime(fragments.getFirstKey(firstFragment));
 | 
				
			||||||
      if (!duration){
 | 
					      if (!duration){
 | 
				
			||||||
        if (M.getLive()){continue;}// skip last fragment when live
 | 
					        if (M.getLive()){continue;}// skip last fragment when live
 | 
				
			||||||
        duration = M.getLastms(idx) - starttime;
 | 
					        duration = M.getLastms(mainTrack) - starttime;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (M.getVod()){starttime -= M.getFirstms(idx);}
 | 
					      if (M.getVod()){starttime -= M.getFirstms(mainTrack);}
 | 
				
			||||||
      callBack(starttime, duration, s, first);
 | 
					      dashSegmentCallBack(starttime, duration, s, first);
 | 
				
			||||||
      first = false;
 | 
					      first = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -662,7 +662,7 @@ namespace Mist{
 | 
				
			||||||
         it++){
 | 
					         it++){
 | 
				
			||||||
      if (M.getType(it->first) == "video"){vTracks.insert(it->first);}
 | 
					      if (M.getType(it->first) == "video"){vTracks.insert(it->first);}
 | 
				
			||||||
      if (M.getType(it->first) == "audio"){aTracks.insert(it->first);}
 | 
					      if (M.getType(it->first) == "audio"){aTracks.insert(it->first);}
 | 
				
			||||||
      if (M.getType(it->first) == "subtitle"){sTracks.insert(it->first);}
 | 
					      if (M.getCodec(it->first) == "subtitle"){sTracks.insert(it->first);}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!vTracks.size() && !aTracks.size()){return "";}
 | 
					    if (!vTracks.size() && !aTracks.size()){return "";}
 | 
				
			||||||
| 
						 | 
					@ -685,12 +685,18 @@ namespace Mist{
 | 
				
			||||||
        << "\" suggestedPresentationDelay=\"PT5.0S\" minBufferTime=\"PT2.0S\" publishTime=\""
 | 
					        << "\" suggestedPresentationDelay=\"PT5.0S\" minBufferTime=\"PT2.0S\" publishTime=\""
 | 
				
			||||||
        << Util::getUTCString(Util::epoch()) << "\" ";
 | 
					        << Util::getUTCString(Util::epoch()) << "\" ";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    r << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
 | 
				
			||||||
 | 
					    r << "xmlns:xlink=\"http://www.w3.org/1999/xlink\" ";
 | 
				
			||||||
 | 
					    r << "xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 "
 | 
				
			||||||
 | 
					         "http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/"
 | 
				
			||||||
 | 
					         "DASH-MPD.xsd\" ";
 | 
				
			||||||
    r << "profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" "
 | 
					    r << "profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" "
 | 
				
			||||||
         "xmlns=\"urn:mpeg:dash:schema:mpd:2011\" >"
 | 
					         "xmlns=\"urn:mpeg:dash:schema:mpd:2011\" >"
 | 
				
			||||||
      << std::endl;
 | 
					      << std::endl;
 | 
				
			||||||
    r << "<ProgramInformation><Title>" << streamName << "</Title></ProgramInformation>"
 | 
					    r << "<ProgramInformation><Title>" << streamName << "</Title></ProgramInformation>"
 | 
				
			||||||
      << std::endl;
 | 
					      << std::endl;
 | 
				
			||||||
    r << "<Period " << (M.getLive() ? "start=\"0\"" : "") << ">" << std::endl;
 | 
					    r << "<Period " << (M.getLive() ? "start=\"PT0.0S\"" : "") << ">" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dashAdaptation(1, vTracks, videoAligned, r);
 | 
					    dashAdaptation(1, vTracks, videoAligned, r);
 | 
				
			||||||
    dashAdaptation(2, aTracks, audioAligned, r);
 | 
					    dashAdaptation(2, aTracks, audioAligned, r);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue