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)
{
if (path.empty())
return path;
// set uri to open
gchar *uritmp = gst_filename_to_uri(path.c_str(), NULL);
std::string uri( uritmp );
g_free(uritmp);
return uri;
}

View File

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

View File

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

View File

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

View File

@@ -99,6 +99,7 @@ void SessionCreator::load(const std::string& filename)
loadConfig( xmlDoc_.FirstChildElement("Views") );
// ready to read sources
sessionFilePath_ = SystemToolkit::path_filename(filename);
SessionLoader::load( xmlDoc_.FirstChildElement("Session") );
// create groups
@@ -344,8 +345,13 @@ void SessionLoader::load(XMLElement *sessionNode)
SourceList::iterator origin;
if (id_origin_ > 0)
origin = session_->find(id_origin_);
else
origin = session_->find( std::string ( originNode->GetText() ) );
else {
const char *text = originNode->GetText();
if (text)
origin = session_->find( std::string(text) );
else
origin = session_->end();
}
// found the orign source
if (origin != session_->end()) {
// create a new source of type Clone
@@ -829,12 +835,27 @@ void SessionLoader::visit (Source& s)
void SessionLoader::visit (MediaSource& s)
{
// set uri
XMLElement* uriNode = xmlCurrent_->FirstChildElement("uri");
if (uriNode) {
std::string uri = std::string ( uriNode->GetText() );
// load only new files
if ( uri != s.path() )
s.setPath(uri);
XMLElement* pathNode = xmlCurrent_->FirstChildElement("uri"); // TODO change to "path" but keep backward compatibility
if (pathNode) {
const char * text = pathNode->GetText();
if (text) {
std::string path(text);
// 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
@@ -850,10 +871,22 @@ void SessionLoader::visit (SessionFileSource& s)
// set uri
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
if (pathNode) {
std::string path = std::string ( pathNode->GetText() );
// load only new files
if ( path != s.path() )
s.load(path, recursion_ + 1);
const char * text = pathNode->GetText();
if (text) {
std::string path(text);
// 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) {
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;
seq->QueryUnsignedAttribute("fps", &fps);
const char *text = seq->GetText();
if (text) {
sequence.location = std::string (text);
// different sequence
if ( sequence != s.sequence() ) {
s.setSequence( sequence, fps);
// fix path if absolute path is not found
std::string folder = SystemToolkit::path_filename(sequence.location);
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:
// result created session
Session *session_;
std::string sessionFilePath_;
// parsing current xml
tinyxml2::XMLElement *xmlCurrent_;
// level of loading recursion

View File

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

View File

@@ -13,6 +13,7 @@ class SessionVisitor : public Visitor {
bool recursive_;
tinyxml2::XMLDocument *xmlDoc_;
tinyxml2::XMLElement *xmlCurrent_;
std::string sessionFilePath_;
static void saveConfig(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
//
@@ -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
//
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 > relativeDirectories;
Tokenize( absolutePath, absoluteDirectories, "/" );
Tokenize( relativeTo, relativeDirectories, "/" );
vector< string > relativeToDirectories;
Tokenize( absolutePath, absoluteDirectories, separator );
Tokenize( relativeTo, relativeToDirectories, separator );
// 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
int lastCommonRoot = -1;
size_t index;
int index = 0;
// Find common root
for (index = 0; index < length; ++index) {
if (StringEQ( absoluteDirectories[index], relativeDirectories[index]))
for (; index < length; ++index) {
if (absoluteDirectories[index].compare(relativeToDirectories[index]) == 0)
lastCommonRoot = index;
else
break;
}
// If we didn't find a common prefix then throw
if (lastCommonRoot == -1)
{
assert( 0 ); // "Paths do not have a common base"
return "";
// If we didn't find a common prefix then return base absolute path
if (lastCommonRoot < 0)
return absolutePath;
// Add the '..'
for (index = lastCommonRoot + 1; index < relativeToDirectories.size(); ++index) {
if (relativeToDirectories[index].size() > 0)
relativePath += ".." + separator;
}
string relativePath;
// 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)
{
// Add the relative folders
for (index = lastCommonRoot + 1; index < absoluteDirectories.size() - 1; ++index) {
relativePath += absoluteDirectories[index];
relativePath += "/";
relativePath += separator;
}
relativePath += absoluteDirectories[absoluteDirectories.size() - 1];
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_absolute_from_path(const std::string& relativePath, const std::string& relativeTo);
// true of file exists
bool file_exists(const std::string& path);