Merge branch 'development' into LTS_development
# Conflicts: # src/output/output_hls.cpp
This commit is contained in:
commit
a79f0fc988
1 changed files with 39 additions and 68 deletions
|
@ -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;
|
||||||
|
@ -134,9 +132,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();
|
||||||
|
@ -145,25 +146,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();
|
||||||
/*LTS-START*/
|
total_dur -= durs.back();
|
||||||
if (config->getInteger("listlimit")) {
|
durs.pop_back();
|
||||||
unsigned long listlimit = config->getInteger("listlimit");
|
//skip the first two segments when live, unless that brings us under 4 target durations
|
||||||
while (lines.size() > listlimit) {
|
while ((total_dur-durs.front()) > (target_dur * 4000) && skippedLines < 2) {
|
||||||
lines.pop_front();
|
lines.pop_front();
|
||||||
skippedLines++;
|
total_dur -= durs.front();
|
||||||
}
|
durs.pop_front();
|
||||||
|
++skippedLines;
|
||||||
}
|
}
|
||||||
/*LTS-END*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result << "#EXT-X-MEDIA-SEQUENCE:" << myMeta.tracks[tid].missedFrags + skippedLines << "\r\n";
|
result << "#EXT-X-MEDIA-SEQUENCE:" << myMeta.tracks[tid].missedFrags + skippedLines << "\r\n";
|
||||||
|
@ -172,7 +175,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());
|
||||||
|
@ -273,24 +276,6 @@ namespace Mist {
|
||||||
/*LTS-END*/
|
/*LTS-END*/
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
|
@ -408,37 +393,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();
|
||||||
|
@ -447,22 +417,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);
|
||||||
|
@ -474,6 +440,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
Reference in a new issue