VLCMediaPlayer.m 46.2 KB
Newer Older
1
/*****************************************************************************
2
 * VLCMediaPlayer.m: VLCKit.framework VLCMediaPlayer implementation
3
 *****************************************************************************
4
 * Copyright (C) 2007-2009 Pierre d'Herbemont
5
 * Copyright (C) 2007-2015 VLC authors and VideoLAN
6
 * Partial Copyright (C) 2009-2017 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
 *          Soomin Lee <TheHungryBu # gmail.com>
13
 *
14 15 16
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
17 18 19 20
 * (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
21 22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
23
 *
24 25 26
 * You should have received a copy of the GNU Lesser 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.
27 28 29 30 31 32
 *****************************************************************************/

#import "VLCLibrary.h"
#import "VLCMediaPlayer.h"
#import "VLCEventManager.h"
#import "VLCLibVLCBridging.h"
Soomin Lee's avatar
Soomin Lee committed
33
#import "VLCRendererItem+Init.h"
Pierre's avatar
Pierre committed
34 35 36
#if !TARGET_OS_IPHONE
# import "VLCVideoView.h"
#endif
37 38 39 40
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

Pierre's avatar
Pierre committed
41
#if !TARGET_OS_IPHONE
42
/* prevent system sleep */
Pierre's avatar
Pierre committed
43
# import <CoreServices/CoreServices.h>
44
/* FIXME: Ugly hack! */
Pierre's avatar
Pierre committed
45 46 47
# ifdef __x86_64__
#  import <CoreServices/../Frameworks/OSServices.framework/Headers/Power.h>
# endif
48
#endif
49

50 51 52
#include <vlc/vlc.h>

/* Notification Messages */
53 54
NSString *const VLCMediaPlayerTimeChanged       = @"VLCMediaPlayerTimeChanged";
NSString *const VLCMediaPlayerStateChanged      = @"VLCMediaPlayerStateChanged";
55 56
NSString *const VLCMediaPlayerTitleChanged       = @"VLCMediaPlayerTitleChanged";
NSString *const VLCMediaPlayerChapterChanged      = @"VLCMediaPlayerChapterChanged";
57
NSString *const VLCMediaPlayerSnapshotTaken     = @"VLCMediaPlayerSnapshotTaken";
58 59 60 61 62 63 64 65 66 67

/* title keys */
NSString *const VLCTitleDescriptionName         = @"VLCTitleDescriptionName";
NSString *const VLCTitleDescriptionDuration     = @"VLCTitleDescriptionDuration";
NSString *const VLCTitleDescriptionIsMenu       = @"VLCTitleDescriptionIsMenu";

/* chapter keys */
NSString *const VLCChapterDescriptionName       = @"VLCChapterDescriptionName";
NSString *const VLCChapterDescriptionTimeOffset = @"VLCChapterDescriptionTimeOffset";
NSString *const VLCChapterDescriptionDuration   = @"VLCChapterDescriptionDuration";
68

69
NSString * VLCMediaPlayerStateToString(VLCMediaPlayerState state)
70
{
71
    static NSString * stateToStrings[] = {
72 73 74 75 76 77 78 79 80 81 82
        [VLCMediaPlayerStateStopped]      = @"VLCMediaPlayerStateStopped",
        [VLCMediaPlayerStateOpening]      = @"VLCMediaPlayerStateOpening",
        [VLCMediaPlayerStateBuffering]    = @"VLCMediaPlayerStateBuffering",
        [VLCMediaPlayerStateEnded]        = @"VLCMediaPlayerStateEnded",
        [VLCMediaPlayerStateError]        = @"VLCMediaPlayerStateError",
        [VLCMediaPlayerStatePlaying]      = @"VLCMediaPlayerStatePlaying",
        [VLCMediaPlayerStatePaused]       = @"VLCMediaPlayerStatePaused"
    };
    return stateToStrings[state];
}

83 84 85 86 87 88 89
// TODO: Documentation
@interface VLCMediaPlayer (Private)

- (instancetype)initWithDrawable:(id)aDrawable options:(NSArray *)options;

- (void)registerObservers;
- (void)unregisterObservers;
90
- (dispatch_queue_t)libVLCBackgroundQueue;
91 92 93 94 95 96 97 98 99 100 101 102
- (void)mediaPlayerTimeChanged:(NSNumber *)newTime;
- (void)mediaPlayerPositionChanged:(NSNumber *)newTime;
- (void)mediaPlayerStateChanged:(NSNumber *)newState;
- (void)mediaPlayerMediaChanged:(VLCMedia *)media;
- (void)mediaPlayerTitleChanged:(NSNumber *)newTitle;
- (void)mediaPlayerChapterChanged:(NSNumber *)newChapter;

#if TARGET_OS_IPHONE
- (void)mediaPlayerSnapshot:(NSString *)fileName;
#endif
@end

103 104
static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
{
105 106 107 108 109 110 111 112 113
    @autoreleasepool {
        [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
                                                     withMethod:@selector(mediaPlayerTimeChanged:)
                                           withArgumentAsObject:@(event->u.media_player_time_changed.new_time)];

        [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
                                                       withDelegateMethod:@selector(mediaPlayerTimeChanged:)
                                                     withNotificationName:VLCMediaPlayerTimeChanged];
    }
114 115
}

