123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- //
- // ZFIJKPlayerManager.m
- // ZFPlayer
- //
- // Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- #import "ZFIJKPlayerManager.h"
- #if __has_include(<ZFPlayer/ZFPlayer.h>)
- #import <ZFPlayer/ZFPlayer.h>
- #import <ZFPlayer/ZFPlayerConst.h>
- #else
- #import "ZFPlayer.h"
- #import "ZFPlayerConst.h"
- #endif
- #if __has_include(<IJKMediaFramework/IJKMediaFramework.h>)
- @interface ZFIJKPlayerManager ()
- @property (nonatomic, strong) IJKFFMoviePlayerController *player;
- @property (nonatomic, strong) IJKFFOptions *options;
- @property (nonatomic, assign) CGFloat lastVolume;
- @property (nonatomic, strong) NSTimer *timer;
- @property (nonatomic, assign) BOOL isReadyToPlay;
- @end
- @implementation ZFIJKPlayerManager
- @synthesize view = _view;
- @synthesize currentTime = _currentTime;
- @synthesize totalTime = _totalTime;
- @synthesize playerPlayTimeChanged = _playerPlayTimeChanged;
- @synthesize playerBufferTimeChanged = _playerBufferTimeChanged;
- @synthesize playerDidToEnd = _playerDidToEnd;
- @synthesize bufferTime = _bufferTime;
- @synthesize playState = _playState;
- @synthesize loadState = _loadState;
- @synthesize assetURL = _assetURL;
- @synthesize playerPrepareToPlay = _playerPrepareToPlay;
- @synthesize playerReadyToPlay = _playerReadyToPlay;
- @synthesize playerPlayStateChanged = _playerPlayStateChanged;
- @synthesize playerLoadStateChanged = _playerLoadStateChanged;
- @synthesize seekTime = _seekTime;
- @synthesize muted = _muted;
- @synthesize volume = _volume;
- @synthesize presentationSize = _presentationSize;
- @synthesize isPlaying = _isPlaying;
- @synthesize rate = _rate;
- @synthesize isPreparedToPlay = _isPreparedToPlay;
- @synthesize shouldAutoPlay = _shouldAutoPlay;
- @synthesize scalingMode = _scalingMode;
- @synthesize playerPlayFailed = _playerPlayFailed;
- @synthesize presentationSizeChanged = _presentationSizeChanged;
- - (void)dealloc {
- [self stop];
- }
- - (instancetype)init {
- self = [super init];
- if (self) {
- _scalingMode = ZFPlayerScalingModeAspectFit;
- _shouldAutoPlay = YES;
- }
- return self;
- }
- - (void)prepareToPlay {
- if (!_assetURL) return;
- _isPreparedToPlay = YES;
- [self initializePlayer];
- if (self.shouldAutoPlay) {
- [self play];
- }
- self.loadState = ZFPlayerLoadStatePrepare;
- if (self.playerPrepareToPlay) self.playerPrepareToPlay(self, self.assetURL);
- }
- - (void)reloadPlayer {
- [self prepareToPlay];
- }
- - (void)play {
- if (!_isPreparedToPlay) {
- [self prepareToPlay];
- } else {
- [self.player play];
- if (self.timer) [self.timer setFireDate:[NSDate date]];
- self.player.playbackRate = self.rate;
- _isPlaying = YES;
- self.playState = ZFPlayerPlayStatePlaying;
- }
- }
- - (void)pause {
- if (self.timer) [self.timer setFireDate:[NSDate distantFuture]];
- [self.player pause];
- _isPlaying = NO;
- self.playState = ZFPlayerPlayStatePaused;
- }
- - (void)stop {
- [self removeMovieNotificationObservers];
- [self.player shutdown];
- [self.player.view removeFromSuperview];
- self.player = nil;
- _assetURL = nil;
- [self.timer invalidate];
- self.presentationSize = CGSizeZero;
- self.timer = nil;
- _isPlaying = NO;
- _isPreparedToPlay = NO;
- self->_currentTime = 0;
- self->_totalTime = 0;
- self->_bufferTime = 0;
- self.isReadyToPlay = NO;
- self.playState = ZFPlayerPlayStatePlayStopped;
- }
- - (void)replay {
- @zf_weakify(self)
- [self seekToTime:0 completionHandler:^(BOOL finished) {
- @zf_strongify(self)
- if (finished) {
- [self play];
- }
- }];
- }
- - (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
- if (self.player.duration > 0) {
- self.player.currentPlaybackTime = time;
- if (completionHandler) completionHandler(YES);
- } else {
- self.seekTime = time;
- }
- }
- - (UIImage *)thumbnailImageAtCurrentTime {
- return [self.player thumbnailImageAtCurrentTime];
- }
- #pragma mark - private method
- - (void)initializePlayer {
- // IJKFFMoviePlayerController 初始化后,必须手动进行释放,否则会依然存在内存中对资源进行播放。
- if (self.player) {
- [self removeMovieNotificationObservers];
- [self.player shutdown];
- [self.player.view removeFromSuperview];
- self.player = nil;
- }
- self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.assetURL withOptions:self.options];
- self.player.shouldAutoplay = self.shouldAutoPlay;
- [self.player prepareToPlay];
- self.view.playerView = self.player.view;
- self.scalingMode = self->_scalingMode;
- [self addPlayerNotificationObservers];
- }
- - (void)addPlayerNotificationObservers {
- /// 准备播放
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(loadStateDidChange:)
- name:IJKMPMoviePlayerLoadStateDidChangeNotification
- object:_player];
- /// 播放完成或者用户退出
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(moviePlayBackFinish:)
- name:IJKMPMoviePlayerPlaybackDidFinishNotification
- object:_player];
- /// 准备开始播放了
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(mediaIsPreparedToPlayDidChange:)
- name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
- object:_player];
- /// 播放状态改变了
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(moviePlayBackStateDidChange:)
- name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
- object:_player];
-
- /// 视频的尺寸变化了
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(sizeAvailableChange:)
- name:IJKMPMovieNaturalSizeAvailableNotification
- object:self.player];
- }
- - (void)removeMovieNotificationObservers {
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:IJKMPMoviePlayerLoadStateDidChangeNotification
- object:_player];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:IJKMPMoviePlayerPlaybackDidFinishNotification
- object:_player];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
- object:_player];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
- object:_player];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:IJKMPMovieNaturalSizeAvailableNotification
- object:_player];
- }
- - (void)timerUpdate {
- if (self.player.currentPlaybackTime > 0 && !self.isReadyToPlay) {
- self.isReadyToPlay = YES;
- self.loadState = ZFPlayerLoadStatePlaythroughOK;
- }
- self->_currentTime = self.player.currentPlaybackTime > 0 ? self.player.currentPlaybackTime : 0;
- self->_totalTime = self.player.duration;
- self->_bufferTime = self.player.playableDuration;
- if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
- if (self.playerBufferTimeChanged) self.playerBufferTimeChanged(self, self.bufferTime);
- }
- #pragma - notification
- /// 播放完成
- - (void)moviePlayBackFinish:(NSNotification *)notification {
- int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
- switch (reason) {
- case IJKMPMovieFinishReasonPlaybackEnded: {
- ZFPlayerLog(@"playbackStateDidChange: 播放完毕: %d\n", reason);
- self.playState = ZFPlayerPlayStatePlayStopped;
- if (self.playerDidToEnd) self.playerDidToEnd(self);
- }
- break;
-
- case IJKMPMovieFinishReasonUserExited: {
- ZFPlayerLog(@"playbackStateDidChange: 用户退出播放: %d\n", reason);
- }
- break;
-
- case IJKMPMovieFinishReasonPlaybackError: {
- ZFPlayerLog(@"playbackStateDidChange: 播放出现错误: %d\n", reason);
- self.playState = ZFPlayerPlayStatePlayFailed;
- if (self.playerPlayFailed) self.playerPlayFailed(self, @(reason));
- }
- break;
-
- default:
- ZFPlayerLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
- break;
- }
- }
- // 准备开始播放了
- - (void)mediaIsPreparedToPlayDidChange:(NSNotification *)notification {
- ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
- // 视频开始播放的时候开启计时器
- if (!self.timer) {
- self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeRefreshInterval > 0 ? self.timeRefreshInterval : 0.1 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
- [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
- }
-
- if (self.isPlaying) {
- [self play];
- self.muted = self.muted;
- if (self.seekTime > 0) {
- [self seekToTime:self.seekTime completionHandler:nil];
- self.seekTime = 0; // 滞空, 防止下次播放出错
- [self play];
- }
- }
- if (self.playerReadyToPlay) self.playerReadyToPlay(self, self.assetURL);
- }
- #pragma mark - 加载状态改变
- /**
- 视频加载状态改变了
- IJKMPMovieLoadStateUnknown == 0
- IJKMPMovieLoadStatePlayable == 1
- IJKMPMovieLoadStatePlaythroughOK == 2
- IJKMPMovieLoadStateStalled == 4
- */
- - (void)loadStateDidChange:(NSNotification*)notification {
- IJKMPMovieLoadState loadState = self.player.loadState;
- if ((loadState & IJKMPMovieLoadStatePlayable)) {
- ZFPlayerLog(@"加载状态变成了缓存数据足够开始播放,但是视频并没有缓存完全");
- if (self.player.currentPlaybackTime > 0) {
- self.loadState = ZFPlayerLoadStatePlayable;
- }
- } else if ((loadState & IJKMPMovieLoadStatePlaythroughOK)) {
- // 加载完成,即将播放,停止加载的动画,并将其移除
- ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
- } else if ((loadState & IJKMPMovieLoadStateStalled)) {
- // 可能由于网速不好等因素导致了暂停,重新添加加载的动画
- ZFPlayerLog(@"网速不好等因素导致了暂停");
- self.loadState = ZFPlayerLoadStateStalled;
- } else {
- ZFPlayerLog(@"加载状态变成了未知状态");
- self.loadState = ZFPlayerLoadStateUnknown;
- }
- }
- // 播放状态改变
- - (void)moviePlayBackStateDidChange:(NSNotification *)notification {
- switch (self.player.playbackState) {
- case IJKMPMoviePlaybackStateStopped: {
- ZFPlayerLog(@"播放器的播放状态变了,现在是停止状态 %d: stoped", (int)_player.playbackState);
- // 这里的回调也会来多次(一次播放完成, 会回调三次), 所以, 这里不设置
- self.playState = ZFPlayerPlayStatePlayStopped;
- }
- break;
-
- case IJKMPMoviePlaybackStatePlaying: {
- ZFPlayerLog(@"播放器的播放状态变了,现在是播放状态 %d: playing", (int)_player.playbackState);
- }
- break;
-
- case IJKMPMoviePlaybackStatePaused: {
- ZFPlayerLog(@"播放器的播放状态变了,现在是暂停状态 %d: paused", (int)_player.playbackState);
- }
- break;
-
- case IJKMPMoviePlaybackStateInterrupted: {
- ZFPlayerLog(@"播放器的播放状态变了,现在是中断状态 %d: interrupted", (int)_player.playbackState);
- }
- break;
-
- case IJKMPMoviePlaybackStateSeekingForward: {
- ZFPlayerLog(@"播放器的播放状态变了,现在是向前拖动状态:%d forward",(int)self.player.playbackState);
- }
- break;
- case IJKMPMoviePlaybackStateSeekingBackward: {
- ZFPlayerLog(@"放器的播放状态变了,现在是向后拖动状态 %d: backward", (int)_player.playbackState);
- }
- break;
-
- default: {
- ZFPlayerLog(@"播放器的播放状态变了,现在是未知状态 %d: unknown", (int)_player.playbackState);
- }
- break;
- }
- }
- /// 视频的尺寸变化了
- - (void)sizeAvailableChange:(NSNotification *)notify {
- self.presentationSize = self.player.naturalSize;
- self.view.presentationSize = self.presentationSize;
- if (self.presentationSizeChanged) {
- self.presentationSizeChanged(self, self->_presentationSize);
- }
- }
- #pragma mark - getter
- - (ZFPlayerView *)view {
- if (!_view) {
- _view = [[ZFPlayerView alloc] init];
- }
- return _view;
- }
- - (float)rate {
- return _rate == 0 ?1:_rate;
- }
- - (IJKFFOptions *)options {
- if (!_options) {
- _options = [IJKFFOptions optionsByDefault];
- /// 精准seek
- [_options setPlayerOptionIntValue:1 forKey:@"enable-accurate-seek"];
- /// 解决http播放不了
- [_options setOptionIntValue:1 forKey:@"dns_cache_clear" ofCategory:kIJKFFOptionCategoryFormat];
- }
- return _options;
- }
- #pragma mark - setter
- - (void)setPlayState:(ZFPlayerPlaybackState)playState {
- _playState = playState;
- if (self.playerPlayStateChanged) self.playerPlayStateChanged(self, playState);
- }
- - (void)setLoadState:(ZFPlayerLoadState)loadState {
- _loadState = loadState;
- if (self.playerLoadStateChanged) self.playerLoadStateChanged(self, loadState);
- }
- - (void)setAssetURL:(NSURL *)assetURL {
- if (self.player) [self stop];
- _assetURL = assetURL;
- [self prepareToPlay];
- }
- - (void)setRate:(float)rate {
- _rate = rate;
- if (self.player && fabsf(_player.playbackRate) > 0.00001f) {
- self.player.playbackRate = rate;
- }
- }
- - (void)setMuted:(BOOL)muted {
- _muted = muted;
- if (muted) {
- self.lastVolume = self.player.playbackVolume;
- self.player.playbackVolume = 0;
- } else {
- /// Fix first called the lastVolume is 0.
- if (self.lastVolume == 0) self.lastVolume = self.player.playbackVolume;
- self.player.playbackVolume = self.lastVolume;
- }
- }
- - (void)setScalingMode:(ZFPlayerScalingMode)scalingMode {
- _scalingMode = scalingMode;
- self.view.scalingMode = scalingMode;
- switch (scalingMode) {
- case ZFPlayerScalingModeNone:
- self.player.scalingMode = IJKMPMovieScalingModeNone;
- break;
- case ZFPlayerScalingModeAspectFit:
- self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
- break;
- case ZFPlayerScalingModeAspectFill:
- self.player.scalingMode = IJKMPMovieScalingModeAspectFill;
- break;
- case ZFPlayerScalingModeFill:
- self.player.scalingMode = IJKMPMovieScalingModeFill;
- break;
- default:
- break;
- }
- }
- - (void)setVolume:(float)volume {
- _volume = MIN(MAX(0, volume), 1);
- self.player.playbackVolume = _volume;
- }
- @end
- #endif
|