AVPlayer 视频播放器常规功能

//

//  MZPlayView.m

//  视频播放器常规功能

//

//  Created by yubo on 16/7/27.

//

#import "MZPlayView.h"

#import 

#import 

#import 

/**

*  Description

关于视频这一块的业务操作全部封装在这个里面。 对外就提供一个NSUrl属性。

*/

typedefNS_ENUM(NSInteger,PanDirection){

PanDirectionHorizontalMoved,//横向移动

PanDirectionVerticalMoved//纵向移动

};

@interfaceMZPlayView()

@property(nonatomic,strong)AVPlayer*player;

@property(nonatomic,strong)AVPlayerItem*playerItem;

@property(nonatomic,strong)AVPlayerLayer*playerLayer;

@property(weak,nonatomic) IBOutletUIButton*backBtn;

@property(weak,nonatomic) IBOutletUILabel*forwardLabel;

@property(weak,nonatomic) IBOutletUILabel*currentTimeLabel;

@property(weak,nonatomic) IBOutletUIProgressView*progressView;

@property(weak,nonatomic) IBOutletUILabel*totalTimeLabel;

@property(weak,nonatomic) IBOutletUIButton*fullScreanBtn;

@property(weak,nonatomic) IBOutletUISlider*sliderView;

@property(weak,nonatomic) IBOutletUIButton*startBtn;

@property(weak,nonatomic) IBOutletUIButton*lockBtn;

@property(nonatomic,assign)boolplayViewFlag;// 隐藏和显示标识

@property(nonatomic,strong)NSTimer*timer;

@property(nonatomic,assign)boollockFlag;// 锁标识

@property(nonatomic,assign) PanDirection panDirection;

@property(nonatomic, assign)BOOLisVolume;// 是否调节音量

@property(nonatomic,strong)UISlider*volumeViewSlider;

@property(nonatomic, assign) CGFloat sumTime;// 用来保存的总时长

@end

@implementationMZPlayView

- (void)awakeFromNib{

[superawakeFromNib];

[_sliderViewsetThumbImage:[UIImageimageNamed:@"slider"]forState:UIControlStateNormal];

[selfinsertSubview:_progressViewbelowSubview:_sliderView];

// 滑块左边的颜色

_sliderView.minimumTrackTintColor= [UIColororangeColor];

// 滑块右边的颜色

_sliderView.maximumTrackTintColor= [UIColorclearColor];

}

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

_playerItem = [AVPlayerItemplayerItemWithURL:url];

_player = [AVPlayerplayerWithPlayerItem:_playerItem];

_playerLayer = [AVPlayerLayerplayerLayerWithPlayer:_player];

[self.layerinsertSublayer:_playerLayeratIndex:0];

[_playerplay];

_forwardLabel.hidden=YES;

// 添加播完通知

[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(moviePlayDidEnd:)name:AVPlayerItemDidPlayToEndTimeNotificationobject:_player.currentItem];

// 添加手势

[selfcreateGesture];

//获取系统音量

[selfconfigureVolume];

// 添加事件

[selfsliderAddEvent];

// 通过定时器获取 时间,

_timer = [NSTimerscheduledTimerWithTimeInterval:1.0ftarget:selfselector:@selector(playerTimerAction)userInfo:nilrepeats:YES];

// 计算缓冲

[_playerItemaddObserver:selfforKeyPath:@"loadedTimeRanges"options:NSKeyValueObservingOptionNewcontext:nil];

[_playerItemaddObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:nil];

}

#pragma mark  滑动事件添加

- (void)sliderAddEvent{

// slider开始滑动事件

[_sliderViewaddTarget:selfaction:@selector(progressSliderTouchBegan:)forControlEvents:UIControlEventTouchDown];

// slider滑动中事件

[_sliderViewaddTarget:selfaction:@selector(progressSliderValueChanged:)forControlEvents:UIControlEventValueChanged];

// slider结束滑动事件

[_sliderViewaddTarget:selfaction:@selector(progressSliderTouchEnded:)forControlEvents:UIControlEventTouchUpInside];

}

// 开始滑动

- (void)progressSliderTouchBegan:(UISlider*)slider{

// 取消延迟

//    [NSObject cancelPreviousPerformRequestsWithTarget:self];

}

// 开始变化

