فهرست منبع

MacOSX/Framework: Merge Enrique Osuna's work on the Framework.

Pierre d'Herbemont 17 سال پیش
والد
کامیت
107721354b

+ 11 - 7
Headers/Internal/VLCEventManager.h

@@ -26,18 +26,22 @@
 #import <pthread.h>
 
 /* This object is here to ensure safe inter thread communication */
-
 @interface VLCEventManager : NSObject
 {
-    NSMutableArray *    messageQueue;
-    pthread_t           dispatcherThread;
-    pthread_mutex_t     queueLock;
-    pthread_cond_t      signalData;
+    NSMutableArray  *messageQueue;
+    pthread_t        dispatcherThread;
+    pthread_mutex_t  queueLock;
+    pthread_cond_t   signalData;
 }
 
 /* Return the default manager */
 + (id)sharedManager;
 
-- (void)callOnMainThreadDelegateOfObject:(id)aTarget withDelegateMethod:(SEL)aSelector withNotificationName:(NSString *)aNotificationName;
-- (void)callOnMainThreadObject:(id)aTarget withMethod:(SEL)aSelector withArgumentAsObject: (id)arg;
+- (void)callOnMainThreadDelegateOfObject:(id)aTarget 
+					  withDelegateMethod:(SEL)aSelector 
+					withNotificationName:(NSString *)aNotificationName;
+- (void)callOnMainThreadObject:(id)aTarget 
+					withMethod:(SEL)aSelector 
+		  withArgumentAsObject:(id)arg;
+
 @end

+ 75 - 0
Headers/Internal/VLCLibVLCBridging.h

@@ -0,0 +1,75 @@
+/*****************************************************************************
+* VLCLibVLCbridging.h: VLC.framework VLCLibVLCBridging header
+*****************************************************************************
+* Copyright (C) 2007 Pierre d'Herbemont
+* Copyright (C) 2007 the VideoLAN team
+* $Id: VLCEventManager.h 21564 2007-08-29 21:09:27Z pdherbemont $
+*
+* Authors: Pierre d'Herbemont <pdherbemont # 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
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+*****************************************************************************/
+
+// TODO: Documentation
+@interface VLCMediaList (LibVLCBridging)
+
++ (id)medialistWithLibVLCMediaList:(void *)p_new_mlist;
+- (id)initWithLibVLCMediaList:(void *)p_new_mlist;
+- (void *)libVLCMediaList;
+
+@end
+
+/**
+* Bridges functionality between libvlc and VLCMedia implementation.
+ */
+@interface VLCMedia (LibVLCBridging)
+
+/* Object Factory */
+/**
+ * Manufactures new object wrapped around specified media descriptor.
+ * \param md LibVLC media descriptor pointer.
+ * \return Newly created media instance using specified descriptor.
+ */
++ (id)mediaWithLibVLCMediaDescriptor:(void *)md;
+
+/**
+ * Initializes new object wrapped around specified media descriptor.
+ * \param md LibVLC media descriptor pointer.
+ * \return Newly created media instance using specified descriptor.
+ */
+- (id)initWithLibVLCMediaDescriptor:(void *)md;
+
+/**
+ * Returns the receiver's internal media descriptor pointer.
+ * \return The receiver's internal media descriptor pointer.
+ */
+- (void *)libVLCMediaDescriptor;
+
+@end
+
+// TODO: Documentation
+@interface VLCMedia (VLCMediaPlayerBridging)
+
+- (void)setLength:(VLCTime *)value;
+
+@end
+
+// TODO: Documentation
+@interface VLCLibrary (VLCAudioBridging)
+
+- (void)setAudio:(VLCAudio *)value;
+
+@end
+

+ 22 - 33
Headers/Internal/VLCLibrary.h

@@ -22,47 +22,36 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-
 #import <Cocoa/Cocoa.h>
+#import "VLCAudio.h"
+#import "VLCMediaList.h"
+#import "VLCMedia.h"
 
-#include <vlc/libvlc.h>
-#include <vlc/libvlc_structures.h>
-
-#import <VLC/VLCPlaylist.h>
-
-/*
- * VLCLibrary object
- */
-
-@interface VLCLibrary : NSObject
-+ (libvlc_instance_t *)sharedInstance;
-@end
+@class VLCAudio;
 
 /*
- * Utility function
+ * VLCLibrary object.  Internal use only.
  */
-#define quit_on_exception( ex ) __quit_on_exception( ex, __FUNCTION__, __FILE__, __LINE__ )
-static inline void __quit_on_exception( libvlc_exception_t * ex, const char * function, const char * file, int line_number )
+// TODO: Documentation
+@interface VLCLibrary : NSObject 
 {
-    if (libvlc_exception_raised( ex ))
-    {
-        /* XXX: localization */
-        NSRunCriticalAlertPanel( @"Error", [NSString stringWithFormat:@"libvlc has thrown us an error: %s (%s:%d %s)", libvlc_exception_get_message(ex), file, line_number, function], @"Quit", nil, nil );
-        exit( ex->i_code );
-    }
+	void *instance;
+	VLCAudio *audio;
 }
 
-/*
- * LibVLCBridging category
- */
+/* Factories */
++ (VLCLibrary *)sharedLibrary;
++ (void *)sharedInstance;
 
-@interface VLCPlaylist (LibVLCBridging)
-+ (id) playlistWithLibVLCMediaList: (libvlc_media_list_t *)p_new_mlist;
-- (libvlc_media_list_t *) libVLCMediaList;
-@end
+/* Properties */
+- (void *)instance;
+- (VLCAudio *)audio;
 
-@interface VLCMedia (LibVLCBridging)
-- (id) initWithLibVLCMediaDescriptor:  (libvlc_media_descriptor_t *)p_md;
-+ (id) mediaWithLibVLCMediaDescriptor: (libvlc_media_descriptor_t *)p_md;
-- (libvlc_media_descriptor_t *) libVLCMediaDescriptor;
 @end
+
+/*
+ * Utility function
+ */
+// TODO: Figure out a better way to raise error messages
+#define quit_on_exception( ex ) __quit_on_exception( (void*)(ex), __FUNCTION__, __FILE__, __LINE__ )
+extern void __quit_on_exception( void* e, const char *function, const char *file, int line_number );

+ 7 - 6
Headers/VLC/VLC.h

@@ -25,15 +25,16 @@
 #ifndef VLC_FRAMEWORK_VLC_H
 #define VLC_FRAMEWORK_VLC_H
 
-typedef void * _opaque_ptr;
-
 #import <VLC/VLCMedia.h>
-#import <VLC/VLCMediaDiscoverer.h>
 #import <VLC/VLCMediaLibrary.h>
-#import <VLC/VLCPlaylist.h>
-#import <VLC/VLCPlaylistDataSource.h>
-#import <VLC/VLCServicesDiscoverer.h>
+#import <VLC/VLCMediaList.h>
 #import <VLC/VLCTime.h>
 #import <VLC/VLCVideoView.h>
 
+@class VLCMedia;
+@class VLCMediaLibrary;
+@class VLCMediaList;
+@class VLCTime;
+@class VLCVideoView;
+
 #endif /* VLC_FRAMEWORK_VLC_H */

+ 52 - 0
Headers/Public/VLCAudio.h

@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * VLCAudio.h: VLC.framework VLCAudio header
+ *****************************************************************************
+ * Copyright (C) 2007 Faustino E. Osuna
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Faustino E. Osuna <enrique.osuna # gmail.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#import "VLCLibrary.h"
+
+/* Notification Messages */
+/**
+ * Standard notification messages that are emitted by VLCMedia object.
+ */
+extern NSString *VLCMediaPlayerVolumeChanged;
+
+@class VLCLibrary;
+
+// TODO: Documentation
+@interface VLCAudio : NSObject 
+{
+	VLCLibrary *library;	//< Library to control audio for
+}
+
+/* Initializers */
+- (id)initWithLibrary:(VLCLibrary *)library;
+
+/* Properties */
+- (void)setMute:(BOOL)value;
+- (BOOL)isMuted;
+
+- (void)setVolume:(int)value;
+- (int)volume;
+
+@end

+ 197 - 0
Headers/Public/VLCMedia.h

@@ -0,0 +1,197 @@
+/*****************************************************************************
+ * VLCMedia.h: VLC.framework VLCMedia header
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#import "VLCMediaList.h"
+#import "VLCTime.h"
+
+/* Meta Dictionary Keys */
+/**
+ * Standard dictionary keys for retreiving meta data.
+ */
+extern NSString *VLCMetaInformationTitle;	    /* NSString */
+extern NSString *VLCMetaInformationArtist;	    /* NSString */
+extern NSString *VLCMetaInformationTitle;       /* NSString */
+extern NSString *VLCMetaInformationArtist;		/* NSString */
+extern NSString *VLCMetaInformationGenre;		/* NSString */
+extern NSString *VLCMetaInformationCopyright;	/* NSString */
+extern NSString *VLCMetaInformationAlbum;		/* NSString */
+extern NSString *VLCMetaInformationTrackNumber;	/* NSString */
+extern NSString *VLCMetaInformationDescription;	/* NSString */
+extern NSString *VLCMetaInformationRating;		/* NSString */
+extern NSString *VLCMetaInformationDate;		/* NSString */
+extern NSString *VLCMetaInformationSetting;		/* NSString */
+extern NSString *VLCMetaInformationURL;			/* NSString */
+extern NSString *VLCMetaInformationLanguage;	/* NSString */
+extern NSString *VLCMetaInformationNowPlaying;	/* NSString */
+extern NSString *VLCMetaInformationPublisher;	/* NSString */
+extern NSString *VLCMetaInformationEncodedBy;	/* NSString */
+extern NSString *VLCMetaInformationArtworkURL;	/* NSString */
+extern NSString *VLCMetaInformationArtwork;     /* NSImage  */
+extern NSString *VLCMetaInformationTrackID;		/* NSString */
+
+/* Notification Messages */
+/**
+ * Available notification messages.
+ */
+extern NSString *VLCMediaMetaChanged;		//< Notification message for when the media's meta data has changed
+
+// Forward declarations, supresses compiler error messages
+@class VLCMediaList;
+@class VLCMedia;
+
+/**
+ * Informal protocol declaration for VLCMedia delegates.  Allows data changes to be
+ * trapped.
+ */
+@protocol VLCMediaDelegate
+
+// TODO: SubItemAdded/SubItemRemoved implementation.  Not sure if we really want to implement this.
+///**
+// * Delegate method called whenever a sub item has been added to the specified VLCMedia.
+// * \param aMedia The media resource that has received the new sub item.
+// * \param childMedia The new sub item added.
+// * \param index Location of the new subitem in the aMedia's sublist.
+// */
+// - (void)media:(VLCMedia *)media addedSubItem:(VLCMedia *)childMedia atIndex:(int)index;
+
+///**
+// * Delegate method called whenever a sub item has been removed from the specified VLCMedia.
+// * \param aMedia The media resource that has had a sub item removed from.
+// * \param childMedia The sub item removed.
+// * \param index The previous location of the recently removed sub item.
+// */
+// - (void)media:(VLCMedia *)aMedia removedSubItem:(VLCMedia *)childMedia atIndex:(int)index;
+
+/**
+ * Delegate method called whenever the meta has changed for the receiver.
+ * \param aMedia The media resource whose meta data has been changed.
+ * \param oldValue The old meta data value.
+ * \param key The key of the value that was changed.
+ */
+- (void)media:(VLCMedia *)aMedia metaValueChangedFrom:(id)oldValue forKey:(NSString *)key;
+
+@end
+
+/**
+ * Defines files and streams as a managed object.  Each media object can be 
+ * administered seperately.  VLCMediaPlayer or VLCMediaControl must be used 
+ * to execute the appropriate playback functions.
+ * \see VLCMediaPlayer
+ * \see VLCMediaControl
+ */
+@interface VLCMedia : NSObject
+{
+    void				*p_md;				//< Internal media descriptor instance
+    NSString			*url;				//< URL for this media resource
+    VLCMediaList		*subitems;			//< Sub list of items
+	VLCTime				*length;			//< Duration of the media
+    NSMutableDictionary *metaDictionary;	//< Meta data storage
+	id					 delegate;			//< Delegate object
+	BOOL				 preparsed;			//< Value used to determine of the file has been preparsed
+}
+
+/* Object Factories */
+/**
+ * Manufactures a new VLCMedia object using the URL specified.  Will return nil if
+ * the specified URL references a directory that does not comply with DVD file 
+ * structure.
+ * \param anURL URL to media to be accessed.
+ * \return A new VLCMedia object, only if there were no errors.  This object 
+ * will be automatically released.
+ * \see initWithMediaURL
+ */
++ (id)mediaWithURL:(NSString *)anURL;
+
+/* Initializers */
+/**
+ * Initializes a new VLCMedia object to use the specified URL.  Will return nil if
+ * the specified URL references a directory that does not comply with DVD file
+ * structure.
+ * \param anURL URL to media to be accessed.
+ * \return A new VLCMedia object, only if there were no errors.
+ */
+- (id)initWithURL:(NSString *)anURL;
+
+/**
+ * Returns an NSComparisonResult value that indicates the lexical ordering of 
+ * the receiver and a given meda.
+ * \param media The media with which to compare with the receiver.
+ * \return NSOrderedAscending if the URL of the receiver precedes media in 
+ * lexical ordering, NSOrderedSame if the URL of the receiver and media are 
+ * equivalent in lexical value, and NSOrderedDescending if the URL of the 
+ * receiver follows media. If media is nil, returns NSOrderedDescending.
+ */
+- (NSComparisonResult)compare:(VLCMedia *)media;
+
+/* Properties */
+/**
+ * Sets the receiver's delegate.
+ * \param delegate The delegate for the receiver.
+ */
+- (void)setDelegate:(id)delegate;
+
+/**
+ * Returns the receiver's delegate
+ * \return The receiver's delegate
+ */
+- (id)delegate;
+
+/**
+ * Returns a VLCTime object describing the length of the media resource.
+ * \return The length of the media resource.
+ */
+- (VLCTime *)length;
+
+/**
+ * Returns a VLCTime object describing the length of the media resource,
+ * however, this is a blocking operation and will wait until the preparsing is
+ * completed before returning anything.
+ * \param aDate Time for operation to wait until, if there are no results
+ * before specified date then nil is returned.
+ * \return The length of the media resource, nil if it couldn't wait for it.
+ */
+- (VLCTime *)lengthWaitUntilDate:(NSDate *)aDate;
+
+- (BOOL)isPreparsed;
+
+/**
+ * Returns the URL for the receiver's media resource.
+ * \return The URL for the receiver's media resource.
+ */
+- (NSString *)url;
+
+/**
+ * Returns the receiver's sub list.
+ * \return The receiver's sub list.
+ */
+- (VLCMediaList *)subitems;
+
+/**
+ * Returns the receiver's meta data as a NSDictionary object.
+ * \return The receiver's meta data as a NSDictionary object.
+ */
+- (NSDictionary *)metaDictionary;
+
+@end

Headers/VLC/VLCMediaDiscoverer.h → Headers/Public/VLCMediaDiscoverer.h


+ 6 - 7
Headers/VLC/VLCMediaLibrary.h

@@ -23,20 +23,19 @@
  *****************************************************************************/
 
 #import <Cocoa/Cocoa.h>
-#import <VLC/VLCPlaylist.h>
+#import "VLCMediaList.h"
 
-@class VLCPlaylist;
+@class VLCMediaList;
 
 @interface VLCMediaLibrary : NSObject
 {
-    VLCPlaylist * allMedia;
-    void * mlib;
+    void *mlib;
+    VLCMediaList *allMedia;
 }
 
 + (id)sharedMediaLibrary;
 
-- (VLCPlaylist *)allMedia;
-
-- (NSArray *) playlists;
+- (VLCMediaList *)allMedia;
+- (NSArray *)playlists;
 
 @end

+ 68 - 0
Headers/Public/VLCMediaList.h

