Support for relative path for files in mix

File path in mix session file add a relative reference to the location of the session mix file. If SessionCreator cannot find the absolute path, it tries to load the file at the relative location. Done for MediaSource, SessionFileSource and SequenceSource.
This commit is contained in:
Bruno
2021-07-30 00:22:44 +02:00
parent fc91e7cbdd
commit d2a576c99c
10 changed files with 165 additions and 75 deletions

View File

@@ -58,11 +58,13 @@ string GstToolkit::time_to_string(guint64 t, time_string_mode m)
std::string GstToolkit::filename_to_uri(std::string path) std::string GstToolkit::filename_to_uri(std::string path)
{ {
if (path.empty())
return path;
// set uri to open // set uri to open
gchar *uritmp = gst_filename_to_uri(path.c_str(), NULL); gchar *uritmp = gst_filename_to_uri(path.c_str(), NULL);
std::string uri( uritmp ); std::string uri( uritmp );
g_free(uritmp); g_free(uritmp);
return uri; return uri;
} }

View File

@@ -232,6 +232,9 @@ void MediaPlayer::open (const std::string & filename, const string &uri)
else else
uri_ = uri; uri_ = uri;
if (uri_.empty())
failed_ = true;
// close before re-openning // close before re-openning
if (isOpen()) if (isOpen())
close(); close();

View File

@@ -117,7 +117,8 @@ void Mixer::update()
// check status of loader: did it finish ? // check status of loader: did it finish ?
if (sessionLoaders_.back().wait_for(timeout_) == std::future_status::ready ) { if (sessionLoaders_.back().wait_for(timeout_) == std::future_status::ready ) {
// get the session loaded by this loader // get the session loaded by this loader
set( sessionLoaders_.back().get() ); if (sessionLoaders_.back().valid())
set( sessionLoaders_.back().get() );
// done with this session loader // done with this session loader
sessionLoaders_.pop_back(); sessionLoaders_.pop_back();
} }

View File

@@ -122,7 +122,6 @@ protected:
Session *back_session_; Session *back_session_;
std::list<Session *> garbage_; std::list<Session *> garbage_;
bool sessionSwapRequested_; bool sessionSwapRequested_;
bool sessionNameChanged_;
void swap(); void swap();
SourceList candidate_sources_; SourceList candidate_sources_;

View File

