VLCMediaPlayer.m 46.8 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"
Pierre's avatar
Pierre committed
33 34 35
#if !TARGET_OS_IPHONE
# import "VLCVideoView.h"
#endif
36 37 38 39
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

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

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

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

/* 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";
67

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

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

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

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

- (void)mediaPlayerSnapshot:(NSString *)fileName;
@end

100 101
static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
{
102 103 104 105 106 107 108 109 110
    @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];
    }
111 112
}

113 114
static void HandleMediaPositionChanged(const libvlc_event_t * event, void * self)
{
115
    @autoreleasepool {
116

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

123
static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void * self)
124
{
125
    VLCMediaPlayerState newState;
126

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

148
    @autoreleasepool {
149

150 151 152
        [[VLCEventManager sharedManager] callOnMainThreadObject:(__bridge id)(self)
                                                     withMethod:@selector(mediaPlayerStateChanged:)
                                           withArgumentAsObject:@(newState)];
153

154 155 156
        [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
                                                       withDelegateMethod:@selector(mediaPlayerStateChanged:)
                                                     withNotificationName:VLCMediaPlayerStateChanged];
157

158
    }
159
}
160

161 162
static void HandleMediaPlayerMediaChanged(const libvlc_event_t * event, void * self)
{
163
    @autoreleasepool {
164

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

169
    }
170 171
}

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

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

190 191 192 193 194 195 196
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]];
197 198 199 200

            [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:(__bridge id)(self)
                                                           withDelegateMethod:@selector(mediaPlayerSnapshot:)
                                                         withNotificationName:VLCMediaPlayerSnapshotTaken];
201 202 203
        }
    }
}
204

205 206
@interface VLCMediaPlayer ()
{
207 208 209 210 211 212 213 214 215 216 217 218
    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
    NSMutableArray *_snapshots;                 ///< Array with snapshot file names
    VLCAudio *_audio;                           ///< The audio controller
    libvlc_equalizer_t *_equalizerInstance;     ///< The equalizer controller
    BOOL _equalizerEnabled;                     ///< Equalizer state
219
    libvlc_video_viewpoint_t *_viewpoint;       ///< Current viewpoint of the media
220
    dispatch_queue_t _libVLCBackgroundQueue;    ///< Background dispatch queue to call libvlc
221 222 223
}
@end

224
@implementation VLCMediaPlayer
225
@synthesize libraryInstance = _privateLibrary;
226

227
/* Bindings */
228 229 230
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    static NSDictionary * dict = nil;
231
    NSSet * superKeyPaths;
232
    if (!dict) {
233
        dict = @{@"playing": [NSSet setWithObject:@"state"],
234 235
                @"seekable": [NSSet setWithObjects:@"state", @"media", nil],
                @"canPause": [NSSet setWithObjects:@"state", @"media", nil],
236
                @"description": [NSSet setWithObjects:@"state", @"media", nil]};
237
    }
238
    if ((superKeyPaths = [super keyPathsForValuesAffectingValueForKey: key])) {
239
        NSMutableSet * ret = [NSMutableSet setWithSet:dict[key]];
240 241 242
        [ret unionSet:superKeyPaths];
        return ret;
    }
243
    return dict[key];
244
}
245

246
/* Constructor */
James Dumay's avatar
James Dumay committed
247
- (instancetype)init
248
{
249
    return [self initWithDrawable:nil options:nil];
250 251
}

252 253 254 255 256 257 258
- (instancetype)initWithLibVLCInstance:(void *)playerInstance andLibrary:(VLCLibrary *)library
{
    if (self = [super init]) {
        _cachedTime = [VLCTime nullTime];
        _cachedRemainingTime = [VLCTime nullTime];
        _position = 0.0f;
        _cachedState = VLCMediaPlayerStateStopped;
259
        _libVLCBackgroundQueue = [self libVLCBackgroundQueue];
260 261 262 263 264 265 266 267 268 269 270

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

        _playerInstance = playerInstance;

        [self registerObservers];
    }
    return self;
}

Pierre's avatar
Pierre committed
271
#if !TARGET_OS_IPHONE
James Dumay's avatar
James Dumay committed
272
- (instancetype)initWithVideoView:(VLCVideoView *)aVideoView
273
{
274
    return [self initWithDrawable: aVideoView options:nil];
275
}
276

James Dumay's avatar
James Dumay committed
277
- (instancetype)initWithVideoLayer:(VLCVideoLayer *)aVideoLayer
278
{
279 280 281
    return [self initWithDrawable: aVideoLayer options:nil];
}