116 117
static void HandleMediaPositionChanged(const libvlc_event_t * event, void * self)
{
118
    @autoreleasepool {
119

120 121 122 123
        [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
                                                     withMethod:@selector(mediaPlayerPositionChanged:)
                                           withArgumentAsObject:@(event->u.media_player_position_changed.new_position)];
    }
124 125
}

126
static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void * self)
127
{
128
    VLCMediaPlayerState newState;
129

130
    if (event->type == libvlc_MediaPlayerPlaying)
131
        newState = VLCMediaPlayerStatePlaying;
132
    else if (event->type == libvlc_MediaPlayerPaused)
133
        newState = VLCMediaPlayerStatePaused;
134
    else if (event->type == libvlc_MediaPlayerStopped)
135
        newState = VLCMediaPlayerStateStopped;
136
    else if (event->type == libvlc_MediaPlayerEncounteredError)
137
        newState = VLCMediaPlayerStateError;
138
    else if (event->type == libvlc_MediaPlayerBuffering)
139
        newState = VLCMediaPlayerStateBuffering;
140
    else if (event->type == libvlc_MediaPlayerOpening)
141
        newState = VLCMediaPlayerStateOpening;
142 143
    else if (event->type == libvlc_MediaPlayerEndReached)
        newState = VLCMediaPlayerStateEnded;
144 145
    else if (event->type == libvlc_MediaPlayerESAdded)
        newState = VLCMediaPlayerStateESAdded;
146
    else {
147
        VKLog(@"%s: Unknown event", __FUNCTION__);
148 149
        return;
    }
150

151
    @autoreleasepool {
152

153 154 155
        [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
                                                     withMethod:@selector(mediaPlayerStateChanged:)
                                           withArgumentAsObject:@(newState)];
156

157 158 159
        [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
                                                       withDelegateMethod:@selector(mediaPlayerStateChanged:)
                                                     withNotificationName:VLCMediaPlayerStateChanged];
160

161
    }
162
}
163

164 165
static void HandleMediaPlayerMediaChanged(const libvlc_event_t * event, void * self)
{
166
    @autoreleasepool {
167

168 169 170
        [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
                                                     withMethod:@selector(mediaPlayerMediaChanged:)
                                           withArgumentAsObject:[VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_player_media_changed.new_media]];
171

172
    }
173 174
}

175 176 177 178
static void HandleMediaTitleChanged(const libvlc_event_t * event, void * self)
{
    @autoreleasepool {
        [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
179
                                                       withDelegateMethod:@selector(mediaPlayerTitleChanged:)
180 181 182 183 184 185 186 187 188 189 190 191 192
                                                     withNotificationName:VLCMediaPlayerTitleChanged];
    }
}

static void HandleMediaChapterChanged(const libvlc_event_t * event, void * self)
{
    @autoreleasepool {
        [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
                                                       withDelegateMethod:@selector(mediaPlayerChapterChanged:)
                                                     withNotificationName:VLCMediaPlayerChapterChanged];
    }
}

193 194 195 196 197 198 199 200
#if TARGET_OS_IPHONE
static void HandleMediaPlayerSnapshot(const libvlc_event_t * event, void * self)
{
    @autoreleasepool {
        if (event->u.media_player_snapshot_taken.psz_filename != NULL) {
            [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
                                                         withMethod:@selector(mediaPlayerSnapshot:)
                                               withArgumentAsObject:[NSString stringWithUTF8String:event->u.media_player_snapshot_taken.psz_filename]];
201 202 203 204

            [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
                                                           withDelegateMethod:@selector(mediaPlayerSnapshot:)
                                                         withNotificationName:VLCMediaPlayerSnapshotTaken];
205 206 207 208
        }
    }
}
#endif
209

210 211
@interface VLCMediaPlayer ()
{
212 213 214 215 216 217 218 219
    VLCLibrary *_privateLibrary;                ///< Internal
    void * _playerInstance;                     ///< Internal
    VLCMedia * _media;                          ///< Current media being played
    VLCTime * _cachedTime;                      ///< Cached time of the media being played
    VLCTime * _cachedRemainingTime;             ///< Cached remaining time of the media being played
    VLCMediaPlayerState _cachedState;           ///< Cached state of the media being played
    float _position;                            ///< The position of the media being played
    id _drawable;                               ///< The drawable associated to this media player
220
#if TARGET_OS_IPHONE
221
    NSMutableArray *_snapshots;                 ///< Array with snapshot file names
222
#endif
223 224 225
    VLCAudio *_audio;                           ///< The audio controller
    libvlc_equalizer_t *_equalizerInstance;     ///< The equalizer controller
    BOOL _equalizerEnabled;                     ///< Equalizer state
226
    libvlc_video_viewpoint_t *_viewpoint;       ///< Current viewpoint of the media
227
    dispatch_queue_t _libVLCBackgroundQueue;    ///< Background dispatch queue to call libvlc
228 229 230
}
@end

