ZFIJKPlayerManager.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. //
  2. // ZFIJKPlayerManager.m
  3. // ZFPlayer
  4. //
  5. // Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. #import "ZFIJKPlayerManager.h"
  25. #if __has_include(<ZFPlayer/ZFPlayer.h>)
  26. #import <ZFPlayer/ZFPlayer.h>
  27. #import <ZFPlayer/ZFPlayerConst.h>
  28. #else
  29. #import "ZFPlayer.h"
  30. #import "ZFPlayerConst.h"
  31. #endif
  32. #if __has_include(<IJKMediaFramework/IJKMediaFramework.h>)
  33. @interface ZFIJKPlayerManager ()
  34. @property (nonatomic, strong) IJKFFMoviePlayerController *player;
  35. @property (nonatomic, strong) IJKFFOptions *options;
  36. @property (nonatomic, assign) CGFloat lastVolume;
  37. @property (nonatomic, strong) NSTimer *timer;
  38. @property (nonatomic, assign) BOOL isReadyToPlay;
  39. @end
  40. @implementation ZFIJKPlayerManager
  41. @synthesize view = _view;
  42. @synthesize currentTime = _currentTime;
  43. @synthesize totalTime = _totalTime;
  44. @synthesize playerPlayTimeChanged = _playerPlayTimeChanged;
  45. @synthesize playerBufferTimeChanged = _playerBufferTimeChanged;
  46. @synthesize playerDidToEnd = _playerDidToEnd;
  47. @synthesize bufferTime = _bufferTime;
  48. @synthesize playState = _playState;
  49. @synthesize loadState = _loadState;
  50. @synthesize assetURL = _assetURL;
  51. @synthesize playerPrepareToPlay = _playerPrepareToPlay;
  52. @synthesize playerReadyToPlay = _playerReadyToPlay;
  53. @synthesize playerPlayStateChanged = _playerPlayStateChanged;
  54. @synthesize playerLoadStateChanged = _playerLoadStateChanged;
  55. @synthesize seekTime = _seekTime;
  56. @synthesize muted = _muted;
  57. @synthesize volume = _volume;
  58. @synthesize presentationSize = _presentationSize;
  59. @synthesize isPlaying = _isPlaying;
  60. @synthesize rate = _rate;
  61. @synthesize isPreparedToPlay = _isPreparedToPlay;
  62. @synthesize shouldAutoPlay = _shouldAutoPlay;
  63. @synthesize scalingMode = _scalingMode;
  64. @synthesize playerPlayFailed = _playerPlayFailed;
  65. @synthesize presentationSizeChanged = _presentationSizeChanged;
  66. - (void)dealloc {
  67. [self stop];
  68. }
  69. - (instancetype)init {
  70. self = [super init];
  71. if (self) {
  72. _scalingMode = ZFPlayerScalingModeAspectFit;
  73. _shouldAutoPlay = YES;
  74. }
  75. return self;
  76. }
  77. - (void)prepareToPlay {
  78. if (!_assetURL) return;
  79. _isPreparedToPlay = YES;
  80. [self initializePlayer];
  81. if (self.shouldAutoPlay) {
  82. [self play];
  83. }
  84. self.loadState = ZFPlayerLoadStatePrepare;
  85. if (self.playerPrepareToPlay) self.playerPrepareToPlay(self, self.assetURL);
  86. }
  87. - (void)reloadPlayer {
  88. [self prepareToPlay];
  89. }
  90. - (void)play {
  91. if (!_isPreparedToPlay) {
  92. [self prepareToPlay];
  93. } else {
  94. [self.player play];
  95. if (self.timer) [self.timer setFireDate:[NSDate date]];
  96. self.player.playbackRate = self.rate;
  97. _isPlaying = YES;
  98. self.playState = ZFPlayerPlayStatePlaying;
  99. }
  100. }
  101. - (void)pause {
  102. if (self.timer) [self.timer setFireDate:[NSDate distantFuture]];
  103. [self.player pause];
  104. _isPlaying = NO;
  105. self.playState = ZFPlayerPlayStatePaused;
  106. }
  107. - (void)stop {
  108. [self removeMovieNotificationObservers];
  109. [self.player shutdown];
  110. [self.player.view removeFromSuperview];
  111. self.player = nil;
  112. _assetURL = nil;
  113. [self.timer invalidate];
  114. self.presentationSize = CGSizeZero;
  115. self.timer = nil;
  116. _isPlaying = NO;
  117. _isPreparedToPlay = NO;
  118. self->_currentTime = 0;
  119. self->_totalTime = 0;
  120. self->_bufferTime = 0;
  121. self.isReadyToPlay = NO;
  122. self.playState = ZFPlayerPlayStatePlayStopped;
  123. }
  124. - (void)replay {
  125. @zf_weakify(self)
  126. [self seekToTime:0 completionHandler:^(BOOL finished) {
  127. @zf_strongify(self)
  128. if (finished) {
  129. [self play];
  130. }
  131. }];
  132. }
  133. - (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
  134. if (self.player.duration > 0) {
  135. self.player.currentPlaybackTime = time;
  136. if (completionHandler) completionHandler(YES);
  137. } else {
  138. self.seekTime = time;
  139. }
  140. }
  141. - (UIImage *)thumbnailImageAtCurrentTime {
  142. return [self.player thumbnailImageAtCurrentTime];
  143. }
  144. #pragma mark - private method
  145. - (void)initializePlayer {
  146. // IJKFFMoviePlayerController 初始化后,必须手动进行释放,否则会依然存在内存中对资源进行播放。
  147. if (self.player) {
  148. [self removeMovieNotificationObservers];
  149. [self.player shutdown];
  150. [self.player.view removeFromSuperview];
  151. self.player = nil;
  152. }
  153. self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.assetURL withOptions:self.options];
  154. self.player.shouldAutoplay = self.shouldAutoPlay;
  155. [self.player prepareToPlay];
  156. self.view.playerView = self.player.view;
  157. self.scalingMode = self->_scalingMode;
  158. [self addPlayerNotificationObservers];
  159. }
  160. - (void)addPlayerNotificationObservers {
  161. /// 准备播放
  162. [[NSNotificationCenter defaultCenter] addObserver:self
  163. selector:@selector(loadStateDidChange:)
  164. name:IJKMPMoviePlayerLoadStateDidChangeNotification
  165. object:_player];
  166. /// 播放完成或者用户退出
  167. [[NSNotificationCenter defaultCenter] addObserver:self
  168. selector:@selector(moviePlayBackFinish:)
  169. name:IJKMPMoviePlayerPlaybackDidFinishNotification
  170. object:_player];
  171. /// 准备开始播放了
  172. [[NSNotificationCenter defaultCenter] addObserver:self
  173. selector:@selector(mediaIsPreparedToPlayDidChange:)
  174. name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
  175. object:_player];
  176. /// 播放状态改变了
  177. [[NSNotificationCenter defaultCenter] addObserver:self
  178. selector:@selector(moviePlayBackStateDidChange:)
  179. name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
  180. object:_player];
  181. /// 视频的尺寸变化了
  182. [[NSNotificationCenter defaultCenter] addObserver:self
  183. selector:@selector(sizeAvailableChange:)
  184. name:IJKMPMovieNaturalSizeAvailableNotification
  185. object:self.player];
  186. }
  187. - (void)removeMovieNotificationObservers {
  188. [[NSNotificationCenter defaultCenter] removeObserver:self
  189. name:IJKMPMoviePlayerLoadStateDidChangeNotification
  190. object:_player];
  191. [[NSNotificationCenter defaultCenter] removeObserver:self
  192. name:IJKMPMoviePlayerPlaybackDidFinishNotification
  193. object:_player];
  194. [[NSNotificationCenter defaultCenter] removeObserver:self
  195. name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
  196. object:_player];
  197. [[NSNotificationCenter defaultCenter] removeObserver:self
  198. name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
  199. object:_player];
  200. [[NSNotificationCenter defaultCenter] removeObserver:self
  201. name:IJKMPMovieNaturalSizeAvailableNotification
  202. object:_player];
  203. }
  204. - (void)timerUpdate {
  205. if (self.player.currentPlaybackTime > 0 && !self.isReadyToPlay) {
  206. self.isReadyToPlay = YES;
  207. self.loadState = ZFPlayerLoadStatePlaythroughOK;
  208. }
  209. self->_currentTime = self.player.currentPlaybackTime > 0 ? self.player.currentPlaybackTime : 0;
  210. self->_totalTime = self.player.duration;
  211. self->_bufferTime = self.player.playableDuration;
  212. if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
  213. if (self.playerBufferTimeChanged) self.playerBufferTimeChanged(self, self.bufferTime);
  214. }
  215. #pragma - notification
  216. /// 播放完成
  217. - (void)moviePlayBackFinish:(NSNotification *)notification {
  218. int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
  219. switch (reason) {
  220. case IJKMPMovieFinishReasonPlaybackEnded: {
  221. ZFPlayerLog(@"playbackStateDidChange: 播放完毕: %d\n", reason);
  222. self.playState = ZFPlayerPlayStatePlayStopped;
  223. if (self.playerDidToEnd) self.playerDidToEnd(self);
  224. }
  225. break;
  226. case IJKMPMovieFinishReasonUserExited: {
  227. ZFPlayerLog(@"playbackStateDidChange: 用户退出播放: %d\n", reason);
  228. }
  229. break;
  230. case IJKMPMovieFinishReasonPlaybackError: {
  231. ZFPlayerLog(@"playbackStateDidChange: 播放出现错误: %d\n", reason);
  232. self.playState = ZFPlayerPlayStatePlayFailed;
  233. if (self.playerPlayFailed) self.playerPlayFailed(self, @(reason));
  234. }
  235. break;
  236. default:
  237. ZFPlayerLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
  238. break;
  239. }
  240. }
  241. // 准备开始播放了
  242. - (void)mediaIsPreparedToPlayDidChange:(NSNotification *)notification {
  243. ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
  244. // 视频开始播放的时候开启计时器
  245. if (!self.timer) {
  246. self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeRefreshInterval > 0 ? self.timeRefreshInterval : 0.1 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
  247. [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
  248. }
  249. if (self.isPlaying) {
  250. [self play];
  251. self.muted = self.muted;
  252. if (self.seekTime > 0) {
  253. [self seekToTime:self.seekTime completionHandler:nil];
  254. self.seekTime = 0; // 滞空, 防止下次播放出错
  255. [self play];
  256. }
  257. }
  258. if (self.playerReadyToPlay) self.playerReadyToPlay(self, self.assetURL);
  259. }
  260. #pragma mark - 加载状态改变
  261. /**
  262. 视频加载状态改变了
  263. IJKMPMovieLoadStateUnknown == 0
  264. IJKMPMovieLoadStatePlayable == 1
  265. IJKMPMovieLoadStatePlaythroughOK == 2
  266. IJKMPMovieLoadStateStalled == 4
  267. */
  268. - (void)loadStateDidChange:(NSNotification*)notification {
  269. IJKMPMovieLoadState loadState = self.player.loadState;
  270. if ((loadState & IJKMPMovieLoadStatePlayable)) {
  271. ZFPlayerLog(@"加载状态变成了缓存数据足够开始播放,但是视频并没有缓存完全");
  272. if (self.player.currentPlaybackTime > 0) {
  273. self.loadState = ZFPlayerLoadStatePlayable;
  274. }
  275. } else if ((loadState & IJKMPMovieLoadStatePlaythroughOK)) {
  276. // 加载完成,即将播放,停止加载的动画,并将其移除
  277. ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
  278. } else if ((loadState & IJKMPMovieLoadStateStalled)) {
  279. // 可能由于网速不好等因素导致了暂停,重新添加加载的动画
  280. ZFPlayerLog(@"网速不好等因素导致了暂停");
  281. self.loadState = ZFPlayerLoadStateStalled;
  282. } else {
  283. ZFPlayerLog(@"加载状态变成了未知状态");
  284. self.loadState = ZFPlayerLoadStateUnknown;
  285. }
  286. }
  287. // 播放状态改变
  288. - (void)moviePlayBackStateDidChange:(NSNotification *)notification {
  289. switch (self.player.playbackState) {
  290. case IJKMPMoviePlaybackStateStopped: {
  291. ZFPlayerLog(@"播放器的播放状态变了,现在是停止状态 %d: stoped", (int)_player.playbackState);
  292. // 这里的回调也会来多次(一次播放完成, 会回调三次), 所以, 这里不设置
  293. self.playState = ZFPlayerPlayStatePlayStopped;
  294. }
  295. break;
  296. case IJKMPMoviePlaybackStatePlaying: {
  297. ZFPlayerLog(@"播放器的播放状态变了,现在是播放状态 %d: playing", (int)_player.playbackState);
  298. }
  299. break;
  300. case IJKMPMoviePlaybackStatePaused: {
  301. ZFPlayerLog(@"播放器的播放状态变了,现在是暂停状态 %d: paused", (int)_player.playbackState);
  302. }
  303. break;
  304. case IJKMPMoviePlaybackStateInterrupted: {
  305. ZFPlayerLog(@"播放器的播放状态变了,现在是中断状态 %d: interrupted", (int)_player.playbackState);
  306. }
  307. break;
  308. case IJKMPMoviePlaybackStateSeekingForward: {
  309. ZFPlayerLog(@"播放器的播放状态变了,现在是向前拖动状态:%d forward",(int)self.player.playbackState);
  310. }
  311. break;
  312. case IJKMPMoviePlaybackStateSeekingBackward: {
  313. ZFPlayerLog(@"放器的播放状态变了,现在是向后拖动状态 %d: backward", (int)_player.playbackState);
  314. }
  315. break;
  316. default: {
  317. ZFPlayerLog(@"播放器的播放状态变了,现在是未知状态 %d: unknown", (int)_player.playbackState);
  318. }
  319. break;
  320. }
  321. }
  322. /// 视频的尺寸变化了
  323. - (void)sizeAvailableChange:(NSNotification *)notify {
  324. self.presentationSize = self.player.naturalSize;
  325. self.view.presentationSize = self.presentationSize;
  326. if (self.presentationSizeChanged) {
  327. self.presentationSizeChanged(self, self->_presentationSize);
  328. }
  329. }
  330. #pragma mark - getter
  331. - (ZFPlayerView *)view {
  332. if (!_view) {
  333. _view = [[ZFPlayerView alloc] init];
  334. }
  335. return _view;
  336. }
  337. - (float)rate {
  338. return _rate == 0 ?1:_rate;
  339. }
  340. - (IJKFFOptions *)options {
  341. if (!_options) {
  342. _options = [IJKFFOptions optionsByDefault];
  343. /// 精准seek
  344. [_options setPlayerOptionIntValue:1 forKey:@"enable-accurate-seek"];
  345. /// 解决http播放不了
  346. [_options setOptionIntValue:1 forKey:@"dns_cache_clear" ofCategory:kIJKFFOptionCategoryFormat];
  347. }
  348. return _options;
  349. }
  350. #pragma mark - setter
  351. - (void)setPlayState:(ZFPlayerPlaybackState)playState {
  352. _playState = playState;
  353. if (self.playerPlayStateChanged) self.playerPlayStateChanged(self, playState);
  354. }
  355. - (void)setLoadState:(ZFPlayerLoadState)loadState {
  356. _loadState = loadState;
  357. if (self.playerLoadStateChanged) self.playerLoadStateChanged(self, loadState);
  358. }
  359. - (void)setAssetURL:(NSURL *)assetURL {
  360. if (self.player) [self stop];
  361. _assetURL = assetURL;
  362. [self prepareToPlay];
  363. }
  364. - (void)setRate:(float)rate {
  365. _rate = rate;
  366. if (self.player && fabsf(_player.playbackRate) > 0.00001f) {
  367. self.player.playbackRate = rate;
  368. }
  369. }
  370. - (void)setMuted:(BOOL)muted {
  371. _muted = muted;
  372. if (muted) {
  373. self.lastVolume = self.player.playbackVolume;
  374. self.player.playbackVolume = 0;
  375. } else {
  376. /// Fix first called the lastVolume is 0.
  377. if (self.lastVolume == 0) self.lastVolume = self.player.playbackVolume;
  378. self.player.playbackVolume = self.lastVolume;
  379. }
  380. }
  381. - (void)setScalingMode:(ZFPlayerScalingMode)scalingMode {
  382. _scalingMode = scalingMode;
  383. self.view.scalingMode = scalingMode;
  384. switch (scalingMode) {
  385. case ZFPlayerScalingModeNone:
  386. self.player.scalingMode = IJKMPMovieScalingModeNone;
  387. break;
  388. case ZFPlayerScalingModeAspectFit:
  389. self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
  390. break;
  391. case ZFPlayerScalingModeAspectFill:
  392. self.player.scalingMode = IJKMPMovieScalingModeAspectFill;
  393. break;
  394. case ZFPlayerScalingModeFill:
  395. self.player.scalingMode = IJKMPMovieScalingModeFill;
  396. break;
  397. default:
  398. break;
  399. }
  400. }
  401. - (void)setVolume:(float)volume {
  402. _volume = MIN(MAX(0, volume), 1);
  403. self.player.playbackVolume = _volume;
  404. }
  405. @end
  406. #endif