James Dumay's avatar
James Dumay committed
282
- (instancetype)initWithVideoView:(VLCVideoView *)aVideoView options:(NSArray *)options
283 284 285 286
{
    return [self initWithDrawable: aVideoView options:options];
}

James Dumay's avatar
James Dumay committed
287
- (instancetype)initWithVideoLayer:(VLCVideoLayer *)aVideoLayer options:(NSArray *)options
288 289
{
    return [self initWithDrawable: aVideoLayer options:options];
290
}
Pierre's avatar
Pierre committed
291
#endif
292

James Dumay's avatar
James Dumay committed
293
- (instancetype)initWithOptions:(NSArray *)options
294 295 296 297
{
    return [self initWithDrawable:nil options:options];
}

298 299
- (void)dealloc
{
300 301 302
    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");
303

Pierre's avatar
Pierre committed
304 305 306
    [self unregisterObservers];
    [[VLCEventManager sharedManager] cancelCallToObject:self];

307 308
    // 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?
309
    _delegate = nil;
310

311 312 313
    // 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.
314
    libvlc_media_player_set_nsobject(_playerInstance, nil);
315

316 317 318 319 320
    if (_equalizerInstance) {
        libvlc_media_player_set_equalizer(_playerInstance, NULL);
        libvlc_audio_equalizer_release(_equalizerInstance);
    }

321 322 323
    if (_viewpoint)
        libvlc_free(_viewpoint);

324
    libvlc_media_player_release(_playerInstance);
325

326 327
    if (_privateLibrary != [VLCLibrary sharedLibrary])
        libvlc_release(_privateLibrary.instance);
328 329
}

Pierre's avatar
Pierre committed
330
#if !TARGET_OS_IPHONE
331
- (void)setVideoView:(VLCVideoView *)aVideoView
332
{
333
    [self setDrawable: aVideoView];
334 335
}

336
- (void)setVideoLayer:(VLCVideoLayer *)aVideoLayer
337
{
338
    [self setDrawable: aVideoLayer];
339
}
Pierre's avatar
Pierre committed
340
#endif
341

