/*****************************************************************************
* VLCMediaPlayer.m: VLCKit.framework VLCMediaPlayer implementation
*****************************************************************************
- * Copyright (C) 2007 Pierre d'Herbemont
- * Copyright (C) 2007 the VideoLAN team
+ * Copyright (C) 2007-2009 Pierre d'Herbemont
+ * Copyright (C) 2007-2009 the VideoLAN team
+ * Partial Copyright (C) 2009 Felix Paul Kühne
* $Id$
*
* Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
* Faustion Osuna <enrique.osuna # gmail.com>
+ * Felix Paul Kühne <fkuehne # videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void * self)
{
VLCMediaPlayerState newState;
-
+
if( event->type == libvlc_MediaPlayerPlaying )
newState = VLCMediaPlayerStatePlaying;
else if( event->type == libvlc_MediaPlayerPaused )
NSLog(@"%s: Unknown event", __FUNCTION__);
return;
}
-
+
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
+
[[VLCEventManager sharedManager] callOnMainThreadObject:self
withMethod:@selector(mediaPlayerStateChanged:)
withArgumentAsObject:[NSNumber numberWithInt:newState]];
-
+
[[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
withDelegateMethod:@selector(mediaPlayerStateChanged:)
withNotificationName:VLCMediaPlayerStateChanged];
-
+
[pool release];
+
+}
+static void HandleMediaPlayerMediaChanged(const libvlc_event_t * event, void * self)
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+ [[VLCEventManager sharedManager] callOnMainThreadObject:self
+ withMethod:@selector(mediaPlayerMediaChanged:)
+ withArgumentAsObject:[VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_player_media_changed.new_media]];
+
+ [pool release];
+
}
- (void)mediaPlayerTimeChanged:(NSNumber *)newTime;
- (void)mediaPlayerPositionChanged:(NSNumber *)newTime;
- (void)mediaPlayerStateChanged:(NSNumber *)newState;
+- (void)mediaPlayerMediaChanged:(VLCMedia *)media;
@end
@implementation VLCMediaPlayer
- (void)dealloc
{
+ NSAssert(libvlc_media_player_get_state(instance, NULL) == libvlc_Stopped, @"You released the media player before ensuring that it is stopped");
+
// Always get rid of the delegate first so we can stop sending messages to it
// TODO: Should we tell the delegate that we're shutting down?
delegate = nil;
- libvlc_media_player_release((libvlc_media_player_t *)instance);
+ // Clear our drawable as we are going to release it, we don't
+ // want the core to use it from this point. This won't happen as
+ // the media player must be stopped.
+ libvlc_media_player_set_nsobject(instance, nil, NULL);
+
+ libvlc_media_player_release(instance);
// Get rid of everything else
[media release];
[cachedTime release];
+ [cachedRemainingTime release];
+ [drawable release];
[super dealloc];
}
return [[VLCLibrary sharedLibrary] audio];
}
-- (void)setVideoAspectRatio:(char *)value
-{
- libvlc_video_set_aspect_ratio( instance, value, NULL );
-}
+#pragma mark -
+#pragma mark Subtitles
-- (char *)videoAspectRatio
+- (void)setCurrentVideoSubTitleIndex:(NSUInteger)index
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- char * result = libvlc_video_get_aspect_ratio( instance, &ex );
+ libvlc_video_set_spu( instance, (int)index, &ex );
catch_exception( &ex );
- return result;
}
-- (void)setVideoSubTitles:(int)value
+- (NSUInteger)currentVideoSubTitleIndex
{
- libvlc_video_set_spu( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSInteger count = libvlc_video_get_spu_count( instance, &ex );
+ if (libvlc_exception_raised( &ex ))
+ {
+ libvlc_exception_clear( &ex );
+ return NSNotFound;
+ }
+ if (count <= 0)
+ return NSNotFound;
+ NSUInteger result = libvlc_video_get_spu( instance, &ex );
+ if (libvlc_exception_raised( &ex ))
+ {
+ libvlc_exception_clear( &ex );
+ return NSNotFound;
+ }
+ else
+ return result;
}
-- (int)videoSubTitles
+- (BOOL)openVideoSubTitlesFromFile:(NSString *)path
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_video_get_spu( instance, &ex );
+ BOOL result = libvlc_video_set_subtitle_file( instance, [path UTF8String], &ex );
catch_exception( &ex );
return result;
}
+- (NSArray *)videoSubTitles
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSInteger count = libvlc_video_get_spu_count( instance, &ex );
+ catch_exception( &ex );
+
+ libvlc_track_description_t *tracks = libvlc_video_get_spu_description( instance, &ex );
+ NSMutableArray *tempArray = [NSMutableArray array];
+ NSInteger i;
+ for (i = 0; i < count; i++)
+ {
+ [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
+ tracks = tracks->p_next;
+ }
+ return [NSArray arrayWithArray: tempArray];
+}
+
+
+#pragma mark -
+#pragma mark Video Crop geometry
+
- (void)setVideoCropGeometry:(char *)value
{
- libvlc_video_set_crop_geometry( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_video_set_crop_geometry( instance, value, &ex );
+ catch_exception( &ex );
}
- (char *)videoCropGeometry
return result;
}
-- (void)setVideoTeleText:(int)value
+- (void)setVideoAspectRatio:(char *)value
{
- libvlc_video_set_teletext( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_video_set_aspect_ratio( instance, value, &ex );
+ catch_exception( &ex );
}
-- (int)videoTeleText
+- (char *)videoAspectRatio
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_video_get_teletext( instance, &ex );
+ char * result = libvlc_video_get_aspect_ratio( instance, &ex );
+ catch_exception( &ex );
+ return result;
+}
+
+- (void)setVideoTeleText:(NSUInteger)value
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_video_set_teletext( instance, value, &ex );
+ catch_exception( &ex );
+}
+
+- (NSUInteger)videoTeleText
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSInteger result = libvlc_video_get_teletext( instance, &ex );
catch_exception( &ex );
return result;
}
- (void)setRate:(float)value
{
- libvlc_media_player_set_rate( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_media_player_set_rate( instance, value, &ex );
+ catch_exception( &ex );
}
- (float)rate
libvlc_exception_init( &ex );
// Time is managed in seconds, while duration is managed in microseconds
// TODO: Redo VLCTime to provide value numberAsMilliseconds, numberAsMicroseconds, numberAsSeconds, numberAsMinutes, numberAsHours
- libvlc_media_player_set_time( (libvlc_media_player_t *)instance,
- (value ? [[value numberValue] longLongValue] / 1000 : 0),
+ libvlc_media_player_set_time( (libvlc_media_player_t *)instance,
+ (value ? [[value numberValue] longLongValue] : 0),
&ex );
catch_exception( &ex );
}
- (VLCTime *)remainingTime
{
- double currentTime = [[cachedTime numberValue] doubleValue];
- double remaining = currentTime / position * (1 - position);
- return [VLCTime timeWithNumber:[NSNumber numberWithDouble:-remaining]];
+ return cachedRemainingTime;
}
-- (void)setChapter:(int)value;
+- (NSUInteger)fps
{
- libvlc_media_player_set_chapter( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSUInteger result = libvlc_media_player_get_fps( instance, &ex );
+ catch_exception( &ex );
+ return result;
}
-- (int)chapter
+#pragma mark -
+#pragma mark Chapters
+- (void)setCurrentChapterIndex:(NSUInteger)value;
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_media_player_get_chapter( instance, &ex );
+ libvlc_media_player_set_chapter( instance, value, &ex );
catch_exception( &ex );
- return result;
}
-- (int)countOfChapters
+- (NSUInteger)currentChapterIndex
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_media_player_get_chapter_count( instance, &ex );
+ NSInteger count = libvlc_media_player_get_chapter_count( instance, &ex );
+ catch_exception( &ex );
+ if (count <= 0)
+ return NSNotFound;
+ NSUInteger result = libvlc_media_player_get_chapter( instance, &ex );
catch_exception( &ex );
return result;
}
-- (void)setAudioTrack:(int)value
+- (void)nextChapter
{
- libvlc_audio_set_track( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_media_player_next_chapter( instance, &ex );
+ catch_exception( &ex );
}
-- (int)audioTrack
+- (void)previousChapter
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_audio_get_track( instance, &ex );
+ libvlc_media_player_previous_chapter( instance, &ex );
+ catch_exception( &ex );
+}
+
+- (NSArray *)chaptersForTitleIndex:(NSUInteger)title
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSInteger count = libvlc_media_player_get_chapter_count(instance, &ex);
+ if (count <= 0)
+ return [NSArray array];
+
+ libvlc_track_description_t *tracks = libvlc_video_get_chapter_description( instance, title, &ex );
+ NSMutableArray *tempArray = [NSMutableArray array];
+ NSInteger i;
+ for (i = 0; i < count ; i++)
+ {
+ [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
+ tracks = tracks->p_next;
+ }
+ return [NSArray arrayWithArray: tempArray];
+}
+
+#pragma mark -
+#pragma mark Titles
+
+- (void)setCurrentTitleIndex:(NSUInteger)value
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_media_player_set_title( instance, value, &ex );
+ catch_exception( &ex );
+}
+
+- (NSUInteger)currentTitleIndex
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+
+ NSInteger count = libvlc_media_player_get_title_count( instance, &ex );
+ catch_exception( &ex );
+ if (count <= 0)
+ return NSNotFound;
+
+ NSUInteger result = libvlc_media_player_get_title( instance, &ex );
+ catch_exception( &ex );
+ return result;
+}
+
+- (NSUInteger)countOfTitles
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSUInteger result = libvlc_media_player_get_title_count( instance, &ex );
catch_exception( &ex );
return result;
}
-- (int)countOfAudioTracks
+- (NSArray *)titles
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_track_description_t *tracks = libvlc_video_get_title_description( instance, &ex );
+ NSMutableArray *tempArray = [NSMutableArray array];
+ NSInteger i;
+ for (i = 0; i < [self countOfTitles] ; i++)
+ {
+ [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
+ tracks = tracks->p_next;
+ }
+ return [NSArray arrayWithArray: tempArray];
+}
+
+#pragma mark -
+#pragma mark Audio tracks
+- (void)setCurrentAudioTrackIndex:(NSUInteger)value
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_audio_set_track( instance, (int)value, &ex );
+ catch_exception( &ex );
+}
+
+- (NSUInteger)currentAudioTrackIndex
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_audio_get_track_count( instance, &ex );
+ NSInteger count = libvlc_audio_get_track_count( instance, &ex );
+ catch_exception( &ex );
+ if (count <= 0)
+ return NSNotFound;
+
+ NSUInteger result = libvlc_audio_get_track( instance, &ex );
catch_exception( &ex );
return result;
}
-- (void)setAudioChannel:(int)value
+- (NSArray *)audioTracks
{
- libvlc_audio_set_channel( instance, value, NULL );
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ NSInteger count = libvlc_audio_get_track_count( instance, &ex );
+ catch_exception( &ex );
+ if (count <= 0)
+ return [NSArray array];
+
+ libvlc_track_description_t *tracks = libvlc_audio_get_track_description( instance, &ex );
+ NSMutableArray *tempArray = [NSMutableArray array];
+ NSUInteger i;
+ for (i = 0; i < count ; i++)
+ {
+ [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
+ tracks = tracks->p_next;
+ }
+
+ return [NSArray arrayWithArray: tempArray];
+}
+
+- (void)setAudioChannel:(NSInteger)value
+{
+ libvlc_exception_t ex;
+ libvlc_exception_init( &ex );
+ libvlc_audio_set_channel( instance, value, &ex );
+ catch_exception( &ex );
}
-- (int)audioChannel
+- (NSInteger)audioChannel
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
- int result = libvlc_audio_get_channel( instance, &ex );
+ NSInteger result = libvlc_audio_get_channel( instance, &ex );
catch_exception( &ex );
return result;
}
libvlc_exception_t ex;
libvlc_exception_init( &ex );
libvlc_media_player_pause( (libvlc_media_player_t *)instance, &ex );
- catch_exception( &ex );
+
+ // fail gracefully
+ // in most cases, it's just EOF so let's stop
+ if (libvlc_exception_raised(&ex))
+ [self stop];
+
+ libvlc_exception_clear(&ex);
}
- (void)stop
{
- if( 0 && [NSThread isMainThread] )
- {
- /* Hack because we create a dead lock here, when the vout is stopped
- * and tries to recontact us on the main thread */
- /* FIXME: to do this properly we need to do some locking. We may want
- * to move that to libvlc */
- [self performSelectorInBackground:@selector(stop) withObject:nil];
- return;
- }
-
libvlc_exception_t ex;
libvlc_exception_init( &ex );
libvlc_media_player_stop((libvlc_media_player_t *)instance, &ex);
{
if( [self isSeekable] )
{
- interval = interval * 1000000;
+ interval = interval * 1000;
[self setTime: [VLCTime timeWithInt: ([[self time] intValue] - interval)]];
}
}
{
if( [self isSeekable] )
{
- interval = interval * 1000000;
+ interval = interval * 1000;
[self setTime: [VLCTime timeWithInt: ([[self time] intValue] + interval)]];
}
}
delegate = nil;
media = nil;
cachedTime = [[VLCTime nullTime] retain];
+ cachedRemainingTime = [[VLCTime nullTime] retain];
position = 0.0f;
cachedState = VLCMediaPlayerStateStopped;
/* FIXME: We may want to turn that off when none is interested by that */
libvlc_event_attach( p_em, libvlc_MediaPlayerPositionChanged, HandleMediaPositionChanged, self, &ex );
libvlc_event_attach( p_em, libvlc_MediaPlayerTimeChanged, HandleMediaTimeChanged, self, &ex );
+ libvlc_event_attach( p_em, libvlc_MediaPlayerMediaChanged, HandleMediaPlayerMediaChanged, self, &ex );
catch_exception( &ex );
}
libvlc_event_detach( p_em, libvlc_MediaPlayerEndReached, HandleMediaInstanceStateChanged, self, NULL );
libvlc_event_detach( p_em, libvlc_MediaPlayerPositionChanged, HandleMediaPositionChanged, self, NULL );
libvlc_event_detach( p_em, libvlc_MediaPlayerTimeChanged, HandleMediaTimeChanged, self, NULL );
+ libvlc_event_attach( p_em, libvlc_MediaPlayerMediaChanged, HandleMediaPlayerMediaChanged, self, NULL );
}
- (void)mediaPlayerTimeChanged:(NSNumber *)newTime
[self willChangeValueForKey:@"remainingTime"];
[cachedTime release];
cachedTime = [[VLCTime timeWithNumber:newTime] retain];
-
+ [cachedRemainingTime release];
+ double currentTime = [[cachedTime numberValue] doubleValue];
+ double remaining = currentTime / position * (1 - position);
+ cachedRemainingTime = [[VLCTime timeWithNumber:[NSNumber numberWithDouble:-remaining]] retain];
[self didChangeValueForKey:@"remainingTime"];
[self didChangeValueForKey:@"time"];
}
[self didChangeValueForKey:@"state"];
}
+- (void)mediaPlayerMediaChanged:(VLCMedia *)newMedia
+{
+ [self willChangeValueForKey:@"media"];
+ if (media != newMedia)
+ {
+ [media release];
+ media = [newMedia retain];
+ }
+ [self didChangeValueForKey:@"media"];
+}
+
@end