231
@implementation VLCMediaPlayer
232
@synthesize libraryInstance = _privateLibrary;
233

234
/* Bindings */
235 236 237
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    static NSDictionary * dict = nil;
238
    NSSet * superKeyPaths;
239
    if (!dict) {
240
        dict = @{@"playing": [NSSet setWithObject:@"state"],
241 242
                @"seekable": [NSSet setWithObjects:@"state", @"media", nil],
                @"canPause": [NSSet setWithObjects:@"state", @"media", nil],
243
                @"description": [NSSet setWithObjects:@"state", @"media", nil]};
244
    }
245
    if ((superKeyPaths = [super keyPathsForValuesAffectingValueForKey: key])) {
246
        NSMutableSet * ret = [NSMutableSet setWithSet:dict[key]];
247 248 249
        [ret unionSet:superKeyPaths];
        return ret;
    }
250
    return dict[key];
251
}
252

253
/* Constructor */
254
- (instancetype)init
255
{
256
    return [self initWithDrawable:nil options:nil];
257 258
}

259 260 261 262 263 264 265
- (instancetype)initWithLibVLCInstance:(void *)playerInstance andLibrary:(VLCLibrary *)library
{
    if (self = [super init]) {
        _cachedTime = [VLCTime nullTime];
        _cachedRemainingTime = [VLCTime nullTime];
        _position = 0.0f;
        _cachedState = VLCMediaPlayerStateStopped;
266
        _libVLCBackgroundQueue = [self libVLCBackgroundQueue];
267 268 269 270 271 272 273 274 275 276 277

        _privateLibrary = library;
        libvlc_retain([_privateLibrary instance]);

        _playerInstance = playerInstance;

        [self registerObservers];
    }
    return self;
}

Pierre's avatar
Pierre committed
278
#if !TARGET_OS_IPHONE
279
- (instancetype)initWithVideoView:(VLCVideoView *)aVideoView
280
{
281
    return [self initWithDrawable: aVideoView options:nil];
282
}
283

284
- (instancetype)initWithVideoLayer:(VLCVideoLayer *)aVideoLayer
285
{
286 287 288
    return [self initWithDrawable: aVideoLayer options:nil];
}

289
- (instancetype)initWithVideoView:(VLCVideoView *)aVideoView options:(NSArray *)options
290 291 292 293
{
    return [self initWithDrawable: aVideoView options:options];
}

294
- (instancetype)initWithVideoLayer:(VLCVideoLayer *)aVideoLayer options:(NSArray *)options
295 296
{
    return [self initWithDrawable: aVideoLayer options:options];
297
}
Pierre's avatar
Pierre committed
298
#endif
299

300
- (instancetype)initWithOptions:(NSArray *)options
301 302 303 304
{
    return [self initWithDrawable:nil options:options];
}

305 306
- (void)dealloc
{
307 308 309
    NSAssert(libvlc_media_player_get_state(_playerInstance) == libvlc_Stopped ||
             libvlc_media_player_get_state(_playerInstance) == libvlc_NothingSpecial,
             @"You released the media player before ensuring that it is stopped");
310

Pierre's avatar
Pierre committed
311 312 313
    [self unregisterObservers];
    [[VLCEventManager sharedManager] cancelCallToObject:self];

314 315
    // 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?
316
    _delegate = nil;
317

318 319 320
    // 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.
321
    libvlc_media_player_set_nsobject(_playerInstance, nil);
322

323 324 325 326 327
    if (_equalizerInstance) {
        libvlc_media_player_set_equalizer(_playerInstance, NULL);
        libvlc_audio_equalizer_release(_equalizerInstance);
    }

328 329 330
    if (_viewpoint)
        libvlc_free(_viewpoint);

331
    libvlc_media_player_release(_playerInstance);
332

333 334
    if (_privateLibrary != [VLCLibrary sharedLibrary])
        libvlc_release(_privateLibrary.instance);
335 336
}

Pierre's avatar
Pierre committed
337
#if !TARGET_OS_IPHONE
338
- (void)setVideoView:(VLCVideoView *)aVideoView
339
{
340
    [self setDrawable: aVideoView];
341 342
}

343
- (void)setVideoLayer:(VLCVideoLayer *)aVideoLayer
344
{
345
    [self setDrawable: aVideoLayer];
346
}
Pierre's avatar
Pierre committed
347
#endif
348

349 350 351
- (void)setDrawable:(id)aDrawable
{
    // Make sure that this instance has been associated with the drawing canvas.
352
    _drawable = aDrawable;
353 354 355 356 357 358

    /* Note that ee need the caller to wait until the setter succeeded.
     * Otherwise, s/he might want to deploy the drawable while it isn’t ready yet. */
    dispatch_sync(_libVLCBackgroundQueue, ^{
        libvlc_media_player_set_nsobject(_playerInstance, (__bridge void *)(aDrawable));
    });
359 360 361 362
}

- (id)drawable
{
363
    return (__bridge id)(libvlc_media_player_get_nsobject(_playerInstance));
364 365
}

