VLCMediaPlayer.m 27.5 KB
Newer Older
1
/*****************************************************************************
2
 * VLCMediaPlayer.m: VLCKit.framework VLCMediaPlayer implementation
3
 *****************************************************************************
4
5
6
 * Copyright (C) 2007-2009 Pierre d'Herbemont
 * Copyright (C) 2007-2009 the VideoLAN team
 * Partial Copyright (C) 2009 Felix Paul Kühne
7
8
9
10
 * $Id$
 *
 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
 *          Faustion Osuna <enrique.osuna # gmail.com>
11
 *          Felix Paul Kühne <fkuehne # videolan.org>
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#import "VLCLibrary.h"
#import "VLCMediaPlayer.h"
#import "VLCEventManager.h"
#import "VLCLibVLCBridging.h"
32
#import "VLCVideoView.h"
33
34
35
36
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

37
38
/* prevent system sleep */
#import <CoreServices/CoreServices.h>
39
40
41
42
/* FIXME: Ugly hack! */
#ifdef __x86_64__
#import <CoreServices/../Frameworks/OSServices.framework/Headers/Power.h>
#endif
43

44
45
46
#include <vlc/vlc.h>

/* Notification Messages */
47
48
NSString * VLCMediaPlayerTimeChanged    = @"VLCMediaPlayerTimeChanged";
NSString * VLCMediaPlayerStateChanged   = @"VLCMediaPlayerStateChanged";
49

50
NSString * VLCMediaPlayerStateToString(VLCMediaPlayerState state)
51
{
52
    static NSString * stateToStrings[] = {
53
54
55
56
57
58
59
60
61
62
63
        [VLCMediaPlayerStateStopped]      = @"VLCMediaPlayerStateStopped",
        [VLCMediaPlayerStateOpening]      = @"VLCMediaPlayerStateOpening",
        [VLCMediaPlayerStateBuffering]    = @"VLCMediaPlayerStateBuffering",
        [VLCMediaPlayerStateEnded]        = @"VLCMediaPlayerStateEnded",
        [VLCMediaPlayerStateError]        = @"VLCMediaPlayerStateError",
        [VLCMediaPlayerStatePlaying]      = @"VLCMediaPlayerStatePlaying",
        [VLCMediaPlayerStatePaused]       = @"VLCMediaPlayerStatePaused"
    };
    return stateToStrings[state];
}

64
/* libvlc event callback */
65
static void HandleMediaInstanceVolumeChanged(const libvlc_event_t * event, void * self)
66
67
{
    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
68
69
                                                   withDelegateMethod:@selector(mediaPlayerVolumeChanged:)
                                                 withNotificationName:VLCMediaPlayerVolumeChanged];
70
71
72
73
}

static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
{
74
75
76
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
                                                 withMethod:@selector(mediaPlayerTimeChanged:) 
77
                                       withArgumentAsObject:[NSNumber numberWithLongLong:event->u.media_player_time_changed.new_time]];
78

79
80
81
    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
                                                   withDelegateMethod:@selector(mediaPlayerTimeChanged:)
                                                 withNotificationName:VLCMediaPlayerTimeChanged];
82
    [pool release];
83
84
}

85
86
87
88
89
90
static void HandleMediaPositionChanged(const libvlc_event_t * event, void * self)
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
                                                 withMethod:@selector(mediaPlayerPositionChanged:) 
91
                                       withArgumentAsObject:[NSNumber numberWithFloat:event->u.media_player_position_changed.new_position]];
92
93
94
    [pool release];
}

