]> git.sesse.net Git - vlc/blobdiff - modules/gui/wxwindows/streamout.cpp
* modules/gui/wxwindows/*: we now have only 1 global "Advanced Options" checkbox...
[vlc] / modules / gui / wxwindows / streamout.cpp
index def6ab20c8c0e7596a223e488e3cb8eeac442319..95aa22fc2a6959eb0e8bde5737e12ed8c7a8aafe 100644 (file)
@@ -2,7 +2,7 @@
  * streamout.cpp : wxWindows plugin for vlc
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: streamout.cpp,v 1.4 2003/04/01 00:18:29 gbazin Exp $
+ * $Id: streamout.cpp,v 1.31 2003/08/30 11:59:44 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
 #include <stdio.h>
 
 #include <vlc/vlc.h>
+#include <vlc/intf.h>
 
-#ifdef WIN32                                                 /* mingw32 hack */
-#undef Yield
-#undef CreateDialog
-#endif
-
-/* Let vlc take care of the i18n stuff */
-#define WXINTL_NO_GETTEXT_MACRO
-
-#include <wx/wxprec.h>
-#include <wx/wx.h>
+#include "wxwindows.h"
 #include <wx/notebook.h>
 #include <wx/textctrl.h>
 #include <wx/combobox.h>
 #include <wx/spinctrl.h>
 #include <wx/statline.h>
 
-#include <vlc/intf.h>
-
-#include "wxwindows.h"
-
 #ifndef wxRB_SINGLE
 #   define wxRB_SINGLE 0
 #endif
 
-enum
-{
-    FILE_ACCESS_OUT = 0,
-    HTTP_ACCESS_OUT,
-    UDP_ACCESS_OUT,
-    RTP_ACCESS_OUT
-};
-
-enum
-{
-    TS_ENCAPSULATION = 0,
-    PS_ENCAPSULATION,
-    AVI_ENCAPSULATION,
-    OGG_ENCAPSULATION
-};
-
 /*****************************************************************************
  * Event Table.
  *****************************************************************************/
@@ -84,14 +56,21 @@ enum
     FileBrowse_Event,
     FileName_Event,
 
-    AccessType_Event,
-    AccessRadio1_Event, AccessRadio2_Event,
-    AccessRadio3_Event, AccessRadio4_Event,
-    NetPort_Event,
-    NetAddr_Event,
+    AccessType1_Event, AccessType2_Event, AccessType3_Event,
+    AccessType4_Event, AccessType5_Event, AccessType6_Event,
+    NetPort1_Event, NetPort2_Event, NetPort3_Event,
+    NetAddr1_Event, NetAddr2_Event, NetAddr3_Event,
 
     EncapsulationRadio1_Event, EncapsulationRadio2_Event,
     EncapsulationRadio3_Event, EncapsulationRadio4_Event,
+    EncapsulationRadio5_Event, EncapsulationRadio6_Event,
+    EncapsulationRadio7_Event, EncapsulationRadio8_Event,
+
+    VideoTranscEnable_Event, VideoTranscCodec_Event, VideoTranscBitrate_Event,
+    AudioTranscEnable_Event, AudioTranscCodec_Event, AudioTranscBitrate_Event,
+    AudioTranscChans_Event,
+
+    SAPMisc_Event, SLPMisc_Event, AnnounceAddr_Event
 };
 
 BEGIN_EVENT_TABLE(SoutDialog, wxDialog)
@@ -100,16 +79,22 @@ BEGIN_EVENT_TABLE(SoutDialog, wxDialog)
     EVT_BUTTON(wxID_CANCEL, SoutDialog::OnCancel)
 
     /* Events generated by the access output panel */
-    EVT_RADIOBUTTON(AccessRadio1_Event, SoutDialog::OnAccessTypeChange)
-    EVT_RADIOBUTTON(AccessRadio2_Event, SoutDialog::OnAccessTypeChange)
-    EVT_RADIOBUTTON(AccessRadio3_Event, SoutDialog::OnAccessTypeChange)
-    EVT_RADIOBUTTON(AccessRadio4_Event, SoutDialog::OnAccessTypeChange)
+    EVT_CHECKBOX(AccessType1_Event, SoutDialog::OnAccessTypeChange)
+    EVT_CHECKBOX(AccessType2_Event, SoutDialog::OnAccessTypeChange)
+    EVT_CHECKBOX(AccessType3_Event, SoutDialog::OnAccessTypeChange)
+    EVT_CHECKBOX(AccessType4_Event, SoutDialog::OnAccessTypeChange)
+    EVT_CHECKBOX(AccessType5_Event, SoutDialog::OnAccessTypeChange)
+    EVT_CHECKBOX(AccessType6_Event, SoutDialog::OnAccessTypeChange)
     EVT_TEXT(FileName_Event, SoutDialog::OnFileChange)
     EVT_BUTTON(FileBrowse_Event, SoutDialog::OnFileBrowse)
-    EVT_TEXT(NetPort_Event, SoutDialog::OnNetChange)
-    EVT_SPINCTRL(NetPort_Event, SoutDialog::OnNetChange)
-    EVT_TEXT(NetAddr_Event, SoutDialog::OnNetChange)
+
+    EVT_TEXT(NetPort1_Event, SoutDialog::OnNetChange)
+    EVT_TEXT(NetAddr1_Event, SoutDialog::OnNetChange)
+    EVT_TEXT(NetPort2_Event, SoutDialog::OnNetChange)
+    EVT_TEXT(NetAddr2_Event, SoutDialog::OnNetChange)
+    EVT_TEXT(NetPort3_Event, SoutDialog::OnNetChange)
+    EVT_TEXT(NetAddr3_Event, SoutDialog::OnNetChange)
+
     /* Events generated by the encapsulation panel */
     EVT_RADIOBUTTON(EncapsulationRadio1_Event,
                     SoutDialog::OnEncapsulationChange)
