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:
parent
e641793195
commit
211d9eac30
2 changed files with 69 additions and 21 deletions
24
lib/url.cpp
24
lib/url.cpp
|
@ -87,7 +87,9 @@ HTTP::URL::URL(const std::string &url){
|
||||||
path.erase(prevslash + 1, path.length());
|
path.erase(prevslash + 1, path.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path = Encodings::URL::decode(path);
|
if (!isLocalPath()){
|
||||||
|
path = Encodings::URL::decode(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// user, pass, host and port are now definitely between proto_sep and first_slash
|
// user, pass, host and port are now definitely between proto_sep and first_slash
|
||||||
|
@ -196,6 +198,8 @@ std::string HTTP::URL::getUrl() const{
|
||||||
ret += "/";
|
ret += "/";
|
||||||
if (protocol == "rtsp"){
|
if (protocol == "rtsp"){
|
||||||
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
|
||||||
|
}else if (isLocalPath()){
|
||||||
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]+ ");}
|
||||||
}else{
|
}else{
|
||||||
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
|
||||||
}
|
}
|
||||||
|
@ -238,6 +242,8 @@ std::string HTTP::URL::getProxyUrl() const{
|
||||||
ret += "/";
|
ret += "/";
|
||||||
if (protocol == "rtsp"){
|
if (protocol == "rtsp"){
|
||||||
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
|
||||||
|
}else if (isLocalPath()){
|
||||||
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]+ ");}
|
||||||
}else{
|
}else{
|
||||||
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +271,8 @@ std::string HTTP::URL::getBareUrl() const{
|
||||||
ret += "/";
|
ret += "/";
|
||||||
if (protocol == "rtsp"){
|
if (protocol == "rtsp"){
|
||||||
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]#?&");}
|
||||||
|
}else if (isLocalPath()){
|
||||||
|
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]+ ");}
|
||||||
}else{
|
}else{
|
||||||
if (path.size()){ret += Encodings::URL::encode(path, "/:=@[]");}
|
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
|
/// 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 HTTP::URL::getBase() const{
|
||||||
std::string tmpUrl = getBareUrl();
|
std::string tmpUrl;
|
||||||
|
if (isLocalPath()){
|
||||||
|
tmpUrl = getFilePath();
|
||||||
|
}else{
|
||||||
|
tmpUrl = getBareUrl();
|
||||||
|
}
|
||||||
size_t slashPos = tmpUrl.rfind('/');
|
size_t slashPos = tmpUrl.rfind('/');
|
||||||
if (slashPos == std::string::npos){
|
if (slashPos == std::string::npos){
|
||||||
tmpUrl += "/";
|
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
|
/// If the given URL is in a parent directory of the URL, it will be relative
|
||||||
/// Otherwise, it will be absolute
|
/// Otherwise, it will be absolute
|
||||||
std::string HTTP::URL::getLinkFrom(const HTTP::URL & fromUrl) const{
|
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();
|
std::string from = fromUrl.getBase();
|
||||||
if (to.substr(0, from.size()) == from){
|
if (to.substr(0, from.size()) == from){
|
||||||
return to.substr(from.size());
|
return to.substr(from.size());
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <mist/util.h>
|
#include <mist/util.h>
|
||||||
#include <mist/urireader.h>
|
#include <mist/urireader.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
|
#include <mist/encode.h>
|
||||||
|
|
||||||
/*LTS-START*/
|
/*LTS-START*/
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
@ -1360,12 +1361,33 @@ namespace Mist{
|
||||||
if (origTargetPtr){
|
if (origTargetPtr){
|
||||||
origTarget = origTargetPtr;
|
origTarget = origTargetPtr;
|
||||||
if (origTarget.rfind('?') != std::string::npos){
|
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('?'));
|
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")){
|
}else if (config->hasOption("target")){
|
||||||
origTarget = config->getString("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")){
|
if (targetParams.count("maxEntries")){
|
||||||
maxEntries = atoll(targetParams["maxEntries"].c_str());
|
maxEntries = atoll(targetParams["maxEntries"].c_str());
|
||||||
}
|
}
|
||||||
|
@ -1380,7 +1402,9 @@ namespace Mist{
|
||||||
if (!systemBoot){systemBoot = (Util::unixMS() - Util::bootMS());}
|
if (!systemBoot){systemBoot = (Util::unixMS() - Util::bootMS());}
|
||||||
// Create a new or connect to an existing playlist file
|
// Create a new or connect to an existing playlist file
|
||||||
if (!plsConn){
|
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()){
|
if (playlistLocation.isLocalPath()){
|
||||||
playlistLocationString = playlistLocation.getFilePath();
|
playlistLocationString = playlistLocation.getFilePath();
|
||||||
INFO_MSG("Segmenting to local playlist '%s'", playlistLocationString.c_str());
|
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());
|
INFO_MSG("Appending to existing remote playlist file '%s'", playlistLocationString.c_str());
|
||||||
}else{
|
}else{
|
||||||
WARN_MSG("Overwriting existing remote playlist file '%s'", playlistLocationString.c_str());
|
WARN_MSG("Overwriting existing remote playlist file '%s'", playlistLocationString.c_str());
|
||||||
|
reInitPlaylist = true;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
INFO_MSG("Creating new remote playlist file '%s'", playlistLocationString.c_str());
|
INFO_MSG("Creating new remote playlist file '%s'", playlistLocationString.c_str());
|
||||||
|
reInitPlaylist = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1510,7 +1536,9 @@ namespace Mist{
|
||||||
std::string newTarget = origTarget;
|
std::string newTarget = origTarget;
|
||||||
Util::replace(newTarget, "$currentMediaTime", JSON::Value(currentStartTime).asString());
|
Util::replace(newTarget, "$currentMediaTime", JSON::Value(currentStartTime).asString());
|
||||||
Util::replace(newTarget, "$segmentCounter", JSON::Value(segmentCount).asString());
|
Util::replace(newTarget, "$segmentCounter", JSON::Value(segmentCount).asString());
|
||||||
|
Util::streamVariables(newTarget, streamName);
|
||||||
currentTarget = newTarget;
|
currentTarget = newTarget;
|
||||||
|
config->getOption("target", true).append(currentTarget);
|
||||||
if (newTarget == "-"){
|
if (newTarget == "-"){
|
||||||
INFO_MSG("Outputting %s to stdout with %s format", streamName.c_str(),
|
INFO_MSG("Outputting %s to stdout with %s format", streamName.c_str(),
|
||||||
capa["name"].asString().c_str());
|
capa["name"].asString().c_str());
|
||||||
|
@ -1649,7 +1677,7 @@ namespace Mist{
|
||||||
if (!M.getLive()){
|
if (!M.getLive()){
|
||||||
uint64_t unixMs = M.getBootMsOffset() + systemBoot + currentStartTime;
|
uint64_t unixMs = M.getBootMsOffset() + systemBoot + currentStartTime;
|
||||||
reinitPlaylist(playlistBuffer, targetAge, maxEntries, segmentCount, segmentsRemoved, unixMs, targetDuration, playlistLocation);
|
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
|
// If we are appending to an existing playlist, we need to recover the playlistBuffer and reopen the playlist
|
||||||
HTTP::URIReader inFile(playlistLocationString);
|
HTTP::URIReader inFile(playlistLocationString);
|
||||||
char *newBuffer;
|
char *newBuffer;
|
||||||
|
@ -1661,7 +1689,7 @@ namespace Mist{
|
||||||
reinitPlaylist(playlistBuffer, targetAge, maxEntries, segmentCount, segmentsRemoved, unixMs, targetDuration, playlistLocation);
|
reinitPlaylist(playlistBuffer, targetAge, maxEntries, segmentCount, segmentsRemoved, unixMs, targetDuration, playlistLocation);
|
||||||
connectToFile(playlistLocationString, false, &plsConn);
|
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
|
// Remove older entries in the playlist
|
||||||
if (maxEntries || targetAge){
|
if (maxEntries || targetAge){
|
||||||
|
@ -1682,20 +1710,22 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of filenames written, so that they can be added to the playlist file
|
// 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;
|
currentStartTime = lastPacketTime;
|
||||||
segmentCount++;
|
segmentCount++;
|
||||||
// Replace variable currentMediaTime and segmentCounter
|
Util::replace(newTarget, "$currentMediaTime", JSON::Value(currentStartTime).asString());
|
||||||
if (targetParams.count("m3u8")){
|
Util::replace(newTarget, "$segmentCounter", JSON::Value(segmentCount).asString());
|
||||||
if (newTarget.find("$currentMediaTime") == std::string::npos && newTarget.find("$segmentCounter") == std::string::npos){
|
Util::streamVariables(newTarget, streamName);
|
||||||
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());
|
|
||||||
}
|
|
||||||
if (newTarget.rfind('?') != std::string::npos){
|
if (newTarget.rfind('?') != std::string::npos){
|
||||||
newTarget.erase(newTarget.rfind('?'));
|
newTarget.erase(newTarget.rfind('?'));
|
||||||
}
|
}
|
||||||
|
@ -1752,8 +1782,8 @@ namespace Mist{
|
||||||
onFinish();
|
onFinish();
|
||||||
// Write last segment
|
// Write last segment
|
||||||
if (targetParams.count("m3u8")){
|
if (targetParams.count("m3u8")){
|
||||||
// If this is VOD, we can finally open up the connection to the playlist file
|
// If this is a non-live source, we can finally open up the connection to the playlist file
|
||||||
if (M.getVod()){connectToFile(playlistLocationString, false, &plsConn);}
|
if (!M.getLive()){connectToFile(playlistLocationString, false, &plsConn);}
|
||||||
if (plsConn){
|
if (plsConn){
|
||||||
std::string segment = HTTP::URL(currentTarget).getLinkFrom(playlistLocation);
|
std::string segment = HTTP::URL(currentTarget).getLinkFrom(playlistLocation);
|
||||||
if (M.getLive()){
|
if (M.getLive()){
|
||||||
|
|
Loading…
Add table
Reference in a new issue