From 37cbafe2848dedd668526796dd06ae39a71ebc19 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 22 Oct 2020 17:52:39 +0200 Subject: [PATCH] Fixed/improved HLS subtitle support --- src/output/output_hls.cpp | 18 ++++++++++++------ src/output/output_srt.cpp | 6 ++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/output/output_hls.cpp b/src/output/output_hls.cpp index d2819002..ffc8e7f6 100644 --- a/src/output/output_hls.cpp +++ b/src/output/output_hls.cpp @@ -72,9 +72,14 @@ namespace Mist{ } 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; // 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 << (M.getEncryption(tid) == "" ? "3" : "5"); @@ -90,20 +95,20 @@ namespace Mist{ std::deque lines; std::deque durations; uint32_t totalDuration = 0; - DTSC::Keys keys(M.keys(tid)); - DTSC::Fragments fragments(M.fragments(tid)); + DTSC::Keys keys(M.keys(timingTid)); + DTSC::Fragments fragments(M.fragments(timingTid)); uint32_t firstFragment = fragments.getFirstValid(); uint32_t endFragment = fragments.getEndValid(); for (int i = firstFragment; i < endFragment; i++){ uint64_t duration = fragments.getDuration(i); size_t keyNumber = fragments.getFirstKey(i); 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; char lineBuf[400]; 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); }else{ if (sessId.size()){ @@ -146,7 +151,7 @@ namespace Mist{ /*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::iterator it = lines.begin(); it != lines.end(); it++){ result << *it; @@ -179,6 +184,7 @@ namespace Mist{ capa["codecs"][0u][4u].append("+MP3"); capa["codecs"][0u][5u].append("+AC3"); capa["codecs"][0u][6u].append("+MP2"); + capa["codecs"][0u][6u].append("+subtitle"); capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["type"] = "html5/application/vnd.apple.mpegurl"; capa["methods"][0u]["priority"] = 9; diff --git a/src/output/output_srt.cpp b/src/output/output_srt.cpp index 5523ed60..c9ef92d9 100644 --- a/src/output/output_srt.cpp +++ b/src/output/output_srt.cpp @@ -15,6 +15,7 @@ namespace Mist{ capa["desc"] = "Pseudostreaming in SubRip Text (SRT) and WebVTT formats over HTTP"; capa["url_match"].append("/$.srt"); capa["url_match"].append("/$.vtt"); + capa["url_match"].append("/$.webvtt"); capa["codecs"][0u][0u].append("subtitle"); capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["type"] = "html5/text/plain"; @@ -23,7 +24,7 @@ namespace Mist{ capa["methods"][1u]["handler"] = "http"; capa["methods"][1u]["type"] = "html5/text/vtt"; capa["methods"][1u]["priority"] = 9; - capa["methods"][1u]["url_rel"] = "/$.vtt"; + capa["methods"][1u]["url_rel"] = "/$.webvtt"; } void OutSRT::sendNext(){ @@ -78,7 +79,7 @@ namespace Mist{ void OutSRT::onHTTP(){ 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") != ""){ size_t tid = atoll(H.GetVar("track").c_str()); 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("to") != ""){filter_to = JSON::Value(H.GetVar("to")).asInt();} + if (filter_to){realTime = 0;} H.Clean(); H.setCORSHeaders();