@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * VLCMediaList.h: VLC.framework VLCMediaList header
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id: VLCMediaList.h 21564 2007-08-29 21:09:27Z pdherbemont $
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCMedia.h"
+
+/* Notification Messages */
+extern NSString *VLCMediaListItemAdded;
+extern NSString *VLCMediaListItemDeleted;
+
+@class VLCMedia;
+@class VLCMediaList;
+
+// TODO: Documentation
+@protocol VLCMediaListDelegate
+
+- (void)mediaList:(VLCMediaList *) mediaAdded:(VLCMedia *)media atIndex:(int)index;
+- (void)mediaList:(VLCMediaList *) mediaRemovedAtIndex:(int)index;
+
+@end
+
+// TODO: Documentation
+@interface VLCMediaList : NSObject
+{
+    void *p_mlist;				//< Internal instance of media list
+	id delegate;                //< Delegate object
+}
+
+/* Properties */
+- (void)setDelegate:(id)value;
+- (id)delegate;
+
+/* Operations */
+- (void)lock;
+- (void)unlock;
+
+- (int)addMedia:(VLCMedia *)media;
+- (void)insertMedia:(VLCMedia *)media atIndex:(int)index;
+- (void)removeMediaAtIndex:(int)index;
+- (VLCMedia *)mediaAtIndex:(int)index;
+- (int)indexOfMedia:(VLCMedia *)media;
+- (int)count;
+
+- (NSArray *)sublists;					// I don't see why this would be useful
+//- (VLCMediaList *)flatPlaylist;		// nore this one
+//- (VLCMedia *)providerMedia;			// I have no clue what this does
+
+@end

+ 181 - 0
Headers/Public/VLCMediaPlayer.h

@@ -0,0 +1,181 @@
+/*****************************************************************************
+ * VLCMediaPlayer.h: VLC.framework VLCMediaPlayer header
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#import "VLCMedia.h"
+
+/* Notification Messages */
+extern NSString *VLCMediaPlayerTimeChanged;
+extern NSString *VLCMediaPlayerStateChanged;
+
+// TODO: Documentation
+typedef enum VLCMediaPlayerState
+{
+    VLCMediaPlayerStateStopped,		//< Player has stopped
+    VLCMediaPlayerStateOpening,		//< Stream is opening
+    VLCMediaPlayerStateBuffering,	//< Stream is buffering
+    VLCMediaPlayerStateEnded,		//< Stream has ended
+    VLCMediaPlayerStateError,		//< Player has generated an error
+    VLCMediaPlayerStatePlaying,		//< Stream is playing
+    VLCMediaPlayerStatePaused		//< Stream is paused
+} VLCMediaPlayerState;
+
+extern NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state);
+
+/**
+ * Formal protocol declaration for playback delegates.  Allows playback messages
+ * to be trapped by delegated objects.
+ */
+@protocol VLCMediaPlayerDelegate
+
+- (void)mediaPlayerTimeChanged:(NSNotification *)aNotification;
+- (void)mediaPlayerStateChanged:(NSNotification *)aNotification;
+
+@end
+
+// TODO: Should we use medialist_player or our own flavor of media player?
+@interface VLCMediaPlayer : NSObject 
+{
+	id delegate;			//< Object delegate
+	VLCVideoView *videoView;//< NSView instance where media is rendered to
+
+	void *instance;			//  Internal
+	VLCMedia *media;		//< Current media being played
+}
+
+/* Initializers */
+- (id)initWithVideoView:(VLCVideoView *)aVideoView;
+
+/* Properties */
+- (void)setDelegate:(id)value;
+- (id)delegate;
+
+/* Video View Options */
+// TODO: Should be it's own object?
+
+// TODO: use VLCVideoView instead of NSView
+- (void)setVideoView:(VLCVideoView *)value;
+- (VLCVideoView *)videoView;
+
+- (void)setFullscreen:(BOOL)value;
+- (BOOL)fullscreen;
+
+- (void)setVideoAspectRatio:(char *)value;
+- (char *)videoAspectRatio;
+- (void)setVideoSubTitles:(int)value;
+- (int)videoSubTitles;
+
+- (void)setVideoCropGeometry:(char *)value;
+- (char *)videoCropGeometry;
+
+- (void)setVideoTeleText:(int)value;
+- (int)videoTeleText;
+
+- (void)setRate:(int)value;
+- (int)rate;
+
+/* Video Information */
+- (NSSize)videoSize;
+- (BOOL)hasVideoOut;
+- (float)framesPerSecond;
+
+/**
+ * Sets the current position (or time) of the feed.
+ * \param value New time to set the current position to.  If time is [VLCTime nullTime], 0 is assumed.
+ */
+- (void)setTime:(VLCTime *)value;
+
+/** 
+ * Returns the current position (or time) of the feed.
+ * \return VLCTIme object with current time.
+ */
+- (VLCTime *)time;
+
+/* Audio Options */
+- (void)setAudioTrack:(int)value;
+- (int)audioTrack;
+
+- (void)setAudioChannel:(int)value;
+- (int)audioChannel;
+
+/* Media Options */
+- (void)setMedia:(VLCMedia *)value;
+- (VLCMedia *)media;
+
+/* Playback Operations */
+/**
+ * Plays a media resource using the currently selected media controller (or 
+ * default controller.  If feed was paused then the feed resumes at the position 
+ * it was paused in.
+ * \return A Boolean determining whether the stream was played or not.
+ */
+- (BOOL)play;
+
+/**
+ * Toggle's the pause state of the feed.
+ */
+- (void)pause;
+
+/**
+ * Fast forwards through the feed at the standard 1x rate.
+ */
+//- (void)fastForward;
+
+/**
+ * Fast forwards through the feed at the rate specified.
+ * \param rate Rate at which the feed should be fast forwarded.
+ */
+//- (void)fastForwardAtRate:(int)rate;
+
+/**
+ * Rewinds through the feed at the standard 1x rate.
+ */
+//- (void)rewind;
+
+/**
+ * Rewinds through the feed at the rate specified.
+ * \param rate Rate at which the feed should be fast rewound.
+ */
+//- (void)rewindAtRate:(int)rate;
+
+/* Playback Information */
+/**
+ * Playback state flag identifying that the stream is currently playing.
+ * \return TRUE if the feed is playing, FALSE if otherwise.
+ */
+- (BOOL)isPlaying;
+
+/**
+ * Playback state flag identifying wheather the stream will play.
+ * \return TRUE if the feed is ready for playback, FALSE if otherwise.
+ */
+- (BOOL)willPlay;
+
+/**
+ * Playback's current state.
+ * \see VLCMediaState
+ */
+- (VLCMediaPlayerState)state;
+	 
+@end

Headers/VLC/VLCPlaylist.h → Headers/Public/VLCPlaylist.h


Headers/VLC/VLCPlaylistDataSource.h → Headers/Public/VLCPlaylistDataSource.h


Headers/VLC/VLCServicesDiscoverer.h → Headers/Public/VLCServicesDiscoverer.h


+ 12 - 3
Headers/VLC/VLCTime.h

@@ -26,10 +26,19 @@
 
 @interface VLCTime : NSObject
 {
-    NSNumber * value;
+    NSNumber *value;
 }
+
++ (VLCTime *)nullTime;
++ (VLCTime *)timeWithNumber:(NSNumber *)aNumber;
+//+ (VLCTime *)timeWithString:(NSString *)aString;
+
 - (id)initWithNumber:(NSNumber *)aNumber;
+//- (id)initWithString:(NSString *)aString;
+
+- (NSNumber *)numberValue;
+- (NSString *)stringValue;
+
+- (NSComparisonResult)compare:(VLCTime *)aTime;
 
-- (NSNumber *)numberRepresentation;
-- (NSString *)stringRepresentation;
 @end

+ 83 - 0
Headers/Public/VLCVideoView.h

@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * VLCVideoView.h: VLC.framework VLCVideoView header
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+
+/* Notifications */
+extern NSString *VLCVideoViewEnteredFullScreen;
+extern NSString *VLCVideoViewLeftFullScreen;
+
+@protocol VLCVideoViewDelegate
+
+// Notifications defined in VLCVideoView.h
+- (void)videoEnteredFullscreen:(NSNotification *)aNotification;
+- (void)videoLeftFullscreen:(NSNotification *)aNotification;
+
+@end
+
+@protocol VLCOpenGLVoutEmbedding
+
+- (void)addVoutSubview:(NSView *)view;
+- (void)removeVoutSubview:(NSView *)view;
+
+- (void)enterFullscreen;
+- (void)leaveFullscreen;
+
+- (BOOL)stretchesVideo;
+
+//- (void)setOnTop: (BOOL)ontop; /* Do we really want that in protocol? */
+
+@end
+
+@interface VLCVideoView : NSView <VLCOpenGLVoutEmbedding>
+{
+	id delegate;
+	NSColor *backColor;
+	BOOL stretchesVideo;
+	
+	// TODO: Allow for view to report transparency to do some cool effects
+	// with the video?
+}
+
+- (void)setDelegate:(id)value;
+- (id)delegate;
+
+- (void)setBackColor:(NSColor *)value;
+- (NSColor *)backColor;
+
+- (void)setStretchesVideo:(BOOL)value;
+- (BOOL)stretchesVideo;
+
+- (void)addVoutSubview:(NSView *)aView;
+- (void)removeVoutSubview:(NSView *)aView;
+
+- (void)enterFullscreen;
+- (void)leaveFullscreen;
+
+//- (void)setOnTop: (BOOL)ontop; /* Do we really want that in protocol? */
+
+// The media controls that were here previously should be moved elsewhere.  This
+// View is just that, a view not a controller. -- Moved to VLCMediaPlayer
+
+@end

+ 0 - 56
Headers/VLC/VLCMedia.h

@@ -1,56 +0,0 @@
-/*****************************************************************************
- * VLCMedia.h: VLC.framework VLCMedia header
- *****************************************************************************
- * Copyright (C) 2007 Pierre d'Herbemont
- * Copyright (C) 2007 the VideoLAN team
- * $Id$
- *
- * Authors: Pierre d'Herbemont <pdherbemont # 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-#import <VLC/VLCPlaylist.h>
-
-/* Meta */
-extern NSString * VLCMetaInformationTitle; /* Associated to an NSString */
-extern NSString * VLCMetaInformationAuthor; /* Associated to an NSString */
-extern NSString * VLCMetaInformationArtwork; /* Associated to an NSImage */
-
-/* Notification */
-extern NSString * VLCMediaSubItemAdded;
-
-@class VLCPlaylist;
-
-@interface VLCMedia : NSObject
-{
-    void * md;
-    NSString * url;
-    VLCPlaylist *subitems;
-    NSMutableDictionary *metaInformation;
-}
-
-- (id)initWithURL:(NSString *)anURL;
-+ (id)mediaWithURL:(NSString *)anURL;
-
-- (void) dealloc;
-
-- (NSString *)url;
-- (VLCPlaylist *)subitems;
-
-/* Returns a dictionary with corresponding object associated with a meta */
-- (NSDictionary *)metaInformation;
-@end

+ 0 - 100
Headers/VLC/VLCVideoView.h

@@ -1,100 +0,0 @@
-/*****************************************************************************
- * VLCVideoView.h: VLC.framework VLCVideoView header
- *****************************************************************************
- * Copyright (C) 2007 Pierre d'Herbemont
- * Copyright (C) 2007 the VideoLAN team
- * $Id$
- *
- * Authors: Pierre d'Herbemont <pdherbemont # 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-
-#import <VLC/VLCTime.h>
-#import <VLC/VLCPlaylist.h>
-
-@protocol VLCVideoViewDelegate;
-
-/* Notification */
-extern NSString * VLCVideoDidChangeVolume;
-extern NSString * VLCVideoDidChangeTime;
-extern NSString * VLCVideoDidChangeCurrentlyPlayingItem;
-extern NSString * VLCVideoDidStop;
-extern NSString * VLCVideoDidPause;
-extern NSString * VLCVideoDidPlay;
-
-@interface VLCVideoView : NSView
-{
-    VLCPlaylist   * playlist;
-    NSConnection  * connection;
-    id              delegate;
-    BOOL            stretchVideo;
-
-    void * p_mi;
-    void * p_mlp;
-}
-
-- (id)initWithFrame:(NSRect)frameRect;
-- (void)dealloc;
-
-- (void)setPlaylist: (VLCPlaylist *)newPlaylist;
-- (VLCPlaylist *)playlist;
-
-/* Play */
-- (void)play;
-- (void)playItemAtIndex:(int)index;
-- (void)playMedia:(VLCMedia *)media;
-- (void)pause;
-- (void)setCurrentTime:(VLCTime *)timeObj;
-
-/* State */
-- (BOOL)isPlaying;
-- (BOOL)isPaused;
-- (VLCTime *)currentTime;
-- (id)currentPlaylistItem;
-
-/* Video output property */
-- (void)setStretchesVideo:(BOOL)flag;
-- (BOOL)stretchesVideo;
-
-/* Fullscreen */
-- (void)enterFullscreen;
-- (void)leaveFullscreen;
-
-/* Delegate */
-- (void)setDelegate: (id)newDelegate;
-- (id)delegate;
-@end
-
-@protocol VLCVideoViewDelegate
-- (void)videoDidStop:(NSNotification *)notification;
-- (void)videoDidPlay:(NSNotification *)notification;
-- (void)videoDidPause:(NSNotification *)notification;
-- (void)videoDidPlayNextPlaylistElement:(NSNotification *)notification;
-
-- (void)videoDidChangeVolume:(NSNotification *)notification;
-
-/* Returns NO if the Video shouldn't be paused */
-- (BOOL)videoWillPause:(NSNotification *)notification;
-/* Returns NO if the Video shouldn't play next playlist element */
-- (BOOL)videoWillPlayNextPlaylistElement:(NSNotification *)notification;
-
-/* Posted when the progress of the video has reached a new step
- * (every second?).
- * The -object contained in the notification is the new VLCTime */
-- (void)videoDidChangeTime:(NSNotification *)notification;
-@end

+ 2 - 162
Makefile