342 343 344
- (void)setDrawable:(id)aDrawable
{
    // Make sure that this instance has been associated with the drawing canvas.
345
    _drawable = aDrawable;
346 347 348 349 350 351

    /* 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));
    });
352 353 354 355
}

- (id)drawable
{
356
    return (__bridge id)(libvlc_media_player_get_nsobject(_playerInstance));
357 358
}

359 360
- (VLCAudio *)audio
{
361 362 363
    if (!_audio)
        _audio = [[VLCAudio alloc] initWithMediaPlayer:self];
    return _audio;
364 365
}

366 367
#pragma mark -
#pragma mark Video Tracks
368
- (void)setCurrentVideoTrackIndex:(int)value
369
{
370
    libvlc_video_set_track(_playerInstance, value);
371 372
}

373
- (int)currentVideoTrackIndex
374
{
375
    int count = libvlc_video_get_track_count(_playerInstance);
376
    if (count <= 0)
377
        return -1;
378

379
    return libvlc_video_get_track(_playerInstance);
380 381
}

382 383
- (NSArray *)videoTrackNames
{
384
    NSInteger count = libvlc_video_get_track_count(_playerInstance);
385
    if (count <= 0)
386
        return @[];
387

388 389
    libvlc_track_description_t *firstTrack = libvlc_video_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
390 391 392

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
393
        [tempArray addObject:@(currentTrack->psz_name)];
394 395
        currentTrack = currentTrack->p_next;
    }
396
    libvlc_track_description_list_release(firstTrack);
397 398 399 400 401
    return [NSArray arrayWithArray: tempArray];
}

- (NSArray *)videoTrackIndexes
{
402
    NSInteger count = libvlc_video_get_track_count(_playerInstance);
403
    if (count <= 0)
404
        return @[];
405

406 407
    libvlc_track_description_t *firstTrack = libvlc_video_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
408 409 410

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
411
        [tempArray addObject:@(currentTrack->i_id)];
412 413
        currentTrack = currentTrack->p_next;
    }
414
    libvlc_track_description_list_release(firstTrack);
415 416 417
    return [NSArray arrayWithArray: tempArray];
}

418 419 420 421 422
- (int)numberOfVideoTracks
{
    return libvlc_video_get_track_count(_playerInstance);
}

423 424
#pragma mark -
#pragma mark Subtitles
425

426
- (void)setCurrentVideoSubTitleIndex:(int)index
427
{
428
    libvlc_video_set_spu(_playerInstance, index);
429 430
}

431
- (int)currentVideoSubTitleIndex
432
{
433
    NSInteger count = libvlc_video_get_spu_count(_playerInstance);
434

435
    if (count <= 0)
436
        return -1;
437

438
    return libvlc_video_get_spu(_playerInstance);
439 440
}

441 442
- (NSArray *)videoSubTitlesNames
{
443
    NSInteger count = libvlc_video_get_spu_count(_playerInstance);
444
    if (count <= 0)
445
        return @[];
446

447 448
    libvlc_track_description_t *firstTrack = libvlc_video_get_spu_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
449 450 451

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
452 453
        NSString *track = @(currentTrack->psz_name);
        [tempArray addObject:track != nil ? track : @""];
454 455
        currentTrack = currentTrack->p_next;
    }
456
    libvlc_track_description_list_release(firstTrack);
457 458 459 460 461
    return [NSArray arrayWithArray: tempArray];
}

- (NSArray *)videoSubTitlesIndexes
{
462
    NSInteger count = libvlc_video_get_spu_count(_playerInstance);
463
    if (count <= 0)
464
        return @[];
465

466 467
    libvlc_track_description_t *firstTrack = libvlc_video_get_spu_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
468 469 470

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
471
        [tempArray addObject:@(currentTrack->i_id)];
472 473
        currentTrack = currentTrack->p_next;
    }
474
    libvlc_track_description_list_release(firstTrack);
475 476 477
    return [NSArray arrayWithArray: tempArray];
}

478 479 480 481 482
- (int)numberOfSubtitlesTracks
{
    return libvlc_video_get_spu_count(_playerInstance);
}

483 484
- (BOOL)openVideoSubTitlesFromFile:(NSString *)path
{
485
    return [self addPlaybackSlave:[NSURL fileURLWithPath:path] type:VLCMediaPlaybackSlaveTypeSubtitle enforce:YES];
486 487
}

488 489 490 491 492 493 494 495 496 497 498
- (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);
}

499 500
- (void)setCurrentVideoSubTitleDelay:(NSInteger)index
{
501
    libvlc_video_set_spu_delay(_playerInstance, index);
502 503 504 505
}

- (NSInteger)currentVideoSubTitleDelay
{
506
    return libvlc_video_get_spu_delay(_playerInstance);
507 508
}

509
#if TARGET_OS_IPHONE
510 511
- (void)setTextRendererFontSize:(NSNumber *)fontSize
{
512
    libvlc_video_set_textrenderer_int(_playerInstance, libvlc_textrender_fontsize, [fontSize intValue]);
513 514 515 516
}

- (void)setTextRendererFont:(NSString *)fontname
{
517
    libvlc_video_set_textrenderer_string(_playerInstance, libvlc_textrender_font, [fontname UTF8String]);
518 519 520 521
}

- (void)setTextRendererFontColor:(NSNumber *)fontColor
{
522
    libvlc_video_set_textrenderer_int(_playerInstance, libvlc_textrender_fontcolor, [fontColor intValue]);
523
}
524 525 526

- (void)setTextRendererFontForceBold:(NSNumber *)fontForceBold
{
527
    libvlc_video_set_textrenderer_bool(_playerInstance, libvlc_textrender_fontforcebold, [fontForceBold boolValue]);
528
}
529
#endif
530

531 532 533
#pragma mark -
#pragma mark Video Crop geometry

534 535
- (void)setVideoCropGeometry:(char *)value
{
536
    libvlc_video_set_crop_geometry(_playerInstance, value);
537 538 539 540
}

- (char *)videoCropGeometry
{
541
    char * result = libvlc_video_get_crop_geometry(_playerInstance);
542
    return result;
543 544
}

545 546
- (void)setVideoAspectRatio:(char *)value
{
547
    libvlc_video_set_aspect_ratio(_playerInstance, value);
548 549 550 551
}

- (char *)videoAspectRatio
{
552
    char * result = libvlc_video_get_aspect_ratio(_playerInstance);
553 554 555
    return result;
}

556 557
- (void)setScaleFactor:(float)value
{
558
    libvlc_video_set_scale(_playerInstance, value);
559 560 561 562
}

- (float)scaleFactor
{
563
    return libvlc_video_get_scale(_playerInstance);
564 565
}

566
- (void)saveVideoSnapshotAt:(NSString *)path withWidth:(int)width andHeight:(int)height
567
{
568
    int failure = libvlc_video_take_snapshot(_playerInstance, 0, [path UTF8String], width, height);
569 570
    if (failure)
        [[NSException exceptionWithName:@"Can't take a video snapshot" reason:@"No video output" userInfo:nil] raise];
571 572
}

573
- (void)setDeinterlaceFilter:(NSString *)name
574
{
575
    if (!name || name.length < 1)
576
        libvlc_video_set_deinterlace(_playerInstance, VLCDeinterlaceOff, NULL);
577
    else
578 579 580 581 582 583
        libvlc_video_set_deinterlace(_playerInstance, VLCDeinterlaceOn, [name UTF8String]);
}

- (void)setDeinterlace:(VLCDeinterlace)deinterlace withFilter:(NSString *)name
{
    libvlc_video_set_deinterlace(_playerInstance, deinterlace, [name UTF8String]);
584 585
}

586 587
- (BOOL)adjustFilterEnabled
{
588
    return libvlc_video_get_adjust_int(_playerInstance, libvlc_adjust_Enable);
589 590 591
}
- (void)setAdjustFilterEnabled:(BOOL)b_value
{
592
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, b_value);
593 594 595
}
- (float)contrast
{
596 597
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Contrast);
598 599 600
}
- (void)setContrast:(float)f_value
{
601
    if (f_value <= 2. && f_value >= 0.) {
602 603
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
        libvlc_video_set_adjust_float(_playerInstance,libvlc_adjust_Contrast, f_value);
604
    }
605 606 607
}
- (float)brightness
{
608 609
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Brightness);
610 611 612
}
- (void)setBrightness:(float)f_value
{
613
    if (f_value <= 2. && f_value >= 0.) {
614 615
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
        libvlc_video_set_adjust_float(_playerInstance, libvlc_adjust_Brightness, f_value);
616
    }
617
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
618 619

- (float)hue
620
{
621
    libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
622
    return libvlc_video_get_adjust_float(_playerInstance, libvlc_adjust_Hue);
623
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
624
- (void)setHue:(float)f_value
625
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
626
    if (f_value <= 180. && f_value >= -180.) {
627
        libvlc_video_set_adjust_int(_playerInstance, libvlc_adjust_Enable, 1);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
628
        libvlc_video_set_adjust_float(_playerInstance, libvlc_adjust_Hue, f_value);
629
    }
630
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
631

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

657
- (void)setRate:(float)value
658
{
659
    libvlc_media_player_set_rate(_playerInstance, value);
660 661
}

662
- (float)rate
663
{
664
    return libvlc_media_player_get_rate(_playerInstance);
665 666
}

Pierre's avatar
Pierre committed
667
- (CGSize)videoSize
668
{
669
    unsigned height = 0, width = 0;
670
    int failure = libvlc_video_get_size(_playerInstance, 0, &width, &height);
671
    if (failure)
672
        return CGSizeZero;
Pierre's avatar
Pierre committed
673
    return CGSizeMake(width, height);
674 675 676 677
}

- (BOOL)hasVideoOut
{
678
    return libvlc_media_player_has_vout(_playerInstance);
679 680 681 682
}

- (float)framesPerSecond
{
683
    return .0;
684 685 686 687
}

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

- (VLCTime *)time
{
695
    return _cachedTime;
696 697
}

698 699
- (VLCTime *)remainingTime
{
700
    return _cachedRemainingTime;
701 702
}

703 704
#pragma mark -
#pragma mark Chapters
705
- (void)setCurrentChapterIndex:(int)value;
706
{
707
    libvlc_media_player_set_chapter(_playerInstance, value);
708 709
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
710
- (int)currentChapterIndex
711
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
712
    int count = libvlc_media_player_get_chapter_count(_playerInstance);
713
    if (count <= 0)
714
        return -1;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
715
    int result = libvlc_media_player_get_chapter(_playerInstance);
716 717 718
    return result;
}

719 720
- (void)nextChapter
{
721
    libvlc_media_player_next_chapter(_playerInstance);
722 723 724 725
}

- (void)previousChapter
{
726
    libvlc_media_player_previous_chapter(_playerInstance);
727 728
}

729
- (NSArray *)chaptersForTitleIndex:(int)title
730
{
731
    NSInteger count = libvlc_media_player_get_chapter_count(_playerInstance);
732
    if (count <= 0)
733
        return @[];
734

735 736
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
737 738
    libvlc_track_description_t *firstTrack = libvlc_video_get_chapter_description(_playerInstance, title);
    libvlc_track_description_t *currentTrack = firstTrack;
739 740
#pragma clang diagnostic push

741
    NSMutableArray *tempArray = [NSMutableArray array];
742
    for (NSInteger i = 0; i < count ; i++) {
743 744
        [tempArray addObject:@(currentTrack->psz_name)];
        currentTrack = currentTrack->p_next;
745
    }
746
    libvlc_track_description_list_release(firstTrack);
747
    return [NSArray arrayWithArray:tempArray];
748 749
}

750 751 752
#pragma mark -
#pragma mark Titles

753
- (void)setCurrentTitleIndex:(int)value
754
{
755
    libvlc_media_player_set_title(_playerInstance, value);
756 757
}

758
- (int)currentTitleIndex
759
{
760
    NSInteger count = libvlc_media_player_get_title_count(_playerInstance);
761
    if (count <= 0)
762
        return -1;
763

764
    return libvlc_media_player_get_title(_playerInstance);
765 766
}

767 768 769 770 771
- (int)numberOfTitles
{
    return libvlc_media_player_get_title_count(_playerInstance);
}

772
- (NSUInteger)countOfTitles
773
{
774
    NSUInteger result = libvlc_media_player_get_title_count(_playerInstance);
775 776 777
    return result;
}

778 779
- (NSArray *)titles
{
780 781 782 783
    NSUInteger count = [self countOfTitles];
    if (count == 0)
        return [NSArray array];

784 785
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
786 787
    libvlc_track_description_t *firstTrack = libvlc_video_get_title_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
788 789
#pragma clang diagnostic pop

790
    if (!currentTrack)
791 792 793
        return [NSArray array];

    NSMutableArray *tempArray = [NSMutableArray array];
794 795

    while (1) {
796 797 798 799
        if (currentTrack->psz_name != nil)
            [tempArray addObject:@(currentTrack->psz_name)];
        if (currentTrack->p_next)
            currentTrack = currentTrack->p_next;
800 801
        else
            break;
802
    }
803

804
    libvlc_track_description_list_release(firstTrack);
805 806 807
    return [NSArray arrayWithArray: tempArray];
}

808 809 810 811 812 813 814 815 816 817 818 819 820
- (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];
    }

821
    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:numberOfTitleDescriptions];
822 823 824 825 826

    for (int i = 0; i < numberOfTitleDescriptions; i++) {
        NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                           [NSNumber numberWithLongLong:titleInfo[i]->i_duration],
                                           VLCTitleDescriptionDuration,
Felix Paul Kühne's avatar
Felix Paul Kühne committed
827
                                           @(titleInfo[i]->i_flags & libvlc_title_menu),
828 829 830 831 832 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
                                           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;
}

859 860 861 862 863
- (int)numberOfChaptersForTitle:(int)titleIndex
{
    return libvlc_media_player_get_chapter_count_for_title(_playerInstance, titleIndex);
}

864 865 866 867 868 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
- (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];
}

898 899
#pragma mark -
#pragma mark Audio tracks
900
- (void)setCurrentAudioTrackIndex:(int)value
901
{
902
    libvlc_audio_set_track(_playerInstance, value);
903 904
}

905
- (int)currentAudioTrackIndex
906
{
907
    NSInteger count = libvlc_audio_get_track_count(_playerInstance);
908
    if (count <= 0)
909
        return -1;
910

911
    return libvlc_audio_get_track(_playerInstance);
912 913
}

914 915
- (NSArray *)audioTrackNames
{
916
    NSInteger count = libvlc_audio_get_track_count(_playerInstance);
917
    if (count <= 0)
918
        return @[];
919

920 921
    libvlc_track_description_t *firstTrack = libvlc_audio_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
922 923 924

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
925 926
        NSString *track = @(currentTrack->psz_name);
        [tempArray addObject:track != nil ? track : @""];
927 928
        currentTrack = currentTrack->p_next;
    }
929
    libvlc_track_description_list_release(firstTrack);
930 931 932 933 934
    return [NSArray arrayWithArray: tempArray];
}

- (NSArray *)audioTrackIndexes
{
935
    NSInteger count = libvlc_audio_get_track_count(_playerInstance);
936
    if (count <= 0)
937
        return @[];
938

939 940
    libvlc_track_description_t *firstTrack = libvlc_audio_get_track_description(_playerInstance);
    libvlc_track_description_t *currentTrack = firstTrack;
941 942 943

    NSMutableArray *tempArray = [NSMutableArray array];
    while (currentTrack) {
944
        [tempArray addObject:@(currentTrack->i_id)];
945 946
        currentTrack = currentTrack->p_next;
    }
947
    libvlc_track_description_list_release(firstTrack);
948 949 950
    return [NSArray arrayWithArray: tempArray];
}

951 952 953 954 955
- (int)numberOfAudioTracks
{
    return libvlc_audio_get_track_count(_playerInstance);
}

956
- (void)setAudioChannel:(int)value