95
static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void * self)
96
{
97
    VLCMediaPlayerState newState;
98
    
99
    if( event->type == libvlc_MediaPlayerPlaying )
100
        newState = VLCMediaPlayerStatePlaying;
101
    else if( event->type == libvlc_MediaPlayerPaused )
102
        newState = VLCMediaPlayerStatePaused;
103
    else if( event->type == libvlc_MediaPlayerEndReached )
104
        newState = VLCMediaPlayerStateStopped;
105
    else if( event->type == libvlc_MediaPlayerEncounteredError )
106
        newState = VLCMediaPlayerStateError;
107
108
109
110
111
    else
    {
        NSLog(@"%s: Unknown event", __FUNCTION__);
        return;
    }
112
    
113
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
114
    
115
116
117
    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
                                                 withMethod:@selector(mediaPlayerStateChanged:) 
                                       withArgumentAsObject:[NSNumber numberWithInt:newState]];
118
    
119
    [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
120
121
                                                   withDelegateMethod:@selector(mediaPlayerStateChanged:)
                                                 withNotificationName:VLCMediaPlayerStateChanged];
122
    
123
    [pool release];
124
125
    
}
126

127
128
129
130
131
132
133
134
135
136
static void HandleMediaPlayerMediaChanged(const libvlc_event_t * event, void * self)
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
                                                 withMethod:@selector(mediaPlayerMediaChanged:) 
                                       withArgumentAsObject:[VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_player_media_changed.new_media]];
        
    [pool release];
    
137
138
}

139

140
// TODO: Documentation
141
@interface VLCMediaPlayer (Private)
142
143
- (id)initWithDrawable:(id)aDrawable;

144
145
- (void)registerObservers;
- (void)unregisterObservers;
146
- (void)mediaPlayerTimeChanged:(NSNumber *)newTime;
147
148
- (void)mediaPlayerPositionChanged:(NSNumber *)newTime;
- (void)mediaPlayerStateChanged:(NSNumber *)newState;
149
- (void)mediaPlayerMediaChanged:(VLCMedia *)media;
150
151
152
@end

@implementation VLCMediaPlayer
153

154
/* Bindings */
155
156
157
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    static NSDictionary * dict = nil;
158
    NSSet * superKeyPaths;
159
160
161
162
163
    if( !dict )
    {
        dict = [[NSDictionary dictionaryWithObjectsAndKeys:
            [NSSet setWithObject:@"state"], @"playing",
            [NSSet setWithObjects:@"state", @"media", nil], @"seekable",
164
            [NSSet setWithObjects:@"state", @"media", nil], @"canPause",
165
            [NSSet setWithObjects:@"state", @"media", nil], @"description",
166
167
            nil] retain];
    }
168
169
170
171
172
173
    if( (superKeyPaths = [super keyPathsForValuesAffectingValueForKey: key]) )
    {
        NSMutableSet * ret = [NSMutableSet setWithSet:[dict objectForKey: key]];
        [ret unionSet:superKeyPaths];
        return ret;
    }
174
175
    return [dict objectForKey: key];
}
176
177

/* Contructor */
178
179
- (id)init
{
180
    return [self initWithDrawable:nil];
181
182
183
184
}

- (id)initWithVideoView:(VLCVideoView *)aVideoView
{
185
186
    return [self initWithDrawable: aVideoView];
}
187

188
189
190
- (id)initWithVideoLayer:(VLCVideoLayer *)aVideoLayer
{
    return [self initWithDrawable: aVideoLayer];
191
192
}

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
- (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 */
            [self unregisterObservers];
        }
        [super release];
    }
}

208
209
- (void)dealloc
{
210
211
    NSAssert(libvlc_media_player_get_state(instance, NULL) == libvlc_Stopped, @"You released the media player before ensuring that it is stopped");

212
213
214
    // Always get rid of the delegate first so we can stop sending messages to it
    // TODO: Should we tell the delegate that we're shutting down?
    delegate = nil;
215

216
217
218
219
220
221
    // Clear our drawable as we are going to release it, we don't
    // want the core to use it from this point. This won't happen as
    // the media player must be stopped.
    libvlc_media_player_set_nsobject(instance, nil, NULL);

    libvlc_media_player_release(instance);
222
223
224
    
    // Get rid of everything else
    [media release];
225
    [cachedTime release];
226
    [cachedRemainingTime release];
227
    [drawable release];
228

229
    [super dealloc];
230
231
232
233
}

