]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/streamout.cpp
* INSTALL.win32: added a small note about running vlc under the msvc debugger.
[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.14 2003/05/22 12:00:56 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, wxT(""),
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
220 SoutDialog::~SoutDialog()
221 {
222 }
223
224 /*****************************************************************************
225  * Private methods.
226  *****************************************************************************/
227 void SoutDialog::UpdateMRL()
228 {
229     /* Let's start with the transcode options */
230     wxString transcode;
231     if( video_transc_checkbox->IsChecked() ||
232         audio_transc_checkbox->IsChecked() )
233     {
234         transcode = wxT("transcode{");
235         if( video_transc_checkbox->IsChecked() )
236         {
237             transcode += wxT("vcodec=") + video_codec_combo->GetValue();
238             transcode += wxT(",vb=") + video_bitrate_combo->GetValue();
239             if( audio_transc_checkbox->IsChecked() ) transcode += wxT(",");
240         }
241         if( audio_transc_checkbox->IsChecked() )
242         {
243             transcode += wxT("acodec=") + audio_codec_combo->GetValue();
244             transcode += wxT(",ab=") + audio_bitrate_combo->GetValue();
245         }
246         transcode += wxT("}");
247     }
248
249     /* Encapsulation */
250     wxString encapsulation;
251     switch( i_encapsulation_type )
252     {
253     case PS_ENCAPSULATION:
254         encapsulation = wxT("ps");
255         break;
256     case AVI_ENCAPSULATION:
257         encapsulation = wxT("avi");
258         break;
259     case OGG_ENCAPSULATION:
260         encapsulation = wxT("ogg");
261         break;
262     case MP4_ENCAPSULATION:
263         encapsulation = wxT("mp4");
264         break;
265     case TS_ENCAPSULATION:
266     default:
267         encapsulation = wxT("ts");
268         break;
269     }
270
271     /* Now continue with the duplicate option */
272     wxString dup_opts;
273     if( access_checkboxes[PLAY_ACCESS_OUT]->IsChecked() )
274     {
275         dup_opts += wxT("dst=display");
276     }
277     if( access_checkboxes[FILE_ACCESS_OUT]->IsChecked() )
278     {
279         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
280         dup_opts += wxT("dst=std{access=file,mux=");
281         dup_opts += encapsulation + wxT(",url=");
282         dup_opts += file_combo->GetValue() + wxT("}");
283     }
284     if( access_checkboxes[HTTP_ACCESS_OUT]->IsChecked() )
285     {
286         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
287         dup_opts += wxT("dst=std{access=http,mux=");
288         dup_opts += encapsulation + wxT(",url=");
289         dup_opts += net_addr->GetLineText(0);
290         dup_opts += wxString::Format( wxT(":%d"), net_port->GetValue() );
291         dup_opts += wxT("}");
292     }
293     if( access_checkboxes[UDP_ACCESS_OUT]->IsChecked() )
294     {
295         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
296         dup_opts += wxT("dst=std{access=udp,mux=");
297         dup_opts += encapsulation + wxT(",url=");
298         dup_opts += net_addr->GetLineText(0);
299         dup_opts += wxString::Format( wxT(":%d"), net_port->GetValue() );
300         dup_opts += wxT("}");
301     }
302     if( access_checkboxes[UDP_ACCESS_OUT]->IsChecked() )
303     {
304         if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
305         dup_opts += wxT("dst=std{access=rtp,mux=");
306         dup_opts += encapsulation + wxT(",url=");
307         dup_opts += net_addr->GetLineText(0);
308         dup_opts += wxString::Format( wxT(":%d"), net_port->GetValue() );
309         dup_opts += wxT("}");
310     }
311
312     wxString duplicate;
313     if( !dup_opts.IsEmpty() )
314     {
315         if( !transcode.IsEmpty() ) duplicate = wxT(":");
316         duplicate += wxT("duplicate{") + dup_opts + wxT("}");
317     }
318
319     if( !transcode.IsEmpty() || !duplicate.IsEmpty() )
320         mrl_combo->SetValue( wxT("#") + transcode + duplicate );
321     else
322         mrl_combo->SetValue( wxT("") );
323 }
324
325 wxPanel *SoutDialog::AccessPanel( wxWindow* parent )
326 {
327     int i;
328     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
329                                   wxSize(200, 200) );
330
331     wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 4, 20 );
332     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
333                                               wxU(_("Output Methods")) );
334     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
335                                                           wxVERTICAL );
336
337     static const wxString access_output_array[] =
338     {
339         wxU(_("Play locally")),
340         wxU(_("File")),
341         wxU(_("HTTP")),
342         wxU(_("UDP")),
343         wxU(_("RTP"))
344     };
345
346     for( i=0; i < ACCESS_OUT_NUM; i++ )
347     {
348         access_checkboxes[i] = new wxCheckBox( panel, AccessType1_Event + i,
349                                                access_output_array[i] );
350         access_subpanels[i] = new wxPanel( panel, -1 );
351     }
352
353     /* Play locally row */
354     wxFlexGridSizer *subpanel_sizer;
355     wxStaticText *label;
356     label = new wxStaticText( access_subpanels[0], -1, wxT("") );
357     subpanel_sizer = new wxFlexGridSizer( 1, 1, 20 );
358     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
359     access_subpanels[0]->SetSizerAndFit( subpanel_sizer );
360
361     /* File row */
362     subpanel_sizer = new wxFlexGridSizer( 3, 1, 20 );
363     label = new wxStaticText( access_subpanels[1], -1, wxU(_("Filename")) );
364     file_combo = new wxComboBox( access_subpanels[1], FileName_Event, wxT(""),
365                                  wxPoint(20,25), wxSize(200, -1), 0, NULL );
366     wxButton *browse_button = new wxButton( access_subpanels[1],
367                                   FileBrowse_Event, wxU(_("Browse...")) );
368     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
369     subpanel_sizer->Add( file_combo, 1,
370                          wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
371     subpanel_sizer->Add( browse_button, 0,
372                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
373
374     access_subpanels[1]->SetSizerAndFit( subpanel_sizer );
375
376     /* Net rows */
377     for( i=2; i < ACCESS_OUT_NUM; i++ )
378     {
379         subpanel_sizer = new wxFlexGridSizer( 4, 1, 20 );
380         label = new wxStaticText( access_subpanels[i], -1, wxU(_("Address")) );
381         net_addr = new wxTextCtrl( access_subpanels[i], NetAddr_Event, wxT(""),
382                                    wxDefaultPosition, wxSize( 200, -1 ),
383                                    wxTE_PROCESS_ENTER);
384         subpanel_sizer->Add( label, 0,
385                              wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
386         subpanel_sizer->Add( net_addr, 1, wxEXPAND |
387                              wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
388
389         int val = config_GetInt( p_intf, "server-port" );
390         label = new wxStaticText( access_subpanels[i], -1, wxU(_("Port")) );
391         net_port = new wxSpinCtrl( access_subpanels[i], NetPort_Event,
392                                    wxString::Format(wxT("%d"), val),
393                                    wxDefaultPosition, wxDefaultSize,
394                                    wxSP_ARROW_KEYS,
395                                    0, 16000, val );
396
397         subpanel_sizer->Add( label, 0,
398                              wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
399         subpanel_sizer->Add( net_port, 0,
400                              wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
401
402         access_subpanels[i]->SetSizerAndFit( subpanel_sizer );
403     }
404
405
406     /* Stuff everything into the main panel */
407     for( i=1; i < ACCESS_OUT_NUM; i++ )
408     {
409         sizer->Add( access_checkboxes[i], 0,
410                     wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL  | wxALL, 5 );
411         sizer->Add( access_subpanels[i], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL
412                     | wxALIGN_LEFT  | wxALL, 5 );
413     }
414
415     panel_sizer->Add( access_checkboxes[0], 0,
416                       wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL  | wxALL, 5 );
417     panel_sizer->Add( sizer, 1, wxEXPAND | wxTOP, 3 );
418
419     panel->SetSizerAndFit( panel_sizer );
420
421     /* Update access type panel */
422     for( i=1; i < ACCESS_OUT_NUM; i++ )
423     {
424         access_subpanels[i]->Disable();
425     }
426
427     return panel;
428 }
429
430 wxPanel *SoutDialog::EncapsulationPanel( wxWindow* parent )
431 {
432     int i;
433     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
434                                   wxSize(200, 200) );
435
436     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
437                                               wxU(_("Encapsulation Method")) );
438     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
439                                                           wxHORIZONTAL );
440
441     static const wxString encapsulation_array[] =
442     {
443         wxT("MPEG TS"),
444         wxT("MPEG PS"),
445         wxT("AVI"),
446         wxT("MP4/MOV"),
447         wxT("Ogg")
448     };
449
450     /* Stuff everything into the main panel */
451     for( i=0; i < ENCAPS_NUM; i++ )
452     {
453         encapsulation_radios[i] =
454             new wxRadioButton( panel, EncapsulationRadio1_Event + i,
455                                encapsulation_array[i] );
456         panel_sizer->Add( encapsulation_radios[i], 0,
457                           wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 8 );
458     }
459
460     panel->SetSizerAndFit( panel_sizer );
461
462     /* Update encapsulation panel */
463     encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
464     i_encapsulation_type = TS_ENCAPSULATION;
465
466     return panel;
467 }
468
469 wxPanel *SoutDialog::TranscodingPanel( wxWindow* parent )
470 {
471     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
472                                   wxSize(200, 200) );
473
474     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
475                                               wxU(_("Transcoding options")) );
476     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
477                                                           wxVERTICAL );
478
479     /* Create video transcoding checkox */
480     static const wxString vcodecs_array[] =
481     {
482         wxT("mpgv"),
483         wxT("mp4v"),
484         wxT("DIV1"),
485         wxT("DIV2"),
486         wxT("DIV3"),
487         wxT("H263"),
488         wxT("I263"),
489         wxT("WMV1"),
490     };
491     static const wxString vbitrates_array[] =
492     {
493         wxT("3000"),
494         wxT("2000"),
495         wxT("1000"),
496         wxT("750"),
497         wxT("500"),
498         wxT("400"),
499         wxT("200"),
500         wxT("150"),
501         wxT("100")
502     };
503
504     wxFlexGridSizer *video_sizer = new wxFlexGridSizer( 4, 1, 20 );
505     video_transc_checkbox =
506         new wxCheckBox( panel, VideoTranscEnable_Event, wxU(_("Video codec")));
507     video_codec_combo =
508         new wxComboBox( panel, VideoTranscCodec_Event, wxT("mp4v"),
509                         wxPoint(20,25), wxDefaultSize, WXSIZEOF(vcodecs_array),
510                         vcodecs_array, wxCB_READONLY );
511     wxStaticText *bitrate_label =
512         new wxStaticText( panel, -1, wxU(_("Bitrate (kb/s)")));
513     video_bitrate_combo =
514         new wxComboBox( panel, VideoTranscBitrate_Event, wxT("1000"),
515                         wxPoint(20,25), wxDefaultSize,
516                         WXSIZEOF(vbitrates_array), vbitrates_array );
517     video_sizer->Add( video_transc_checkbox, 0,
518                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
519     video_sizer->Add( video_codec_combo, 1,
520                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
521     video_sizer->Add( bitrate_label, 0,
522                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
523     video_sizer->Add( video_bitrate_combo, 1,
524                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
525
526     /* Create audio transcoding checkox */
527     static const wxString acodecs_array[] =
528     {
529         wxT("mpga"),
530         wxT("a52")
531     };
532     static const wxString abitrates_array[] =
533     {
534         wxT("512"),
535         wxT("256"),
536         wxT("192"),
537         wxT("128"),
538         wxT("96")
539     };
540
541     wxFlexGridSizer *audio_sizer = new wxFlexGridSizer( 4, 1, 20 );
542     audio_transc_checkbox =
543         new wxCheckBox( panel, AudioTranscEnable_Event, wxU(_("Audio codec")));
544     audio_codec_combo =
545         new wxComboBox( panel, AudioTranscCodec_Event, wxT("mpga"),
546                         wxPoint(20,25), wxDefaultSize, WXSIZEOF(acodecs_array),
547                         acodecs_array, wxCB_READONLY );
548     bitrate_label =
549         new wxStaticText( panel, -1, wxU(_("Bitrate (kb/s)")));
550     audio_bitrate_combo =
551         new wxComboBox( panel, AudioTranscBitrate_Event, wxT("192"),
552                         wxPoint(20,25), wxDefaultSize,
553                         WXSIZEOF(abitrates_array), abitrates_array );
554     audio_sizer->Add( audio_transc_checkbox, 0,
555                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
556     audio_sizer->Add( audio_codec_combo, 1,
557                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
558     audio_sizer->Add( bitrate_label, 0,
559                       wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
560     audio_sizer->Add( audio_bitrate_combo, 1,
561                       wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
562
563     /* Stuff everything into the main panel */
564     panel_sizer->Add( video_sizer, 0,
565                       wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
566     panel_sizer->Add( audio_sizer, 0,
567                       wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
568
569     panel->SetSizerAndFit( panel_sizer );
570
571     /* Update transcoding panel */
572     wxCommandEvent event( 0, VideoTranscEnable_Event );
573     event.SetInt( 0 );
574     OnTranscodingEnable( event );
575     event.SetId( AudioTranscEnable_Event );
576     OnTranscodingEnable( event );
577
578     return panel;
579 }
580
581 /*****************************************************************************
582  * Events methods.
583  *****************************************************************************/
584 void SoutDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
585 {
586     mrl_combo->Append( mrl_combo->GetValue() );
587     mrl = mrl_combo->GetValue();
588     EndModal( wxID_OK );
589 }
590
591 void SoutDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
592 {
593     EndModal( wxID_CANCEL );
594 }
595
596 void SoutDialog::OnMRLChange( wxCommandEvent& event )
597 {
598     //mrl = event.GetString();
599 }
600
601 /*****************************************************************************
602  * Access output panel event methods.
603  *****************************************************************************/
604 void SoutDialog::OnAccessTypeChange( wxCommandEvent& event )
605 {
606     int i;
607     i_access_type = event.GetId() - AccessType1_Event;
608
609     access_subpanels[i_access_type]->Enable( event.GetInt() );
610
611     switch( i_access_type )
612     {
613     case UDP_ACCESS_OUT:
614     case RTP_ACCESS_OUT:
615         for( i = 1; i < ENCAPS_NUM; i++ )
616         {
617             encapsulation_radios[i]->Enable( !event.GetInt() );
618         }
619         if( event.GetInt() )
620         {
621             encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
622             i_encapsulation_type = TS_ENCAPSULATION;
623         }
624         break;
625     }
626
627     UpdateMRL();
628 }
629
630 /*****************************************************************************
631  * File access output event methods.
632  *****************************************************************************/
633 void SoutDialog::OnFileChange( wxCommandEvent& WXUNUSED(event) )
634 {
635     UpdateMRL();
636 }
637
638 void SoutDialog::OnFileBrowse( wxCommandEvent& WXUNUSED(event) )
639 {
640     wxFileDialog dialog( this, wxU(_("Save file")),
641                          wxT(""), wxT(""), wxT("*"), wxSAVE );
642
643     if( dialog.ShowModal() == wxID_OK )
644     {
645         file_combo->SetValue( dialog.GetPath() );
646         UpdateMRL();
647     }
648 }
649
650 /*****************************************************************************
651  * Net access output event methods.
652  *****************************************************************************/
653 void SoutDialog::OnNetChange( wxCommandEvent& WXUNUSED(event) )
654 {
655     UpdateMRL();
656 }
657
658 /*****************************************************************************
659  * Encapsulation panel event methods.
660  *****************************************************************************/
661 void SoutDialog::OnEncapsulationChange( wxCommandEvent& event )
662 {
663     i_encapsulation_type = event.GetId() - EncapsulationRadio1_Event;
664     UpdateMRL();
665 }
666
667 /*****************************************************************************
668  * Transcoding panel event methods.
669  *****************************************************************************/
670 void SoutDialog::OnTranscodingEnable( wxCommandEvent& event )
671 {
672     switch( event.GetId() )
673     {
674     case VideoTranscEnable_Event:
675         video_codec_combo->Enable( event.GetInt() );
676         video_bitrate_combo->Enable( event.GetInt() );
677         break;
678     case AudioTranscEnable_Event:
679         audio_codec_combo->Enable( event.GetInt() );
680         audio_bitrate_combo->Enable( event.GetInt() );
681         break;
682     }
683
684     UpdateMRL();
685 }
686
687 void SoutDialog::OnTranscodingChange( wxCommandEvent& event )
688 {
689     UpdateMRL();
690 }