[vlc-devel] [PATCH 0/3] Bug when converting with both deinterlace checked and codec options

Jérôme Froissart software at froissart.eu
Thu Sep 19 22:47:57 CEST 2019


>From c3e064e8985acf23d7af688167345335f80f568a Mon Sep 17 00:00:00 2001
From: Jérôme Froissart <software at froissart.eu>
Date: Thu, 19 Sep 2019 12:48:29 +0200
Subject: [PATCH 3/3] Deinterlace can be associated with codec arguments

Previously, one could not convert a video into a video with both:
 * deinterlace checked (in the Convert dialog)
 * custom options (in "Profile edition" dialog, "Video codec" tab)
This was due to incorrectly handled braces in a SoutMrl.

This patches requires to make VLCProfileSelector::getTranscode() return a
SoutMrl instead of a plain QString, which eases the handling of the Mrl
---
 .../qt/components/sout/profile_selector.cpp   | 78 +++++++++----------
 .../qt/components/sout/profile_selector.hpp   |  5 +-
 modules/gui/qt/dialogs/convert.cpp            | 37 ++++++---
 modules/gui/qt/dialogs/sout.cpp               |  4 +-
 4 files changed, 66 insertions(+), 58 deletions(-)

diff --git a/modules/gui/qt/components/sout/profile_selector.cpp
b/modules/gui/qt/components/sout/profile_selector.cpp
index 55fc5c9c28..36867bc91b 100644
--- a/modules/gui/qt/components/sout/profile_selector.cpp
+++ b/modules/gui/qt/components/sout/profile_selector.cpp
@@ -203,7 +203,7 @@ void VLCProfileSelector::updateOptions( int i )
     if ( rx.indexIn( options ) != -1 )
         return updateOptionsOldFormat( i );

-    transcode = "";
+    transcode.clear();

     QStringList tuples = options.split( ";" );
     typedef QHash<QString, QString> proptovalueHashType;
@@ -242,8 +242,7 @@ void VLCProfileSelector::updateOptions( int i )
     }\
     else value = QString()

-    SoutMrl smrl;
-    smrl.begin( "transcode" );
+    transcode.begin( "transcode" );

     /* First muxer options */
     HASHPICK( "muxer", "mux" );
@@ -257,19 +256,19 @@ void VLCProfileSelector::updateOptions( int i )

         if ( !value.isEmpty() )
         {
-            smrl.option( "vcodec", value );
+            transcode.option( "vcodec", value );

             HASHPICK( "vcodec", "bitrate" );
             if ( value.toInt() > 0 )
             {
-                smrl.option( "vb", value.toInt() );
+                transcode.option( "vb", value.toInt() );
             }

             HASHPICK( "video", "filters" );
             if ( !value.isEmpty() )
             {
                 QStringList valuesList = QUrl::fromPercentEncoding(
value.toLatin1() ).split( ";" );
-                smrl.option( "vfilter", valuesList.join( ":" ) );
+                transcode.option( "vfilter", valuesList.join( ":" ) );
             }

             /*if ( codec is h264 )*/
@@ -286,28 +285,28 @@ void VLCProfileSelector::updateOptions( int i )
                     codecoptions << QUrl::fromPercentEncoding(
value.toLatin1() );

                 if ( codecoptions.count() )
-                    smrl.option( "venc",
+                    transcode.option( "venc",
                         QString("x264{%1}").arg( codecoptions.join(",") )
);
             }

             HASHPICK( "vcodec", "framerate" );
             if ( !value.isEmpty() && value.toInt() > 0 )
-                smrl.option( "fps", value );
+                transcode.option( "fps", value );

             HASHPICK( "vcodec", "scale" );
             if ( !value.isEmpty() )
-                smrl.option( "scale", value );
+                transcode.option( "scale", value );

             HASHPICK( "vcodec", "width" );
             if ( !value.isEmpty() && value.toInt() > 0 )
-                smrl.option( "width", value );
+                transcode.option( "width", value );

             HASHPICK( "vcodec", "height" );
             if ( !value.isEmpty() && value.toInt() > 0 )
-                smrl.option( "height", value );
+                transcode.option( "height", value );
         }
     } else {
-        smrl.option( "vcodec", "none" );
+        transcode.option( "vcodec", "none" );
     }

     HASHPICK( "audio", "enable" );