- (void)setDelegate:(id)value
{
234
    delegate = value;
235
236
237
238
}

- (id)delegate
{
239
    return delegate;
240
241
}

242
243
244
- (void)setVideoView:(VLCVideoView *)aVideoView
{    
    [self setDrawable: aVideoView];
245
246
}

247
- (void)setVideoLayer:(VLCVideoLayer *)aVideoLayer
248
{
249
    [self setDrawable: aVideoLayer];
250
251
}

252
253
254
255
256
- (void)setDrawable:(id)aDrawable
{
    // Make sure that this instance has been associated with the drawing canvas.
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
257
    libvlc_media_player_set_nsobject(instance, aDrawable, &ex);
258
259
260
261
262
263
264
    catch_exception( &ex );
}

- (id)drawable
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
265
    id ret = libvlc_media_player_get_nsobject(instance);
266
    catch_exception( &ex );
267
    return ret;
268
269
}

270
271
- (VLCAudio *)audio
{
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
272
    return [[VLCLibrary sharedLibrary] audio];
273
274
}

275
276
#pragma mark -
#pragma mark Subtitles
277

278
- (void)setCurrentVideoSubTitleIndex:(NSUInteger)index
279
{
280
281
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
282
    libvlc_video_set_spu( instance, (int)index, &ex );
283
    catch_exception( &ex );
284
285
}

286
- (NSUInteger)currentVideoSubTitleIndex
287
{
288
    libvlc_exception_t ex;
289
    libvlc_exception_init( &ex );
290
    NSInteger count = libvlc_video_get_spu_count( instance, &ex );
291
    catch_exception( &ex );
292
293
294
    if (count <= 0)
        return NSNotFound;
    NSUInteger result = libvlc_video_get_spu( instance, &ex );
295
296
    catch_exception( &ex );
    return result;
297
298
}

299
300
301
302
303
304
305
306
307
- (BOOL)openVideoSubTitlesFromFile:(NSString *)path
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    BOOL result = libvlc_video_set_subtitle_file( instance, [path UTF8String], &ex );
    catch_exception( &ex );
    return result;
}

308
309
310
311
- (NSArray *)videoSubTitles
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
312
    NSInteger count = libvlc_video_get_spu_count( instance, &ex );
313
314
    catch_exception( &ex );

315
316
317
    libvlc_track_description_t *tracks = libvlc_video_get_spu_description( instance, &ex );
    NSMutableArray *tempArray = [NSMutableArray array];
    NSInteger i;
318
    for (i = 0; i < count; i++)
319
320
321
322
323
324
325
    {
        [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
        tracks = tracks->p_next;
    }
    return [NSArray arrayWithArray: tempArray];
}

326
327
328
329

#pragma mark -
#pragma mark Video Crop geometry

330
331
- (void)setVideoCropGeometry:(char *)value
{
332
333
334
335
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_video_set_crop_geometry( instance, value, &ex );
    catch_exception( &ex );
336
337
338
339
}

- (char *)videoCropGeometry
{
340
    libvlc_exception_t ex;
341
    libvlc_exception_init( &ex );
342
    char * result = libvlc_video_get_crop_geometry( instance, &ex );
343
    catch_exception( &ex );
344
    return result;
345
346
}

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
- (void)setVideoAspectRatio:(char *)value
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_video_set_aspect_ratio( instance, value, &ex );
    catch_exception( &ex );
}

- (char *)videoAspectRatio
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    char * result = libvlc_video_get_aspect_ratio( instance, &ex );
    catch_exception( &ex );
    return result;
}

364
- (void)setVideoTeleText:(NSUInteger)value
365
{
366
367
368
369
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_video_set_teletext( instance, value, &ex );
    catch_exception( &ex );
370
371
}

