Various improvements and simplifications to HLS
This commit is contained in:
		
							parent
							
								
									224e3a3f0d
								
							
						
					
					
						commit
						54d927c9df
					
				
					 1 changed files with 46 additions and 66 deletions
				
			
		|  | @ -5,12 +5,10 @@ | ||||||
| namespace Mist { | namespace Mist { | ||||||
|   bool OutHLS::isReadyForPlay() { |   bool OutHLS::isReadyForPlay() { | ||||||
|     if (myMeta.tracks.size()){ |     if (myMeta.tracks.size()){ | ||||||
|       for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){ |       if (myMeta.mainTrack().fragments.size() > 4){ | ||||||
|         if (it->second.fragments.size() >= 3){ |  | ||||||
|         return true; |         return true; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -57,9 +55,12 @@ namespace Mist { | ||||||
|     updateMeta(); |     updateMeta(); | ||||||
|     std::stringstream result; |     std::stringstream result; | ||||||
|     //parse single track
 |     //parse single track
 | ||||||
|     result << "#EXTM3U\r\n#EXT-X-TARGETDURATION:" << (myMeta.tracks[tid].biggestFragment() / 1000) + 1 << "\r\n"; |     uint32_t target_dur = (myMeta.tracks[tid].biggestFragment() / 1000) + 1; | ||||||
|  |     result << "#EXTM3U\r\n#EXT-X-VERSION:3\r\n#EXT-X-TARGETDURATION:" << target_dur << "\r\n"; | ||||||
| 
 | 
 | ||||||
|     std::deque<std::string> lines; |     std::deque<std::string> lines; | ||||||
|  |     std::deque<uint16_t> durs; | ||||||
|  |     uint32_t total_dur = 0; | ||||||
|     for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); it != myMeta.tracks[tid].fragments.end(); it++) { |     for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); it != myMeta.tracks[tid].fragments.end(); it++) { | ||||||
|       long long int starttime = myMeta.tracks[tid].getKey(it->getNumber()).getTime(); |       long long int starttime = myMeta.tracks[tid].getKey(it->getNumber()).getTime(); | ||||||
|       long long duration = it->getDuration(); |       long long duration = it->getDuration(); | ||||||
|  | @ -68,16 +69,27 @@ namespace Mist { | ||||||
|       } |       } | ||||||
|       char lineBuf[400]; |       char lineBuf[400]; | ||||||
|       if (sessId.size()){ |       if (sessId.size()){ | ||||||
|         snprintf(lineBuf, 400, "#EXTINF:%lld, no desc\r\n%lld_%lld.ts?sessId=%s\r\n", ((duration + 500) / 1000), starttime, starttime + duration, sessId.c_str()); |         snprintf(lineBuf, 400, "#EXTINF:%f,\r\n%lld_%lld.ts?sessId=%s\r\n", (double)duration/1000, starttime, starttime + duration, sessId.c_str()); | ||||||
|       }else{ |       }else{ | ||||||
|         snprintf(lineBuf, 400, "#EXTINF:%lld, no desc\r\n%lld_%lld.ts\r\n", ((duration + 500) / 1000), starttime, starttime + duration); |         snprintf(lineBuf, 400, "#EXTINF:%f,\r\n%lld_%lld.ts\r\n", (double)duration/1000, starttime, starttime + duration); | ||||||
|       } |       } | ||||||
|  |       durs.push_back(duration); | ||||||
|  |       total_dur += duration; | ||||||
|       lines.push_back(lineBuf); |       lines.push_back(lineBuf); | ||||||
|     } |     } | ||||||
|     unsigned int skippedLines = 0; |     unsigned int skippedLines = 0; | ||||||
|     if (myMeta.live && lines.size()) { |     if (myMeta.live && lines.size()) { | ||||||
|       //only print the last segment when VoD
 |       //only print the last segment when VoD
 | ||||||
|       lines.pop_back(); |       lines.pop_back(); | ||||||
|  |       total_dur -= durs.back(); | ||||||
|  |       durs.pop_back(); | ||||||
|  |       //skip the first two segments when live, unless that brings us under 4 target durations
 | ||||||
|  |       while ((total_dur-durs.front()) > (target_dur * 4000) && skippedLines < 2) { | ||||||
|  |         lines.pop_front(); | ||||||
|  |         total_dur -= durs.front(); | ||||||
|  |         durs.pop_front(); | ||||||
|  |         ++skippedLines; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     result << "#EXT-X-MEDIA-SEQUENCE:" << myMeta.tracks[tid].missedFrags + skippedLines << "\r\n"; |     result << "#EXT-X-MEDIA-SEQUENCE:" << myMeta.tracks[tid].missedFrags + skippedLines << "\r\n"; | ||||||
|  | @ -86,7 +98,7 @@ namespace Mist { | ||||||
|       result << lines.front(); |       result << lines.front(); | ||||||
|       lines.pop_front(); |       lines.pop_front(); | ||||||
|     } |     } | ||||||
|     if ( !myMeta.live){ |     if (!myMeta.live || total_dur == 0) { | ||||||
|       result << "#EXT-X-ENDLIST\r\n"; |       result << "#EXT-X-ENDLIST\r\n"; | ||||||
|     } |     } | ||||||
|     DEBUG_MSG(DLVL_HIGH, "Sending this index: %s", result.str().c_str()); |     DEBUG_MSG(DLVL_HIGH, "Sending this index: %s", result.str().c_str()); | ||||||
|  | @ -114,24 +126,6 @@ namespace Mist { | ||||||
|     capa["methods"][0u]["priority"] = 9ll; |     capa["methods"][0u]["priority"] = 9ll; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   int OutHLS::canSeekms(unsigned int ms){ |  | ||||||
|     //no tracks? Frame too new by definition.
 |  | ||||||
|     if ( !myMeta.tracks.size()){ |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|     //check main track
 |  | ||||||
|     DTSC::Track & mainTrack = myMeta.tracks[*selectedTracks.begin()]; |  | ||||||
|     //return "too late" if one track is past this point
 |  | ||||||
|     if (ms < mainTrack.firstms){ |  | ||||||
|       return -1; |  | ||||||
|     } |  | ||||||
|     //return "too early" if one track is not yet at this point
 |  | ||||||
|     if (ms > mainTrack.lastms){ |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   void OutHLS::onHTTP() { |   void OutHLS::onHTTP() { | ||||||
|     std::string method = H.method; |     std::string method = H.method; | ||||||
|     std::string sessId = H.GetVar("sessId"); |     std::string sessId = H.GetVar("sessId"); | ||||||
|  | @ -207,37 +201,22 @@ namespace Mist { | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       //Keep a reference to the main track
 | ||||||
|  |       //This is called vidTrack, even for audio-only streams
 | ||||||
|  |       DTSC::Track & Trk = myMeta.tracks[vidTrack]; | ||||||
|  | 
 | ||||||
|       if (myMeta.live) { |       if (myMeta.live) { | ||||||
|         unsigned int timeout = 0; |         if (from < Trk.firstms){ | ||||||
|         int seekable; |  | ||||||
|         do { |  | ||||||
|           seekable = canSeekms(from); |  | ||||||
|           /// \todo Detection of out-of-range parts.
 |  | ||||||
|           if (seekable > 0){ |  | ||||||
|             //time out after 21 seconds
 |  | ||||||
|             if (++timeout > 42){ |  | ||||||
|               myConn.close(); |  | ||||||
|               break; |  | ||||||
|             } |  | ||||||
|             Util::wait(500); |  | ||||||
|             updateMeta(); |  | ||||||
|           } |  | ||||||
|         }while (myConn && seekable > 0); |  | ||||||
|         if (seekable < 0){ |  | ||||||
|           H.Clean(); |           H.Clean(); | ||||||
|           H.setCORSHeaders(); |           H.setCORSHeaders(); | ||||||
|           H.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); |           H.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); | ||||||
|           myConn.SendNow(H.BuildResponse("412", "Fragment out of range")); |           myConn.SendNow(H.BuildResponse("404", "Fragment out of range")); | ||||||
|           H.Clean(); //clean for any possible next requests
 |           H.Clean(); //clean for any possible next requests
 | ||||||
|           DEBUG_MSG(DLVL_WARN, "Fragment @ %llu too old", from); |           WARN_MSG("Fragment @ %llu too old", from); | ||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       seek(from); |  | ||||||
|       ts_from = from; |  | ||||||
|       lastVid = from * 90; |  | ||||||
|        |  | ||||||
|       H.Clean(); |       H.Clean(); | ||||||
|       H.SetHeader("Content-Type", "video/mp2t"); |       H.SetHeader("Content-Type", "video/mp2t"); | ||||||
|       H.setCORSHeaders(); |       H.setCORSHeaders(); | ||||||
|  | @ -246,22 +225,18 @@ namespace Mist { | ||||||
|         H.Clean(); |         H.Clean(); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       H.StartResponse(H, myConn, VLCworkaround); |  | ||||||
| 
 | 
 | ||||||
|       unsigned int fragCounter = myMeta.tracks[vidTrack].missedFrags; |       H.StartResponse(H, myConn, VLCworkaround); | ||||||
|       for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[vidTrack].fragments.begin(); it != myMeta.tracks[vidTrack].fragments.end(); it++){ |       //we assume whole fragments - but timestamps may be altered at will
 | ||||||
|         long long int starttime = myMeta.tracks[vidTrack].getKey(it->getNumber()).getTime();         |       uint32_t fragIndice = Trk.timeToFragnum(from); | ||||||
|         if (starttime <= from && starttime + it->getDuration() > from){ |       contCounters[0] = Trk.missedFrags + fragIndice;   //PAT continuity counter
 | ||||||
|           EXTREME_MSG("setting continuity counter for PAT/PMT to %d",fragCounter); |       contCounters[4096] = Trk.missedFrags + fragIndice; //PMT continuity counter
 | ||||||
|           contCounters[0]=fragCounter;     //PAT continuity counter
 |  | ||||||
|           contCounters[4096]=fragCounter;  //PMT continuity counter
 |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         ++fragCounter; |  | ||||||
|       } |  | ||||||
|       packCounter = 0; |       packCounter = 0; | ||||||
|       parseData = true; |       parseData = true; | ||||||
|       wantRequest = false; |       wantRequest = false; | ||||||
|  |       seek(from); | ||||||
|  |       ts_from = from; | ||||||
|  |       lastVid = from * 90; | ||||||
|     } else { |     } else { | ||||||
|       initialize(); |       initialize(); | ||||||
|       std::string request = H.url.substr(H.url.find("/", 5) + 1); |       std::string request = H.url.substr(H.url.find("/", 5) + 1); | ||||||
|  | @ -273,6 +248,11 @@ namespace Mist { | ||||||
|       } |       } | ||||||
|       H.SetHeader("Cache-Control", "no-cache"); |       H.SetHeader("Cache-Control", "no-cache"); | ||||||
|       H.setCORSHeaders(); |       H.setCORSHeaders(); | ||||||
|  |       if (!myMeta.tracks.size()){ | ||||||
|  |         H.SendResponse("404", "Not online or found", myConn); | ||||||
|  |         H.Clean(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|       if(method == "OPTIONS" || method == "HEAD"){ |       if(method == "OPTIONS" || method == "HEAD"){ | ||||||
|         H.SendResponse("200", "OK", myConn); |         H.SendResponse("200", "OK", myConn); | ||||||
|         H.Clean(); |         H.Clean(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thulinma
						Thulinma