@@ -119,19 +104,47 @@ BEGIN_EVENT_TABLE(SoutDialog, wxDialog)
                     SoutDialog::OnEncapsulationChange)
     EVT_RADIOBUTTON(EncapsulationRadio4_Event,
                     SoutDialog::OnEncapsulationChange)
+    EVT_RADIOBUTTON(EncapsulationRadio5_Event,
+                    SoutDialog::OnEncapsulationChange)
+    EVT_RADIOBUTTON(EncapsulationRadio6_Event,
+                    SoutDialog::OnEncapsulationChange)
+    EVT_RADIOBUTTON(EncapsulationRadio7_Event,
+                    SoutDialog::OnEncapsulationChange)
+    EVT_RADIOBUTTON(EncapsulationRadio8_Event,
+                    SoutDialog::OnEncapsulationChange)
+
+    /* Events generated by the transcoding panel */
+    EVT_CHECKBOX(VideoTranscEnable_Event, SoutDialog::OnTranscodingEnable)
+    EVT_CHECKBOX(AudioTranscEnable_Event, SoutDialog::OnTranscodingEnable)
+    EVT_COMBOBOX(VideoTranscCodec_Event, SoutDialog::OnTranscodingChange)
+    EVT_TEXT(VideoTranscCodec_Event, SoutDialog::OnTranscodingChange)
+    EVT_COMBOBOX(AudioTranscCodec_Event, SoutDialog::OnTranscodingChange)
+    EVT_TEXT(AudioTranscCodec_Event, SoutDialog::OnTranscodingChange)
+    EVT_COMBOBOX(VideoTranscBitrate_Event, SoutDialog::OnTranscodingChange)
+    EVT_TEXT(VideoTranscBitrate_Event, SoutDialog::OnTranscodingChange)
+    EVT_COMBOBOX(AudioTranscBitrate_Event, SoutDialog::OnTranscodingChange)
+    EVT_TEXT(AudioTranscBitrate_Event, SoutDialog::OnTranscodingChange)
+    EVT_COMBOBOX(AudioTranscChans_Event, SoutDialog::OnTranscodingChange)
+    EVT_TEXT(AudioTranscChans_Event, SoutDialog::OnTranscodingChange)
+
+    /* Events generated by the misc panel */
+    EVT_CHECKBOX(SAPMisc_Event, SoutDialog::OnSAPMiscChange)
+    EVT_CHECKBOX(SLPMisc_Event, SoutDialog::OnSLPMiscChange)
+    EVT_TEXT(AnnounceAddr_Event, SoutDialog::OnAnnounceAddrChange)
 
 END_EVENT_TABLE()
 
 /*****************************************************************************
  * Constructor.
  *****************************************************************************/
-SoutDialog::SoutDialog( intf_thread_t *_p_intf, Interface *_p_main_interface ):
-    wxDialog( _p_main_interface, -1, _("Stream output"), wxDefaultPosition,
-             wxDefaultSize, wxDEFAULT_FRAME_STYLE )
+SoutDialog::SoutDialog( intf_thread_t *_p_intf, wxWindow* _p_parent ):
+    wxDialog( _p_parent, -1, wxU(_("Stream output")),
+             wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE )
 {
     /* Initializations */
     p_intf = _p_intf;
-    p_main_interface = _p_main_interface;
+    p_parent = _p_parent;
+    SetIcon( *p_intf->p_sys->p_icon );
 
     /* Create a panel to put everything in */
     wxPanel *panel = new wxPanel( this, -1 );
@@ -140,31 +153,41 @@ SoutDialog::SoutDialog( intf_thread_t *_p_intf, Interface *_p_main_interface ):
     /* Create MRL combobox */
     wxBoxSizer *mrl_sizer_sizer = new wxBoxSizer( wxHORIZONTAL );
     wxStaticBox *mrl_box = new wxStaticBox( panel, -1,
-                               _("Stream output MRL") );
+                               wxU(_("Stream output MRL")) );
     wxStaticBoxSizer *mrl_sizer = new wxStaticBoxSizer( mrl_box,
                                                         wxHORIZONTAL );
     wxStaticText *mrl_label = new wxStaticText( panel, -1,
-                                                _("Destination Target:") );
-    mrl_combo = new wxComboBox( panel, MRL_Event, mrl,
-                                wxPoint(20,25), wxSize(120, -1),
-                                0, NULL );
-    mrl_sizer->Add( mrl_label, 0, wxEXPAND | wxALL, 5 );
-    mrl_sizer->Add( mrl_combo, 1, wxEXPAND | wxALL, 5 );
+                                                wxU(_("Destination Target:")));
+    mrl_combo = new wxComboBox( panel, MRL_Event, wxT(""),
+                                wxPoint(20,25), wxSize(120, -1), 0, NULL );
+    mrl_combo->SetToolTip( wxU(_("You can use this field directly by typing "
+        "the full MRL you want to open.\n""Alternatively, the field will be "
+        "filled automatically when you use the controls below")) );
+
+    mrl_sizer->Add( mrl_label, 0, wxALL | wxALIGN_CENTER, 5 );
+    mrl_sizer->Add( mrl_combo, 1, wxALL | wxALIGN_CENTER, 5 );
     mrl_sizer_sizer->Add( mrl_sizer, 1, wxEXPAND | wxALL, 5 );
 
     /* Create the output encapsulation panel */
