sout.cpp 14 KB
Newer Older
zorglub's avatar
zorglub committed
1
/*****************************************************************************
2
 * sout.cpp : Stream output dialog ( old-style )
zorglub's avatar
zorglub committed
3
 ****************************************************************************
4
 * Copyright ( C ) 2006 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
9
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *          Jean-François Massol <jf.massol -at- gmail.com>
zorglub's avatar
zorglub committed
10
11
12
13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
14
 * ( at your option ) any later version.
zorglub's avatar
zorglub committed
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "dialogs/sout.hpp"
#include "qt4.hpp"
#include <vlc_streaming.h>

30
31
#include <iostream>
#include <QString>
zorglub's avatar
zorglub committed
32
33
#include <QFileDialog>

34
35
SoutDialog::SoutDialog( QWidget *parent, intf_thread_t *_p_intf,
                     bool _transcode_only ) : QVLCDialog( parent,  _p_intf )
zorglub's avatar
zorglub committed
36
{
37
    setWindowTitle( qtr( "Stream output" ) );
38

zorglub's avatar
zorglub committed
39
    /* UI stuff */
40
    ui.setupUi( this );
41

42
43
44
45
46
47
48
49
/* ADD HERE for new profiles */
#define ADD_PROFILE( name, shortname ) ui.profileBox->addItem( qtr( name ), QVariant( QString( shortname ) ) );
    ADD_PROFILE( "Custom" , "Custom" )
    ADD_PROFILE( "IPod (mp4/aac)", "IPod" )
    ADD_PROFILE( "XBox", "XBox" )
    ADD_PROFILE( "Windows (wmv/asf)", "Windows" )
    ADD_PROFILE( "PSP", "PSP")
    ADD_PROFILE( "GSM", "GSM" )
50

51
#define ADD_VCODEC( name, fourcc ) ui.vCodecBox->addItem( name, QVariant( fourcc ) );
52
53
54
55
56
57
58
59
60
61
62
63
64
    ADD_VCODEC( "MPEG-1", "mp1v" )
    ADD_VCODEC( "MPEG-2", "mp2v" )
    ADD_VCODEC( "MPEG-4", "mp4v" )
    ADD_VCODEC( "DIVX 1" , "DIV1" )
    ADD_VCODEC( "DIVX 2" , "DIV1" )
    ADD_VCODEC( "DIVX 3" , "DIV1" )
    ADD_VCODEC( "H-263", "H263" )
    ADD_VCODEC( "H-264", "h264" )
    ADD_VCODEC( "WMV1", "WMV1" )
    ADD_VCODEC( "WMV2" , "WMV2" )
    ADD_VCODEC( "M-JPEG", "MJPG" )
    ADD_VCODEC( "Theora", "theo" )

65
#define ADD_ACODEC( name, fourcc ) ui.aCodecBox->addItem( name, QVariant( fourcc ) );
66
67
    ADD_ACODEC( "MPEG Audio", "mpga" )
    ADD_ACODEC( "MP3", "mp3" )
68
69
    ADD_ACODEC( "MPEG 4 Audio ( AAC )", "mp4a" )
    ADD_ACODEC( "A52/AC-3", "a52" )
70
71
72
73
74
75
    ADD_ACODEC( "Vorbis", "vorb" )
    ADD_ACODEC( "Flac", "flac" )
    ADD_ACODEC( "Speex", "spx" )
    ADD_ACODEC( "WAV", "s16l" )
    ADD_ACODEC( "WMA", "wma" )

76
#define ADD_SCALING( factor ) ui.vScaleBox->addItem( factor );
77
78
79
80
81
82
83
84
85
    ADD_SCALING( "0.25" )
    ADD_SCALING( "0.5" )
    ADD_SCALING( "0.75" )
    ADD_SCALING( "1" )
    ADD_SCALING( "1.25" )
    ADD_SCALING( "1.5" )
    ADD_SCALING( "1.75" )
    ADD_SCALING( "2" )

86
87
    ui.mrlEdit->setToolTip ( qtr( "Stream output string.\n This is automatically generated "
                                                "when you change the above settings,\n but you can update it manually." ) ) ;
88
89

//     /* Connect everything to the updateMRL function */
90
91
92
93
 #define CB( x ) CONNECT( ui.x, clicked( 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() );
