diff --git a/GstToolkit.cpp b/GstToolkit.cpp index 24be3ea..ea753db 100644 --- a/GstToolkit.cpp +++ b/GstToolkit.cpp @@ -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; } diff --git a/MediaPlayer.cpp b/MediaPlayer.cpp index 423cd46..6e3f496 100644 --- a/MediaPlayer.cpp +++ b/MediaPlayer.cpp @@ -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(); diff --git a/Mixer.cpp b/Mixer.cpp index 9a12a76..dc1d07b 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -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(); } diff --git a/Mixer.h b/Mixer.h index 88ad30e..7000886 100644 --- a/Mixer.h +++ b/Mixer.h @@ -122,7 +122,6 @@ protected: Session *back_session_; std::list garbage_; bool sessionSwapRequested_; - bool sessionNameChanged_; void swap(); SourceList candidate_sources_; diff --git a/SessionCreator.cpp b/SessionCreator.cpp index daeadb0..ca7b027 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -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); } } diff --git a/SessionCreator.h b/SessionCreator.h index a2a769d..d34241b 100644 --- a/SessionCreator.h +++ b/SessionCreator.h @@ -67,6 +67,7 @@ public: protected: // result created session Session *session_; + std::string sessionFilePath_; // parsing current xml tinyxml2::XMLElement *xmlCurrent_; // level of loading recursion diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index cc9ebd5..ea76088 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -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 ); diff --git a/SessionVisitor.h b/SessionVisitor.h index e2a4c8b..d447c67 100644 --- a/SessionVisitor.h +++ b/SessionVisitor.h @@ -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); diff --git a/SystemToolkit.cpp b/SystemToolkit.cpp index 16be2ac..ad97329 100644 --- a/SystemToolkit.cpp +++ b/SystemToolkit.cpp @@ -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& 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; +} diff --git a/SystemToolkit.h b/SystemToolkit.h index bc6db6f..fc51892 100644 --- a/SystemToolkit.h +++ b/SystemToolkit.h @@ -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);