-    encapsulation_panel = EncapsulationPanel( panel );
+    wxPanel *encapsulation_panel = EncapsulationPanel( panel );
 
     /* Create the access output panel */
-    access_panel = AccessPanel( panel );
+    wxPanel *access_panel = AccessPanel( panel );
+
+    /* Create the transcoding panel */
+    wxPanel *transcoding_panel = TranscodingPanel( panel );
+
+    /* Create the Misc panel */
+    wxPanel *misc_panel = MiscPanel( panel );
 
     /* Separation */
     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
 
     /* Create the buttons */
-    wxButton *ok_button = new wxButton( panel, wxID_OK, _("OK") );
+    wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
     ok_button->SetDefault();
-    wxButton *cancel_button = new wxButton( panel, wxID_CANCEL, _("Cancel") );
+    wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
+                                            wxU(_("Cancel")) );
 
     /* Place everything in sizers */
     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
@@ -176,6 +199,8 @@ SoutDialog::SoutDialog( intf_thread_t *_p_intf, Interface *_p_main_interface ):
     panel_sizer->Add( mrl_sizer_sizer, 0, wxEXPAND, 5 );
     panel_sizer->Add( access_panel, 1, wxEXPAND | wxALL, 5 );
     panel_sizer->Add( encapsulation_panel, 0, wxEXPAND | wxALL, 5 );
+    panel_sizer->Add( transcoding_panel, 0, wxEXPAND | wxALL, 5 );
+    panel_sizer->Add( misc_panel, 0, wxEXPAND | wxALL, 5 );
     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
                       wxALL, 5 );
@@ -184,62 +209,158 @@ SoutDialog::SoutDialog( intf_thread_t *_p_intf, Interface *_p_main_interface ):
     main_sizer->Add( panel, 1, wxGROW, 0 );
     main_sizer->Layout();
     SetSizerAndFit( main_sizer );
-
-    /* Update all the values */
-    ParseMRL();
 }
 
 SoutDialog::~SoutDialog()
 {
 }
 