@@ -1,162 +1,2 @@
-CC=gcc
-CFLAGS=-g -O2
-OBJCFLAGS=-fobjc-exceptions 
-LDFLAGS=-single_module -read_only_relocs suppress
-
-# We should set this properly.
-top_srcdir=../../..
-top_builddir=../../..
-
-LIBVLC_HEADERS=$(top_srcdir)/include
-VLCCONFIG=$(top_srcdir)/vlc-config
-
-MODULES = $(patsubst %,$(SRC_DIR)/%,$(_MODULES))
-
-HEADERS_DIR = Headers
-
-_EXPORTED_HEADERS= \
-     VLC/VLC.h \
-     VLC/VLCMedia.h \
-     VLC/VLCMediaDiscoverer.h \
-     VLC/VLCMediaLibrary.h \
-     VLC/VLCPlaylist.h \
-     VLC/VLCPlaylistDataSource.h \
-     VLC/VLCServicesDiscoverer.h \
-     VLC/VLCTime.h \
-     VLC/VLCVideoView.h
-
-EXPORTED_HEADERS = $(patsubst %,$(HEADERS_DIR)/%,$(_EXPORTED_HEADERS))
-
-EXPORTED_RESOURCES= \
-     Resources/Info.plist \
-     Resources/version.plist
-
-SRC_DIR = Sources
-
-_SRC = \
-     test.m \
-     VLCEventManager.m \
-     VLCLibrary.m \
-	 VLCMedia.m \
-	 VLCMediaLibrary.m \
-     VLCMediaDiscoverer.m \
-	 VLCPlaylist.m \
-     VLCPlaylistDataSource.m \
-     VLCServicesDiscoverer.m \
-     VLCTime.m \
-     VLCVideoView.m
-
-SRC = $(patsubst %,$(SRC_DIR)/%,$(_SRC))
-
-HEADERS = $(EXPORTED_HEADERS)
-
-INCLUDES=  -I .  -I $(LIBVLC_HEADERS) -I $(HEADERS_DIR) -I $(HEADERS_DIR)/Internal
-
-FRAMEWORKS= -framework Cocoa  
-
-OBJECTS=$(SRC:.m=.o)
-
-all: VLC.framework
-
-$(OBJECTS): $(HEADERS)
-
-.m.o: $<
-	$(CC) -c $(CFLAGS) $(OBJCFLAGS) $(INCLUDES) $< -o $@
-
-DIR = VLC.framework \
-      VLC.framework/Version/Current/Framework \
-      VLC.framework/Version/Current/Headers \
-
-VLC.framework/lib/libvlc.dylib: $(top_builddir)/src/.libs/libvlc.dylib VLC.framework/lib
-	cp -f $(top_builddir)/src/.libs/libvlc.1.dylib VLC.framework/lib/libvlc.dylib && \
-	install_name_tool -id `pwd`/VLC.framework/lib/libvlc.1.dylib \
-	                   VLC.framework/lib/libvlc.dylib
-	install_name_tool -change @executable_path/lib/vlc_libintl.dylib \
-	                          `pwd`/VLC.framework/lib/vlc_libintl.dylib  $@
-
-VLC.framework/lib/libvlc-control.dylib: $(top_builddir)/src/.libs/libvlc-control.dylib VLC.framework/lib
-	mkdir -p VLC.framework/Version/Current/lib && \
-	cp -f $< $@ && \
-	install_name_tool -id `pwd`/$@ $@ && \
-	install_name_tool -change /usr/local/lib/libvlc.1.dylib \
-	                          `pwd`/VLC.framework/lib/libvlc.dylib  $@
-	install_name_tool -change @executable_path/lib/vlc_libintl.dylib \
-	                          `pwd`/VLC.framework/lib/vlc_libintl.dylib  $@
-
-
-VLC.framework/Headers: $(HEADERS)
-	mkdir -p VLC.framework/Version/Current/Headers && \
-	cp -f $(EXPORTED_HEADERS) VLC.framework/Version/Current/Headers && \
-	ln -sf Version/Current/Headers VLC.framework
-
-VLC.framework/Resources:
-	mkdir -p VLC.framework/Version/Current/Resources && \
-	cp -f $(EXPORTED_RESOURCES) VLC.framework/Version/Current/Resources && \
-	ln -sf Version/Current/Resources VLC.framework
-
-
-VLC.framework/modules:
-	/usr/bin/install -c -d ./VLC.framework/Version/Current/modules && \
-	for i in `top_builddir="$(top_builddir)" $(VLCCONFIG) --target plugin` ; do \
-	  if test -n "$$i" ; \
-        then \
-	    cp "`pwd`/`dirname $$i`/.libs/`basename $$i`.dylib" \
-	       "./VLC.framework/Version/Current/modules" ; \
-		module="./VLC.framework/Version/Current/modules/`basename $$i`.dylib"; \
-	    install_name_tool -change /usr/local/lib/libvlc.1.dylib \
-                                  @loader_path/../lib/libvlc.dylib \
-                          "$$module"; \
-	    echo "changing install name of $$module";\
-	    for lib in `otool -L "$$module" | grep @executable_path | sed 's/(\([0-z]*\ *\.*\,*\)*)//g'` ; do \
-	        install_name_tool -change "$$lib" \
-                                       `echo "$$lib" | sed 's:executable_path:loader_path/../:'` \
-                              "$$module"; \
-	    done; \
-	  fi \
-    done && \
-	ln -sf Version/Current/modules VLC.framework
-	
-
-VLC.framework/share:
-	cp -R $(top_builddir)/share ./VLC.framework/Version/Current && \
-	ln -sf Version/Current/share ./VLC.framework
-
-VLC.framework/lib: 
-	mkdir -p VLC.framework/Version/Current/lib && \
-	if test -d $(top_builddir)/extras/contrib/vlc-lib; then \
-	  for i in $(top_builddir)/extras/contrib/vlc-lib/*.dylib ; do \
-		module="VLC.framework/Version/Current/lib/`basename $${i}`"; \
-	    cp `pwd`/$${i}  $${module} ; \
-		install_name_tool -change /usr/local/lib/libvlc.1 @loader_path/../lib/libvlc.dylib \
-		                  $${module}; \
-	    echo "changing install name of $$module";\
-	    for lib in `otool -L "$$module" | grep @executable_path | sed 's/(\([0-z]*\ *\.*\,*\)*)//g'` ; do \
-	        install_name_tool -change "$$lib" \
-                                       `echo "$$lib" | sed 's:executable_path:loader_path/../:'` \
-                              "$$module"; \
-	    done; \
-	  done \
-    fi && \
-	ln -sf Version/Current/lib VLC.framework
-    
-VLC.framework/VLC:
-	ln -sf Version/Current/VLC VLC.framework
-
-VLC.framework/Version/Current/VLC: $(OBJECTS) VLC.framework/Headers VLC.framework/Resources VLC.framework/lib/libvlc-control.dylib VLC.framework/lib/libvlc.dylib VLC.framework/modules VLC.framework/share VLC.framework/VLC
-	mkdir -p VLC.framework/Version/Current/Framework && \
-	$(CXX) -dynamiclib $(LDFLAGS) $(OBJECTS) $(FRAMEWORKS) -LVLC.framework/lib -lvlc -lvlc-control $(MODULES) $(LIBS) -install_name @loader_path/../Frameworks/VLC.framework/Version/Current/VLC -o VLC.framework/Version/Current/VLC && \
-	install_name_tool -change `pwd`/VLC.framework/lib/libvlc-control.0.dylib \
-	                          `pwd`/VLC.framework/lib/libvlc-control.dylib \
-	                   VLC.framework/Version/Current/VLC && \
-	install_name_tool -change `pwd`/VLC.framework/lib/libvlc.1.dylib \
-	                          `pwd`/VLC.framework/lib/libvlc.dylib \
-	                   VLC.framework/Version/Current/VLC && \
-	touch VLC.framework
-
-VLC.framework:: VLC.framework/Version/Current/VLC
- 
-.PHONY: clean
-
-clean:
-	rm -Rf VLC.framework
-	rm -Rf $(OBJECTS) *.o $(SRC_DIR)/*.o
+all:
+	xcodebuild

+ 242 - 0
Pre-Compile.sh

@@ -0,0 +1,242 @@
+if [ ${ACTION} = "" ]; then
+	# Debug --
+	TARGET_BUILD_DIR="."
+	FULL_PRODUCT_NAME="VLC.framework"
+	CONTENTS_FOLDER_PATH="${FULL_PRODUCT_NAME}/Versions/A"
+	VLC_BUILD_DIR="../../.."
+	VLC_SRC_DIR="../../.."
+	# Debug --
+fi
+
+if [ ${ACTION} = "build" ]; then	
+	vlc_config="${VLC_SRC_DIR}/vlc-config"
+	lib="lib"
+	modules="modules"
+	target="${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}"
+	target_lib="${target}/${lib}"			# Should we consider using a different well-known folder like shared resources?
+	target_modules="${target}/${modules}"	# Should we consider using a different well-known folder like shared resources?
+	
+    ##########################
+    # @function install_library(src_lib, dest_dir)
+	# @description Installs the specified library into the destination folder, automatically changes the references to dependencies
+	# @param src_lib 	source library to copy to the destination directory
+	# @param dest_dir	destination directory where the src_lib should be copied to
+	install_library() {	
+		if [ ${3} = "library" ]; then
+			install_name="@loader_path/lib"
+		else
+			install_name="@loader_path/modules"
+		fi
+		
+		if [ "${4}" != "" ]; then
+			lib_dest="${2}/${4}"
+		else
+			lib_dest="${2}/`basename ${1}`"
+		fi
+		
+		if test -e ${1} && ! test -e ${lib_dest}; then
+			mkdir -p ${2}
+			
+			# Lets copy the library from the source folder to our new destination folder
+			cp ${1} ${lib_dest}
+
+			# Update the dynamic library so it will know where to look for the other libraries
+			echo "Installing ${3} `basename ${lib_dest}`"
+
+			# Change the reference of libvlc.1 stored in the usr directory to libvlc.dylib in the framework's library directory
+			install_name_tool -change /usr/local/lib/libvlc.1.dylib @loader_path/../lib/libvlc.dylib ${lib_dest}
+			install_name_tool -change @executable_path/lib/vlc_libintl.dylib @loader_path/../lib/vlc_libintl.dylib ${lib_dest}
+			install_name_tool -id "${install_name}/`basename ${lib_dest}`" ${lib_dest}
+
+			# Iterate through each installed library and modify the references to other dynamic libraries to match the framework's library directory
+			for linked_lib in `otool -L "${lib_dest}" | grep @executable_path | sed 's/(\([0-z]*\ *\.*\,*\)*)//g'` ; do
+				ref_lib=`echo "${linked_lib}" | sed 's:executable_path/:loader_path/../:'`
+				install_name_tool -change ${linked_lib} ${ref_lib} ${lib_dest}
+			done
+		fi
+	}
+	# @function install_library
+    ##########################
+
+    ##########################
+	# Create a symbolic link in the root of the framework
+	mkdir -p ${target_lib}
+	mkdir -p ${target_modules}
+	
+	pushd `pwd` > /dev/null 
+	cd ${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}
+	
+	ln -sf Versions/Current/${lib} .
+	ln -sf Versions/Current/${modules} .
+	
+	popd > /dev/null 
+	# Create a symbolic link in the root of the framework
+    ##########################
+	
+    ##########################
+    # Build the library folder (Same as VLC.framework/lib in Makefile)
+	echo "Building library folder..."
+
+	# Check to see if there are any vlc libraries available
+	echo "Copying VLC libraries..."
+	if test -d ${VLC_BUILD_DIR}/extras/contrib/vlc-lib; then
+		# Iterate through the dyanmic libraries available
+		for lib_src in ${VLC_BUILD_DIR}/extras/contrib/vlc-lib/*.dylib ; do
+			install_library ${lib_src} ${target_lib} "library"
+		done
+	fi
+
+	# Check to see if there are any core libraries available
+	echo "Copying core libraries..."
+#	if test -d ${VLC_BUILD_DIR}/src/.libs; then
+#		# Iterate through all the core libraries
+#		for lib_src = ${VLC_BUILD_DIR}/src/.libs/*.dylib; do
+#			# Only install the library if it is not a symbolic link
+#			if ! test -L ${lib_src}; then
+#				echo "install_library ${lib_src} ${target_lib} `echo "${lib_src}" | sed 's:(.\d+)+.dylib:.dylib:'`"
+#			fi
+#		done
+#	fi
+
+	install_library "${VLC_BUILD_DIR}/src/.libs/libvlc.dylib" ${target_lib} "library"
+	install_library "${VLC_BUILD_DIR}/src/.libs/libvlc-control.dylib" ${target_lib} "library"
+	install_library "${VLC_BUILD_DIR}/extras/contrib/vlc-lib/vlc_libintl.dylib" ${target_lib} "library"
+    # Build the library folder
+    ##########################
+
+    ##########################
+    # Build the modules folder (Same as VLC.framework/modules in Makefile)
+	echo "Building modules folder..."
+	# Figure out what modules are available to install
+	for module in `top_builddir="${VLC_BUILD_DIR}" ${vlc_config} --target plugin` ; do
+		# Check to see that the reported module actually exists
+		if test -n ${module}; then
+			module_src="`dirname ${module}`/.libs/`basename ${module}`.dylib"
+			install_library ${module_src} ${target_modules} "module"
+		fi
+    done
+	
+    # Build the modules folder
+    ##########################
+fi
+if [ ${ACTION} = "" ]; then
+	# Debug --
+	TARGET_BUILD_DIR="."
+	FULL_PRODUCT_NAME="VLC.framework"
+	CONTENTS_FOLDER_PATH="${FULL_PRODUCT_NAME}/Versions/A"
+	VLC_BUILD_DIR="../../.."
+	VLC_SRC_DIR="../../.."
+	# Debug --
+fi
+
+if [ ${ACTION} = "build" ]; then	
+	vlc_config="${VLC_SRC_DIR}/vlc-config"
+	lib="lib"
+	modules="modules"
+	target="${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}"
+	target_lib="${target}/${lib}"			# Should we consider using a different well-known folder like shared resources?
+	target_modules="${target}/${modules}"	# Should we consider using a different well-known folder like shared resources?
+	
+    ##########################
+    # @function install_library(src_lib, dest_dir)
+	# @description Installs the specified library into the destination folder, automatically changes the references to dependencies
+	# @param src_lib 	source library to copy to the destination directory
+	# @param dest_dir	destination directory where the src_lib should be copied to
+	install_library() {	
+		if [ ${3} = "library" ]; then
+			install_name="@loader_path/lib"
+		else
+			install_name="@loader_path/modules"
+		fi
+		
+		if [ "${4}" != "" ]; then
+			lib_dest="${2}/${4}"
+		else
+			lib_dest="${2}/`basename ${1}`"
+		fi
+		
+		if test -e ${1} && ! test -e ${lib_dest}; then
+			mkdir -p ${2}
+			
+			# Lets copy the library from the source folder to our new destination folder
+			cp ${1} ${lib_dest}
+
+			# Update the dynamic library so it will know where to look for the other libraries
+			echo "Installing ${3} `basename ${lib_dest}`"
+
+			# Change the reference of libvlc.1 stored in the usr directory to libvlc.dylib in the framework's library directory
+			install_name_tool -change /usr/local/lib/libvlc.1.dylib @loader_path/../lib/libvlc.dylib ${lib_dest}
+			install_name_tool -change @executable_path/lib/vlc_libintl.dylib @loader_path/../lib/vlc_libintl.dylib ${lib_dest}
+			install_name_tool -id "${install_name}/`basename ${lib_dest}`" ${lib_dest}
+
+			# Iterate through each installed library and modify the references to other dynamic libraries to match the framework's library directory
+			for linked_lib in `otool -L "${lib_dest}" | grep @executable_path | sed 's/(\([0-z]*\ *\.*\,*\)*)//g'` ; do
+				ref_lib=`echo "${linked_lib}" | sed 's:executable_path/:loader_path/../:'`
+				install_name_tool -change ${linked_lib} ${ref_lib} ${lib_dest}
+			done
+		fi
+	}
+	# @function install_library
+    ##########################
+
+    ##########################
+	# Create a symbolic link in the root of the framework
+	mkdir -p ${target_lib}
+	mkdir -p ${target_modules}
+	
+	pushd `pwd` > /dev/null 
+	cd ${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}
+	
+	ln -sf Versions/Current/${lib} .
+	ln -sf Versions/Current/${modules} .
+	
+	popd > /dev/null 
+	# Create a symbolic link in the root of the framework
+    ##########################
+	
+    ##########################
+    # Build the library folder (Same as VLC.framework/lib in Makefile)
+	echo "Building library folder..."
+
+	# Check to see if there are any vlc libraries available
+	echo "Copying VLC libraries..."
+	if test -d ${VLC_BUILD_DIR}/extras/contrib/vlc-lib; then
+		# Iterate through the dyanmic libraries available
+		for lib_src in ${VLC_BUILD_DIR}/extras/contrib/vlc-lib/*.dylib ; do
+			install_library ${lib_src} ${target_lib} "library"
+		done
+	fi
+
+	# Check to see if there are any core libraries available
+	echo "Copying core libraries..."
+#	if test -d ${VLC_BUILD_DIR}/src/.libs; then
+#		# Iterate through all the core libraries
+#		for lib_src = ${VLC_BUILD_DIR}/src/.libs/*.dylib; do
+#			# Only install the library if it is not a symbolic link
+#			if ! test -L ${lib_src}; then
+#				echo "install_library ${lib_src} ${target_lib} `echo "${lib_src}" | sed 's:(.\d+)+.dylib:.dylib:'`"
+#			fi
+#		done
+#	fi
+
+	install_library "${VLC_BUILD_DIR}/src/.libs/libvlc.dylib" ${target_lib} "library"
+	install_library "${VLC_BUILD_DIR}/src/.libs/libvlc-control.dylib" ${target_lib} "library"
+	install_library "${VLC_BUILD_DIR}/extras/contrib/vlc-lib/vlc_libintl.dylib" ${target_lib} "library"
+    # Build the library folder
+    ##########################
+
+    ##########################
+    # Build the modules folder (Same as VLC.framework/modules in Makefile)
+	echo "Building modules folder..."
+	# Figure out what modules are available to install
+	for module in `top_builddir="${VLC_BUILD_DIR}" ${vlc_config} --target plugin` ; do
+		# Check to see that the reported module actually exists
+		if test -n ${module}; then
+			module_src="`dirname ${module}`/.libs/`basename ${module}`.dylib"
+			install_library ${module_src} ${target_modules} "module"
+		fi
+    done
+	
+    # Build the modules folder
+    ##########################
+fi

+ 84 - 0
Sources/VLCAudio.m

@@ -0,0 +1,84 @@
+/*****************************************************************************
+ * VLCAudio.m: VLC.framework VLCAudio implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Faustino E. Osuna
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Faustino E. Osuna <enrique.osuna # gmail.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCAudio.h"
+#import "VLCLibVLCBridging.h"
+
+/* Notification Messages */
+NSString *VLCMediaPlayerVolumeChanged = @"VLCMediaPlayerVolumeChanged"; 
+
+/* libvlc event callback */
+// TODO: Callbacks
+
+@implementation VLCAudio
+
+- (id)init
+{
+	return nil;
+}
+
+- (id)initWithLibrary:(VLCLibrary *)aLibrary
+{
+	if (![library audio] && (self = [super init]))
+	{
+		library = aLibrary;
+		[library setAudio:self];
+	}
+	return self;
+}
+
+- (void)setMute:(BOOL)value
+{
+	libvlc_audio_set_mute([library instance], value, NULL);
+}
+
+- (BOOL)isMuted
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	BOOL result = libvlc_audio_get_mute([library instance], &ex);
+	quit_on_exception(&ex);
+	
+	return result;
+}
+
+- (void)setVolume:(int)value
+{
+	if (value < 0)
+		value = 0;
+	else if (value > 200)
+		value = 200;
+	libvlc_audio_set_volume([library instance], value, NULL);
+}
+
+- (int)volume
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	int result = libvlc_audio_get_volume([library instance], &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+@end

+ 37 - 15
Sources/VLCEventManager.m

@@ -44,13 +44,15 @@ struct message {
     enum message_type_t type;
 };
 
-@interface VLCEventManager (Private)
+@interface VLCEventManager (PrivateAPI)
+
 - (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data;
 - (void)callObjectMethodWithArgs:(NSData*)data;
 - (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName;
 - (pthread_cond_t *)signalData;
 - (pthread_mutex_t *)queueLock;
 - (NSMutableArray *)messageQueue;
+
 @end
 
 static void * EventDispatcherMainLoop(void * user_data)
@@ -68,10 +70,10 @@ static void * EventDispatcherMainLoop(void * user_data)
         pthread_mutex_lock( [self queueLock] );
         
         /* Wait until we have something on the queue */
-        if ([[self messageQueue] count] <= 0 ) do {
+        while([[self messageQueue] count] <= 0 )
+		{
             pthread_cond_wait( [self signalData], [self queueLock] );
-        } while([[self messageQueue] count] <= 0 );
-        
+		}
         message = (struct message *)[(NSData *)[[self messageQueue] lastObject] bytes];
         
         /* Don't send the same notification twice */
@@ -82,6 +84,7 @@ static void * EventDispatcherMainLoop(void * user_data)
                 message_newer = (struct message *)[(NSData *)[[self messageQueue] objectAtIndex: i] bytes];
                 if( message_newer->type != VLCNotification )
                     continue;
+				
                 if( message_newer->target == message->target && message_newer->target == message->target && [message_newer->u.name isEqualToString:message->u.name] )
                 {
                     [message_newer->target release];
@@ -106,10 +109,12 @@ static void * EventDispatcherMainLoop(void * user_data)
         pthread_mutex_unlock( [self queueLock] );
     
         [pool release];
-    }
+    };
+	return nil;
 }
 
 @implementation VLCEventManager
+
 + (id)sharedManager
 {
     /* We do want a lock here to avoid leaks */
@@ -137,33 +142,54 @@ static void * EventDispatcherMainLoop(void * user_data)
 {
     pthread_kill( dispatcherThread, SIGKILL );
     pthread_join( dispatcherThread, NULL );
+
+	[messageQueue release];
     [super dealloc];
 }
 
 - (void)callOnMainThreadDelegateOfObject:(id)aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
 {
     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-    struct message message = { [aTarget retain], aSelector, [aNotificationName retain], VLCNotification };
+    
+	struct message message = 
+	{ 
+		[aTarget retain], 
+		aSelector, 
+		[aNotificationName retain], 
+		VLCNotification 
+	};
+	
     pthread_mutex_lock( [self queueLock] );
     [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(struct message)] atIndex:0];
     pthread_cond_signal( [self signalData] );
     pthread_mutex_unlock( [self queueLock] );
+    
     [pool release];
 }
 
 - (void)callOnMainThreadObject:(id)aTarget withMethod:(SEL)aSelector withArgumentAsObject: (id)arg
 {
     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-    struct message message = { [aTarget retain], aSelector, [arg retain], VLCObjectMethodWithObjectArg };
+
+    struct message message = 
+	{ 
+		[aTarget retain], 
+		aSelector, 
+		[arg retain], 
+		VLCObjectMethodWithObjectArg 
+	};
+	
     pthread_mutex_lock( [self queueLock] );
     [[self messageQueue] insertObject:[NSData dataWithBytes:&message length:sizeof(struct message)] atIndex:0];
     pthread_cond_signal( [self signalData] );
     pthread_mutex_unlock( [self queueLock] );
+	
     [pool release];
 }
 @end
 
-@implementation VLCEventManager (Private)
+@implementation VLCEventManager (PrivateAPI)
+
 - (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data
 {
     struct message * message = (struct message *)[data bytes];
@@ -185,11 +211,11 @@ static void * EventDispatcherMainLoop(void * user_data)
     [data release];
 }
 
-
 - (NSMutableArray *)messageQueue
 {
     return messageQueue;
 }
+
 - (pthread_cond_t *)signalData
 {
     return &signalData;
@@ -202,17 +228,13 @@ static void * EventDispatcherMainLoop(void * user_data)
 
 - (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
 {
-    NSMethodSignature * aSignature;
-    NSInvocation * anInvocation;
-
-    [[NSNotificationCenter defaultCenter] postNotification: [NSNotification notificationWithName:aNotificationName object:aTarget]];
+//    [[NSNotificationCenter defaultCenter] postNotification: [NSNotification notificationWithName:aNotificationName object:aTarget]];
 
     if (![aTarget delegate] || ![[aTarget delegate] respondsToSelector: aSelector])
         return;
 
-    /* NSInvocation could maybe be prefered here */
     void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[[aTarget delegate] methodForSelector: aSelector];
     method( [aTarget delegate], aSelector, [NSNotification notificationWithName:aNotificationName object:aTarget]);
-
 }
+
 @end

+ 114 - 8
Sources/VLCLibrary.m

@@ -24,23 +24,129 @@
 
 #import "VLCLibrary.h"
 
-static libvlc_instance_t * shared_instance = NULL;
+#include <vlc/vlc.h>
+#include <vlc/libvlc_structures.h>
+
+static VLCLibrary *sharedLibrary = nil;
+
+// TODO: Change from a terminal error to raising an exception?
+void __quit_on_exception( void * e, const char * function, const char * file, int line_number )
+{
+	libvlc_exception_t *ex = (libvlc_exception_t *)e;
+    if (libvlc_exception_raised( ex ))
+    {
+        /* XXX: localization */
+        NSRunCriticalAlertPanel( @"Error", [NSString stringWithFormat:@"libvlc has thrown us an error: %s (%s:%d %s)", 
+			libvlc_exception_get_message(ex), file, line_number, function], @"Quit", nil, nil );
+        exit( ex->i_code );
+    }
+}
+
+static void *DestroySharedLibraryAtExit()
+{
+	// Destroy the shared library
+	if (sharedLibrary)
+		[sharedLibrary release];
+	sharedLibrary = nil;
+	
+	return nil;
+}
 
 @implementation VLCLibrary
-+ (libvlc_instance_t *)sharedInstance
+
++ (VLCLibrary *)sharedLibrary
+{
+	if (!sharedLibrary) 
+	{
+		// Initialize a shared instance
+		[[self alloc] init];
+		
+		// Register a function to gracefully destroy the shared library on exit.
+		atexit((void*)DestroySharedLibraryAtExit);
+	}
+	return sharedLibrary;
+}
+
++ (void *)sharedInstance
+{
+	return [[self sharedLibrary] instance];
+}
+
+- (id)init 
 {
-    if(!shared_instance)
+	if (self = [super init]) 
     {
         libvlc_exception_t ex;
-        char *lib_vlc_params[] = { "vlc", "-I", "dummy",
-                                   "--opengl-provider=minimal_macosx",
-                                   "-vvvvvv" };
         libvlc_exception_init( &ex );
         
-        shared_instance = libvlc_new( 5, lib_vlc_params, &ex );
+		// Figure out the frameworks path
+		char *applicationPath = strdup([[NSString stringWithFormat:@"%@/Versions/Current/VLC", 
+			[[NSBundle bundleForClass:[VLCLibrary class]] bundlePath]] UTF8String]);
+		// TODO: Raise error if there is no memory available
+		
+		char *lib_vlc_params[] = { 
+			applicationPath, "-I", "dummy", "-vvvv", 
+			"--opengl-provider", "minimal_macosx", 
+			"--no-video-title-show", NULL
+		};
+		
+		instance = (void *)libvlc_new(7, lib_vlc_params, &ex);
         quit_on_exception( &ex );
+		
+		if (!sharedLibrary) 
+			sharedLibrary = [[self retain] autorelease];
+		
+		// Assignment unneeded, as the audio unit will do it for us
+		/*audio = */ [[VLCAudio alloc] initWithLibrary:self];
+		
+		// free allocated resources
+		free(applicationPath);
     }
-    return shared_instance;
+	return self;
 }
+
+- (void)dealloc 
+{
+	// TODO: libvlc core locks up or has segfaults while shutting down, the 
+	// following code allows for the framework to be removed without crashing
+	// the host application.
+	@try
+	{
+		if (instance) 
+		{
+			libvlc_exception_t ex;
+			libvlc_exception_init(&ex);
+			
+			libvlc_destroy(instance, &ex);
+		}
+	}
+	@finally 
+	{
+		instance = nil;
+		[audio release];
+		[super dealloc];
+	}
+}
+
+- (void *)instance
+{
+	return instance;
+}
+
+- (VLCAudio *)audio
+{
+	return audio;
+}
+
+@end
+
+@implementation VLCLibrary (VLCAudioBridging)
+
+- (void)setAudio:(VLCAudio *)value
+{
+	if (!audio)
+		audio = value;
+}
+
 @end
 

+ 485 - 150
Sources/VLCMedia.m

@@ -22,159 +22,176 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#import <Cocoa/Cocoa.h>
-#import <VLC/VLCMedia.h>
-#import <VLC/VLCPlaylist.h>
+#import "VLCMedia.h"
+#import "VLCMediaList.h"
 #import "VLCEventManager.h"
 #import "VLCLibrary.h"
-
+#import "VLCLibVLCBridging.h"
 #include <vlc/libvlc.h>
 
-NSString * VLCMetaInformationTitle = @"title";
-NSString * VLCMetaInformationAuthor = @"author";
-NSString * VLCMetaInformationArtwork = @"artwork";
-
-/* Our notification */
-NSString * VLCMediaSubItemAdded = @"VLCMediaSubItemAdded";
-NSString * VLCMediaMetaChanged = @"VLCMediaMetaChanged";
+/* Meta Dictionary Keys */
+NSString *VLCMetaInformationTitle       = @"title";
+NSString *VLCMetaInformationArtist      = @"artist";
+NSString *VLCMetaInformationGenre       = @"genre";
+NSString *VLCMetaInformationCopyright   = @"copyright";
+NSString *VLCMetaInformationAlbum       = @"album";
+NSString *VLCMetaInformationTrackNumber = @"trackNumber";
+NSString *VLCMetaInformationDescription = @"description";
+NSString *VLCMetaInformationRating      = @"rating";
+NSString *VLCMetaInformationDate        = @"date";
+NSString *VLCMetaInformationSetting     = @"setting";
+NSString *VLCMetaInformationURL         = @"url";
+NSString *VLCMetaInformationLanguage    = @"language";
+NSString *VLCMetaInformationNowPlaying  = @"nowPlaying";
+NSString *VLCMetaInformationPublisher   = @"publisher";
+NSString *VLCMetaInformationEncodedBy   = @"encodedBy";
+NSString *VLCMetaInformationArtworkURL  = @"artworkURL";
+NSString *VLCMetaInformationArtwork     = @"artwork";
+NSString *VLCMetaInformationTrackID     = @"trackID";
 
-/* libvlc event callback */
-static void HandleMediaSubItemAdded( const libvlc_event_t * event, void * self)
-{
-    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
-                                     withDelegateMethod: @selector(subItemAdded:)
-                                     withNotificationName: VLCMediaSubItemAdded];
-}
+/* Notification Messages */
+NSString *VLCMediaMetaChanged           = @"VLCMediaMetaChanged";
+//NSString *VLCMediaSubItemAdded        = @"VLCMediaSubItemAdded";
+//NSString *VLCMediaSubItemDeleted      = @"VLCMediaSubItemDeleted";
 
 /* libvlc event callback */
-static void HandleMediaMetaChanged( const libvlc_event_t * event, void * self)
-{
-    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
-                                     withDelegateMethod: @selector(metaChanged:)
-                                     withNotificationName: VLCMediaMetaChanged];
+//static void HandleMediaSubItemAdded(const libvlc_event_t *event, void *self)
+//{
+//  [[VLCEventManager sharedManager] callOnMainThreadObject:self
+//                                               withMethod:@selector(subItemAdded:)
+//                                     withArgumentAsObject:(id)event->u.media_descriptor_subitem_added.new_child];
+//}
+//
+//static void HandleMediaSubItemDeleted(const libvlc_event_t *event, void *self)
+//{
+//  [[VLCEventManager sharedManager] callOnMainThreadObject:self
+//                                               withMethod:@selector(subItemDeleted)
+//                                     withArgumentAsObject:nil];
+//}
 
-}
-
-@interface VLCMedia (Private)
-- (void)initializeInternalMediaDescriptor;
-- (void)subItemAdded:(NSNotification *)notification;
-- (void)metaChanged:(NSNotification *)notification;
-- (void)fetchMetaInformation;
-@end
-
-@implementation VLCMedia (Private)
-- (void)initializeInternalMediaDescriptor
+static void HandleMediaMetaChanged(const libvlc_event_t *event, void *self)
 {
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subItemAdded:) name:VLCMediaSubItemAdded object:self];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(metaChanged:) name:VLCMediaMetaChanged object:self];
-    libvlc_exception_t ex;
-    libvlc_exception_init( &ex );
-    libvlc_event_manager_t * p_em = libvlc_media_descriptor_event_manager( md, &ex );
-    libvlc_event_attach( p_em, libvlc_MediaDescriptorSubItemAdded, HandleMediaSubItemAdded, self, &ex );
-    libvlc_event_attach( p_em, libvlc_MediaDescriptorMetaChanged, HandleMediaMetaChanged, self, &ex );
-    quit_on_exception( &ex );
-    libvlc_media_list_t * p_mlist = libvlc_media_descriptor_subitems( md, NULL );
-    if (!p_mlist)
-        subitems = nil;
-    else
-    {
-        subitems= [[VLCPlaylist playlistWithLibVLCMediaList: p_mlist] retain];
-        libvlc_media_list_release( p_mlist );
-    }
-    [self fetchMetaInformation];
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    
+    [[VLCEventManager sharedManager] callOnMainThreadObject:self
+                                                 withMethod:@selector(metaChanged:)
+                                       withArgumentAsObject:[NSNumber numberWithInt:(int)event->u.media_descriptor_meta_changed.meta_type]];
+    [pool release];
 }
 