366 367
- (VLCAudio *)audio
{
368 369 370
    if (!_audio)
        _audio = [[VLCAudio alloc] initWithMediaPlayer:self];
    return _audio;
371 372
}

373 374
#pragma mark -
#pragma mark Video Tracks
375
- (void)setCurrentVideoTrackIndex:(int)value
376
{
377
    libvlc_video_set_track(_playerInstance, value);
378 379
}

380
- (int)currentVideoTrackIndex
381
{
382
    int count = libvlc_video_get_track_count(_playerInstance);
383
    if (count <= 0)
384
        return -1;
385

386
    return libvlc_video_get_track(_playerInstance);
387 388
}

389 390
- (NSArray *)videoTrackNames
{
391
    NSInteger count = libvlc_video_get_track_count(_playerInstance);
392
    if (count <= 0)
393
        return @[];
394

395 396
    libvlc_track_description_t *firstTrack = libvlc_video_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
397 398 399

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
400
        [tempArray addObject:@(currentTrack->psz_name)];
401 402
        currentTrack = currentTrack->p_next;
    }
403
    libvlc_track_description_list_release(firstTrack);
404 405 406 407 408
    return [NSArray arrayWithArray: tempArray];
}

- (NSArray *)videoTrackIndexes
{
409
    NSInteger count = libvlc_video_get_track_count(_playerInstance);
410
    if (count <= 0)
411
        return @[];
412

413 414
    libvlc_track_description_t *firstTrack = libvlc_video_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
415 416 417

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
418
        [tempArray addObject:@(currentTrack->i_id)];
419 420
        currentTrack = currentTrack->p_next;
    }
421
    libvlc_track_description_list_release(firstTrack);
422 423 424
    return [NSArray arrayWithArray: tempArray];
}

425 426 427 428 429
- (int)numberOfVideoTracks
{
    return libvlc_video_get_track_count(_playerInstance);
}

430 431
#pragma mark -
#pragma mark Subtitles
432

433
- (void)setCurrentVideoSubTitleIndex:(int)index
434
{
435
    libvlc_video_set_spu(_playerInstance, index);
436 437
}

438
- (int)currentVideoSubTitleIndex
439
{
440
    NSInteger count = libvlc_video_get_spu_count(_playerInstance);
441

442
    if (count <= 0)
443
        return -1;
444

445
    return libvlc_video_get_spu(_playerInstance);
446 447
}

448 449
- (NSArray *)videoSubTitlesNames
{
450
    NSInteger count = libvlc_video_get_spu_count(_playerInstance);
451
    if (count <= 0)
452
        return @[];
453

454 455
    libvlc_track_description_t *firstTrack = libvlc_video_get_spu_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
456 457 458

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
459 460
        NSString *track = @(currentTrack->psz_name);
        [tempArray addObject:track != nil ? track : @""];
461 462
        currentTrack = currentTrack->p_next;
    }
463
    libvlc_track_description_list_release(firstTrack);
464 465 466 467 468
    return [NSArray arrayWithArray: tempArray];
}

- (NSArray *)videoSubTitlesIndexes
{
469
    NSInteger count = libvlc_video_get_spu_count(_playerInstance);
470
    if (count <= 0)
471
        return @[];
472

473 474
    libvlc_track_description_t *firstTrack = libvlc_video_get_spu_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
475 476 477

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
478
        [tempArray addObject:@(currentTrack->i_id)];
479 480
        currentTrack = currentTrack->p_next;
    }
481
    libvlc_track_description_list_release(firstTrack);
482 483 484
    return [NSArray arrayWithArray: tempArray];
}

485 486 487 488 489
- (int)numberOfSubtitlesTracks
{
    return libvlc_video_get_spu_count(_playerInstance);
}

490 491
- (BOOL)openVideoSubTitlesFromFile:(NSString *)path
{
492 493 494 495
    return libvlc_media_player_add_slave(_playerInstance,
                                         libvlc_media_slave_type_subtitle,
                                         [path UTF8String],
                                         TRUE);
496 497
}

498 499 500 501 502 503 504 505 506 507 508
- (int)addPlaybackSlave:(NSURL *)slaveURL type:(VLCMediaPlaybackSlaveType)slaveType enforce:(BOOL)enforceSelection
{
    if (!slaveURL)
        return -1;

    return libvlc_media_player_add_slave(_playerInstance,
                                         slaveType,
                                         [[slaveURL absoluteString] UTF8String],
                                         enforceSelection);
}

509 510
- (void)setCurrentVideoSubTitleDelay:(NSInteger)index
{
511
    libvlc_video_set_spu_delay(_playerInstance, index);
512 513 514 515
}

- (NSInteger)currentVideoSubTitleDelay
{
516
    return libvlc_video_get_spu_delay(_playerInstance);
517 518
}

519
#if TARGET_OS_IPHONE
520 521
- (void)setTextRendererFontSize:(NSNumber *)fontSize
{
522
    libvlc_video_set_textrenderer_int(_playerInstance, libvlc_textrender_fontsize, [fontSize intValue]);
523 524 525 526
}

- (void)setTextRendererFont:(NSString *)fontname
{
527
    libvlc_video_set_textrenderer_string(_playerInstance, libvlc_textrender_font, [fontname UTF8String]);
528 529 530 531
}