94
95
96
97
98
99
//     /* Output */
     CB( fileOutput ); CB( HTTPOutput ); CB( localOutput );
     CB( UDPOutput ); CB( MMSHOutput ); CB( rawInput );
     CT( fileEdit ); CT( HTTPEdit ); CT( UDPEdit ); CT( MMSHEdit );
     CS( HTTPPort ); CS( UDPPort ); CS( MMSHPort );
//     /* Transcode */
100
101
     CC( vCodecBox ); CC( subsCodecBox ); CC( aCodecBox ) ;
     CB( transcodeVideo ); CB( transcodeAudio ); CB( transcodeSubs );
102
//     CB( sOverlay );
103
     CS( vBitrateSpin ); CS( aBitrateSpin ); CS( aChannelsSpin ); CC( vScaleBox );
104
105
106
107
108
//     /* Mux */
     CB( PSMux ); CB( TSMux ); CB( MPEG1Mux ); CB( OggMux ); CB( ASFMux );
     CB( MP4Mux ); CB( MOVMux ); CB( WAVMux ); CB( RAWMux ); CB( FLVMux );
//     /* Misc */
     CB( soutAll ); CS( ttl ); CT( sapName ); CT( sapGroup );
109
//
110
111
112
113
114
115
    CONNECT( ui.profileBox, activated( const QString & ), this, setOptions() );
    CONNECT( ui.fileSelectButton, clicked() , this, fileBrowse()  );
    CONNECT( ui.transcodeVideo, toggled( bool ), this, setVTranscodeOptions( bool ) );
    CONNECT( ui.transcodeAudio, toggled( bool ), this, setATranscodeOptions( bool ) );
    CONNECT( ui.transcodeSubs, toggled( bool ), this, setSTranscodeOptions( bool ) );
    CONNECT( ui.rawInput, toggled( bool ), this, setRawOptions( bool ) );
zorglub's avatar
zorglub committed
116

117
118
119
120
121
122
123
    QPushButton *okButton = new QPushButton( qtr( "&Stream" ) );
    QPushButton *cancelButton = new QPushButton( qtr( "&Cancel" ) );

    okButton->setDefault( true );
    ui.acceptButtonBox->addButton( okButton, QDialogButtonBox::AcceptRole );
    ui.acceptButtonBox->addButton( cancelButton, QDialogButtonBox::RejectRole );

124
125
    BUTTONACT( okButton, ok() );
    BUTTONACT( cancelButton, cancel() );
126
127

    if( _transcode_only ) toggleSout();
zorglub's avatar
zorglub committed
128
129
130
}

void SoutDialog::fileBrowse()
131
132
{
    ui.tabWidget->setTabEnabled( 0,false );
133
    QString f = QFileDialog::getOpenFileName( this, qtr( "Save file" ), "", "" );
zorglub's avatar
zorglub committed
134
135
136
137
    ui.fileEdit->setText( f );
    updateMRL();
}

138
void SoutDialog::setVTranscodeOptions( bool b_trans )
139
{
140
141
142
143
    ui.vCodecLabel->setEnabled( b_trans );
    ui.vCodecBox->setEnabled( b_trans );
    ui.vBitrateLabel->setEnabled( b_trans );
    ui.vBitrateSpin->setEnabled( b_trans );
144
    ui.vScaleLabel->setEnabled( b_trans );
145
    ui.vScaleBox->setEnabled( b_trans );
146
147
}

148
void SoutDialog::setATranscodeOptions( bool b_trans )
149
{
150
151
152
153
154
155
    ui.aCodecLabel->setEnabled( b_trans );
    ui.aCodecBox->setEnabled( b_trans );
    ui.aBitrateLabel->setEnabled( b_trans );
    ui.aBitrateSpin->setEnabled( b_trans );
    ui.aChannelsLabel->setEnabled( b_trans );
    ui.aChannelsSpin->setEnabled( b_trans );
156
157
}

158
void SoutDialog::setSTranscodeOptions( bool b_trans )
159
{
160
161
    ui.subsCodecBox->setEnabled( b_trans );
    ui.subsOverlay->setEnabled( b_trans );
162
163
}

164
void SoutDialog::setRawOptions( bool b_raw )
165
{
166
167
168
169
170
171
172
173
    if ( b_raw )
    {
        ui.tabWidget->setDisabled( true );
    }
    else
    {
        SoutDialog::setOptions();
    }
174
175
}

