1 /*****************************************************************************
2 * streamout.cpp : wxWindows plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2001 VideoLAN
5 * $Id: streamout.cpp,v 1.15 2003/05/22 22:24:34 gbazin Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <errno.h> /* ENOMEM */
29 #include <string.h> /* strerror() */
34 #ifdef WIN32 /* mingw32 hack */
39 /* Let vlc take care of the i18n stuff */
40 #define WXINTL_NO_GETTEXT_MACRO
42 #include <wx/wxprec.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>
52 #if defined MODULE_NAME_IS_skins
53 # include "../skins/src/skin_common.h"
56 #include "wxwindows.h"
59 # define wxRB_SINGLE 0
82 /*****************************************************************************
84 *****************************************************************************/
86 /* IDs for the controls and the menu commands */
89 Notebook_Event = wxID_HIGHEST,
95 AccessType1_Event, AccessType2_Event, AccessType3_Event,
96 AccessType4_Event, AccessType5_Event,
100 EncapsulationRadio1_Event, EncapsulationRadio2_Event,
101 EncapsulationRadio3_Event, EncapsulationRadio4_Event,
102 EncapsulationRadio5_Event,
104 VideoTranscEnable_Event, VideoTranscCodec_Event, VideoTranscBitrate_Event,
105 AudioTranscEnable_Event, AudioTranscCodec_Event, AudioTranscBitrate_Event,
108 BEGIN_EVENT_TABLE(SoutDialog, wxDialog)
110 EVT_BUTTON(wxID_OK, SoutDialog::OnOk)
111 EVT_BUTTON(wxID_CANCEL, SoutDialog::OnCancel)
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)
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)
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)
147 /*****************************************************************************
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 )
154 /* Initializations */
156 p_parent = _p_parent;
157 SetIcon( *p_intf->p_sys->p_icon );
159 /* Create a panel to put everything in */
160 wxPanel *panel = new wxPanel( this, -1 );
161 panel->SetAutoLayout( TRUE );
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,
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")) );
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 );
181 /* Create the output encapsulation panel */
182 wxPanel *encapsulation_panel = EncapsulationPanel( panel );
184 /* Create the access output panel */
185 wxPanel *access_panel = AccessPanel( panel );
187 /* Create the transcoding panel */
188 wxPanel *transcoding_panel = TranscodingPanel( panel );
191 wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
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,
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 |
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 );
220 SoutDialog::~SoutDialog()
224 /*****************************************************************************
226 *****************************************************************************/
227 void SoutDialog::UpdateMRL()
229 /* Let's start with the transcode options */
231 if( video_transc_checkbox->IsChecked() ||
232 audio_transc_checkbox->IsChecked() )
234 transcode = wxT("transcode{");
235 if( video_transc_checkbox->IsChecked() )
237 transcode += wxT("vcodec=") + video_codec_combo->GetValue();
238 transcode += wxT(",vb=") + video_bitrate_combo->GetValue();
239 if( audio_transc_checkbox->IsChecked() ) transcode += wxT(",");
241 if( audio_transc_checkbox->IsChecked() )
243 transcode += wxT("acodec=") + audio_codec_combo->GetValue();
244 transcode += wxT(",ab=") + audio_bitrate_combo->GetValue();
246 transcode += wxT("}");
250 wxString encapsulation;
251 switch( i_encapsulation_type )
253 case PS_ENCAPSULATION:
254 encapsulation = wxT("ps");
256 case AVI_ENCAPSULATION:
257 encapsulation = wxT("avi");
259 case OGG_ENCAPSULATION:
260 encapsulation = wxT("ogg");
262 case MP4_ENCAPSULATION:
263 encapsulation = wxT("mp4");
265 case TS_ENCAPSULATION:
267 encapsulation = wxT("ts");
271 /* Now continue with the duplicate option */
273 if( access_checkboxes[PLAY_ACCESS_OUT]->IsChecked() )
275 dup_opts += wxT("dst=display");
277 if( access_checkboxes[FILE_ACCESS_OUT]->IsChecked() )
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("}");
284 if( access_checkboxes[HTTP_ACCESS_OUT]->IsChecked() )
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("}");
293 if( access_checkboxes[UDP_ACCESS_OUT]->IsChecked() )
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("}");
302 if( access_checkboxes[RTP_ACCESS_OUT]->IsChecked() )
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("}");
313 if( !dup_opts.IsEmpty() )
315 if( !transcode.IsEmpty() ) duplicate = wxT(":");
316 duplicate += wxT("duplicate{") + dup_opts + wxT("}");
319 if( !transcode.IsEmpty() || !duplicate.IsEmpty() )
320 mrl_combo->SetValue( wxT("#") + transcode + duplicate );
322 mrl_combo->SetValue( wxT("") );
325 wxPanel *SoutDialog::AccessPanel( wxWindow* parent )
328 wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
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,
337 static const wxString access_output_array[] =
339 wxU(_("Play locally")),
346 for( i=0; i < ACCESS_OUT_NUM; i++ )
348 access_checkboxes[i] = new wxCheckBox( panel, AccessType1_Event + i,
349 access_output_array[i] );
350 access_subpanels[i] = new wxPanel( panel, -1 );
353 /* Play locally row */
354 wxFlexGridSizer *subpanel_sizer;
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 );
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 );
374 access_subpanels[1]->SetSizerAndFit( subpanel_sizer );
377 for( i=2; i < ACCESS_OUT_NUM; i++ )
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 ),
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 );
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,
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 );
402 access_subpanels[i]->SetSizerAndFit( subpanel_sizer );
406 /* Stuff everything into the main panel */
407 for( i=1; i < ACCESS_OUT_NUM; i++ )
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 );
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 );
419 panel->SetSizerAndFit( panel_sizer );
421 /* Update access type panel */
422 for( i=1; i < ACCESS_OUT_NUM; i++ )
424 access_subpanels[i]->Disable();
430 wxPanel *SoutDialog::EncapsulationPanel( wxWindow* parent )
433 wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
436 wxStaticBox *panel_box = new wxStaticBox( panel, -1,
437 wxU(_("Encapsulation Method")) );
438 wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
441 static const wxString encapsulation_array[] =
450 /* Stuff everything into the main panel */
451 for( i=0; i < ENCAPS_NUM; i++ )
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 );
460 panel->SetSizerAndFit( panel_sizer );
462 /* Update encapsulation panel */
463 encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
464 i_encapsulation_type = TS_ENCAPSULATION;
469 wxPanel *SoutDialog::TranscodingPanel( wxWindow* parent )
471 wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
474 wxStaticBox *panel_box = new wxStaticBox( panel, -1,
475 wxU(_("Transcoding options")) );
476 wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
479 /* Create video transcoding checkox */
480 static const wxString vcodecs_array[] =
491 static const wxString vbitrates_array[] =
504 wxFlexGridSizer *video_sizer = new wxFlexGridSizer( 4, 1, 20 );
505 video_transc_checkbox =
506 new wxCheckBox( panel, VideoTranscEnable_Event, wxU(_("Video codec")));
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 );
526 /* Create audio transcoding checkox */
527 static const wxString acodecs_array[] =
532 static const wxString abitrates_array[] =
541 wxFlexGridSizer *audio_sizer = new wxFlexGridSizer( 4, 1, 20 );
542 audio_transc_checkbox =
543 new wxCheckBox( panel, AudioTranscEnable_Event, wxU(_("Audio codec")));
545 new wxComboBox( panel, AudioTranscCodec_Event, wxT("mpga"),
546 wxPoint(20,25), wxDefaultSize, WXSIZEOF(acodecs_array),
547 acodecs_array, wxCB_READONLY );
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 );
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 );
569 panel->SetSizerAndFit( panel_sizer );
571 /* Update transcoding panel */
572 wxCommandEvent event( 0, VideoTranscEnable_Event );
574 OnTranscodingEnable( event );
575 event.SetId( AudioTranscEnable_Event );
576 OnTranscodingEnable( event );
581 /*****************************************************************************
583 *****************************************************************************/
584 void SoutDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
586 mrl_combo->Append( mrl_combo->GetValue() );
587 mrl = mrl_combo->GetValue();
591 void SoutDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
593 EndModal( wxID_CANCEL );
596 void SoutDialog::OnMRLChange( wxCommandEvent& event )
598 //mrl = event.GetString();
601 /*****************************************************************************
602 * Access output panel event methods.
603 *****************************************************************************/
604 void SoutDialog::OnAccessTypeChange( wxCommandEvent& event )
607 i_access_type = event.GetId() - AccessType1_Event;
609 access_subpanels[i_access_type]->Enable( event.GetInt() );
611 switch( i_access_type )
615 for( i = 1; i < ENCAPS_NUM; i++ )
617 encapsulation_radios[i]->Enable( !event.GetInt() );
621 encapsulation_radios[TS_ENCAPSULATION]->SetValue(true);
622 i_encapsulation_type = TS_ENCAPSULATION;
630 /*****************************************************************************
631 * File access output event methods.
632 *****************************************************************************/
633 void SoutDialog::OnFileChange( wxCommandEvent& WXUNUSED(event) )
638 void SoutDialog::OnFileBrowse( wxCommandEvent& WXUNUSED(event) )
640 wxFileDialog dialog( this, wxU(_("Save file")),
641 wxT(""), wxT(""), wxT("*"), wxSAVE );
643 if( dialog.ShowModal() == wxID_OK )
645 file_combo->SetValue( dialog.GetPath() );
650 /*****************************************************************************
651 * Net access output event methods.
652 *****************************************************************************/
653 void SoutDialog::OnNetChange( wxCommandEvent& WXUNUSED(event) )
658 /*****************************************************************************
659 * Encapsulation panel event methods.
660 *****************************************************************************/
661 void SoutDialog::OnEncapsulationChange( wxCommandEvent& event )
663 i_encapsulation_type = event.GetId() - EncapsulationRadio1_Event;
667 /*****************************************************************************
668 * Transcoding panel event methods.
669 *****************************************************************************/
670 void SoutDialog::OnTranscodingEnable( wxCommandEvent& event )
672 switch( event.GetId() )
674 case VideoTranscEnable_Event:
675 video_codec_combo->Enable( event.GetInt() );
676 video_bitrate_combo->Enable( event.GetInt() );
678 case AudioTranscEnable_Event:
679 audio_codec_combo->Enable( event.GetInt() );
680 audio_bitrate_combo->Enable( event.GetInt() );
687 void SoutDialog::OnTranscodingChange( wxCommandEvent& event )