Various fixes to generic segmenter code

Segmenter: when using the external writer, do not re-open a playlist to adjust the target duration
Segmenter: edit comments and fix logic for opening the playlist with streams which are live and vod at the same time
Segmenter: fix init of playlist data when using an external writer
This commit is contained in:
Marco van Dijk 2023-01-25 16:14:29 +01:00 committed by Thulinma
parent e641793195
commit 211d9eac30
2 changed files with 69 additions and 21 deletions

View file

@ -87,9 +87,11 @@ HTTP::URL::URL(const std::string &url){
path.erase(prevslash + 1, path.length());
}
}
if (!isLocalPath()){
path = Encodings::URL::decode(path);
}
}
}
// user, pass, host and port are now definitely between proto_sep and first_slash
std::string uphp = url.substr(proto_sep, first_slash - proto_sep); // user+pass+host+port
// Check if we have a user/pass before the host
@ -196,6 +198,8 @@ std::string HTTP::URL::getUrl() const{
ret += "/";
if (protocol == "rtsp"){
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
}else if (isLocalPath()){
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]+ ");}
}else{
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
}
@ -238,6 +242,8 @@ std::string HTTP::URL::getProxyUrl() const{
ret += "/";
if (protocol == "rtsp"){
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
}else if (isLocalPath()){
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]+ ");}
}else{
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
}
@ -265,6 +271,8 @@ std::string HTTP::URL::getBareUrl() const{
ret += "/";
if (protocol == "rtsp"){
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
}else if (isLocalPath()){
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]+ ");}
}else{
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
}
@ -273,7 +281,12 @@ std::string HTTP::URL::getBareUrl() const{
/// Returns a string guaranteed to end in a slash, pointing to the base directory-equivalent of the URL
std::string HTTP::URL::getBase() const{
std::string tmpUrl = getBareUrl();
std::string tmpUrl;
if (isLocalPath()){
tmpUrl = getFilePath();
}else{
tmpUrl = getBareUrl();
}
size_t slashPos = tmpUrl.rfind('/');
if (slashPos == std::string::npos){
tmpUrl += "/";
@ -287,7 +300,12 @@ std::string HTTP::URL::getBase() const{
/// If the given URL is in a parent directory of the URL, it will be relative
/// Otherwise, it will be absolute
std::string HTTP::URL::getLinkFrom(const HTTP::URL & fromUrl) const{
std::string to = getUrl();
std::string to;
if (isLocalPath()){
to = getFilePath();
}else{
to = getUrl();
}
std::string from = fromUrl.getBase();
if (to.substr(0, from.size()) == from){
return to.substr(from.size());

View file

@ -19,6 +19,7 @@
#include <mist/util.h>
#include <mist/urireader.h>
#include <sys/file.h>
#include <mist/encode.h>
/*LTS-START*/
#include <arpa/inet.h>
@ -1360,12 +1361,33 @@ namespace Mist{
if (origTargetPtr){
origTarget = origTargetPtr;
if (origTarget.rfind('?') != std::string::npos){
std::map<std::string, std::string> tmpParams;
HTTP::parseVars(origTarget.substr(origTarget.rfind('?') + 1), tmpParams);
origTarget.erase(origTarget.rfind('?'));
if (tmpParams.count("m3u8")){
targetParams["m3u8"] = tmpParams["m3u8"];
}
if (tmpParams.count("segment")){
targetParams["segment"] = tmpParams["segment"];
}
}
}else if (config->hasOption("target")){
origTarget = config->getString("target");
}
Util::streamVariables(origTarget, streamName);
// Check if the target segment contains any of the required variables
if (targetParams.count("m3u8")){
std::string tmpTarget;
if (targetParams.count("segment")){
tmpTarget = targetParams["segment"];
}else{
tmpTarget = origTarget;
}
if (tmpTarget.find("$currentMediaTime") == std::string::npos && tmpTarget.find("$segmentCounter") == std::string::npos){
FAIL_MSG("Target segmented output does not contain a currentMediaTime or segmentCounter: %s", tmpTarget.c_str());
Util::logExitReason("Target segmented output does not contain a currentMediaTime or segmentCounter: %s", tmpTarget.c_str());
return 1;
}
}
if (targetParams.count("maxEntries")){
maxEntries = atoll(targetParams["maxEntries"].c_str());
}
@ -1380,7 +1402,9 @@ namespace Mist{
if (!systemBoot){systemBoot = (Util::unixMS() - Util::bootMS());}
// Create a new or connect to an existing playlist file
if (!plsConn){
playlistLocation = HTTP::URL(origTarget).link(targetParams["m3u8"]);
std::string plsRel = targetParams["m3u8"];
Util::streamVariables(plsRel, streamName);
playlistLocation = HTTP::URL(config->getString("target")).link(plsRel);
if (playlistLocation.isLocalPath()){
playlistLocationString = playlistLocation.getFilePath();
INFO_MSG("Segmenting to local playlist '%s'", playlistLocationString.c_str());
@ -1455,9 +1479,11 @@ namespace Mist{
INFO_MSG("Appending to existing remote playlist file '%s'", playlistLocationString.c_str());
}else{
WARN_MSG("Overwriting existing remote playlist file '%s'", playlistLocationString.c_str());
reInitPlaylist = true;
}
}else{
INFO_MSG("Creating new remote playlist file '%s'", playlistLocationString.c_str());
reInitPlaylist = true;
}
}
}
@ -1510,7 +1536,9 @@ namespace Mist{
std::string newTarget = origTarget;
Util::replace(newTarget, "$currentMediaTime", JSON::Value(currentStartTime).asString());
Util::replace(newTarget, "$segmentCounter", JSON::Value(segmentCount).asString());
Util::streamVariables(newTarget, streamName);
currentTarget = newTarget;
config->getOption("target", true).append(currentTarget);
if (newTarget == "-"){
INFO_MSG("Outputting %s to stdout with %s format", streamName.c_str(),
capa["name"].asString().c_str());
@ -1649,7 +1677,7 @@ namespace Mist{
if (!M.getLive()){
uint64_t unixMs = M.getBootMsOffset() + systemBoot + currentStartTime;
reinitPlaylist(playlistBuffer, targetAge, maxEntries, segmentCount, segmentsRemoved, unixMs, targetDuration, playlistLocation);
}else if (!maxEntries && !targetAge){
}else if (!maxEntries && !targetAge && playlistLocation.isLocalPath()){
// If we are appending to an existing playlist, we need to recover the playlistBuffer and reopen the playlist
HTTP::URIReader inFile(playlistLocationString);
char *newBuffer;
@ -1661,7 +1689,7 @@ namespace Mist{
reinitPlaylist(playlistBuffer, targetAge, maxEntries, segmentCount, segmentsRemoved, unixMs, targetDuration, playlistLocation);
connectToFile(playlistLocationString, false, &plsConn);
}
// Else we are in a sliding window playlist, so it will already get overwritten
// Else we are in a sliding window playlist, so it will automatically get overwritten
}
// Remove older entries in the playlist
if (maxEntries || targetAge){
@ -1682,20 +1710,22 @@ namespace Mist{
}
// Keep track of filenames written, so that they can be added to the playlist file
std::string newTarget = origTarget;
std::string newTarget;
if (targetParams.count("segment")){
HTTP::URL targetUrl = HTTP::URL(config->getString("target")).link(targetParams["segment"]);
if (targetUrl.isLocalPath()){
newTarget = targetUrl.getFilePath();
}else{
newTarget = targetUrl.getUrl();
}
}else{
newTarget = origTarget;
}
currentStartTime = lastPacketTime;
segmentCount++;
// Replace variable currentMediaTime and segmentCounter
if (targetParams.count("m3u8")){
if (newTarget.find("$currentMediaTime") == std::string::npos && newTarget.find("$segmentCounter") == std::string::npos){
FAIL_MSG("Target segmented output does not contain a currentMediaTime or segmentCounter: %s", newTarget.c_str());
Util::logExitReason("Target segmented output does not contain a currentMediaTime or segmentCounter: %s", newTarget.c_str());
onFinish();
break;
}
Util::replace(newTarget, "$currentMediaTime", JSON::Value(currentStartTime).asString());
Util::replace(newTarget, "$segmentCounter", JSON::Value(segmentCount).asString());
}
Util::streamVariables(newTarget, streamName);
if (newTarget.rfind('?') != std::string::npos){
newTarget.erase(newTarget.rfind('?'));
}
@ -1752,8 +1782,8 @@ namespace Mist{
onFinish();
// Write last segment
if (targetParams.count("m3u8")){
// If this is VOD, we can finally open up the connection to the playlist file
if (M.getVod()){connectToFile(playlistLocationString, false, &plsConn);}
// If this is a non-live source, we can finally open up the connection to the playlist file
if (!M.getLive()){connectToFile(playlistLocationString, false, &plsConn);}
if (plsConn){
std::string segment = HTTP::URL(currentTarget).getLinkFrom(playlistLocation);
if (M.getLive()){