Fixed/improved HLS subtitle support

This commit is contained in:
Thulinma 2020-10-22 17:52:39 +02:00
parent 37af199a1c
commit 37cbafe284
2 changed files with 16 additions and 8 deletions

View file

@ -72,9 +72,14 @@ namespace Mist{
} }
std::string OutHLS::liveIndex(size_t tid, const std::string &sessId){ std::string OutHLS::liveIndex(size_t tid, const std::string &sessId){
//Timing track is current track, unless non-video, then time by video track
size_t timingTid = tid;
if (M.getType(timingTid) != "video"){timingTid = M.mainTrack();}
if (timingTid == INVALID_TRACK_ID){timingTid = tid;}
std::stringstream result; std::stringstream result;
// parse single track // parse single track
uint32_t targetDuration = (M.biggestFragment(tid) / 1000) + 1; uint32_t targetDuration = (M.biggestFragment(timingTid) / 1000) + 1;
result << "#EXTM3U\r\n#EXT-X-VERSION:"; result << "#EXTM3U\r\n#EXT-X-VERSION:";
result << (M.getEncryption(tid) == "" ? "3" : "5"); result << (M.getEncryption(tid) == "" ? "3" : "5");
@ -90,20 +95,20 @@ namespace Mist{
std::deque<std::string> lines; std::deque<std::string> lines;
std::deque<uint16_t> durations; std::deque<uint16_t> durations;
uint32_t totalDuration = 0; uint32_t totalDuration = 0;
DTSC::Keys keys(M.keys(tid)); DTSC::Keys keys(M.keys(timingTid));
DTSC::Fragments fragments(M.fragments(tid)); DTSC::Fragments fragments(M.fragments(timingTid));
uint32_t firstFragment = fragments.getFirstValid(); uint32_t firstFragment = fragments.getFirstValid();
uint32_t endFragment = fragments.getEndValid(); uint32_t endFragment = fragments.getEndValid();
for (int i = firstFragment; i < endFragment; i++){ for (int i = firstFragment; i < endFragment; i++){
uint64_t duration = fragments.getDuration(i); uint64_t duration = fragments.getDuration(i);
size_t keyNumber = fragments.getFirstKey(i); size_t keyNumber = fragments.getFirstKey(i);
uint64_t startTime = keys.getTime(keyNumber); uint64_t startTime = keys.getTime(keyNumber);
if (!duration){duration = M.getLastms(tid) - startTime;} if (!duration){duration = M.getLastms(timingTid) - startTime;}
double floatDur = (double)duration / 1000; double floatDur = (double)duration / 1000;
char lineBuf[400]; char lineBuf[400];
if (M.getCodec(tid) == "subtitle"){ if (M.getCodec(tid) == "subtitle"){
snprintf(lineBuf, 400, "#EXTINF:%f,\r\n../../../%s.vtt?track=%zu&from=%" PRIu64 "&to=%" PRIu64 "\r\n", snprintf(lineBuf, 400, "#EXTINF:%f,\r\n../../../%s.webvtt?track=%zu&from=%" PRIu64 "&to=%" PRIu64 "\r\n",
(double)duration / 1000, streamName.c_str(), tid, startTime, startTime + duration); (double)duration / 1000, streamName.c_str(), tid, startTime, startTime + duration);
}else{ }else{
if (sessId.size()){ if (sessId.size()){
@ -146,7 +151,7 @@ namespace Mist{
/*LTS-END*/ /*LTS-END*/
} }
result << "#EXT-X-MEDIA-SEQUENCE:" << M.getMissedFragments(tid) + skippedLines << "\r\n"; result << "#EXT-X-MEDIA-SEQUENCE:" << M.getMissedFragments(timingTid) + skippedLines << "\r\n";
for (std::deque<std::string>::iterator it = lines.begin(); it != lines.end(); it++){ for (std::deque<std::string>::iterator it = lines.begin(); it != lines.end(); it++){
result << *it; result << *it;
@ -179,6 +184,7 @@ namespace Mist{
capa["codecs"][0u][4u].append("+MP3"); capa["codecs"][0u][4u].append("+MP3");
capa["codecs"][0u][5u].append("+AC3"); capa["codecs"][0u][5u].append("+AC3");
capa["codecs"][0u][6u].append("+MP2"); capa["codecs"][0u][6u].append("+MP2");
capa["codecs"][0u][6u].append("+subtitle");
capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["handler"] = "http";
capa["methods"][0u]["type"] = "html5/application/vnd.apple.mpegurl"; capa["methods"][0u]["type"] = "html5/application/vnd.apple.mpegurl";
capa["methods"][0u]["priority"] = 9; capa["methods"][0u]["priority"] = 9;

View file

@ -15,6 +15,7 @@ namespace Mist{
capa["desc"] = "Pseudostreaming in SubRip Text (SRT) and WebVTT formats over HTTP"; capa["desc"] = "Pseudostreaming in SubRip Text (SRT) and WebVTT formats over HTTP";
capa["url_match"].append("/$.srt"); capa["url_match"].append("/$.srt");
capa["url_match"].append("/$.vtt"); capa["url_match"].append("/$.vtt");
capa["url_match"].append("/$.webvtt");
capa["codecs"][0u][0u].append("subtitle"); capa["codecs"][0u][0u].append("subtitle");
capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["handler"] = "http";
capa["methods"][0u]["type"] = "html5/text/plain"; capa["methods"][0u]["type"] = "html5/text/plain";
@ -23,7 +24,7 @@ namespace Mist{
capa["methods"][1u]["handler"] = "http"; capa["methods"][1u]["handler"] = "http";
capa["methods"][1u]["type"] = "html5/text/vtt"; capa["methods"][1u]["type"] = "html5/text/vtt";
capa["methods"][1u]["priority"] = 9; capa["methods"][1u]["priority"] = 9;
capa["methods"][1u]["url_rel"] = "/$.vtt"; capa["methods"][1u]["url_rel"] = "/$.webvtt";
} }
void OutSRT::sendNext(){ void OutSRT::sendNext(){
@ -78,7 +79,7 @@ namespace Mist{
void OutSRT::onHTTP(){ void OutSRT::onHTTP(){
std::string method = H.method; std::string method = H.method;
webVTT = (H.url.find(".vtt") != std::string::npos); webVTT = (H.url.find(".vtt") != std::string::npos) || (H.url.find(".webvtt") != std::string::npos);
if (H.GetVar("track") != ""){ if (H.GetVar("track") != ""){
size_t tid = atoll(H.GetVar("track").c_str()); size_t tid = atoll(H.GetVar("track").c_str());
if (M.getValidTracks().count(tid)){ if (M.getValidTracks().count(tid)){
@ -93,6 +94,7 @@ namespace Mist{
if (H.GetVar("from") != ""){filter_from = JSON::Value(H.GetVar("from")).asInt();} if (H.GetVar("from") != ""){filter_from = JSON::Value(H.GetVar("from")).asInt();}
if (H.GetVar("to") != ""){filter_to = JSON::Value(H.GetVar("to")).asInt();} if (H.GetVar("to") != ""){filter_to = JSON::Value(H.GetVar("to")).asInt();}
if (filter_to){realTime = 0;}
H.Clean(); H.Clean();
H.setCORSHeaders(); H.setCORSHeaders();