VLCMediaPlayer.m 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /*****************************************************************************
  2. * VLCMediaPlayer.m: VLCKit.framework VLCMediaPlayer implementation
  3. *****************************************************************************
  4. * Copyright (C) 2007-2009 Pierre d'Herbemont
  5. * Copyright (C) 2007-2013 VLC authors and VideoLAN
  6. * Partial Copyright (C) 2009-2013 Felix Paul Kühne
  7. * $Id$
  8. *
  9. * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
  10. * Faustion Osuna <enrique.osuna # gmail.com>
  11. * Felix Paul Kühne <fkuehne # videolan.org>
  12. *
  13. * This program is free software; you can redistribute it and/or modify it
  14. * under the terms of the GNU Lesser General Public License as published by
  15. * the Free Software Foundation; either version 2.1 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU Lesser General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Lesser General Public License
  24. * along with this program; if not, write to the Free Software Foundation,
  25. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  26. *****************************************************************************/
  27. #import "VLCLibrary.h"
  28. #import "VLCMediaPlayer.h"
  29. #import "VLCEventManager.h"
  30. #import "VLCLibVLCBridging.h"
  31. #if !TARGET_OS_IPHONE
  32. # import "VLCVideoView.h"
  33. #endif
  34. #ifdef HAVE_CONFIG_H
  35. # include "config.h"
  36. #endif
  37. #if !TARGET_OS_IPHONE
  38. /* prevent system sleep */
  39. # import <CoreServices/CoreServices.h>
  40. /* FIXME: Ugly hack! */
  41. # ifdef __x86_64__
  42. # import <CoreServices/../Frameworks/OSServices.framework/Headers/Power.h>
  43. # endif
  44. #endif
  45. #include <vlc/vlc.h>
  46. /* Notification Messages */
  47. NSString * VLCMediaPlayerTimeChanged = @"VLCMediaPlayerTimeChanged";
  48. NSString * VLCMediaPlayerStateChanged = @"VLCMediaPlayerStateChanged";
  49. NSString * VLCMediaPlayerStateToString(VLCMediaPlayerState state)
  50. {
  51. static NSString * stateToStrings[] = {
  52. [VLCMediaPlayerStateStopped] = @"VLCMediaPlayerStateStopped",
  53. [VLCMediaPlayerStateOpening] = @"VLCMediaPlayerStateOpening",
  54. [VLCMediaPlayerStateBuffering] = @"VLCMediaPlayerStateBuffering",
  55. [VLCMediaPlayerStateEnded] = @"VLCMediaPlayerStateEnded",
  56. [VLCMediaPlayerStateError] = @"VLCMediaPlayerStateError",
  57. [VLCMediaPlayerStatePlaying] = @"VLCMediaPlayerStatePlaying",
  58. [VLCMediaPlayerStatePaused] = @"VLCMediaPlayerStatePaused"
  59. };
  60. return stateToStrings[state];
  61. }
  62. /* libvlc event callback */
  63. static void HandleMediaInstanceVolumeChanged(const libvlc_event_t * event, void * self)
  64. {
  65. [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
  66. withDelegateMethod:@selector(mediaPlayerVolumeChanged:)
  67. withNotificationName:VLCMediaPlayerVolumeChanged];
  68. }
  69. static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
  70. {
  71. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  72. [[VLCEventManager sharedManager] callOnMainThreadObject:self
  73. withMethod:@selector(mediaPlayerTimeChanged:)
  74. withArgumentAsObject:@(event->u.media_player_time_changed.new_time)];
  75. [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
  76. withDelegateMethod:@selector(mediaPlayerTimeChanged:)
  77. withNotificationName:VLCMediaPlayerTimeChanged];
  78. [pool release];
  79. }
  80. static void HandleMediaPositionChanged(const libvlc_event_t * event, void * self)
  81. {
  82. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  83. [[VLCEventManager sharedManager] callOnMainThreadObject:self
  84. withMethod:@selector(mediaPlayerPositionChanged:)
  85. withArgumentAsObject:@(event->u.media_player_position_changed.new_position)];
  86. [pool release];
  87. }
  88. static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void * self)
  89. {
  90. VLCMediaPlayerState newState;
  91. if (event->type == libvlc_MediaPlayerPlaying)
  92. newState = VLCMediaPlayerStatePlaying;
  93. else if (event->type == libvlc_MediaPlayerPaused)
  94. newState = VLCMediaPlayerStatePaused;
  95. else if (event->type == libvlc_MediaPlayerEndReached)
  96. newState = VLCMediaPlayerStateStopped;
  97. else if (event->type == libvlc_MediaPlayerEncounteredError)
  98. newState = VLCMediaPlayerStateError;
  99. else if (event->type == libvlc_MediaPlayerBuffering)
  100. newState = VLCMediaPlayerStateBuffering;
  101. else if (event->type == libvlc_MediaPlayerOpening)
  102. newState = VLCMediaPlayerStateOpening;
  103. else {
  104. VKLog(@"%s: Unknown event", __FUNCTION__);
  105. return;
  106. }
  107. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  108. [[VLCEventManager sharedManager] callOnMainThreadObject:self
  109. withMethod:@selector(mediaPlayerStateChanged:)
  110. withArgumentAsObject:@(newState)];
  111. [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
  112. withDelegateMethod:@selector(mediaPlayerStateChanged:)
  113. withNotificationName:VLCMediaPlayerStateChanged];
  114. [pool release];
  115. }
  116. static void HandleMediaPlayerMediaChanged(const libvlc_event_t * event, void * self)
  117. {
  118. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  119. [[VLCEventManager sharedManager] callOnMainThreadObject:self
  120. withMethod:@selector(mediaPlayerMediaChanged:)
  121. withArgumentAsObject:[VLCMedia mediaWithLibVLCMediaDescriptor:event->u.media_player_media_changed.new_media]];
  122. [pool release];
  123. }
  124. // TODO: Documentation
  125. @interface VLCMediaPlayer (Private)
  126. - (id)initWithDrawable:(id)aDrawable;
  127. - (void)registerObservers;
  128. - (void)unregisterObservers;
  129. - (void)mediaPlayerTimeChanged:(NSNumber *)newTime;
  130. - (void)mediaPlayerPositionChanged:(NSNumber *)newTime;
  131. - (void)mediaPlayerStateChanged:(NSNumber *)newState;
  132. - (void)mediaPlayerMediaChanged:(VLCMedia *)media;
  133. @end
  134. @implementation VLCMediaPlayer
  135. /* Bindings */
  136. + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
  137. {
  138. static NSDictionary * dict = nil;
  139. NSSet * superKeyPaths;
  140. if (!dict) {
  141. dict = [@{@"playing": [NSSet setWithObject:@"state"],
  142. @"seekable": [NSSet setWithObjects:@"state", @"media", nil],
  143. @"canPause": [NSSet setWithObjects:@"state", @"media", nil],
  144. @"description": [NSSet setWithObjects:@"state", @"media", nil]} retain];
  145. }
  146. if ((superKeyPaths = [super keyPathsForValuesAffectingValueForKey: key])) {
  147. NSMutableSet * ret = [NSMutableSet setWithSet:dict[key]];
  148. [ret unionSet:superKeyPaths];
  149. return ret;
  150. }
  151. return dict[key];
  152. }
  153. /* Contructor */
  154. - (id)init
  155. {
  156. return [self initWithDrawable:nil];
  157. }
  158. #if !TARGET_OS_IPHONE
  159. - (id)initWithVideoView:(VLCVideoView *)aVideoView
  160. {
  161. return [self initWithDrawable: aVideoView];
  162. }
  163. - (id)initWithVideoLayer:(VLCVideoLayer *)aVideoLayer
  164. {
  165. return [self initWithDrawable: aVideoLayer];
  166. }
  167. #endif
  168. - (void)dealloc
  169. {
  170. NSAssert(libvlc_media_player_get_state(instance) == libvlc_Stopped, @"You released the media player before ensuring that it is stopped");
  171. [self unregisterObservers];
  172. [[VLCEventManager sharedManager] cancelCallToObject:self];
  173. #if TARGET_OS_IPHONE
  174. [[NSNotificationCenter defaultCenter] removeObserver:self];
  175. #endif
  176. // Always get rid of the delegate first so we can stop sending messages to it
  177. // TODO: Should we tell the delegate that we're shutting down?
  178. delegate = nil;
  179. // Clear our drawable as we are going to release it, we don't
  180. // want the core to use it from this point. This won't happen as
  181. // the media player must be stopped.
  182. libvlc_media_player_set_nsobject(instance, nil);
  183. libvlc_media_player_release(instance);
  184. // Get rid of everything else
  185. [media release];
  186. [cachedTime release];
  187. [cachedRemainingTime release];
  188. [drawable release];
  189. [audio release];
  190. [super dealloc];
  191. }
  192. - (void)setDelegate:(id)value
  193. {
  194. delegate = value;
  195. }
  196. - (id)delegate
  197. {
  198. return delegate;
  199. }
  200. #if !TARGET_OS_IPHONE
  201. - (void)setVideoView:(VLCVideoView *)aVideoView
  202. {
  203. [self setDrawable: aVideoView];
  204. }
  205. - (void)setVideoLayer:(VLCVideoLayer *)aVideoLayer
  206. {
  207. [self setDrawable: aVideoLayer];
  208. }
  209. #endif
  210. - (void)setDrawable:(id)aDrawable
  211. {
  212. // Make sure that this instance has been associated with the drawing canvas.
  213. libvlc_media_player_set_nsobject(instance, aDrawable);
  214. }
  215. - (id)drawable
  216. {
  217. return libvlc_media_player_get_nsobject(instance);
  218. }
  219. - (VLCAudio *)audio
  220. {
  221. if (!audio)
  222. audio = [[VLCAudio alloc] initWithMediaPlayer:self];
  223. return audio;
  224. }
  225. #pragma mark -
  226. #pragma mark Video Tracks
  227. - (void)setCurrentVideoTrackIndex:(NSUInteger)value
  228. {
  229. libvlc_video_set_track(instance, (int)value);
  230. }
  231. - (NSUInteger)currentVideoTrackIndex
  232. {
  233. NSInteger count = libvlc_video_get_track_count(instance);
  234. if (count <= 0)
  235. return NSNotFound;
  236. NSUInteger result = libvlc_video_get_track(instance);
  237. return result;
  238. }
  239. - (NSArray *)videoTrackNames
  240. {
  241. NSInteger count = libvlc_video_get_track_count(instance);
  242. if (count <= 0)
  243. return @[];
  244. libvlc_track_description_t *currentTrack = libvlc_video_get_track_description(instance);
  245. NSMutableArray *tempArray = [NSMutableArray array];
  246. while (currentTrack) {
  247. [tempArray addObject:@(currentTrack->psz_name)];
  248. currentTrack = currentTrack->p_next;
  249. }
  250. libvlc_track_description_list_release(currentTrack);
  251. return [NSArray arrayWithArray: tempArray];
  252. }
  253. - (NSArray *)videoTrackIndexes
  254. {
  255. NSInteger count = libvlc_video_get_track_count(instance);
  256. if (count <= 0)
  257. return @[];
  258. libvlc_track_description_t *currentTrack = libvlc_video_get_track_description(instance);
  259. NSMutableArray *tempArray = [NSMutableArray array];
  260. while (currentTrack) {
  261. [tempArray addObject:@(currentTrack->i_id)];
  262. currentTrack = currentTrack->p_next;
  263. }
  264. libvlc_track_description_list_release(currentTrack);
  265. return [NSArray arrayWithArray: tempArray];
  266. }
  267. - (NSArray *)videoTracks
  268. {
  269. NSInteger count = libvlc_video_get_track_count(instance);
  270. if (count <= 0)
  271. return @[];
  272. libvlc_track_description_t *tracks = libvlc_video_get_track_description(instance);
  273. NSMutableArray *tempArray = [NSMutableArray array];
  274. for (NSUInteger i = 0; i < count ; i++) {
  275. [tempArray addObject:@(tracks->psz_name)];
  276. tracks = tracks->p_next;
  277. }
  278. libvlc_track_description_list_release(tracks);
  279. return [NSArray arrayWithArray: tempArray];
  280. }
  281. #pragma mark -
  282. #pragma mark Subtitles
  283. - (void)setCurrentVideoSubTitleIndex:(NSUInteger)index
  284. {
  285. libvlc_video_set_spu(instance, (int)index);
  286. }
  287. - (NSUInteger)currentVideoSubTitleIndex
  288. {
  289. NSInteger count = libvlc_video_get_spu_count(instance);
  290. if (count <= 0)
  291. return NSNotFound;
  292. return libvlc_video_get_spu(instance);
  293. }
  294. - (NSArray *)videoSubTitlesNames
  295. {
  296. NSInteger count = libvlc_video_get_spu_count(instance);
  297. if (count <= 0)
  298. return @[];
  299. libvlc_track_description_t *currentTrack = libvlc_video_get_spu_description(instance);
  300. NSMutableArray *tempArray = [NSMutableArray array];
  301. while (currentTrack) {
  302. [tempArray addObject:@(currentTrack->psz_name)];
  303. currentTrack = currentTrack->p_next;
  304. }
  305. libvlc_track_description_list_release(currentTrack);
  306. return [NSArray arrayWithArray: tempArray];
  307. }
  308. - (NSArray *)videoSubTitlesIndexes
  309. {
  310. NSInteger count = libvlc_video_get_spu_count(instance);
  311. if (count <= 0)
  312. return @[];
  313. libvlc_track_description_t *currentTrack = libvlc_video_get_spu_description(instance);
  314. NSMutableArray *tempArray = [NSMutableArray array];
  315. while (currentTrack) {
  316. [tempArray addObject:@(currentTrack->i_id)];
  317. currentTrack = currentTrack->p_next;
  318. }
  319. libvlc_track_description_list_release(currentTrack);
  320. return [NSArray arrayWithArray: tempArray];
  321. }
  322. - (BOOL)openVideoSubTitlesFromFile:(NSString *)path
  323. {
  324. return libvlc_video_set_subtitle_file(instance, [path UTF8String]);
  325. }
  326. - (NSArray *)videoSubTitles
  327. {
  328. libvlc_track_description_t *currentTrack = libvlc_video_get_spu_description(instance);
  329. NSMutableArray *tempArray = [NSMutableArray array];
  330. while (currentTrack) {
  331. [tempArray addObject:@(currentTrack->psz_name)];
  332. currentTrack = currentTrack->p_next;
  333. }
  334. libvlc_track_description_list_release(currentTrack);
  335. return [NSArray arrayWithArray: tempArray];
  336. }
  337. - (void)setCurrentVideoSubTitleDelay:(NSInteger)index
  338. {
  339. libvlc_video_set_spu_delay(instance, index);
  340. }
  341. - (NSInteger)currentVideoSubTitleDelay
  342. {
  343. return libvlc_video_get_spu_delay(instance);
  344. }
  345. #pragma mark -
  346. #pragma mark Video Crop geometry
  347. - (void)setVideoCropGeometry:(char *)value
  348. {
  349. libvlc_video_set_crop_geometry(instance, value);
  350. }
  351. - (char *)videoCropGeometry
  352. {
  353. char * result = libvlc_video_get_crop_geometry(instance);
  354. return result;
  355. }
  356. - (void)setVideoAspectRatio:(char *)value
  357. {
  358. libvlc_video_set_aspect_ratio(instance, value);
  359. }
  360. - (char *)videoAspectRatio
  361. {
  362. char * result = libvlc_video_get_aspect_ratio(instance);
  363. return result;
  364. }
  365. - (void)setScaleFactor:(float)value
  366. {
  367. libvlc_video_set_scale(instance, value);
  368. }
  369. - (float)scaleFactor
  370. {
  371. return libvlc_video_get_scale(instance);
  372. }
  373. - (void)saveVideoSnapshotAt:(NSString *)path withWidth:(NSUInteger)width andHeight:(NSUInteger)height
  374. {
  375. int failure = libvlc_video_take_snapshot(instance, 0, [path UTF8String], width, height);
  376. if (failure)
  377. [[NSException exceptionWithName:@"Can't take a video snapshot" reason:@"No video output" userInfo:nil] raise];
  378. }
  379. - (void)setDeinterlaceFilter:(NSString *)name
  380. {
  381. libvlc_video_set_deinterlace(instance, [name UTF8String]);
  382. }
  383. - (BOOL)adjustFilterEnabled
  384. {
  385. return libvlc_video_get_adjust_int(instance, libvlc_adjust_Enable);
  386. }
  387. - (void)setAdjustFilterEnabled:(BOOL)b_value
  388. {
  389. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, b_value);
  390. }
  391. - (float)contrast
  392. {
  393. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  394. return libvlc_video_get_adjust_float(instance, libvlc_adjust_Contrast);
  395. }
  396. - (void)setContrast:(float)f_value
  397. {
  398. if (f_value <= 2. && f_value >= 0.) {
  399. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  400. libvlc_video_set_adjust_float(instance,libvlc_adjust_Contrast, f_value);
  401. }
  402. }
  403. - (float)brightness
  404. {
  405. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  406. return libvlc_video_get_adjust_float(instance, libvlc_adjust_Brightness);
  407. }
  408. - (void)setBrightness:(float)f_value
  409. {
  410. if (f_value <= 2. && f_value >= 0.) {
  411. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  412. libvlc_video_set_adjust_float(instance, libvlc_adjust_Brightness, f_value);
  413. }
  414. }
  415. - (NSInteger)hue
  416. {
  417. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  418. return libvlc_video_get_adjust_int(instance, libvlc_adjust_Hue);
  419. }
  420. - (void)setHue:(NSInteger)i_value
  421. {
  422. if (i_value <= 360 && i_value >= 0) {
  423. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  424. libvlc_video_set_adjust_int(instance, libvlc_adjust_Hue, i_value);
  425. }
  426. }
  427. - (float)saturation
  428. {
  429. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  430. return libvlc_video_get_adjust_float(instance, libvlc_adjust_Saturation);
  431. }
  432. - (void)setSaturation:(float)f_value
  433. {
  434. if (f_value <= 3. && f_value >= 0.) {
  435. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  436. libvlc_video_set_adjust_float(instance, libvlc_adjust_Saturation, f_value);
  437. }
  438. }
  439. - (float)gamma
  440. {
  441. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  442. return libvlc_video_get_adjust_float(instance, libvlc_adjust_Gamma);
  443. }
  444. - (void)setGamma:(float)f_value
  445. {
  446. if (f_value <= 10. && f_value >= 0.) {
  447. libvlc_video_set_adjust_int(instance, libvlc_adjust_Enable, 1);
  448. libvlc_video_set_adjust_float(instance, libvlc_adjust_Gamma, f_value);
  449. }
  450. }
  451. - (void)setRate:(float)value
  452. {
  453. libvlc_media_player_set_rate(instance, value);
  454. }
  455. - (float)rate
  456. {
  457. return libvlc_media_player_get_rate(instance);
  458. }
  459. - (CGSize)videoSize
  460. {
  461. unsigned height = 0, width = 0;
  462. int failure = libvlc_video_get_size(instance, 0, &width, &height);
  463. if (failure)
  464. [[NSException exceptionWithName:@"Can't get video size" reason:@"No video output" userInfo:nil] raise];
  465. return CGSizeMake(width, height);
  466. }
  467. - (BOOL)hasVideoOut
  468. {
  469. return libvlc_media_player_has_vout(instance);
  470. }
  471. - (float)framesPerSecond
  472. {
  473. return libvlc_media_player_get_fps(instance);
  474. }
  475. - (void)setTime:(VLCTime *)value
  476. {
  477. // Time is managed in seconds, while duration is managed in microseconds
  478. // TODO: Redo VLCTime to provide value numberAsMilliseconds, numberAsMicroseconds, numberAsSeconds, numberAsMinutes, numberAsHours
  479. libvlc_media_player_set_time(instance, value ? [[value numberValue] longLongValue] : 0);
  480. }
  481. - (VLCTime *)time
  482. {
  483. return cachedTime;
  484. }
  485. - (VLCTime *)remainingTime
  486. {
  487. return cachedRemainingTime;
  488. }
  489. - (NSUInteger)fps
  490. {
  491. return libvlc_media_player_get_fps(instance);
  492. }
  493. #pragma mark -
  494. #pragma mark Chapters
  495. - (void)setCurrentChapterIndex:(NSUInteger)value;
  496. {
  497. libvlc_media_player_set_chapter(instance, value);
  498. }
  499. - (NSUInteger)currentChapterIndex
  500. {
  501. NSInteger count = libvlc_media_player_get_chapter_count(instance);
  502. if (count <= 0)
  503. return NSNotFound;
  504. NSUInteger result = libvlc_media_player_get_chapter(instance);
  505. return result;
  506. }
  507. - (void)nextChapter
  508. {
  509. libvlc_media_player_next_chapter(instance);
  510. }
  511. - (void)previousChapter
  512. {
  513. libvlc_media_player_previous_chapter(instance);
  514. }
  515. - (NSArray *)chaptersForTitleIndex:(NSUInteger)title
  516. {
  517. NSInteger count = libvlc_media_player_get_chapter_count(instance);
  518. if (count <= 0)
  519. return @[];
  520. libvlc_track_description_t *tracks = libvlc_video_get_chapter_description(instance, title);
  521. NSMutableArray *tempArray = [NSMutableArray array];
  522. for (NSInteger i = 0; i < count ; i++) {
  523. [tempArray addObject:@(tracks->psz_name)];
  524. tracks = tracks->p_next;
  525. }
  526. libvlc_track_description_list_release(tracks);
  527. return [NSArray arrayWithArray:tempArray];
  528. }
  529. #pragma mark -
  530. #pragma mark Titles
  531. - (void)setCurrentTitleIndex:(NSUInteger)value
  532. {
  533. libvlc_media_player_set_title(instance, value);
  534. }
  535. - (NSUInteger)currentTitleIndex
  536. {
  537. NSInteger count = libvlc_media_player_get_title_count(instance);
  538. if (count <= 0)
  539. return NSNotFound;
  540. return libvlc_media_player_get_title(instance);
  541. }
  542. - (NSUInteger)countOfTitles
  543. {
  544. NSUInteger result = libvlc_media_player_get_title_count(instance);
  545. return result;
  546. }
  547. - (NSArray *)titles
  548. {
  549. libvlc_track_description_t *tracks = libvlc_video_get_title_description(instance);
  550. NSMutableArray *tempArray = [NSMutableArray array];
  551. for (NSInteger i = 0; i < [self countOfTitles] ; i++) {
  552. [tempArray addObject:@(tracks->psz_name)];
  553. tracks = tracks->p_next;
  554. }
  555. libvlc_track_description_list_release(tracks);
  556. return [NSArray arrayWithArray: tempArray];
  557. }
  558. #pragma mark -
  559. #pragma mark Audio tracks
  560. - (void)setCurrentAudioTrackIndex:(NSUInteger)value
  561. {
  562. libvlc_audio_set_track(instance, (int)value);
  563. }
  564. - (NSUInteger)currentAudioTrackIndex
  565. {
  566. NSInteger count = libvlc_audio_get_track_count(instance);
  567. if (count <= 0)
  568. return NSNotFound;
  569. NSUInteger result = libvlc_audio_get_track(instance);
  570. return result;
  571. }
  572. - (NSArray *)audioTrackNames
  573. {
  574. NSInteger count = libvlc_audio_get_track_count(instance);
  575. if (count <= 0)
  576. return @[];
  577. libvlc_track_description_t *currentTrack = libvlc_audio_get_track_description(instance);
  578. NSMutableArray *tempArray = [NSMutableArray array];
  579. while (currentTrack) {
  580. [tempArray addObject:@(currentTrack->psz_name)];
  581. currentTrack = currentTrack->p_next;
  582. }
  583. libvlc_track_description_list_release(currentTrack);
  584. return [NSArray arrayWithArray: tempArray];
  585. }
  586. - (NSArray *)audioTrackIndexes
  587. {
  588. NSInteger count = libvlc_audio_get_track_count(instance);
  589. if (count <= 0)
  590. return @[];
  591. libvlc_track_description_t *currentTrack = libvlc_audio_get_track_description(instance);
  592. NSMutableArray *tempArray = [NSMutableArray array];
  593. while (currentTrack) {
  594. [tempArray addObject:@(currentTrack->i_id)];
  595. currentTrack = currentTrack->p_next;
  596. }
  597. libvlc_track_description_list_release(currentTrack);
  598. return [NSArray arrayWithArray: tempArray];
  599. }
  600. - (NSArray *)audioTracks
  601. {
  602. NSInteger count = libvlc_audio_get_track_count(instance);
  603. if (count <= 0)
  604. return @[];
  605. libvlc_track_description_t *tracks = libvlc_audio_get_track_description(instance);
  606. NSMutableArray *tempArray = [NSMutableArray array];
  607. for (NSUInteger i = 0; i < count ; i++) {
  608. [tempArray addObject:@(tracks->psz_name)];
  609. tracks = tracks->p_next;
  610. }
  611. libvlc_track_description_list_release(tracks);
  612. return [NSArray arrayWithArray: tempArray];
  613. }
  614. - (void)setAudioChannel:(NSInteger)value
  615. {
  616. libvlc_audio_set_channel(instance, value);
  617. }
  618. - (NSInteger)audioChannel
  619. {
  620. return libvlc_audio_get_channel(instance);
  621. }
  622. - (void)setCurrentAudioPlaybackDelay:(NSInteger)index
  623. {
  624. libvlc_audio_set_delay(instance, index);
  625. }
  626. - (NSInteger)currentAudioPlaybackDelay
  627. {
  628. return libvlc_audio_get_delay(instance);
  629. }
  630. #pragma mark -
  631. #pragma mark set/get media
  632. - (void)setMedia:(VLCMedia *)value
  633. {
  634. if (media != value) {
  635. if (media && [media compare:value] == NSOrderedSame)
  636. return;
  637. [media release];
  638. media = [value retain];
  639. libvlc_media_player_set_media(instance, [media libVLCMediaDescriptor]);
  640. }
  641. }
  642. - (VLCMedia *)media
  643. {
  644. return media;
  645. }
  646. #pragma mark -
  647. #pragma mark playback
  648. - (BOOL)play
  649. {
  650. libvlc_media_player_play(instance);
  651. return YES;
  652. }
  653. - (void)pause
  654. {
  655. if ([NSThread isMainThread]) {
  656. /* Hack because we create a dead lock here, when the vout is stopped
  657. * and tries to recontact us on the main thread */
  658. /* FIXME: to do this properly we need to do some locking. We may want
  659. * to move that to libvlc */
  660. [self performSelectorInBackground:@selector(pause) withObject:nil];
  661. return;
  662. }
  663. // Pause the stream
  664. libvlc_media_player_pause(instance);
  665. }
  666. - (void)stop
  667. {
  668. libvlc_media_player_stop(instance);
  669. }
  670. - (void)gotoNextFrame
  671. {
  672. libvlc_media_player_next_frame(instance);
  673. }
  674. - (void)fastForward
  675. {
  676. [self fastForwardAtRate: 2.0];
  677. }
  678. - (void)fastForwardAtRate:(float)rate
  679. {
  680. [self setRate:rate];
  681. }
  682. - (void)rewind
  683. {
  684. [self rewindAtRate: 2.0];
  685. }
  686. - (void)rewindAtRate:(float)rate
  687. {
  688. [self setRate: -rate];
  689. }
  690. - (void)jumpBackward:(NSInteger)interval
  691. {
  692. if ([self isSeekable]) {
  693. interval = interval * 1000;
  694. [self setTime: [VLCTime timeWithInt: ([[self time] intValue] - interval)]];
  695. }
  696. }
  697. - (void)jumpForward:(NSInteger)interval
  698. {
  699. if ([self isSeekable]) {
  700. interval = interval * 1000;
  701. [self setTime: [VLCTime timeWithInt: ([[self time] intValue] + interval)]];
  702. }
  703. }
  704. - (void)extraShortJumpBackward
  705. {
  706. [self jumpBackward:3];
  707. }
  708. - (void)extraShortJumpForward
  709. {
  710. [self jumpForward:3];
  711. }
  712. - (void)shortJumpBackward
  713. {
  714. [self jumpBackward:10];
  715. }
  716. - (void)shortJumpForward
  717. {
  718. [self jumpForward:10];
  719. }
  720. - (void)mediumJumpBackward
  721. {
  722. [self jumpBackward:60];
  723. }
  724. - (void)mediumJumpForward
  725. {
  726. [self jumpForward:60];
  727. }
  728. - (void)longJumpBackward
  729. {
  730. [self jumpBackward:300];
  731. }
  732. - (void)longJumpForward
  733. {
  734. [self jumpForward:300];
  735. }
  736. + (NSSet *)keyPathsForValuesAffectingIsPlaying
  737. {
  738. return [NSSet setWithObjects:@"state", nil];
  739. }
  740. - (BOOL)isPlaying
  741. {
  742. VLCMediaPlayerState state = [self state];
  743. return ((state == VLCMediaPlayerStateOpening) || (state == VLCMediaPlayerStateBuffering) ||
  744. (state == VLCMediaPlayerStatePlaying));
  745. }
  746. - (BOOL)willPlay
  747. {
  748. return libvlc_media_player_will_play(instance);
  749. }
  750. static const VLCMediaPlayerState libvlc_to_local_state[] =
  751. {
  752. [libvlc_Stopped] = VLCMediaPlayerStateStopped,
  753. [libvlc_Opening] = VLCMediaPlayerStateOpening,
  754. [libvlc_Buffering] = VLCMediaPlayerStateBuffering,
  755. [libvlc_Playing] = VLCMediaPlayerStatePlaying,
  756. [libvlc_Paused] = VLCMediaPlayerStatePaused,
  757. [libvlc_Ended] = VLCMediaPlayerStateEnded,
  758. [libvlc_Error] = VLCMediaPlayerStateError
  759. };
  760. - (VLCMediaPlayerState)state
  761. {
  762. return cachedState;
  763. }
  764. - (float)position
  765. {
  766. return position;
  767. }
  768. - (void)setPosition:(float)newPosition
  769. {
  770. libvlc_media_player_set_position(instance, newPosition);
  771. }
  772. - (BOOL)isSeekable
  773. {
  774. return libvlc_media_player_is_seekable(instance);
  775. }
  776. - (BOOL)canPause
  777. {
  778. return libvlc_media_player_can_pause(instance);
  779. }
  780. - (void *)libVLCMediaPlayer
  781. {
  782. return instance;
  783. }
  784. @end
  785. @implementation VLCMediaPlayer (Private)
  786. - (id)initWithDrawable:(id)aDrawable
  787. {
  788. if (self = [super init]) {
  789. delegate = nil;
  790. media = nil;
  791. cachedTime = [[VLCTime nullTime] retain];
  792. cachedRemainingTime = [[VLCTime nullTime] retain];
  793. position = 0.0f;
  794. cachedState = VLCMediaPlayerStateStopped;
  795. // Create a media instance, it doesn't matter what library we start off with
  796. // it will change depending on the media descriptor provided to the media
  797. // instance
  798. instance = libvlc_media_player_new([VLCLibrary sharedInstance]);
  799. [self registerObservers];
  800. #if TARGET_OS_IPHONE
  801. NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  802. [center addObserver:self selector:@selector(applicationWillResignActive:)
  803. name:UIApplicationWillResignActiveNotification object:nil];
  804. [center addObserver:self selector:@selector(applicationDidBecomeActive:)
  805. name:UIApplicationDidBecomeActiveNotification object:nil];
  806. [center addObserver:self selector:@selector(applicationDidEnterBackground:)
  807. name:UIApplicationDidEnterBackgroundNotification object:nil];
  808. #endif
  809. [self setDrawable:aDrawable];
  810. }
  811. return self;
  812. }
  813. - (void)registerObservers
  814. {
  815. // Attach event observers into the media instance
  816. libvlc_event_manager_t * p_em = libvlc_media_player_event_manager(instance);
  817. libvlc_event_attach(p_em, libvlc_MediaPlayerPlaying, HandleMediaInstanceStateChanged, self);
  818. libvlc_event_attach(p_em, libvlc_MediaPlayerPaused, HandleMediaInstanceStateChanged, self);
  819. libvlc_event_attach(p_em, libvlc_MediaPlayerEncounteredError, HandleMediaInstanceStateChanged, self);
  820. libvlc_event_attach(p_em, libvlc_MediaPlayerEndReached, HandleMediaInstanceStateChanged, self);
  821. libvlc_event_attach(p_em, libvlc_MediaPlayerOpening, HandleMediaInstanceStateChanged, self);
  822. libvlc_event_attach(p_em, libvlc_MediaPlayerBuffering, HandleMediaInstanceStateChanged, self);
  823. /* FIXME: We may want to turn that off when none is interested by that */
  824. libvlc_event_attach(p_em, libvlc_MediaPlayerPositionChanged, HandleMediaPositionChanged, self);
  825. libvlc_event_attach(p_em, libvlc_MediaPlayerTimeChanged, HandleMediaTimeChanged, self);
  826. libvlc_event_attach(p_em, libvlc_MediaPlayerMediaChanged, HandleMediaPlayerMediaChanged, self);
  827. }
  828. - (void)unregisterObservers
  829. {
  830. libvlc_event_manager_t * p_em = libvlc_media_player_event_manager(instance);
  831. libvlc_event_detach(p_em, libvlc_MediaPlayerPlaying, HandleMediaInstanceStateChanged, self);
  832. libvlc_event_detach(p_em, libvlc_MediaPlayerPaused, HandleMediaInstanceStateChanged, self);
  833. libvlc_event_detach(p_em, libvlc_MediaPlayerEncounteredError, HandleMediaInstanceStateChanged, self);
  834. libvlc_event_detach(p_em, libvlc_MediaPlayerEndReached, HandleMediaInstanceStateChanged, self);
  835. libvlc_event_detach(p_em, libvlc_MediaPlayerOpening, HandleMediaInstanceStateChanged, self);
  836. libvlc_event_detach(p_em, libvlc_MediaPlayerBuffering, HandleMediaInstanceStateChanged, self);
  837. libvlc_event_detach(p_em, libvlc_MediaPlayerPositionChanged, HandleMediaPositionChanged, self);
  838. libvlc_event_detach(p_em, libvlc_MediaPlayerTimeChanged, HandleMediaTimeChanged, self);
  839. libvlc_event_detach(p_em, libvlc_MediaPlayerMediaChanged, HandleMediaPlayerMediaChanged, self);
  840. }
  841. #if TARGET_OS_IPHONE
  842. - (void)applicationWillResignActive:(NSNotification *)notification
  843. {
  844. shouldResumePlaying = YES;
  845. [self pause];
  846. }
  847. - (void)applicationDidEnterBackground:(NSNotification *)notification
  848. {
  849. shouldResumePlaying = NO;
  850. }
  851. - (void)applicationDidBecomeActive:(NSNotification *)notification
  852. {
  853. if (shouldResumePlaying) {
  854. shouldResumePlaying = NO;
  855. [self play];
  856. }
  857. }
  858. #endif
  859. - (void)mediaPlayerTimeChanged:(NSNumber *)newTime
  860. {
  861. [self willChangeValueForKey:@"time"];
  862. [self willChangeValueForKey:@"remainingTime"];
  863. [cachedTime release];
  864. cachedTime = [[VLCTime timeWithNumber:newTime] retain];
  865. [cachedRemainingTime release];
  866. double currentTime = [[cachedTime numberValue] doubleValue];
  867. double remaining = currentTime / position * (1 - position);
  868. cachedRemainingTime = [[VLCTime timeWithNumber:@(-remaining)] retain];
  869. [self didChangeValueForKey:@"remainingTime"];
  870. [self didChangeValueForKey:@"time"];
  871. }
  872. #if !TARGET_OS_IPHONE
  873. - (void)delaySleep
  874. {
  875. UpdateSystemActivity(UsrActivity);
  876. }
  877. #endif
  878. - (void)mediaPlayerPositionChanged:(NSNumber *)newPosition
  879. {
  880. #if !TARGET_OS_IPHONE
  881. // This seems to be the most relevant place to delay sleeping and screen saver.
  882. [self delaySleep];
  883. #endif
  884. [self willChangeValueForKey:@"position"];
  885. position = [newPosition floatValue];
  886. [self didChangeValueForKey:@"position"];
  887. }
  888. - (void)mediaPlayerStateChanged:(NSNumber *)newState
  889. {
  890. [self willChangeValueForKey:@"state"];
  891. cachedState = [newState intValue];
  892. #if TARGET_OS_IPHONE
  893. // Disable idle timer if player is playing media
  894. // Exclusion can be made for audio only media
  895. [UIApplication sharedApplication].idleTimerDisabled = [self isPlaying];
  896. #endif
  897. [self didChangeValueForKey:@"state"];
  898. }
  899. - (void)mediaPlayerMediaChanged:(VLCMedia *)newMedia
  900. {
  901. [self willChangeValueForKey:@"media"];
  902. if (media != newMedia)
  903. {
  904. [media release];
  905. media = [newMedia retain];
  906. }
  907. [self didChangeValueForKey:@"media"];
  908. }
  909. @end