]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/sout/profile_selector.cpp
Qt: profile_selector: Bind data to muxers
[vlc] / modules / gui / qt4 / components / sout / profile_selector.cpp
1 /*****************************************************************************
2  * profile_selector.cpp : A small profile selector and editor
3  ****************************************************************************
4  * Copyright (C) 2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Baptiste Kempf <jb@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24
25 #include "components/sout/profile_selector.hpp"
26 #include "components/sout/profiles.hpp"
27 #include "dialogs/sout.hpp"
28
29 #include <QHBoxLayout>
30 #include <QToolButton>
31 #include <QComboBox>
32 #include <QLabel>
33 #include <QMessageBox>
34 #include <QRadioButton>
35
36 #include <assert.h>
37
38 VLCProfileSelector::VLCProfileSelector( QWidget *_parent ): QWidget( _parent )
39 {
40     QHBoxLayout *layout = new QHBoxLayout( this );
41
42     QLabel *prLabel = new QLabel( qtr( "Profile"), this );
43     layout->addWidget( prLabel );
44
45     profileBox = new QComboBox( this );
46     layout->addWidget( profileBox );
47
48     QToolButton *editButton = new QToolButton( this );
49     editButton->setIcon( QIcon( ":/menu/preferences" ) );
50     editButton->setToolTip( qtr( "Edit selected profile" ) );
51     layout->addWidget( editButton );
52
53     QToolButton *deleteButton = new QToolButton( this );
54     deleteButton->setIcon( QIcon( ":/toolbar/clear" ) );
55     deleteButton->setToolTip( qtr( "Delete selected profile" ) );
56     layout->addWidget( deleteButton );
57
58     QToolButton *newButton = new QToolButton( this );
59     newButton->setIcon( QIcon( ":/new" ) );
60     newButton->setToolTip( qtr( "Create a new profile" ) );
61     layout->addWidget(newButton);
62
63     BUTTONACT( newButton, newProfile() );
64     BUTTONACT( editButton, editProfile() );
65     BUTTONACT( deleteButton, deleteProfile() );
66     fillProfilesCombo();
67
68     CONNECT( profileBox, activated( int ),
69              this, updateOptions( int ) );
70
71     updateOptions( 0 );
72 }
73
74 inline void VLCProfileSelector::fillProfilesCombo()
75 {
76     QSettings settings(
77 #ifdef WIN32
78             QSettings::IniFormat,
79 #else
80             QSettings::NativeFormat,
81 #endif
82             QSettings::UserScope, "vlc", "vlc-qt-interface" );
83
84     int i_size = settings.beginReadArray( "codecs-profiles" );
85
86     for( int i = 0; i < i_size; i++ )
87     {
88         settings.setArrayIndex( i );
89         if( settings.value( "Profile-Name" ).toString().isEmpty() ) continue;
90         profileBox->addItem( settings.value( "Profile-Name" ).toString(),
91                 settings.value( "Profile-Value" ) );
92     }
93     if( i_size == 0 )
94     {
95         for( size_t i = 0; i < NB_PROFILE; i++ )
96         {
97             profileBox->addItem( video_profile_name_list[i],
98                                  video_profile_value_list[i] );
99         }
100     }
101     settings.endArray();
102 }
103
104 void VLCProfileSelector::newProfile()
105 {
106     editProfile( "", "" );
107 }
108
109 void VLCProfileSelector::editProfile()
110 {
111     editProfile( profileBox->currentText(),
112                  profileBox->itemData( profileBox->currentIndex() ).toString() );
113 }
114
115 void VLCProfileSelector::editProfile( const QString& qs, const QString& value )
116 {
117     /* Create the Profile Editor */
118     VLCProfileEditor *editor = new VLCProfileEditor( qs, value, this );
119
120     /* Show it */
121     if( QDialog::Accepted == editor->exec() )
122     {
123         /* New Profile */
124         if( qs.isEmpty() )
125             profileBox->addItem( editor->name, QVariant( editor->transcodeValue() ) );
126         /* Update old profile */
127         else
128         {
129             /* Look for the profile */
130             int i_profile = profileBox->findText( qs );
131             assert( i_profile != -1 );
132             profileBox->setItemText( i_profile, editor->name );
133             profileBox->setItemData( i_profile, QVariant( editor->transcodeValue() ) );
134             /* Force mrl recreation */
135             updateOptions( i_profile );
136         }
137     }
138     delete editor;
139
140     saveProfiles();
141     emit optionsChanged();
142 }
143
144 void VLCProfileSelector::deleteProfile()
145 {
146     profileBox->removeItem( profileBox->currentIndex() );
147     saveProfiles();
148 }
149
150 void VLCProfileSelector::saveProfiles()
151 {
152     QSettings settings(
153 #ifdef WIN32
154             QSettings::IniFormat,
155 #else
156             QSettings::NativeFormat,
157 #endif
158             QSettings::UserScope, "vlc", "vlc-qt-interface" );
159
160     settings.remove( "codecs-profiles" ); /* Erase old profiles to be rewritten */
161     settings.beginWriteArray( "codecs-profiles" );
162     for( int i = 0; i < profileBox->count(); i++ )
163     {
164         settings.setArrayIndex( i );
165         settings.setValue( "Profile-Name", profileBox->itemText( i ) );
166         settings.setValue( "Profile-Value", profileBox->itemData( i ).toString() );
167     }
168     settings.endArray();
169 }
170
171 void VLCProfileSelector::updateOptions( int i )
172 {
173     QStringList options = profileBox->itemData( i ).toString().split( ";" );
174     if( options.count() < 16 )
175         return;
176
177     mux = options[0];
178
179     SoutMrl smrl;
180     if( options[1].toInt() || options[2].toInt() || options[3].toInt() )
181     {
182         smrl.begin( "transcode" );
183
184         if( options[1].toInt() )
185         {
186             smrl.option( "vcodec", options[4] );
187             if( options[4] != "none" )
188             {
189                 smrl.option( "vb", options[5].toInt() );
190                 if( !options[7].isEmpty() && options[7].toInt() > 0 )
191                     smrl.option( "fps", options[7] );
192                 if( !options[6].isEmpty() )
193                     smrl.option( "scale", options[6] );
194                 if( !options[8].isEmpty() && options[8].toInt() > 0 )
195                     smrl.option( "width", options[8].toInt() );
196                 if( !options[9].isEmpty() && options[9].toInt() > 0 )
197                     smrl.option( "height", options[9].toInt() );
198             }
199         }
200
201         if( options[2].toInt() )
202         {
203             smrl.option( "acodec", options[10] );
204             if( options[10] != "none" )
205             {
206                 smrl.option( "ab", options[11].toInt() );
207                 smrl.option( "channels", options[12].toInt() );
208                 smrl.option( "samplerate", options[13].toInt() );
209             }
210         }
211
212         if( options[3].toInt() )
213         {
214             smrl.option( "scodec", options[14] );
215             if( options[15].toInt() )
216                 smrl.option( "soverlay" );
217         }
218
219         smrl.end();
220
221         transcode = smrl.getMrl();
222     }
223     else
224         transcode = "";
225     emit optionsChanged();
226 }
227
228
229 /**
230  * VLCProfileEditor
231  **/
232 VLCProfileEditor::VLCProfileEditor( const QString& qs_name, const QString& value,
233         QWidget *_parent )
234                  : QVLCDialog( _parent, NULL )
235 {
236     ui.setupUi( this );
237     if( !qs_name.isEmpty() )
238     {
239         ui.profileLine->setText( qs_name );
240         ui.profileLine->setReadOnly( true );
241     }
242     registerCodecs();
243     CONNECT( ui.transcodeVideo, toggled( bool ),
244             this, setVTranscodeOptions( bool ) );
245     CONNECT( ui.transcodeAudio, toggled( bool ),
246             this, setATranscodeOptions( bool ) );
247     CONNECT( ui.transcodeSubs, toggled( bool ),
248             this, setSTranscodeOptions( bool ) );
249     setVTranscodeOptions( false );
250     setATranscodeOptions( false );
251     setSTranscodeOptions( false );
252
253     QPushButton *saveButton = new QPushButton(
254                 ( qs_name.isEmpty() ) ? qtr( "Create" ) : qtr( "Save" ) );
255     ui.buttonBox->addButton( saveButton, QDialogButtonBox::AcceptRole );
256     BUTTONACT( saveButton, close() );
257     QPushButton *cancelButton = new QPushButton( qtr( "Cancel" ) );
258     ui.buttonBox->addButton( cancelButton, QDialogButtonBox::RejectRole );
259     BUTTONACT( cancelButton, reject() );
260
261     fillProfile( value );
262 }
263
264 inline void VLCProfileEditor::registerCodecs()
265 {
266 #define SETMUX( button, val ) ui.button->setProperty( "sout", val );
267     SETMUX( PSMux, "ps" )
268     SETMUX( TSMux, "ts" )
269     SETMUX( WEBMux, "webm" )
270     SETMUX( MPEG1Mux, "mpeg1" )
271     SETMUX( OggMux, "ogg" )
272     SETMUX( ASFMux, "asf" )
273     SETMUX( MOVMux, "mp4" )
274     SETMUX( WAVMux, "wav" )
275     SETMUX( RAWMux, "raw" )
276     SETMUX( FLVMux, "flv" )
277     SETMUX( MKVMux, "mkv" )
278     SETMUX( AVIMux, "avi" )
279     SETMUX( MJPEGMux, "mpjpeg" )
280 #undef SETMUX
281
282 #define ADD_VCODEC( name, fourcc ) ui.vCodecBox->addItem( name, QVariant( fourcc ) );
283     ADD_VCODEC( "MPEG-1", "mp1v" )
284     ADD_VCODEC( "MPEG-2", "mp2v" )
285     ADD_VCODEC( "MPEG-4", "mp4v" )
286     ADD_VCODEC( "DIVX 1" , "DIV1" )
287     ADD_VCODEC( "DIVX 2" , "DIV2" )
288     ADD_VCODEC( "DIVX 3" , "DIV3" )
289     ADD_VCODEC( "H-263", "H263" )
290     ADD_VCODEC( "H-264", "h264" )
291     ADD_VCODEC( "VP8", "VP80" )
292     ADD_VCODEC( "WMV1", "WMV1" )
293     ADD_VCODEC( "WMV2" , "WMV2" )
294     ADD_VCODEC( "M-JPEG", "MJPG" )
295     ADD_VCODEC( "Theora", "theo" )
296     ADD_VCODEC( "Dirac", "drac" )
297 #undef ADD_VCODEC
298
299 #define ADD_ACODEC( name, fourcc ) ui.aCodecBox->addItem( name, QVariant( fourcc ) );
300     ADD_ACODEC( "MPEG Audio", "mpga" )
301     ADD_ACODEC( "MP3", "mp3" )
302     ADD_ACODEC( "MPEG 4 Audio ( AAC )", "mp4a" )
303     ADD_ACODEC( "A52/AC-3", "a52" )
304     ADD_ACODEC( "Vorbis", "vorb" )
305     ADD_ACODEC( "Flac", "flac" )
306     ADD_ACODEC( "Speex", "spx" )
307     ADD_ACODEC( "WAV", "s16l" )
308     ADD_ACODEC( "WMA2", "wma2" )
309 #undef ADD_ACODEC
310
311 #define ADD_SCALING( factor ) ui.vScaleBox->addItem( factor );
312     ADD_SCALING( qtr("Auto") );
313     ADD_SCALING( "1" )
314     ADD_SCALING( "0.25" )
315     ADD_SCALING( "0.5" )
316     ADD_SCALING( "0.75" )
317     ADD_SCALING( "1.25" )
318     ADD_SCALING( "1.5" )
319     ADD_SCALING( "1.75" )
320     ADD_SCALING( "2" )
321 #undef ADD_SCALING
322
323 #define ADD_SAMPLERATE( sample, val ) ui.aSampleBox->addItem( sample, val );
324     ADD_SAMPLERATE( "8000 Hz", 8000 )
325     ADD_SAMPLERATE( "11025 Hz", 11025 )
326     ADD_SAMPLERATE( "22050 Hz", 22050 )
327     ADD_SAMPLERATE( "44100 Hz", 44100 )
328     ADD_SAMPLERATE( "48000 Hz", 48000 )
329 #undef ADD_SAMPLERATE
330
331 #define ADD_SCODEC( name, fourcc ) ui.subsCodecBox->addItem( name, QVariant( fourcc ) );
332     ADD_SCODEC( "DVB subtitle", "dvbs" )
333     ADD_SCODEC( "T.140", "t140" )
334 #undef ADD_SCODEC
335 }
336
337 void VLCProfileEditor::fillProfile( const QString& qs )
338 {
339     QStringList options = qs.split( ";" );
340     if( options.count() < 16 )
341         return;
342
343     const QString mux = options[0];
344     for ( int i=0; i< ui.muxer->layout()->count(); i++ )
345     {
346         QRadioButton *current =
347                 qobject_cast<QRadioButton *>(ui.muxer->layout()->itemAt(i)->widget());
348         if ( unlikely( !current ) ) continue;/* someone is messing up with ui */
349         if ( current->property("sout").toString() == mux )
350         {
351             current->setChecked( true );
352             break;/* radios are exclusive */
353         }
354     }
355
356     ui.keepVideo->setChecked( !options[1].toInt() );
357     ui.transcodeVideo->setChecked( ( options[4] != "none" ) );
358     ui.keepAudio->setChecked( !options[2].toInt() );
359     ui.transcodeAudio->setChecked( ( options[10] != "none" ) );
360     ui.transcodeSubs->setChecked( options[3].toInt() );
361
362     ui.vCodecBox->setCurrentIndex( ui.vCodecBox->findData( options[4] ) );
363     ui.vBitrateSpin->setValue( options[5].toInt() );
364     if ( options[6].toInt() > 0 )
365         ui.vScaleBox->setEditText( options[6] );
366     else
367         ui.vScaleBox->setCurrentIndex( 0 );
368     ui.vFrameBox->setValue( options[7].toDouble() );
369     ui.widthBox->setValue( options[8].toInt() );
370     ui.heightBox->setValue( options[9].toInt() );
371
372     ui.aCodecBox->setCurrentIndex( ui.aCodecBox->findData( options[10] ) );
373     ui.aBitrateSpin->setValue( options[11].toInt() );
374     ui.aChannelsSpin->setValue( options[12].toInt() );
375
376     int index = ui.aSampleBox->findData( options[13] );
377     if ( index == -1 ) index = ui.aSampleBox->findData( 44100 );
378     ui.aSampleBox->setCurrentIndex( index );
379
380     ui.subsCodecBox->setCurrentIndex( ui.subsCodecBox->findData( options[14] ) );
381     ui.subsOverlay->setChecked( options[15].toInt() );
382 }
383
384 void VLCProfileEditor::setVTranscodeOptions( bool b_trans )
385 {
386     ui.vCodecLabel->setEnabled( b_trans );
387     ui.vCodecBox->setEnabled( b_trans );
388     ui.vBitrateLabel->setEnabled( b_trans );
389     ui.vBitrateSpin->setEnabled( b_trans );
390     ui.vScaleLabel->setEnabled( b_trans );
391     ui.vScaleBox->setEnabled( b_trans );
392     ui.heightBox->setEnabled( b_trans );
393     ui.heightLabel->setEnabled( b_trans );
394     ui.widthBox->setEnabled( b_trans );
395     ui.widthLabel->setEnabled( b_trans );
396     ui.vFrameBox->setEnabled( b_trans );
397     ui.vFrameLabel->setEnabled( b_trans );
398     ui.keepVideo->setEnabled( b_trans );
399 }
400
401 void VLCProfileEditor::setATranscodeOptions( bool b_trans )
402 {
403     ui.aCodecLabel->setEnabled( b_trans );
404     ui.aCodecBox->setEnabled( b_trans );
405     ui.aBitrateLabel->setEnabled( b_trans );
406     ui.aBitrateSpin->setEnabled( b_trans );
407     ui.aChannelsLabel->setEnabled( b_trans );
408     ui.aChannelsSpin->setEnabled( b_trans );
409     ui.aSampleLabel->setEnabled( b_trans );
410     ui.aSampleBox->setEnabled( b_trans );
411     ui.keepAudio->setEnabled( b_trans );
412 }
413
414 void VLCProfileEditor::setSTranscodeOptions( bool b_trans )
415 {
416     ui.subsCodecBox->setEnabled( b_trans );
417     ui.subsOverlay->setEnabled( b_trans );
418 }
419
420 void VLCProfileEditor::close()
421 {
422     if( ui.profileLine->text().isEmpty() )
423     {
424         QMessageBox::warning( this, qtr(" Profile Name Missing" ),
425                 qtr( "You must set a name for the profile." ) );
426         ui.profileLine->setFocus();
427         return;
428     }
429     name = ui.profileLine->text();
430
431     accept();
432 }
433
434 QString VLCProfileEditor::transcodeValue()
435 {
436     for ( int i=0; i< ui.muxer->layout()->count(); i++ )
437     {
438         QRadioButton *current =
439                 qobject_cast<QRadioButton *>(ui.muxer->layout()->itemAt(i)->widget());
440         if ( unlikely( !current ) ) continue;/* someone is messing up with ui */
441         if ( current->isChecked() )
442         {
443             muxValue = current->property("sout").toString();
444             break;/* radios are exclusive */
445         }
446     }
447
448 #define currentData( box ) box->itemData( box->currentIndex() )
449     QString qs_acodec, qs_vcodec;
450
451     qs_vcodec = ( ui.transcodeVideo->isChecked() ) ? currentData( ui.vCodecBox ).toString()
452                                                    : "none";
453     qs_acodec = ( ui.transcodeAudio->isChecked() ) ? currentData( ui.aCodecBox ).toString()
454                                                    : "none";
455     QStringList transcodeMRL;
456     transcodeMRL
457             << muxValue
458
459             << QString::number( !ui.keepVideo->isChecked() )
460             << QString::number( !ui.keepAudio->isChecked() )
461             << QString::number( ui.transcodeSubs->isChecked() )
462
463             << qs_vcodec
464             << QString::number( ui.vBitrateSpin->value() )
465             << ( ( ui.vScaleBox->currentIndex() != 0 ) ? ui.vScaleBox->currentText() : QString("0") )
466             << QString::number( ui.vFrameBox->value() )
467             << QString::number( ui.widthBox->value() )
468             << QString::number( ui.heightBox->value() )
469
470             << qs_acodec
471             << QString::number( ui.aBitrateSpin->value() )
472             << QString::number( ui.aChannelsSpin->value() )
473             << currentData( ui.aSampleBox ).toString()
474
475             << currentData( ui.subsCodecBox ).toString()
476             << QString::number( ui.subsOverlay->isChecked() );
477 #undef currentData
478
479     return transcodeMRL.join( ";" );
480 }
481