@@ -99,6 +99,7 @@ void SessionCreator::load(const std::string& filename)
loadConfig( xmlDoc_.FirstChildElement("Views") ); loadConfig( xmlDoc_.FirstChildElement("Views") );
// ready to read sources // ready to read sources
sessionFilePath_ = SystemToolkit::path_filename(filename);
SessionLoader::load( xmlDoc_.FirstChildElement("Session") ); SessionLoader::load( xmlDoc_.FirstChildElement("Session") );
// create groups // create groups
@@ -344,8 +345,13 @@ void SessionLoader::load(XMLElement *sessionNode)
SourceList::iterator origin; SourceList::iterator origin;
if (id_origin_ > 0) if (id_origin_ > 0)
origin = session_->find(id_origin_); origin = session_->find(id_origin_);
else else {
origin = session_->find( std::string ( originNode->GetText() ) ); const char *text = originNode->GetText();
if (text)
origin = session_->find( std::string(text) );
else
origin = session_->end();
}
// found the orign source // found the orign source
if (origin != session_->end()) { if (origin != session_->end()) {
// create a new source of type Clone // create a new source of type Clone
@@ -829,12 +835,27 @@ void SessionLoader::visit (Source& s)
void SessionLoader::visit (MediaSource& s) void SessionLoader::visit (MediaSource& s)
{ {
// set uri // set uri
XMLElement* uriNode = xmlCurrent_->FirstChildElement("uri"); XMLElement* pathNode = xmlCurrent_->FirstChildElement("uri"); // TODO change to "path" but keep backward compatibility
if (uriNode) { if (pathNode) {
std::string uri = std::string ( uriNode->GetText() ); const char * text = pathNode->GetText();
// load only new files if (text) {
if ( uri != s.path() ) std::string path(text);
s.setPath(uri); // load only new files
if ( path.compare(s.path()) != 0 ) {
if ( !SystemToolkit::file_exists(path)){
const char * relative;
if ( pathNode->QueryStringAttribute("relative", &relative) == XML_SUCCESS) {
std::string rel = SystemToolkit::path_absolute_from_path(std::string( relative ), sessionFilePath_);
Log::Info("File %s not found; Trying %s instead.", path.c_str(), rel.c_str());
path = rel;
}
}
s.setPath(path);
}
}
// ensures the source is initialized even if no valid path is given
else
s.setPath("");
} }
// set config media player // set config media player
@@ -850,10 +871,22 @@ void SessionLoader::visit (SessionFileSource& s)
// set uri // set uri
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path"); XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
if (pathNode) { if (pathNode) {
std::string path = std::string ( pathNode->GetText() ); const char * text = pathNode->GetText();
// load only new files if (text) {
if ( path != s.path() ) std::string path(text);
s.load(path, recursion_ + 1); // load only new files
if ( path != s.path() ) {
if ( !SystemToolkit::file_exists(path)){
const char * relative;
if ( pathNode->QueryStringAttribute("relative", &relative) == XML_SUCCESS) {
std::string rel = SystemToolkit::path_absolute_from_path(std::string( relative ), sessionFilePath_);
Log::Info("File %s not found; Trying %s instead.", path.c_str(), rel.c_str());
path = rel;
}
}
s.load(path, recursion_ + 1);
}
}
} }
} }
@@ -921,38 +954,56 @@ void SessionLoader::visit (MultiFileSource& s)
if (seq) { if (seq) {
MultiFileSequence sequence; MultiFileSequence sequence;
sequence.location = std::string ( seq->GetText() );
seq->QueryIntAttribute("min", &sequence.min);
seq->QueryIntAttribute("max", &sequence.max);
seq->QueryUnsignedAttribute("width", &sequence.width);
seq->QueryUnsignedAttribute("height", &sequence.height);
const char *codec = seq->Attribute("codec");
if (codec)
sequence.codec = std::string(codec);
uint fps = 0; const char *text = seq->GetText();
seq->QueryUnsignedAttribute("fps", &fps); if (text) {
sequence.location = std::string (text);
// different sequence // fix path if absolute path is not found
if ( sequence != s.sequence() ) { std::string folder = SystemToolkit::path_filename(sequence.location);
s.setSequence( sequence, fps); std::string dir = SystemToolkit::path_directory(folder);
if ( dir.empty() ){
const char * relative;
if ( seq->QueryStringAttribute("relative", &relative) == XML_SUCCESS) {
std::string rel = SystemToolkit::path_absolute_from_path(std::string(relative), sessionFilePath_);
Log::Info("Folder %s not found; Trying %s instead.", folder.c_str(), rel.c_str());
sequence.location = rel;
}
}
// set sequence parameters
seq->QueryIntAttribute("min", &sequence.min);
seq->QueryIntAttribute("max", &sequence.max);
seq->QueryUnsignedAttribute("width", &sequence.width);
seq->QueryUnsignedAttribute("height", &sequence.height);
const char *codec = seq->Attribute("codec");
if (codec)
sequence.codec = std::string(codec);
uint fps = 0;
seq->QueryUnsignedAttribute("fps", &fps);
// different sequence
if ( sequence != s.sequence() ) {
s.setSequence( sequence, fps);
}
// same sequence, different framerate
else if ( fps != s.framerate() ) {
s.setFramerate( fps );
}
int begin = -1;
seq->QueryIntAttribute("begin", &begin);
int end = INT_MAX;
seq->QueryIntAttribute("end", &end);
if ( begin != s.begin() || end != s.end() )
s.setRange(begin, end);
bool loop = true;
seq->QueryBoolAttribute("loop", &loop);
if ( loop != s.loop() )
s.setLoop(loop);
} }
// same sequence, different framerate
else if ( fps != s.framerate() ) {
s.setFramerate( fps );
}
int begin = -1;
seq->QueryIntAttribute("begin", &begin);
int end = INT_MAX;
seq->QueryIntAttribute("end", &end);
if ( begin != s.begin() || end != s.end() )
s.setRange(begin, end);
bool loop = true;
seq->QueryBoolAttribute("loop", &loop);
if ( loop != s.loop() )
s.setLoop(loop);
} }
} }

View File

@@ -67,6 +67,7 @@ public:
protected: protected:
// result created session // result created session
Session *session_; Session *session_;
std::string sessionFilePath_;
// parsing current xml // parsing current xml
tinyxml2::XMLElement *xmlCurrent_; tinyxml2::XMLElement *xmlCurrent_;
// level of loading recursion // level of loading recursion

