Commit b5763548 authored by Pierre d'Herbemont's avatar Pierre d'Herbemont

extra/MacOSX/Framework: Initial import of the Mac OS X Framework.

parent 41f6c279
/* Controller */
#import <Cocoa/Cocoa.h>
#import <VLC/VLC.h>
@interface Controller : NSObject
{
IBOutlet id window;
IBOutlet id playlistOutline;
IBOutlet id videoHolderView;
VLCVideoView * videoView;
VLCPlaylist * playlist;
}
- (void)awakeFromNib;
- (void)play:(id)sender;
@end
#import "Controller.h"
@implementation Controller
- (void)awakeFromNib
{
NSRect rect;
VLCPlaylistDataSource * aDataSource;
/* Won't be released */
videoView = [[VLCVideoView alloc] init];
rect = [videoHolderView frame];
[[window contentView] replaceSubview: videoHolderView with: videoView];
[videoView setFrame: rect];
[videoView setAutoresizingMask: NSViewHeightSizable|NSViewWidthSizable];
/* Won't be released */
playlist = [[VLCPlaylist alloc] init];
/* Won't be released */
aDataSource = [[VLCPlaylistDataSource alloc] initWithPlaylist:playlist videoView:videoView];
[playlistOutline setDataSource: aDataSource];
[playlistOutline registerForDraggedTypes: [NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]];
}
- (void)play:(id)sender
{
if(![videoView playlist])
[videoView setPlaylist: playlist];
if( [sender isKindOfClass:[NSTableView class]] && [sender selectedRow] >= 0)
[videoView playItemAtIndex: [sender selectedRow]];
}
@end
B/* Localized versions of Info.plist keys */ B/* Localized versions of Info.plist keys */
{
IBClasses = (
{
ACTIONS = {play = id; };
CLASS = Controller;
LANGUAGE = ObjC;
OUTLETS = {playlistOutline = id; videoHolderView = id; window = id; };
SUPERCLASS = NSObject;
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }
);
IBVersion = 1;
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>135 107 356 240 0 0 1680 1028 </string>
<key>IBEditorPositions</key>
<dict>
<key>29</key>
<string>132 353 338 44 0 0 1680 1028 </string>
</dict>
<key>IBFramework Version</key>
<string>446.1</string>
<key>IBOpenObjects</key>
<array>
<integer>21</integer>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
<string>8R218</string>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.test</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
//
// main.m
// test
//
// Created by Pierre d'Herbemont on 13/04/07.
// Copyright __MyCompanyName__ 2007. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <VLC/VLC.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
/* If we can't load the VLC.framework dyld will tell us anyway
* But this is cool */
if(test_vlc_framework() == 0xbabe)
printf("We are linked to VLC.framework!\n");
else
{
fprintf(stderr, "*** Can't load the VLC.framework\n");
return -1;
}
return NSApplicationMain(argc, (const char **) argv);
}
//
// Prefix header for all source files of the 'test' target in the 'test' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif
/*****************************************************************************
* VLC.h: VLC.framework main 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.
*****************************************************************************/
#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/VLCTime.h>
#import <VLC/VLCVideoView.h>
#endif /* VLC_FRAMEWORK_VLC_H */
/*****************************************************************************
* 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
/*****************************************************************************
* VLCMediaDiscoverer.h: VLC.framework VLCMediaDiscoverer 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>
@class VLCPlaylist;
@interface VLCMediaDiscoverer : NSObject
{
NSString *localizedName;
VLCPlaylist * playlist;
void * mdis;
}
- (id)initWithName:(NSString *)aServiceName;
- (VLCPlaylist *)playlist;
- (NSString *)localizedName;
@end
/*****************************************************************************
* VLCMediaDiscoverer.h: VLC.framework VLCMediaDiscoverer 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>
@class VLCPlaylist;
@interface VLCMediaLibrary : NSObject
{
VLCPlaylist * allMedia;
void * mlib;
}
+ (id)sharedMediaLibrary;
- (VLCPlaylist *)allMedia;
- (NSArray *) playlists;
@end
/*****************************************************************************
* VLCPlaylist.h: VLC.framework VLCPlaylist 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 <Foundation/Foundation.h>
#import <VLC/VLCMedia.h>
/* Hack to avoid troubles with modules/macosx for now */
#define VLCPlaylist VLCPlaylistBis
/* Notification Posted */
extern NSString * VLCPlaylistItemChanged;
extern NSString * VLCPlaylistItemDeleted;
extern NSString * VLCPlaylistItemAdded;
@class VLCMedia;
@interface VLCPlaylist : NSObject
{
NSMutableArray * items;
void * p_mlist;
}
- (id)init;
- (void)lock;
- (void)unlock;
- (VLCMedia *)mediaAtIndex: (int)index;
- (int)countMedia;
- (NSArray *)sublists;
- (VLCPlaylist *)flatPlaylist;
- (VLCMedia *)providerMedia;
- (void)addMedia: (VLCMedia *)item;
- (void)insertMedia: (VLCMedia *)item atIndex: (int)index;
- (void)removeMediaAtIndex: (int)index;
@end
/*****************************************************************************
* VLCPlaylistDataSource.h: VLC.framework VLCPlaylistDataSource 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 <VLC/VLCPlaylist.h>
#import <VLC/VLCVideoView.h>
/* This class can be used as a data source for an NSOutlineView
* it will display the playlist content. If provided the videoView
* will automatically be associated to the given playlist, and actions
* in the outlineView will trigger the videoView, visual feedback of the
* current item in the videoview will be displayed in the outlineview
*/
@interface VLCPlaylistDataSource : NSObject
{
VLCPlaylist * playlist;
VLCVideoView * videoView;
NSOutlineView *outlineView;
}
- (id)initWithPlaylist:(VLCPlaylist *)aPlaylist;
- (id)initWithPlaylist:(VLCPlaylist *)aPlaylist videoView:(VLCVideoView *)aVideoView;
- (VLCPlaylist *)playlist;
- (VLCVideoView *)videoView;
@end
/* It could be really useful to use that, this probably need to be reviewed to see
* if it really belongs here */
@interface VLCPlaylistDataSource (OutlineViewDataSource)
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item;
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item;
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item;
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
@end
@interface VLCPlaylistDataSource (OutlineViewDataSourceDropping)
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index;
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;
@end
/*****************************************************************************
* VLCMediaDiscoverer.h: VLC.framework VLCMediaDiscoverer 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>
@interface VLCServicesDiscoverer : NSObject
{
NSArray * services;
}
+ (id)sharedDiscoverer;
- (id)init;
- (NSArray *)services;
@end
/*****************************************************************************
* VLCTime.h: VLC.framework VLCTime 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>
@interface VLCTime : NSObject
{
NSNumber * value;
}
- (id)initWithNumber:(NSNumber *)aNumber;
- (NSNumber *)numberRepresentation;
- (NSString *)stringRepresentation;
@end
/*****************************************************************************
* 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
/*****************************************************************************
* VLCEventManager.h: VLC.framework VLCEventManager 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 <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;
}
/* 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;
@end
/*****************************************************************************
* VLCLibrary.h: VLC.framework VLCLibrary 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 <Cocoa/Cocoa.h>
#include <vlc/libvlc.h>
#include <vlc/libvlc_structures.h>
#import <VLC/VLCPlaylist.h>
/*
* VLCLibrary object
*/
@interface VLCLibrary : NSObject
+ (libvlc_instance_t *)sharedInstance;
@end
/*
* Utility function
*/
#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 )
{
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 );
}
}
/*
* LibVLCBridging category
*/
@interface VLCPlaylist (LibVLCBridging)
+ (id) playlistWithLibVLCMediaList: (libvlc_media_list_t *)p_new_mlist;
- (libvlc_media_list_t *) libVLCMediaList;
@end
@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
CC=gcc
CFLAGS=-g -O2
OBJCFLAGS=-fobjc-exceptions
LDFLAGS=-single_module -read_only_relocs suppress
# We should set this properly.
srcdir=../../..
LIBVLC=$(srcdir)/src/.libs/libvlc.1.dylib $(srcdir)/src/.libs/libvlc-control.0.dylib
LIBVLC_HEADERS=$(srcdir)/include
VLCCONFIG=$(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)
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: $(srcdir)/src/.libs/libvlc.dylib VLC.framework/lib
cp -f $(srcdir)/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
VLC.framework/lib/libvlc-control.dylib: $(srcdir)/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 $@
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="$(srcdir)" $(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 $(srcdir)/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 $(srcdir)/extras/contrib/vlc-lib; then \
for i in $(srcdir)/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) $(LIBVLC) 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) $(LIBVLC) $(MODULES) $(LIBS) -install_name @loader_path/../Frameworks/VLC.framework/Version/Current/VLC -o VLC.framework/Version/Current/VLC && \
install_name_tool -change /usr/local/lib/libvlc-control.0.dylib \
`pwd`/VLC.framework/lib/libvlc-control.dylib \
VLC.framework/Version/Current/VLC && \
install_name_tool -change /usr/local/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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>Quartz</string>
<key>CFBundleIdentifier</key>
<string>org.videolan.vlcframework</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>VLC</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleVersion</key>
<string>0.1</string>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>ProjectName</key>
<string>VLC</string>
</dict>
</plist>
/*****************************************************************************
* VLCTime.h: VLC.framework VLCTime 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 "VLCEventManager.h"
#import <pthread.h>
static VLCEventManager * defaultManager = NULL;
enum message_type_t
{
VLCNotification,
VLCObjectMethodWithObjectArg
};
struct message {
id target;
SEL sel;
union u
{
NSString * name;
id object;
} u;
enum message_type_t type;
};
@interface VLCEventManager (Private)
- (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)
{
VLCEventManager * self = user_data;
for(;;)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
struct message * message, * message_newer = NULL;
NSData *dataMessage;
int i;
/* Wait for some data */
pthread_mutex_lock( [self queueLock] );
/* Wait until we have something on the queue */
if ([[self messageQueue] count] <= 0 ) do {
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 */
if( message->type == VLCNotification )
{
for( i = 0; i < [[self messageQueue] count]-1; i++ )
{
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];
[message->u.name release];
[[self messageQueue] removeObjectAtIndex: i];
i--;
}
}
}
dataMessage = [[self messageQueue] lastObject];
pthread_mutex_unlock( [self queueLock] );
if( message->type == VLCNotification )
[self performSelectorOnMainThread:@selector(callDelegateOfObjectAndSendNotificationWithArgs:) withObject:[dataMessage retain] waitUntilDone: NO];
else
[self performSelectorOnMainThread:@selector(callObjectMethodWithArgs:) withObject:[dataMessage retain] waitUntilDone: NO];
pthread_mutex_lock( [self queueLock] );
[[self messageQueue] removeLastObject];
pthread_mutex_unlock( [self queueLock] );
[pool release];
}
}
@implementation VLCEventManager
+ (id)sharedManager
{
/* We do want a lock here to avoid leaks */
if ( !defaultManager )
{
defaultManager = [[VLCEventManager alloc] init];
}
return defaultManager;
}
- (id)init
{
if( self = [super init] )
{
pthread_mutex_init( &queueLock, NULL );
pthread_cond_init( &signalData, NULL );
pthread_create( &dispatcherThread, NULL, EventDispatcherMainLoop, self );
messageQueue = [[NSMutableArray alloc] initWithCapacity:10];
}
return self;
}
- (void)dealloc
{
pthread_kill( dispatcherThread, SIGKILL );
pthread_join( dispatcherThread, NULL );
[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 };
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 };
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)
- (void)callDelegateOfObjectAndSendNotificationWithArgs:(NSData*)data
{
struct message * message = (struct message *)[data bytes];
[self callDelegateOfObject:message->target withDelegateMethod:message->sel withNotificationName:message->u.name];
[message->u.name release];
[message->target release];
[data release];
}
- (void)callObjectMethodWithArgs:(NSData*)data
{
struct message * message = (struct message *)[data bytes];
void (*method)(id, SEL, id) = (void (*)(id, SEL, id))[message->target methodForSelector: message->sel];
method( message->target, message->sel, message->u.object);
[message->u.object release];
[message->target release];
[data release];
}
- (NSMutableArray *)messageQueue
{
return messageQueue;
}
- (pthread_cond_t *)signalData
{
return &signalData;
}
- (pthread_mutex_t *)queueLock
{
return &queueLock;
}
- (void)callDelegateOfObject:(id) aTarget withDelegateMethod:(SEL)aSelector withNotificationName: (NSString *)aNotificationName
{
NSMethodSignature * aSignature;
NSInvocation * anInvocation;
[[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
/*****************************************************************************
* VLCLibrary.h: VLC.framework VLCLibrary 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 "VLCLibrary.h"
static libvlc_instance_t * shared_instance = NULL;
@implementation VLCLibrary
+ (libvlc_instance_t *)sharedInstance
{
if(!shared_instance)
{
libvlc_exception_t ex;
char *lib_vlc_params[] = { "vlc", "-I", "dummy", "-vvvvvv" };
libvlc_exception_init( &ex );
shared_instance = libvlc_new( 4, lib_vlc_params, &ex );
quit_on_exception( &ex );
}
return shared_instance;
}
@end
/*****************************************************************************
* VLCMedia.m: VLC.framework VLCMedia 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 <Cocoa/Cocoa.h>
#import <VLC/VLCMedia.h>
#import <VLC/VLCPlaylist.h>
#import "VLCEventManager.h"
#import "VLCLibrary.h"
#include <vlc/libvlc.h>
NSString * VLCMetaInformationTitle = @"title";
NSString * VLCMetaInformationAuthor = @"author";
NSString * VLCMetaInformationArtwork = @"artwork";
/* Our notification */
NSString * VLCMediaSubItemAdded = @"VLCMediaSubItemAdded";
NSString * VLCMediaMetaChanged = @"VLCMediaMetaChanged";
/* libvlc event callback */
static void HandleMediaSubItemAdded( const libvlc_event_t * event, void * self)
{
[[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
withDelegateMethod: @selector(subItemAdded:)
withNotificationName: VLCMediaSubItemAdded];
}
/* libvlc event callback */
static void HandleMediaMetaChanged( const libvlc_event_t * event, void * self)
{
[[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
withDelegateMethod: @selector(metaChanged:)
withNotificationName: VLCMediaMetaChanged];
}
@interface VLCMedia (Private)
- (void)initializeInternalMediaDescriptor;
- (void)subItemAdded:(NSNotification *)notification;
- (void)metaChanged:(NSNotification *)notification;
- (void)fetchMetaInformation;
@end
@implementation VLCMedia (Private)
- (void)initializeInternalMediaDescriptor
{
[[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];
}
- (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
{
[self fetchMetaInformation];
}
- (void)fetchMetaInformation
{
NSMutableDictionary * temp;
libvlc_exception_t ex;
char * title;
char * artist;
char * arturl = NULL;
libvlc_exception_init( &ex );
title = libvlc_media_descriptor_get_meta( md, libvlc_meta_Title, &ex );
quit_on_exception( &ex );
artist = libvlc_media_descriptor_get_meta( md, libvlc_meta_Artist, &ex );
quit_on_exception( &ex );
arturl = libvlc_media_descriptor_get_meta( md, libvlc_meta_ArtworkURL, &ex );
quit_on_exception( &ex );
temp = [NSMutableDictionary dictionaryWithCapacity: 2];
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
free( title );
free( artist );
free( arturl );
[self willChangeValueForKey:@"metaInformation"];
if( metaInformation )
[metaInformation release];
metaInformation = [[NSMutableDictionary alloc] initWithDictionary:temp];
[self didChangeValueForKey:@"metaInformation"];
}
@end
@implementation VLCMedia
- (id)initWithURL:(NSString *)anURL
{
if (self = [super init])
{
libvlc_exception_t ex;
url = [anURL copy];
libvlc_exception_init( &ex );
md = libvlc_media_descriptor_new( [VLCLibrary sharedInstance],
[anURL cString],
&ex );
quit_on_exception( &ex );
metaInformation = nil;
[self initializeInternalMediaDescriptor];
}
return self;
}
+ (id)mediaWithURL:(NSString *)anURL;
{
return [[(VLCMedia*)[VLCMedia alloc] initWithURL: anURL ] autorelease];
}
- (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_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 );
}
[super release];
}
}
- (void) dealloc
{
if( subitems )
[subitems release];
if( metaInformation )
[metaInformation release];
libvlc_media_descriptor_release( md );
[url release];
[super dealloc];
}
- (NSString *)url
{
return [[url copy] autorelease];
}
- (VLCPlaylist *)subitems
{
return subitems;
}
/* Returns a dictionary with corresponding object associated with a meta */
- (NSDictionary *)metaInformation
{
return metaInformation;
}
/* Not supported yet */
- (id)delegate
{
return nil;
}
@end
@implementation VLCMedia (LibVLCBridging)
- (id) initWithLibVLCMediaDescriptor: (libvlc_media_descriptor_t *)p_md
{
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 );
quit_on_exception( &ex );
url = [[NSString stringWithCString: p_url] retain];
libvlc_media_descriptor_retain( p_md );
md = p_md;
[self initializeInternalMediaDescriptor];
}
return self;
}
+ (id) mediaWithLibVLCMediaDescriptor: (libvlc_media_descriptor_t *)p_md
{
return [[[VLCMedia alloc] initWithLibVLCMediaDescriptor: p_md] autorelease];
}
- (libvlc_media_descriptor_t *) libVLCMediaDescriptor
{
libvlc_media_descriptor_retain( md );
return md;
}
@end
\ No newline at end of file
/*****************************************************************************
* VLCMediaDiscoverer.m: VLC.framework VLCMediaDiscoverer 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 <Cocoa/Cocoa.h>
#import <VLC/VLCMediaDiscoverer.h>
#import "VLCLibrary.h"
#include <vlc/libvlc.h>
@implementation VLCMediaDiscoverer
- (id)initWithName:(NSString *)aServiceName
{
if (self = [super init])
{
libvlc_exception_t ex;
libvlc_exception_init( &ex );
localizedName = nil;
playlist = nil;
mdis = libvlc_media_discoverer_new_from_name( [VLCLibrary sharedInstance],
[aServiceName cString],
&ex );
quit_on_exception( &ex );
}
return self;
}
- (void)dealloc
{
if( localizedName )
[localizedName release];
if( playlist )
[playlist release];
libvlc_media_discoverer_release( mdis );
[super dealloc];
}
- (VLCPlaylist *) playlist
{
if( playlist )
return playlist;
libvlc_media_list_t * p_mlist = libvlc_media_discoverer_media_list( mdis );
VLCPlaylist * ret = [VLCPlaylist playlistWithLibVLCMediaList: p_mlist];
libvlc_media_list_release( p_mlist );
/* Hack until this gets done properly upstream */
char * name = libvlc_media_discoverer_localized_name( mdis );
if( !name )
{
VLCMedia * media = [ret mediaAtIndex: 0];
ret = media ? (VLCPlaylist *)[media subitems] : nil;
}
free(name);
if( ret )
{
playlist = [ret retain];
}
return ret;
}
- (NSString *)localizedName
{
NSString * ret = nil;
char * name = libvlc_media_discoverer_localized_name( mdis );
if( localizedName )
return localizedName;
if (name)
{
ret = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
free( name );
}
/* XXX: Hack until this gets done properly upstream. This is really slow. */
if (!ret)
{
libvlc_media_list_t * p_mlist = libvlc_media_discoverer_media_list( mdis );
ret = [[[[VLCPlaylist playlistWithLibVLCMediaList: p_mlist] mediaAtIndex:0] metaInformation] objectForKey: VLCMetaInformationTitle];
libvlc_media_list_release( p_mlist );
}
if( ret )
{
localizedName = [ret retain];
}
return localizedName;
}
@end
/*****************************************************************************
* VLCMediaDiscoverer.m: VLC.framework VLCMediaDiscoverer 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 <Cocoa/Cocoa.h>
#import <VLC/VLCMediaLibrary.h>
#import "VLCLibrary.h"
#include <vlc/libvlc.h>
static VLCMediaLibrary * sharedMediaLibrary = NULL;
@implementation VLCMediaLibrary
+ (id)sharedMediaLibrary
{
if( !sharedMediaLibrary )
{
sharedMediaLibrary = [[VLCMediaLibrary alloc] init];
}
return sharedMediaLibrary;
}
- (id)init
{
if (self = [super init])
{
libvlc_exception_t p_e;
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 );
allMedia = nil;
}
return self;
}
- (void)dealloc
{
if (allMedia)
[allMedia release];
libvlc_media_library_release( mlib );
[super dealloc];
}
- (VLCPlaylist *)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 );
}
return allMedia;
}
- (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];
return ret;
}
@end
This diff is collapsed.
/*****************************************************************************
* VLCPlaylistDataSource.m: VLC.framework VLCPlaylistDataSource 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 <VLC/VLCPlaylistDataSource.h>
#import "VLCEventManager.h"
@implementation VLCPlaylistDataSource
- (id)init
{
if (self = [super init])
{
playlist = nil;
videoView = nil;
}
return self;
}
- (id)initWithPlaylist:(VLCPlaylist *)aPlaylist
{
if (self = [super init])
{
playlist = [aPlaylist retain];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(playlistDidChange:) name:VLCPlaylistItemAdded object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(itemDidAddSubitem:) name:VLCMediaSubItemAdded object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(itemDidChange:) name:VLCPlaylistItemChanged object:nil];
videoView = nil;
outlineView = nil;
}
return self;
}
- (id)initWithPlaylist:(VLCPlaylist *)aPlaylist videoView:(VLCVideoView *)aVideoView;
{
if (self = [super init])
{
playlist = [aPlaylist retain];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(playlistDidChange:) name:VLCPlaylistItemAdded object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(itemDidAddSubitem:) name:VLCMediaSubItemAdded object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(itemDidChange:) name:VLCPlaylistItemChanged object:nil];
videoView = [aVideoView retain];
/* Will be automatically set if an outline view ask us data,
* be careful not to connect two outlineView to this object or this goes wrong. */
outlineView = nil;
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
if (playlist)
[playlist release];
if (videoView)
[videoView release];
[super dealloc];
}
- (VLCPlaylist *)playlist
{
return playlist;
}
- (VLCVideoView *)videoView
{
return videoView;
}
@end
@implementation VLCPlaylistDataSource (OutlineViewDataSource)
- (BOOL) outlineView: (NSOutlineView *)ov isItemExpandable: (id)item { return NO; }
- (int) outlineView: (NSOutlineView *)ov numberOfChildrenOfItem:(id)item { return 0; }
- (id) outlineView: (NSOutlineView *)ov child:(int)index ofItem:(id)item { return nil; }
- (id) outlineView: (NSOutlineView *)ov objectValueForTableColumn:(NSTableColumn*)col byItem:(id)item { return nil; }
@end
@implementation VLCPlaylistDataSource (TableViewDropping)
/* Dummy implementation cause we need them */
- (int)numberOfRowsInTableView:(NSTableView *)aTableView { return 0; }
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex {return nil;}
- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op
{
return NSDragOperationEvery; /* This is for now */
}
- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
row:(int)row dropOperation:(NSTableViewDropOperation)operation
{
int i;
NSArray * droppedItems = [[info draggingPasteboard] propertyListForType: NSFilenamesPboardType];
for (i = 0; i < [droppedItems count]; i++)
{
NSString * filename = [droppedItems objectAtIndex:i];
[[self playlist] insertMedia:[VLCMedia mediaWithURL:filename] atIndex:row+i];
}
}
@end
@interface NSObject (UnknownBindingsObject)
/* OutlineViewDataSourceDropping and bindings hack */
- (id)observedObject;
@end
@implementation VLCPlaylistDataSource (OutlineViewDataSourceDropping)
- (BOOL)outlineView:(NSOutlineView *)aOutlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
{
NSArray * droppedItems = [[info draggingPasteboard] propertyListForType: NSFilenamesPboardType];
VLCPlaylist * aPlaylist;
int i;
if (!item)
item = [self playlist]; /* The root object is our playlist */
else
item = [item observedObject];
if (![item isMemberOfClass:[VLCPlaylist class]])
return NO;
if (index < 0) /* No precise item given, put it as the first one */
index = 0;
aPlaylist = item;
if (!droppedItems)
{
/* XXX: localization */
NSRunCriticalAlertPanelRelativeToWindow(@"Error", @"Unable to drop the provided item.", @"OK", nil, nil, [outlineView window]);
return NO;
}
for (i = 0; i < [droppedItems count]; i++)
{
NSString * filename = [droppedItems objectAtIndex:i];
[aPlaylist insertMedia:[VLCMedia mediaWithURL:filename] atIndex:index+i];
}
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)aOutlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
{
return NSDragOperationEvery;
}
@end
\ No newline at end of file
/*****************************************************************************
* VLCMediaDiscoverer.m: VLC.framework VLCMediaDiscoverer 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 <Cocoa/Cocoa.h>
#import <VLC/VLCServicesDiscoverer.h>
#import <VLC/VLCMediaDiscoverer.h>
#import "VLCLibrary.h"
#include <vlc/libvlc.h>
static VLCServicesDiscoverer * sharedDiscoverer = NULL;
@implementation VLCServicesDiscoverer
+ (id)sharedDiscoverer
{
if (!sharedDiscoverer)
{
sharedDiscoverer = [[self alloc] init];
}
return sharedDiscoverer;
}
- (id) init
{
if( self = [super init] )
{
services = [[NSArray arrayWithObjects:
[[[VLCMediaDiscoverer alloc] initWithName:@"sap"] autorelease],
[[[VLCMediaDiscoverer alloc] initWithName:@"shoutcast"] autorelease],
[[[VLCMediaDiscoverer alloc] initWithName:@"shoutcasttv"] autorelease], nil] retain];
}
return self;
}
- (NSArray *) services
{
return [[services copy] autorelease];
}
@end
/*****************************************************************************
* VLCTime.h: VLC.framework VLCTime 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 <VLC/VLCTime.h>
@implementation VLCTime
- (id)initWithNumber:(NSNumber *)aNumber
{
if (self = [super init])
{
value = [aNumber copy];
}
return self;
}
- (void)dealloc
{
[value release];
[super dealloc];
}
- (NSNumber *)numberRepresentation
{
[[value copy] autorelease];
}
- (NSString *)stringRepresentation
{
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;
return [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
}
@end
/*****************************************************************************
* VLCVideoView.h: VLC.framework VLCVideoView 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 <VLC/VLCVideoView.h>
#import "VLCLibrary.h"
#import "VLCEventManager.h"
/* Libvlc */
#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";
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];
}
static void HandleMediaListPlayerPlayed( const libvlc_event_t * event, void * self )
{
[[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
withDelegateMethod: @selector(videoDidPlay:)
withNotificationName: VLCVideoDidPlay];
}
static void HandleMediaListPlayerStopped( const libvlc_event_t * event, void * self )
{
[[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject: self
withDelegateMethod: @selector(videoDidStop:)
withNotificationName: VLCVideoDidStop];
}
@implementation VLCVideoView
- (id)initWithFrame:(NSRect)frameRect
{
if (self = [super initWithFrame: frameRect])
{
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];
}
return self;
}
- (void)dealloc
{
libvlc_media_instance_release( p_mi );
if (delegate)
{
[delegate release];
delegate = nil;
}
[super dealloc];
}
- (void)setPlaylist: (VLCPlaylist *)newPlaylist
{
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 );
}
- (VLCPlaylist *)playlist
{
return playlist;
}
/* Play */
- (void)play
{
libvlc_exception_t p_e;
libvlc_exception_init( &p_e );
libvlc_media_list_player_play( p_mlp, &p_e );
quit_on_exception( &p_e );
}
- (void)playItemAtIndex:(int) i
{
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 );
}
- (void)playMedia:(VLCMedia *) media
{
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 );
}
- (void)pause
{
libvlc_exception_t p_e;
libvlc_exception_init( &p_e );
//libvlc_media_list_player_pause( p_mlp, &p_e );
quit_on_exception( &p_e );
}
- (void)setCurrentTime:(VLCTime *)timeObj
{
}
/* State */
- (BOOL)isPlaying
{
//libvlc_media_list_player_is_playing( p_mlp, &p_e );
//quit_on_exception( &p_e );
return FALSE;
}
- (BOOL)isPaused
{
return FALSE;
}
- (VLCTime *)currentTime
{
return NULL;
}
- (id)currentPlaylistItem
{
return NULL;
}
/* Video output property */
- (void)setStretchesVideo:(BOOL)flag
{
stretchVideo = flag;
}
- (BOOL)stretchesVideo
{
return stretchVideo;
}
/* Fullscreen */
- (void)enterFullscreen
{
}
- (void)leaveFullscreen
{
}
/* Delegate */
- (void)setDelegate: (id)newDelegate
{
if (delegate)
[delegate release];
delegate = [newDelegate retain];
}
- (id)delegate
{
return delegate;
}
@end
@implementation VLCVideoView (NSViewSubclass)
- (void)drawRect:(NSRect)aRect
{
[self lockFocus];
[[NSColor blackColor] set];
NSRectFill(aRect);
[self unlockFocus];
}
- (BOOL)preservesContentDuringLiveResize
{
return NO;//YES;
}
- (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
//
// 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment