iOS AVPlayer封装的播放器

.h文件

#import

#import

typedefNS_ENUM(NSInteger, XCMVPlayerStatus) {

    XCMVPlayerStatusReadyToPlay =0,// 准备好播放

    XCMVPlayerStatusLoadingVideo,    // 加载视频

    XCMVPlayerStatusPlayEnd,        // 播放结束

    XCMVPlayerStatusCacheData,      // 缓冲视频

    XCMVPlayerStatusCacheEnd,        // 缓冲结束

    XCMVPlayerStatusPlayStop,        // 播放中断 (多是没网)

    XCMVPlayerStatusItemFailed,      // 视频资源问题

    XCMVPlayerStatusEnterBack,      // 进入后台

    XCMVPlayerStatusBecomeActive,    // 从后台返回

};

@protocolXCMusicManagerDelegate

@optional

// 数据刷新

- (void)refreshDataWith:(NSTimeInterval)totalTime CurrentTime:(NSTimeInterval)currentTime LoadRange:(NSTimeInterval)loadTime Progress:(CGFloat)progress;

// 状态/错误 提示

- (void)promptPlayerStatusOrErrorWith:(XCMVPlayerStatus)status;

@end

@interfaceXCMusicManager :NSObject

/** 播放器 */

@property (nonatomic, strong) AVPlayer *player;

/** 视频资源 */

@property (nonatomic, strong) AVPlayerItem *currentItem;

// 音频/视频总长度

@property (nonatomic, assign) NSTimeInterval totalTime;

// 缓存数据

@property (nonatomic, assign) NSTimeInterval loadRange;

+ (instancetype)manager;

- (void)setPlayerWith:(NSURL*)url;

/** 播放 */

- (void)play;

/** 暂停 */

- (void)pause;

/** 正在播放 */

- (BOOL)isPlay;

/** 拖动音频/视频进度 */

- (void)seekPlayerTimeTo:(NSTimeInterval)time;

//代理

@property(nonatomic,weak)id XCMusicManagerDelegate;

/** 快进 */

- (void)fastForward;

/** 快退 */

- (void)fastBack;

@end


.m文件

#import "XCMusicManager.h"

@interface XCMusicManager()

/** 播放器观察者 */

@property (nonatomic ,strong)  id timeObser;

// 是否正在拖动

@property (nonatomic ,assign) BOOL isSeeking;

// 是否能正常播放(缓冲)

@property (nonatomic, assign) BOOL isCanPlay;

// 是否需要缓冲

@property (nonatomic, assign) BOOL needBuffer;

@end

@implementation XCMusicManager

+ (instancetype)manager {


    staticXCMusicManager* player;

    staticdispatch_once_tonceToken;

    dispatch_once(&onceToken, ^{

        player = [[XCMusicManageralloc]init];

    });

    returnplayer;

}

#pragma mark - 销毁 release

- (void)dealloc

{

    NSLog(@"--- %@ --- 销毁了",[self class]);

    [self removeNotification];

    [self removePlayerObserver];

    [self removeObserverWithPlayItem:self.player.currentItem];

}

#pragma mark - 属性和方法

- (NSTimeInterval)totalTime

{

    return CMTimeGetSeconds(self.player.currentItem.duration);

}

- (void)setPlayerWith:(NSURL*)url{

    //当前播放

    self.currentItem= [selfgetPlayerItem:url];

    //创建播放器

    _player = [AVPlayer playerWithPlayerItem:self.currentItem];

    //添加播放器监察者

    [self addPlayerObserver];

    //当前曲目添加监察者

    [self addObserverWithPlayItem:self.currentItem];

    //为播放器添加通知

    [self addNotificatonForPlayer];

}

#pragma mark - 创建播放器

/**

 获取播放item

 @param videoURL 视频网址

 @return AVPlayerItem

 */

- (AVPlayerItem*)getPlayerItem:(NSURL*)videoURL

{

    // 转utf8 防止中文报错

//        videoPath = [videoPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

//        videoPath = [videoPath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

    //网络音乐 AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];

//    NSString *path =[ [NSBundle mainBundle]  pathForResource:@"avengers" ofType:@"mp3"];

//    NSURL  *url = [NSURL  fileURLWithPath:path];

//    NSLog(@"sss-%@-%@",path,url);

    AVPlayerItem*item = [AVPlayerItemplayerItemWithURL:videoURL];

    returnitem;

}

#pragma mark - 添加 监控

/** 给player 添加 time observer */

- (void)addPlayerObserver

{

    __weak typeof(self)weakSelf = self;

    _timeObser = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {

        AVPlayerItem*playerItem = weakSelf.player.currentItem;


        floatcurrent =CMTimeGetSeconds(time);

        floattotal =CMTimeGetSeconds([playerItemduration]);

        if(weakSelf.isSeeking) {

            return;

        }

        if(weakSelf.XCMusicManagerDelegate&& [weakSelf.XCMusicManagerDelegaterespondsToSelector:@selector(refreshDataWith:CurrentTime:LoadRange:Progress:)]) {

            [weakSelf.XCMusicManagerDelegaterefreshDataWith:totalCurrentTime:currentLoadRange:weakSelf.loadRangeProgress:current/total];

        }

        //        NSLog(@"当前播放进度 %.2f/%.2f.",current,total);


    }];

}

