mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 15:30:00 +01:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
1
Mixer.h
1
Mixer.h
@@ -122,7 +122,6 @@ protected:
|
||||
Session *back_session_;
|
||||
std::list<Session *> garbage_;
|
||||
bool sessionSwapRequested_;
|
||||
bool sessionNameChanged_;
|
||||
void swap();
|
||||
|
||||
SourceList candidate_sources_;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
protected:
|
||||
// result created session
|
||||
Session *session_;
|
||||
std::string sessionFilePath_;
|
||||
// parsing current xml
|
||||
tinyxml2::XMLElement *xmlCurrent_;
|
||||
// level of loading recursion
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user