-- (void)subItemAdded:(NSNotification *)notification
-{
-    if(!subitems)
-    {
-        libvlc_media_list_t * p_mlist = libvlc_media_descriptor_subitems( md, NULL );
-        [self willChangeValueForKey:@"subitems"];
-        subitems = [[VLCPlaylist playlistWithLibVLCMediaList: p_mlist] retain];
-        [self didChangeValueForKey:@"subitems"];
-        libvlc_media_list_release( p_mlist );
-    }
-}
-- (void)metaChanged:(NSNotification *)notification
+static void HandleMediaDurationChanged(const libvlc_event_t *event, void *self)
 {
-    [self fetchMetaInformation];
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    
+    //[[VLCEventManager sharedManager] callOnMainThreadObject:self
+//                                                 withMethod:@selector(setLength:)
+//                                       withArgumentAsObject:[VLCTime timeWithNumber:
+//                                           [NSNumber numberWithLongLong:event->u.media_descriptor_duration_changed.new_duration]]];
+    [pool release];
 }
 
-- (void)fetchMetaInformation
-{
-    NSMutableDictionary * temp;
-    libvlc_exception_t ex;
-    char * title;
-    char * artist;
-    char * arturl = NULL;
 
-    libvlc_exception_init( &ex );
+// TODO: Documentation
+@interface VLCMedia (PrivateAPI)
 
-    title = libvlc_media_descriptor_get_meta( md, libvlc_meta_Title, &ex );
-    quit_on_exception( &ex );
+/* Statics */
++ (libvlc_meta_t)stringToMetaType:(NSString *)string;
++ (NSString *)metaTypeToString:(libvlc_meta_t)type;
 
-    artist = libvlc_media_descriptor_get_meta( md, libvlc_meta_Artist, &ex );
-    quit_on_exception( &ex );
+/* Initializers */
+- (void)initInternalMediaDescriptor;
 
-    arturl = libvlc_media_descriptor_get_meta( md, libvlc_meta_ArtworkURL, &ex );
-    quit_on_exception( &ex );
+/* Operations */
+- (BOOL)setMetaValue:(char *)value forKey:(NSString *)key;
+- (void)fetchMetaInformation;
+- (void)fetchMetaInformationForArtWorkWithURL:(NSString *)anURL;
+- (void)notifyChangeForKey:(NSString *)key withOldValue:(id)oldValue;
 
-    temp = [NSMutableDictionary dictionaryWithCapacity: 2];
+/* Callback Methods */
+//- (void)subItemAdded:(libvlc_media_descriptor_t *)child;
+//- (void)subItemRemoved:(libvlc_media_descriptor_t *)child;
+- (void)metaChanged:(NSNumber *)metaType;
 
-    if (title)
-        [temp setObject: [NSString stringWithUTF8String: title] forKey: VLCMetaInformationTitle];
-    
-#if 0
-    /* We need to perform that in a thread because this takes long. */
-    if (arturl)
-    {
-        NSString *plainStringURL = [NSString stringWithUTF8String:arturl];
-        NSString *escapedStringURL = [plainStringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-        NSURL *aURL = [NSURL URLWithString:escapedStringURL];
-        NSImage * art =  [[NSImage alloc] initWithContentsOfURL: aURL];
-        [art autorelease];
-        if( art )
-            [temp setObject: art forKey: VLCMetaInformationArtwork];
-    }
-#endif
+@end
 
-    free( title );
-    free( artist );
-    free( arturl );
+@implementation VLCMedia
 
-    [self willChangeValueForKey:@"metaInformation"];
-    if( metaInformation )
-        [metaInformation release];
-    metaInformation = [[NSMutableDictionary alloc] initWithDictionary:temp];
-    [self didChangeValueForKey:@"metaInformation"];
++ (id)mediaWithURL:(NSString *)aURL;
+{
+    // For some unknown reason, compiler kept shooting me a warning saying:
+    //  warning: passing argument 1 of 'initWithURL:' from distinct Objective-C type
+    // Research on the net shows that the error means that the argument passed
+    // is not compatible with the expected argument.  Doesn't make sense, however
+    // the warning goes away when it is casted it with "id".
+    return [[[VLCMedia alloc] initWithURL:(id)aURL] autorelease];
 }
-@end
 
-@implementation VLCMedia
-- (id)initWithURL:(NSString *)anURL
+- (id)initWithURL:(NSString *)aURL
 {
+    // Parse the URL
+    NSString *scheme;   // Everything before ://, defaults to file if not present
+    NSString *path;     // Everything after ://
+    NSRange range;
+    
+    range = [aURL rangeOfString:@"://"];
+    if (range.length > 0)
+    {
+        scheme = [aURL substringToIndex:range.location];
+    }
+    else
+    {
+        scheme = @"file";
+        range.location = 0;
+    }
+    path = [aURL substringFromIndex:NSMaxRange(range)];
+    
+    if ([scheme isEqualToString:@"file"]) 
+    {
+        BOOL isDirectory;
+        path = [path stringByExpandingTildeInPath];
+        
+        // Check to see if it's a file or url
+        NSString *videoTSPath = path;
+        if ([[NSFileManager defaultManager] fileExistsAtPath:videoTSPath isDirectory:&isDirectory] && isDirectory)
+        {
+            if ([[videoTSPath lastPathComponent] compare:@"VIDEO_TS"] != NSOrderedSame)
+                videoTSPath = [videoTSPath stringByAppendingPathComponent:@"VIDEO_TS/"];
+            videoTSPath = [videoTSPath stringByAppendingPathComponent:@"VIDEO_TS.VOB"];
+            
+            // The url is a directory should we check for a DVD directory structure?
+            if ([[NSFileManager defaultManager] fileExistsAtPath:videoTSPath isDirectory:&isDirectory] && !isDirectory)
+                /* do nothing because this is a DVD */;
+            else
+                // TODO: Should we search for playable items?
+                // This is not a playable file
+                return nil;
+        }
+    }
+    
     if (self = [super init])
     {
+        url = [[NSString stringWithFormat:@"%@://%@", scheme, path] retain];
+        
         libvlc_exception_t ex;
-        url = [anURL copy];
-
-        libvlc_exception_init( &ex );
+        libvlc_exception_init(&ex);
         
-        md = libvlc_media_descriptor_new( [VLCLibrary sharedInstance],
-                                          [anURL cString],
-                                          &ex );
-        quit_on_exception( &ex );
-        metaInformation = nil;
-        [self initializeInternalMediaDescriptor];
+        p_md = libvlc_media_descriptor_new([VLCLibrary sharedInstance],
+                                           [url cString],
+                                           &ex);
+        quit_on_exception(&ex);
+        
+        delegate = nil;
+        metaDictionary = nil;
+        
+        // This value is set whenever the demuxer figures out what the length is.
+        // TODO: Easy way to tell the length of the movie without having to instiate the demuxer.  Maybe cached info?
+        length = nil;
+
+        [self initInternalMediaDescriptor];
     }
     return self;
 }
 
-+ (id)mediaWithURL:(NSString *)anURL;
-{
-    return [[(VLCMedia*)[VLCMedia alloc] initWithURL: anURL ] autorelease];
-}
-
 - (void)release
 {
     @synchronized(self)
@@ -184,74 +201,392 @@ static void HandleMediaMetaChanged( const libvlc_event_t * event, void * self)
             /* We must make sure we won't receive new event after an upcoming dealloc
              * We also may receive a -retain in some event callback that may occcur
              * Before libvlc_event_detach. So this can't happen in dealloc */
-            libvlc_event_manager_t * p_em = libvlc_media_descriptor_event_manager( md, NULL );
-            libvlc_event_detach( p_em, libvlc_MediaDescriptorSubItemAdded, HandleMediaSubItemAdded, self, NULL );
-            libvlc_event_detach( p_em, libvlc_MediaDescriptorMetaChanged, HandleMediaMetaChanged, self, NULL );
+            libvlc_event_manager_t *p_em = libvlc_media_descriptor_event_manager(p_md, NULL);
+//            libvlc_event_detach(p_em, libvlc_MediaDescriptorSubItemAdded,    HandleMediaSubItemAdded,    self, NULL);
+//            libvlc_event_detach(p_em, libvlc_MediaDescriptorSubItemDeleted,  HandleMediaSubItemAdded,    self, NULL);
+//            libvlc_event_detach(p_em, libvlc_MediaDescriptorMetaChanged,     HandleMediaMetaChanged,     self, NULL);
+//            libvlc_event_detach(p_em, libvlc_MediaDescriptorDurationChanged, HandleMediaDurationChanged, self, NULL);
         }
         [super release];
     }
 }
 