/** 移除 time observer */

- (void)removePlayerObserver

{

    [_player removeTimeObserver:_timeObser];

}

#pragma mark - 给当前播放的item 添加观察者

/** 给当前播放的item 添加观察者


 需要监听的字段和状态

 status :  AVPlayerItemStatusUnknown,AVPlayerItemStatusReadyToPlay,AVPlayerItemStatusFailed

 loadedTimeRanges  :  缓冲进度

 playbackBufferEmpty : seekToTime后,缓冲数据为空,而且有效时间内数据无法补充,播放失败

 playbackLikelyToKeepUp : seekToTime后,可以正常播放,相当于readyToPlay,一般拖动滑竿菊花转,到了这个这个状态菊花隐藏


 */

- (void)addObserverWithPlayItem:(AVPlayerItem*)item

{

    [itemaddObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

    [itemaddObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

    [itemaddObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];

    [itemaddObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];

}

/** 移除 item 的 observer */

- (void)removeObserverWithPlayItem:(AVPlayerItem*)item

{

    [itemremoveObserver:self forKeyPath:@"status"];

    [itemremoveObserver:self forKeyPath:@"loadedTimeRanges"];

    [itemremoveObserver:self forKeyPath:@"playbackBufferEmpty"];

    [itemremoveObserver:self forKeyPath:@"playbackLikelyToKeepUp"];

}

/** 数据处理 获取到观察到的数据 并进行处理 */

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context

{

    AVPlayerItem*item = object;

    if([keyPathisEqualToString:@"status"]) {// 播放状态

        [self handleStatusWithPlayerItem:item];

    }elseif([keyPathisEqualToString:@"loadedTimeRanges"]) {// 缓冲进度

        [self handleLoadedTimeRangesWithPlayerItem:item];

    }elseif([keyPathisEqualToString:@"playbackBufferEmpty"]) {// 跳转后没数据

        // 转菊花

        if(self.isCanPlay) {

            NSLog(@"跳转后没数据");

            self.needBuffer=YES;

            [self useDelegateWith:XCMVPlayerStatusCacheData];

        }

    }else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {// 跳转后有数据

        // 隐藏菊花

        if (self.isCanPlay && self.needBuffer) {


            NSLog(@"跳转后有数据");


            self.needBuffer=NO;


            [self useDelegateWith:XCMVPlayerStatusCacheEnd];

        }


    }

}

/**

 处理 AVPlayerItem 播放状态

 AVPlayerItemStatusUnknown          状态未知

 AVPlayerItemStatusReadyToPlay      准备好播放

 AVPlayerItemStatusFailed            播放出错

 */

- (void)handleStatusWithPlayerItem:(AVPlayerItem*)item

{

    AVPlayerItemStatus status = item.status;

    switch(status) {

        case AVPlayerItemStatusReadyToPlay:  // 准备好播放


            NSLog(@"AVPlayerItemStatusReadyToPlay");

            self.isCanPlay=YES;

            [self useDelegateWith:XCMVPlayerStatusReadyToPlay];


            break;

        case AVPlayerItemStatusFailed:        // 播放出错


            NSLog(@"AVPlayerItemStatusFailed");

            [self useDelegateWith:XCMVPlayerStatusItemFailed];


            break;

        case AVPlayerItemStatusUnknown:      // 状态未知


            NSLog(@"AVPlayerItemStatusUnknown");


            break;


        default:

            break;

    }


}

/** 处理缓冲进度 */

- (void)handleLoadedTimeRangesWithPlayerItem:(AVPlayerItem*)item

{

    NSArray*loadArray = item.loadedTimeRanges;


    CMTimeRangerange = [[loadArrayfirstObject]CMTimeRangeValue];


    floatstart =CMTimeGetSeconds(range.start);


    floatduration =CMTimeGetSeconds(range.duration);


    NSTimeIntervaltotalTime = start + duration;// 缓存总长度


    _loadRange= totalTime;

    //    NSLog(@"缓冲进度 -- %.2f",totalTime);

}

/**

 添加关键通知

 AVPlayerItemDidPlayToEndTimeNotification    视频播放结束通知

 AVPlayerItemTimeJumpedNotification          视频进行跳转通知

 AVPlayerItemPlaybackStalledNotification      视频异常中断通知

 UIApplicationDidEnterBackgroundNotification  进入后台

 UIApplicationDidBecomeActiveNotification    返回前台

 */

- (void)addNotificatonForPlayer

{

    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [centeraddObserver:self selector:@selector(videoPlayEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

    //    [center addObserver:self selector:@selector(videoPlayToJump:) name:AVPlayerItemTimeJumpedNotification object:nil];//没意义

    [centeraddObserver:self selector:@selector(videoPlayError:) name:AVPlayerItemPlaybackStalledNotification object:nil];

    if(@available(iOS8.2, *)) {

        [centeraddObserver:selfselector:@selector(videoPlayEnterBack:)name:NSExtensionHostDidEnterBackgroundNotificationobject:nil];

    }else{

        // Fallback on earlier versions

    }

    if(@available(iOS8.2, *)) {

        [centeraddObserver:selfselector:@selector(videoPlayBecomeActive:)name:NSExtensionHostDidBecomeActiveNotificationobject:nil];

    }else{

        // Fallback on earlier versions

    }

}

/** 移除 通知 */

- (void)removeNotification

{

    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [centerremoveObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

    //    [center removeObserver:self name:AVPlayerItemTimeJumpedNotification object:nil];

    [centerremoveObserver:self name:AVPlayerItemPlaybackStalledNotification object:nil];

    if(@available(iOS8.2, *)) {

        [centerremoveObserver:self name:NSExtensionHostDidEnterBackgroundNotification object:nil];

    }else{

        // Fallback on earlier versions

    }

    if(@available(iOS8.2, *)) {

        [centerremoveObserver:self name:NSExtensionHostDidBecomeActiveNotification object:nil];

    }else{

        // Fallback on earlier versions

    }

    [centerremoveObserver:self];

}

/** 视频播放结束 */

- (void)videoPlayEnd:(NSNotification*)notic

{

    NSLog(@"视频播放结束");

    [self useDelegateWith:XCMVPlayerStatusPlayEnd];

    [self.player seekToTime:kCMTimeZero];

}

/** 视频异常中断 */

- (void)videoPlayError:(NSNotification*)notic

{

    NSLog(@"视频异常中断");

    [self useDelegateWith:XCMVPlayerStatusPlayStop];

}

/** 进入后台 */

- (void)videoPlayEnterBack:(NSNotification*)notic

{

    NSLog(@"进入后台");

    [self useDelegateWith:XCMVPlayerStatusEnterBack];

}

/** 返回前台 */

- (void)videoPlayBecomeActive:(NSNotification*)notic

{

    NSLog(@"返回前台");

    [self useDelegateWith:XCMVPlayerStatusBecomeActive];

}

/**

 播放状态代理调用


 @param status 播放状态

 */

- (void)useDelegateWith:(XCMVPlayerStatus)status

{

    if(self.isCanPlay==NO) {

        return;

    }

    if(self.XCMusicManagerDelegate&& [self.XCMusicManagerDelegaterespondsToSelector:@selector(promptPlayerStatusOrErrorWith:)]) {

        [self.XCMusicManagerDelegate promptPlayerStatusOrErrorWith:status];

    }

}

/** 播放 */

- (void)play

{

    NSLog(@"播放");

    [self.playerplay];

}

/** 暂停 */

- (void)pause

{

    [self.playerpause];

}

/** 拖动视频进度 */

- (void)seekPlayerTimeTo:(NSTimeInterval)time

{

    [selfpause];

    [self startToSeek];

    __weak typeof(self)weakSelf = self;

    [self.player seekToTime:CMTimeMake(time, 1.0) completionHandler:^(BOOL finished) {

        [weakSelfendSeek];

        [weakSelfplay];

    }];

}

/** 跳动中不监听 */

- (void)startToSeek

{

    self.isSeeking = YES;

}

- (void)endSeek

{

    self.isSeeking = NO;

}

/** 快进15s */

- (void)fastForward{

    [selfpause];

    [self startToSeek];

    __weak typeof(self)weakSelf = self;

    [self.player seekToTime:CMTimeMakeWithSeconds(self.currentItem.currentTime.value/self.currentItem.currentTime.timescale+15, self.currentItem.currentTime.timescale) completionHandler:^(BOOL finished) {

        [weakSelfendSeek];

        [weakSelfplay];

    }];

}

/** 快退15s */

- (void)fastBack{

    [selfpause];

    [self startToSeek];

    __weak typeof(self)weakSelf = self;

    [self.player seekToTime:CMTimeMakeWithSeconds(self.currentItem.currentTime.value/self.currentItem.currentTime.timescale-15, self.currentItem.currentTime.timescale) completionHandler:^(BOOL finished) {

        [weakSelfendSeek];

        [weakSelfplay];

    }];

}

/** 正在播放 */

- (BOOL)isPlay{

    return  _player.rate==1?YES:NO;

}




使用

 NSString *path =[ [NSBundle mainBundle]  pathForResource:@"avengers" ofType:@"mp3"];

    NSURL  *url = [NSURL  fileURLWithPath:path];

    [musicManager setPlayerWith:url];

    musicManager.XCMusicManagerDelegate = self;

  [musicManager play];

你可能感兴趣的:(iOS AVPlayer封装的播放器)