From: Jean-Baptiste Kempf Date: Fri, 6 Mar 2009 23:56:23 +0000 (+0100) Subject: Qt: rework of the Sout Dialog X-Git-Tag: 1.0.0-pre1~207 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=fc37db067e133092fceec6f3c3ee2b9c151d151b;p=vlc Qt: rework of the Sout Dialog You can now add any number of duplicate parts you want. You can add them to create a new Tab. You can have two HTTP output or two File output, for example. Most of the widgets creation and MRL generation part has been splitted from the main class so that people why little knowledge of Qt can understand what is going on. Expert in streaming can personnalize more easily 'their' part of the UI with derivation of VirtualDestBox and implementing constructor+getMRL() The huge structure has been removed. This is a huge change in this dialog, but I think the old one was beyond possible repair. --- diff --git a/modules/gui/qt4/components/sout/profile_selector.cpp b/modules/gui/qt4/components/sout/profile_selector.cpp index f84f809682..96b647f51f 100644 --- a/modules/gui/qt4/components/sout/profile_selector.cpp +++ b/modules/gui/qt4/components/sout/profile_selector.cpp @@ -198,6 +198,7 @@ void VLCProfileSelector::updateOptions( int i ) } else transcode = ""; + emit optionsChanged(); } diff --git a/modules/gui/qt4/components/sout/sout_widgets.cpp b/modules/gui/qt4/components/sout/sout_widgets.cpp index b63e60a589..457228a862 100644 --- a/modules/gui/qt4/components/sout/sout_widgets.cpp +++ b/modules/gui/qt4/components/sout/sout_widgets.cpp @@ -22,11 +22,14 @@ *****************************************************************************/ #include "components/sout/sout_widgets.hpp" +#include "dialogs/sout.hpp" +#include "util/qt_dirs.hpp" #include #include #include #include +#include SoutInputBox::SoutInputBox( QWidget *_parent, QString mrl ) : QGroupBox( _parent ) { @@ -63,10 +66,328 @@ void SoutInputBox::setMRL( QString mrl ) int i = mrl.indexOf( "://" ); if( i != -1 ) { - printf( "%i\n", i ); type = mrl.left( i ); } else type = qtr( "File/Directory" ); sourceValueLabel->setText( type ); } + + #define CT( x ) connect( x, SIGNAL( textChanged( const QString ) ), this, SIGNAL( mrlUpdated() ) ); + #define CS( x ) connect( x, SIGNAL( valueChanged( int ) ), this, SIGNAL( mrlUpdated() ) ); + +/* FileDest Box */ +FileDestBox::FileDestBox( QWidget *_parent ) : VirtualDestBox( _parent ) +{ + QPushButton *fileSelectButton; + QGridLayout *layout = new QGridLayout( this ); + + QLabel *fileOutput = new QLabel( + qtr( "This modules outputs to a file on your disk."), this ); + layout->addWidget(fileOutput, 0, 0, 1, -1); + + QLabel *fileLabel = new QLabel( qtr( "Filename"), this ); + layout->addWidget(fileLabel, 1, 0, 1, 1); + + fileEdit = new QLineEdit(this); + layout->addWidget(fileEdit, 1, 4, 1, 1); + + fileSelectButton = new QPushButton( qtr( "Browse..." ), this ); + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); + fileSelectButton->setSizePolicy(sizePolicy); + + layout->addWidget(fileSelectButton, 1, 5, 1, 1); + CT( fileEdit ); + BUTTONACT( fileSelectButton, fileBrowse() ); +} + +QString FileDestBox::getMRL( QString mux ) +{ + if( fileEdit->text().isEmpty() ) return ""; + + SoutMrl m; + m.begin( "std" ); + m.option( "access", "file" ); + if( !mux.isEmpty() ) + m.option( "mux", mux ); //FIXME: alert if ext doesn't match + m.option( "dst", fileEdit->text() ); + m.end(); + + return m.getMrl(); +} + +void FileDestBox::fileBrowse() +{ + QString fileName = QFileDialog::getSaveFileName( this, qtr( "Save file..." ), + "", qtr( "Containers (*.ps *.ts *.mpg *.ogg *.asf *.mp4 *.mov *.wav *.raw *.flv)" ) ); + fileEdit->setText( toNativeSeparators( fileName ) ); + emit mrlUpdated(); +} + + + +HTTPDestBox::HTTPDestBox( QWidget *_parent ) : VirtualDestBox( _parent ) +{ + QGridLayout *layout = new QGridLayout( this ); + + QLabel *httpOutput = new QLabel( + qtr( "This modules streams on the networks with the HTTP protocol."), this ); + layout->addWidget(httpOutput, 0, 0, 1, -1); + + QLabel *HTTPLabel = new QLabel( qtr("Address"), this ); + QLabel *HTTPPortLabel = new QLabel( qtr("Port"), this ); + layout->addWidget(HTTPLabel, 1, 0, 1, 1); + layout->addWidget(HTTPPortLabel, 2, 0, 1, 1); + + HTTPEdit = new QLineEdit(this); + + HTTPPort = new QSpinBox(this); + HTTPPort->setMaximumSize(QSize(90, 16777215)); + HTTPPort->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + HTTPPort->setMinimum(1); + HTTPPort->setMaximum(65535); + HTTPPort->setValue(8080); + + layout->addWidget(HTTPEdit, 1, 1, 1, 1); + layout->addWidget(HTTPPort, 2, 1, 1, 1); + CS( HTTPPort ); + CT( HTTPEdit ); +} + +QString HTTPDestBox::getMRL( QString mux ) +{ + if( HTTPEdit->text().isEmpty() ) return ""; + + SoutMrl m; + m.begin( "std" ); + m.option( "access", "http" ); + if( !mux.isEmpty() ) + m.option( "mux", mux ); + m.option( "dst", HTTPEdit->text(), HTTPPort->value() ); + m.end(); + + return m.getMrl(); +} + +MMSHDestBox::MMSHDestBox( QWidget *_parent ) : VirtualDestBox( _parent ) +{ + QGridLayout *layout = new QGridLayout( this ); + + QLabel *mmshOutput = new QLabel( + qtr( "This modules streams on the networks with the mms: protocol."), this ); + layout->addWidget(mmshOutput, 0, 0, 1, -1); + + QLabel *MMSHLabel = new QLabel( qtr("Address"), this ); + QLabel *MMSHPortLabel = new QLabel( qtr("Port"), this ); + layout->addWidget(MMSHLabel, 1, 0, 1, 1); + layout->addWidget(MMSHPortLabel, 2, 0, 1, 1); + + MMSHEdit = new QLineEdit(this); + + MMSHPort = new QSpinBox(this); + MMSHPort->setMaximumSize(QSize(90, 16777215)); + MMSHPort->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + MMSHPort->setMinimum(1); + MMSHPort->setMaximum(65535); + MMSHPort->setValue(1234); + + layout->addWidget(MMSHEdit, 1, 1, 1, 1); + layout->addWidget(MMSHPort, 2, 1, 1, 1); + CS( MMSHPort ); + CT( MMSHEdit ); +} + +QString MMSHDestBox::getMRL( QString mux ) +{ + if( MMSHEdit->text().isEmpty() ) return ""; + + SoutMrl m; + m.begin( "std" ); + m.option( "access", "mmsh" ); + m.option( "mux", "asfh" ); + m.option( "dst", MMSHEdit->text(), MMSHPort->value() ); + m.end(); + + return m.getMrl(); +} + + +UDPDestBox::UDPDestBox( QWidget *_parent ) : VirtualDestBox( _parent ) +{ + QGridLayout *layout = new QGridLayout( this ); + + QLabel *udpOutput = new QLabel( + qtr( "This modules streams on the networks with the UDP protocol."), this ); + layout->addWidget(udpOutput, 0, 0, 1, -1); + + QLabel *UDPLabel = new QLabel( qtr("Address"), this ); + QLabel *UDPPortLabel = new QLabel( qtr("Port"), this ); + layout->addWidget(UDPLabel, 1, 0, 1, 1); + layout->addWidget(UDPPortLabel, 2, 0, 1, 1); + + UDPEdit = new QLineEdit(this); + + UDPPort = new QSpinBox(this); + UDPPort->setMaximumSize(QSize(90, 16777215)); + UDPPort->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + UDPPort->setMinimum(1); + UDPPort->setMaximum(65535); + UDPPort->setValue(1234); + + layout->addWidget(UDPEdit, 1, 1, 1, 1); + layout->addWidget(UDPPort, 2, 1, 1, 1); + CS( UDPPort ); + CT( UDPEdit ); +} + +QString UDPDestBox::getMRL( QString mux ) +{ + if( UDPEdit->text().isEmpty() ) return ""; + + SoutMrl m; + m.begin( "std" ); + m.option( "access", "udp" ); + if( !mux.isEmpty() ) + m.option( "mux", mux ); + m.option( "dst", UDPEdit->text(), UDPPort->value() ); + m.end(); + + return m.getMrl(); +} + + + +RTPDestBox::RTPDestBox( QWidget *_parent ) : VirtualDestBox( _parent ) +{ + QGridLayout *layout = new QGridLayout( this ); + + QLabel *rtpOutput = new QLabel( + qtr( "This modules streams on the networks with the RTP protocol."), this ); + layout->addWidget(rtpOutput, 0, 0, 1, -1); + + QLabel *RTPLabel = new QLabel( qtr("Address"), this ); + QLabel *RTPPortLabel = new QLabel( qtr("Port"), this ); + layout->addWidget(RTPLabel, 1, 0, 1, 1); + layout->addWidget(RTPPortLabel, 2, 0, 1, 1); + + RTPEdit = new QLineEdit(this); + + RTPPort = new QSpinBox(this); + RTPPort->setMaximumSize(QSize(90, 16777215)); + RTPPort->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + RTPPort->setMinimum(1); + RTPPort->setMaximum(65535); + RTPPort->setValue(1234); + + RTPPortAudio = new QSpinBox(this); + RTPPortAudio->setMaximumSize(QSize(90, 16777215)); + RTPPortAudio->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + RTPPortAudio->setMinimum(-1); + RTPPortAudio->setMaximum(65535); + RTPPortAudio->setValue(-1); + + RTPPortVideo = new QSpinBox(this); + RTPPortVideo->setMaximumSize(QSize(90, 16777215)); + RTPPortVideo->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + RTPPortVideo->setMinimum(-1); + RTPPortVideo->setMaximum(65535); + RTPPortVideo->setValue(-1); + + layout->addWidget(RTPEdit, 1, 1, 1, 1); + layout->addWidget(RTPPort, 2, 1, 1, 1); + + QLabel *RTPPortAudioLabel = new QLabel( qtr("Audio Port"), this ); + QLabel *RTPPortVideoLabel = new QLabel( qtr("Video Port"), this ); + layout->addWidget(RTPPortAudioLabel, 3, 0, 1, 1); + layout->addWidget(RTPPortAudio, 3, 1, 1, 1); + layout->addWidget(RTPPortVideoLabel, 3, 2, 1, 1); + layout->addWidget(RTPPortVideo, 3, 3, 1, 1); + + + CS( RTPPort ); + CS( RTPPortAudio ); + CS( RTPPortVideo ); + CT( RTPEdit ); +} + +QString RTPDestBox::getMRL( QString mux ) +{ + if( RTPEdit->text().isEmpty() ) return ""; + + SoutMrl m; + m.begin( "rtp" ); + m.option( "dst", RTPEdit->text() ); + m.option( "port", RTPPort->value() ); + if( !mux.isEmpty() ) + m.option( "mux", mux ); + if( mux.isEmpty() || mux.compare( "ts", Qt::CaseInsensitive ) ) + { + + m.option( "port-audio", RTPPortAudio->value() ); + m.option( "port-video", RTPPortVideo->value() ); + } + m.end(); + + return m.getMrl(); +} + + +ICEDestBox::ICEDestBox( QWidget *_parent ) : VirtualDestBox( _parent ) +{ + QGridLayout *layout = new QGridLayout( this ); + + QLabel *iceOutput = new QLabel( + qtr( "This modules streams using IceCast."), this ); + layout->addWidget(iceOutput, 0, 0, 1, -1); + + QLabel *ICELabel = new QLabel( qtr("Address"), this ); + QLabel *ICEPortLabel = new QLabel( qtr("Port"), this ); + layout->addWidget(ICELabel, 1, 0, 1, 1); + layout->addWidget(ICEPortLabel, 2, 0, 1, 1); + + ICEEdit = new QLineEdit(this); + + ICEPort = new QSpinBox(this); + ICEPort->setMaximumSize(QSize(90, 16777215)); + ICEPort->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ICEPort->setMinimum(1); + ICEPort->setMaximum(65535); + ICEPort->setValue(1234); + + layout->addWidget(ICEEdit, 1, 1, 1, 1); + layout->addWidget(ICEPort, 2, 1, 1, 1); + + QLabel *IcecastMountpointLabel = new QLabel( qtr( "Mount Point" ), this ); + QLabel *IcecastNameLabel = new QLabel( qtr( "Login:pass" ), this ); + ICEMountEdit = new QLineEdit( this ); + ICEPassEdit = new QLineEdit( this ); + layout->addWidget(IcecastMountpointLabel, 3, 0, 1, 1 ); + layout->addWidget(ICEMountEdit, 3, 1, 1, -1 ); + layout->addWidget(IcecastNameLabel, 4, 0, 1, 1 ); + layout->addWidget(ICEPassEdit, 4, 1, 1, -1 ); + + CS( ICEPort ); + CT( ICEEdit ); + CT( ICEMountEdit ); + CT( ICEPassEdit ); +} + +QString ICEDestBox::getMRL( QString mux ) +{ + if( ICEEdit->text().isEmpty() ) return ""; + + SoutMrl m; + m.begin( "std" ); + m.option( "access", "shout" ); + m.option( "mux", "ogg" ); + + QString url = ICEPassEdit->text() + "@" + + ICEEdit->text() + + ":" + QString::number( ICEPort->value(), 10 ) + + "/" + ICEMountEdit->text(); + + m.option( "dst", url ); + m.end(); + return m.getMrl(); +} + diff --git a/modules/gui/qt4/components/sout/sout_widgets.hpp b/modules/gui/qt4/components/sout/sout_widgets.hpp index f10cf2fd17..83d8e28100 100644 --- a/modules/gui/qt4/components/sout/sout_widgets.hpp +++ b/modules/gui/qt4/components/sout/sout_widgets.hpp @@ -30,6 +30,7 @@ class QLineEdit; class QLabel; +class QSpinBox; class SoutInputBox : public QGroupBox { @@ -43,4 +44,89 @@ class SoutInputBox : public QGroupBox }; +class VirtualDestBox : public QWidget +{ + Q_OBJECT; + public: + VirtualDestBox( QWidget *_parent = NULL ) : QWidget( _parent ){} + virtual QString getMRL( QString ) = 0; + protected: + QString mrl; + signals: + void mrlUpdated(); +}; + +class FileDestBox: public VirtualDestBox +{ + Q_OBJECT; + public: + FileDestBox( QWidget *_parent = NULL ); + virtual QString getMRL( QString ); + private: + QLineEdit *fileEdit; + private slots: + void fileBrowse(); +}; + +class HTTPDestBox: public VirtualDestBox +{ + Q_OBJECT; + public: + HTTPDestBox( QWidget *_parent = NULL ); + virtual QString getMRL( QString ); + private: + QLineEdit *HTTPEdit; + QSpinBox *HTTPPort; +}; + +class MMSHDestBox: public VirtualDestBox +{ + Q_OBJECT; + public: + MMSHDestBox( QWidget *_parent = NULL ); + virtual QString getMRL( QString ); + private: + QLineEdit *MMSHEdit; + QSpinBox *MMSHPort; +}; + +class UDPDestBox: public VirtualDestBox +{ + Q_OBJECT; + public: + UDPDestBox( QWidget *_parent = NULL ); + virtual QString getMRL( QString ); + private: + QLineEdit *UDPEdit; + QSpinBox *UDPPort; +}; + +class RTPDestBox: public VirtualDestBox +{ + Q_OBJECT; + public: + RTPDestBox( QWidget *_parent = NULL ); + virtual QString getMRL( QString ); + private: + QLineEdit *RTPEdit; + QSpinBox *RTPPort; + QSpinBox *RTPPortVideo; + QSpinBox *RTPPortAudio; +}; + +class ICEDestBox: public VirtualDestBox +{ + Q_OBJECT; + public: + ICEDestBox( QWidget *_parent = NULL ); + virtual QString getMRL( QString ); + private: + QLineEdit *ICEEdit; + QLineEdit *ICEMountEdit; + QLineEdit *ICEPassEdit; + QSpinBox *ICEPort; +}; + + + #endif diff --git a/modules/gui/qt4/dialogs/sout.cpp b/modules/gui/qt4/dialogs/sout.cpp index 59c8ab55c0..250dc3cf5e 100644 --- a/modules/gui/qt4/dialogs/sout.cpp +++ b/modules/gui/qt4/dialogs/sout.cpp @@ -37,55 +37,7 @@ #include #include - -struct streaming_account_t -{ - char *psz_username; /*< username of account */ - char *psz_password; /*< password of account */ -}; - -struct sout_gui_descr_t -{ - /* Access types */ - bool b_local; /*< local access module */ - bool b_file; /*< file access module */ - bool b_http; /*< http access module */ - bool b_mms; /*< mms access module */ - bool b_rtp; /*< rtp access module */ - bool b_udp; /*< udp access module */ - bool b_dump; /*< dump access module */ - bool b_icecast; /*< icecast access module */ - - char *psz_file; /*< filename */ - char *psz_http; /*< HTTP servername or ipaddress */ - char *psz_mms; /*< MMS servername or ipaddress */ - char *psz_rtp; /*< RTP servername or ipaddress */ - char *psz_udp; /*< UDP servername or ipaddress */ - char *psz_icecast; /*< Icecast servername or ipaddress*/ - - int32_t i_http; /*< http port number */ - int32_t i_mms; /*< mms port number */ - int32_t i_rtp; /*< rtp port number */ - int32_t i_rtp_audio; /*< rtp port number */ - int32_t i_rtp_video; /*< rtp port number */ - int32_t i_udp; /*< udp port number */ - int32_t i_icecast; /*< icecast port number */ - - /* Mux */ - char *psz_mux; /*< name of muxer to use in streaming */ - - /* Misc */ - bool b_sap; /*< send SAP announcement */ - bool b_all_es;/*< send all elementary streams from source stream */ - bool b_sout_keep; - char *psz_group; /*< SAP Group name */ - char *psz_name; /*< SAP name */ - int32_t i_ttl; /*< Time To Live (TTL) for network traversal */ - - /* Icecast */ - char *psz_icecast_mountpoint;/*< path to Icecast mountpoint */ - struct streaming_account_t sa_icecast; /*< Icecast account information */ -}; +#include SoutDialog* SoutDialog::instance = NULL; @@ -103,46 +55,44 @@ SoutDialog::SoutDialog( QWidget *parent, intf_thread_t *_p_intf, QString inputMR "You should start by checking that your input matches what you " "want and go on with the \"Next\" button.\n" ); - changeUDPandRTPmess( false ); - -/* ADD HERE for new profiles */ -#define ADD_PROFILE( name, shortname ) ui.profileBox->addItem( qtr( name ), QVariant( QString( shortname ) ) ); -/* ADD_PROFILE( "Custom" , "Custom" ) - ADD_PROFILE( "Ogg / Theora", "theora" ) - ADD_PROFILE( "Ogg / Vorbis", "vorbis" ) - ADD_PROFILE( "MPEG-2", "mpeg2" ) - ADD_PROFILE( "MP3", "mp3" ) - ADD_PROFILE( "MPEG-4 audio AAC", "aac" ) - ADD_PROFILE( "MPEG-4 / DivX", "mp4" ) - ADD_PROFILE( "H264", "h264" ) - ADD_PROFILE( "IPod (mp4/aac)", "IPod" ) - ADD_PROFILE( "XBox", "XBox" ) - ADD_PROFILE( "Windows (wmv/asf)", "Windows" ) - ADD_PROFILE( "PSP", "PSP") - -*/ ui.mrlEdit->setToolTip ( qtr( "Stream output string.\n" "This is automatically generated " "when you change the above settings,\n" "but you can change it manually." ) ) ; +#if 0 + /* This needs Qt4.5 to be cool */ + ui.destTab->setTabsClosable( true ); +#else + closeTabButton = new QToolButton( this ); + ui.destTab->setCornerWidget( closeTabButton ); + closeTabButton->hide(); + closeTabButton->setAutoRaise( true ); + closeTabButton->setIcon( QIcon( ":/clear" ) ); + BUTTONACT( closeTabButton, closeTab() ); +#endif + CONNECT( ui.destTab, currentChanged( int ), this, tabChanged( int ) ); + ui.destTab->setTabIcon( 0, QIcon( ":/playlist_add" ) ); + + ui.destBox->addItem( qtr( "File" ) ); + ui.destBox->addItem( "HTTP" ); + ui.destBox->addItem( "MMS" ); + ui.destBox->addItem( "UDP" ); + ui.destBox->addItem( "RTP" ); + ui.destBox->addItem( "IceCast" ); + + BUTTONACT( ui.addButton, addDest() ); + // /* Connect everything to the updateMRL function */ #define CB( x ) CONNECT( ui.x, toggled( bool ), this, updateMRL() ); #define CT( x ) CONNECT( ui.x, textChanged( const QString ), this, updateMRL() ); #define CS( x ) CONNECT( ui.x, valueChanged( int ), this, updateMRL() ); #define CC( x ) CONNECT( ui.x, currentIndexChanged( int ), this, updateMRL() ); - /* Output */ - CB( fileOutput ); CB( HTTPOutput ); CB( localOutput ); - CB( RTPOutput ); CB( MMSHOutput ); CB( rawInput ); CB( UDPOutput ); - CT( fileEdit ); CT( HTTPEdit ); CT( RTPEdit ); CT( MMSHEdit ); CT( UDPEdit ); - CT( IcecastEdit ); CT( IcecastMountpointEdit ); CT( IcecastNamePassEdit ); - CS( HTTPPort ); CS( RTPPort ); CS( RTPPort2 ); CS( MMSHPort ); CS( UDPPort ); + /* Misc */ CB( soutAll ); CB( soutKeep ); CS( ttl ); CT( sapName ); CT( sapGroup ); - -// CONNECT( ui.profileSelect, optionsChanged(), this, updateMRL() ); - CONNECT( ui.fileSelectButton, clicked() , this, fileBrowse() ); - CONNECT( ui.rawInput, toggled( bool ), this, setRawOptions( bool ) ); + CB( localOutput ); + CONNECT( ui.profileSelect, optionsChanged(), this, updateMRL() ); okButton = new QPushButton( qtr( "&Stream" ) ); QPushButton *cancelButton = new QPushButton( qtr( "&Cancel" ) ); @@ -154,9 +104,6 @@ SoutDialog::SoutDialog( QWidget *parent, intf_thread_t *_p_intf, QString inputMR BUTTONACT( okButton, ok() ); BUTTONACT( cancelButton, cancel() ); - CONNECT( ui.UDPOutput, toggled( bool ), this, changeUDPandRTPmess( bool ) ); - CONNECT( ui.RTPOutput, clicked(bool), this, RTPtoggled( bool ) ); - BUTTONACT( ui.nextButton, next() ); BUTTONACT( ui.nextButton2, next() ); BUTTONACT( ui.prevButton, prev() ); @@ -173,113 +120,72 @@ void SoutDialog::prev() ui.toolBox->setCurrentIndex( ui.toolBox->currentIndex() - 1 ); } - -void SoutDialog::fileBrowse() -{ - QString fileName = QFileDialog::getSaveFileName( this, qtr( "Save file..." ), - "", qtr( "Containers (*.ps *.ts *.mpg *.ogg *.asf *.mp4 *.mov *.wav *.raw *.flv)" ) ); - ui.fileEdit->setText( toNativeSeparators( fileName ) ); - updateMRL(); -} - -void SoutDialog::setRawOptions( bool b_raw ) +void SoutDialog::tabChanged( int i ) { - ui.localOutput->setEnabled( !b_raw ); - ui.HTTPOutput->setEnabled( !b_raw ); - ui.MMSHOutput->setEnabled( !b_raw ); - ui.UDPOutput->setEnabled( !b_raw ); - ui.RTPOutput->setEnabled( !b_raw ); - ui.IcecastOutput->setEnabled( !b_raw ); - ui.UDPRTPLabel->setEnabled( !b_raw ); - - if( b_raw ) - ; -// ui.tabWidget->setDisabled( true ); - else - setOptions(); + closeTabButton->setVisible( (i != 0) ); } -void SoutDialog::setOptions() +void SoutDialog::closeTab() { -/* QString profileString = - ui.profileBox->itemData( ui.profileBox->currentIndex() ).toString(); - msg_Dbg( p_intf, "Profile Used: %s", qtu( profileString )); */ - int index; - -#define setProfile( muxName, hasVideo, vCodecName, hasAudio, aCodecName ) \ - { \ - ui.muxName ##Mux->setChecked( true ); \ - \ - ui.transcodeAudio->setChecked( hasAudio ); \ - index = ui.aCodecBox->findData( aCodecName ); \ - if( index >= 0 ) ui.aCodecBox->setCurrentIndex( index ); \ - \ - ui.transcodeVideo->setChecked( hasVideo ); \ - index = ui.vCodecBox->findData( vCodecName ); \ - if( index >=0 ) ui.vCodecBox->setCurrentIndex( index ); \ - } + int i = ui.destTab->currentIndex(); + if( i == 0 ) return; - /* ADD HERE the profiles you want and need */ -/* if( profileString == "IPod" ) setProfile( MP4, true, "mp4v", true, "mp4a" ) - else if( profileString == "theora" ) setProfile( Ogg, true, "theo", true, "vorb" ) - else if( profileString == "vorbis" ) setProfile( Ogg, false, "", true, "vorb" ) - else if( profileString == "mpeg2" ) setProfile( TS, true, "mp2v", true, "mpga" ) - else if( profileString == "mp3" ) setProfile( RAW, false, "", true, "mp3" ) - else if( profileString == "aac" ) setProfile( MP4, false, "", true, "mp4a" ) - else if( profileString == "mp4" ) setProfile( MP4, true, "mp4v", true, "mp4a" ) - else if( profileString == "h264" ) setProfile( TS, true, "h264", true, "mp4a" ) - else if( profileString == "XBox" ) setProfile( ASF, true, "WMV2", true, "wma" ) - else if( profileString == "Windows" ) setProfile( ASF, true, "WMV2", true, "wma" ) - else if( profileString == "PSP" ) setProfile( MP4, true, "mp4v", true, "mp4a" )*/ - - /* If the profile is not a custom one, then disable the tabWidget */ - /* if ( profileString == "Custom" ) - ui.tabWidget->setEnabled( true ); - else - ui.tabWidget->setDisabled( true ); - - /* Update the MRL !! */ + QWidget *temp = ui.destTab->currentWidget(); + ui.destTab->removeTab( i ); + delete temp; updateMRL(); } -void SoutDialog::changeUDPandRTPmess( bool b_udp ) +void SoutDialog::addDest( ) { - ui.RTPEdit->setVisible( !b_udp ); - ui.RTPLabel->setVisible( !b_udp ); - ui.RTPPort->setVisible( !b_udp ); - ui.RTPPortLabel->setVisible( !b_udp ); - ui.UDPEdit->setVisible( b_udp ); - ui.UDPLabel->setVisible( b_udp ); - ui.UDPPortLabel->setText( b_udp ? qtr( "Port:") : qtr( "Audio Port:" ) ); - ui.RTPPort2->setVisible( !b_udp ); - ui.RTPPortLabel2->setVisible( !b_udp ); -} - -void SoutDialog::RTPtoggled( bool b_en ) -{ - if( !b_en ) + int index; + switch( ui.destBox->currentIndex() ) { - if( ui.RTPPort->value() == ui.UDPPort->value() ) - { - ui.UDPPort->setValue( ui.UDPPort->value() + 1 ); - } - - while( ui.RTPPort2->value() == ui.UDPPort->value() || - ui.RTPPort2->value() == ui.RTPPort->value() ) - { - ui.RTPPort2->setValue( ui.RTPPort2->value() + 1 ); - } + case 0: + { + FileDestBox *fdb = new FileDestBox( this ); + index = ui.destTab->addTab( fdb, "File" ); + CONNECT( fdb, mrlUpdated(), this, updateMRL() ); + } + break; + case 1: + { + HTTPDestBox *hdb = new HTTPDestBox( this ); + index = ui.destTab->addTab( hdb, "HTTP" ); + CONNECT( hdb, mrlUpdated(), this, updateMRL() ); + } + break; + case 2: + { + MMSHDestBox *mdb = new MMSHDestBox( this ); + index = ui.destTab->addTab( mdb, "MMSH" ); + CONNECT( mdb, mrlUpdated(), this, updateMRL() ); + } + break; + case 3: + { + UDPDestBox *udb = new UDPDestBox( this ); + index = ui.destTab->addTab( udb, "UDP" ); + CONNECT( udb, mrlUpdated(), this, updateMRL() ); + } + break; + case 4: + { + RTPDestBox *rdb = new RTPDestBox( this ); + index = ui.destTab->addTab( rdb, "RTP" ); + CONNECT( rdb, mrlUpdated(), this, updateMRL() ); + } + break; + case 5: + { + ICEDestBox *idb = new ICEDestBox( this ); + index = ui.destTab->addTab( idb, "Icecast" ); + CONNECT( idb, mrlUpdated(), this, updateMRL() ); + } } - ui.sap->setEnabled( b_en ); - ui.RTPLabel->setEnabled( b_en ); - ui.RTPEdit->setEnabled( b_en ); - ui.UDPOutput->setEnabled( b_en ); - ui.UDPRTPLabel->setEnabled( b_en ); - ui.UDPEdit->setEnabled( b_en ); - ui.UDPPort->setEnabled( b_en ); - ui.UDPPortLabel->setEnabled( b_en ); - ui.RTPPort2->setEnabled( b_en ); - ui.RTPPortLabel2->setEnabled( b_en ); + + ui.destTab->setCurrentIndex( index ); + updateMRL(); } void SoutDialog::ok() @@ -296,222 +202,62 @@ void SoutDialog::cancel() void SoutDialog::updateMRL() { - sout_gui_descr_t sout; - memset( &sout, 0, sizeof( sout_gui_descr_t ) ); - unsigned int counter = 0; - - sout.b_local = ui.localOutput->isChecked(); - sout.b_file = ui.fileOutput->isChecked(); - sout.b_http = ui.HTTPOutput->isChecked(); - sout.b_mms = ui.MMSHOutput->isChecked(); - sout.b_icecast = ui.IcecastOutput->isChecked(); - sout.b_rtp = ui.RTPOutput->isChecked(); - sout.b_udp = ui.UDPOutput->isChecked(); - sout.b_dump = ui.rawInput->isChecked(); - sout.b_sap = ui.sap->isChecked(); - sout.b_all_es = ui.soutAll->isChecked(); - sout.b_sout_keep = ui.soutKeep->isChecked(); -/* sout.psz_vcodec = strdup( qtu( ui.vCodecBox->itemData( ui.vCodecBox->currentIndex() ).toString() ) ); - sout.psz_acodec = strdup( qtu( ui.aCodecBox->itemData( ui.aCodecBox->currentIndex() ).toString() ) ); - sout.psz_scodec = strdup( qtu( ui.subsCodecBox->itemData( ui.subsCodecBox->currentIndex() ).toString() ) );*/ - sout.psz_file = strdup( qtu( ui.fileEdit->text() ) ); - sout.psz_http = strdup( qtu( ui.HTTPEdit->text() ) ); - sout.psz_mms = strdup( qtu( ui.MMSHEdit->text() ) ); - sout.psz_rtp = strdup( qtu( ui.RTPEdit->text() ) ); - sout.psz_udp = strdup( qtu( ui.UDPEdit->text() ) ); - sout.psz_icecast = strdup( qtu( ui.IcecastEdit->text() ) ); - sout.sa_icecast.psz_username = strdup( qtu( ui.IcecastNamePassEdit->text() ) ); - sout.sa_icecast.psz_password = strdup( qtu( ui.IcecastNamePassEdit->text() ) ); - sout.psz_icecast_mountpoint = strdup( qtu( ui.IcecastMountpointEdit->text() ) ); - sout.i_http = ui.HTTPPort->value(); - sout.i_mms = ui.MMSHPort->value(); - sout.i_rtp = ui.RTPPort->value(); - sout.i_rtp_audio = sout.i_udp = ui.UDPPort->value(); - sout.i_rtp_video = ui.RTPPort2->value(); - sout.i_icecast = ui.IcecastPort->value(); -/* sout.i_ab = ui.aBitrateSpin->value(); - sout.i_vb = ui.vBitrateSpin->value(); - sout.i_channels = ui.aChannelsSpin->value(); - sout.f_scale = atof( qtu( ui.vScaleBox->currentText() ) ); */ - sout.psz_group = strdup( qtu( ui.sapGroup->text() ) ); - sout.psz_name = strdup( qtu( ui.sapName->text() ) ); - - if ( sout.b_local ) counter++ ; - if ( sout.b_file ) counter++ ; - if ( sout.b_http ) counter++ ; - if ( sout.b_mms ) counter++ ; - if ( sout.b_rtp ) counter++ ; - if ( sout.b_udp ) counter ++; - if ( sout.b_icecast ) counter ++; - - sout.psz_mux = strdup( qtu( ui.profileSelect->getMux() ) ); - - bool trans = false; - bool more = false; + QString qs_mux = ui.profileSelect->getMux(); SoutMrl smrl( ":sout=#" ); - - /* Special case for demuxdump */ - if ( sout.b_file && sout.b_dump ) - { - mrl = ":demux=dump :demuxdump-file="; - mrl.append( qfu( sout.psz_file ) ); - } - else { if( !ui.profileSelect->getTranscode().isEmpty() ) { smrl.begin( ui.profileSelect->getTranscode() ); smrl.end(); } - /* Protocol output */ - if ( sout.b_local || sout.b_file || sout.b_http || - sout.b_mms || sout.b_rtp || sout.b_udp || sout.b_icecast ) - { - if( counter > 1 ) - smrl.begin( "duplicate" ); - -#define ADD(m) do { if( counter > 1 ) { \ - smrl.option( "dst", m.getMrl() ); \ - } else { \ - smrl.begin( m.getMrl() ); \ - smrl.end(); \ - } } while(0) - - if ( sout.b_local ) - { - SoutMrl m; - m.begin( "display" ); - m.end(); - - ADD( m ); - more = true; - } - - if ( sout.b_file ) - { - SoutMrl m; - - m.begin( "std" ); - m.option( "access", "file" ); - if( sout.psz_mux ) - m.option( "mux", qfu( sout.psz_mux ) ); - m.option( "dst", qfu( sout.psz_file ) ); - m.end(); - - ADD( m ); - more = true; - } + bool multi = false; - if ( sout.b_http ) - { - SoutMrl m; + if( ui.destTab->count() >= 3 || + ( ui.destTab->count() == 2 && ui.localOutput->isChecked() ) ) + multi = true; - m.begin( "std" ); - m.option( "access", "http" ); - if( sout.psz_mux ) - m.option( "mux", qfu( sout.psz_mux ) ); - m.option( "dst", qfu( sout.psz_http ), sout.i_http ); - m.end(); + if( multi ) + smrl.begin( "duplicate" ); - ADD( m ); - more = true; - } + for( int i = 1; i < ui.destTab->count(); i++ ) + { + VirtualDestBox *vdb = qobject_cast(ui.destTab->widget( i )); + QString tempMRL = vdb->getMRL( qs_mux ); - if ( sout.b_mms ) + if( tempMRL.isEmpty() ) continue; + if( multi ) + smrl.option( "dst", tempMRL ); + else { - SoutMrl m; - - m.begin( "std" ); - m.option( "access", "mmsh" ); - m.option( "mux", "asfh" ); - m.option( "dst", qfu( sout.psz_mms ), sout.i_mms ); - m.end(); - - ADD( m ); - more = true; + smrl.begin( tempMRL); + smrl.end(); } - - if ( sout.b_rtp ) + } + if( ui.localOutput->isChecked() ) + { + if( multi ) + smrl.option( "dst", "display" ); + else { - SoutMrl m; - if ( sout.b_udp ) - { - m.begin( "std" ); - m.option( "access", "udp" ); - if( sout.psz_mux ) - m.option( "mux", qfu( sout.psz_mux ) ); - m.option( "dst", qfu( sout.psz_udp ), sout.i_udp ); - } - else - { - m.begin( "rtp" ); - - if( sout.psz_rtp && *sout.psz_rtp ) - m.option( "dst", qfu( sout.psz_rtp ) ); - if( sout.psz_mux ) - m.option( "mux", qfu( sout.psz_mux ) ); - - m.option( "port", sout.i_rtp ); - if( !sout.psz_mux || strncmp( sout.psz_mux, "ts", 2 ) ) - { - m.option( "port-audio", sout.i_rtp_audio ); - m.option( "port-video", sout.i_rtp_video ); - } - } - - /* SAP */ - if ( sout.b_sap ) - { - m.option( "sap" ); - m.option( "group", qfu( sout.psz_group ) ); - m.option( "name", qfu( sout.psz_name ) ); - } - - m.end(); - ADD( m ); - more = true; + smrl.begin( "display" ); + smrl.end(); } + } - if( sout.b_icecast ) - { - SoutMrl m; - QString url; - - url = qfu(sout.sa_icecast.psz_username) + "@" - + qfu( sout.psz_icecast ) - + ":" + QString::number( sout.i_icecast, 10 ) - + "/" + qfu( sout.psz_icecast_mountpoint ); - - m.begin( "std" ); - m.option( "access", "shout" ); - m.option( "mux", "ogg" ); - m.option( "dst", url ); - m.end(); - - ADD( m ); - more = true; - } + if ( multi ) smrl.end(); - if ( counter ) - smrl.end(); + mrl = smrl.getMrl(); - mrl = smrl.getMrl(); - } - } + /* FIXME, deal with SAP + sout.b_sap = ui.sap->isChecked(); + sout.psz_group = strdup( qtu( ui.sapGroup->text() ) ); + sout.psz_name = strdup( qtu( ui.sapName->text() ) ); */ - if ( sout.b_all_es ) - mrl.append( " :sout-all" ); + if( ui.soutAll->isChecked() ) mrl.append( " :sout-all" ); - if ( sout.b_sout_keep ) - mrl.append( " :sout-keep" ); + if( ui.soutKeep->isChecked() ) mrl.append( " :sout-keep" ); ui.mrlEdit->setPlainText( mrl ); - free( sout.psz_file );free( sout.psz_http ); free( sout.psz_mms ); - free( sout.psz_rtp ); free( sout.psz_udp ); free( sout.psz_mux ); - free( sout.psz_name ); free( sout.psz_group ); - free( sout.psz_icecast ); free( sout.psz_icecast_mountpoint ); - free( sout.sa_icecast.psz_password ); free( sout.sa_icecast.psz_username ); } - diff --git a/modules/gui/qt4/dialogs/sout.hpp b/modules/gui/qt4/dialogs/sout.hpp index d5b391b1e8..67ee3aba99 100644 --- a/modules/gui/qt4/dialogs/sout.hpp +++ b/modules/gui/qt4/dialogs/sout.hpp @@ -34,6 +34,7 @@ #include "util/qvlcframe.hpp" class QPushButton; +class QToolButton; class QCheckBox; class QGridLayout; class QTextEdit; @@ -133,8 +134,10 @@ private: Ui::Sout ui; static SoutDialog *instance; SoutDialog( QWidget* parent, intf_thread_t *, QString mrl ); - QPushButton *okButton; + QString mrl; + QPushButton *okButton; + QToolButton *closeTabButton; public slots: void updateMRL(); @@ -142,13 +145,11 @@ public slots: private slots: void ok(); void cancel(); - void setOptions(); - void fileBrowse(); - void setRawOptions( bool ); - void changeUDPandRTPmess( bool ); - void RTPtoggled( bool ); void next(); void prev(); + void closeTab(); + void tabChanged( int ); + void addDest(); }; #endif diff --git a/modules/gui/qt4/ui/sout.ui b/modules/gui/qt4/ui/sout.ui index 504936d3d3..72c5403321 100644 --- a/modules/gui/qt4/ui/sout.ui +++ b/modules/gui/qt4/ui/sout.ui @@ -7,8 +7,8 @@ 0 0 - 651 - 532 + 708 + 587 @@ -18,15 +18,15 @@ - 0 + 1 - + 0 0 - 633 - 414 + 690 + 469 @@ -127,452 +127,147 @@ - + 0 0 - 649 - 399 + 690 + 469 _("Destination") - + - - - - - _("Play locally") - - - - - - - Qt::NoContextMenu - - - _("File") - - - - - - - _("Filename") - - - - - - - - - - - 0 - 0 - - - - _("Browse...") - - - - - - - _("Dump raw input") - - - - - - - HTTP - - - - - - - _("Address") - - - - - - - - - - _("Port:") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 65535 - - - 1 - - - 8080 - - - - - - - MMSH - - - - - - - _("Address") - - - - - - - - - - _("Port:") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 65535 - - - 1234 - - - - - - - RTP - - - - - - - _("Address") - - - - - - - - - - _("Port:") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 65535 - - - 1234 - - - - - - - true - - - _("Address") - - - - - - - - - - _("Port") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - 1 - - - 65535 - - - 1234 - - - - - - - _("Video Port") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - 65355 - - - 1234 - - - - - - - IceCast - - - - - - - _("Address") - - - - - - - - - - _("Port:") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 65535 - - - 1024 - - - - - - - _("Mount Point") - - - - - - - - - - _("Login:pass:") - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - 0 - 0 - - - - - 100 - 16777215 - - - - _("Prefer UDP over RTP") - - - Qt::PlainText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - UDPOutput - - - - - - - - 0 - 0 - - - - _("Using this option is not recommended in most of the cases.") - - - - - - - + + + _("Destinations") + + + + + + 0 + + + + + + + + + + _("New destination") + + + + + + + + + + + 0 + 0 + + + + _("Add") + + + + + + + _("Add destinations following the streaming methods you need. +Be sure to check with transcoding that the format is compatible with the method used.") + + + Qt::PlainText + + + true + + + + + + + _("Display locally") + + + + + + + + + - + + + + _("Transcoding options") + + + + + + + + + _("Previous") - - + + Qt::Horizontal - 581 - 20 + 382 + 26 - + _("Next") + + + + Qt::Vertical + + + + 20 + 40 + + + + - + 0 0 - 633 - 414 + 690 + 469 @@ -580,23 +275,6 @@ - - - Qt::Horizontal - - - - - - - - - - Qt::Horizontal - - - - _("Miscellaneous") @@ -659,7 +337,7 @@ - + _("Generated stream output string") @@ -675,14 +353,14 @@ - + _("Previous") - + Qt::Horizontal