View File

@@ -46,6 +46,7 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
XMLElement *sessionNode = xmlDoc.NewElement("Session"); XMLElement *sessionNode = xmlDoc.NewElement("Session");
xmlDoc.InsertEndChild(sessionNode); xmlDoc.InsertEndChild(sessionNode);
SessionVisitor sv(&xmlDoc, sessionNode); SessionVisitor sv(&xmlDoc, sessionNode);
sv.sessionFilePath_ = SystemToolkit::path_filename(filename);
for (auto iter = session->begin(); iter != session->end(); ++iter, sv.setRoot(sessionNode) ) for (auto iter = session->begin(); iter != session->end(); ++iter, sv.setRoot(sessionNode) )
// source visitor // source visitor
(*iter)->accept(sv); (*iter)->accept(sv);
@@ -549,6 +550,9 @@ void SessionVisitor::visit (MediaSource& s)
XMLText *text = xmlDoc_->NewText( s.path().c_str() ); XMLText *text = xmlDoc_->NewText( s.path().c_str() );
uri->InsertEndChild( text ); uri->InsertEndChild( text );
if (!sessionFilePath_.empty())
uri->SetAttribute("relative", SystemToolkit::path_relative_to_path(s.path(), sessionFilePath_).c_str());
s.mediaplayer()->accept(*this); s.mediaplayer()->accept(*this);
} }
@@ -562,6 +566,9 @@ void SessionVisitor::visit (SessionFileSource& s)
xmlCurrent_->InsertEndChild(path); xmlCurrent_->InsertEndChild(path);
XMLText *text = xmlDoc_->NewText( s.path().c_str() ); XMLText *text = xmlDoc_->NewText( s.path().c_str() );
path->InsertEndChild( text ); path->InsertEndChild( text );
if (!sessionFilePath_.empty())
path->SetAttribute("relative", SystemToolkit::path_relative_to_path(s.path(), sessionFilePath_).c_str());
} }
void SessionVisitor::visit (SessionGroupSource& s) void SessionVisitor::visit (SessionGroupSource& s)
@@ -648,6 +655,10 @@ void SessionVisitor::visit (MultiFileSource& s)
sequence->SetAttribute("width", s.sequence().width); sequence->SetAttribute("width", s.sequence().width);
sequence->SetAttribute("height", s.sequence().height); sequence->SetAttribute("height", s.sequence().height);
sequence->SetAttribute("codec", s.sequence().codec.c_str()); sequence->SetAttribute("codec", s.sequence().codec.c_str());
if (!sessionFilePath_.empty())
sequence->SetAttribute("relative", SystemToolkit::path_relative_to_path(s.sequence().location, sessionFilePath_).c_str());
XMLText *location = xmlDoc_->NewText( s.sequence().location.c_str() ); XMLText *location = xmlDoc_->NewText( s.sequence().location.c_str() );
sequence->InsertEndChild( location ); sequence->InsertEndChild( location );

View File