- (void)setTextRendererFontColor:(NSNumber *)fontColor
{
532
    libvlc_video_set_textrenderer_int(_playerInstance, libvlc_textrender_fontcolor, [fontColor intValue]);
533
}
534 535 536

- (void)setTextRendererFontForceBold:(NSNumber *)fontForceBold
{
537
    libvlc_video_set_textrenderer_bool(_playerInstance, libvlc_textrender_fontforcebold, [fontForceBold boolValue]);
538
}
539
#endif
540

541 542 543
#pragma mark -
#pragma mark Video Crop geometry

544 545
- (void)setVideoCropGeometry:(char *)value
{
546
    libvlc_video_set_crop_geometry(_playerInstance, value);
547 548 549 550
}

- (char *)videoCropGeometry
{
551
    char * result = libvlc_video_get_crop_geometry(_playerInstance);
552
    return result;
553 554
}

555 556
- (void)setVideoAspectRatio:(char *)value
{
557
    libvlc_video_set_aspect_ratio(_playerInstance, value);
558 559 560 561
}

- (char *)videoAspectRatio
{
562
    char * result = libvlc_video_get_aspect_ratio(_playerInstance);
563 564 565
    return result;
}

566 567
- (void)setScaleFactor:(float)value
{
568
    libvlc_video_set_scale(_playerInstance, value);
569 570 571 572
}

- (float)scaleFactor
{
573
    return libvlc_video_get_scale(_playerInstance);
574 575
}

576
- (void)saveVideoSnapshotAt:(NSString *)path withWidth:(int)width andHeight:(int)height
577
{
578
    int failure = libvlc_video_take_snapshot(_playerInstance, 0, [path UTF8String], width, height);
579 580
    if (failure)
        [[NSException exceptionWithName:@"Can't take a video snapshot" reason:@"No video output" userInfo:nil] raise];
581 582
}

583
- (void)setDeinterlaceFilter:(NSString *)name
584
{
585 586 587 588
    if (!name || name.length < 1)
        libvlc_video_set_deinterlace(_playerInstance, NULL);
    else
        libvlc_video_set_deinterlace(_playerInstance, [name UTF8String]);
589 590
}

591 592
- (BOOL)adjustFilterEnabled
{
593
    return libvlc_video_get_adjust_int(_playerInstance, libvlc_adjust_Enable);
594 595 596
}
- (void)setAdjustFilterEnabled:(BOOL)b_value
{
597
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, b_value);
598 599 600
}
- (float)contrast
{
601 602
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Contrast);
603 604 605
}
- (void)setContrast:(float)f_value
{
606
    if (f_value <= 2. && f_value >= 0.) {
607 608
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
        libvlc_video_set_adjust_float(_playerInstance,libvlc_adjust_Contrast, f_value);
609
    }
610 611 612
}
- (float)brightness
{
613 614
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Brightness);
615 616 617
}
- (void)setBrightness:(float)f_value
{
618
    if (f_value <= 2. && f_value >= 0.) {
619 620
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
        libvlc_video_set_adjust_float(_playerInstance, libvlc_adjust_Brightness, f_value);
621
    }
622
}
623 624

- (float)hue
625
{
626
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
627
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Hue);
628
}
629
- (void)setHue:(float)f_value
630
{
631
    if (f_value <= 180. && f_value >= -180.) {
632
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
633
        libvlc_video_set_adjust_float(_playerInstance, libvlc_adjust_Hue, f_value);
634
    }
635
}
636

637 638
- (float)saturation
{
639 640
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Saturation);
641 642 643
}
- (void)setSaturation:(float)f_value
{
644
    if (f_value <= 3. && f_value >= 0.) {
645 646
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
        libvlc_video_set_adjust_float(_playerInstance, libvlc_adjust_Saturation, f_value);
647
    }
648 649 650
}
- (float)gamma
{
651 652
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Gamma);
653 654 655
}
- (void)setGamma:(float)f_value
{
656
    if (f_value <= 10. && f_value >= 0.) {
657 658
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
        libvlc_video_set_adjust_float(_playerInstance, libvlc_adjust_Gamma, f_value);
659
    }
660 661
}

662
- (void)setRate:(float)value
663
{
664
    libvlc_media_player_set_rate(_playerInstance, value);
665 666
}

667
- (float)rate
668
{
669
    return libvlc_media_player_get_rate(_playerInstance);
670 671
}

Pierre's avatar
Pierre committed
672
- (CGSize)videoSize
673
{
674
    unsigned height = 0, width = 0;
675
    int failure = libvlc_video_get_size(_playerInstance, 0, &width, &height);
676
    if (failure)
677
        return CGSizeZero;
Pierre's avatar
Pierre committed
678
    return CGSizeMake(width, height);
679 680 681 682
}

- (BOOL)hasVideoOut
{
683
    return libvlc_media_player_has_vout(_playerInstance);
684 685 686 687
}

- (float)framesPerSecond
{
688
    return .0;
689 690 691 692
}

