]> git.sesse.net Git - vlc/blob - modules/gui/macosx/output.m
0aa917ef1e988023dc7463914a67ac636899e50b
[vlc] / modules / gui / macosx / output.m
1 /*****************************************************************************
2  * output.m: MacOS X Output Dialog
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net> 
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <thedj@users.sourceforge.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <string.h>
31
32 #include "intf.h"
33 #include "output.h"
34
35 /*****************************************************************************
36  * VLCOutput implementation 
37  *****************************************************************************/
38 @implementation VLCOutput
39
40 - (id)init
41 {
42     self = [super init];
43     o_mrl = [[NSString alloc] init];
44     o_transcode = [[NSString alloc] init];
45     return self;
46 }
47
48 - (void)dealloc
49 {
50     [o_mrl release];
51     [o_transcode release];
52     [super dealloc];
53 }
54
55 - (void)setMRL:(NSString *)o_mrl_string
56 {
57     [o_mrl autorelease];
58     o_mrl = [o_mrl_string copy];
59 }
60
61 - (NSString *)getMRL
62 {
63     return [o_mrl copy];
64 }
65
66 - (void)setTranscode:(NSString *)o_transcode_string
67 {
68     [o_transcode autorelease];
69     o_transcode = [o_transcode_string copy];
70 }
71
72 - (void)awakeFromNib
73 {
74     [self initStrings];
75     
76     [[NSNotificationCenter defaultCenter] addObserver: self
77         selector: @selector(outputInfoChanged:)
78         name: NSControlTextDidChangeNotification
79         object: o_file_field];
80     [[NSNotificationCenter defaultCenter] addObserver: self
81         selector: @selector(outputInfoChanged:)
82         name: NSControlTextDidChangeNotification
83         object: o_stream_address];
84     [[NSNotificationCenter defaultCenter] addObserver: self
85         selector: @selector(outputInfoChanged:)
86         name: NSControlTextDidChangeNotification
87         object: o_stream_port];
88     [[NSNotificationCenter defaultCenter] addObserver: self
89         selector: @selector(TTLChanged:)
90         name: NSControlTextDidChangeNotification
91         object: o_stream_ttl];
92     [[NSNotificationCenter defaultCenter] addObserver: self
93         selector: @selector(transcodeInfoChanged:)
94         name: NSControlTextDidChangeNotification
95         object: o_transcode_video_bitrate];
96     [[NSNotificationCenter defaultCenter] addObserver: self
97         selector: @selector(transcodeInfoChanged:)
98         name: NSControlTextDidChangeNotification
99         object: o_transcode_audio_bitrate];
100     [[NSNotificationCenter defaultCenter] addObserver: self
101         selector: @selector(transcodeInfoChanged:)
102         name: NSControlTextDidChangeNotification
103         object: o_transcode_audio_channels];
104     [[NSNotificationCenter defaultCenter] addObserver: self
105         selector: @selector(transcodeInfoChanged:)
106         name: NSControlTextDidChangeNotification
107         object: o_channel_name];
108
109     [o_mux_selector setAutoenablesItems: NO];
110     [self transcodeChanged:nil];
111 }
112
113 - (void)initStrings
114 {
115     NSArray *o_muxers = [NSArray arrayWithObjects: @"MPEG TS", @"MPEG PS", @"MPEG 1",
116         @"Ogg", @"AVI", @"ASF", @"MPEG 4", @"Quicktime", @"Raw", nil];
117     NSArray *o_a_channels = [NSArray arrayWithObjects: @"1", @"2", @"4", @"6", nil];
118     NSArray *o_a_bitrates = [NSArray arrayWithObjects: @"16", @"32", @"64", @"96",
119         @"128", @"192", @"256", @"512", nil];
120     NSArray *o_v_bitrates = [NSArray arrayWithObjects: @"16", @"32", @"64", @"96",
121         @"128", @"192", @"256", @"384", @"512", @"768", @"1024", @"2048", @"3072", nil];
122     NSArray *o_a_codecs = [NSArray arrayWithObjects: @"mpga", @"mp3 ", @"mp4a", @"a52 ", @"vorb", @"flac", @"spx ", nil];
123     NSArray *o_v_codecs = [NSArray arrayWithObjects: @"mp1v", @"mp2v", @"mp4v", @"DIV1",
124         @"DIV2", @"DIV3", @"H263", @"I263", @"WMV1", @"WMV2", @"MJPG", @"theo", nil];
125     
126     [o_output_ckbox setTitle: _NS("Advanced output:")];
127     [o_output_settings setTitle: _NS("Settings...")];
128     [o_btn_ok setTitle: _NS("OK")];
129     
130     [o_options_lbl setTitle: _NS("Output Options")];
131     [o_display setTitle: _NS("Play locally")];
132     [[o_method cellAtRow:0 column:0] setTitle: _NS("File")];
133     [[o_method cellAtRow:1 column:0] setTitle: _NS("Stream")];
134     [o_dump_chkbox setTitle: _NS("Dump raw input")];
135     [o_btn_browse setTitle: _NS("Browse...")]; 
136     [o_stream_address_lbl setStringValue: _NS("Address")];
137     [o_stream_port_lbl setStringValue: _NS("Port")];
138     [o_stream_ttl_lbl setStringValue: @"TTL"];
139     [[o_stream_type itemAtIndex: 0] setTitle: @"HTTP"];
140     [[o_stream_type itemAtIndex: 1] setTitle: @"MMSH"];
141     [[o_stream_type itemAtIndex: 2] setTitle: @"UDP"];
142     [[o_stream_type itemAtIndex: 3] setTitle: @"RTP"];
143     [o_stream_type_lbl setStringValue: _NS("Type")];
144     
145     [o_mux_lbl setStringValue: _NS("Encapsulation Method")];
146     [o_mux_selector removeAllItems];
147     [o_mux_selector addItemsWithTitles: o_muxers];
148     
149     [o_transcode_lbl setTitle: _NS("Transcode options")];
150     [o_transcode_video_chkbox setTitle: _NS("Video")];
151     [o_transcode_video_selector removeAllItems];
152     [o_transcode_video_selector addItemsWithTitles: o_v_codecs];
153     [o_transcode_video_bitrate_lbl setStringValue: _NS("Bitrate (kb/s)")];
154     [o_transcode_video_bitrate removeAllItems];
155     [o_transcode_video_bitrate addItemsWithObjectValues: o_v_bitrates];
156     [o_transcode_audio_chkbox setTitle: _NS("Audio")];
157     [o_transcode_audio_selector removeAllItems];
158     [o_transcode_audio_selector addItemsWithTitles: o_a_codecs];
159     [o_transcode_audio_bitrate_lbl setStringValue: _NS("Bitrate (kb/s)")];
160     [o_transcode_audio_bitrate removeAllItems];
161     [o_transcode_audio_bitrate addItemsWithObjectValues: o_a_bitrates];
162     [o_transcode_audio_channels_lbl setStringValue: _NS("Channels")];
163     [o_transcode_audio_channels removeAllItems];
164     [o_transcode_audio_channels addItemsWithObjectValues: o_a_channels];
165     
166     [o_misc_lbl setTitle: _NS("Stream Announcing")];
167     [o_sap_chkbox setTitle: _NS("SAP announce")];
168     [o_slp_chkbox setTitle: _NS("SLP announce")];
169     [o_channel_name_lbl setStringValue: _NS("Channel Name")];
170 }
171
172 - (IBAction)outputChanged:(id)sender;
173 {
174     if ([o_output_ckbox state] == NSOnState)
175     {
176         [o_output_settings setEnabled:YES];
177     }
178     else
179     {
180         [o_output_settings setEnabled:NO];
181     }
182 }
183
184 - (IBAction)outputSettings:(id)sender
185 {
186     [NSApp beginSheet: o_output_sheet
187         modalForWindow: o_open_panel
188         modalDelegate: self
189         didEndSelector: NULL
190         contextInfo: nil];
191 }
192
193 - (IBAction)outputCloseSheet:(id)sender
194 {
195     [o_output_sheet orderOut:sender];
196     [NSApp endSheet: o_output_sheet];
197 }
198
199 - (void)outputMethodChanged:(NSNotification *)o_notification
200 {
201     NSString *o_mode;
202     o_mode = [[o_method selectedCell] title];
203     
204     [o_sap_chkbox setEnabled: NO];
205     [o_slp_chkbox setEnabled: NO];
206     [o_channel_name setEnabled: NO];
207     [[o_mux_selector itemAtIndex: 0] setEnabled: YES];
208
209     if( [o_mode isEqualToString: _NS("File")] )
210     {
211         [o_file_field setEnabled: YES];
212         [o_btn_browse setEnabled: YES];
213         [o_dump_chkbox setEnabled: YES];
214         [o_stream_address setEnabled: NO];
215         [o_stream_port setEnabled: NO];
216         [o_stream_ttl setEnabled: NO];
217         [o_stream_port_stp setEnabled: NO];
218         [o_stream_ttl_stp setEnabled: NO];
219         [o_stream_type setEnabled: NO];
220         [o_mux_selector setEnabled: YES];
221         [[o_mux_selector itemAtIndex: 1] setEnabled: YES]; // MPEG PS
222         [[o_mux_selector itemAtIndex: 2] setEnabled: YES]; // MPEG 1
223         [[o_mux_selector itemAtIndex: 3] setEnabled: YES]; // Ogg
224         [[o_mux_selector itemAtIndex: 4] setEnabled: YES]; // AVI
225         [[o_mux_selector itemAtIndex: 5] setEnabled: YES]; // ASF
226         [[o_mux_selector itemAtIndex: 6] setEnabled: YES]; // MPEG 4
227         [[o_mux_selector itemAtIndex: 7] setEnabled: YES]; // QuickTime
228         [[o_mux_selector itemAtIndex: 8] setEnabled: YES]; // Raw
229     }
230     else if( [o_mode isEqualToString: _NS("Stream")] )
231     {
232         [o_file_field setEnabled: NO];
233         [o_dump_chkbox setEnabled: NO];
234         [o_btn_browse setEnabled: NO];
235         [o_stream_port setEnabled: YES];
236         [o_stream_port_stp setEnabled: YES];
237         [o_stream_type setEnabled: YES];
238         [o_mux_selector setEnabled: YES];
239         
240         o_mode = [o_stream_type titleOfSelectedItem];
241         
242         if( [o_mode isEqualToString: @"HTTP"] )
243         {
244             [o_stream_address setEnabled: YES];
245             [o_stream_ttl setEnabled: NO];
246             [o_stream_ttl_stp setEnabled: NO];
247             [[o_mux_selector itemAtIndex: 1] setEnabled: YES];
248             [[o_mux_selector itemAtIndex: 2] setEnabled: YES];
249             [[o_mux_selector itemAtIndex: 3] setEnabled: YES];
250             [[o_mux_selector itemAtIndex: 4] setEnabled: NO];
251             [[o_mux_selector itemAtIndex: 5] setEnabled: YES];
252             [[o_mux_selector itemAtIndex: 6] setEnabled: NO];
253             [[o_mux_selector itemAtIndex: 7] setEnabled: NO];
254             [[o_mux_selector itemAtIndex: 8] setEnabled: YES];
255         }
256         else if( [o_mode isEqualToString: @"MMSH"] )
257         {
258             [o_stream_address setEnabled: YES];
259             [o_stream_ttl setEnabled: NO];
260             [o_stream_ttl_stp setEnabled: NO];
261             [[o_mux_selector itemAtIndex: 0] setEnabled: NO];
262             [[o_mux_selector itemAtIndex: 1] setEnabled: NO];
263             [[o_mux_selector itemAtIndex: 2] setEnabled: NO];
264             [[o_mux_selector itemAtIndex: 3] setEnabled: NO];
265             [[o_mux_selector itemAtIndex: 4] setEnabled: NO];
266             [[o_mux_selector itemAtIndex: 5] setEnabled: YES];
267             [[o_mux_selector itemAtIndex: 6] setEnabled: NO];
268             [[o_mux_selector itemAtIndex: 7] setEnabled: NO];
269             [[o_mux_selector itemAtIndex: 8] setEnabled: NO];
270         }
271         else if( [o_mode isEqualToString: @"UDP"] )
272         {
273             [o_stream_address setEnabled: YES];
274             [o_stream_ttl setEnabled: YES];
275             [o_stream_ttl_stp setEnabled: YES];
276             [[o_mux_selector itemAtIndex: 1] setEnabled: NO];
277             [[o_mux_selector itemAtIndex: 2] setEnabled: NO];
278             [[o_mux_selector itemAtIndex: 3] setEnabled: NO];
279             [[o_mux_selector itemAtIndex: 4] setEnabled: NO];
280             [[o_mux_selector itemAtIndex: 5] setEnabled: NO];
281             [[o_mux_selector itemAtIndex: 6] setEnabled: NO];
282             [[o_mux_selector itemAtIndex: 7] setEnabled: NO];
283             [[o_mux_selector itemAtIndex: 8] setEnabled: YES];
284             [o_sap_chkbox setEnabled: YES];
285             [o_slp_chkbox setEnabled: YES];
286             [o_channel_name setEnabled: YES];
287         }
288         else if( [o_mode isEqualToString: @"RTP"] )
289         {
290             [o_stream_address setEnabled: YES];
291             [o_stream_ttl setEnabled: YES];
292             [o_stream_ttl_stp setEnabled: YES];
293             [[o_mux_selector itemAtIndex: 1] setEnabled: NO];
294             [[o_mux_selector itemAtIndex: 2] setEnabled: NO];
295             [[o_mux_selector itemAtIndex: 3] setEnabled: NO];
296             [[o_mux_selector itemAtIndex: 4] setEnabled: NO];
297             [[o_mux_selector itemAtIndex: 5] setEnabled: NO];
298             [[o_mux_selector itemAtIndex: 6] setEnabled: NO];
299             [[o_mux_selector itemAtIndex: 7] setEnabled: NO];
300             [[o_mux_selector itemAtIndex: 8] setEnabled: YES];
301         }
302     }
303     if( ![[o_mux_selector selectedItem] isEnabled] )
304     {
305         [o_mux_selector selectItemAtIndex: 0];
306     }
307     [self outputInfoChanged: nil];
308 }
309
310 - (void)outputInfoChanged:(NSNotification *)o_notification
311 {
312     NSString *o_mode, *o_mux, *o_mux_string, *o_announce;
313     NSMutableString *o_mrl_string = [NSMutableString stringWithString:@":sout=#"];
314
315     [o_mrl_string appendString: o_transcode];
316     if( [o_display state] == NSOnState )
317     {
318         [o_mrl_string appendString: @"duplicate{dst=display,dst="];
319     }
320
321     o_mode = [[o_method selectedCell] title];
322     o_mux = [o_mux_selector titleOfSelectedItem];
323
324     if ( [o_mux isEqualToString: @"AVI"] ) o_mux_string = @"avi";
325     else if ( [o_mux isEqualToString: @"Ogg"] ) o_mux_string = @"ogg";
326     else if ( [o_mux isEqualToString: @"MPEG PS"] ) o_mux_string = @"ps";
327     else if ( [o_mux isEqualToString: @"MPEG 4"] ) o_mux_string = @"mp4";
328     else if ( [o_mux isEqualToString: @"MPEG 1"] ) o_mux_string = @"mpeg1";
329     else if ( [o_mux isEqualToString: @"Quicktime"] ) o_mux_string = @"mov";
330     else if ( [o_mux isEqualToString: @"ASF"] ) o_mux_string = @"asf";
331     else if ( [o_mux isEqualToString: @"Raw"] ) o_mux_string = @"raw";
332     else o_mux_string = @"ts";
333
334     if( [o_mode isEqualToString: _NS("File")] )
335     {
336         if( [o_dump_chkbox state] == NSOnState )
337         {
338             o_mrl_string = [NSMutableString stringWithFormat:
339                             @":demux=demuxdump :demuxdump-file=\"%@\"",
340                             [o_file_field stringValue]];
341             [self setMRL:o_mrl_string];
342             return;
343         }
344         else
345         {
346                 [o_mrl_string appendFormat:
347                         @"std{access=file,mux=%@,url=\"%@\"}",
348                         o_mux_string, [o_file_field stringValue]];
349         }
350     }
351     else if( [o_mode isEqualToString: _NS("Stream")] )
352     {
353         o_mode = [o_stream_type titleOfSelectedItem];
354         o_announce = @"";
355         
356         if ( [o_mode isEqualToString: @"HTTP"] )
357             o_mode = @"http";
358         else if ( [o_mode isEqualToString: @"MMSH"] )
359         {
360             if ( [o_mux isEqualToString: @"ASF"] ) o_mux_string = @"asfh";
361             o_mode = @"mmsh";
362         }
363         else if ( [o_mode isEqualToString: @"UDP"] )
364         {
365             o_mode = @"udp";
366             if( [o_sap_chkbox state] == NSOnState )
367             {
368                 if ( ![[o_channel_name stringValue] isEqualToString: @""] )
369                     o_announce = [NSString stringWithFormat:@",sap,name=%@", 
370                         [o_channel_name stringValue]];
371                 else
372                     o_announce = @",sap";
373             }
374             if( [o_slp_chkbox state] == NSOnState )
375             {
376                if ( ![[o_channel_name stringValue] isEqualToString: @""] )
377                     o_announce = [o_announce stringByAppendingFormat:@
378                             "slp,name=%@",[o_channel_name stringValue]];
379                 else
380                     o_announce = [o_announce stringByAppendingString: @",slp"];
381             }
382         }
383         else if ( [o_mode isEqualToString: @"RTP"] )
384             o_mode = @"rtp";
385             
386         [o_mrl_string appendFormat:
387                         @"std{access=%@,mux=%@,url=\"%@:%@\"%@}",
388                         o_mode, o_mux_string, [o_stream_address stringValue],
389                         [o_stream_port stringValue], o_announce];
390     }
391     if( [o_display state] == NSOnState )
392     {
393         [o_mrl_string appendString: @"}"];
394     }
395     [self setMRL:o_mrl_string];
396 }
397
398 - (void)TTLChanged:(NSNotification *)o_notification
399 {
400     intf_thread_t * p_intf = [NSApp getIntf];
401     config_PutInt( p_intf, "ttl", [o_stream_ttl intValue] );
402 }
403
404 - (IBAction)outputFileBrowse:(id)sender
405 {
406     NSSavePanel *o_save_panel = [NSSavePanel savePanel];
407     NSString *o_mux_string;
408     if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"MPEG PS"] )
409         o_mux_string = @"vob";
410     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"MPEG 1"] )
411         o_mux_string = @"mpg";
412     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"AVI"] )
413         o_mux_string = @"avi";
414     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"ASF"] )
415         o_mux_string = @"asf";
416     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"Ogg"] )
417         o_mux_string = @"ogm";
418     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"MPEG 4"] )
419         o_mux_string = @"mp4";
420     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"Quicktime"] )
421         o_mux_string = @"mov";
422     else if ( [[o_mux_selector titleOfSelectedItem] isEqualToString: @"Raw"] )
423         o_mux_string = @"raw";
424     else
425         o_mux_string = @"ts";
426
427     NSString * o_name = [NSString stringWithFormat: @"vlc-output.%@",
428                          o_mux_string];
429
430     [o_save_panel setTitle: _NS("Save File")];
431     [o_save_panel setPrompt: _NS("Save")];
432
433     if( [o_save_panel runModalForDirectory: nil
434             file: o_name] == NSOKButton )
435     {
436         NSString *o_filename = [o_save_panel filename];
437         [o_file_field setStringValue: o_filename];
438         [self outputInfoChanged: nil];
439     }
440 }
441
442 - (IBAction)streamPortStepperChanged:(id)sender
443 {
444     [o_stream_port setIntValue: [o_stream_port_stp intValue]];
445     [self outputInfoChanged: nil];
446 }
447
448 - (IBAction)streamTTLStepperChanged:(id)sender
449 {
450     [o_stream_ttl setIntValue: [o_stream_ttl_stp intValue]];
451     [self TTLChanged:nil];
452 }
453
454 - (void)transcodeChanged:(NSNotification *)o_notification
455 {
456     if( [o_transcode_video_chkbox state] == NSOnState )
457     {
458         [o_transcode_video_selector setEnabled: YES];
459         [o_transcode_video_bitrate setEnabled: YES];
460     }
461     else
462     {
463         [o_transcode_video_selector setEnabled: NO];
464         [o_transcode_video_bitrate setEnabled: NO];
465     }
466     if( [o_transcode_audio_chkbox state] == NSOnState )
467     {
468         [o_transcode_audio_selector setEnabled: YES];
469         [o_transcode_audio_bitrate setEnabled: YES];
470         [o_transcode_audio_channels setEnabled: YES];
471     }
472     else
473     {
474         [o_transcode_audio_selector setEnabled: NO];
475         [o_transcode_audio_bitrate setEnabled: NO];
476         [o_transcode_audio_channels setEnabled: NO];
477     }
478
479     [self transcodeInfoChanged:nil];
480 }
481
482 - (void)transcodeInfoChanged:(NSNotification *)o_notification
483 {
484     NSMutableString *o_transcode_string;
485     
486     if( [o_transcode_video_chkbox state] == NSOnState ||
487         [o_transcode_audio_chkbox state] == NSOnState )
488     {
489         o_transcode_string = [NSMutableString stringWithString:@"transcode{"];
490         if ( [o_transcode_video_chkbox state] == NSOnState )
491         {
492             [o_transcode_string appendFormat: @"vcodec=\"%@\",vb=\"%@\"",
493                 [o_transcode_video_selector titleOfSelectedItem],
494                 [o_transcode_video_bitrate stringValue]];
495             if ( [o_transcode_audio_chkbox state] == NSOnState )
496             {
497                 [o_transcode_string appendString: @","];
498             }
499         }
500         if ( [o_transcode_audio_chkbox state] == NSOnState )
501         {
502             [o_transcode_string appendFormat: @"acodec=\"%@\",ab=\"%@\"",
503                 [o_transcode_audio_selector titleOfSelectedItem],
504                 [o_transcode_audio_bitrate stringValue]];
505         }
506         [o_transcode_string appendString:@"}:"];
507     }
508     else
509     {
510         o_transcode_string = [NSString stringWithString:@""];
511     }
512     [self setTranscode: o_transcode_string];
513     [self outputInfoChanged:nil];
514 }
515
516 - (IBAction)announceChanged:(id)sender
517 {
518     [o_channel_name setEnabled: [o_sap_chkbox state] || [o_slp_chkbox state]];
519     [self outputInfoChanged: nil];
520 }
521
522 @end