@@ -13,6 +13,7 @@ class SessionVisitor : public Visitor {
bool recursive_; bool recursive_;
tinyxml2::XMLDocument *xmlDoc_; tinyxml2::XMLDocument *xmlDoc_;
tinyxml2::XMLElement *xmlCurrent_; tinyxml2::XMLElement *xmlCurrent_;
std::string sessionFilePath_;
static void saveConfig(tinyxml2::XMLDocument *doc, Session *session); static void saveConfig(tinyxml2::XMLDocument *doc, Session *session);
static void saveSnapshots(tinyxml2::XMLDocument *doc, Session *session); static void saveSnapshots(tinyxml2::XMLDocument *doc, Session *session);

View File

@@ -336,12 +336,6 @@ void SystemToolkit::execute(const string& command)
bool StringEQ( const std::string& a, const std::string& b )
{
if ( a.size() != b.size() )
return false;
return ( strcmp( a.c_str(), b.c_str() ) == 0 );
}
// 7.3: http://www.oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html // 7.3: http://www.oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
// //
@@ -364,54 +358,79 @@ void Tokenize(const string& str, vector<string>& tokens, const string& delimiter
} }
// //
// "c:\a\b\c" + "c:\a\x\file.txt" => "..\..\x\file.txt"
// http://mrpmorris.blogspot.com/2007/05/convert-absolute-path-to-relative-path.html // http://mrpmorris.blogspot.com/2007/05/convert-absolute-path-to-relative-path.html
// //
string SystemToolkit::path_relative_to_path( const string& absolutePath, const string& relativeTo ) string SystemToolkit::path_relative_to_path( const string& absolutePath, const string& relativeTo )
{ {
const string separator = string(1, PATH_SEP);
string relativePath = "";
vector< string > absoluteDirectories; vector< string > absoluteDirectories;
vector< string > relativeDirectories; vector< string > relativeToDirectories;
Tokenize( absolutePath, absoluteDirectories, "/" ); Tokenize( absolutePath, absoluteDirectories, separator );
Tokenize( relativeTo, relativeDirectories, "/" ); Tokenize( relativeTo, relativeToDirectories, separator );
// Get the shortest of the two paths // Get the shortest of the two paths
size_t length = absoluteDirectories.size() < relativeDirectories.size() ? absoluteDirectories.size() : relativeDirectories.size(); int length = MINI( absoluteDirectories.size(), relativeToDirectories.size() );
// Use to determine where in the loop we exited // Use to determine where in the loop we exited
int lastCommonRoot = -1; int lastCommonRoot = -1;
size_t index; int index = 0;
// Find common root // Find common root
for (index = 0; index < length; ++index) { for (; index < length; ++index) {
if (StringEQ( absoluteDirectories[index], relativeDirectories[index])) if (absoluteDirectories[index].compare(relativeToDirectories[index]) == 0)
lastCommonRoot = index; lastCommonRoot = index;
else else
break; break;
} }
// If we didn't find a common prefix then throw // If we didn't find a common prefix then return base absolute path
if (lastCommonRoot == -1) if (lastCommonRoot < 0)
{ return absolutePath;
assert( 0 ); // "Paths do not have a common base"
return ""; // Add the '..'
for (index = lastCommonRoot + 1; index < relativeToDirectories.size(); ++index) {
if (relativeToDirectories[index].size() > 0)
relativePath += ".." + separator;
} }
string relativePath; // Add the relative folders
for (index = lastCommonRoot + 1; index < absoluteDirectories.size() - 1; ++index) {
// Add on the ..
for (index = lastCommonRoot + 1; index < relativeDirectories.size(); ++index) {
if (relativeDirectories[index].size() > 0)
relativePath += "../";
}
// Add on the folders
for (index = lastCommonRoot + 1; index < absoluteDirectories.size() - 1; ++index)
{
relativePath += absoluteDirectories[index]; relativePath += absoluteDirectories[index];
relativePath += "/"; relativePath += separator;
} }
relativePath += absoluteDirectories[absoluteDirectories.size() - 1]; relativePath += absoluteDirectories[absoluteDirectories.size() - 1];
return relativePath; return relativePath;
} }
std::string SystemToolkit::path_absolute_from_path(const std::string& relativePath, const std::string& relativeTo)
{
const string separator = string(1, PATH_SEP);
string absolutePath = separator;
vector< string > relativeDirectories;
vector< string > relativeToDirectories;
Tokenize( relativePath, relativeDirectories, separator );
Tokenize( relativeTo, relativeToDirectories, separator );
// how many ".."
int count_relative = 0;
for (; count_relative < relativeDirectories.size() - 1; ++count_relative) {
if (relativeDirectories[count_relative].compare("..") != 0)
break;
}
// take the left part of relativeTo path
for (int i = 0; i < relativeToDirectories.size() -count_relative; ++i) {
absolutePath += relativeToDirectories[i];
absolutePath += separator;
}
// add the rest of the relative path
for (; count_relative < relativeDirectories.size() - 1; ++count_relative) {
absolutePath += relativeDirectories[count_relative];
absolutePath += separator;
}
absolutePath += relativeDirectories[count_relative];
return absolutePath;
}

View File

@@ -53,6 +53,8 @@ namespace SystemToolkit
std::string path_relative_to_path(const std::string& absolutePath, const std::string& relativeTo); std::string path_relative_to_path(const std::string& absolutePath, const std::string& relativeTo);
std::string path_absolute_from_path(const std::string& relativePath, const std::string& relativeTo);
// true of file exists // true of file exists
bool file_exists(const std::string& path); bool file_exists(const std::string& path);