- (void)setTime:(VLCTime *)value
{
693 694
    // Time is managed in seconds, while duration is managed in microseconds
    // TODO: Redo VLCTime to provide value numberAsMilliseconds, numberAsMicroseconds, numberAsSeconds, numberAsMinutes, numberAsHours
695
    libvlc_media_player_set_time(_playerInstance, value ? [[value value] longLongValue] : 0);
696 697 698 699
}

- (VLCTime *)time
{
700
    return _cachedTime;
701 702
}

703 704
- (VLCTime *)remainingTime
{
705
    return _cachedRemainingTime;
706 707
}

708 709
#pragma mark -
#pragma mark Chapters
710
- (void)setCurrentChapterIndex:(int)value;
711
{
712
    libvlc_media_player_set_chapter(_playerInstance, value);
713 714
}

715
- (int)currentChapterIndex
716
{
717
    int count = libvlc_media_player_get_chapter_count(_playerInstance);
718
    if (count <= 0)
719
        return -1;
720
    int result = libvlc_media_player_get_chapter(_playerInstance);
721 722 723
    return result;
}

724 725
- (void)nextChapter
{
726
    libvlc_media_player_next_chapter(_playerInstance);
727 728 729 730
}

- (void)previousChapter
{
731
    libvlc_media_player_previous_chapter(_playerInstance);
732 733
}

734
- (NSArray *)chaptersForTitleIndex:(int)title
735
{
736
    NSInteger count = libvlc_media_player_get_chapter_count(_playerInstance);
737
    if (count <= 0)
738
        return @[];
739

740 741
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
742 743
    libvlc_track_description_t *firstTrack = libvlc_video_get_chapter_description(_playerInstance, title);
    libvlc_track_description_t *currentTrack = firstTrack;
744 745
#pragma clang diagnostic push

746
    NSMutableArray *tempArray = [NSMutableArray array];
747
    for (NSInteger i = 0; i < count ; i++) {
748 749
        [tempArray addObject:@(currentTrack->psz_name)];
        currentTrack = currentTrack->p_next;
750
    }
751
    libvlc_track_description_list_release(firstTrack);
752
    return [NSArray arrayWithArray:tempArray];
753 754
}

755 756 757
#pragma mark -
#pragma mark Titles

758
- (void)setCurrentTitleIndex:(int)value
759
{
760
    libvlc_media_player_set_title(_playerInstance, value);
761 762
}

763
- (int)currentTitleIndex
764
{
765
    NSInteger count = libvlc_media_player_get_title_count(_playerInstance);
766
    if (count <= 0)
767
        return -1;
768

769
    return libvlc_media_player_get_title(_playerInstance);
770 771
}

772 773 774 775 776
- (int)numberOfTitles
{
    return libvlc_media_player_get_title_count(_playerInstance);
}

777
- (NSUInteger)countOfTitles
778
{
779
    NSUInteger result = libvlc_media_player_get_title_count(_playerInstance);
780 781 782
    return result;
}

783 784
- (NSArray *)titles
{
785 786 787 788
    NSUInteger count = [self countOfTitles];
    if (count == 0)
        return [NSArray array];

789 790
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
791 792
    libvlc_track_description_t *firstTrack = libvlc_video_get_title_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
793 794
#pragma clang diagnostic pop

795
    if (!currentTrack)
796 797 798
        return [NSArray array];

    NSMutableArray *tempArray = [NSMutableArray array];
799 800

    while (1) {
801 802 803 804
        if (currentTrack->psz_name != nil)
            [tempArray addObject:@(currentTrack->psz_name)];
        if (currentTrack->p_next)
            currentTrack = currentTrack->p_next;
805 806
        else
            break;
807
    }
808

809
    libvlc_track_description_list_release(firstTrack);
810 811 812
    return [NSArray arrayWithArray: tempArray];
}

813 814 815 816 817 818 819 820 821 822 823 824 825
- (NSArray *)titleDescriptions
{
    libvlc_title_description_t **titleInfo;
    int numberOfTitleDescriptions = libvlc_media_player_get_full_title_descriptions(_playerInstance, &titleInfo);

    if (numberOfTitleDescriptions < 0)
        return [NSArray array];

    if (numberOfTitleDescriptions == 0) {
        libvlc_title_descriptions_release(titleInfo, numberOfTitleDescriptions);
        return [NSArray array];
    }

826
    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:numberOfTitleDescriptions];
827 828 829 830 831

    for (int i = 0; i < numberOfTitleDescriptions; i++) {
        NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                           [NSNumber numberWithLongLong:titleInfo[i]->i_duration],
                                           VLCTitleDescriptionDuration,
832
                                           @(titleInfo[i]->i_flags & libvlc_title_menu),
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
                                           VLCTitleDescriptionIsMenu,
                                           nil];
        if (titleInfo[i]->psz_name != NULL)
            dictionary[VLCTitleDescriptionName] = [NSString stringWithUTF8String:titleInfo[i]->psz_name];
        [array addObject:[NSDictionary dictionaryWithDictionary:dictionary]];
    }
    libvlc_title_descriptions_release(titleInfo, numberOfTitleDescriptions);

    return [NSArray arrayWithArray:array];
}