-- (void) dealloc
+- (void)dealloc
 {
-    if( subitems )
-        [subitems release];
-    if( metaInformation )
-        [metaInformation release];
-    libvlc_media_descriptor_release( md );
+    // Testing to see if the pointer exists is not required, if the pointer is null
+    // then the release message is not sent to it.
+    [self setDelegate:nil];
+    [self setLength:nil];
+
     [url release];
+    [subitems release];
+    [metaDictionary release];
+    
+    libvlc_media_descriptor_release(p_md);
+
     [super dealloc];
 }
 
+- (NSString *)description
+{
+    NSString *result = nil;
+    if (metaDictionary)
+        result = [metaDictionary objectForKey:VLCMetaInformationTitle];
+    return (result ? result : url);
+}
+
+- (NSComparisonResult)compare:(VLCMedia *)media
+{
+    if (self == media)
+        return NSOrderedSame;
+    else if (!media)
+        return NSOrderedDescending;
+    else
+        return [[self url] compare:[media url]];
+}
+
 - (NSString *)url
 {
     return [[url copy] autorelease];
 }
 
-- (VLCPlaylist *)subitems
+- (VLCMediaList *)subitems
 {
     return subitems;
 }
 
-/* Returns a dictionary with corresponding object associated with a meta */
-- (NSDictionary *)metaInformation
+- (VLCTime *)length
 {
-    return metaInformation;
+    // TODO: Value is updated whenever the item is updated in the libvlc 
+    // (var_Addcallback(instance, "item-changed", callback)) would work but 
+    // that's not authorized from here.
+    if (!length) 
+    {
+        // Try figuring out what the length is
+        long long duration = libvlc_media_descriptor_get_duration(p_md, NULL);
+        if (duration > -1) 
+        {
+            [self setLength:[VLCTime timeWithNumber:[NSNumber numberWithLongLong:duration]]];
+            return [[length retain] autorelease];
+        } 
+    }
+    return [VLCTime nullTime];
+}
+
+#define CLOCK_FREQ      1000000
+#define THREAD_SLEEP    ((long long)(0.010*CLOCK_FREQ))
+
+- (VLCTime *)lengthWaitUntilDate:(NSDate *)aDate
+{
+    if (![url hasPrefix:@"file://"])
+        return [self length];
+    else if (!length)
+    {
+        while (!length && ![self isPreparsed] && [aDate timeIntervalSinceNow] > 0)
+        {
+            usleep(THREAD_SLEEP);
+        }
+        
+        // So we're done waiting, but sometimes we trap the fact that the parsing
+        // was done before the length gets assigned, so lets go ahead and assign
+        // it ourselves.
+        if (!length)
+            return [self length];
+    }
+    return [[length retain] autorelease];
 }
-/* Not supported yet */
+
+- (BOOL)isPreparsed
+{
+    return libvlc_media_descriptor_is_preparsed(p_md, NULL);
+}
+
+- (NSDictionary *)metaDictionary
+{
+    return metaDictionary;
+}
+
+- (void)setDelegate:(id)value
+{
+    delegate = value;
+}
+
 - (id)delegate
 {
-    return nil;
+    return delegate;
 }
+
 @end
 
 @implementation VLCMedia (LibVLCBridging)
-- (id) initWithLibVLCMediaDescriptor: (libvlc_media_descriptor_t *)p_md
+
++ (id)mediaWithLibVLCMediaDescriptor:(void *)md
+{
+    libvlc_exception_t ex;
+    libvlc_exception_init( &ex );
+    
+    VLCMedia *media = (VLCMedia *)libvlc_media_descriptor_get_user_data(md, &ex);
+    if (!media || libvlc_exception_raised(&ex))
+    {
+        libvlc_exception_clear(&ex);
+        return [[[VLCMedia alloc] initWithLibVLCMediaDescriptor:md] autorelease];
+    }
+    else
+    {
+        return media;
+    }
+}
+
+- (id)initWithLibVLCMediaDescriptor:(void *)md
 {
+    libvlc_exception_t ex;
+    libvlc_exception_init( &ex );
+
+    // Core hacks that allows for native objects to be paired with core objects.  Otherwise, a native object
+    // would be recreated every time we want to address the media descriptor.  This eliminates the need
+    // for maintaining local copies of core objects.
+    if ((self = (id)libvlc_media_descriptor_get_user_data(md, &ex)) && !libvlc_exception_raised(&ex))
+    {
+        return [self retain];
+    }
+    libvlc_exception_clear(&ex);    // Just in case an exception was raised, lets release it
+    
     if (self = [super init])
     {
-        libvlc_exception_t ex;
         char * p_url;
-        libvlc_exception_init( &ex );
-
-        p_url = libvlc_media_descriptor_get_mrl( p_md, &ex );
+        
+        p_url = libvlc_media_descriptor_get_mrl(md, &ex);
         quit_on_exception( &ex );
-        url = [[NSString stringWithCString: p_url] retain];
-        libvlc_media_descriptor_retain( p_md );   
-        md = p_md;
-        [self initializeInternalMediaDescriptor];
+        
+        url = [NSString stringWithCString:p_url];
+        
+        libvlc_media_descriptor_retain(md);
+        p_md = md;
+        
+        [self initInternalMediaDescriptor];
     }
     return self;
 }
 
-+ (id) mediaWithLibVLCMediaDescriptor: (libvlc_media_descriptor_t *)p_md
+- (void *)libVLCMediaDescriptor
 {
-    return [[[VLCMedia alloc] initWithLibVLCMediaDescriptor: p_md] autorelease];
+    return p_md;
 }
 
-- (libvlc_media_descriptor_t *) libVLCMediaDescriptor
+@end
+
+@implementation VLCMedia (PrivateAPI)
+
+#define VLCStringToMeta( name, string ) if ([VLCMetaInformation##name compare:string] == NSOrderedSame) return libvlc_meta_##name;
+#define VLCMetaToString( name, type )   if (libvlc_meta_##name == type) return VLCMetaInformation##name;
+
++ (libvlc_meta_t)stringToMetaType:(NSString *)string
+{
+    VLCStringToMeta(Title, string);
+    VLCStringToMeta(Artist, string);
+    VLCStringToMeta(Genre, string);
+    VLCStringToMeta(Copyright, string);
+    VLCStringToMeta(Album, string);
+    VLCStringToMeta(TrackNumber, string);
+    VLCStringToMeta(Description, string);
+    VLCStringToMeta(Rating, string);
+    VLCStringToMeta(Date, string);
+    VLCStringToMeta(Setting, string);
+    VLCStringToMeta(URL, string);
+    VLCStringToMeta(Language, string);
+    VLCStringToMeta(NowPlaying, string);
+    VLCStringToMeta(Publisher, string);
+    VLCStringToMeta(ArtworkURL, string);
+    VLCStringToMeta(TrackID, string);
+    return -1;
+}
+
++ (NSString *)metaTypeToString:(libvlc_meta_t)type
+{
+    VLCMetaToString(Title, type);
+    VLCMetaToString(Artist, type);
+    VLCMetaToString(Genre, type);
+    VLCMetaToString(Copyright, type);
+    VLCMetaToString(Album, type);
+    VLCMetaToString(TrackNumber, type);
+    VLCMetaToString(Description, type);
+    VLCMetaToString(Rating, type);
+    VLCMetaToString(Date, type);
+    VLCMetaToString(Setting, type);
+    VLCMetaToString(URL, type);
+    VLCMetaToString(Language, type);
+    VLCMetaToString(NowPlaying, type);
+    VLCMetaToString(Publisher, type);
+    VLCMetaToString(ArtworkURL, type);
+    VLCMetaToString(TrackID, type);
+    return nil;
+}
+
+- (void)initInternalMediaDescriptor
 {
-    libvlc_media_descriptor_retain( md );
-    return md;
+    libvlc_exception_t ex;
+    libvlc_exception_init(&ex);
+    
+    libvlc_media_descriptor_set_user_data(p_md, (void*)self, &ex);
+    quit_on_exception(&ex);
+    
+    // TODO: Should these events be caught by VLCMediaList's notification hooks?
+    libvlc_event_manager_t *p_em = libvlc_media_descriptor_event_manager(p_md, &ex);
+//    libvlc_event_attach(p_em, libvlc_MediaDescriptorSubItemAdded,    HandleMediaSubItemAdded,    self, &ex);
+//    libvlc_event_attach(p_em, libvlc_MediaDescriptorSubItemRemoved,  HandleMediaSubItemRemoved,  self, &ex);
+//    libvlc_event_attach(p_em, libvlc_MediaDescriptorMetaChanged,     HandleMediaMetaChanged,     self, &ex);
+//    libvlc_event_attach(p_em, libvlc_MediaDescriptorDurationChanged, HandleMediaDurationChanged, self, &ex);
+    quit_on_exception(&ex);
+    
+    libvlc_media_list_t *p_mlist = libvlc_media_descriptor_subitems(p_md, NULL);
+    if (!p_mlist)
+        subitems = nil;
+    else
+    {
+        [subitems release];
+        subitems = [[VLCMediaList medialistWithLibVLCMediaList:p_mlist] retain];
+        libvlc_media_list_release(p_mlist);
+    }
+    [self fetchMetaInformation];
 }
