[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:50:05 CEST 2019


I am sorry, I may not have sent the emails the way you wanted.
I never used plain emails to send patches and am not familiar with this
technique, so please have forgiveness :-)

(Maybe you want me to send them again properly? But I wasn't sure about the
command I found on your wiki, which send 4 consecutive emails instead of
replying to the first one, which is --I think-- what you ask to do)

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

> 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/d96967f9/attachment-0001.html>


More information about the vlc-devel mailing list