[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