@@ -316,27 +315,27 @@ void VLCProfileSelector::updateOptions( int i )
         HASHPICK( "audio", "codec" );
         if ( !value.isEmpty() )
         {
-            smrl.option( "acodec", value );
+            transcode.option( "acodec", value );

             HASHPICK( "acodec", "bitrate" );
-            smrl.option( "ab", value.toInt() );
+            transcode.option( "ab", value.toInt() );

             HASHPICK( "acodec", "channels" );
-            smrl.option( "channels", value.toInt() );
+            transcode.option( "channels", value.toInt() );

             HASHPICK( "acodec", "samplerate" );
-            smrl.option( "samplerate", value.toInt() );
+            transcode.option( "samplerate", value.toInt() );

             HASHPICK( "audio", "filters" );
             if ( !value.isEmpty() )
             {
                 QStringList valuesList = QUrl::fromPercentEncoding(
value.toLatin1() ).split( ";" );
-                smrl.option( "afilter", valuesList.join( ":" ) );
+                transcode.option( "afilter", valuesList.join( ":" ) );
             }

         }
     } else {
-        smrl.option( "acodec", "none" );
+        transcode.option( "acodec", "none" );
     }

     HASHPICK( "subtitles", "enable" );
@@ -346,20 +345,18 @@ void VLCProfileSelector::updateOptions( int i )
         if ( value.isEmpty() )
         {
             HASHPICK( "subtitles", "codec" );
-            smrl.option( "scodec", value );
+            transcode.option( "scodec", value );
         }
         else
         {
-            smrl.option( "soverlay" );
+            transcode.option( "soverlay" );
         }
     } else {
-        smrl.option( "scodec", "none" );
+        transcode.option( "scodec", "none" );
     }
-    smrl.end();
+    transcode.end();
 #undef HASHPICK

-    transcode = smrl.getMrl();
-
     cleanup:
     /* Temp hash tables cleanup */
     foreach( proptovalueHashType *hash, categtopropHash )
@@ -376,52 +373,49 @@ void VLCProfileSelector::updateOptionsOldFormat( int
i )

     mux = options[0];

-    SoutMrl smrl;
     if( options[1].toInt() || options[2].toInt() || options[3].toInt() )
     {
-        smrl.begin( "transcode" );
+        transcode.begin( "transcode" );

         if( options[1].toInt() )
         {
-            smrl.option( "vcodec", options[4] );
+            transcode.option( "vcodec", options[4] );
             if( options[4] != "none" )
             {
-                smrl.option( "vb", options[5].toInt() );
+                transcode.option( "vb", options[5].toInt() );
                 if( !options[7].isEmpty() && options[7].toInt() > 0 )
-                    smrl.option( "fps", options[7] );
+                    transcode.option( "fps", options[7] );
                 if( !options[6].isEmpty() )
-                    smrl.option( "scale", options[6] );
+                    transcode.option( "scale", options[6] );
                 if( !options[8].isEmpty() && options[8].toInt() > 0 )
-                    smrl.option( "width", options[8].toInt() );
+                    transcode.option( "width", options[8].toInt() );
                 if( !options[9].isEmpty() && options[9].toInt() > 0 )
-                    smrl.option( "height", options[9].toInt() );
+                    transcode.option( "height", options[9].toInt() );
             }
         }

         if( options[2].toInt() )
         {
-            smrl.option( "acodec", options[10] );
+            transcode.option( "acodec", options[10] );
             if( options[10] != "none" )
             {
-                smrl.option( "ab", options[11].toInt() );
-                smrl.option( "channels", options[12].toInt() );
-                smrl.option( "samplerate", options[13].toInt() );
+                transcode.option( "ab", options[11].toInt() );
+                transcode.option( "channels", options[12].toInt() );
+                transcode.option( "samplerate", options[13].toInt() );
             }
         }

         if( options[3].toInt() )
         {
-            smrl.option( "scodec", options[14] );
+            transcode.option( "scodec", options[14] );
             if( options[15].toInt() )
-                smrl.option( "soverlay" );
+                transcode.option( "soverlay" );
         }

-        smrl.end();
-
-        transcode = smrl.getMrl();
+        transcode.end();
     }
     else
-        transcode = "";
+        transcode.clear();
     emit optionsChanged();
 }

diff --git a/modules/gui/qt/components/sout/profile_selector.hpp
b/modules/gui/qt/components/sout/profile_selector.hpp
index 1074c7b220..61d3502eb7 100644
--- a/modules/gui/qt/components/sout/profile_selector.hpp
+++ b/modules/gui/qt/components/sout/profile_selector.hpp
@@ -30,6 +30,7 @@
 #include <QHash>

 #include "util/qvlcframe.hpp"
