]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/streamout.cpp
1306e31850d356165a99fbd72430d49187bdf76b
[vlc] / modules / gui / wxwindows / streamout.cpp
1 /*****************************************************************************
2  * streamout.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: streamout.cpp,v 1.13 2003/05/20 23:17:59 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <vlc/vlc.h>
33
34 #ifdef WIN32                                                 /* mingw32 hack */
35 #undef Yield
36 #undef CreateDialog
37 #endif
38
39 /* Let vlc take care of the i18n stuff */
40 #define WXINTL_NO_GETTEXT_MACRO
41
42 #include <wx/wxprec.h>
43 #include <wx/wx.h>
44 #include <wx/notebook.h>
45 #include <wx/textctrl.h>
46 #include <wx/combobox.h>
47 #include <wx/spinctrl.h>
48 #include <wx/statline.h>
49
50 #include <vlc/intf.h>
51
52 #if defined MODULE_NAME_IS_skins
53 #   include "../skins/src/skin_common.h"
54 #endif
55
56 #include "wxwindows.h"
57
58 #ifndef wxRB_SINGLE
59 #   define wxRB_SINGLE 0
60 #endif
61
62 enum
63 {
64     PLAY_ACCESS_OUT = 0,
65     FILE_ACCESS_OUT,
66     HTTP_ACCESS_OUT,
67     UDP_ACCESS_OUT,
68     RTP_ACCESS_OUT,
69     ACCESS_OUT_NUM
70 };
71
72 enum
73 {
74     TS_ENCAPSULATION = 0,
75     PS_ENCAPSULATION,
76     AVI_ENCAPSULATION,
77     MP4_ENCAPSULATION,
78     OGG_ENCAPSULATION,
79     ENCAPS_NUM
80 };
81
82 /*****************************************************************************
83  * Event Table.
84  *****************************************************************************/
85
86 /* IDs for the controls and the menu commands */
87 enum
88 {
89     Notebook_Event = wxID_HIGHEST,
90     MRL_Event,
91
92     FileBrowse_Event,
93     FileName_Event,
94
95     AccessType1_Event, AccessType2_Event, AccessType3_Event,
96     AccessType4_Event, AccessType5_Event,
97     NetPort_Event,
98     NetAddr_Event,
99
100     EncapsulationRadio1_Event, EncapsulationRadio2_Event,
101     EncapsulationRadio3_Event, EncapsulationRadio4_Event,
102     EncapsulationRadio5_Event,
103
104     VideoTranscEnable_Event, VideoTranscCodec_Event, VideoTranscBitrate_Event,
105     AudioTranscEnable_Event, AudioTranscCodec_Event, AudioTranscBitrate_Event,
106 };
107
108 BEGIN_EVENT_TABLE(SoutDialog, wxDialog)
109     /* Button events */
110     EVT_BUTTON(wxID_OK, SoutDialog::OnOk)
111     EVT_BUTTON(wxID_CANCEL, SoutDialog::OnCancel)
112
113     /* Events generated by the access output panel */
114     EVT_CHECKBOX(AccessType1_Event, SoutDialog::OnAccessTypeChange)
115     EVT_CHECKBOX(AccessType2_Event, SoutDialog::OnAccessTypeChange)
116     EVT_CHECKBOX(AccessType3_Event, SoutDialog::OnAccessTypeChange)
117     EVT_CHECKBOX(AccessType4_Event, SoutDialog::OnAccessTypeChange)
118     EVT_CHECKBOX(AccessType5_Event, SoutDialog::OnAccessTypeChange)
119     EVT_TEXT(FileName_Event, SoutDialog::OnFileChange)
120     EVT_BUTTON(FileBrowse_Event, SoutDialog::OnFileBrowse)
121     EVT_TEXT(NetPort_Event, SoutDialog::OnNetChange)
122     EVT_SPINCTRL(NetPort_Event, SoutDialog::OnNetChange)
123     EVT_TEXT(NetAddr_Event, SoutDialog::OnNetChange)
124  
125     /* Events generated by the encapsulation panel */
126     EVT_RADIOBUTTON(EncapsulationRadio1_Event,
127                     SoutDialog::OnEncapsulationChange)
128     EVT_RADIOBUTTON(EncapsulationRadio2_Event,
129                     SoutDialog::OnEncapsulationChange)
130     EVT_RADIOBUTTON(EncapsulationRadio3_Event,
131                     SoutDialog::OnEncapsulationChange)
132     EVT_RADIOBUTTON(EncapsulationRadio4_Event,
133                     SoutDialog::OnEncapsulationChange)
134     EVT_RADIOBUTTON(EncapsulationRadio5_Event,
135                     SoutDialog::OnEncapsulationChange)
136
137     /* Events generated by the transcoding panel */
138     EVT_CHECKBOX(VideoTranscEnable_Event, SoutDialog::OnTranscodingEnable)
139     EVT_CHECKBOX(AudioTranscEnable_Event, SoutDialog::OnTranscodingEnable)
140     EVT_COMBOBOX(VideoTranscCodec_Event, SoutDialog::OnTranscodingChange)
141     EVT_COMBOBOX(AudioTranscCodec_Event, SoutDialog::OnTranscodingChange)
142     EVT_COMBOBOX(VideoTranscBitrate_Event, SoutDialog::OnTranscodingChange)
143     EVT_COMBOBOX(AudioTranscBitrate_Event, SoutDialog::OnTranscodingChange)
144
145 END_EVENT_TABLE()
146
147 /*****************************************************************************
148  * Constructor.
149  *****************************************************************************/
150 SoutDialog::SoutDialog( intf_thread_t *_p_intf, wxWindow* _p_parent ):
151     wxDialog( _p_parent, -1, wxU(_("Stream output")),
152              wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE )
153 {
154     /* Initializations */
155     p_intf = _p_intf;
156     p_parent = _p_parent;
157     SetIcon( *p_intf->p_sys->p_icon );
158
159     /* Create a panel to put everything in */
160     wxPanel *panel = new wxPanel( this, -1 );
161     panel->SetAutoLayout( TRUE );
162
163     /* Create MRL combobox */
164     wxBoxSizer *mrl_sizer_sizer = new wxBoxSizer( wxHORIZONTAL );
165     wxStaticBox *mrl_box = new wxStaticBox( panel, -1,
166                                wxU(_("Stream output MRL")) );
167     wxStaticBoxSizer *mrl_sizer = new wxStaticBoxSizer( mrl_box,
168                                                         wxHORIZONTAL );
169     wxStaticText *mrl_label = new wxStaticText( panel, -1,
170                                                 wxU(_("Destination Target:")));
171     mrl_combo = new wxComboBox( panel, MRL_Event, mrl,
172                                 wxPoint(20,25), wxSize(120, -1), 0, NULL );
173     mrl_combo->SetToolTip( wxU(_("You can use this field directly by typing "
174         "the full MRL you want to open.\n""Alternatively, the field will be "
175         "filled automatically when you use the controls below")) );
176
177     mrl_sizer->Add( mrl_label, 0, wxALL | wxALIGN_CENTER, 5 );
178     mrl_sizer->Add( mrl_combo, 1, wxALL | wxALIGN_CENTER, 5 );
179     mrl_sizer_sizer->Add( mrl_sizer, 1, wxEXPAND | wxALL, 5 );
180
181     /* Create the output encapsulation panel */
182     wxPanel *encapsulation_panel = EncapsulationPanel( panel );
183
184     /* Create the access output panel */
185     wxPanel *access_panel = AccessPanel( panel );
186
187     /* Create the transcoding panel */
188     wxPanel *transcoding_panel = TranscodingPanel( panel );
189
190     /* Separation */
191     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
192
193     /* Create the buttons */
194     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
195     ok_button->SetDefault();
196     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
197                                             wxU(_("Cancel")) );
198
199     /* Place everything in sizers */
200     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
201     button_sizer->Add( ok_button, 0, wxALL, 5 );
202     button_sizer->Add( cancel_button, 0, wxALL, 5 );
203     button_sizer->Layout();
204     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
205     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
206     panel_sizer->Add( mrl_sizer_sizer, 0, wxEXPAND, 5 );
207     panel_sizer->Add( access_panel, 1, wxEXPAND | wxALL, 5 );
208     panel_sizer->Add( encapsulation_panel, 0, wxEXPAND | wxALL, 5 );
209     panel_sizer->Add( transcoding_panel, 0, wxEXPAND | wxALL, 5 );
210     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
211     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
212                       wxALL, 5 );
213     panel_sizer->Layout();
214     panel->SetSizerAndFit( panel_sizer );
215     main_sizer->Add( panel, 1, wxGROW, 0 );
216     main_sizer->Layout();
217     SetSizerAndFit( main_sizer );
218
219     /* Update all the values */
220     //ParseMRL();
221 }
222
223 SoutDialog::~SoutDialog()
224 {
225 }
226
227 /*****************************************************************************
228  * Private methods.
229  *****************************************************************************/
230 void SoutDialog::UpdateMRL()
231 {
232     /* Let's start with the transcode options */
233     wxString transcode;
234     if( video_transc_checkbox->IsChecked() ||
235         audio_transc_checkbox->IsChecked() )
236     {
237         transcode = wxT("transcode{");
238         if( video_transc_checkbox->IsChecked() )
239         {
240             transcode += wxT("vcodec=") + video_codec_combo->GetValue();
241             transcode += wxT(",vb=") + video_bitrate_combo->GetValue();
242             if( audio_transc_checkbox->IsChecked() ) transcode += wxT(",");
243         }
244         if( audio_transc_checkbox->IsChecked() )
245         {
246             transcode += wxT("acodec=") + audio_codec_combo->GetValue();
247             transcode += wxT(",ab=") + audio_bitrate_combo->GetValue();
248         }
249         transcode += wxT("}");
250     }
251
252     /* Encapsulation */
253     wxString encapsulation;
254     switch( i_encapsulation_type )
255     {
256     case PS_ENCAPSULATION:
257         encapsulation = wxT("ps");
258         break;
259     case AVI_ENCAPSULATION:
260         encapsulation = wxT("avi");
261         break;
262     case OGG_ENCAPSULATION:
263         encapsulation = wxT("ogg");
264         break;
265     case MP4_ENCAPSULATION:
266         encapsulation = wxT("mp4");
267         break;
268     case TS_ENCAPSULATION:
269     default:
270         encapsulation = wxT("ts");
271         break;
272     }
273
274     /* Now continue with the duplicate option */
275     wxString dup_opts;
276     if( access_checkboxes[PLAY_ACCESS_OUT]->IsChecked() )
277     {
278         dup_opts += wxT("dst=display");
279     }
280     if( access_checkboxes[FILE_ACCESS_OUT]->IsChecked() )
281     {
282         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
283         dup_opts += wxT("dst=std{access=file,mux=");
284         dup_opts += encapsulation + wxT(",url=");
285         dup_opts += file_combo->GetValue() + wxT("}");
286     }
287     if( access_checkboxes[HTTP_ACCESS_OUT]->IsChecked() )
288     {
289         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
290         dup_opts += wxT("dst=std{access=http,mux=");
291         dup_opts += encapsulation + wxT(",url=");
292         dup_opts += net_addr->GetLineText(0);
293         dup_opts += wxString::Format( wxT(":%d"), net_port->GetValue() );
294         dup_opts += wxT("}");
295     }
296     if( access_checkboxes[UDP_ACCESS_OUT]->IsChecked() )
297     {
298         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
299         dup_opts += wxT("dst=std{access=udp,mux=");
300         dup_opts += encapsulation + wxT(",url=");
301         dup_opts += net_addr->GetLineText(0);
302         dup_opts += wxString::Format( wxT(":%d"), net_port->GetValue() );
303         dup_opts += wxT("}");
304     }
305     if( access_checkboxes[UDP_ACCESS_OUT]->IsChecked() )
306     {
307         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
308         dup_opts += wxT("dst=std{access=rtp,mux=");
309         dup_opts += encapsulation + wxT(",url=");
310         dup_opts += net_addr->GetLineText(0);
311         dup_opts += wxString::Format( wxT(":%d"), net_port->GetValue() );
312         dup_opts += wxT("}");
313     }
314
315     wxString duplicate;
316     if( !dup_opts.IsEmpty() )
317     {
318         if( !transcode.IsEmpty() ) duplicate = wxT(":");
319         duplicate += wxT("duplicate{") + dup_opts + wxT("}");
320     }
321
322     if( !transcode.IsEmpty() || !duplicate.IsEmpty() )
323         mrl = wxT("#") + transcode + duplicate;
324     else
325         mrl = wxT("");
326
327     mrl_combo->SetValue( mrl );
328 }
329
330 wxPanel *SoutDialog::AccessPanel( wxWindow* parent )
331 {
332     int i;
333     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
334                                   wxSize(200, 200) );
335
336     wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 4, 20 );
337     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
338                                               wxU(_("Output Methods")) );
339     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
340                                                           wxVERTICAL );
341
342     static const wxString access_output_array[] =
343     {
344         wxU(_("Play locally")),
345         wxU(_("File")),
346         wxU(_("HTTP")),
347         wxU(_("UDP")),
348         wxU(_("RTP"))
349     };
350
351     for( i=0; i < ACCESS_OUT_NUM; i++ )
352     {
353         access_checkboxes[i] = new wxCheckBox( panel, AccessType1_Event + i,
354                                                access_output_array[i] );
355         access_subpanels[i] = new wxPanel( panel, -1 );
356     }
357
358     /* Play locally row */
359     wxFlexGridSizer *subpanel_sizer;
360     wxStaticText *label;
361     label = new wxStaticText( access_subpanels[0], -1, wxT("") );
362     subpanel_sizer = new wxFlexGridSizer( 1, 1, 20 );
363     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
364     access_subpanels[0]->SetSizerAndFit( subpanel_sizer );
365
366     /* File row */
367     subpanel_sizer = new wxFlexGridSizer( 3, 1, 20 );
368     label = new wxStaticText( access_subpanels[1], -1, wxU(_("Filename")) );
369     file_combo = new wxComboBox( access_subpanels[1], FileName_Event, wxT(""),
370                                  wxPoint(20,25), wxSize(200, -1), 0, NULL );
371     wxButton *browse_button = new wxButton( access_subpanels[1],
372                                   FileBrowse_Event, wxU(_("Browse...")) );
373     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
374     subpanel_sizer->Add( file_combo, 1,
375                          wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
376     subpanel_sizer->Add( browse_button, 0,
377                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
378
379     access_subpanels[1]->SetSizerAndFit( subpanel_sizer );
380
381     /* Net rows */
382     for( i=2; i < ACCESS_OUT_NUM; i++ )
383     {
384         subpanel_sizer = new wxFlexGridSizer( 4, 1, 20 );
385         label = new wxStaticText( access_subpanels[i], -1, wxU(_("Address")) );
386         net_addr = new wxTextCtrl( access_subpanels[i], NetAddr_Event, wxT(""),
387                                    wxDefaultPosition, wxSize( 200, -1 ),
388                                    wxTE_PROCESS_ENTER);
389         subpanel_sizer->Add( label, 0,
390                              wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
391         subpanel_sizer->Add( net_addr, 1, wxEXPAND |
392                              wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
393
394         int val = config_GetInt( p_intf, "server-port" );
395         label = new wxStaticText( access_subpanels[i], -1, wxU(_("Port")) );
396         net_port = new wxSpinCtrl( access_subpanels[i], NetPort_Event,
397                                    wxString::Format(wxT("%d"), val),
398                                    wxDefaultPosition, wxDefaultSize,
399                                    wxSP_ARROW_KEYS,
400                                    0, 16000, val );
401
402         subpanel_sizer->Add( label, 0,
403                              wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
404         subpanel_sizer->Add( net_port, 0,
405                              wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
406
407         access_subpanels[i]->SetSizerAndFit( subpanel_sizer );
408     }
409
410
411     /* Stuff everything into the main panel */
412     for( i=1; i < ACCESS_OUT_NUM; i++ )
413     {
414         sizer->Add( access_checkboxes[i], 0,
415                     wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL  | wxALL, 5 );
416         sizer->Add( access_subpanels[i], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL
417                     | wxALIGN_LEFT  | wxALL, 5 );
418     }
419
420     panel_sizer->Add( access_checkboxes[0], 0,
421                       wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL  | wxALL, 5 );
422     panel_sizer->Add( sizer, 1, wxEXPAND | wxTOP, 3 );
423
424     panel->SetSizerAndFit( panel_sizer );
425
426     /* Update access type panel */
427     for( i=1; i < ACCESS_OUT_NUM; i++ )
428     {
429         access_subpanels[i]->Disable();
430     }
431
432     return panel;
433 }
434
435 wxPanel *SoutDialog::EncapsulationPanel( wxWindow* parent )
436 {
437     int i;
438     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
439                                   wxSize(200, 200) );
440
441     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
442                                               wxU(_("Encapsulation Method")) );
443     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
444                                                           wxHORIZONTAL );
445
446     static const wxString encapsulation_array[] =
447     {
448         wxT("MPEG TS"),
449         wxT("MPEG PS"),
450         wxT("AVI"),
451         wxT("MP4/MOV"),
452         wxT("Ogg")
453     };
454
455     /* Stuff everything into the main panel */
456     for( i=0; i < ENCAPS_NUM; i++ )
457     {
458         encapsulation_radios[i] =
459             new wxRadioButton( panel, EncapsulationRadio1_Event + i,
460                                encapsulation_array[i] );
461         panel_sizer->Add( encapsulation_radios[i], 0,
462                           wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 8 );
463     }
464
465     panel->SetSizerAndFit( panel_sizer );
466
467     /* Update encapsulation panel */
468     encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
469     i_encapsulation_type = TS_ENCAPSULATION;
470
471     return panel;
472 }
473
474 wxPanel *SoutDialog::TranscodingPanel( wxWindow* parent )
475 {
476     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
477                                   wxSize(200, 200) );
478
479     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
480                                               wxU(_("Transcoding options")) );
481     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
482                                                           wxVERTICAL );
483
484     /* Create video transcoding checkox */
485     static const wxString vcodecs_array[] =
486     {
487         wxT("mpgv"),
488         wxT("mp4v"),
489         wxT("DIV1"),
490         wxT("DIV2"),
491         wxT("DIV3"),
492         wxT("H263"),
493         wxT("I263"),
494         wxT("WMV1"),
495     };
496     static const wxString vbitrates_array[] =
497     {
498         wxT("3000"),
499         wxT("2000"),
500         wxT("1000"),
501         wxT("750"),
502         wxT("500"),
503         wxT("400"),
504         wxT("200"),
505         wxT("150"),
506         wxT("100")
507     };
508
509     wxFlexGridSizer *video_sizer = new wxFlexGridSizer( 4, 1, 20 );
510     video_transc_checkbox =
511         new wxCheckBox( panel, VideoTranscEnable_Event, wxU(_("Video codec")));
512     video_codec_combo =
513         new wxComboBox( panel, VideoTranscCodec_Event, wxT("mp4v"),
514                         wxPoint(20,25), wxDefaultSize, WXSIZEOF(vcodecs_array),
515                         vcodecs_array, wxCB_READONLY );
516     wxStaticText *bitrate_label =
517         new wxStaticText( panel, -1, wxU(_("Bitrate (kb/s)")));
518     video_bitrate_combo =
519         new wxComboBox( panel, VideoTranscBitrate_Event, wxT("1000"),
520                         wxPoint(20,25), wxDefaultSize,
521                         WXSIZEOF(vbitrates_array), vbitrates_array );
522     video_sizer->Add( video_transc_checkbox, 0,
523                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
524     video_sizer->Add( video_codec_combo, 1,
525                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
526     video_sizer->Add( bitrate_label, 0,
527                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
528     video_sizer->Add( video_bitrate_combo, 1,
529                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
530
531     /* Create audio transcoding checkox */
532     static const wxString acodecs_array[] =
533     {
534         wxT("mpga"),
535         wxT("a52")
536     };
537     static const wxString abitrates_array[] =
538     {
539         wxT("512"),
540         wxT("256"),
541         wxT("192"),
542         wxT("128"),
543         wxT("96")
544     };
545
546     wxFlexGridSizer *audio_sizer = new wxFlexGridSizer( 4, 1, 20 );
547     audio_transc_checkbox =
548         new wxCheckBox( panel, AudioTranscEnable_Event, wxU(_("Audio codec")));
549     audio_codec_combo =
550         new wxComboBox( panel, AudioTranscCodec_Event, wxT("mpga"),
551                         wxPoint(20,25), wxDefaultSize, WXSIZEOF(acodecs_array),
552                         acodecs_array, wxCB_READONLY );
553     bitrate_label =
554         new wxStaticText( panel, -1, wxU(_("Bitrate (kb/s)")));
555     audio_bitrate_combo =
556         new wxComboBox( panel, AudioTranscBitrate_Event, wxT("192"),
557                         wxPoint(20,25), wxDefaultSize,
558                         WXSIZEOF(abitrates_array), abitrates_array );
559     audio_sizer->Add( audio_transc_checkbox, 0,
560                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
561     audio_sizer->Add( audio_codec_combo, 1,
562                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
563     audio_sizer->Add( bitrate_label, 0,
564                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
565     audio_sizer->Add( audio_bitrate_combo, 1,
566                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
567
568     /* Stuff everything into the main panel */
569     panel_sizer->Add( video_sizer, 0,
570                       wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
571     panel_sizer->Add( audio_sizer, 0,
572                       wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
573
574     panel->SetSizerAndFit( panel_sizer );
575
576     /* Update transcoding panel */
577     wxCommandEvent event( 0, VideoTranscEnable_Event );
578     event.SetInt( 0 );
579     OnTranscodingEnable( event );
580     event.SetId( AudioTranscEnable_Event );
581     OnTranscodingEnable( event );
582
583     return panel;
584 }
585
586 #if 0
587 void SoutDialog::ParseMRL()
588 {
589     /* Initialise MRL value */
590     char *psz_sout = config_GetPsz( p_intf, "sout" );
591     if( psz_sout )
592     {
593         mrl = wxU(psz_sout);
594         free( psz_sout );
595     }
596
597     /* Parse the MRL */
598     wxString access = mrl.BeforeFirst( wxT('/') );
599     wxString encapsulation = mrl.BeforeFirst( wxT(':') ).AfterFirst(wxT('/'));
600
601     if( !access.Cmp( wxT("http") ) )
602     {
603         i_access_type = HTTP_ACCESS_OUT;
604     }
605     else if( !access.Cmp( wxT("udp") ) )
606     {
607         i_access_type = UDP_ACCESS_OUT;
608     }
609     else if( !access.Cmp( wxT("rtp") ) )
610     {
611         i_access_type = RTP_ACCESS_OUT;
612     }
613     else
614     {
615         i_access_type = FILE_ACCESS_OUT;
616     }
617
618     if( !encapsulation.Cmp( wxT("ps") ) )
619     {
620         i_encapsulation_type = PS_ENCAPSULATION;
621     }
622     else if( !encapsulation.Cmp( wxT("avi") ) )
623     {
624         i_encapsulation_type = AVI_ENCAPSULATION;
625     }
626     else if( !encapsulation.Cmp( wxT("ogg") ) )
627     {
628         i_encapsulation_type = OGG_ENCAPSULATION;
629     }
630     else
631     {
632         i_encapsulation_type = TS_ENCAPSULATION;
633     }
634
635     wxString second_part = mrl.AfterFirst( wxT(':') );
636
637     if( i_access_type == FILE_ACCESS_OUT )
638     {
639         /* The whole second part of the MRL is the filename */
640         file_combo->SetValue( second_part );
641     }
642     else
643     {
644         /* we've got address:port */
645         wxString address = second_part.BeforeLast( wxT(':') );
646         net_addr->SetValue( address );
647
648         long int i_port;
649         wxString port = second_part.AfterLast( wxT(':') );
650         if( port.ToLong( &i_port ) )
651         {
652             net_port->SetValue( i_port );
653         }
654         else
655         {
656             net_port->SetValue( config_GetInt( p_intf, "server-port" ) );
657         }
658     }
659
660     /* Update access output panel */
661     wxCommandEvent dummy_event;
662     dummy_event.SetId( AccessType1_Event + i_access_type );
663     OnAccessTypeChange( dummy_event );
664
665     /* Update encapsulation output panel */
666     dummy_event.SetId( EncapsulationRadio1_Event + i_encapsulation_type );
667     OnEncapsulationChange( dummy_event );
668 }
669 #endif
670
671 /*****************************************************************************
672  * Events methods.
673  *****************************************************************************/
674 void SoutDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
675 {
676     EndModal( wxID_OK );
677 }
678
679 void SoutDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
680 {
681     EndModal( wxID_CANCEL );
682 }
683
684 void SoutDialog::OnMRLChange( wxCommandEvent& event )
685 {
686     mrl = event.GetString();
687 }
688
689 /*****************************************************************************
690  * Access output panel event methods.
691  *****************************************************************************/
692 void SoutDialog::OnAccessTypeChange( wxCommandEvent& event )
693 {
694     int i;
695     i_access_type = event.GetId() - AccessType1_Event;
696
697     access_subpanels[i_access_type]->Enable( event.GetInt() );
698
699     switch( i_access_type )
700     {
701     case UDP_ACCESS_OUT:
702     case RTP_ACCESS_OUT:
703         for( i = 1; i < ENCAPS_NUM; i++ )
704         {
705             encapsulation_radios[i]->Enable( !event.GetInt() );
706         }
707         if( event.GetInt() )
708         {
709             encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
710             i_encapsulation_type = TS_ENCAPSULATION;
711         }
712         break;
713     }
714
715     UpdateMRL();
716 }
717
718 /*****************************************************************************
719  * File access output event methods.
720  *****************************************************************************/
721 void SoutDialog::OnFileChange( wxCommandEvent& WXUNUSED(event) )
722 {
723     UpdateMRL();
724 }
725
726 void SoutDialog::OnFileBrowse( wxCommandEvent& WXUNUSED(event) )
727 {
728     wxFileDialog dialog( this, wxU(_("Save file")),
729                          wxT(""), wxT(""), wxT("*"), wxSAVE );
730
731     if( dialog.ShowModal() == wxID_OK )
732     {
733         file_combo->SetValue( dialog.GetPath() );
734         UpdateMRL();
735     }
736 }
737
738 /*****************************************************************************
739  * Net access output event methods.
740  *****************************************************************************/
741 void SoutDialog::OnNetChange( wxCommandEvent& WXUNUSED(event) )
742 {
743     UpdateMRL();
744 }
745
746 /*****************************************************************************
747  * Encapsulation panel event methods.
748  *****************************************************************************/
749 void SoutDialog::OnEncapsulationChange( wxCommandEvent& event )
750 {
751     i_encapsulation_type = event.GetId() - EncapsulationRadio1_Event;
752     UpdateMRL();
753 }
754
755 /*****************************************************************************
756  * Transcoding panel event methods.
757  *****************************************************************************/
758 void SoutDialog::OnTranscodingEnable( wxCommandEvent& event )
759 {
760     switch( event.GetId() )
761     {
762     case VideoTranscEnable_Event:
763         video_codec_combo->Enable( event.GetInt() );
764         video_bitrate_combo->Enable( event.GetInt() );
765         break;
766     case AudioTranscEnable_Event:
767         audio_codec_combo->Enable( event.GetInt() );
768         audio_bitrate_combo->Enable( event.GetInt() );
769         break;
770     }
771
772     UpdateMRL();
773 }
774
775 void SoutDialog::OnTranscodingChange( wxCommandEvent& event )
776 {
777     UpdateMRL();
778 }