- (void)progressSliderValueChanged:(UISlider*)slider{

// 拖动改变视频播放进度

if(_player.status== AVPlayerItemStatusReadyToPlay) {

// 总秒数

CGFloat total = (CGFloat)_playerItem.duration.value/ _playerItem.duration.timescale;

// 已经拖动到了现在的秒数了。

NSInteger dragedSeconds = floorf(total* slider.value);

//转换成CMTime才能给player来控制播放进度---这个类用来控制时间的。

CMTime dragedCMTime = CMTimeMake(dragedSeconds,1);

[_playerpause];

[_playerseekToTime:dragedCMTimecompletionHandler:^(BOOLfinished) {

[_playerplay];

}];

}

}

#pragma mark slider事件结束

- (void)progressSliderTouchEnded:(UISlider*)slider{

}

#pragma mark 重新布局 frame

- (void)layoutSubviews{

_playerLayer.frame=self.bounds;

};

#pragma mark 添加手势, 点击隐藏视频所有按钮

- (void)createGesture{

UITapGestureRecognizer*tap = [[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(playViewHanlder:)];

tap.numberOfTapsRequired=1;

[selfaddGestureRecognizer:tap];

}

#pragma mark 手势回调处理

- (void)playViewHanlder:(UITapGestureRecognizer*)recognizer{

if(!_lockFlag) {

if(recognizer.state== UIGestureRecognizerStateRecognized) {

if(!_playViewFlag) {

[selfhiddlePlayView];

}else{

[selfshowPlayView];

}

}

}

}

#pragma mark 隐藏组件

- (void)hiddlePlayView{

[UIViewanimateWithDuration:0.5animations:^{

_backBtn.alpha=0;

_currentTimeLabel.alpha=0;

_progressView.alpha=0;

_totalTimeLabel.alpha=0;

_fullScreanBtn.alpha=0;

_sliderView.alpha=0;

_startBtn.alpha=0;

}completion:^(BOOLfinished) {

_playViewFlag = !_playViewFlag;

}];

}

#pragma mark 显示组件

- (void)showPlayView{

[UIViewanimateWithDuration:0.5animations:^{

_backBtn.alpha=1;

_currentTimeLabel.alpha=1;

_progressView.alpha=1;

_totalTimeLabel.alpha=1;

_fullScreanBtn.alpha=1;

_sliderView.alpha=1;

_startBtn.alpha=1;

}completion:^(BOOLfinished) {

_playViewFlag = !_playViewFlag;

}];

}

#pragma mark  播放完后---通知处理

- (void)moviePlayDidEnd:(NSNotification*)notification{

}

#pragma mark 播放或者暂停

- (IBAction)startAction:(id)sender {

UIButton*btn = (UIButton*)sender;

if(btn.selected) {

[_playerplay];

}else{

[_playerpause];

}

btn.selected= !btn.selected;

}

#pragma mark 全屏按钮事件

- (IBAction)fullScreanAction:(id)sender {

UIDeviceOrientation orientation = [UIDevicecurrentDevice].orientation;

UIInterfaceOrientation interfaceOrientation = (UIInterfaceOrientation)orientation;

switch(interfaceOrientation) {

caseUIInterfaceOrientationPortraitUpsideDown:// 电池栏在下

[selfinterfaceOrientation:UIInterfaceOrientationLandscapeRight];

break;

caseUIInterfaceOrientationPortrait:// 电池栏在上

[selfinterfaceOrientation:UIInterfaceOrientationLandscapeRight];

break;

caseUIInterfaceOrientationLandscapeLeft:// 电池栏在右边

[selfinterfaceOrientation:UIInterfaceOrientationPortrait];

break;

caseUIInterfaceOrientationLandscapeRight:// 电池栏左边

[selfinterfaceOrientation:UIInterfaceOrientationPortrait];

break;

default:

break;

}

}

#pragma mark  强制转屏相关

- (void)interfaceOrientation:(UIInterfaceOrientation)orientation{

// arc下

if([[UIDevicecurrentDevice]respondsToSelector:@selector(setOrientation:)]) {

SELselector = NSSelectorFromString(@"setOrientation:");

NSInvocation*invocation = [NSInvocationinvocationWithMethodSignature:[UIDeviceinstanceMethodSignatureForSelector:selector]];

[invocationsetSelector:selector];

[invocationsetTarget:[UIDevicecurrentDevice]];

intval = orientation;

[invocationsetArgument:&valatIndex:2];

[invocationinvoke];

}

}

#pragma mark 通过定时器获取视频的时间问题

- (void)playerTimerAction{

if(_playerItem.duration.timescale!=0) {

_sliderView.maximumValue=1;//音乐总共时长

_sliderView.value= CMTimeGetSeconds([_playerItemcurrentTime]) / (_playerItem.duration.value/ _playerItem.duration.timescale);//当前进度

//duration 总时长

NSInteger durMin = (NSInteger)_playerItem.duration.value/ _playerItem.duration.timescale;//总秒

NSInteger durSec = (NSInteger)_playerItem.duration.value/ _playerItem.duration.timescale/60;//总分钟

_totalTimeLabel.text= [NSStringstringWithFormat:@"%02ld:%02ld",durSec,durMin];

//当前时长进度progress

NSInteger proMin = (NSInteger)CMTimeGetSeconds([_playerItemcurrentTime]);//当前秒

NSInteger proSec = (NSInteger)CMTimeGetSeconds([_playerItemcurrentTime]) /60;//当前分

_currentTimeLabel.text= [NSStringstringWithFormat:@"%02ld:%02ld", proSec,proMin];

}

}

#pragma mark 计算出总时间

- (void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionary *)changecontext:(voidvoid*)context{

if(object == _playerItem) {

if([keyPathisEqualToString:@"status"]) {// 这里代表添加完成

if(_playerItem.status== AVPlayerItemStatusReadyToPlay) {

// 添加滑动手势

UIPanGestureRecognizer*pan = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(panDirection:)];

[selfaddGestureRecognizer:pan];

}

}elseif([keyPathisEqualToString:@"loadedTimeRanges"]){

NSTimeInterval timeInterval = [selfavailableDuration];// 计算缓冲进度

CMTime  duration = _playerItem.duration;

CGFloat totalDuration = CMTimeGetSeconds(duration);

[_progressViewsetProgress:timeInterval / totalDurationanimated:NO];

}

}

}

