Various improvements and simplifications to HLS

This commit is contained in:
Thulinma 2016-10-11 16:14:27 +02:00
parent 224e3a3f0d
commit 54d927c9df

View file

@ -5,10 +5,8 @@
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,10 +55,13 @@ 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;
for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); it != myMeta.tracks[tid].fragments.end(); it++){ 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++) {
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();
if (duration <= 0){ if (duration <= 0){
@ -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,25 +126,7 @@ namespace Mist {
capa["methods"][0u]["priority"] = 9ll; capa["methods"][0u]["priority"] = 9ll;
} }
int OutHLS::canSeekms(unsigned int ms){ void OutHLS::onHTTP() {
//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(){
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 {
} }
} }
if (myMeta.live){ //Keep a reference to the main track
unsigned int timeout = 0; //This is called vidTrack, even for audio-only streams
int seekable; DTSC::Track & Trk = myMeta.tracks[vidTrack];
do {
seekable = canSeekms(from); if (myMeta.live) {
/// \todo Detection of out-of-range parts. if (from < Trk.firstms){
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,23 +225,19 @@ 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;
}else{ seek(from);
ts_from = from;
lastVid = from * 90;
} 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);
H.Clean(); H.Clean();
@ -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();