176
int indexFromItemData( QComboBox *aCombo, QString aString )
177
{
178
    for( int i=0; i < aCombo->count(); i++ )
179
    {
180
        if( aCombo->itemData( i ).toString() == aString ) return i;
181
    }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    return -1;
}

void SoutDialog::setOptions()
{
    QString profileString = ui.profileBox->itemData( ui.profileBox->currentIndex() ).toString();
    msg_Dbg( p_intf, "Profile Used: %s",  qta( profileString ));
    int index;

#define setProfile( muxName, hasVideo, vCodecName, hasAudio, aCodecName ) \
    { \
        ui.muxName ##Mux->setChecked( true ); \
        \
        ui.transcodeAudio->setChecked( hasAudio ); \
        index = indexFromItemData( ui.aCodecBox, vCodecName );  \
        if( index >= 0 ) ui.aCodecBox->setCurrentIndex( index ); \
        \
        ui.transcodeVideo->setChecked( hasVideo ); \
        index = indexFromItemData( ui.aCodecBox, vCodecName );  \
        if( index >=0 ) ui.vCodecBox->setCurrentIndex( index ); \
202
    }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

    /* ADD HERE the profiles you want and need */
    if( profileString == "IPod" ) setProfile( MP4, true, "mp4a", true, "mp4v" )
    else if( profileString == "XBox" ) setProfile( ASF, true, "wma", true, "WMV2" )

        /* 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 !! */
    updateMRL();
220
221
}

222
223
void SoutDialog::toggleSout()
{
224
225
    #define TGV( x ) { \
        if( ( x->isHidden() ) )  \
226
        x->show();          \
227
228
229
230
231
232
233
234
        else  x->hide();\
    }
    TGV( ui.HTTPOutput ) ; TGV( ui.UDPOutput ) ; TGV( ui.MMSHOutput ) ;
    TGV( ui.HTTPEdit ) ; TGV( ui.UDPEdit ) ; TGV( ui.MMSHEdit ) ;
    TGV( ui.HTTPLabel ) ; TGV( ui.UDPLabel ) ; TGV( ui.MMSHLabel ) ;
    TGV( ui.HTTPPortLabel ) ; TGV( ui.UDPPortLabel ) ; TGV( ui.MMSHPortLabel ) ;
    TGV( ui.HTTPPort ) ; TGV( ui.UDPPort ) ; TGV( ui.MMSHPort ) ;
    updateGeometry();
235
236
}

zorglub's avatar
zorglub committed
237
238
void SoutDialog::ok()
{
zorglub's avatar
zorglub committed
239
240
    mrl = ui.mrlEdit->text();
    accept();
zorglub's avatar
zorglub committed
241
242
243
}
void SoutDialog::cancel()
{
zorglub's avatar
zorglub committed
244
245
    mrl = ui.mrlEdit->text();
    reject();
zorglub's avatar
zorglub committed
246
247
248
249
}

void SoutDialog::updateMRL()
{
250
251
252
253
254
255
256
257
258
259
    sout_gui_descr_t sout;
    memset( &sout, 0, sizeof( sout_gui_descr_t ) );

    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_udp = ui.UDPOutput->isChecked();
    sout.b_sap = ui.sap->isChecked();
    sout.b_all_es = ui.soutAll->isChecked();
260
261
262
    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() ) );
263
264
265
266
267
268
269
    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_udp = strdup( qtu( ui.UDPEdit->text() ) );
    sout.i_http = ui.HTTPPort->value();
    sout.i_mms = ui.MMSHPort->value();
    sout.i_udp = ui.UDPPort->value();
270
271
272
273
    sout.i_ab = ui.aBitrateSpin->value();
    sout.i_vb = ui.vBitrateSpin->value();
    sout.i_channels = ui.aChannelsSpin->value();
    sout.f_scale = atof( qta( ui.vScaleBox->currentText() ) );
274
275
276
277
    sout.psz_group = strdup( qtu( ui.sapGroup->text() ) );
    sout.psz_name = strdup( qtu( ui.sapName->text() ) );

#define SMUX( x, txt ) if( ui.x->isChecked() ) sout.psz_mux = strdup( txt );
278
279
280
281
282
283
284
285
286
287
    SMUX( PSMux, "ps" );
    SMUX( TSMux, "ts" );
    SMUX( MPEG1Mux, "mpeg" );
    SMUX( OggMux, "ogg" );
    SMUX( ASFMux, "asf" );
    SMUX( MP4Mux, "mp4" );
    SMUX( MOVMux, "mov" );
    SMUX( WAVMux, "wav" );
    SMUX( RAWMux, "raw" );
    SMUX( FLVMux, "flv" );