#pragma mark  计算缓存

- (NSTimeInterval)availableDuration {

NSArray*loadedTimeRanges = [[_playercurrentItem]loadedTimeRanges];

CMTimeRange timeRange = [loadedTimeRanges.firstObjectCMTimeRangeValue];// 获取缓冲区域

floatstartSeconds = CMTimeGetSeconds(timeRange.start);

floatdurationSeconds = CMTimeGetSeconds(timeRange.duration);

NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度

returnresult;

}

#pragma mark 锁屏

- (IBAction)lockAction:(id)sender {

UIButton*btn = (UIButton*)sender;

btn.selected= !btn.selected;

_lockFlag = btn.selected;

if(btn.selected) {

[btnsetImage:[UIImageimageNamed:@"lock-nor"]forState:UIControlStateNormal];

}else{

[btnsetImage:[UIImageimageNamed:@"unlock-nor"]forState:UIControlStateNormal];

}

}

#pragma mark   平移手势

- (void)panDirection:(UIPanGestureRecognizer*)pan{

// 根据在Uiview的位置,调节音量或者亮度

CGPoint locationPoint = [panlocationInView:self];

NSLog(@"当前点的位置--->%@",NSStringFromCGPoint(locationPoint));

// 拖动的速度---->返回值就是你拖动时X和Y轴上的速度,速度是矢量,有方向

CGPoint veloctyPoint = [panvelocityInView:self];

NSLog(@"拖动的速度--->%@",NSStringFromCGPoint(veloctyPoint));

// 判断是垂直移动还是水平移动

switch(pan.state) {

caseUIGestureRecognizerStateBegan:{// 开始移动

CGFloat x = fabs(veloctyPoint.x);

CGFloat y = fabs(veloctyPoint.y);

if(x > y) {// 水平移动

_panDirection = PanDirectionHorizontalMoved;

CMTime time = _player.currentTime;

_sumTime = time.value/time.timescale;

NSLog(@"===%f",_sumTime);

}elseif(x < y){// 垂直移动

_panDirection = PanDirectionVerticalMoved;

if(locationPoint.x>self.bounds.size.width/2) {// 右边是控制音量

_isVolume =true;

}else{// 左边是控制亮度

_isVolume =false;

}

}

}

break;

caseUIGestureRecognizerStateChanged:{// 正在移动

if(self.panDirection== PanDirectionHorizontalMoved) {// 水平

[selfhorizontalMoved:veloctyPoint.x];// 水平移动的方法只要x方向的值

}else{// 垂直

[selfverticalMoved:veloctyPoint.y];// 垂直移动方法只要y方向的值

}

}

break;

caseUIGestureRecognizerStateEnded:{

NSLog(@"移动停止l......");

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(11* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

// 隐藏视图

_forwardLabel.hidden=YES;

});

if(self.panDirection== PanDirectionHorizontalMoved) {

//转换成CMTime才能给player来控制播放进度

CMTime dragedCMTime = CMTimeMake(self.sumTime,1);

[_playerpause];

[_playerseekToTime:dragedCMTimecompletionHandler:^(BOOLfinish){

[_playerplay];

}];

// 把sumTime滞空,不然会越加越多

self.sumTime=0;

}else{

}

}

break;

default:

break;

}

}