372
- (NSUInteger)videoTeleText
373
{
374
    libvlc_exception_t ex;
375
    libvlc_exception_init( &ex );
376
    NSInteger result = libvlc_video_get_teletext( instance, &ex );
377
    catch_exception( &ex );
378
    return result;
379
380
}

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
- (void)saveVideoSnapshotAt: (NSString *)path withWidth:(NSUInteger)width andHeight:(NSUInteger)height
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_video_take_snapshot( instance, [path UTF8String], width, height, &ex );
    catch_exception( &ex );
}

- (void)setDeinterlaceFilter: (NSString *)name enabled: (BOOL)enabled
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_video_set_deinterlace( instance, (int)enabled , [name UTF8String], &ex );
    catch_exception( &ex );
}

397
- (void)setRate:(float)value
398
{
399
400
401
402
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_media_player_set_rate( instance, value, &ex );
    catch_exception( &ex );
403
404
}

405
- (float)rate
406
{
407
    libvlc_exception_t ex;
408
    libvlc_exception_init( &ex );
409
    float result = libvlc_media_player_get_rate( instance, &ex );
410
    catch_exception( &ex );
411
    return result;
412
413
414
415
}

- (NSSize)videoSize
{
416
    libvlc_exception_t ex;
417
    libvlc_exception_init( &ex );
418
419
    NSSize result = NSMakeSize(libvlc_video_get_height((libvlc_media_player_t *)instance, &ex),
                               libvlc_video_get_width((libvlc_media_player_t *)instance, &ex));
420
    catch_exception( &ex );
421
    return result;
422
423
424
425
}

- (BOOL)hasVideoOut
{
426
    libvlc_exception_t ex;
427
    libvlc_exception_init( &ex );
428
    BOOL result = libvlc_media_player_has_vout((libvlc_media_player_t *)instance, &ex);
429
    if (libvlc_exception_raised( &ex ))
430
    {
431
        libvlc_exception_clear( &ex );
432
433
434
435
        return NO;
    }
    else
        return result;
436
437
438
439
}

- (float)framesPerSecond
{
440
    libvlc_exception_t ex;
441
    libvlc_exception_init( &ex );
442
    float result = libvlc_media_player_get_fps( (libvlc_media_player_t *)instance, &ex );
443
    catch_exception( &ex );
444
    return result;
445
446
447
448
}

- (void)setTime:(VLCTime *)value
{
449
    libvlc_exception_t ex;
450
    libvlc_exception_init( &ex );
451
452
    // Time is managed in seconds, while duration is managed in microseconds
    // TODO: Redo VLCTime to provide value numberAsMilliseconds, numberAsMicroseconds, numberAsSeconds, numberAsMinutes, numberAsHours
453
454
    libvlc_media_player_set_time( (libvlc_media_player_t *)instance,
                                    (value ? [[value numberValue] longLongValue] : 0),
455
                                    &ex );
456
    catch_exception( &ex );
457
458
459
460
}

- (VLCTime *)time
{
461
    return cachedTime;
462
463
}

464
465
- (VLCTime *)remainingTime
{
466
    return cachedRemainingTime;
467
468
}

469
- (NSUInteger)fps
470
471
472
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
473
    NSUInteger result = libvlc_media_player_get_fps( instance, &ex );
474
475
476
477
    catch_exception( &ex );
    return result;
}

478
479
480
#pragma mark -
#pragma mark Chapters
- (void)setCurrentChapterIndex:(NSUInteger)value;
481
{
482
483
484
485
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_media_player_set_chapter( instance, value, &ex );
    catch_exception( &ex );
486
487
}

488
- (NSUInteger)currentChapterIndex
489
490
491
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
492
    NSInteger count = libvlc_media_player_get_chapter_count( instance, &ex );
493
    catch_exception( &ex );
494
495
496
    if (count <= 0)
        return NSNotFound;
    NSUInteger result = libvlc_media_player_get_chapter( instance, &ex );
