mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 23:40:02 +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)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
1
Mixer.h
1
Mixer.h
@@ -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_;
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user