+wxArrayString SoutDialog::GetOptions()
+{
+   return SeparateEntries( mrl_combo->GetValue() );
+}
+
 /*****************************************************************************
  * Private methods.
  *****************************************************************************/
 void SoutDialog::UpdateMRL()
 {
-    wxString encapsulation;
+    /* Let's start with the transcode options */
+    wxString transcode;
+    if( video_transc_checkbox->IsChecked() ||
+        audio_transc_checkbox->IsChecked() )
+    {
+        transcode = wxT("transcode{");
+        if( video_transc_checkbox->IsChecked() )
+        {
+            transcode += wxT("vcodec=") + video_codec_combo->GetValue();
+            transcode += wxT(",vb=") + video_bitrate_combo->GetValue();
+            if( audio_transc_checkbox->IsChecked() ) transcode += wxT(",");
+        }
+        if( audio_transc_checkbox->IsChecked() )
+        {
+            transcode += wxT("acodec=") + audio_codec_combo->GetValue();
+            transcode += wxT(",ab=") + audio_bitrate_combo->GetValue();
+            transcode += wxT(",channels=") + audio_channels_combo->GetValue();
+        }
+        transcode += wxT("}");
+    }
 
+    /* Encapsulation */
+    wxString encapsulation;
     switch( i_encapsulation_type )
     {
     case PS_ENCAPSULATION:
-        encapsulation = "/ps";
+        encapsulation = wxT("ps");
+        break;
+    case MPEG1_ENCAPSULATION:
+        encapsulation = wxT("mpeg1");
         break;
     case AVI_ENCAPSULATION:
-        encapsulation = "/avi";
+        encapsulation = wxT("avi");
         break;
     case OGG_ENCAPSULATION:
-        encapsulation = "/ogg";
+        encapsulation = wxT("ogg");
+        break;
+    case MP4_ENCAPSULATION:
+        encapsulation = wxT("mp4");
+        break;
+    case MOV_ENCAPSULATION:
+        encapsulation = wxT("mov");
+        break;
+    case ASF_ENCAPSULATION:
+        encapsulation = wxT("asf");
         break;
     case TS_ENCAPSULATION:
     default:
-        encapsulation = "/ts";
+        encapsulation = wxT("ts");
         break;
     }
 
-    switch( i_access_type )
+    /* Now continue with the duplicate option */
+    wxString dup_opts;
+    if( access_checkboxes[PLAY_ACCESS_OUT]->IsChecked() )
     {
-    case FILE_ACCESS_OUT:
-        mrl = "file" + encapsulation + ":" + file_combo->GetValue();
-        break;
+        dup_opts += wxT("dst=display");
+    }
+    if( access_checkboxes[FILE_ACCESS_OUT]->IsChecked() )
+    {
+        if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
+        dup_opts += wxT("dst=std{access=file,mux=");
+        dup_opts += encapsulation + wxT(",url=\"");
+        dup_opts += file_combo->GetValue() + wxT("\"}");
+    }
+    if( access_checkboxes[HTTP_ACCESS_OUT]->IsChecked() )
+    {
+        if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
+        dup_opts += wxT("dst=std{access=http,mux=");
+        dup_opts += encapsulation + wxT(",url=");
+        dup_opts += net_addrs[HTTP_ACCESS_OUT]->GetLineText(0);
+        dup_opts += wxString::Format( wxT(":%d"),
+                                      net_ports[HTTP_ACCESS_OUT]->GetValue() );
+        dup_opts += wxT("}");
+    }
+    if( access_checkboxes[MMSH_ACCESS_OUT]->IsChecked() )
+    {
+        if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
+        dup_opts += wxT("dst=std{access=mmsh,mux=");
+        dup_opts += encapsulation;
+        if( i_encapsulation_type == ASF_ENCAPSULATION ) dup_opts += wxT("h");
+        dup_opts += wxT(",url=");
+        dup_opts += net_addrs[HTTP_ACCESS_OUT]->GetLineText(0);
+        dup_opts += wxString::Format( wxT(":%d"),
+                                      net_ports[MMSH_ACCESS_OUT]->GetValue() );
+        dup_opts += wxT("}");
+    }
+    if( access_checkboxes[UDP_ACCESS_OUT]->IsChecked() )
+    {
+        if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
+        dup_opts += wxT("dst=std{access=udp,mux=");
+        dup_opts += encapsulation + wxT(",url=");
+        dup_opts += net_addrs[UDP_ACCESS_OUT]->GetLineText(0);
+        dup_opts += wxString::Format( wxT(":%d"),
+                                      net_ports[UDP_ACCESS_OUT]->GetValue() );
+
+        /* SAP only if UDP */
+        if( sap_checkbox->IsChecked() )
+        {
+            dup_opts += wxT(",sap=\"");
+            dup_opts += announce_addr->GetLineText(0);
+            dup_opts += wxT("\"");
+        }
 
-    case HTTP_ACCESS_OUT:
-        mrl = "http" + encapsulation + ":" + net_addr->GetLineText(0)
-              + wxString::Format( ":%d", net_port->GetValue() );
-        break;
+        /* SLP only if UDP */
+        if( slp_checkbox->IsChecked() )
+        {
+            dup_opts += wxT(",slp=\"");
+            dup_opts += announce_addr->GetLineText(0);
+            dup_opts += wxT("\"");
+        }
 
-    case UDP_ACCESS_OUT:
-    case RTP_ACCESS_OUT:
-        mrl = ( i_access_type == UDP_ACCESS_OUT ) ? "udp" : "rtp";
-       mrl += encapsulation + ":" + net_addr->GetLineText(0);
-       if( net_port->GetValue() != config_GetInt( p_intf, "server-port" ) )
-       {
-           mrl += wxString::Format( ":%d", net_port->GetValue() );
-       }
-        break;
+        dup_opts += wxT("}");
+    }
+    if( access_checkboxes[RTP_ACCESS_OUT]->IsChecked() )
+    {
+        if( !dup_opts.IsEmpty() ) dup_opts += wxT(",");
+        dup_opts += wxT("dst=std{access=rtp,mux=");
+        dup_opts += encapsulation + wxT(",url=");
+        dup_opts += net_addrs[RTP_ACCESS_OUT]->GetLineText(0);
+        dup_opts += wxString::Format( wxT(":%d"),
+                                      net_ports[RTP_ACCESS_OUT]->GetValue() );
+        dup_opts += wxT("}");
     }
 
-    mrl_combo->SetValue( mrl );
+    wxString duplicate;
+    if( !dup_opts.IsEmpty() )
+    {
+        if( !transcode.IsEmpty() ) duplicate = wxT(":");
+        duplicate += wxT("duplicate{") + dup_opts + wxT("}");
+    }
+
+    if( !transcode.IsEmpty() || !duplicate.IsEmpty() )
+        mrl_combo->SetValue( wxT(":sout=#") + transcode + duplicate );
+    else
+        mrl_combo->SetValue( wxT("") );
 }
 
 wxPanel *SoutDialog::AccessPanel( wxWindow* parent )
@@ -248,85 +369,155 @@ wxPanel *SoutDialog::AccessPanel( wxWindow* parent )
     wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
                                   wxSize(200, 200) );
 
-    wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 4, 20 );
-    wxStaticBox *panel_box = new wxStaticBox( panel, -1, _("Output Method") );
+    wxStaticBox *panel_box = new wxStaticBox( panel, -1,
+                                              wxU(_("Output Methods")) );
     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
-                                                          wxHORIZONTAL );
+                                                          wxVERTICAL );
 
+    wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 4, 20 );
     static const wxString access_output_array[] =
     {
-        _("File"),
-        _("HTTP"),
-        _("UDP"),
-        _("RTP")
+        wxU(_("Play locally")),
+        wxU(_("File")),
+        wxU(_("HTTP")),
+        wxU(_("MMSH")),
+        wxU(_("UDP")),
+        wxU(_("RTP"))
     };
 
-    for( i=0; i<4; i++ )
+    for( i=0; i < ACCESS_OUT_NUM; i++ )
     {
-        access_radios[i] = new wxRadioButton( panel, AccessRadio1_Event + i,
-                                              access_output_array[i],
-                                              wxDefaultPosition, wxDefaultSize,
-                                              wxRB_SINGLE );
-
-        access_subpanels[i] = new wxPanel( panel, -1,
-                                           wxDefaultPosition, wxDefaultSize );
+        access_checkboxes[i] = new wxCheckBox( panel, AccessType1_Event + i,
+                                               access_output_array[i] );
+        access_subpanels[i] = new wxPanel( panel, -1 );
     }
 
-    /* File row */
+    /* Play locally row */
     wxFlexGridSizer *subpanel_sizer;
     wxStaticText *label;