497
    catch_exception( &ex );
498
499
500
    return result;
}

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
- (void)nextChapter
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_media_player_next_chapter( instance, &ex );
    catch_exception( &ex );
}

- (void)previousChapter
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_media_player_previous_chapter( instance, &ex );
    catch_exception( &ex );
}

517
- (NSArray *)chaptersForTitleIndex:(NSUInteger)title
518
519
520
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
521
    NSInteger count = libvlc_media_player_get_chapter_count(instance, &ex);
522
523
524
    if (count <= 0)
        return [NSArray array];

525
526
527
    libvlc_track_description_t *tracks = libvlc_video_get_chapter_description( instance, title, &ex );
    NSMutableArray *tempArray = [NSMutableArray array];
    NSInteger i;
528
    for (i = 0; i < count ; i++)
529
530
531
532
533
534
535
    {
        [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
        tracks = tracks->p_next;
    }
    return [NSArray arrayWithArray: tempArray];
}

536
537
538
539
#pragma mark -
#pragma mark Titles

- (void)setCurrentTitleIndex:(NSUInteger)value
540
541
{
    libvlc_exception_t ex;
542
    libvlc_exception_init( &ex );    
543
544
545
546
    libvlc_media_player_set_title( instance, value, &ex );
    catch_exception( &ex );
}

547
- (NSUInteger)currentTitleIndex
548
549
550
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
551

552
    NSInteger count = libvlc_media_player_get_title_count( instance, &ex );
553
554
555
556
557
    catch_exception( &ex );
    if (count <= 0)
        return NSNotFound;
    
    NSUInteger result = libvlc_media_player_get_title( instance, &ex );
558
559
560
561
    catch_exception( &ex );
    return result;
}

562
- (NSUInteger)countOfTitles
563
564
565
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
566
    NSUInteger result = libvlc_media_player_get_title_count( instance, &ex );
567
568
569
570
    catch_exception( &ex );
    return result;
}

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
- (NSArray *)titles
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_track_description_t *tracks = libvlc_video_get_title_description( instance, &ex );
    NSMutableArray *tempArray = [NSMutableArray array];
    NSInteger i;
    for (i = 0; i < [self countOfTitles] ; i++)
    {
        [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
        tracks = tracks->p_next;
    }
    return [NSArray arrayWithArray: tempArray];
}

586
587
588
#pragma mark -
#pragma mark Audio tracks
- (void)setCurrentAudioTrackIndex:(NSUInteger)value
589
{
590
591
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
592
    libvlc_audio_set_track( instance, (int)value, &ex );
593
    catch_exception( &ex );
594
595
}

596
- (NSUInteger)currentAudioTrackIndex
597
{
598
    libvlc_exception_t ex;
599
    libvlc_exception_init( &ex );
600
    NSInteger count = libvlc_audio_get_track_count( instance, &ex );
601
    catch_exception( &ex );
602
603
604
605
    if (count <= 0)
        return NSNotFound;
    
    NSUInteger result = libvlc_audio_get_track( instance, &ex );
606
    catch_exception( &ex );
607
608
609
    return result;
}

610
611
612
613
- (NSArray *)audioTracks
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
614
    NSInteger count = libvlc_audio_get_track_count( instance, &ex );
615
616
617
618
    catch_exception( &ex );
    if (count <= 0)
        return [NSArray array];

619
620
    libvlc_track_description_t *tracks = libvlc_audio_get_track_description( instance, &ex );
    NSMutableArray *tempArray = [NSMutableArray array];
621
    NSUInteger i;
622
    for (i = 0; i < count ; i++)
623
624
625
626
627
628
629
630
    {
        [tempArray addObject:[NSString stringWithUTF8String: tracks->psz_name]];
        tracks = tracks->p_next;
    }

    return [NSArray arrayWithArray: tempArray];
}

631
- (void)setAudioChannel:(NSInteger)value
632
{
633
634
635
636
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
    libvlc_audio_set_channel( instance, value, &ex );
    catch_exception( &ex );
637
638
}

