<div dir="ltr"><br>---<br> modules/gui/qt/Makefile.am | 1 +<br> .../qt/components/sout/profile_selector.cpp | 2 +-<br> .../gui/qt/components/sout/sout_widgets.cpp | 1 +<br> modules/gui/qt/dialogs/sout.hpp | 71 +---------<br> modules/gui/qt/util/soutmrl.cpp | 81 +++++++++++<br> modules/gui/qt/util/soutmrl.hpp | 128 ++++++++++++++++++<br> 6 files changed, 213 insertions(+), 71 deletions(-)<br> create mode 100644 modules/gui/qt/util/soutmrl.cpp<br> create mode 100644 modules/gui/qt/util/soutmrl.hpp<br><br>diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am<br>index af4a5d05cc..71f96a5910 100644<br>--- a/modules/gui/qt/Makefile.am<br>+++ b/modules/gui/qt/Makefile.am<br>@@ -186,6 +186,7 @@ libqt_plugin_la_SOURCES = \<br> gui/qt/util/customwidgets.cpp gui/qt/util/customwidgets.hpp \<br> gui/qt/util/searchlineedit.cpp gui/qt/util/searchlineedit.hpp \<br> gui/qt/util/registry.cpp gui/qt/util/registry.hpp \<br>+ gui/qt/util/soutmrl.cpp gui/qt/util/soutmrl.hpp \<br> gui/qt/util/qt_dirs.cpp gui/qt/util/qt_dirs.hpp \<br> gui/qt/util/validators.cpp gui/qt/util/validators.hpp \<br> gui/qt/util/buttons/BrowseButton.cpp \<br>diff --git a/modules/gui/qt/components/sout/profile_selector.cpp b/modules/gui/qt/components/sout/profile_selector.cpp<br>index 586a01f681..55fc5c9c28 100644<br>--- a/modules/gui/qt/components/sout/profile_selector.cpp<br>+++ b/modules/gui/qt/components/sout/profile_selector.cpp<br>@@ -23,7 +23,7 @@<br><br> #include "components/sout/profile_selector.hpp"<br> #include "components/sout/profiles.hpp"<br>-#include "dialogs/sout.hpp"<br>+#include "util/soutmrl.hpp"<br><br> #include <QHBoxLayout><br> #include <QToolButton><br>diff --git a/modules/gui/qt/components/sout/sout_widgets.cpp b/modules/gui/qt/components/sout/sout_widgets.cpp<br>index 8eb9cccea3..88e64f42cc 100644<br>--- a/modules/gui/qt/components/sout/sout_widgets.cpp<br>+++ b/modules/gui/qt/components/sout/sout_widgets.cpp<br>@@ -26,6 +26,7 @@<br> #include "components/sout/sout_widgets.hpp"<br> #include "dialogs/sout.hpp"<br> #include "util/qt_dirs.hpp"<br>+#include "util/soutmrl.hpp"<br> #include <vlc_intf_strings.h><br><br> #include <QGroupBox><br>diff --git a/modules/gui/qt/dialogs/sout.hpp b/modules/gui/qt/dialogs/sout.hpp<br>index 909dcf80bf..9380a0bc5b 100644<br>--- a/modules/gui/qt/dialogs/sout.hpp<br>+++ b/modules/gui/qt/dialogs/sout.hpp<br>@@ -31,81 +31,12 @@<br><br> #include "ui_sout.h"<br> #include "util/qvlcframe.hpp"<br>+#include "util/soutmrl.hpp"<br><br> #include <QWizard><br><br> class QPushButton;<br><br>-class SoutMrl<br>-{<br>-public:<br>- SoutMrl( const QString& head = "")<br>- {<br>- mrl = head;<br>- b_first = true;<br>- b_has_bracket = false;<br>- }<br>-<br>- QString getMrl()<br>- {<br>- return mrl;<br>- }<br>-<br>- void begin( const QString& module )<br>- {<br>- if( !b_first )<br>- mrl += ":";<br>- b_first = false;<br>-<br>- mrl += module;<br>- b_has_bracket = false;<br>- }<br>- void end()<br>- {<br>- if( b_has_bracket )<br>- mrl += "}";<br>- }<br>- void option( const QString& option, const QString& value = "" )<br>- {<br>- if( !b_has_bracket )<br>- mrl += "{";<br>- else<br>- mrl += ",";<br>- b_has_bracket = true;<br>-<br>- mrl += option;<br>-<br>- if( !value.isEmpty() )<br>- {<br>- char *psz = config_StringEscape( qtu(value) );<br>- if( psz )<br>- {<br>- mrl += "=" + qfu( psz );<br>- free( psz );<br>- }<br>- }<br>- }<br>- void option( const QString& name, const int i_value, const int i_precision = 10 )<br>- {<br>- option( name, QString::number( i_value, i_precision ) );<br>- }<br>- void option( const QString& name, const double f_value )<br>- {<br>- option( name, QString::number( f_value ) );<br>- }<br>-<br>- void option( const QString& name, const QString& base, const int i_value, const int i_precision = 10 )<br>- {<br>- option( name, base + ":" + QString::number( i_value, i_precision ) );<br>- }<br>-<br>-private:<br>- QString mrl;<br>- bool b_has_bracket;<br>- bool b_first;<br>-};<br>-<br>-<br> class SoutDialog : public QWizard<br> {<br> Q_OBJECT<br>diff --git a/modules/gui/qt/util/soutmrl.cpp b/modules/gui/qt/util/soutmrl.cpp<br>new file mode 100644<br>index 0000000000..92aa10ae90<br>--- /dev/null<br>+++ b/modules/gui/qt/util/soutmrl.cpp<br>@@ -0,0 +1,81 @@<br>+#include "soutmrl.hpp"<br>+<br>+QString MrlModule::to_string() const<br>+{<br>+ QString s = moduleName;<br>+<br>+ if( options.size() > 0 )<br>+ {<br>+ s += "{";<br>+ }<br>+ OptionsType::const_iterator it;<br>+ for( it=options.begin(); it!=options.end(); )<br>+ {<br>+ s += it->first;<br>+ if( it->second.to_string().compare("") != 0 )<br>+ {<br>+ s += "=" + it->second.to_string();<br>+ }<br>+ ++it;<br>+ if( it != options.end() )<br>+ {<br>+ s += ",";<br>+ }<br>+ }<br>+ if( options.size() > 0 )<br>+ {<br>+ s += "}";<br>+ }<br>+ return s;<br>+}<br>+<br>+void MrlModule::option( const QString& option, const MrlOption& value )<br>+{<br>+ options.append( OptionPairType( option, value ) );<br>+}<br>+void MrlModule::option( const QString& option )<br>+{<br>+ options.append( OptionPairType( option, "" ) );<br>+}<br>+<br>+QString SoutMrl::getMrl() const<br>+{<br>+ QString mrl = hdr;<br>+ for( int m=0; m<modules.size(); m++ )<br>+ {<br>+ mrl += modules[m].to_string();<br>+ if( m < modules.size() - 1 )<br>+ {<br>+ mrl += ":";<br>+ }<br>+ }<br>+<br>+ return mrl;<br>+}<br>+<br>+void SoutMrl::option( const QString& name, const QString& value )<br>+{<br>+ if( modules.size() > 0 )<br>+ {<br>+ modules.back().option( name, value );<br>+ }<br>+}<br>+void SoutMrl::option( const QString& name, const int i_value, const int i_precision )<br>+{<br>+ option( name, QString::number( i_value, i_precision ) );<br>+}<br>+void SoutMrl::option( const QString& name, const double f_value )<br>+{<br>+ option( name, QString::number( f_value ) );<br>+}<br>+void SoutMrl::option( const QString& name, const QString& base, const int i_value, const int i_precision )<br>+{<br>+ option( name, base + ":" + QString::number( i_value, i_precision ) );<br>+}<br>+void SoutMrl::option( const QString& name, const MrlModule& nested )<br>+{<br>+ if( modules.size() > 0 )<br>+ {<br>+ modules.back().option( name, nested );<br>+ }<br>+}<br>\ No newline at end of file<br>diff --git a/modules/gui/qt/util/soutmrl.hpp b/modules/gui/qt/util/soutmrl.hpp<br>new file mode 100644<br>index 0000000000..f584e1162b<br>--- /dev/null<br>+++ b/modules/gui/qt/util/soutmrl.hpp<br>@@ -0,0 +1,128 @@<br>+/*****************************************************************************<br>+ * soutmrl.hpp: A class to generate sout MRLs<br>+ ****************************************************************************<br>+ *<br>+ *<br>+ *<br>+ *<br>+ * What should we put here?<br>+ * Authors: Jérôme Froissart <<a href="mailto:software@froissart.eu">software@froissart.eu</a>><br>+ *<br>+ *<br>+ *<br>+ *<br>+ *<br>+ *****************************************************************************/<br>+<br>+#ifndef VLC_QT_SOUTMRL_HPP_<br>+#define VLC_QT_SOUTMRL_HPP_<br>+<br>+#include "qt.hpp"<br>+<br>+#include <QMap><br>+<br>+<br>+class MrlOption;<br>+<br>+class MrlModule<br>+{<br>+public:<br>+ MrlModule( const QString& name ) :<br>+ moduleName( name )<br>+ {<br>+ }<br>+<br>+ void option( const QString& option, const MrlOption& value );<br>+ void option( const QString& option );<br>+ QString to_string() const;<br>+<br>+private:<br>+ typedef QPair<QString, MrlOption> OptionPairType;<br>+ typedef QList<OptionPairType> OptionsType;<br>+ const QString moduleName;<br>+ OptionsType options;<br>+};<br>+<br>+<br>+class MrlOption<br>+{<br>+public:<br>+ MrlOption( const QString& value ) :<br>+ kind( String ),<br>+ stringValue( value ),<br>+ nestedModule("")<br>+ {}<br>+<br>+ MrlOption( const char* s ) :<br>+ MrlOption( QString(s) )<br>+ {}<br>+<br>+ MrlOption( const MrlModule& module ) :<br>+ kind(Nested),<br>+ nestedModule(module)<br>+ {}<br>+<br>+ QString to_string() const{<br>+ if( kind == String )<br>+ {<br>+ return stringValue;<br>+ }<br>+ else<br>+ {<br>+ return nestedModule.to_string();<br>+ }<br>+ }<br>+<br>+private:<br>+ enum Kind{ String, Nested };<br>+ const Kind kind;<br>+ const QString stringValue;<br>+ const MrlModule nestedModule;<br>+};<br>+<br>+<br>+/// This class helps building MRLs<br>+///<br>+/// An MRL has the following structure:<br>+/// * a header<br>+/// * any number of modules, which have<br>+/// - a name<br>+/// - any number of key(=value) pairs<br>+/// values can be nested modules<br>+///<br>+/// Example of MRL: HEADERmodule1{a,b=val}:module2:module3{opt,arg=1,stuff=nestedModule{subkey=subvalue}}<br>+class SoutMrl<br>+{<br>+public:<br>+ SoutMrl( const QString& header="" ) :<br>+ hdr(header)<br>+ {<br>+ }<br>+<br>+ MrlModule& begin( const QString& module )<br>+ {<br>+ modules.append( MrlModule( module ) );<br>+ return modules.back();<br>+ }<br>+<br>+ // Useless, kept for compatibility with an older API<br>+ void end()<br>+ {<br>+ }<br>+<br>+ // These should be only in MRLModule, but they are kept in this parent class for compatibility with an older API<br>+ void option( const QString& name, const QString& value = "" );<br>+ void option( const QString& name, const int i_value, const int i_precision = 10 );<br>+ void option( const QString& name, const double f_value );<br>+ void option( const QString& name, const QString& base, const int i_value, const int i_precision = 10 );<br>+ void option( const QString& name, const MrlModule& nested );<br>+<br>+ QString getMrl() const;<br>+<br>+private:<br>+ QString hdr;<br>+ QList<MrlModule> modules;<br>+};<br>+<br>+#endif // include guard<br>+<br>--<br>2.20.1<br><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le jeu. 19 sept. 2019 à 22:44, Jérôme Froissart <<a href="mailto:software@froissart.eu">software@froissart.eu</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi,<br><br>When converting a video, an MRL is poorly handled.<br>When the user checks the "deinterlace" statement, convert.cpp inserts this statement after removing closing braces to the MRL (using "mrl.remove( '}' );").<br>This causes issues in case the passed mrl already contains closing braces (which is the case when the selected profile has custom video codec options).<br>A quick-and-dirty fix would be to remove only the latest brace before inserting the "deinterlace" statement, but, well...that would be quick-and-dirty.<br><br>I rather send you a more object-oriented implementation of SoutMrl, that avoids problems because it better handles "modules" and "options" within SoutMrls.<br>The first and second patches are drop-in replacement for the current implementation.<br>Then the thirs patch actually fixes the bug.<br><br>To reproduce the bug:<br>* open VLC, then "Open capture device" (I am not using the English version, my description can be slightly wrong)<br>* Choose whatever source you want, e.g. screen<br>* Choose "convert"<br>* Choose a profile, and edit it. In the "video codec" tab, add a custom argument (e.g. "preset=faster", which makes sense with the x264 codec)<br>* Start the process. VLC will fail because the MRL will lack a closing brace.<br> You can see the MRL in the "messages" dialog.<br> Without my patch, the MRL may look like<br> sout=#transcode{vcodec=MJPG,venc=x264{preset=faster,scale=Auto,acodec=mp4a,ab=128,channels=1,samplerate=44100,scodec=none,deinterlace}:std{access=file{no-overwrite},mux=mp4,dst='/path/to/output.mp4'}<br> whereas my patch correctly handles the closing brace<br><br><br>Sorry, I did not know what to put in the .hpp header, I could have copied/pasted the GPL license, but I do not know how to properly set the copyright. Maybe you'll know this better than I do.<br><br>These patches can be applied (almost painlessly) to the 3.0.8 branch (there may only be slight issues with a Makefile.am and a convert.cpp that was slightly changed)<br><br><br>Jérôme Froissart (3):<br> Re-implemented SoutMrl in a more object-oriented way<br> Additions to the new SoutMrl implementation<br> Deinterlace can be associated with codec arguments<br><br> modules/gui/qt/Makefile.am | 1 +<br> .../qt/components/sout/profile_selector.cpp | 80 +++++-----<br> .../qt/components/sout/profile_selector.hpp | 5 +-<br> .../gui/qt/components/sout/sout_widgets.cpp | 1 +<br> modules/gui/qt/dialogs/convert.cpp | 37 +++--<br> modules/gui/qt/dialogs/sout.cpp | 4 +-<br> modules/gui/qt/dialogs/sout.hpp | 71 +--------<br> modules/gui/qt/util/soutmrl.cpp | 86 +++++++++++<br> modules/gui/qt/util/soutmrl.hpp | 145 ++++++++++++++++++<br> 9 files changed, 301 insertions(+), 129 deletions(-)<br> create mode 100644 modules/gui/qt/util/soutmrl.cpp<br> create mode 100644 modules/gui/qt/util/soutmrl.hpp<br><br>--<br>2.20.1<br><br></div>
</blockquote></div>