#pragma mark   垂直移动处理。

- (void)verticalMoved:(CGFloat)value{

if(_isVolume) {// 控制音量

// 更改系统的音量

self.volumeViewSlider.value-= value /10000;// 越小幅度越小

// 这个就对手机有效果, 最大的值为 1  。

NSLog(@"声音----->%lf",self.volumeViewSlider.value);

}else{// 调节亮度

[UIScreenmainScreen].brightness-= value /10000;

NSString*brightness = [NSStringstringWithFormat:@"亮度%.0f%%",[UIScreenmainScreen].brightness/1.0*100];

_forwardLabel.hidden=NO;

_forwardLabel.text= brightness;

}

}

//获取系统音量

- (void)configureVolume

{

// 系统声音控制

MPVolumeView*volumeView = [[MPVolumeViewalloc]init];

_volumeViewSlider =nil;

for(UIView*view in [volumeViewsubviews]){

if([view.class.descriptionisEqualToString:@"MPVolumeSlider"]){

_volumeViewSlider = (UISlider*)view;

break;

}

}

// 使用这个category的应用不会随着手机静音键打开而静音,可在手机静音下播放声音

NSError*setCategoryError =nil;

BOOLsuccess = [[AVAudioSessionsharedInstance]

setCategory: AVAudioSessionCategoryPlayback

error: &setCategoryError];

if(!success) {/* handle the error in setCategoryError */}

}

#pragma mark - pan水平移动的方法

- (void)horizontalMoved:(CGFloat)value{

// 快进快退的方法

NSString*style =@"";

if(value <0) {

style =@"<<";

}

elseif(value >0){

style =@">>";

}

// 每次滑动需要叠加时间

self.sumTime+= value /200;

// 需要限定sumTime的范围

CMTime totalTime =self.playerItem.duration;

CGFloat totalMovieDuration = (CGFloat)totalTime.value/totalTime.timescale;

if(self.sumTime> totalMovieDuration) {

self.sumTime= totalMovieDuration;

}elseif(self.sumTime<0){

self.sumTime=0;

}

// 当前快进的时间

NSString*nowTime = [selfdurationStringWithTime:(int)self.sumTime];

// 总时间

NSString*durationTime = [selfdurationStringWithTime:(int)totalMovieDuration];

// 给label赋值

_forwardLabel.text= [NSStringstringWithFormat:@"%@ %@ / %@",style, nowTime,durationTime];

_forwardLabel.hidden=NO;

}

#pragma mark - 根据时长求出字符串

- (NSString*)durationStringWithTime:(int)time

{

// 获取分钟

NSString*min = [NSStringstringWithFormat:@"%02d",time /60];

// 获取秒数

NSString*sec = [NSStringstringWithFormat:@"%02d",time %60];

return[NSStringstringWithFormat:@"%@:%@", min,sec];

}

@end

视图只设置了   6+ 的适配, 其他的没做处理。

AVPlayer 视频播放器常规功能_第1张图片

调用

self.view.backgroundColor = [UIColor blackColor];

[objc]view plaincopy

NSURL*url = [NSURLURLWithString:@"http://baobab.wdjcdn.com/14562919706254.mp4"];

NSURL*url = [[NSBundlemainBundle]URLForResource:@"minion_01"withExtension:@"mp4"];

[_playViewsetUrl:url];

效果:

AVPlayer 视频播放器常规功能_第2张图片

实现了,  暂停, 拖放,声音,亮度, 锁屏。 这一些基本简单操作。

你可能感兴趣的:(AVPlayer 视频播放器常规功能)