639
- (NSInteger)audioChannel
640
{
641
    libvlc_exception_t ex;
642
    libvlc_exception_init( &ex );
643
    NSInteger result = libvlc_audio_get_channel( instance, &ex );
644
    catch_exception( &ex );
645
    return result;
646
647
648
649
}

- (void)setMedia:(VLCMedia *)value
{
650
    if (media != value)
651
652
653
654
655
656
657
658
    {
        if (media && [media compare:value] == NSOrderedSame)
            return;
        
        [media release];
        media = [value retain];

        libvlc_exception_t ex;
659
        libvlc_exception_init( &ex );
660
        libvlc_media_player_set_media( instance, [media libVLCMediaDescriptor], &ex );
661
        catch_exception( &ex );
662
    }
663
664
665
666
}

- (VLCMedia *)media
{
667
    return media;
668
669
670
}

- (BOOL)play
671
{    
672
    libvlc_exception_t ex;
673
    libvlc_exception_init( &ex );
674
    libvlc_media_player_play( (libvlc_media_player_t *)instance, &ex );
675
    catch_exception( &ex );
676
    return YES;
677
678
679
680
}

- (void)pause
{
681
682
683
684
685
686
687
688
689
690
    if( [NSThread isMainThread] )
    {
        /* Hack because we create a dead lock here, when the vout is stopped
         * and tries to recontact us on the main thread */
        /* FIXME: to do this properly we need to do some locking. We may want 
         * to move that to libvlc */
        [self performSelectorInBackground:@selector(pause) withObject:nil];
        return;
    }

691
692
    // Pause the stream
    libvlc_exception_t ex;
693
    libvlc_exception_init( &ex );
694
    libvlc_media_player_pause( (libvlc_media_player_t *)instance, &ex );
695
696
697
698
699
700
701

    // fail gracefully
    // in most cases, it's just EOF so let's stop
    if (libvlc_exception_raised(&ex))
        [self stop];

    libvlc_exception_clear(&ex);
702
703
704
705
}

- (void)stop
{
706
707
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
708
    libvlc_media_player_stop((libvlc_media_player_t *)instance, &ex);
709
    catch_exception( &ex );
710
711
}

712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
- (void)fastForward
{
    [self fastForwardAtRate: 2.0];
}

- (void)fastForwardAtRate:(float)rate
{
    [self setRate:rate];
}

- (void)rewind
{
    [self rewindAtRate: 2.0];
}

- (void)rewindAtRate:(float)rate
{
    [self setRate: -rate];
}
731

732
733
734
735
- (void)jumpBackward:(NSInteger)interval
{
    if( [self isSeekable] )
    {
736
        interval = interval * 1000;
737
738
739
740
741
742
743
744
        [self setTime: [VLCTime timeWithInt: ([[self time] intValue] - interval)]];
    }
}

- (void)jumpForward:(NSInteger)interval
{
    if( [self isSeekable] )
    {
745
        interval = interval * 1000;
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
        [self setTime: [VLCTime timeWithInt: ([[self time] intValue] + interval)]];
    }
}

- (void)extraShortJumpBackward
{
    [self jumpBackward:3];
}

- (void)extraShortJumpForward
{
    [self jumpForward:3];
}

- (void)shortJumpBackward
{
    [self jumpBackward:10];
}

- (void)shortJumpForward
{
    [self jumpForward:10];
}

- (void)mediumJumpBackward
{
    [self jumpBackward:60];
}

- (void)mediumJumpForward
{
    [self jumpForward:60];
}

- (void)longJumpBackward
{
    [self jumpBackward:300];
}

- (void)longJumpForward
{
    [self jumpForward:300];
}

790
791
792
793
794
+ (NSSet *)keyPathsForValuesAffectingIsPlaying
{
    return [NSSet setWithObjects:@"state", nil];
}