- (int)indexOfLongestTitle
{
    NSArray *titles = [self titleDescriptions];
    NSUInteger titleCount = titles.count;

    int currentlyFoundTitle = 0;
    int64_t currentlySelectedDuration = 0;
    int64_t randomTitleDuration = 0;

    for (int x = 0; x < titleCount; x++) {
        randomTitleDuration = [[titles[x] valueForKey:VLCTitleDescriptionDuration] longLongValue];
        if (randomTitleDuration > currentlySelectedDuration) {
            currentlySelectedDuration = randomTitleDuration;
            currentlyFoundTitle = x;
        }
    }

    return currentlyFoundTitle;
}

864 865 866 867 868
- (int)numberOfChaptersForTitle:(int)titleIndex
{
    return libvlc_media_player_get_chapter_count_for_title(_playerInstance, titleIndex);
}

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
- (NSArray *)chapterDescriptionsOfTitle:(int)titleIndex
{
    libvlc_chapter_description_t **chapterDescriptions;
    int numberOfChapterDescriptions = libvlc_media_player_get_full_chapter_descriptions(_playerInstance,
                                                                                        titleIndex,
                                                                                        &chapterDescriptions);

    if (numberOfChapterDescriptions < 0)
        return [NSArray array];

    if (numberOfChapterDescriptions == 0) {
        libvlc_chapter_descriptions_release(chapterDescriptions, numberOfChapterDescriptions);
        return [NSArray array];
    }

    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:numberOfChapterDescriptions];

    for (int i = 0; i < numberOfChapterDescriptions; i++) {
        NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                           [NSNumber numberWithLongLong:chapterDescriptions[i]->i_duration],
                                           VLCChapterDescriptionDuration,
                                           [NSNumber numberWithLongLong:chapterDescriptions[i]->i_time_offset],
                                           VLCChapterDescriptionTimeOffset,
                                           nil];
        if (chapterDescriptions[i]->psz_name != NULL)
            dictionary[VLCChapterDescriptionName] = [NSString stringWithUTF8String:chapterDescriptions[i]->psz_name];
        [array addObject:[NSDictionary dictionaryWithDictionary:dictionary]];
    }

    libvlc_chapter_descriptions_release(chapterDescriptions, numberOfChapterDescriptions);

    return [NSArray arrayWithArray:array];
}

903 904
#pragma mark -
#pragma mark Audio tracks
905
- (void)setCurrentAudioTrackIndex:(int)value
906
{
907
    libvlc_audio_set_track(_playerInstance, value);
908 909
}

910
- (int)currentAudioTrackIndex
911
{
912
    NSInteger count = libvlc_audio_get_track_count(_playerInstance);
913
    if (count <= 0)
914
        return -1;
915

916
    return libvlc_audio_get_track(_playerInstance);
917 918
}

919 920
- (NSArray *)audioTrackNames
{
921
    NSInteger count = libvlc_audio_get_track_count(_playerInstance);
922
    if (count <= 0)
923
        return @[];
924

925 926
    libvlc_track_description_t *firstTrack = libvlc_audio_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
927 928 929

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
930 931
        NSString *track = @(currentTrack->psz_name);
        [tempArray addObject:track != nil ? track : @""];
932 933
        currentTrack = currentTrack->p_next;
    }
934
    libvlc_track_description_list_release(firstTrack);
935 936 937 938 939
    return [NSArray arrayWithArray: tempArray];
}

- (NSArray *)audioTrackIndexes
{
940
    NSInteger count = libvlc_audio_get_track_count(_playerInstance);
941
    if (count <= 0)
942
        return @[];
943

944 945
    libvlc_track_description_t *firstTrack = libvlc_audio_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
946 947 948

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
949
        [tempArray addObject:@(currentTrack->i_id)];
950 951
        currentTrack = currentTrack->p_next;
    }
952
    libvlc_track_description_list_release(firstTrack);
953 954 955
    return [NSArray arrayWithArray: tempArray];
}

956 957 958 959 960
- (int)numberOfAudioTracks
{
    return libvlc_audio_get_track_count(_playerInstance);
}

961
- (void)setAudioChannel:(int)value
962
{
963
    libvlc_audio_set_channel(_playerInstance, value);
964 965
}

966
- (int)audioChannel
967
{
968
    return libvlc_audio_get_channel(_playerInstance);
969 970
}

971 972
- (void)setCurrentAudioPlaybackDelay:(NSInteger)index
{
973
    libvlc_audio_set_delay(_playerInstance, index);
974 975 976 977
}

- (NSInteger)currentAudioPlaybackDelay
{
978
    return libvlc_audio_get_delay(_playerInstance);
979 980
}

981 982 983 984 985
#pragma mark -
#pragma mark equalizer

- (void)setEqualizerEnabled:(BOOL)equalizerEnabled
{
986 987
    _equalizerEnabled = equalizerEnabled;
    if (!_equalizerEnabled) {
988 989 990 991 992 993 994 995 996 997 998 999
        libvlc_media_player_set_equalizer(_playerInstance, NULL);

        if (_equalizerInstance)
            libvlc_audio_equalizer_release(_equalizerInstance);
        return;
    }

    if (!_equalizerInstance)
        _equalizerInstance = libvlc_audio_equalizer_new();
    libvlc_media_player_set_equalizer(_playerInstance, _equalizerInstance);
}