-@end
+
+- (BOOL)setMetaValue:(char *)value forKey:(NSString *)key
+{
+    BOOL result = NO;
+    
+    NSString *oldValue = [metaDictionary valueForKey:key];
+    if ((!oldValue && value) || (oldValue && !value) || (oldValue && value && [oldValue compare:[NSString stringWithCString:value]] != NSOrderedSame))
+    {
+        if (!metaDictionary)
+            metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3];
+
+        if (value)
+            [metaDictionary setValue:[NSString stringWithCString:value] forKeyPath:key];
+        else
+            [metaDictionary setValue:nil forKeyPath:key];
+        
+        if ([key compare:VLCMetaInformationArtworkURL] == NSOrderedSame)
+        {
+            if ([metaDictionary valueForKey:VLCMetaInformationArtworkURL])
+            {
+                // Initialize a new thread
+                [NSThread detachNewThreadSelector:@selector(fetchMetaInformationForArtWorkWithURL:) 
+                                         toTarget:self
+                                       withObject:[metaDictionary valueForKey:VLCMetaInformationArtworkURL]];
+            }
+        }
+        result = YES;
+    }
+    free(value);
+    return result;
+}
+
+- (void)fetchMetaInformation
+{
+    // TODO: Only fetch meta data that has been requested.  Just don't fetch
+    // it, just because.
+    
+    [self setMetaValue:libvlc_media_descriptor_get_meta(p_md, libvlc_meta_Title,      NULL) forKey:[VLCMedia metaTypeToString:libvlc_meta_Title]];
+    [self setMetaValue:libvlc_media_descriptor_get_meta(p_md, libvlc_meta_Artist,     NULL) forKey:[VLCMedia metaTypeToString:libvlc_meta_Artist]];
+    [self setMetaValue:libvlc_media_descriptor_get_meta(p_md, libvlc_meta_ArtworkURL, NULL) forKey:[VLCMedia metaTypeToString:libvlc_meta_ArtworkURL]];
+}
+
+- (void)fetchMetaInformationForArtWorkWithURL:(NSString *)anURL
+{
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    @try
+    {
+        // Go ahead and load up the art work
+        NSURL *artUrl = [NSURL URLWithString:[anURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+        NSImage *art  = [[[NSImage alloc] initWithContentsOfURL:artUrl] autorelease]; 
+        
+        // If anything was found, lets save it to the meta data dictionary
+        if (art)
+        {
+            @synchronized(metaDictionary)
+            {
+                [metaDictionary setObject:art forKey:VLCMetaInformationArtwork];
+            }
+            
+            // Let the world know that there is new art work available
+            [self notifyChangeForKey:VLCMetaInformationArtwork withOldValue:nil];
+        }
+    }
+    @finally 
+    {
+        [pool release];
+    }
+}
+
+- (void)notifyChangeForKey:(NSString *)key withOldValue:(id)oldValue
+{
+    // Send out a formal notification
+    [[NSNotificationCenter defaultCenter] postNotificationName:VLCMediaMetaChanged
+                                                        object:self
+                                                      userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+                                                          key, @"key",
+                                                          oldValue, @"oldValue", 
+                                                          nil]];
+    
+    // Now notify the delegate
+    if (delegate && [delegate respondsToSelector:@selector(media:metaValueChangedFrom:forKey:)])
+        [delegate media:self metaValueChangedFrom:oldValue forKey:key];
+}
+
+//- (void)subItemAdded:(libvlc_media_descriptor_t *)child
+//{
+//  // TODO: SubItemAdded Notification
+////    if (!subitems)
+////    {
+////        subitems = [[VLCMediaList alloc] initWithLibVLCMediaList:];
+////    }
+//}
+//
+//- (void)subItemRemoved:(libvlc_media_descriptor_t *)child
+//{
+//  // TODO: SubItemAdded Notification
+//  //    if (!subitems)
+//  //    {
+//  //      subitems = [[VLCMediaList alloc] initWithLibVLCMediaList:];
+//  //    }
+//}
+
+- (void)metaChanged:(NSNumber *)metaType
+{
+    // TODO: Only retrieve the meta that was changed
+    // Can we figure out what piece was changed instead of retreiving everything?
+    NSString *key = [VLCMedia metaTypeToString:[metaType intValue]];
+    id oldValue = (metaDictionary ? [metaDictionary valueForKey:key] : nil);
+
+    // Update the meta data
+    if ([self setMetaValue:libvlc_media_descriptor_get_meta(p_md, [metaType intValue], NULL) forKey:key])
+        // There was actually a change, send out the notifications
+        [self notifyChangeForKey:key withOldValue:oldValue];
+}
+
+@end
+
+@implementation VLCMedia (VLCMediaPlayerBridging)
+
+- (void)setLength:(VLCTime *)value
+{
+    if (length != value)
+    {
+        if (length && value && [length compare:value] == NSOrderedSame)
+            return;
+        
+        [self willChangeValueForKey:@"length"];
+
+        if (length) {
+            [length release];
+            length = nil;
+        }
+        
+        if (value)
+            length = [value retain];
+
+        [self didChangeValueForKey:@"length"];
+    }
+}
+
+@end

+ 25 - 19
Sources/VLCMediaLibrary.m

@@ -23,17 +23,19 @@
  *****************************************************************************/
 
 #import <Cocoa/Cocoa.h>
-#import <VLC/VLCMediaLibrary.h>
+#import "VLCMediaLibrary.h"
 #import "VLCLibrary.h"
+#import "VLCLibVLCBridging.h"
 
 #include <vlc/libvlc.h>
 
-static VLCMediaLibrary * sharedMediaLibrary = NULL;
+static VLCMediaLibrary * sharedMediaLibrary = nil;
 
 @implementation VLCMediaLibrary
+
 + (id)sharedMediaLibrary
 {
-    if( !sharedMediaLibrary )
+    if(!sharedMediaLibrary)
     {
         sharedMediaLibrary = [[VLCMediaLibrary alloc] init];
     }
@@ -48,8 +50,9 @@ static VLCMediaLibrary * sharedMediaLibrary = NULL;
         libvlc_exception_init( &p_e );
         mlib = libvlc_media_library_new( [VLCLibrary sharedInstance], &p_e );
         quit_on_exception( &p_e );
-        libvlc_media_library_load( mlib, &p_e );
-        quit_on_exception( &p_e );
+        
+        libvlc_media_library_load(mlib, &p_e);
+        quit_on_exception(&p_e);
         allMedia = nil;
     }
     return self;
@@ -57,31 +60,34 @@ static VLCMediaLibrary * sharedMediaLibrary = NULL;
 
 - (void)dealloc
 {
-    if (allMedia)
-        [allMedia release];
-    libvlc_media_library_release( mlib );
+    [allMedia release];
+    
+    libvlc_media_library_release(mlib);
+    mlib = nil;     // make sure that the pointer is dead
+    
     [super dealloc];
 }
 
-- (VLCPlaylist *)allMedia
+- (VLCMediaList *)allMedia
 {
     if (!allMedia)
     {
-        libvlc_media_list_t * p_mlist = libvlc_media_library_media_list( mlib, NULL );
-        libvlc_media_list_t * p_flat_mlist = libvlc_media_list_flat_media_list( p_mlist, NULL );
-        allMedia = [[VLCPlaylist playlistWithLibVLCMediaList: p_flat_mlist] retain];
-        libvlc_media_list_release( p_flat_mlist );
-        libvlc_media_list_release( p_mlist );
+//        libvlc_media_list_t *p_mlist = libvlc_media_library_media_list(mlib, NULL);
+//        libvlc_media_list_t * p_flat_mlist = libvlc_media_list_flat_media_list(p_mlist, NULL);
+//        allMedia = [[VLCMediaList medialistWithLibVLCMediaList: p_flat_mlist] retain];
+//        libvlc_media_list_release(p_flat_mlist);
+//        libvlc_media_list_release(p_mlist);
     }
     return allMedia;
 }
 
-- (NSArray *) playlists
+- (NSArray *)playlists
 {
-    libvlc_media_list_t * p_mlist = libvlc_media_library_media_list( mlib, NULL );
-    VLCPlaylist * playlist = [VLCPlaylist playlistWithLibVLCMediaList: p_mlist];
-    libvlc_media_list_release( p_mlist );
-    NSArray * ret = [playlist sublists];
+    libvlc_media_list_t *p_mlist = libvlc_media_library_media_list( mlib, NULL );
+    VLCMediaList *medialist = [VLCMediaList medialistWithLibVLCMediaList:p_mlist];
+    libvlc_media_list_release(p_mlist);
+    NSArray *ret = [medialist sublists];
+    
     return ret;
 }
 @end

+ 326 - 0
Sources/VLCMediaList.m

@@ -0,0 +1,326 @@
+/*****************************************************************************
+ * VLCMediaList.m: VLC.framework VLCMediaList implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCMediaList.h"
+#import "VLCLibrary.h"
+#import "VLCEventManager.h"
+#import "VLCLibVLCBridging.h"
+#include <vlc/vlc.h>
+#include <vlc/libvlc.h>
+
+/* Notification Messages */
+NSString *VLCMediaListItemAdded		= @"VLCMediaListItemAdded";
+NSString *VLCMediaListItemDeleted	= @"VLCMediaListItemDeleted";
+
+// TODO: Documentation
+@interface VLCMediaList (PrivateAPI)
+
+/* Initializers */
+- (void)initInternalMediaList;
+
+/* Libvlc event bridges */
+- (void)mediaListItemAdded:(NSArray *)args;
+- (void)mediaListItemRemoved:(NSNumber *)index;
+
+@end
+
+/* libvlc event callback */
+static void HandleMediaListItemAdded(const libvlc_event_t *event, void *user_data)
+{
+    id self = user_data;
+	
+	// Check to see if the last item added is this item we're trying to introduce
+	// If no, then add the item to the local list, otherwise, the item has already 
+	// been added
+	[[VLCEventManager sharedManager] callOnMainThreadObject:self 
+												 withMethod:@selector(mediaListItemAdded:) 
+									   withArgumentAsObject:[NSArray arrayWithObjects:[VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_list_item_added.item],
+										   [NSNumber numberWithInt:event->u.media_list_item_added.index], nil]];
+}
+
+static void HandleMediaListItemDeleted( const libvlc_event_t * event, void * user_data)
+{
+    id self = user_data;
+	
+	// Check to see if the last item deleted is this item we're trying delete now.
+	// If no, then delete the item from the local list, otherwise, the item has already 
+	// been deleted
+	[[VLCEventManager sharedManager] callOnMainThreadObject:self 
+												 withMethod:@selector(mediaListItemRemoved:) 
+									   withArgumentAsObject:[NSNumber numberWithInt:event->u.media_list_item_deleted.index]];
+}
+
+@implementation VLCMediaList
+
+- (id)init
+{
+    if (self = [super init])
+    {
+		// Create a new libvlc media list instance
+        libvlc_exception_t p_e;
+        libvlc_exception_init(&p_e);
+        p_mlist = libvlc_media_list_new([VLCLibrary sharedInstance], &p_e);
+        quit_on_exception(&p_e);
+		
+		// Initialize internals to defaults
+		delegate = nil;
+        [self initInternalMediaList];
+    }
+    return self;
+}
+
+- (void)release
+{
+    @synchronized(self)
+    {
+        if([self retainCount] <= 1)
+        {
+            /* We must make sure we won't receive new event after an upcoming dealloc
+             * We also may receive a -retain in some event callback that may occcur
+             * Before libvlc_event_detach. So this can't happen in dealloc */
+            libvlc_event_manager_t * p_em = libvlc_media_list_event_manager(p_mlist, NULL);
+            libvlc_event_detach(p_em, libvlc_MediaListItemDeleted, HandleMediaListItemDeleted, self, NULL);
+            libvlc_event_detach(p_em, libvlc_MediaListItemAdded,   HandleMediaListItemAdded,   self, NULL);
+        }
+        [super release];
+    }
+}
+
+- (void)dealloc
+{
+	// Release allocated memory
+    libvlc_media_list_release(p_mlist);
+	
+    [super dealloc];
+}
+
+- (void)setDelegate:(id)value
+{
+	delegate = value;
+}
+
+- (id)delegate
+{
+	return delegate;
+}
+
+- (void)lock
+{
+    libvlc_media_list_lock(p_mlist);
+}
+
+- (void)unlock
+{
+    libvlc_media_list_unlock(p_mlist);
+}
+
+- (int)addMedia:(VLCMedia *)media
+{
+	int index = [self count];
+	[self insertMedia:media atIndex:index];
+	return index;
+}
+
+- (void)insertMedia:(VLCMedia *)media atIndex: (int)index
+{
+	[media retain];
+	
+	// Add it to the libvlc's medialist
+    libvlc_exception_t p_e;
+    libvlc_exception_init( &p_e );
+    libvlc_media_list_insert_media_descriptor(p_mlist, [media libVLCMediaDescriptor], index, &p_e);
+    quit_on_exception(&p_e);
+}
+
+- (void)removeMediaAtIndex:(int)index
+{
+	[[self mediaAtIndex:index] release];
+
+	// Remove it from the libvlc's medialist
+    libvlc_exception_t p_e;
+    libvlc_exception_init(&p_e);
+    libvlc_media_list_remove_index(p_mlist, index, &p_e);
+    quit_on_exception(&p_e);
+}
+
+- (VLCMedia *)mediaAtIndex:(int)index
+{
+	libvlc_exception_t p_e;
+	libvlc_exception_init(&p_e);
+	libvlc_media_descriptor_t *p_md = libvlc_media_list_item_at_index(p_mlist, index, &p_e);
+	quit_on_exception(&p_e);
+	
+	// Returns local object for media descriptor, searchs for user data first.  If not found it creates a 
+	// new cocoa object representation of the media descriptor.
+	return [VLCMedia mediaWithLibVLCMediaDescriptor:p_md];
+}
+
+- (int)count
+{
+	libvlc_exception_t p_e;
+	libvlc_exception_init(&p_e);
+	int result = libvlc_media_list_count(p_mlist, &p_e);
+	quit_on_exception(&p_e);
+
+	return result;
+}
+
+- (int)indexOfMedia:(VLCMedia *)media
+{
+	libvlc_exception_t p_e;
+	libvlc_exception_init(&p_e);
+    int result = libvlc_media_list_index_of_item(p_mlist, [media libVLCMediaDescriptor], &p_e);
+	quit_on_exception(&p_e);
+	
+	return result;
+}
+
+- (NSArray *)sublists
+{
+    NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity: 0];
+    int i, count;
+
+    libvlc_exception_t p_e;
+    libvlc_exception_init(&p_e);
+    count = libvlc_media_list_count(p_mlist, &p_e);
+    quit_on_exception(&p_e);
+
+    for(i = 0; i < count; i++)
+    {
+        libvlc_media_descriptor_t *p_md;
+        libvlc_media_list_t *p_submlist;
+        p_md = libvlc_media_list_item_at_index(p_mlist, i, NULL);
+        p_submlist = libvlc_media_descriptor_subitems(p_md, NULL);
+        if(p_submlist)
+        {
+            [ret addObject:[VLCMediaList medialistWithLibVLCMediaList:p_submlist]];
+            libvlc_media_list_release(p_submlist);
+        }
+        libvlc_media_descriptor_release(p_md);
+    }
+    return [ret autorelease];
+}
+
+//- (VLCMediaList *)flatPlaylist
+//{
+//    VLCMediaList * flatPlaylist;
+//    libvlc_exception_t p_e;
+//    libvlc_exception_init( &p_e );
+//    libvlc_media_list_t * p_flat_mlist = libvlc_media_list_flat_media_list( p_mlist, &p_e );
+//    quit_on_exception( &p_e );
+//    flatPlaylist = [VLCMediaList medialistWithLibVLCMediaList: p_flat_mlist];
+//    libvlc_media_list_release( p_flat_mlist );
+//    return flatPlaylist;
+//}
+//
+//- (VLCMedia *)providerMedia
+//{
+//    VLCMedia * ret;
+//    libvlc_exception_t p_e;
+//    libvlc_exception_init( &p_e );
+//    libvlc_media_descriptor_t * p_md = libvlc_media_list_media_descriptor( p_mlist, &p_e );
+//    ret = [VLCMedia mediaWithLibVLCMediaDescriptor: p_md];
+//    libvlc_media_descriptor_release( p_md );
+//    quit_on_exception( &p_e );
+//    return ret;
+//}
+
+@end
+
+@implementation VLCMediaList (LibVLCBridging)
+
++ (id)medialistWithLibVLCMediaList:(void *)p_new_mlist;
+{
+    return [[[VLCMediaList alloc] initWithLibVLCMediaList:p_new_mlist] autorelease];
+}
+
+- (id)initWithLibVLCMediaList:(void *)p_new_mlist;
+{
+    if( self = [super init] )
+    {
+        p_mlist = p_new_mlist;
+        libvlc_media_list_retain(p_mlist);
+        [self initInternalMediaList];
+    }
+    return self;
+}
+
+- (void *)libVLCMediaList
+{
+    return p_mlist;
+}
+
+@end
+
+@implementation VLCMediaList (PrivateAPI)
+
+- (void)initInternalMediaList
+{
+	// Add event callbacks
+    [self lock];
+    libvlc_exception_t p_e;
+    libvlc_exception_init(&p_e);
+
+    libvlc_event_manager_t *p_em = libvlc_media_list_event_manager(p_mlist, &p_e);
+    libvlc_event_attach(p_em, libvlc_MediaListItemAdded,   HandleMediaListItemAdded,   self, &p_e);
+    libvlc_event_attach(p_em, libvlc_MediaListItemDeleted, HandleMediaListItemDeleted, self, &p_e);
+    [self unlock];
+	
+    quit_on_exception( &p_e );
+}
+
+- (void)mediaListItemAdded:(NSArray *)args
+{
+	VLCMedia *media = [args objectAtIndex:0];
+	NSNumber *index = [args objectAtIndex:1];
+	
+	// Post the notification
+	[[NSNotificationCenter defaultCenter] postNotificationName:VLCMediaListItemAdded
+														object:self
+													  userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+														  media, @"media",
+														  index, @"index",
+														  nil]];
+	
+	// Let the delegate know that the item was added
+	if (delegate && [delegate respondsToSelector:@selector(mediaList:mediaAdded:atIndex:)])
+		[delegate mediaList:self mediaAdded:media atIndex:[index intValue]];
+}
+
+- (void)mediaListItemRemoved:(NSNumber *)index
+{
+	// Post the notification
+	[[NSNotificationCenter defaultCenter] postNotificationName:VLCMediaListItemDeleted 
+														object:self
+													  userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+														  index, @"index",
+														  nil]];
+	
+	// Let the delegate know that the item is being removed
+	if (delegate && [delegate respondsToSelector:@selector(mediaList:mediaRemovedAtIndex:)])
+		[delegate mediaList:self mediaRemovedAtIndex:index];
+}
+
+@end
+

