]> git.sesse.net Git - vlc/blob - projects/macosx/framework/Sources/VLCMedia.m
VLCKit: Import MobileVLCKit.
[vlc] / projects / macosx / framework / Sources / VLCMedia.m
1 /*****************************************************************************
2  * VLCMedia.m: VLCKit.framework VLCMedia implementation
3  *****************************************************************************
4  * Copyright (C) 2007 Pierre d'Herbemont
5  * Copyright (C) 2007 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "VLCMedia.h"
26 #import "VLCMediaList.h"
27 #import "VLCEventManager.h"
28 #import "VLCLibrary.h"
29 #import "VLCLibVLCBridging.h"
30 #include <vlc/libvlc.h>
31
32 /* Meta Dictionary Keys */
33 NSString * VLCMetaInformationTitle          = @"title";
34 NSString * VLCMetaInformationArtist         = @"artist";
35 NSString * VLCMetaInformationGenre          = @"genre";
36 NSString * VLCMetaInformationCopyright      = @"copyright";
37 NSString * VLCMetaInformationAlbum          = @"album";
38 NSString * VLCMetaInformationTrackNumber    = @"trackNumber";
39 NSString * VLCMetaInformationDescription    = @"description";
40 NSString * VLCMetaInformationRating         = @"rating";
41 NSString * VLCMetaInformationDate           = @"date";
42 NSString * VLCMetaInformationSetting        = @"setting";
43 NSString * VLCMetaInformationURL            = @"url";
44 NSString * VLCMetaInformationLanguage       = @"language";
45 NSString * VLCMetaInformationNowPlaying     = @"nowPlaying";
46 NSString * VLCMetaInformationPublisher      = @"publisher";
47 NSString * VLCMetaInformationEncodedBy      = @"encodedBy";
48 NSString * VLCMetaInformationArtworkURL     = @"artworkURL";
49 NSString * VLCMetaInformationArtwork        = @"artwork";
50 NSString * VLCMetaInformationTrackID        = @"trackID";
51
52 /* Notification Messages */
53 NSString * VLCMediaMetaChanged              = @"VLCMediaMetaChanged";
54
55 /******************************************************************************
56  * @property (readwrite)
57  */
58 @interface VLCMedia ()
59 @property (readwrite) VLCMediaState state;
60 @end
61
62 /******************************************************************************
63  * Interface (Private)
64  */
65 // TODO: Documentation
66 @interface VLCMedia (Private)
67 /* Statics */
68 + (libvlc_meta_t)stringToMetaType:(NSString *)string;
69 + (NSString *)metaTypeToString:(libvlc_meta_t)type;
70
71 /* Initializers */
72 - (void)initInternalMediaDescriptor;
73
74 /* Operations */
75 - (void)fetchMetaInformationFromLibVLCWithType:(NSString*)metaType;
76 #if !TARGET_OS_IPHONE
77 - (void)fetchMetaInformationForArtWorkWithURL:(NSString *)anURL;
78 - (void)setArtwork:(NSImage *)art;
79 #endif
80
81 - (void)parseIfNeeded;
82
83 /* Callback Methods */
84 - (void)parsedChanged:(NSNumber *)isParsedAsNumber;
85 - (void)metaChanged:(NSString *)metaType;
86 - (void)subItemAdded;
87 - (void)setStateAsNumber:(NSNumber *)newStateAsNumber;
88 @end
89
90 static VLCMediaState libvlc_state_to_media_state[] =
91 {
92     [libvlc_NothingSpecial] = VLCMediaStateNothingSpecial,
93     [libvlc_Stopped]        = VLCMediaStateNothingSpecial,
94     [libvlc_Opening]        = VLCMediaStateNothingSpecial,
95     [libvlc_Buffering]      = VLCMediaStateBuffering,
96     [libvlc_Ended]          = VLCMediaStateNothingSpecial,
97     [libvlc_Error]          = VLCMediaStateError,
98     [libvlc_Playing]        = VLCMediaStatePlaying,
99     [libvlc_Paused]         = VLCMediaStatePlaying,
100 };
101
102 static inline VLCMediaState LibVLCStateToMediaState( libvlc_state_t state )
103 {
104     return libvlc_state_to_media_state[state];
105 }
106
107 /******************************************************************************
108  * LibVLC Event Callback
109  */
110 static void HandleMediaMetaChanged(const libvlc_event_t * event, void * self)
111 {
112     if( event->u.media_meta_changed.meta_type == libvlc_meta_Publisher ||
113         event->u.media_meta_changed.meta_type == libvlc_meta_NowPlaying )
114     {
115         /* Skip those meta. We don't really care about them for now.
116          * And they occure a lot */
117         return;
118     }
119     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
120     [[VLCEventManager sharedManager] callOnMainThreadObject:self
121                                                  withMethod:@selector(metaChanged:)
122                                        withArgumentAsObject:[VLCMedia metaTypeToString:event->u.media_meta_changed.meta_type]];
123     [pool drain];
124 }
125
126 static void HandleMediaDurationChanged(const libvlc_event_t * event, void * self)
127 {
128     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
129
130     [[VLCEventManager sharedManager] callOnMainThreadObject:self
131                                                  withMethod:@selector(setLength:)
132                                        withArgumentAsObject:[VLCTime timeWithNumber:
133                                            [NSNumber numberWithLongLong:event->u.media_duration_changed.new_duration]]];
134     [pool drain];
135 }
136
137 static void HandleMediaStateChanged(const libvlc_event_t * event, void * self)
138 {
139     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
140
141     [[VLCEventManager sharedManager] callOnMainThreadObject:self
142                                                  withMethod:@selector(setStateAsNumber:)
143                                        withArgumentAsObject:[NSNumber numberWithInt:
144                                             LibVLCStateToMediaState(event->u.media_state_changed.new_state)]];
145     [pool drain];
146 }
147
148 static void HandleMediaSubItemAdded(const libvlc_event_t * event, void * self)
149 {
150     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
151     [[VLCEventManager sharedManager] callOnMainThreadObject:self
152                                                  withMethod:@selector(subItemAdded)
153                                        withArgumentAsObject:nil];
154     [pool drain];
155 }
156
157 static void HandleMediaParsedChanged(const libvlc_event_t * event, void * self)
158 {
159     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
160     [[VLCEventManager sharedManager] callOnMainThreadObject:self
161                                                  withMethod:@selector(parsedChanged:)
162                                        withArgumentAsObject:[NSNumber numberWithBool:event->u.media_parsed_changed.new_status]];
163     [pool release];
164 }
165
166
167 /******************************************************************************
168  * Implementation
169  */
170 @implementation VLCMedia
171 + (id)mediaWithURL:(NSURL *)anURL;
172 {
173     return [[[VLCMedia alloc] initWithURL:anURL] autorelease];
174 }
175
176 + (id)mediaWithPath:(NSString *)aPath;
177 {
178     return [[[VLCMedia alloc] initWithPath:aPath] autorelease];
179 }
180
181 + (id)mediaAsNodeWithName:(NSString *)aName;
182 {
183     return [[[VLCMedia alloc] initAsNodeWithName:aName] autorelease];
184 }
185
186 - (id)initWithPath:(NSString *)aPath
187 {
188     return [self initWithURL:[NSURL fileURLWithPath:aPath isDirectory:NO]];
189 }
190
191 - (id)initWithURL:(NSURL *)anURL
192 {
193     if (self = [super init])
194     {
195         p_md = libvlc_media_new_location([VLCLibrary sharedInstance],
196                                            [[anURL absoluteString] UTF8String]);
197
198         delegate = nil;
199         metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3];
200
201         // This value is set whenever the demuxer figures out what the length is.
202         // TODO: Easy way to tell the length of the movie without having to instiate the demuxer.  Maybe cached info?
203         length = nil;
204
205         [self initInternalMediaDescriptor];
206     }
207     return self;
208 }
209
210 - (id)initAsNodeWithName:(NSString *)aName
211 {
212     if (self = [super init])
213     {
214         p_md = libvlc_media_new_as_node([VLCLibrary sharedInstance],
215                                                    [aName UTF8String]);
216
217         delegate = nil;
218         metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3];
219
220         // This value is set whenever the demuxer figures out what the length is.
221         // TODO: Easy way to tell the length of the movie without having to instiate the demuxer.  Maybe cached info?
222         length = nil;
223
224         [self initInternalMediaDescriptor];
225     }
226     return self;
227 }
228
229 - (void)setValue:(NSString *)value forMeta:(NSString *)meta
230 {
231     libvlc_meta_t metaName = [VLCMedia stringToMetaType:meta];
232     NSAssert(metaName >= 0, @"Invalid meta");
233     libvlc_media_set_meta(p_md, metaName, [value UTF8String]);
234 }
235
236 - (void)dealloc
237 {
238     libvlc_event_manager_t * p_em = libvlc_media_event_manager(p_md);
239     libvlc_event_detach(p_em, libvlc_MediaMetaChanged,     HandleMediaMetaChanged,     self);
240     libvlc_event_detach(p_em, libvlc_MediaDurationChanged, HandleMediaDurationChanged, self);
241     libvlc_event_detach(p_em, libvlc_MediaStateChanged,    HandleMediaStateChanged,    self);
242     libvlc_event_detach(p_em, libvlc_MediaSubItemAdded,    HandleMediaSubItemAdded,    self);
243     libvlc_event_detach(p_em, libvlc_MediaParsedChanged,   HandleMediaParsedChanged,    self);
244     [[VLCEventManager sharedManager] cancelCallToObject:self];
245
246     // Testing to see if the pointer exists is not required, if the pointer is null
247     // then the release message is not sent to it.
248     delegate = nil;
249     [length release];
250     [url release];
251     [subitems release];
252     [metaDictionary release];
253
254     libvlc_media_release( p_md );
255
256     [super dealloc];
257 }
258
259 - (NSString *)description
260 {
261     NSString * result = [metaDictionary objectForKey:VLCMetaInformationTitle];
262     return [NSString stringWithFormat:@"<%@ %p> %@", [self class], self, (result ? result : [url absoluteString])];
263 }
264
265 - (NSComparisonResult)compare:(VLCMedia *)media
266 {
267     if (self == media)
268         return NSOrderedSame;
269     if (!media)
270         return NSOrderedDescending;
271     return p_md == [media libVLCMediaDescriptor] ? NSOrderedSame : NSOrderedAscending;
272 }
273
274 @synthesize delegate;
275
276 - (VLCTime *)length
277 {
278     if (!length)
279     {
280         // Try figuring out what the length is
281         long long duration = libvlc_media_get_duration( p_md );
282         if (duration > -1)
283         {
284             length = [[VLCTime timeWithNumber:[NSNumber numberWithLongLong:duration]] retain];
285             return [[length retain] autorelease];
286         }
287         return [VLCTime nullTime];
288     }
289     return [[length retain] autorelease];
290 }
291
292 - (VLCTime *)lengthWaitUntilDate:(NSDate *)aDate
293 {
294     static const long long thread_sleep = 10000;
295
296     if (!length)
297     {
298         // Force parsing of this item.
299         [self parseIfNeeded];
300
301         // wait until we are preparsed
302         while (!length && !libvlc_media_is_parsed(p_md) && [aDate timeIntervalSinceNow] > 0)
303         {
304             usleep( thread_sleep );
305         }
306
307         // So we're done waiting, but sometimes we trap the fact that the parsing
308         // was done before the length gets assigned, so lets go ahead and assign
309         // it ourselves.
310         if (!length)
311             return [self length];
312     }
313
314     return [[length retain] autorelease];
315 }
316
317 - (BOOL)isParsed
318 {
319     return isParsed;
320 }
321
322 - (void)parse
323 {
324     libvlc_media_parse_async(p_md);
325 }
326
327 NSString *VLCMediaTracksInformationCodec = @"codec"; // NSNumber
328 NSString *VLCMediaTracksInformationId    = @"id";    // NSNumber
329 NSString *VLCMediaTracksInformationType  = @"type";  // NSString
330
331 NSString *VLCMediaTracksInformationTypeAudio    = @"audio";
332 NSString *VLCMediaTracksInformationTypeVideo    = @"video";
333 NSString *VLCMediaTracksInformationTypeText     = @"text";
334 NSString *VLCMediaTracksInformationTypeUnknown  = @"unknown";
335
336 NSString *VLCMediaTracksInformationCodecProfile  = @"profile"; // NSNumber
337 NSString *VLCMediaTracksInformationCodecLevel    = @"level";   // NSNumber
338
339 NSString *VLCMediaTracksInformationAudioChannelsNumber = @"channelsNumber"; // NSNumber
340 NSString *VLCMediaTracksInformationAudioRate           = @"rate";           // NSNumber
341
342 NSString *VLCMediaTracksInformationVideoHeight = @"height"; // NSNumber
343 NSString *VLCMediaTracksInformationVideoWidth  = @"width";  // NSNumber
344
345 - (NSArray *)tracksInformation
346 {
347     // Trigger parsing if needed
348     [self parseIfNeeded];
349
350     libvlc_media_track_info_t *tracksInfo;
351     int count = libvlc_media_get_tracks_info(p_md, &tracksInfo);
352     NSMutableArray *array = [NSMutableArray array];
353     for (int i = 0; i < count; i++) {
354         NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
355                                            [NSNumber numberWithUnsignedInt:tracksInfo[i].i_codec], VLCMediaTracksInformationCodec,
356                                            [NSNumber numberWithInt:tracksInfo[i].i_id],            VLCMediaTracksInformationId,
357                                            [NSNumber numberWithInt:tracksInfo[i].i_profile],       VLCMediaTracksInformationCodecProfile,
358                                            [NSNumber numberWithInt:tracksInfo[i].i_level],         VLCMediaTracksInformationCodecLevel,
359                                            nil];
360
361         NSString *type;
362         switch (tracksInfo[i].i_type) {
363             case libvlc_track_audio:
364                 type = VLCMediaTracksInformationTypeAudio;
365                 NSNumber *level = [NSNumber numberWithUnsignedInt:tracksInfo[i].u.audio.i_channels];
366                 NSNumber *rate =  [NSNumber numberWithUnsignedInt:tracksInfo[i].u.audio.i_rate];
367                 [dictionary setObject:level forKey:VLCMediaTracksInformationAudioChannelsNumber];
368                 [dictionary setObject:rate  forKey:VLCMediaTracksInformationAudioRate];
369                 break;
370             case libvlc_track_video:
371                 type = VLCMediaTracksInformationTypeVideo;
372                 NSNumber *width =  [NSNumber numberWithUnsignedInt:tracksInfo[i].u.video.i_width];
373                 NSNumber *height = [NSNumber numberWithUnsignedInt:tracksInfo[i].u.video.i_height];
374                 [dictionary setObject:width  forKey:VLCMediaTracksInformationVideoWidth];
375                 [dictionary setObject:height forKey:VLCMediaTracksInformationVideoHeight];
376                 break;
377             case libvlc_track_text:
378                 type = VLCMediaTracksInformationTypeText;
379                 [dictionary setObject:VLCMediaTracksInformationTypeText forKey:VLCMediaTracksInformationType];
380                 break;
381             case libvlc_track_unknown:
382             default:
383                 type = VLCMediaTracksInformationTypeUnknown;
384                 break;
385         }
386         [dictionary setValue:type forKey:VLCMediaTracksInformationType];
387
388         [array addObject:dictionary];
389     }
390     free(tracksInfo);
391     return array;
392 }
393
394
395 @synthesize url;
396 @synthesize subitems;
397 @synthesize metaDictionary;
398 @synthesize state;
399
400 @end
401
402 /******************************************************************************
403  * Implementation VLCMedia (LibVLCBridging)
404  */
405 @implementation VLCMedia (LibVLCBridging)
406
407 + (id)mediaWithLibVLCMediaDescriptor:(void *)md
408 {
409     return [[[VLCMedia alloc] initWithLibVLCMediaDescriptor:md] autorelease];
410 }
411
412 - (id)initWithLibVLCMediaDescriptor:(void *)md
413 {
414     if (self = [super init])
415     {
416         libvlc_media_retain( md );
417         p_md = md;
418
419         metaDictionary = [[NSMutableDictionary alloc] initWithCapacity:3];
420         [self initInternalMediaDescriptor];
421     }
422     return self;
423 }
424
425 - (void *)libVLCMediaDescriptor
426 {
427     return p_md;
428 }
429
430 + (id)mediaWithMedia:(VLCMedia *)media andLibVLCOptions:(NSDictionary *)options
431 {
432     libvlc_media_t * p_md;
433     p_md = libvlc_media_duplicate( [media libVLCMediaDescriptor] );
434
435     for( NSString * key in [options allKeys] )
436     {
437         if ( [options objectForKey:key] != [NSNull null] )
438             libvlc_media_add_option(p_md, [[NSString stringWithFormat:@"%@=%@", key, [options objectForKey:key]] UTF8String]);
439         else
440             libvlc_media_add_option(p_md, [[NSString stringWithFormat:@"%@", key] UTF8String]);
441
442     }
443     return [VLCMedia mediaWithLibVLCMediaDescriptor:p_md];
444 }
445
446 @end
447
448 /******************************************************************************
449  * Implementation VLCMedia (Private)
450  */
451 @implementation VLCMedia (Private)
452
453 + (libvlc_meta_t)stringToMetaType:(NSString *)string
454 {
455     static NSDictionary * stringToMetaDictionary = nil;
456     // TODO: Thread safe-ize
457     if( !stringToMetaDictionary )
458     {
459 #define VLCStringToMeta( name ) [NSNumber numberWithInt: libvlc_meta_##name], VLCMetaInformation##name
460         stringToMetaDictionary =
461             [[NSDictionary dictionaryWithObjectsAndKeys:
462                 VLCStringToMeta(Title),
463                 VLCStringToMeta(Artist),
464                 VLCStringToMeta(Genre),
465                 VLCStringToMeta(Copyright),
466                 VLCStringToMeta(Album),
467                 VLCStringToMeta(TrackNumber),
468                 VLCStringToMeta(Description),
469                 VLCStringToMeta(Rating),
470                 VLCStringToMeta(Date),
471                 VLCStringToMeta(Setting),
472                 VLCStringToMeta(URL),
473                 VLCStringToMeta(Language),
474                 VLCStringToMeta(NowPlaying),
475                 VLCStringToMeta(Publisher),
476                 VLCStringToMeta(ArtworkURL),
477                 VLCStringToMeta(TrackID),
478                 nil] retain];
479 #undef VLCStringToMeta
480     }
481     NSNumber * number = [stringToMetaDictionary objectForKey:string];
482     return number ? [number intValue] : -1;
483 }
484
485 + (NSString *)metaTypeToString:(libvlc_meta_t)type
486 {
487 #define VLCMetaToString( name, type )   if (libvlc_meta_##name == type) return VLCMetaInformation##name;
488     VLCMetaToString(Title, type);
489     VLCMetaToString(Artist, type);
490     VLCMetaToString(Genre, type);
491     VLCMetaToString(Copyright, type);
492     VLCMetaToString(Album, type);
493     VLCMetaToString(TrackNumber, type);
494     VLCMetaToString(Description, type);
495     VLCMetaToString(Rating, type);
496     VLCMetaToString(Date, type);
497     VLCMetaToString(Setting, type);
498     VLCMetaToString(URL, type);
499     VLCMetaToString(Language, type);
500     VLCMetaToString(NowPlaying, type);
501     VLCMetaToString(Publisher, type);
502     VLCMetaToString(ArtworkURL, type);
503     VLCMetaToString(TrackID, type);
504 #undef VLCMetaToString
505     return nil;
506 }
507
508 - (void)initInternalMediaDescriptor
509 {
510     char * p_url = libvlc_media_get_mrl( p_md );
511
512     url = [[NSURL URLWithString:[NSString stringWithUTF8String:p_url]] retain];
513     if( !url ) /* Attempt to interpret as a file path then */
514         url = [[NSURL fileURLWithPath:[NSString stringWithUTF8String:p_url]] retain];
515     free( p_url );
516
517     libvlc_media_set_user_data( p_md, (void*)self );
518
519     libvlc_event_manager_t * p_em = libvlc_media_event_manager( p_md );
520     libvlc_event_attach(p_em, libvlc_MediaMetaChanged,     HandleMediaMetaChanged,     self);
521     libvlc_event_attach(p_em, libvlc_MediaDurationChanged, HandleMediaDurationChanged, self);
522     libvlc_event_attach(p_em, libvlc_MediaStateChanged,    HandleMediaStateChanged,    self);
523     libvlc_event_attach(p_em, libvlc_MediaSubItemAdded,    HandleMediaSubItemAdded,    self);
524     libvlc_event_attach(p_em, libvlc_MediaParsedChanged,   HandleMediaParsedChanged,   self);
525
526     libvlc_media_list_t * p_mlist = libvlc_media_subitems( p_md );
527
528     if (!p_mlist)
529         subitems = nil;
530     else
531     {
532         subitems = [[VLCMediaList mediaListWithLibVLCMediaList:p_mlist] retain];
533         libvlc_media_list_release( p_mlist );
534     }
535
536     isParsed = libvlc_media_is_parsed(p_md);
537     state = LibVLCStateToMediaState(libvlc_media_get_state( p_md ));
538 }
539
540 - (void)fetchMetaInformationFromLibVLCWithType:(NSString *)metaType
541 {
542     char * psz_value = libvlc_media_get_meta( p_md, [VLCMedia stringToMetaType:metaType] );
543     NSString * newValue = psz_value ? [NSString stringWithUTF8String: psz_value] : nil;
544     NSString * oldValue = [metaDictionary valueForKey:metaType];
545     free(psz_value);
546
547     if ( newValue != oldValue && !(oldValue && newValue && [oldValue compare:newValue] == NSOrderedSame) )
548     {
549         // Only fetch the art if needed. (ie, create the NSImage, if it was requested before)
550         if (isArtFetched && [metaType isEqualToString:VLCMetaInformationArtworkURL])
551         {
552             [NSThread detachNewThreadSelector:@selector(fetchMetaInformationForArtWorkWithURL:)
553                                          toTarget:self
554                                        withObject:newValue];
555         }
556
557         [metaDictionary setValue:newValue forKeyPath:metaType];
558     }
559 }
560
561 #if !TARGET_OS_IPHONE
562 - (void)fetchMetaInformationForArtWorkWithURL:(NSString *)anURL
563 {
564     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
565     NSImage * art = nil;
566
567     if( anURL )
568     {
569         // Go ahead and load up the art work
570         NSURL * artUrl = [NSURL URLWithString:[anURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
571         // Don't attempt to fetch artwork from remote. Core will do that alone
572         if ([artUrl isFileURL])
573             art  = [[[NSImage alloc] initWithContentsOfURL:artUrl] autorelease];
574     }
575
576     // If anything was found, lets save it to the meta data dictionary
577     [self performSelectorOnMainThread:@selector(setArtwork:) withObject:art waitUntilDone:NO];
578
579     [pool release];
580 }
581
582 - (void)setArtwork:(NSImage *)art
583 {
584     if (!art)
585     {
586         [metaDictionary removeObjectForKey:@"artwork"];
587         return;
588     }
589
590     [metaDictionary setObject:art forKey:@"artwork"];
591 }
592 #endif
593
594 - (void)parseIfNeeded
595 {
596     if (![self isParsed])
597         [self parse];
598 }
599
600 - (void)metaChanged:(NSString *)metaType
601 {
602     [self fetchMetaInformationFromLibVLCWithType:metaType];
603 }
604
605 - (void)subItemAdded
606 {
607     if( subitems )
608         return; /* Nothing to do */
609
610     libvlc_media_list_t * p_mlist = libvlc_media_subitems( p_md );
611
612     NSAssert( p_mlist, @"The mlist shouldn't be nil, we are receiving a subItemAdded");
613
614     [self willChangeValueForKey:@"subitems"];
615     subitems = [[VLCMediaList mediaListWithLibVLCMediaList:p_mlist] retain];
616     [self didChangeValueForKey:@"subitems"];
617     libvlc_media_list_release( p_mlist );
618 }
619
620 - (void)parsedChanged:(NSNumber *)isParsedAsNumber
621 {
622     [self willChangeValueForKey:@"parsed"];
623     isParsed = [isParsedAsNumber boolValue];
624     [self didChangeValueForKey:@"parsed"];
625
626     // FIXME: Probably don't even call this if there is no delegate.
627     if (!delegate || !isParsed)
628         return;
629
630     if ([delegate respondsToSelector:@selector(mediaDidFinishParsing:)]) {
631         [delegate mediaDidFinishParsing:self];
632     }
633 }
634
635 - (void)setStateAsNumber:(NSNumber *)newStateAsNumber
636 {
637     [self setState: [newStateAsNumber intValue]];
638 }
639
640 #if TARGET_OS_IPHONE
641 - (NSDictionary *)metaDictionary
642 {
643     if (!areOthersMetaFetched) {
644         areOthersMetaFetched = YES;
645         /* Force VLCMetaInformationTitle, that will trigger preparsing
646          * And all the other meta will be added through the libvlc event system */
647         [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationTitle];
648
649     }
650     if (!isArtURLFetched)
651     {
652         isArtURLFetched = YES;
653         /* Force isArtURLFetched, that will trigger artwork download eventually
654          * And all the other meta will be added through the libvlc event system */
655         [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtworkURL];
656     }
657     return metaDictionary;
658 }
659
660 #else
661
662 - (id)valueForKeyPath:(NSString *)keyPath
663 {
664     if( !isArtFetched && [keyPath isEqualToString:@"metaDictionary.artwork"])
665     {
666         isArtFetched = YES;
667         /* Force the retrieval of the artwork now that someone asked for it */
668         [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtworkURL];
669     }
670     else if( !areOthersMetaFetched && [keyPath hasPrefix:@"metaDictionary."])
671     {
672         areOthersMetaFetched = YES;
673         /* Force VLCMetaInformationTitle, that will trigger preparsing
674          * And all the other meta will be added through the libvlc event system */
675         [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationTitle];
676
677     }
678     else if( !isArtURLFetched && [keyPath hasPrefix:@"metaDictionary.artworkURL"])
679     {
680         isArtURLFetched = YES;
681         /* Force isArtURLFetched, that will trigger artwork download eventually
682          * And all the other meta will be added through the libvlc event system */
683         [self fetchMetaInformationFromLibVLCWithType: VLCMetaInformationArtworkURL];
684     }
685     return [super valueForKeyPath:keyPath];
686 }
687 #endif
688 @end
689
690 /******************************************************************************
691  * Implementation VLCMedia (VLCMediaPlayerBridging)
692  */
693
694 @implementation VLCMedia (VLCMediaPlayerBridging)
695
696 - (void)setLength:(VLCTime *)value
697 {
698     if (length && value && [length compare:value] == NSOrderedSame)
699         return;
700
701     [length release];
702     length = value ? [value retain] : nil;
703 }
704
705 @end