+#include "util/soutmrl.hpp"
 #include "ui_profiles.h"

 class QComboBox;
@@ -42,14 +43,14 @@ public:
     VLCProfileSelector( QWidget *_parent );
     ~VLCProfileSelector();
     QString getMux() { return mux; }
-    QString getTranscode() { return transcode; }
+    SoutMrl getTranscode() { return transcode; }
 private:
     QComboBox *profileBox;
     void fillProfilesCombo();
     void editProfile( const QString&, const QString& );
     void saveProfiles();
     QString mux;
-    QString transcode;
+    SoutMrl transcode;
 private slots:
     void newProfile();
     void editProfile();
diff --git a/modules/gui/qt/dialogs/convert.cpp
b/modules/gui/qt/dialogs/convert.cpp
index cf157472b6..332da28c70 100644
--- a/modules/gui/qt/dialogs/convert.cpp
+++ b/modules/gui/qt/dialogs/convert.cpp
@@ -176,21 +176,20 @@ void ConvertDialog::close()

     for(int i = 0; i < incomingMRLs->length(); i++)
     {
-        QString mrl;
+        SoutMrl mrl;

         if( dumpRadio->isChecked() )
         {
-            mrl = "demux=dump :demuxdump-file=" + fileLine->text();
+            mrl.header("demux=dump :demuxdump-file=" + fileLine->text());
         }
         else
         {
-            mrl = "sout=#" + profile->getTranscode();
+            mrl = profile->getTranscode();
+            mrl.header( "sout=#" + mrl.getHeader() );
             if( deinterBox->isChecked() )
             {
-                mrl.remove( '}' );
-                mrl += ",deinterlace}";
+                mrl.option("deinterlace");
             }
-            mrl += ":";

             QString newFileName;

@@ -229,15 +228,29 @@ void ConvertDialog::close()

             newFileName.replace( QChar('\''), "\\\'" );

-            QString chain =
QString("std{access=file{no-overwrite},mux=%1,dst='%2'}")
-                                    .arg( profile->getMux() ).arg(
newFileName );
+
+            mrl.end();
+            MrlModule dstModule("std");
+            MrlModule file("file");
+            file.option("no-overwrite");
+            dstModule.option("access", file);
+            dstModule.option("mux", profile->getMux());
+            dstModule.option("dst", "'" + newFileName + "'");
+
             if( displayBox->isChecked() )
-                mrl += QString( "duplicate{dst=display,dst=%1}" ).arg(
chain );
+            {
+                MrlModule duplicate("duplicate");
+                duplicate.option("dst", "display");
+                duplicate.option("dst", dstModule);
+                mrl.module(duplicate);
+            }
             else
-                mrl += chain;
+            {
+                mrl.module(dstModule);
+            }
         }
-        msg_Dbg( p_intf, "Transcode MRL: %s", qtu( mrl ) );
-        mrls.append(mrl);
+        msg_Dbg( p_intf, "Transcode MRL: %s", qtu( mrl.getMrl() ) );
+        mrls.append(mrl.getMrl());
     }
     accept();
 }
diff --git a/modules/gui/qt/dialogs/sout.cpp
b/modules/gui/qt/dialogs/sout.cpp
index bbcc308d63..3dd764e418 100644
--- a/modules/gui/qt/dialogs/sout.cpp
+++ b/modules/gui/qt/dialogs/sout.cpp
@@ -179,9 +179,9 @@ void SoutDialog::updateMRL()
     QString qs_mux = ui.profileSelect->getMux();

     SoutMrl smrl( ":sout=#" );
-    if( !ui.profileSelect->getTranscode().isEmpty() &&
ui.transcodeBox->isChecked() )
+    if( !ui.profileSelect->getTranscode().getMrl().isEmpty() &&
ui.transcodeBox->isChecked() )
     {
-        smrl.begin( ui.profileSelect->getTranscode() );
+        smrl.begin( ui.profileSelect->getTranscode().getMrl() );
         smrl.end();
     }

-- 
2.20.1


Le jeu. 19 sept. 2019 à 22:46, Jérôme Froissart <software at froissart.eu> a
écrit :

>
> ---
>  modules/gui/qt/util/soutmrl.cpp |  5 +++++
>  modules/gui/qt/util/soutmrl.hpp | 17 +++++++++++++++++
>  2 files changed, 22 insertions(+)
>
> diff --git a/modules/gui/qt/util/soutmrl.cpp
> b/modules/gui/qt/util/soutmrl.cpp
> index 92aa10ae90..90615c6c86 100644
> --- a/modules/gui/qt/util/soutmrl.cpp
> +++ b/modules/gui/qt/util/soutmrl.cpp
> @@ -38,6 +38,11 @@ void MrlModule::option( const QString& option )
>      options.append( OptionPairType( option, "" ) );
>  }
>
> +QString SoutMrl::getHeader() const
> +{
> +    return hdr;
> +}
> +
>  QString SoutMrl::getMrl() const
>  {
>      QString mrl = hdr;
> diff --git a/modules/gui/qt/util/soutmrl.hpp
> b/modules/gui/qt/util/soutmrl.hpp
> index f584e1162b..69ba4458bb 100644
> --- a/modules/gui/qt/util/soutmrl.hpp
> +++ b/modules/gui/qt/util/soutmrl.hpp
> @@ -99,6 +99,17 @@ public:
>      {
>      }
>
> +    void clear()
> +    {
> +        hdr = "";
> +        modules.clear();
> +    }
> +
> +    void header( const QString& newHeader )
> +    {
> +        hdr = newHeader;
> +    }
> +
>      MrlModule& begin( const QString& module )
>      {
>          modules.append( MrlModule( module ) );
> @@ -110,6 +121,11 @@ public:
>      {
>      }
>
> +    void module( const MrlModule& module )
> +    {
> +        modules.append( module );
> +    }
> +
>      // These should be only in MRLModule, but they are kept in this
> parent class for compatibility with an older API
>      void option( const QString& name, const QString& value = "" );
>      void option( const QString& name, const int i_value, const int
> i_precision = 10 );
> @@ -117,6 +133,7 @@ public:
>      void option( const QString& name, const QString& base, const int
> i_value, const int i_precision = 10 );
>      void option( const QString& name, const MrlModule& nested );
>
> +    QString getHeader() const;
>      QString getMrl() const;
>
>  private:
> --
> 2.20.1
>
>
> Le jeu. 19 sept. 2019 à 22:46, Jérôme Froissart <software at froissart.eu> a
> écrit :
>
>>
>> ---
>>  modules/gui/qt/Makefile.am                    |   1 +
>>  .../qt/components/sout/profile_selector.cpp   |   2 +-
>>  .../gui/qt/components/sout/sout_widgets.cpp   |   1 +
>>  modules/gui/qt/dialogs/sout.hpp               |  71 +---------
>>  modules/gui/qt/util/soutmrl.cpp               |  81 +++++++++++
>>  modules/gui/qt/util/soutmrl.hpp               | 128 ++++++++++++++++++
>>  6 files changed, 213 insertions(+), 71 deletions(-)
>>  create mode 100644 modules/gui/qt/util/soutmrl.cpp
>>  create mode 100644 modules/gui/qt/util/soutmrl.hpp
>>
>> diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
>> index af4a5d05cc..71f96a5910 100644
>> --- a/modules/gui/qt/Makefile.am
>> +++ b/modules/gui/qt/Makefile.am
>> @@ -186,6 +186,7 @@ libqt_plugin_la_SOURCES = \
>>   gui/qt/util/customwidgets.cpp gui/qt/util/customwidgets.hpp \
>>   gui/qt/util/searchlineedit.cpp gui/qt/util/searchlineedit.hpp \
>>   gui/qt/util/registry.cpp gui/qt/util/registry.hpp \
>> + gui/qt/util/soutmrl.cpp gui/qt/util/soutmrl.hpp \
>>   gui/qt/util/qt_dirs.cpp gui/qt/util/qt_dirs.hpp \
>>   gui/qt/util/validators.cpp gui/qt/util/validators.hpp \
>>   gui/qt/util/buttons/BrowseButton.cpp \
>> diff --git a/modules/gui/qt/components/sout/profile_selector.cpp
>> b/modules/gui/qt/components/sout/profile_selector.cpp
>> index 586a01f681..55fc5c9c28 100644
>> --- a/modules/gui/qt/components/sout/profile_selector.cpp
>> +++ b/modules/gui/qt/components/sout/profile_selector.cpp
>> @@ -23,7 +23,7 @@
>>
>>  #include "components/sout/profile_selector.hpp"
>>  #include "components/sout/profiles.hpp"
>> -#include "dialogs/sout.hpp"
>> +#include "util/soutmrl.hpp"
>>
>>  #include <QHBoxLayout>
>>  #include <QToolButton>
>> diff --git a/modules/gui/qt/components/sout/sout_widgets.cpp
>> b/modules/gui/qt/components/sout/sout_widgets.cpp
>> index 8eb9cccea3..88e64f42cc 100644
>> --- a/modules/gui/qt/components/sout/sout_widgets.cpp
>> +++ b/modules/gui/qt/components/sout/sout_widgets.cpp
>> @@ -26,6 +26,7 @@
>>  #include "components/sout/sout_widgets.hpp"
>>  #include "dialogs/sout.hpp"
>>  #include "util/qt_dirs.hpp"
>> +#include "util/soutmrl.hpp"
>>  #include <vlc_intf_strings.h>
>>
>>  #include <QGroupBox>
>> diff --git a/modules/gui/qt/dialogs/sout.hpp
>> b/modules/gui/qt/dialogs/sout.hpp
>> index 909dcf80bf..9380a0bc5b 100644
>> --- a/modules/gui/qt/dialogs/sout.hpp
>> +++ b/modules/gui/qt/dialogs/sout.hpp
>> @@ -31,81 +31,12 @@
>>
>>  #include "ui_sout.h"
>>  #include "util/qvlcframe.hpp"
>> +#include "util/soutmrl.hpp"
>>
>>  #include <QWizard>
>>
>>  class QPushButton;
>>
>> -class SoutMrl
>> -{
>> -public:
>> -    SoutMrl( const QString& head = "")
>> -    {
>> -        mrl = head;
>> -        b_first = true;
>> -        b_has_bracket = false;
>> -    }
>> -
>> -    QString getMrl()
>> -    {
>> -        return mrl;
>> -    }
>> -
>> -    void begin( const QString& module )
>> -    {
>> -        if( !b_first )
>> -            mrl += ":";
>> -        b_first = false;
>> -
>> -        mrl += module;
>> -        b_has_bracket = false;
>> -    }
>> -    void end()
>> -    {
>> -        if( b_has_bracket )
>> -            mrl += "}";
>> -    }
>> -    void option( const QString& option, const QString& value = "" )
>> -    {
>> -        if( !b_has_bracket )
>> -            mrl += "{";
>> -        else
>> -            mrl += ",";
>> -        b_has_bracket = true;
>> -
>> -        mrl += option;
>> -
>> -        if( !value.isEmpty() )
>> -        {
>> -            char *psz = config_StringEscape( qtu(value) );
>> -            if( psz )
>> -            {
>> -                mrl += "=" + qfu( psz );
>> -                free( psz );
>> -            }
>> -        }
>> -    }
>> -    void option( const QString& name, const int i_value, const int
>> i_precision = 10 )
>> -    {
>> -        option( name, QString::number( i_value, i_precision ) );
>> -    }
>> -    void option( const QString& name, const double f_value )
>> -    {
>> -        option( name, QString::number( f_value ) );
>> -    }
>> -
>> -    void option( const QString& name, const QString& base, const int
>> i_value, const int i_precision = 10 )
>> -    {
>> -        option( name, base + ":" + QString::number( i_value, i_precision
>> ) );
>> -    }
>> -
>> -private:
>> -    QString mrl;
>> -    bool b_has_bracket;
>> -    bool b_first;
>> -};
>> -
>> -
>>  class SoutDialog : public QWizard
>>  {
>>      Q_OBJECT
>> diff --git a/modules/gui/qt/util/soutmrl.cpp
>> b/modules/gui/qt/util/soutmrl.cpp
>> new file mode 100644
>> index 0000000000..92aa10ae90
>> --- /dev/null
>> +++ b/modules/gui/qt/util/soutmrl.cpp
>> @@ -0,0 +1,81 @@
>> +#include "soutmrl.hpp"
>> +
>> +QString MrlModule::to_string() const
>> +{
>> +    QString s = moduleName;
>> +
>> +    if( options.size() > 0 )
>> +    {
>> +        s += "{";
>> +    }
>> +    OptionsType::const_iterator it;
>> +    for( it=options.begin(); it!=options.end(); )
>> +    {
>> +        s += it->first;
>> +        if( it->second.to_string().compare("") != 0 )
>> +        {
>> +            s += "=" + it->second.to_string();
>> +        }
>> +        ++it;
>> +        if( it != options.end() )
>> +        {
>> +            s += ",";
>> +        }
>> +    }
>> +    if( options.size() > 0 )
>> +    {
>> +        s += "}";
>> +    }
>> +    return s;
>> +}
>> +
>> +void MrlModule::option( const QString& option, const MrlOption& value )
>> +{
>> +    options.append( OptionPairType( option, value ) );
>> +}
>> +void MrlModule::option( const QString& option )
>> +{
>> +    options.append( OptionPairType( option, "" ) );
>> +}
>> +
>> +QString SoutMrl::getMrl() const
>> +{
>> +    QString mrl = hdr;
>> +    for( int m=0; m<modules.size(); m++ )
>> +    {
>> +        mrl += modules[m].to_string();
>> +        if( m < modules.size() - 1 )
>> +        {
>> +            mrl += ":";
>> +        }
>> +    }
>> +
>> +    return mrl;
>> +}
>> +
>> +void SoutMrl::option( const QString& name, const QString& value )
>> +{
>> +    if( modules.size() > 0 )
>> +    {
>> +        modules.back().option( name, value );
>> +    }
>> +}
>> +void SoutMrl::option( const QString& name, const int i_value, const int
>> i_precision )
>> +{
>> +    option( name, QString::number( i_value, i_precision ) );
>> +}
>> +void SoutMrl::option( const QString& name, const double f_value )
>> +{
>> +    option( name, QString::number( f_value ) );
>> +}
>> +void SoutMrl::option( const QString& name, const QString& base, const
>> int i_value, const int i_precision )
>> +{
>> +    option( name, base + ":" + QString::number( i_value, i_precision ) );
>> +}
>> +void SoutMrl::option( const QString& name, const MrlModule& nested )
>> +{
>> +    if( modules.size() > 0 )
>> +    {
>> +        modules.back().option( name, nested );
>> +    }
>> +}
>> \ No newline at end of file
>> diff --git a/modules/gui/qt/util/soutmrl.hpp
>> b/modules/gui/qt/util/soutmrl.hpp
>> new file mode 100644
>> index 0000000000..f584e1162b
>> --- /dev/null
>> +++ b/modules/gui/qt/util/soutmrl.hpp
>> @@ -0,0 +1,128 @@
>>
>> +/*****************************************************************************
>> + * soutmrl.hpp: A class to generate sout MRLs
>> +
>> ****************************************************************************
>> + *
>> + *
>> + *
>> + *
>> + * What should we put here?
>> + * Authors: Jérôme Froissart <software at froissart.eu>
>> + *
>> + *
>> + *
>> + *
>> + *
>> +
>> *****************************************************************************/
>> +
>> +#ifndef VLC_QT_SOUTMRL_HPP_
>> +#define VLC_QT_SOUTMRL_HPP_
>> +
>> +#include "qt.hpp"
>> +
>> +#include <QMap>
>> +
>> +
>> +class MrlOption;
>> +
>> +class MrlModule
>> +{
>> +public:
>> +    MrlModule( const QString& name ) :
>> +        moduleName( name )
>> +    {
>> +    }
>> +
>> +    void option( const QString& option, const MrlOption& value );
>> +    void option( const QString& option );
>> +    QString to_string() const;
>> +
>> +private:
>> +    typedef QPair<QString, MrlOption> OptionPairType;
>> +    typedef QList<OptionPairType> OptionsType;
>> +    const QString moduleName;
>> +    OptionsType options;
>> +};
>> +
>> +
>> +class MrlOption
>> +{
>> +public:
>> +    MrlOption( const QString& value ) :
>> +        kind( String ),
>> +        stringValue( value ),
>> +        nestedModule("")
>> +    {}
>> +
>> +    MrlOption( const char* s ) :
>> +        MrlOption( QString(s) )
>> +    {}
>> +
>> +    MrlOption( const MrlModule& module ) :
>> +        kind(Nested),
>> +        nestedModule(module)
>> +    {}
>> +
>> +    QString to_string() const{
>> +        if( kind == String )
>> +        {
>> +            return stringValue;
>> +        }
>> +        else
>> +        {
>> +            return nestedModule.to_string();
>> +        }
>> +    }
>> +
>> +private:
>> +    enum Kind{ String, Nested };
>> +    const Kind kind;
>> +    const QString stringValue;
>> +    const MrlModule nestedModule;
>> +};
>> +
>> +
>> +/// This class helps building MRLs
>> +///
>> +/// An MRL has the following structure:
>> +///  * a header
>> +///  * any number of modules, which have
>> +///     - a name
>> +///     - any number of key(=value) pairs
>> +///       values can be nested modules
>> +///
>> +/// Example of MRL:
>> HEADERmodule1{a,b=val}:module2:module3{opt,arg=1,stuff=nestedModule{subkey=subvalue}}
>> +class SoutMrl
>> +{
>> +public:
>> +    SoutMrl( const QString& header="" ) :
>> +        hdr(header)
>> +    {
>> +    }
>> +
>> +    MrlModule& begin( const QString& module )
>> +    {
>> +        modules.append( MrlModule( module ) );
>> +        return modules.back();
>> +    }
>> +
>> +    // Useless, kept for compatibility with an older API
>> +    void end()
>> +    {
>> +    }
>> +
>> +    // These should be only in MRLModule, but they are kept in this
>> parent class for compatibility with an older API
>> +    void option( const QString& name, const QString& value = "" );
>> +    void option( const QString& name, const int i_value, const int
>> i_precision = 10 );
>> +    void option( const QString& name, const double f_value );
>> +    void option( const QString& name, const QString& base, const int
>> i_value, const int i_precision = 10 );
>> +    void option( const QString& name, const MrlModule& nested );
>> +
>> +    QString getMrl() const;
>> +
>> +private:
>> +    QString hdr;
>> +    QList<MrlModule> modules;
>> +};
>> +
>> +#endif // include guard
>> +
>> --
>> 2.20.1
>>
>>
>> Le jeu. 19 sept. 2019 à 22:44, Jérôme Froissart <software at froissart.eu>
>> a écrit :
>>
>>> Hi,
>>>
>>> When converting a video, an MRL is poorly handled.
>>> When the user checks the "deinterlace" statement, convert.cpp inserts
>>> this statement after removing closing braces to the MRL (using "mrl.remove(
>>> '}' );").
>>> 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).
>>> 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.
>>>
>>> I rather send you a more object-oriented implementation of SoutMrl, that
>>> avoids problems because it better handles "modules" and "options" within
>>> SoutMrls.
>>> The first and second patches are drop-in replacement for the current
>>> implementation.
>>> Then the thirs patch actually fixes the bug.
>>>
>>> To reproduce the bug:
>>> * open VLC, then "Open capture device" (I am not using the English
>>> version, my description can be slightly wrong)
>>> * Choose whatever source you want, e.g. screen
>>> * Choose "convert"
>>> * 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)
>>> * Start the process. VLC will fail because the MRL will lack a closing
>>> brace.
>>>   You can see the MRL in the "messages" dialog.
>>>   Without my patch, the MRL may look like
>>>
>>> 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'}
>>>   whereas my patch correctly handles the closing brace
>>>
>>>
>>> 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.
>>>
>>> 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)
>>>
>>>
>>> Jérôme Froissart (3):
>>>   Re-implemented SoutMrl in a more object-oriented way
>>>   Additions to the new SoutMrl implementation
>>>   Deinterlace can be associated with codec arguments
>>>
>>>  modules/gui/qt/Makefile.am                    |   1 +
>>>  .../qt/components/sout/profile_selector.cpp   |  80 +++++-----
>>>  .../qt/components/sout/profile_selector.hpp   |   5 +-
>>>  .../gui/qt/components/sout/sout_widgets.cpp   |   1 +
>>>  modules/gui/qt/dialogs/convert.cpp            |  37 +++--
>>>  modules/gui/qt/dialogs/sout.cpp               |   4 +-
>>>  modules/gui/qt/dialogs/sout.hpp               |  71 +--------
>>>  modules/gui/qt/util/soutmrl.cpp               |  86 +++++++++++
>>>  modules/gui/qt/util/soutmrl.hpp               | 145 ++++++++++++++++++
>>>  9 files changed, 301 insertions(+), 129 deletions(-)
>>>  create mode 100644 modules/gui/qt/util/soutmrl.cpp
>>>  create mode 100644 modules/gui/qt/util/soutmrl.hpp
>>>
>>> --
>>> 2.20.1
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20190919/9aa5762c/attachment-0001.html>


More information about the vlc-devel mailing list