+ 507 - 0
Sources/VLCMediaPlayer.m

@@ -0,0 +1,507 @@
+/*****************************************************************************
+ * VLCMediaPlayer.m: VLC.framework VLCMediaPlayer implementation
+ *****************************************************************************
+ * Copyright (C) 2007 Pierre d'Herbemont
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *          Faustion Osuna <enrique.osuna # gmail.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCLibrary.h"
+#import "VLCMediaPlayer.h"
+#import "VLCEventManager.h"
+#import "VLCLibVLCBridging.h"
+#include <vlc/vlc.h>
+
+/* Notification Messages */
+NSString *VLCMediaPlayerTimeChanged   = @"VLCMediaPlayerTimeChanged";
+NSString *VLCMediaPlayerStateChanged  = @"VLCMediaPlayerStateChanged";
+
+/* libvlc event callback */
+static void HandleMediaInstanceVolumeChanged(const libvlc_event_t *event, void *self)
+{
+    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
+												   withDelegateMethod:@selector(mediaPlayerVolumeChanged:)
+												 withNotificationName:VLCMediaPlayerVolumeChanged];
+}
+
+static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
+{
+	[[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
+												   withDelegateMethod:@selector(mediaPlayerTimeChanged:)
+												 withNotificationName:VLCMediaPlayerTimeChanged];
+		
+}
+
+static void HandleMediaInstanceStateChanged(const libvlc_event_t *event, void *self)
+{
+    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
+												   withDelegateMethod:@selector(mediaPlayerStateChanged:)
+												 withNotificationName:VLCMediaPlayerStateChanged];
+}
+
+NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state)
+{
+	static NSString *stateToStrings[] = {
+		[VLCMediaPlayerStateStopped]	= @"VLCMediaPlayerStateStopped",
+		[VLCMediaPlayerStateOpening]	= @"VLCMediaPlayerStateOpening",
+		[VLCMediaPlayerStateBuffering]	= @"VLCMediaPlayerStateBuffering",
+		[VLCMediaPlayerStateEnded]		= @"VLCMediaPlayerStateEnded",
+		[VLCMediaPlayerStateError]		= @"VLCMediaPlayerStateError",
+		[VLCMediaPlayerStatePlaying]	= @"VLCMediaPlayerStatePlaying",
+		[VLCMediaPlayerStatePaused]		= @"VLCMediaPlayerStatePaused"
+	};
+	return stateToStrings[state];
+}
+
+// TODO: Documentation
+@interface VLCMediaPlayer (PrivateAPI)
+
+- (void)registerObservers;
+- (void)unregisterObservers;
+
+@end
+
+@implementation VLCMediaPlayer
+
+- (id)init
+{
+	self = [self initWithVideoView:nil];
+	return self;
+}
+
+- (id)initWithVideoView:(VLCVideoView *)aVideoView
+{
+	if (self = [super init])
+	{
+		delegate = nil;
+		media = nil;
+		
+		// Create a media instance, it doesn't matter what library we start off with
+		// it will change depending on the media descriptor provided to the media
+		// instance
+		libvlc_exception_t ex;
+		libvlc_exception_init(&ex);
+		instance = (void *)libvlc_media_instance_new([VLCLibrary sharedInstance], &ex);
+		quit_on_exception(&ex);
+		
+		[self registerObservers];
+		
+		[self setVideoView:aVideoView];
+	}
+	return self;
+}
+
+- (void)dealloc
+{
+	// 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;
+
+	// Next get rid of the event managers so we can stop trapping events
+	[self unregisterObservers];
+	libvlc_media_instance_release((libvlc_media_instance_t *)instance);
+	
+	// Get rid of everything else
+	instance = nil;
+	videoView = nil;
+	[media release];
+	
+	[super dealloc];
+}
+
+- (void)setDelegate:(id)value
+{
+	delegate = value;
+}
+
+- (id)delegate
+{
+	return delegate;
+}
+
+- (void)setVideoView:(VLCVideoView *)value
+{
+	videoView = value;
+	
+	// Make sure that this instance has been associated with the drawing canvas.
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	libvlc_media_instance_set_drawable ((libvlc_media_instance_t *)instance, 
+										(libvlc_drawable_t)videoView, 
+										&ex);
+	quit_on_exception(&ex);
+}
+
+- (VLCVideoView *)videoView
+{
+	return videoView;
+}
+
+- (void)setFullscreen:(BOOL)value
+{
+	libvlc_set_fullscreen(instance, value, NULL);
+}
+
+- (BOOL)fullscreen
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	int result = libvlc_get_fullscreen(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setVideoAspectRatio:(char *)value
+{
+	libvlc_video_set_aspect_ratio(instance, value, NULL);
+}
+
+- (char *)videoAspectRatio
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	char *result = libvlc_video_get_aspect_ratio(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setVideoSubTitles:(int)value
+{
+	libvlc_video_set_spu(instance, value, NULL);
+}
+
+- (int)videoSubTitles
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	int result = libvlc_video_get_spu(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setVideoCropGeometry:(char *)value
+{
+	libvlc_video_set_crop_geometry(instance, value, NULL);
+}
+
+- (char *)videoCropGeometry
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	char *result = libvlc_video_get_crop_geometry(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setVideoTeleText:(int)value
+{
+	libvlc_video_set_teletext(instance, value, NULL);
+}
+
+- (int)videoTeleText
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	int result = libvlc_video_get_teletext(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setRate:(int)value
+{
+	libvlc_media_instance_set_rate(instance, value, NULL);
+}
+
+- (int)rate
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	float result = libvlc_media_instance_get_rate(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (NSSize)videoSize
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	NSSize result = NSMakeSize(libvlc_video_get_height((libvlc_media_instance_t *)instance, &ex),
+							   libvlc_video_get_width((libvlc_media_instance_t *)instance, &ex));
+	quit_on_exception(&ex);
+	return result;	
+}
+
+- (BOOL)hasVideoOut
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	BOOL result = libvlc_media_instance_has_vout((libvlc_media_instance_t *)instance, &ex);
+	if (libvlc_exception_raised(&ex))
+	{
+		libvlc_exception_clear(&ex);
+		return NO;
+	}
+	else
+		return result;
+}
+
+- (float)framesPerSecond
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	float result = libvlc_media_instance_get_fps((libvlc_media_instance_t *)instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setTime:(VLCTime *)value
+{
+	libvlc_exception_t ex;
+	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_instance_set_time((libvlc_media_instance_t *)instance, 
+								   (value ? [[value numberValue] longLongValue] / 1000 : 0),
+								   &ex);
+	quit_on_exception(&ex);
+}
+
+- (VLCTime *)time
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	
+	// Results are returned in seconds...duration is returned in milliseconds
+	long long time = libvlc_media_instance_get_time((libvlc_media_instance_t *)instance, &ex) * 1000;
+	if (libvlc_exception_raised(&ex))
+	{
+		libvlc_exception_clear(&ex);
+		return [VLCTime nullTime];		// Error in obtaining the time, return a null time defintition (--:--:--)
+	}
+	else
+		return [VLCTime timeWithNumber:[NSNumber numberWithLongLong:time]];
+}
+
+- (void)setAudioTrack:(int)value
+{
+	libvlc_audio_set_track(instance, value, NULL);
+}
+
+- (int)audioTrack
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	int result = libvlc_audio_get_track(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setAudioChannel:(int)value
+{
+	libvlc_audio_set_channel(instance, value, NULL);
+}
+
+- (int)audioChannel
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	int result = libvlc_audio_get_channel(instance, &ex);
+	quit_on_exception(&ex);
+	return result;
+}
+
+- (void)setMedia:(VLCMedia *)value
+{
+	// We only know how to play media files...not media resources with subitems
+	if (media != value && [media subitems] == nil)
+	{
+		if (media && [media compare:value] == NSOrderedSame)
+			return;
+		
+		BOOL wasPlaying;
+		if (wasPlaying = [self isPlaying])
+		{
+			[self pause];
+//			// TODO: Should we wait until it stops playing?
+//			while ([self isPlaying])
+//				usleep(1000);
+		}
+		
+		[self willChangeValueForKey:@"media"];
+		[media release];
+		media = [value retain];
+		[self didChangeValueForKey:@"media"];
+
+		libvlc_exception_t ex;
+		libvlc_exception_init(&ex);
+		libvlc_media_instance_set_media_descriptor(instance, [media libVLCMediaDescriptor], &ex);
+		quit_on_exception(&ex);
+		
+		if (media) {
+			if (wasPlaying)
+				[self play];
+		}
+	}
+}
+
+- (VLCMedia *)media
+{
+	return media;
+}
+
+- (BOOL)play
+{
+	// Return if there is no media available or if the stream is already playing something
+	if (!media || [self isPlaying])
+		return [self isPlaying];
+	
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+
+	libvlc_media_instance_play((libvlc_media_instance_t *)instance, &ex);
+	quit_on_exception(&ex);
+
+	return YES;
+}
+
+- (void)pause
+{
+	// Return if there is no media available or if the stream is not paused or 
+	// playing something else
+	if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
+		return;
+
+	// Should never get here.
+	if (!instance)
+		return;
+
+	// Pause the stream
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	libvlc_media_instance_pause((libvlc_media_instance_t *)instance, &ex);
+	quit_on_exception(&ex);
+	
+	// TODO: Should we record the time in case the media instance is destroyed
+	// then rebuilt?
+}
+
+- (void)stop
+{
+	// Return if there is no media available or if the system is not in play status 
+	// or pause status.
+	if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
+		return;
+	
+	// The following is not implemented in the core, should I fix it or just
+	// compensate?
+	//	libvlc_exception_t ex;
+	//	libvlc_exception_init(&ex);
+	//	libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex);
+	//	quit_on_exception(&ex);
+	
+	// Pause and reposition to the begining of the stream.
+	[self pause];
+	[self setTime:0];
+	// TODO: Should we pause this or destroy the media instance so that it appears as being "stopped"?
+}
+
+//- (void)fastForward;
+//- (void)fastForwardAtRate:(int)rate;
+//- (void)rewind;
+//- (void)rewindAtRate:(int)rate;
+
+- (BOOL)isPlaying
+{
+	VLCMediaPlayerState state = [self state];
+    return ((state == VLCMediaPlayerStateOpening) || (state == VLCMediaPlayerStateBuffering) ||
+			(state == VLCMediaPlayerStatePlaying));
+}
+
+- (BOOL)willPlay
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	BOOL ret = libvlc_media_instance_will_play((libvlc_media_instance_t *)instance, &ex);
+	if (libvlc_exception_raised(&ex))
+	{
+		libvlc_exception_clear(&ex);
+		return NO;
+	}
+	else
+		return ret;
+}
+
+static VLCMediaPlayerState libvlc_to_local_state [] =
+{
+    [libvlc_Stopped]	= VLCMediaPlayerStateStopped,
+    [libvlc_Opening]	= VLCMediaPlayerStateOpening,
+    [libvlc_Buffering]	= VLCMediaPlayerStateBuffering,
+    [libvlc_Playing]	= VLCMediaPlayerStatePlaying,
+    [libvlc_Paused]		= VLCMediaPlayerStatePaused,
+    [libvlc_Ended]		= VLCMediaPlayerStateEnded,
+    [libvlc_Error]		= VLCMediaPlayerStateError
+};
+
+- (VLCMediaPlayerState)state
+{
+	// If there is no instance, assume that we're in a stopped state
+	if (!instance)
+		return VLCMediaPlayerStateStopped;
+	
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+	libvlc_state_t libvlc_state = libvlc_media_instance_get_state((libvlc_media_instance_t *)instance, &ex);
+	if (libvlc_exception_raised(&ex))
+	{
+		libvlc_exception_clear(&ex);
+		return VLCMediaPlayerStateError;
+	}
+	else
+		return libvlc_to_local_state[libvlc_state];
+}
+
+@end
+
+@implementation VLCMediaPlayer (PrivateAPI)
+
+- (void)registerObservers
+{
+	libvlc_exception_t ex;
+	libvlc_exception_init(&ex);
+
+	// Attach event observers into the media instance
+	libvlc_event_manager_t *p_em = libvlc_media_instance_event_manager(instance, &ex);
+	libvlc_event_attach(p_em, libvlc_MediaInstancePlayed,          HandleMediaInstanceStateChanged, self, &ex);
+	libvlc_event_attach(p_em, libvlc_MediaInstancePaused,          HandleMediaInstanceStateChanged, self, &ex);
+	libvlc_event_attach(p_em, libvlc_MediaInstanceReachedEnd,      HandleMediaInstanceStateChanged, self, &ex);
+	libvlc_event_attach(p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged,			self, &ex);
+	quit_on_exception(&ex);
+}
+
+- (void)unregisterObservers
+{
+	libvlc_event_manager_t *p_em = libvlc_media_instance_event_manager(instance, NULL);
+	libvlc_event_detach(p_em, libvlc_MediaInstancePlayed,          HandleMediaInstanceStateChanged, self, NULL);
+	libvlc_event_detach(p_em, libvlc_MediaInstancePaused,          HandleMediaInstanceStateChanged, self, NULL);
+	libvlc_event_detach(p_em, libvlc_MediaInstanceReachedEnd,      HandleMediaInstanceStateChanged, self, NULL);
+	libvlc_event_detach(p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged,			self, NULL);
+}
+
+@end

+ 71 - 9
Sources/VLCTime.m

@@ -22,35 +22,97 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#import <VLC/VLCTime.h>
+#import <VLCTime.h>
+
+static VLCTime *nullTime = nil;
 
 @implementation VLCTime
+
++ (VLCTime *)nullTime
+{
+    if (!nullTime)
+        nullTime = [VLCTime timeWithNumber:[NSNumber numberWithInt:0]];
+    return nullTime;
+}
+
++ (VLCTime *)timeWithNumber:(NSNumber *)aNumber
+{
+    return [[[VLCTime alloc] initWithNumber:aNumber] autorelease];
+}
+
+// TODO: Implement [VLCTime timeWithString]
+//+ (VLCTime *)timeWithString:(NSString *)aString
+//{
+//  return [[[VLCTime alloc] initWithString:aString] autorelease];
+//}
+
 - (id)initWithNumber:(NSNumber *)aNumber
 {
     if (self = [super init])
     {
-        value = [aNumber copy];
+        if (aNumber)
+            value = [[aNumber copy] retain];
+        else
+            value = nil;
     }
     return self;
 }
 
+// TODO: Implement [VLCTime initWithString]
+//- (id)initWithString:(NSString *)aString
+//{
+//  // Sounds like a good idea but I really don't think there is any value added
+//  if (self = [super init])
+//  {
+//      // convert value
+//  }
+//  return self;
+//}
+
 - (void)dealloc
 {
     [value release];
     [super dealloc];
 }
 
-- (NSNumber *)numberRepresentation
+- (NSNumber *)numberValue
 {
-    [[value copy] autorelease];
+    if (value)
+        return [value copy];
+    else
+        return nil;
 }
 
-- (NSString *)stringRepresentation
+- (NSString *)stringValue
 {
-    int hours = [value intValue] / (3600*1000);
-    int minutes = ([value intValue] - hours * 3600) / (60*1000);
-    int seconds = ([value intValue] - hours * 3600 * 1000 - minutes * 60 * 1000)/1000;
+    if (value)
+    {
+        long long duration = [value longLongValue] / 1000000;
+        return [NSString stringWithFormat:@"%02d:%02d:%02d",
+            (long) (duration / 3600),
+            (long)((duration / 60) % 60),
+            (long) (duration % 60)];
+    }
+    else
+    {
+        // Return a string that represents an undefined time.
+        return @"--:--:--";
+    }
+}
 
-    return [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
+- (NSComparisonResult)compare:(VLCTime *)aTime
+{
+    if (!aTime && !value)
+        return NSOrderedSame;
+    else if (!aTime)
+        return NSOrderedDescending;
+    else
+        return [value compare:[aTime numberValue]];
 }
+
+- (NSString *)description
+{
+    return [self stringValue];
+}
+
 @end

+ 74 - 179
Sources/VLCVideoView.m

@@ -22,7 +22,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#import <VLC/VLCVideoView.h>
+#import "VLCVideoView.h"
 #import "VLCLibrary.h"
 #import "VLCEventManager.h"
 
@@ -30,243 +30,138 @@
 #include <vlc/vlc.h>
 #include <vlc/libvlc.h>
 
-/* Notification */
-NSString * VLCVideoDidChangeVolume                  = @"VLCVideoDidChangeVolume";
-NSString * VLCVideoDidChangeTime                    = @"VLCVideoDidChangeTime";
-NSString * VLCVideoDidChangeCurrentlyPlayingItem    = @"VLCVideoDidChangeCurrentlyPlayingItem";
-NSString * VLCVideoDidPause                         = @"VLCVideoDidPause";
-NSString * VLCVideoDidPlay                          = @"VLCVideoDidPlay";
-NSString * VLCVideoDidStop                          = @"VLCVideoDidStop";
+/* Notifications */
+NSString *VLCVideoViewEnteredFullScreen = @"VLCVideoViewEnteredFullScreen";
+NSString *VLCVideoViewLeftFullScreen = @"VLCVideoViewLeftFullScreen";
 
-static void HandleMediaListPlayerCurrentPlayingItemChanged( const libvlc_event_t * event, void * self )
-{
-    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
-                                     withDelegateMethod: @selector(volumeDidChangeCurrentPlayingItem:)
-                                     withNotificationName: VLCVideoDidChangeCurrentlyPlayingItem];
-}
-
-static void HandleMediaListPlayerPaused( const libvlc_event_t * event, void * self )
-{
-    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
-                                     withDelegateMethod: @selector(videoDidPause:)
-                                     withNotificationName: VLCVideoDidPause];
-}
+/* This is a forward reference to VLCOpenGLVoutView specified in minimal_macosx
+   library.  We could get rid of this, but it prevents warnings from the 
+   compiler. */
+@interface VLCOpenGLVoutView : NSView
 
-static void HandleMediaListPlayerPlayed( const libvlc_event_t * event, void * self )
-{
-    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
-                                     withDelegateMethod: @selector(videoDidPlay:)
-                                     withNotificationName: VLCVideoDidPlay];
-}
+- (void)detachFromVout;
 
-static void HandleMediaListPlayerStopped( const libvlc_event_t * event, void * self )
-{
-    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
-                                     withDelegateMethod: @selector(videoDidStop:)
-                                     withNotificationName: VLCVideoDidStop];
-}
+@end
 
 @implementation VLCVideoView