795
796
- (BOOL)isPlaying
{
797
    VLCMediaPlayerState state = [self state];
798
    return ((state == VLCMediaPlayerStateOpening) || (state == VLCMediaPlayerStateBuffering) ||
799
            (state == VLCMediaPlayerStatePlaying));
800
801
802
803
}

- (BOOL)willPlay
{
804
    libvlc_exception_t ex;
805
    libvlc_exception_init( &ex );
806
    BOOL ret = libvlc_media_player_will_play( (libvlc_media_player_t *)instance, &ex );
807
808
809
810
811
812
813
    if (libvlc_exception_raised(&ex))
    {
        libvlc_exception_clear(&ex);
        return NO;
    }
    else
        return ret;
814
815
}

816
static const VLCMediaPlayerState libvlc_to_local_state[] =
817
{
818
819
    [libvlc_Stopped]    = VLCMediaPlayerStateStopped,
    [libvlc_Opening]    = VLCMediaPlayerStateOpening,
820
    [libvlc_Buffering]  = VLCMediaPlayerStateBuffering,
821
    [libvlc_Playing]    = VLCMediaPlayerStatePlaying,
822
823
824
    [libvlc_Paused]     = VLCMediaPlayerStatePaused,
    [libvlc_Ended]      = VLCMediaPlayerStateEnded,
    [libvlc_Error]      = VLCMediaPlayerStateError
825
826
827
828
};

- (VLCMediaPlayerState)state
{
829
830
    return cachedState;
}
831

832
833
834
835
- (float)position
{
    return position;
}
836

837
838
- (void)setPosition:(float)newPosition
{
839
    libvlc_exception_t ex;
840
    libvlc_exception_init( &ex );
841
    libvlc_media_player_set_position( instance, newPosition, &ex );
842
    catch_exception( &ex );
843
}
844
845
846
847
848

- (BOOL)isSeekable
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
849
    BOOL ret = libvlc_media_player_is_seekable( instance, &ex );
850
    catch_exception( &ex );
851
852
853
    return ret;
}

854
855
856
857
- (BOOL)canPause
{
    libvlc_exception_t ex;
    libvlc_exception_init( &ex );
858
    BOOL ret = libvlc_media_player_can_pause( instance, &ex );
859
860
861
    catch_exception( &ex );
    return ret;
}
862

863
864
865
866
- (void *)libVLCMediaPlayer
{
    return instance;
}
867
868
@end

869
@implementation VLCMediaPlayer (Private)
870
871
872
873
874
875
876
- (id)initWithDrawable:(id)aDrawable
{
    if (self = [super init])
    {
        delegate = nil;
        media = nil;
        cachedTime = [[VLCTime nullTime] retain];
877
        cachedRemainingTime = [[VLCTime nullTime] retain];
878
879
880
881
882
883
884
885
        position = 0.0f;
        cachedState = VLCMediaPlayerStateStopped;

        // Create a media instance, it doesn't matter what library we start off with
        // it will change depending on the media descriptor provided to the media
        // instance
        libvlc_exception_t ex;
        libvlc_exception_init( &ex );
886
        instance = (void *)libvlc_media_player_new([VLCLibrary sharedInstance], &ex);
887
888
889
890
891
892
893
894
895
        catch_exception( &ex );
        
        [self registerObservers];
        
        [self setDrawable:aDrawable];
    }
    return self;
}