+    label = new wxStaticText( access_subpanels[0], -1, wxT("") );
+    subpanel_sizer = new wxFlexGridSizer( 1, 1, 20 );
+    subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    access_subpanels[0]->SetSizerAndFit( subpanel_sizer );
+    access_subpanels[0]->Hide();
+
+    /* File row */
     subpanel_sizer = new wxFlexGridSizer( 3, 1, 20 );
-    label = new wxStaticText( access_subpanels[0], -1, _("Filename") );
-    file_combo = new wxComboBox( access_subpanels[0], FileName_Event, "",
+    label = new wxStaticText( access_subpanels[1], -1, wxU(_("Filename")) );
+    file_combo = new wxComboBox( access_subpanels[1], FileName_Event, wxT(""),
                                  wxPoint(20,25), wxSize(200, -1), 0, NULL );
-    wxButton *browse_button = new wxButton( access_subpanels[0],
-                                            FileBrowse_Event, _("Browse...") );
+    wxButton *browse_button = new wxButton( access_subpanels[1],
+                                  FileBrowse_Event, wxU(_("Browse...")) );
     subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
     subpanel_sizer->Add( file_combo, 1,
                          wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
     subpanel_sizer->Add( browse_button, 0,
                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
 
-    access_subpanels[0]->SetSizerAndFit( subpanel_sizer );
+    access_subpanels[1]->SetSizerAndFit( subpanel_sizer );
 
-    /* Net row */
-    subpanel_sizer = new wxFlexGridSizer( 4, 1, 20 );
-    label = new wxStaticText( access_subpanels[2], -1, _("Address") );
-    net_addr = new wxTextCtrl( access_subpanels[2], NetAddr_Event, "",
-                               wxDefaultPosition, wxSize( 200, -1 ),
-                               wxTE_PROCESS_ENTER);
-    subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
-    subpanel_sizer->Add( net_addr, 1,
-                         wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
+    /* Net rows */
+    for( i = HTTP_ACCESS_OUT; i < ACCESS_OUT_NUM; i++ )
+    {
+        subpanel_sizer = new wxFlexGridSizer( 4, 1, 20 );
+        label = new wxStaticText( access_subpanels[i], -1, wxU(_("Address")) );
+        net_addrs[i] = new wxTextCtrl( access_subpanels[i],
+                                   NetAddr1_Event + i - HTTP_ACCESS_OUT,
+                                   wxT(""), wxDefaultPosition,
+                                   wxSize( 200, -1 ), wxTE_PROCESS_ENTER);
+        subpanel_sizer->Add( label, 0,
+                             wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+        subpanel_sizer->Add( net_addrs[i], 1, wxEXPAND |
+                             wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
+
+        int val = config_GetInt( p_intf, "server-port" );
+        label = new wxStaticText( access_subpanels[i], -1, wxU(_("Port")) );
+        net_ports[i] = new wxSpinCtrl( access_subpanels[i],
+                                   NetPort1_Event + i - HTTP_ACCESS_OUT,
+                                   wxString::Format(wxT("%d"), val),
+                                   wxDefaultPosition, wxDefaultSize,
+                                   wxSP_ARROW_KEYS,
+                                   0, 16000, val );
+
+        subpanel_sizer->Add( label, 0,
+                             wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+        subpanel_sizer->Add( net_ports[i], 0,
+                             wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
+
+        access_subpanels[i]->SetSizerAndFit( subpanel_sizer );
+    }
 
-    int val = config_GetInt( p_intf, "server-port" );
-    label = new wxStaticText( access_subpanels[2], -1, _("Port") );
-    net_port = new wxSpinCtrl( access_subpanels[2], NetPort_Event,
-                               wxString::Format("%d", val),
-                               wxDefaultPosition, wxDefaultSize,
-                               wxSP_ARROW_KEYS,
-                               0, 16000, val );
 
-    subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
-    subpanel_sizer->Add( net_port, 0,
-                         wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
+    /* Stuff everything into the main panel */
+    for( i=1; i < ACCESS_OUT_NUM; i++ )
+    {
+        sizer->Add( access_checkboxes[i], 0,
+                    wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL  | wxALL, 5 );
+        sizer->Add( access_subpanels[i], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL
+                    | wxALIGN_LEFT  | wxALL, 5 );
+    }
 
-    access_subpanels[2]->SetSizerAndFit( subpanel_sizer );
+    panel_sizer->Add( access_checkboxes[0], 0,
+                      wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL  | wxALL, 5 );
+    panel_sizer->Add( sizer, 1, wxEXPAND | wxTOP, 3 );
 
+    panel->SetSizerAndFit( panel_sizer );
 
-    /* Stuff everything into the main panel */
-    for( i=0; i<4; i++ )
+    /* Update access type panel */
+    for( i=1; i < ACCESS_OUT_NUM; i++ )
     {
-        sizer->Add( access_radios[i], 0,
-                    wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
-        sizer->Add( access_subpanels[i], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL
-                    | wxALIGN_LEFT );
+        access_subpanels[i]->Disable();
     }
 
-    panel_sizer->Add( sizer, 1, wxEXPAND, 0 );
+    return panel;
+}
+
+wxPanel *SoutDialog::MiscPanel( wxWindow* parent )
+{
+    wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
+                                  wxSize(200, 200) );
+
+    wxStaticBox *panel_box = new wxStaticBox( panel, -1,
+                                   wxU(_("Miscellaneous Options")) );
+    wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
+                                                          wxVERTICAL );
+
+    /* Announce Row */
+    misc_subpanels[ANN_MISC_SOUT] = new wxPanel( panel, -1 );
+    wxFlexGridSizer *subpanel_sizer = new wxFlexGridSizer( 4, 4, 20 );
+
+    sap_checkbox = new wxCheckBox( misc_subpanels[ANN_MISC_SOUT],SAPMisc_Event,
+                                   wxU(_("SAP Announce")) );
+    slp_checkbox = new wxCheckBox( misc_subpanels[ANN_MISC_SOUT],SLPMisc_Event,
+                                   wxU(_("SLP Announce")) );
+
+    wxStaticText *label = new wxStaticText( misc_subpanels[ANN_MISC_SOUT], -1,
+                                            wxU(_("Channel Name")) );
+    announce_addr = new wxTextCtrl( misc_subpanels[ANN_MISC_SOUT],
+                                    AnnounceAddr_Event,
+                                    wxT(""), wxDefaultPosition,
+                                    wxSize( 200, -1 ), wxTE_PROCESS_ENTER);
+
+    subpanel_sizer->Add( sap_checkbox, 0,
+                         wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    subpanel_sizer->Add( slp_checkbox, 0,
+                         wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    subpanel_sizer->Add( label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    subpanel_sizer->Add( announce_addr, 1, wxEXPAND |
+                         wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL );
+
+    misc_subpanels[ANN_MISC_SOUT]->SetSizerAndFit( subpanel_sizer );
+
+    /* Stuff everything into the main panel */
+    panel_sizer->Add( misc_subpanels[ANN_MISC_SOUT], 1,
+                      wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
 
     panel->SetSizerAndFit( panel_sizer );
 
+    /* Update misc panel */
+    misc_subpanels[ANN_MISC_SOUT]->Disable();
+    announce_addr->Disable();
+
     return panel;
 }
 
@@ -337,118 +528,185 @@ wxPanel *SoutDialog::EncapsulationPanel( wxWindow* parent )
                                   wxSize(200, 200) );
 
     wxStaticBox *panel_box = new wxStaticBox( panel, -1,
-                                              _("Encapsulation Method") );
+                                              wxU(_("Encapsulation Method")) );
     wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
                                                           wxHORIZONTAL );
 
     static const wxString encapsulation_array[] =
     {
-        _("MPEG TS"),
-        _("MPEG PS"),
-        _("AVI"),
-        _("Ogg")
+        wxT("MPEG TS"),
+        wxT("MPEG PS"),
+        wxT("MPEG 1"),
+        wxT("Ogg"),
+        wxT("ASF"),
+        wxT("AVI"),
+        wxT("MP4"),
+        wxT("MOV")
     };
 
     /* Stuff everything into the main panel */
-    for( i=0; i<4; i++ )
+    for( i=0; i < ENCAPS_NUM; i++ )
     {
         encapsulation_radios[i] =
             new wxRadioButton( panel, EncapsulationRadio1_Event + i,
                                encapsulation_array[i] );
         panel_sizer->Add( encapsulation_radios[i], 0,
-                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5 );
+                          wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
+                          wxALL, 4 );
     }
 
     panel->SetSizerAndFit( panel_sizer );
 
     /* Update encapsulation panel */
-    encapsulation_radios[0]->Enable();
+    encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
     i_encapsulation_type = TS_ENCAPSULATION;
 
     return panel;
 }
 
-void SoutDialog::ParseMRL()
+wxPanel *SoutDialog::TranscodingPanel( wxWindow* parent )
 {
-    /* Initialise MRL value */
-    char *psz_sout = config_GetPsz( p_intf, "sout" );
-    if( psz_sout )
-    {
-        mrl = psz_sout;
-        free( psz_sout );
-    }
+    wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
+                                  wxSize(200, 200) );
 
-    /* Parse the MRL */
-    wxString access = mrl.BeforeFirst( '/' );
-    wxString encapsulation = mrl.BeforeFirst( ':' ).AfterFirst('/');
+    wxStaticBox *panel_box = new wxStaticBox( panel, -1,
+                                              wxU(_("Transcoding options")) );
+    wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
+                                                          wxVERTICAL );
 
-    if( !access.Cmp( "http" ) )
-    {
-        i_access_type = HTTP_ACCESS_OUT;
-    }
-    else if( !access.Cmp( "udp" ) )
-    {
-        i_access_type = UDP_ACCESS_OUT;
-    }
-    else if( !access.Cmp( "rtp" ) )
+    /* Create video transcoding checkox */
+    static const wxString vcodecs_array[] =
     {
-        i_access_type = RTP_ACCESS_OUT;
-    }
-    else
+        wxT("mp1v"),
+        wxT("mp2v"),
+        wxT("mp4v"),
+        wxT("DIV1"),
+        wxT("DIV2"),
+        wxT("DIV3"),
+        wxT("H263"),
+        wxT("I263"),
+        wxT("WMV1"),
+        wxT("WMV2"),
+        wxT("MJPG")
+    };
+    static const wxString vbitrates_array[] =
     {
-        i_access_type = FILE_ACCESS_OUT;
-    }
+        wxT("3000"),
+        wxT("2000"),
+        wxT("1000"),
+        wxT("750"),
+        wxT("500"),
+        wxT("400"),
+        wxT("200"),
+        wxT("150"),
+        wxT("100")
+    };
 
-    if( !encapsulation.Cmp( "ps" ) )
+    wxFlexGridSizer *video_sizer = new wxFlexGridSizer( 4, 1, 20 );
+    video_transc_checkbox =
+        new wxCheckBox( panel, VideoTranscEnable_Event, wxU(_("Video codec")));
+    video_codec_combo =
+        new wxComboBox( panel, VideoTranscCodec_Event, wxT(""),
+                        wxPoint(20,25), wxDefaultSize, WXSIZEOF(vcodecs_array),
+                        vcodecs_array, wxCB_READONLY );
+    video_codec_combo->SetSelection(2);
+    wxStaticText *bitrate_label =
+        new wxStaticText( panel, -1, wxU(_("Bitrate (kb/s)")));
+    video_bitrate_combo =
+        new wxComboBox( panel, VideoTranscBitrate_Event, wxT("1000"),
+                        wxPoint(20,25), wxDefaultSize,
+                        WXSIZEOF(vbitrates_array), vbitrates_array );
+    video_sizer->Add( video_transc_checkbox, 0,
+                      wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    video_sizer->Add( video_codec_combo, 1,
+                      wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    video_sizer->Add( bitrate_label, 0,
+                      wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    video_sizer->Add( video_bitrate_combo, 1,
+                      wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+
+    /* Create audio transcoding checkox */
+    static const wxString acodecs_array[] =
     {
-        i_encapsulation_type = PS_ENCAPSULATION;
-    }
-    else if( !encapsulation.Cmp( "avi" ) )
-    {
-        i_encapsulation_type = AVI_ENCAPSULATION;
-    }
-    else if( !encapsulation.Cmp( "ogg" ) )
+        wxT("mpga"),
+        wxT("mp3"),
+        wxT("a52"),
+        wxT("vorb")
+    };
+    static const wxString abitrates_array[] =
     {
-        i_encapsulation_type = OGG_ENCAPSULATION;
-    }
-    else
+        wxT("512"),
+        wxT("256"),
+        wxT("192"),
+        wxT("128"),
+        wxT("96")
+    };
+    static const wxString achannels_array[] =
     {
-        i_encapsulation_type = TS_ENCAPSULATION;
-    }
+        wxT("1"),
+        wxT("2"),
+        wxT("4"),
+        wxT("6")
+    };
 
-    wxString second_part = mrl.AfterFirst( ':' );
+    wxFlexGridSizer *audio_sizer = new wxFlexGridSizer( 3, 1, 20 );
+    audio_transc_checkbox =
+        new wxCheckBox( panel, AudioTranscEnable_Event, wxU(_("Audio codec")));
+    audio_codec_combo =
+        new wxComboBox( panel, AudioTranscCodec_Event, wxT(""),
+                        wxPoint(10,25), wxDefaultSize, WXSIZEOF(acodecs_array),
+                        acodecs_array, wxCB_READONLY );
+    audio_codec_combo->SetSelection(0);
+#if defined( __WXMSW__ )
+    wxFlexGridSizer *audio_sub_sizer = new wxFlexGridSizer( 4, 5, 20 );
+#else
+    wxFlexGridSizer *audio_sub_sizer = new wxFlexGridSizer( 2, 5, 20 );
+#endif
+    bitrate_label =
+        new wxStaticText( panel, -1, wxU(_("Bitrate (kb/s)")));
+    audio_bitrate_combo =
+        new wxComboBox( panel, AudioTranscBitrate_Event, wxT("192"),
+                        wxPoint(10,25), wxDefaultSize,
+                        WXSIZEOF(abitrates_array), abitrates_array );
+    wxStaticText *channels_label =
+        new wxStaticText( panel, -1, wxU(_("Channels")));
+    audio_channels_combo =
+        new wxComboBox( panel, AudioTranscChans_Event, wxT(""),
+                        wxPoint(10,25), wxDefaultSize,
+                        WXSIZEOF(achannels_array), achannels_array );
+    audio_channels_combo->SetSelection(1);
+    audio_sub_sizer->Add( bitrate_label, 0,
+                      wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    audio_sub_sizer->Add( audio_bitrate_combo, 1,
+                      wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    audio_sub_sizer->Add( channels_label, 0,
+                      wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    audio_sub_sizer->Add( audio_channels_combo, 1,
+                      wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+
+    audio_sizer->Add( audio_transc_checkbox, 0,
+                      wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    audio_sizer->Add( audio_codec_combo, 1,
+                      wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
+    audio_sizer->Add( audio_sub_sizer, 1,
+                      wxEXPAND | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL );
 
-    if( i_access_type == FILE_ACCESS_OUT )
-    {
-        /* The whole second part of the MRL is the filename */
-        file_combo->SetValue( second_part );
-    }
-    else
-    {
-        /* we've got address:port */
-        wxString address = second_part.BeforeLast( ':' );
-        net_addr->SetValue( address );
+    /* Stuff everything into the main panel */
+    panel_sizer->Add( video_sizer, 0,
+                      wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
+    panel_sizer->Add( audio_sizer, 0,
+                      wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
 
-        long int i_port;
-        wxString port = second_part.AfterLast( ':' );
-        if( port.ToLong( &i_port ) )
-        {
-            net_port->SetValue( i_port );
-        }
-        else
-        {
-            net_port->SetValue( config_GetInt( p_intf, "server-port" ) );
-        }
-    }
+    panel->SetSizerAndFit( panel_sizer );
 
-    /* Update access output panel */
-    wxCommandEvent dummy_event;
-    dummy_event.SetId( AccessRadio1_Event + i_access_type );
-    OnAccessTypeChange( dummy_event );
+    /* Update transcoding panel */
+    wxCommandEvent event( 0, VideoTranscEnable_Event );
+    event.SetInt( 0 );
+    OnTranscodingEnable( event );
+    event.SetId( AudioTranscEnable_Event );
+    OnTranscodingEnable( event );
 
-    /* Update encapsulation output panel */
-    dummy_event.SetId( EncapsulationRadio1_Event + i_encapsulation_type );
-    OnEncapsulationChange( dummy_event );
+    return panel;
 }
 
 /*****************************************************************************
@@ -456,6 +714,7 @@ void SoutDialog::ParseMRL()
  *****************************************************************************/
 void SoutDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
 {
+    mrl_combo->Append( mrl_combo->GetValue() );
     EndModal( wxID_OK );
 }
 
@@ -466,7 +725,7 @@ void SoutDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
 
 void SoutDialog::OnMRLChange( wxCommandEvent& event )
 {
-    mrl = event.GetString();
+    //mrl = event.GetString();
 }
 
 /*****************************************************************************
@@ -475,49 +734,56 @@ void SoutDialog::OnMRLChange( wxCommandEvent& event )
 void SoutDialog::OnAccessTypeChange( wxCommandEvent& event )
 {
     int i;
-    i_access_type = event.GetId() - AccessRadio1_Event;
+    i_access_type = event.GetId() - AccessType1_Event;
+
+    access_subpanels[i_access_type]->Enable( event.GetInt() );
 
     switch( i_access_type )
     {
-    case FILE_ACCESS_OUT:
-        access_subpanels[0]->Enable();
-        access_subpanels[2]->Disable();
-        access_subpanels[3]->Disable();
-        for( i = 1; i < 4; i++ )
-        {
-            encapsulation_radios[i]->Enable();
-        }
-        break;
+    case UDP_ACCESS_OUT:
+        misc_subpanels[ANN_MISC_SOUT]->Enable( event.GetInt() );
 
-    case HTTP_ACCESS_OUT:
-        access_subpanels[0]->Disable();
-        access_subpanels[2]->Enable();
-        access_subpanels[3]->Disable();
-        for( i = 1; i < 4; i++ )
+    case RTP_ACCESS_OUT:
+        for( i = 1; i < ENCAPS_NUM; i++ )
         {
-            encapsulation_radios[i]->Enable();
+            encapsulation_radios[i]->Enable( !event.GetInt() );
         }
-        break;
-
-    case UDP_ACCESS_OUT:
-    case RTP_ACCESS_OUT:
-        access_subpanels[0]->Disable();
-        access_subpanels[2]->Enable();
-        access_subpanels[3]->Enable();
-        for( i = 1; i < 4; i++ )
+        if( event.GetInt() )
         {
-            encapsulation_radios[i]->Disable();
+            encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
+            i_encapsulation_type = TS_ENCAPSULATION;
         }
-        encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
-        i_encapsulation_type = TS_ENCAPSULATION;
         break;
     }
+    UpdateMRL();
+}
+
+/*****************************************************************************
+ * AnnounceMisc panel event methods.
+ *****************************************************************************/
+void SoutDialog::OnSAPMiscChange( wxCommandEvent& event )
+{
+    if( !slp_checkbox->IsChecked() )
+    {
+        announce_addr->Enable( event.GetInt() );
+    }
+    UpdateMRL();
+}
 
-    for( i = 0; i < 4; i++ )
+void SoutDialog::OnSLPMiscChange( wxCommandEvent& event )
+{
+    if( !sap_checkbox->IsChecked() )
     {
-        access_radios[i]->SetValue( event.GetId() == (AccessRadio1_Event+i) );
+        announce_addr->Enable( event.GetInt() );
     }
+    UpdateMRL();
+}
 
+/*****************************************************************************
+ * SAPAddr panel event methods.
+ *****************************************************************************/
+void SoutDialog::OnAnnounceAddrChange( wxCommandEvent& WXUNUSED(event) )
+{
     UpdateMRL();
 }
 
@@ -531,7 +797,8 @@ void SoutDialog::OnFileChange( wxCommandEvent& WXUNUSED(event) )
 
 void SoutDialog::OnFileBrowse( wxCommandEvent& WXUNUSED(event) )
 {
-    wxFileDialog dialog( this, _("Save file"), "", "", "*.*", wxSAVE );
+    wxFileDialog dialog( this, wxU(_("Save file")), wxT(""), wxT(""), wxT("*"),
+                         wxSAVE | wxOVERWRITE_PROMPT );
 
     if( dialog.ShowModal() == wxID_OK )
     {
@@ -556,3 +823,29 @@ void SoutDialog::OnEncapsulationChange( wxCommandEvent& event )
     i_encapsulation_type = event.GetId() - EncapsulationRadio1_Event;
     UpdateMRL();
 }
+
+/*****************************************************************************
+ * Transcoding panel event methods.
+ *****************************************************************************/
+void SoutDialog::OnTranscodingEnable( wxCommandEvent& event )
+{
+    switch( event.GetId() )
+    {
+    case VideoTranscEnable_Event:
+        video_codec_combo->Enable( event.GetInt() );
+        video_bitrate_combo->Enable( event.GetInt() );
+        break;
+    case AudioTranscEnable_Event:
+        audio_codec_combo->Enable( event.GetInt() );
+        audio_bitrate_combo->Enable( event.GetInt() );
+        audio_channels_combo->Enable( event.GetInt() );
+        break;
+    }
+
+    UpdateMRL();
+}
+
+void SoutDialog::OnTranscodingChange( wxCommandEvent& event )
+{
+    UpdateMRL();
+}