-- (id)initWithFrame:(NSRect)frameRect
+
+- (id)initWithFrame:(NSRect)rect
 {
-    if (self = [super initWithFrame: frameRect])
+    if (self = [super initWithFrame:rect]) 
     {
-        libvlc_exception_t p_e;
-        libvlc_exception_init( &p_e );
-        p_mi = libvlc_media_instance_new( [VLCLibrary sharedInstance], &p_e );
-        quit_on_exception( &p_e );
-        p_mlp = libvlc_media_list_player_new( [VLCLibrary sharedInstance], &p_e );
-        quit_on_exception( &p_e );
-        libvlc_media_list_player_set_media_instance( p_mlp, p_mi, &p_e );
-        quit_on_exception( &p_e );
-        libvlc_media_instance_set_drawable( p_mi, (libvlc_drawable_t)self, &p_e );
-        quit_on_exception( &p_e );
-
-        libvlc_event_manager_t * p_em = libvlc_media_list_event_manager( p_mlp, &p_e );
-        //libvlc_event_attach( p_em, libvlc_MediaListPlayerCurrentPlayingItemChanged, HandleMediaListPlayerCurrentPlayingItemChanged, self, &p_e );
-        //libvlc_event_attach( p_em, libvlc_MediaListPlayerPaused,                    HandleMediaListPlayerPaused,  self, &p_e );
-        //libvlc_event_attach( p_em, libvlc_MediaListPlayerPlayed,                    HandleMediaListPlayerPlayed,  self, &p_e );
-        //libvlc_event_attach( p_em, libvlc_MediaListPlayerStopped,                   HandleMediaListPlayerStopped, self, &p_e );
-        quit_on_exception( &p_e );
-
         delegate = nil;
-        playlist = nil;
-
-        [self setStretchesVideo: NO];
-        [self setAutoresizesSubviews: YES];
+        [self setBackColor:[NSColor blackColor]];
+        [self setStretchesVideo:NO];
+        [self setAutoresizesSubviews:YES];
     }
     return self;
 }
 
 - (void)dealloc
 {
-    libvlc_media_instance_release( p_mi );
-
-    if (delegate)
-    {
-        [delegate release];
-        delegate = nil;
-    }
+    delegate = nil;
+    [backColor release];
     [super dealloc];
 }
 
-- (void)setPlaylist: (VLCPlaylist *)newPlaylist
+- (void)setDelegate:(id)value
 {
-    libvlc_exception_t p_e;
-    libvlc_exception_init( &p_e );
-
-    if (playlist)
-        [playlist release];
-
-    playlist = [newPlaylist retain];
-
-    libvlc_media_list_player_set_media_list( p_mlp, [playlist libVLCMediaList], &p_e );
-    quit_on_exception( &p_e );
+    delegate = value;
 }
 
-- (VLCPlaylist *)playlist
+- (id)delegate
 {
-    return playlist;
+    return delegate;
 }
 
-/* Play */
-- (void)play
+- (void)setBackColor:(NSColor *)value
 {
-    libvlc_exception_t p_e;
-    libvlc_exception_init( &p_e );
-    libvlc_media_list_player_play( p_mlp, &p_e );
-    quit_on_exception( &p_e );
+    if (backColor != value)
+    {
+        [backColor release];
+        backColor = [value retain];
+    }
 }
 
-- (void)playItemAtIndex:(int) i
+- (NSColor *)backColor
 {
-    libvlc_exception_t p_e;
-    libvlc_exception_init( &p_e );
-    libvlc_media_list_player_play_item_at_index( p_mlp, i, &p_e );
-    quit_on_exception( &p_e );
+    return backColor;
 }
 
-- (void)playMedia:(VLCMedia *) media
+- (void)setStretchesVideo:(BOOL)value
 {
-    libvlc_exception_t p_e;
-    libvlc_exception_init( &p_e );
-    libvlc_media_list_player_play_item( p_mlp, [media libVLCMediaDescriptor], &p_e );
-    quit_on_exception( &p_e );
+    stretchesVideo = value;
 }
 
-- (void)pause
+- (BOOL)stretchesVideo
 {
-    libvlc_exception_t p_e;
-    libvlc_exception_init( &p_e );
-    libvlc_media_list_player_pause( p_mlp, &p_e );
-    quit_on_exception( &p_e );
+    return stretchesVideo;
 }
 
-- (void)setCurrentTime:(VLCTime *)timeObj
+/* This is called by the libvlc module 'minimal_macosx' as soon as there is one 
+ * vout available 
+ */
+- (void)addVoutSubview:(NSView *)aView
 {
+    if( [[self subviews] count] )
+    {
+        /* XXX: This is a hack until core gets fixed */
+        int i;
+        for( i = 0; i < [[self subviews] count]; i++ )
+        {
+            [[[self subviews] objectAtIndex:i] detachFromVout];
+            [[[self subviews] objectAtIndex:i] retain];
+            [[[self subviews] objectAtIndex:i] removeFromSuperview];
+        }
+    }
+    [self addSubview:aView];
+    [aView setFrame:[self bounds]];
     
+    // TODO: Should we let the media player specify these values?
+    [aView setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
 }
 
-/* State */
-- (BOOL)isPlaying
+- (void)removeVoutSubview:(NSView *)view
 {
-    libvlc_exception_t p_e;
-    BOOL ret = libvlc_media_list_player_is_playing( p_mlp, &p_e );
-    quit_on_exception( &p_e );
-    return ret;
+    // Should we do something?  I don't know, however the protocol requires
+    // this to be implemented
 }
 
-- (BOOL)isPaused
-{
-    libvlc_exception_t p_e;
-    libvlc_state_t state = libvlc_media_list_player_get_state( p_mlp, &p_e );
-    quit_on_exception( &p_e );
-    return (state == libvlc_Paused);
-}
-
-- (VLCTime *)currentTime
-{
-    return NULL;
-}
-
-- (id)currentPlaylistItem
-{
-    return NULL;
-}
-
-/* Video output property */
-- (void)setStretchesVideo:(BOOL)flag
-{
-    stretchVideo = flag;
-}
-
-- (BOOL)stretchesVideo
-{
-    return stretchVideo;
-}
-
-/* Fullscreen */
+/* This is a LibVLC notification that we're about to enter into full screen,
+   there is no other place where I can see where we can trap this event */
 - (void)enterFullscreen
 {
-
+    // Go ahead and send a notification to the world we're going into full screen
+    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self 
+                                                   withDelegateMethod:nil 
+                                                 withNotificationName:VLCVideoViewEnteredFullScreen];
+    
+    // There is nothing else to do, as this object strictly displays the video feed
 }
 
+/* This is a LibVLC notification that we're about to enter leaving full screen,
+   there is no other place where I can see where we can trap this event */
 - (void)leaveFullscreen
 {
-
-}
-
-/* Delegate */
-- (void)setDelegate: (id)newDelegate
-{
-    if (delegate)
-        [delegate release];
-    delegate = [newDelegate retain];
-}
-
-- (id)delegate
-{
-    return delegate;
+    // Go ahead and send a notification to the world we're leaving full screen
+    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self 
+                                                   withDelegateMethod:nil 
+                                                 withNotificationName:VLCVideoViewLeftFullScreen];
+    
+    // There is nothing else to do, as this object strictly displays the video feed
 }
-@end
 
-@implementation VLCVideoView (NSViewSubclass)
 - (void)drawRect:(NSRect)aRect
 {
     [self lockFocus];
-    [[NSColor blackColor] set];
+    [backColor set];
     NSRectFill(aRect);
     [self unlockFocus];
 }
+
 - (BOOL)isOpaque
 {
     return YES;
 }
-@end
-
-@interface VLCOpenGLVoutView : NSView
- /* This is part of the hack to avoid a warning in -[VLCVideoView addVoutSubview:] */
-- (void)detachFromVout;
-@end
 
-@implementation VLCVideoView (VLCOpenGLVoutEmbedding)
-/* This is called by the libvlc module 'macosx' as soon as there is one vout
- * available */
-- (void)addVoutSubview:(id)aView
-{
-    if( [[self subviews] count] )
-    {
-        /* XXX: This is a hack until core gets fixed */
-        int i;
-        for( i = 0; i < [[self subviews] count]; i++ )
-        {
-            [[[self subviews] objectAtIndex: i] detachFromVout];
-            [[[self subviews] objectAtIndex: i] retain];
-            [[[self subviews] objectAtIndex: i] removeFromSuperview];
-        }
-    }
-    [self addSubview: aView];
-    [aView setFrame: [self bounds]];
-    [aView setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable];
-}
 @end

+ 0 - 13
Sources/test.m

@@ -1,13 +0,0 @@
-//
-//  test.m - Nothing useful yet
-//  VLC.framework
-//
-//  Created by Pierre d'Herbemont on 13/04/07.
-//  Copyright __MyCompanyName__ 2007. All rights reserved.
-//
-#include <VLC/VLC.h>
-
-int test_vlc_framework()
-{
-    return 0xbabe;
-}

+ 24 - 0
TODO

@@ -0,0 +1,24 @@
+TODO List:
+
+- Add user data into media_descriptor to reference internal VLC object -- fix not committed to SVN.
+
+- Fix stream.c to recognize VLC_ENOOBJECT
+- Easy way to tell the length of the movie without having to instiate the demuxer.  Maybe cached info?
+- Hook into "length" variable for media streams vs. using intf-change as a hook.
+- Figure out a better way to raise error messages versus quit_on_exception
+- Have VLCMedia search for playable files when directories are referenced.
+- Only fetch meta data that has been requested.  Just don't fetch it, just because.
+- md callback to notify VLCMedia that it is about to be destroyed.
+- add media_list_player
+
+Changelog
+- VLCMediaControl eliminated
+- setView/view renamed to setVideoView/videoView
+- VLCMediaPlayer NSView *view changed to VLCVideoView *videoView
+- VLCMediaPlayer initWithView changed to initWithVideoView:(VLCVideoView *)aVideoView
+- Updated VLCMediaPlayer.videoSize from NSRect to NSSize
+- Updated Pre-Compile.sh script to create symbolic links based on relative pathes
+- More issues with VLCTime length, released object by setting to nil
+- Added VLCMedia.h to VLCMediaPlayer.h.
+- Static linked libvlc-control.a and libvlc.a -- dynamically linked libiconv (system file) and vlc_libintl.dylib
+  eliminates errors and warning messages when framework linked against other applications.

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 438 - 0
VLC.xcodeproj/project.pbxproj


+ 50 - 0
VLC_Prefix.pch

@@ -0,0 +1,50 @@
+//
+// Prefix header for all source files of the 'VLC' target in the 'VLC' project.
+//
+
+#ifdef __OBJC__
+    #import <Cocoa/Cocoa.h>
+#endif
+
+#include <vlc/vlc.h>
+
+#ifndef VLC_PUBLIC_API
+
+// For some reason Xcode refuses to read vlc/vlc.h contents -- so we have to do
+// this so we can supress the errors
+#define VLC_PUBLIC_API extern
+typedef int vlc_bool_t;
+typedef struct vlc_list_t vlc_list_t;
+typedef struct vlc_object_t vlc_object_t;
+typedef signed long long vlc_int64_t;
+
+#endif
+
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc.h>
+
+//
+// Prefix header for all source files of the 'VLC' target in the 'VLC' project.
+//
+
+#ifdef __OBJC__
+    #import <Cocoa/Cocoa.h>
+#endif
+
+#include <vlc/vlc.h>
+
+#ifndef VLC_PUBLIC_API
+
+// For some reason Xcode refuses to read vlc/vlc.h contents -- so we have to do
+// this so we can supress the errors
+#define VLC_PUBLIC_API extern
+typedef int vlc_bool_t;
+typedef struct vlc_list_t vlc_list_t;
+typedef struct vlc_object_t vlc_object_t;
+typedef signed long long vlc_int64_t;
+
+#endif
+
+#include <vlc/libvlc_structures.h>
+#include <vlc/libvlc.h>
+