896
897
- (void)registerObservers
{
898
    libvlc_exception_t ex;
899
    libvlc_exception_init( &ex );
900

901
    // Attach event observers into the media instance
902
    libvlc_event_manager_t * p_em = libvlc_media_player_event_manager( instance, &ex );
903
    libvlc_event_attach( p_em, libvlc_MediaPlayerPlaying,          HandleMediaInstanceStateChanged, self, &ex );
904
905
906
    libvlc_event_attach( p_em, libvlc_MediaPlayerPaused,           HandleMediaInstanceStateChanged, self, &ex );
    libvlc_event_attach( p_em, libvlc_MediaPlayerEncounteredError, HandleMediaInstanceStateChanged, self, &ex );
    libvlc_event_attach( p_em, libvlc_MediaPlayerEndReached,       HandleMediaInstanceStateChanged, self, &ex );
907
    /* FIXME: We may want to turn that off when none is interested by that */
908
909
    libvlc_event_attach( p_em, libvlc_MediaPlayerPositionChanged, HandleMediaPositionChanged,      self, &ex );
    libvlc_event_attach( p_em, libvlc_MediaPlayerTimeChanged,     HandleMediaTimeChanged,          self, &ex );
910
    libvlc_event_attach( p_em, libvlc_MediaPlayerMediaChanged,     HandleMediaPlayerMediaChanged,  self, &ex );
911
    catch_exception( &ex );
912
913
914
915
}

- (void)unregisterObservers
{
916
    libvlc_event_manager_t * p_em = libvlc_media_player_event_manager( instance, NULL );
917
    libvlc_event_detach( p_em, libvlc_MediaPlayerPlaying,          HandleMediaInstanceStateChanged, self, NULL );
918
919
920
921
922
    libvlc_event_detach( p_em, libvlc_MediaPlayerPaused,           HandleMediaInstanceStateChanged, self, NULL );
    libvlc_event_detach( p_em, libvlc_MediaPlayerEncounteredError, HandleMediaInstanceStateChanged, self, NULL );
    libvlc_event_detach( p_em, libvlc_MediaPlayerEndReached,       HandleMediaInstanceStateChanged, self, NULL );
    libvlc_event_detach( p_em, libvlc_MediaPlayerPositionChanged,  HandleMediaPositionChanged,      self, NULL );
    libvlc_event_detach( p_em, libvlc_MediaPlayerTimeChanged,      HandleMediaTimeChanged,          self, NULL );
923
    libvlc_event_attach( p_em, libvlc_MediaPlayerMediaChanged,     HandleMediaPlayerMediaChanged,   self, NULL );
924
}
925

926
927
928
- (void)mediaPlayerTimeChanged:(NSNumber *)newTime
{
    [self willChangeValueForKey:@"time"];
929
    [self willChangeValueForKey:@"remainingTime"];
930
931
    [cachedTime release];
    cachedTime = [[VLCTime timeWithNumber:newTime] retain];
932
933
934
935
    [cachedRemainingTime release];
    double currentTime = [[cachedTime numberValue] doubleValue];
    double remaining = currentTime / position * (1 - position);
    cachedRemainingTime = [[VLCTime timeWithNumber:[NSNumber numberWithDouble:-remaining]] retain];
936
    [self didChangeValueForKey:@"remainingTime"];
937
938
    [self didChangeValueForKey:@"time"];
}
939

940
941
942
943
944
- (void)delaySleep
{
    UpdateSystemActivity(UsrActivity);
}

945
946
- (void)mediaPlayerPositionChanged:(NSNumber *)newPosition
{
947
948
949
    // This seems to be the most relevant place to delay sleeping and screen saver.
    [self delaySleep];

950
    [self willChangeValueForKey:@"position"];
Pierre's avatar
Pierre committed
951
    position = [newPosition floatValue];
952
953
954
955
956
957
958
959
960
    [self didChangeValueForKey:@"position"];
}

- (void)mediaPlayerStateChanged:(NSNumber *)newState
{
    [self willChangeValueForKey:@"state"];
    cachedState = [newState intValue];
    [self didChangeValueForKey:@"state"];
}
961

962
963
964
965
966
967
968
969
970
971
972
- (void)mediaPlayerMediaChanged:(VLCMedia *)newMedia
{
    [self willChangeValueForKey:@"media"];
    if (media != newMedia)
    {
        [media release];
        media = [newMedia retain];
    }
    [self didChangeValueForKey:@"media"];
}

973
@end