1000 1001 1002 1003 1004
- (BOOL)equalizerEnabled
{
    return _equalizerEnabled;
}

1005 1006 1007 1008 1009
- (NSArray *)equalizerProfiles
{
    unsigned count = libvlc_audio_equalizer_get_preset_count();
    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
    for (unsigned x = 0; x < count; x++)
1010
        [array addObject:@(libvlc_audio_equalizer_get_preset_name(x))];
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

    return [NSArray arrayWithArray:array];
}

- (void)resetEqualizerFromProfile:(unsigned)profile
{
    BOOL wasactive = NO;
    if (_equalizerInstance) {
        libvlc_media_player_set_equalizer(_playerInstance, NULL);
        libvlc_audio_equalizer_release(_equalizerInstance);
        wasactive = YES;
    }

    _equalizerInstance = libvlc_audio_equalizer_new_from_preset(profile);
    if (wasactive)
        libvlc_media_player_set_equalizer(_playerInstance, _equalizerInstance);
}

- (CGFloat)preAmplification
{
    if (!_equalizerInstance)
        return 0.;

    return libvlc_audio_equalizer_get_preamp(_equalizerInstance);
}

- (void)setPreAmplification:(CGFloat)preAmplification
{
    if (!_equalizerInstance)
        _equalizerInstance = libvlc_audio_equalizer_new();

    libvlc_audio_equalizer_set_preamp(_equalizerInstance, preAmplification);
1043
    libvlc_media_player_set_equalizer(_playerInstance, _equalizerInstance);
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
}

- (unsigned)numberOfBands
{
    return libvlc_audio_equalizer_get_band_count();
}

- (CGFloat)frequencyOfBandAtIndex:(unsigned int)index
{
    return libvlc_audio_equalizer_get_band_frequency(index);
}

- (void)setAmplification:(CGFloat)amplification forBand:(unsigned int)index
{
    if (!_equalizerInstance)
        _equalizerInstance = libvlc_audio_equalizer_new();

    libvlc_audio_equalizer_set_amp_at_index(_equalizerInstance, amplification, index);
}

- (CGFloat)amplificationOfBand:(unsigned int)index
{
    if (!_equalizerInstance)
        return 0.;

    return libvlc_audio_equalizer_get_amp_at_index(_equalizerInstance, index);
}

1072 1073 1074
#pragma mark -
#pragma mark set/get media

1075 1076
- (void)setMedia:(VLCMedia *)value
{
1077 1078
    if (_media != value) {
        if (_media && [_media compare:value] == NSOrderedSame)
1079
            return;
1080

1081
        _media = value;
1082

1083
        libvlc_media_player_set_media(_playerInstance, [_media libVLCMediaDescriptor]);
1084
    }
1085 1086 1087 1088
}

- (VLCMedia *)media
{
1089
    return _media;
1090 1091
}

1092 1093 1094
#pragma mark -
#pragma mark playback

1095
- (void)play
1096
{
1097 1098 1099
    dispatch_async(_libVLCBackgroundQueue, ^{
        libvlc_media_player_play(_playerInstance);
    });
1100 1101 1102 1103
}

- (void)pause
{
1104
    // Pause the stream
1105 1106 1107
    dispatch_async(_libVLCBackgroundQueue, ^{
        libvlc_media_player_set_pause(_playerInstance, 1);
    });
1108 1109 1110 1111
}

- (void)stop
{
1112 1113 1114
    dispatch_async(_libVLCBackgroundQueue, ^{
        libvlc_media_player_stop(_playerInstance);
    });
1115 1116
}

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
- (BOOL)updateViewpoint:(CGFloat)yaw pitch:(CGFloat)pitch roll:(CGFloat)roll fov:(CGFloat)fov absolute:(BOOL)absolute
{
    if (_viewpoint == NULL) {
        _viewpoint = libvlc_video_new_viewpoint();
        if (_viewpoint == NULL)
            return NO;
    }

    _viewpoint->f_yaw = yaw;
    _viewpoint->f_pitch = pitch;
    _viewpoint->f_roll = roll;
    _viewpoint->f_field_of_view = fov;

    return libvlc_video_update_viewpoint(_playerInstance, _viewpoint, absolute) == 0 ? YES : NO;
}

1133 1134
- (void)gotoNextFrame
{
1135
    libvlc_media_player_next_frame(_playerInstance);
1136 1137
}

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
- (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];
}
1157

1158
- (void)jumpBackward:(int)interval
1159
{
1160
    if ([self isSeekable]) {
1161
        interval = interval * 1000;
1162 1163 1164 1165
        [self setTime: [VLCTime timeWithInt: ([[self time] intValue] - interval)]];
    }
}

1166
- (void)jumpForward:(int)interval
1167
{
1168
    if ([self isSeekable]) {
1169
        interval = interval * 1000;
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
        [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];
}

<