1 /*****************************************************************************
2 * ConvertAndSave.h: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2012 Felix Paul Kühne
7 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #import "ConvertAndSave.h"
27 #import <vlc_common.h>
31 * the used NSMatrix includes a bunch of cells referenced most easily by tags. There you go: */
45 /* 13-15 are present, but not set */
47 @implementation VLCConvertAndSave
49 @synthesize MRL=_MRL, outputDestination=_outputDestination, profileNames=_profileNames, profileValueList=_profileValueList, currentProfile=_currentProfile;
51 static VLCConvertAndSave *_o_sharedInstance = nil;
54 #pragma mark Initialization
57 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
59 /* We are using the same format as the Qt4 intf here:
60 * Container(string), transcode video(bool), transcode audio(bool),
61 * use subtitles(bool), video codec(string), video bitrate(integer),
62 * scale(float), fps(float), width(integer, height(integer),
63 * audio codec(string), audio bitrate(integer), channels(integer),
64 * samplerate(integer), subtitle codec(string), subtitle overlay(bool) */
65 NSArray * defaultProfiles = [[NSArray alloc] initWithObjects:
66 @"mp4;1;1;0;h264;0;0;0;0;0;mpga;128;2;44100;0;1",
67 @"webm;1;1;0;VP80;2000;0;0;0;0;vorb;128;2;44100;0;1",
68 @"ts;1;1;0;h264;800;1;0;0;0;mpga;128;2;44100;0;0",
69 @"ts;1;1;0;drac;800;1;0;0;0;mpga;128;2;44100;0;0",
70 @"ogg;1;1;0;theo;800;1;0;0;0;vorb;128;2;44100;0;0",
71 @"ogg;1;1;0;theo;800;1;0;0;0;flac;128;2;44100;0;0",
72 @"ts;1;1;0;mp2v;800;1;0;0;0;mpga;128;2;44100;0;0",
73 @"asf;1;1;0;WMV2;800;1;0;0;0;wma2;128;2;44100;0;0",
74 @"asf;1;1;0;DIV3;800;1;0;0;0;mp3;128;2;44100;0;0",
75 @"ogg;1;1;0;none;800;1;0;0;0;vorb;128;2;44100;none;0",
76 @"raw;1;1;0;none;800;1;0;0;0;mp3;128;2;44100;none;0",
77 @"mp4;1;1;0;none;800;1;0;0;0;mpga;128;2;44100;none;0",
78 @"raw;1;1;0;none;800;1;0;0;0;flac;128;2;44100;none;0",
79 @"wav;1;1;0;none;800;1;0;0;0;s16l;128;2;44100;none;0", nil];
81 NSArray * defaultProfileNames = [[NSArray alloc] initWithObjects:
82 @"Video - H.264 + MP3 (MP4)",
83 @"Video - VP80 + Vorbis (Webm)",
84 @"Video - H.264 + MP3 (TS)",
85 @"Video - Dirac + MP3 (TS)",
86 @"Video - Theora + Vorbis (OGG)",
87 @"Video - Theora + Flac (OGG)",
88 @"Video - MPEG-2 + MPGA (TS)",
89 @"Video - WMV + WMA (ASF)",
90 @"Video - DIV3 + MP3 (ASF)",
91 @"Audio - Vorbis (OGG)",
98 NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:defaultProfiles, @"CASProfiles", defaultProfileNames, @"CASProfileNames", nil];
100 [defaults registerDefaults:appDefaults];
101 [defaultProfiles release];
104 + (VLCConvertAndSave *)sharedInstance
106 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
111 if (_o_sharedInstance) {
114 _o_sharedInstance = [super init];
117 return _o_sharedInstance;
123 [_currentProfile release];
125 [_profileNames release];
126 [_profileValueList release];
127 [_videoCodecs release];
128 [_audioCodecs release];
129 [_subsCodecs release];
136 [_window setTitle: _NS("Convert & Save")];
137 [_ok_btn setTitle: _NS("Save")];
138 [_drop_lbl setStringValue: _NS("Drop media here")];
139 [_drop_btn setTitle: _NS("Open media...")];
140 [_profile_lbl setStringValue: _NS("Choose Profile")];
141 [_profile_btn setTitle: _NS("Customize")];
142 [_destination_lbl setStringValue: _NS("Choose Destination")];
143 [_destination_filename_stub_lbl setStringValue: _NS("Choose an output location")];
144 [_destination_filename_lbl setHidden: YES];
145 [_destination_browse_btn setTitle:_NS("Browse...")];
146 [_destination_stream_btn setTitle:_NS("Setup Streaming...")];
147 [_destination_stream_lbl setStringValue:@"Select Streaming Method"];
148 [_destination_itwantafile_btn setTitle:_NS("Save as File")];
149 [_destination_itwantastream_btn setTitle:_NS("Stream")];
150 [_destination_cancel_btn setHidden:YES];
151 [_customize_ok_btn setTitle: _NS("Apply")];
152 [_customize_cancel_btn setTitle: _NS("Cancel")];
153 [[_customize_tabview tabViewItemAtIndex:0] setLabel: _NS("Encapsulation")];
154 [[_customize_tabview tabViewItemAtIndex:1] setLabel: _NS("Video codec")];
155 [[_customize_tabview tabViewItemAtIndex:2] setLabel: _NS("Audio codec")];
156 [[_customize_tabview tabViewItemAtIndex:3] setLabel: _NS("Subtitles")];
157 [_customize_tabview selectTabViewItemAtIndex: 0];
158 [_customize_vid_ckb setTitle: _NS("Video")];
159 [_customize_vid_keep_ckb setTitle: _NS("Keep original video track")];
160 [_customize_vid_codec_lbl setStringValue: _NS("Codec")];
161 [_customize_vid_bitrate_lbl setStringValue: _NS("Bitrate")];
162 [_customize_vid_framerate_lbl setStringValue: _NS("Frame Rate")];
163 [_customize_vid_res_box setTitle: _NS("Resolution")];
164 [_customize_vid_res_lbl setStringValue: _NS("You just need to fill one of the three following parameters, VLC will autodetect the other using the original aspect ratio")];
165 [_customize_vid_width_lbl setStringValue: _NS("Width")];
166 [_customize_vid_height_lbl setStringValue: _NS("Height")];
167 [_customize_vid_scale_lbl setStringValue: _NS("Scale")];
168 [_customize_aud_ckb setTitle: _NS("Audio")];
169 [_customize_aud_keep_ckb setTitle: _NS("Keep original audio track")];
170 [_customize_aud_codec_lbl setStringValue: _NS("Codec")];
171 [_customize_aud_bitrate_lbl setStringValue: _NS("Bitrate")];
172 [_customize_aud_channels_lbl setStringValue: _NS("Channels")];
173 [_customize_aud_samplerate_lbl setStringValue: _NS("Sample Rate")];
174 [_customize_subs_ckb setTitle: _NS("Subtitles")];
175 [_customize_subs_overlay_ckb setTitle: _NS("Overlay subtitles on the video")];
176 [_stream_ok_btn setTitle:_NS("Close")];
177 [_stream_destination_lbl setStringValue:_NS("Stream Destination")];
178 [_stream_announcement_lbl setStringValue:_NS("Stream Announcement")];
179 [_stream_type_lbl setStringValue:_NS("Type")];
180 [_stream_address_lbl setStringValue:_NS("Address")];
181 [_stream_ttl_lbl setStringValue:_NS("TTL")];
182 [_stream_ttl_fld setEnabled:NO];
183 [_stream_ttl_stepper setEnabled:NO];
184 [_stream_port_lbl setStringValue:_NS("Port")];
185 [_stream_sap_ckb setStringValue:_NS("SAP Announcement")];
186 [_stream_http_ckb setStringValue:_NS("HTTP Announcement")];
187 [_stream_rtsp_ckb setStringValue:_NS("RTSP Announcement")];
188 [_stream_sdp_ckb setStringValue:_NS("Export SDP as file")];
189 [_stream_sap_ckb setState:NSOffState];
190 [_stream_http_ckb setState:NSOffState];
191 [_stream_rtsp_ckb setState:NSOffState];
192 [_stream_sdp_ckb setState:NSOffState];
194 /* there is no way to hide single cells, so replace the existing ones with empty cells.. */
195 id blankCell = [[[NSCell alloc] init] autorelease];
196 [blankCell setEnabled:NO];
197 [_customize_encap_matrix putCell:blankCell atRow:3 column:1];
198 [_customize_encap_matrix putCell:blankCell atRow:3 column:2];
199 [_customize_encap_matrix putCell:blankCell atRow:3 column:3];
201 /* fetch profiles from defaults */
202 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
203 _profileValueList = [[defaults arrayForKey:@"CASProfiles"] retain];
204 _profileNames = [[defaults arrayForKey:@"CASProfileNames"] retain];
206 [_profile_pop removeAllItems];
207 [_profile_pop addItemsWithTitles:_profileNames];
208 [_profile_pop addItemWithTitle:_NS("Custom")];
210 _videoCodecs = [[NSArray alloc] initWithObjects:
211 [NSArray arrayWithObjects:@"MPEG-1", @"MPEG-2", @"MPEG-4", @"DIVX 1", @"DIVX 2", @"DIVX 3", @"H.263", @"H.264", @"VP8", @"WMV1", @"WMV2", @"M-JPEG", @"Theora", @"Dirac", nil],
212 [NSArray arrayWithObjects:@"mpgv", @"mp2v", @"mp4v", @"DIV1", @"DIV2", @"DIV3", @"H263", @"h264", @"VP80", @"WMV1", @"WMV2", @"MJPG", @"theo", @"drac", nil],
214 _audioCodecs = [[NSArray alloc] initWithObjects:
215 [NSArray arrayWithObjects:@"MPEG Audio", @"MP3", @"MPEG 4 Audio (AAC)", @"A52/AC-3", @"Vorbis", @"Flac", @"Speex", @"WAV", @"WMA2", nil],
216 [NSArray arrayWithObjects:@"mpga", @"mp3", @"mp4a", @"a52", @"vorb", @"flac", @"spx", @"s16l", @"wma2", nil],
218 _subsCodecs = [[NSArray alloc] initWithObjects:
219 [NSArray arrayWithObjects:@"DVB subtitle", @"T.140", nil],
220 [NSArray arrayWithObjects:@"dvbs", @"t140", nil],
223 [_customize_vid_codec_pop removeAllItems];
224 [_customize_vid_scale_pop removeAllItems];
225 [_customize_aud_codec_pop removeAllItems];
226 [_customize_aud_samplerate_pop removeAllItems];
227 [_customize_subs_pop removeAllItems];
229 [_customize_vid_codec_pop addItemsWithTitles:[_videoCodecs objectAtIndex:0]];
230 [_customize_aud_codec_pop addItemsWithTitles:[_audioCodecs objectAtIndex:0]];
231 [_customize_subs_pop addItemsWithTitles:[_subsCodecs objectAtIndex:0]];
233 [_customize_aud_samplerate_pop addItemWithTitle:@"8000"];
234 [_customize_aud_samplerate_pop addItemWithTitle:@"11025"];
235 [_customize_aud_samplerate_pop addItemWithTitle:@"22050"];
236 [_customize_aud_samplerate_pop addItemWithTitle:@"44100"];
237 [_customize_aud_samplerate_pop addItemWithTitle:@"48000"];
239 [_customize_vid_scale_pop addItemWithTitle:@"1"];
240 [_customize_vid_scale_pop addItemWithTitle:@"0.25"];
241 [_customize_vid_scale_pop addItemWithTitle:@"0.5"];
242 [_customize_vid_scale_pop addItemWithTitle:@"0.75"];
243 [_customize_vid_scale_pop addItemWithTitle:@"1.25"];
244 [_customize_vid_scale_pop addItemWithTitle:@"1.5"];
245 [_customize_vid_scale_pop addItemWithTitle:@"1.75"];
246 [_customize_vid_scale_pop addItemWithTitle:@"2"];
248 [_ok_btn setEnabled: NO];
250 [self resetCustomizationSheetBasedOnProfile:[_profileValueList objectAtIndex:0]];
254 # pragma mark Code to Communicate with other objects
258 [_window makeKeyAndOrderFront: nil];
262 # pragma mark User Interaction
264 - (IBAction)finalizePanel:(id)sender
266 playlist_t * p_playlist = pl_Get(VLCIntf);
268 input_item_t *p_input = input_item_New([_MRL UTF8String], [[_dropin_media_lbl stringValue] UTF8String]);
272 input_item_AddOption(p_input, [[self composedOptions] UTF8String], VLC_INPUT_OPTION_TRUSTED);
275 returnValue = playlist_AddInput( p_playlist, p_input, PLAYLIST_STOP, PLAYLIST_END, true, pl_Unlocked );
277 if (returnValue == VLC_SUCCESS) {
280 playlist_item_t *p_item = playlist_ItemGetByInput( p_playlist, p_input );
281 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Locked, NULL,
286 msg_Err( VLCIntf, "CAS: playlist add input failed :(");
288 /* we're done with this input */
289 vlc_gc_decref( p_input );
291 [_window performClose:sender];
294 - (IBAction)openMedia:(id)sender
296 /* preliminary implementation until the open panel is cleaned up */
297 NSOpenPanel * openPanel = [NSOpenPanel openPanel];
298 [openPanel setCanChooseDirectories:NO];
299 [openPanel setResolvesAliases:YES];
300 [openPanel setAllowsMultipleSelection:NO];
301 [openPanel beginSheetForDirectory:nil file:nil types:nil modalForWindow: _window modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
304 - (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
306 if (returnCode == NSOKButton)
308 [self setMRL: [NSString stringWithUTF8String:vlc_path2uri([[[panel URL] path] UTF8String], NULL)]];
309 [self updateOKButton];
310 [self updateDropView];
314 - (IBAction)switchProfile:(id)sender
316 NSUInteger index = [_profile_pop indexOfSelectedItem];
317 if (index < ([_profileValueList count] - 1))
318 [self resetCustomizationSheetBasedOnProfile:[_profileValueList objectAtIndex:index]];
321 - (IBAction)customizeProfile:(id)sender
323 [NSApp beginSheet:_customize_panel modalForWindow:_window modalDelegate:self didEndSelector:NULL contextInfo:nil];
326 - (IBAction)closeCustomizationSheet:(id)sender
328 [_customize_panel orderOut:sender];
329 [NSApp endSheet: _customize_panel];
331 /* update current profile based upon the sheet's values */
332 /* Container(string), transcode video(bool), transcode audio(bool),
333 * use subtitles(bool), video codec(string), video bitrate(integer),
334 * scale(float), fps(float), width(integer, height(integer),
335 * audio codec(string), audio bitrate(integer), channels(integer),
336 * samplerate(integer), subtitle codec(string), subtitle overlay(bool) */
338 if (sender == _customize_ok_btn && [_currentProfile count] == 16) {
340 [_currentProfile replaceObjectAtIndex:0 withObject:[self currentEncapsulationFormatAsFileExtension:NO]];
341 [_currentProfile replaceObjectAtIndex:1 withObject:[NSString stringWithFormat:@"%li", [_customize_vid_ckb state]]];
342 [_currentProfile replaceObjectAtIndex:2 withObject:[NSString stringWithFormat:@"%li", [_customize_aud_ckb state]]];
343 [_currentProfile replaceObjectAtIndex:3 withObject:[NSString stringWithFormat:@"%li", [_customize_subs_ckb state]]];
344 i = [_customize_vid_codec_pop indexOfSelectedItem];
346 [_currentProfile replaceObjectAtIndex:4 withObject:[_videoCodecs objectAtIndex:i]];
348 [_currentProfile replaceObjectAtIndex:4 withObject:@"none"];
349 [_currentProfile replaceObjectAtIndex:5 withObject:[_customize_vid_bitrate_fld stringValue]];
350 [_currentProfile replaceObjectAtIndex:6 withObject:[[_customize_vid_scale_pop selectedItem] title]];
351 [_currentProfile replaceObjectAtIndex:7 withObject:[_customize_vid_framerate_fld stringValue]];
352 [_currentProfile replaceObjectAtIndex:8 withObject:[_customize_vid_width_fld stringValue]];
353 [_currentProfile replaceObjectAtIndex:9 withObject:[_customize_vid_height_fld stringValue]];
354 i = [_customize_aud_codec_pop indexOfSelectedItem];
356 [_currentProfile replaceObjectAtIndex:10 withObject:[_audioCodecs objectAtIndex:i]];
358 [_currentProfile replaceObjectAtIndex:10 withObject:@"none"];
359 [_currentProfile replaceObjectAtIndex:11 withObject:[_customize_aud_bitrate_fld stringValue]];
360 [_currentProfile replaceObjectAtIndex:12 withObject:[_customize_aud_channels_fld stringValue]];
361 [_currentProfile replaceObjectAtIndex:13 withObject:[[_customize_aud_samplerate_pop selectedItem] title]];
362 i = [_customize_subs_pop indexOfSelectedItem];
364 [_currentProfile replaceObjectAtIndex:14 withObject:[_subsCodecs objectAtIndex:i]];
366 [_currentProfile replaceObjectAtIndex:14 withObject:@"none"];
367 [_currentProfile replaceObjectAtIndex:15 withObject:[NSString stringWithFormat:@"%li", [_customize_subs_overlay_ckb state]]];
371 - (IBAction)iWantAFile:(id)sender
373 NSRect boxFrame = [_destination_box frame];
374 NSRect subViewFrame = [_destination_itwantafile_view frame];
375 subViewFrame.origin.x = (boxFrame.size.width - subViewFrame.size.width) / 2;
376 subViewFrame.origin.y = ((boxFrame.size.height - subViewFrame.size.height) / 2) - 15.;
377 [_destination_itwantafile_view setFrame: subViewFrame];
378 [[_destination_itwantafile_btn animator] setHidden: YES];
379 [[_destination_itwantastream_btn animator] setHidden: YES];
380 [_destination_box performSelector:@selector(addSubview:) withObject:_destination_itwantafile_view afterDelay:0.2];
381 [[_destination_cancel_btn animator] setHidden:NO];
383 [_ok_btn setTitle:_NS("Save")];
386 - (IBAction)iWantAStream:(id)sender
388 NSRect boxFrame = [_destination_box frame];
389 NSRect subViewFrame = [_destination_itwantastream_view frame];
390 subViewFrame.origin.x = (boxFrame.size.width - subViewFrame.size.width) / 2;
391 subViewFrame.origin.y = ((boxFrame.size.height - subViewFrame.size.height) / 2) - 15.;
392 [_destination_itwantastream_view setFrame: subViewFrame];
393 [[_destination_itwantafile_btn animator] setHidden: YES];
394 [[_destination_itwantastream_btn animator] setHidden: YES];
395 [_destination_box performSelector:@selector(addSubview:) withObject:_destination_itwantastream_view afterDelay:0.2];
396 [[_destination_cancel_btn animator] setHidden:NO];
398 [_ok_btn setTitle:_NS("Stream")];
401 - (IBAction)cancelDestination:(id)sender
403 if ([_destination_itwantastream_view superview] != nil)
404 [_destination_itwantastream_view removeFromSuperview];
405 if ([_destination_itwantafile_view superview] != nil)
406 [_destination_itwantafile_view removeFromSuperview];
408 [_destination_cancel_btn setHidden:YES];
409 [[_destination_itwantafile_btn animator] setHidden: NO];
410 [[_destination_itwantastream_btn animator] setHidden: NO];
414 - (IBAction)browseFileDestination:(id)sender
416 NSSavePanel * saveFilePanel = [NSSavePanel savePanel];
417 [saveFilePanel setCanSelectHiddenExtension: YES];
418 [saveFilePanel setCanCreateDirectories: YES];
419 if ([[_customize_encap_matrix selectedCell] tag] != RAW) // there is no clever guess for this
420 [saveFilePanel setAllowedFileTypes:[NSArray arrayWithObject:[self currentEncapsulationFormatAsFileExtension:YES]]];
421 [saveFilePanel beginSheetForDirectory:nil file:nil modalForWindow:_window modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
424 - (void)savePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
426 if (returnCode == NSOKButton) {
427 [self setOutputDestination:[[sheet URL] path]];
428 [_destination_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:_outputDestination]];
429 [[_destination_filename_stub_lbl animator] setHidden: YES];
430 [[_destination_filename_lbl animator] setHidden: NO];
432 [self setOutputDestination:@""];
433 [[_destination_filename_lbl animator] setHidden: YES];
434 [[_destination_filename_stub_lbl animator] setHidden: NO];
436 [self updateOKButton];
439 - (IBAction)showStreamPanel:(id)sender
441 [NSApp beginSheet:_stream_panel modalForWindow:_window modalDelegate:self didEndSelector:NULL contextInfo:nil];
444 - (IBAction)closeStreamPanel:(id)sender
446 NSMutableString * labelContent = [[NSMutableString alloc] initWithFormat:@"%@ @ %@:%@", [_stream_type_pop titleOfSelectedItem], [_stream_address_fld stringValue], [_stream_port_fld stringValue]];
448 if ([_stream_type_pop indexOfSelectedItem] > 1) {
449 [labelContent appendFormat:@" TTL:%@", [_stream_ttl_fld stringValue]];
450 if ([_stream_sap_ckb state] || [_stream_rtsp_ckb state] || [_stream_http_ckb state] || [_stream_sdp_ckb state])
451 [labelContent appendFormat:@" — %@:\"%@\" (", _NS("Channel"), [_stream_channel_fld stringValue]];
454 if (_stream_sap_ckb) {
455 [labelContent appendString:@"SAP"];
456 b_gotSomething = YES;
458 if (_stream_rtsp_ckb) {
460 [labelContent appendString:@", "];
461 [labelContent appendString:@"RTSP"];
462 b_gotSomething = YES;
464 if (_stream_http_ckb) {
466 [labelContent appendString:@", "];
467 [labelContent appendString:@"HTTP"];
468 b_gotSomething = YES;
470 if ([_stream_sdp_ckb state]) {
472 [labelContent appendString:@", "];
473 [labelContent appendString:@"SDP"];
476 if ([_stream_sap_ckb state] || [_stream_rtsp_ckb state] || [_stream_http_ckb state] || [_stream_sdp_ckb state])
477 [labelContent appendString:@")"];
479 [_destination_stream_lbl setStringValue:labelContent];
480 [labelContent release];
482 [_stream_panel orderOut:sender];
483 [NSApp endSheet: _stream_panel];
486 - (IBAction)streamTypeToggle:(id)sender
488 NSUInteger index = [_stream_type_pop indexOfSelectedItem];
489 if (index <= 1) { // HTTP, MMSH
490 [_stream_ttl_fld setEnabled:NO];
491 [_stream_ttl_stepper setEnabled:NO];
492 [_stream_sap_ckb setEnabled:NO];
493 [_stream_rtsp_ckb setEnabled:NO];
494 [_stream_http_ckb setEnabled:NO];
495 [_stream_sdp_ckb setEnabled:NO];
496 } else if (index == 2) { // RTP
497 [_stream_ttl_fld setEnabled:YES];
498 [_stream_ttl_stepper setEnabled:YES];
499 [_stream_sap_ckb setEnabled:YES];
500 [_stream_rtsp_ckb setEnabled:YES];
501 [_stream_http_ckb setEnabled:YES];
502 [_stream_sdp_ckb setEnabled:YES];
503 [_stream_channel_fld setEnabled:YES];
504 [_stream_sdp_fld setEnabled:[_stream_sdp_ckb state]];
506 [_stream_ttl_fld setEnabled:YES];
507 [_stream_ttl_stepper setEnabled:YES];
508 [_stream_sap_ckb setEnabled:YES];
509 [_stream_rtsp_ckb setEnabled:NO];
510 [_stream_http_ckb setEnabled:NO];
511 [_stream_sdp_ckb setEnabled:NO];
512 [_stream_channel_fld setEnabled:YES];
516 - (IBAction)streamAnnouncementToggle:(id)sender
518 [_stream_sdp_fld setEnabled:[_stream_sdp_ckb state]];
521 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
523 NSPasteboard *paste = [sender draggingPasteboard];
524 NSArray *types = [NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil];
525 NSString *desired_type = [paste availableTypeFromArray: types];
526 NSData *carried_data = [paste dataForType: desired_type];
529 if( [desired_type isEqualToString:NSFilenamesPboardType] ) {
530 NSArray *values = [[paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
532 if ([values count] > 0) {
533 [self setMRL: [NSString stringWithUTF8String:vlc_path2uri([[values objectAtIndex:0] UTF8String], NULL)]];
534 [self updateOKButton];
535 [self updateDropView];
538 } else if( [desired_type isEqualToString:@"VLCPlaylistItemPboardType"] ) {
539 NSArray * array = [[[VLCMain sharedInstance] playlist] draggedItems];
540 NSUInteger count = [array count];
542 playlist_t * p_playlist = pl_Get( VLCIntf );
543 playlist_item_t * p_item = NULL;
546 /* let's look for the first proper input item */
547 for (NSUInteger x = 0; x < count; x++) {
548 p_item = [[array objectAtIndex:x] pointerValue];
550 if (p_item->p_input) {
551 if (p_item->p_input->psz_uri != nil) {
552 [self setMRL: [NSString stringWithFormat:@"%s", p_item->p_input->psz_uri]];
553 [self updateDropView];
554 [self updateOKButton];
571 # pragma mark Private Functionality
572 - (void)updateDropView
574 if ([_MRL length] > 0) {
575 NSString * path = [[NSURL URLWithString:_MRL] path];
576 [_dropin_media_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath: path]];
577 NSImage * image = [[NSWorkspace sharedWorkspace] iconForFile: path];
578 [image setSize:NSMakeSize(128,128)];
579 [_dropin_icon_view setImage: image];
581 if (![_dropin_view superview]) {
582 NSRect boxFrame = [_drop_box frame];
583 NSRect subViewFrame = [_dropin_view frame];
584 subViewFrame.origin.x = (boxFrame.size.width - subViewFrame.size.width) / 2;
585 subViewFrame.origin.y = (boxFrame.size.height - subViewFrame.size.height) / 2;
586 [_dropin_view setFrame: subViewFrame];
587 [[_drop_image_view animator] setHidden: YES];
588 [_drop_box performSelector:@selector(addSubview:) withObject:_dropin_view afterDelay:0.6];
591 [_dropin_view removeFromSuperview];
592 [[_drop_image_view animator] setHidden: NO];
596 - (void)updateOKButton
598 if ([_outputDestination length] > 0 && [_MRL length] > 0)
599 [_ok_btn setEnabled: YES];
601 [_ok_btn setEnabled: NO];
604 - (void)resetCustomizationSheetBasedOnProfile:(NSString *)profileString
606 /* Container(string), transcode video(bool), transcode audio(bool),
607 * use subtitles(bool), video codec(string), video bitrate(integer),
608 * scale(float), fps(float), width(integer, height(integer),
609 * audio codec(string), audio bitrate(integer), channels(integer),
610 * samplerate(integer), subtitle codec(string), subtitle overlay(bool) */
612 NSArray * components = [profileString componentsSeparatedByString:@";"];
613 if ([components count] != 16) {
614 msg_Err(VLCIntf, "CAS: the requested profile '%s' is invalid", [profileString UTF8String]);
618 [self selectCellByEncapsulationFormat:[components objectAtIndex:0]];
619 [_customize_vid_ckb setState:[[components objectAtIndex:1] intValue]];
620 [_customize_aud_ckb setState:[[components objectAtIndex:2] intValue]];
621 [_customize_subs_ckb setState:[[components objectAtIndex:3] intValue]];
622 [_customize_vid_bitrate_fld setStringValue:[components objectAtIndex:5]];
623 [_customize_vid_scale_pop selectItemWithTitle:[components objectAtIndex:6]];
624 [_customize_vid_framerate_fld setStringValue:[components objectAtIndex:7]];
625 [_customize_vid_width_fld setStringValue:[components objectAtIndex:8]];
626 [_customize_vid_height_fld setStringValue:[components objectAtIndex:9]];
627 [_customize_aud_bitrate_fld setStringValue:[components objectAtIndex:11]];
628 [_customize_aud_channels_fld setStringValue:[components objectAtIndex:12]];
629 [_customize_aud_samplerate_pop selectItemWithTitle:[components objectAtIndex:13]];
630 [_customize_subs_overlay_ckb setState:[[components objectAtIndex:15] intValue]];
632 /* since there is no proper lookup mechanism in arrays, we need to implement a string specific one ourselves */
633 NSArray * tempArray = [_videoCodecs objectAtIndex:1];
634 NSUInteger count = [tempArray count];
635 NSString * searchString = [components objectAtIndex:4];
636 if ([searchString isEqualToString:@"none"] || [searchString isEqualToString:@"0"]) {
637 [_customize_vid_codec_pop selectItemAtIndex:-1];
639 for (NSUInteger x = 0; x < count; x++) {
640 if ([[tempArray objectAtIndex:x] isEqualToString: searchString]) {
641 [_customize_vid_codec_pop selectItemAtIndex:x];
647 tempArray = [_audioCodecs objectAtIndex:1];
648 count = [tempArray count];
649 searchString = [components objectAtIndex:10];
650 if ([searchString isEqualToString:@"none"] || [searchString isEqualToString:@"0"]) {
651 [_customize_aud_codec_pop selectItemAtIndex:-1];
653 for (NSUInteger x = 0; x < count; x++) {
654 if ([[tempArray objectAtIndex:x] isEqualToString: searchString]) {
655 [_customize_aud_codec_pop selectItemAtIndex:x];
661 tempArray = [_subsCodecs objectAtIndex:1];
662 count = [tempArray count];
663 searchString = [components objectAtIndex:14];
664 if ([searchString isEqualToString:@"none"] || [searchString isEqualToString:@"0"]) {
665 [_customize_subs_pop selectItemAtIndex:-1];
667 for (NSUInteger x = 0; x < count; x++) {
668 if ([[tempArray objectAtIndex:x] isEqualToString: searchString]) {
669 [_customize_subs_pop selectItemAtIndex:x];
676 [_currentProfile release];
677 _currentProfile = [[NSMutableArray alloc] initWithArray: [profileString componentsSeparatedByString:@";"]];
680 - (void)selectCellByEncapsulationFormat:(NSString *)format
682 if ([format isEqualToString:@"ts"])
683 [_customize_encap_matrix selectCellWithTag:MPEGTS];
684 else if([format isEqualToString:@"webm"])
685 [_customize_encap_matrix selectCellWithTag:WEBM];
686 else if([format isEqualToString:@"ogg"])
687 [_customize_encap_matrix selectCellWithTag:OGG];
688 else if([format isEqualToString:@"ogm"])
689 [_customize_encap_matrix selectCellWithTag:OGG];
690 else if([format isEqualToString:@"mp4"])
691 [_customize_encap_matrix selectCellWithTag:MP4];
692 else if([format isEqualToString:@"mov"])
693 [_customize_encap_matrix selectCellWithTag:MP4];
694 else if([format isEqualToString:@"ps"])
695 [_customize_encap_matrix selectCellWithTag:MPEGPS];
696 else if([format isEqualToString:@"mpjpeg"])
697 [_customize_encap_matrix selectCellWithTag:MJPEG];
698 else if([format isEqualToString:@"wav"])
699 [_customize_encap_matrix selectCellWithTag:WAV];
700 else if([format isEqualToString:@"flv"])
701 [_customize_encap_matrix selectCellWithTag:FLV];
702 else if([format isEqualToString:@"mpeg1"])
703 [_customize_encap_matrix selectCellWithTag:MPEG1];
704 else if([format isEqualToString:@"mkv"])
705 [_customize_encap_matrix selectCellWithTag:MKV];
706 else if([format isEqualToString:@"raw"])
707 [_customize_encap_matrix selectCellWithTag:RAW];
708 else if([format isEqualToString:@"avi"])
709 [_customize_encap_matrix selectCellWithTag:AVI];
710 else if([format isEqualToString:@"asf"])
711 [_customize_encap_matrix selectCellWithTag:ASF];
712 else if([format isEqualToString:@"wmv"])
713 [_customize_encap_matrix selectCellWithTag:ASF];
715 msg_Err(VLCIntf, "CAS: unknown encap format requested for customization");
718 - (NSString *)currentEncapsulationFormatAsFileExtension:(BOOL)b_extension
720 NSUInteger cellTag = [[_customize_encap_matrix selectedCell] tag];
721 NSString * returnValue;
727 returnValue = @"webm";
730 returnValue = @"ogg";
735 returnValue = @"m4v";
737 returnValue = @"mp4";
743 returnValue = @"mpg";
749 returnValue = @"mjpeg";
752 returnValue = @"wav";
755 returnValue = @"flv";
760 returnValue = @"mpg";
762 returnValue = @"mpeg1";
766 returnValue = @"mkv";
769 returnValue = @"raw";
772 returnValue = @"avi";
775 returnValue = @"asf";
779 returnValue = @"none";
786 - (NSString *)composedOptions
788 NSMutableString *composedOptions = [[NSMutableString alloc] initWithString:@":sout=#transcode{"];
789 if ([[_currentProfile objectAtIndex:1] intValue]) {
791 [composedOptions appendFormat:@"vcodec=%@", [_currentProfile objectAtIndex:4]];
792 if (![[_currentProfile objectAtIndex:4] isEqualToString:@"none"]) {
793 if ([[_currentProfile objectAtIndex:5] intValue] > 0) // bitrate
794 [composedOptions appendFormat:@",vb=%@", [_currentProfile objectAtIndex:5]];
795 if ([[_currentProfile objectAtIndex:6] floatValue] > 0.) // scale
796 [composedOptions appendFormat:@",scale=%@", [_currentProfile objectAtIndex:6]];
797 if ([[_currentProfile objectAtIndex:7] floatValue] > 0.) // fps
798 [composedOptions appendFormat:@",fps=%@", [_currentProfile objectAtIndex:7]];
799 if ([[_currentProfile objectAtIndex:8] intValue] > 0) // width
800 [composedOptions appendFormat:@",width=%@", [_currentProfile objectAtIndex:8]];
801 if ([[_currentProfile objectAtIndex:9] intValue] > 0) // height
802 [composedOptions appendFormat:@",height=%@", [_currentProfile objectAtIndex:9]];
805 if ([[_currentProfile objectAtIndex:2] intValue]) {
808 // add another comma in case video is enabled
809 if ([[_currentProfile objectAtIndex:1] intValue])
810 [composedOptions appendString:@","];
812 [composedOptions appendFormat:@"acodec=%@", [_currentProfile objectAtIndex:10]];
813 if (![[_currentProfile objectAtIndex:10] isEqualToString:@"none"]) {
814 [composedOptions appendFormat:@",ab=%@", [_currentProfile objectAtIndex:11]]; // bitrate
815 [composedOptions appendFormat:@",channels=%@", [_currentProfile objectAtIndex:12]]; // channel number
816 [composedOptions appendFormat:@",samplerate=%@", [_currentProfile objectAtIndex:13]]; // sample rate
819 if ([_currentProfile objectAtIndex:3]) {
821 [composedOptions appendFormat:@",scodec=%@", [_currentProfile objectAtIndex:14]];
822 if ([[_currentProfile objectAtIndex:15] intValue])
823 [composedOptions appendFormat:@",soverlay"];
827 [composedOptions appendFormat:@"}:standard{mux=%@", [_currentProfile objectAtIndex:0]];
829 // add output destination (file only at this point)
830 [composedOptions appendFormat:@",dst=%@,access=file}", _outputDestination];
832 NSString * returnString = [NSString stringWithString:composedOptions];
833 [composedOptions release];
841 # pragma mark Drag and drop handling
843 @implementation VLCDropEnabledBox
847 [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
850 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
852 b_activeDragAndDrop = YES;
853 [self setNeedsDisplay:YES];
855 if (OSX_SNOW_LEOPARD || OSX_LION)
856 [[NSCursor dragCopyCursor] set];
858 if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric)
859 return NSDragOperationGeneric;
861 return NSDragOperationNone;
864 - (void)draggingEnded:(id < NSDraggingInfo >)sender
866 [[NSCursor arrowCursor] set];
867 b_activeDragAndDrop = NO;
868 [self setNeedsDisplay:YES];
871 - (void)draggingExited:(id < NSDraggingInfo >)sender
873 [[NSCursor arrowCursor] set];
874 b_activeDragAndDrop = NO;
875 [self setNeedsDisplay:YES];
878 - (void)drawRect:(NSRect)dirtyRect
880 if (b_activeDragAndDrop) {
881 [[NSColor colorWithCalibratedRed:(.154/.255) green:(.154/.255) blue:(.154/.255) alpha:1.] setFill];
882 NSRect frameRect = [[self contentView] bounds];
883 frameRect.origin.x += 10;
884 frameRect.origin.y += 10;
885 frameRect.size.width -= 17;
886 frameRect.size.height -= 17;
887 NSFrameRectWithWidthUsingOperation(frameRect, 4., NSCompositeHighlight);
890 [super drawRect:dirtyRect];
893 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
898 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
900 return [[VLCConvertAndSave sharedInstance] performDragOperation: sender];
903 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
905 [self setNeedsDisplay:YES];
910 @implementation VLCDropEnabledImageView
914 [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
917 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
919 return [[[self superview] superview] draggingEntered:sender];
922 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
927 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
929 return [[VLCConvertAndSave sharedInstance] performDragOperation: sender];
932 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
934 [self setNeedsDisplay:YES];
939 @implementation VLCDropEnabledButton
943 [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
946 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
948 return [[[self superview] superview] draggingEntered:sender];
951 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
956 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
958 return [[VLCConvertAndSave sharedInstance] performDragOperation: sender];
961 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
963 [self setNeedsDisplay:YES];