288
289
290
291

    bool trans = false;
    bool more = false;

292
    if ( ui.transcodeVideo->isChecked() || ui.transcodeAudio->isChecked() )
293
    {
294
        if ( ui.transcodeVideo->isChecked() )
295
        {
296
297
298
299
300
301
            mrl = ":sout=#transcode{";
            mrl.append( "vcodec=" );
            mrl.append( sout.psz_vcodec );
            mrl.append( "," );
            mrl.append( "vb=" );
            mrl.append( QString::number( sout.i_vb,10 ) );
302
            mrl.append( "," );
303
304
305
            mrl.append( "scale=" );
            mrl.append( QString::number( sout.f_scale ) );
            trans = true;
306
        }
307
308

        if ( ui.transcodeAudio->isChecked() )
309
        {
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
            if ( trans )
            {
                mrl.append( "," );
            }
            else
            {
                mrl = ":sout=#transcode{";
            }
            mrl.append( "acodec=" );
            mrl.append( sout.psz_acodec );
            mrl.append( "," );
            mrl.append( "ab=" );
            mrl.append( QString::number( sout.i_ab,10 ) );
            mrl.append( "," );
            mrl.append( "channels=" );
            mrl.append( QString::number( sout.i_channels,10 ) );
            trans = true;
327
        }
328
        mrl.append( "}" );
329
    }
330

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
    if ( sout.b_local || sout.b_file || sout.b_http || sout.b_mms || sout.b_udp )
    {

#define ISMORE() if ( more ) mrl.append( "," );

        if ( trans )
        {
            mrl.append( ":duplicate{" );
        }
        else
        {
            mrl = ":sout=#";
        }

        if ( sout.b_local )
        {
            ISMORE();
            mrl.append( "dst=display" );
            more = true;
        }

        if ( sout.b_file )
        {
            ISMORE();
            mrl.append( "dst=std{access=file,mux=" );
            mrl.append( sout.psz_mux );
            mrl.append( ",dst=" );
            mrl.append( sout.psz_file );
            mrl.append( "}" );
            more = true;
        }

        if ( sout.b_http )
        {
            ISMORE();
            mrl.append( "dst=std{access=http,mux=" );
            mrl.append( sout.psz_mux );
            mrl.append( ",dst=" );
            mrl.append( sout.psz_http );
            mrl.append( ":" );
            mrl.append( QString::number( sout.i_http,10 ) );
            mrl.append( "}" );
            more = true;
        }

        if ( sout.b_mms )
        {
            ISMORE();
            mrl.append( "dst=std{access=mmsh,mux=" );
            mrl.append( sout.psz_mux );
            mrl.append( ",dst=" );
            mrl.append( sout.psz_mms );
            mrl.append( ":" );
            mrl.append( QString::number( sout.i_mms,10 ) );
            mrl.append( "}" );
            more = true;
        }

        if ( sout.b_udp )
        {
            ISMORE();
            mrl.append( "dst=std{access=udp,mux=" );
            mrl.append( sout.psz_mux );
            mrl.append( ",dst=" );
            mrl.append( sout.psz_udp );
            mrl.append( ":" );
            mrl.append( QString::number( sout.i_udp,10 ) );
            if ( sout.b_sap )
            {
                mrl.append( ",sap," );
                mrl.append( "group=\"" );
                mrl.append( sout.psz_group );
                mrl.append( "\"," );
                mrl.append( "name=\"" );
                mrl.append( sout.psz_name );
                mrl.append( "\"" );
            }
            mrl.append( "}" );
            more = true;
        }

        if ( trans )
        {
            mrl.append( "}" );
        }
    }

    if ( sout.b_all_es )
419
        mrl.append( ":sout-all" );
420
421
422
423
424
425

    ui.mrlEdit->setText( mrl );
    free( sout.psz_acodec ); free( sout.psz_vcodec ); free( sout.psz_scodec );
    free( sout.psz_file );free( sout.psz_http ); free( sout.psz_mms );
    free( sout.psz_udp ); free( sout.psz_mux );
    free( sout.psz_name ); free( sout.psz_group );
426
}