AVPlayer 視頻播放器常規(guī)功能

//

//??MZPlayView.m

//??視頻播放器常規(guī)功能

//

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

//

#import?"MZPlayView.h"

#import?

#import?

#import?

/**

*??Description

關(guān)于視頻這一塊的業(yè)務(wù)操作全部封裝在這個(gè)里面。?對(duì)外就提供一個(gè)NSUrl屬性。

*/

typedefNS_ENUM(NSInteger,PanDirection){

PanDirectionHorizontalMoved,//橫向移動(dòng)

PanDirectionVerticalMoved//縱向移動(dòng)

};

@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;//?隱藏和顯示標(biāo)識(shí)

@property(nonatomic,strong)NSTimer*timer;

@property(nonatomic,assign)boollockFlag;//?鎖標(biāo)識(shí)

@property(nonatomic,assign)?PanDirection?panDirection;

@property(nonatomic,?assign)BOOLisVolume;//?是否調(diào)節(jié)音量

@property(nonatomic,strong)UISlider*volumeViewSlider;

@property(nonatomic,?assign)?CGFloat?sumTime;//?用來保存的總時(shí)長(zhǎng)

@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];

//?添加手勢(shì)

[selfcreateGesture];

//獲取系統(tǒng)音量

[selfconfigureVolume];

//?添加事件

[selfsliderAddEvent];

//?通過定時(shí)器獲取?時(shí)間,

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

//?計(jì)算緩沖

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

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

}

#pragma?mark??滑動(dòng)事件添加

-?(void)sliderAddEvent{

//?slider開始滑動(dòng)事件

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

//?slider滑動(dòng)中事件

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

//?slider結(jié)束滑動(dòng)事件

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

}

//?開始滑動(dòng)

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

//?取消延遲

//????[NSObject?cancelPreviousPerformRequestsWithTarget:self];

}

//?開始變化

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

//?拖動(dòng)改變視頻播放進(jìn)度

if(_player.status==?AVPlayerItemStatusReadyToPlay)?{

//?總秒數(shù)

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

//?已經(jīng)拖動(dòng)到了現(xiàn)在的秒數(shù)了。

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

//轉(zhuǎn)換成CMTime才能給player來控制播放進(jìn)度---這個(gè)類用來控制時(shí)間的。

CMTime?dragedCMTime?=?CMTimeMake(dragedSeconds,1);

[_playerpause];

[_playerseekToTime:dragedCMTimecompletionHandler:^(BOOLfinished)?{

[_playerplay];

}];

}

}

#pragma?mark?slider事件結(jié)束

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

}

#pragma?mark?重新布局?frame

-?(void)layoutSubviews{

_playerLayer.frame=self.bounds;

};

#pragma?mark?添加手勢(shì),?點(diǎn)擊隱藏視頻所有按鈕

-?(void)createGesture{

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

tap.numberOfTapsRequired=1;

[selfaddGestureRecognizer:tap];

}

#pragma?mark?手勢(shì)回調(diào)處理

-?(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??強(qiáng)制轉(zhuǎn)屏相關(guān)

-?(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?通過定時(shí)器獲取視頻的時(shí)間問題

-?(void)playerTimerAction{

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

_sliderView.maximumValue=1;//音樂總共時(shí)長(zhǎng)

_sliderView.value=?CMTimeGetSeconds([_playerItemcurrentTime])?/?(_playerItem.duration.value/?_playerItem.duration.timescale);//當(dāng)前進(jìn)度

//duration?總時(shí)長(zhǎng)

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];

//當(dāng)前時(shí)長(zhǎng)進(jìn)度progress

NSInteger?proMin?=?(NSInteger)CMTimeGetSeconds([_playerItemcurrentTime]);//當(dāng)前秒

NSInteger?proSec?=?(NSInteger)CMTimeGetSeconds([_playerItemcurrentTime])?/60;//當(dāng)前分

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

}

}

#pragma?mark?計(jì)算出總時(shí)間

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

if(object?==?_playerItem)?{

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

if(_playerItem.status==?AVPlayerItemStatusReadyToPlay)?{

//?添加滑動(dòng)手勢(shì)

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

[selfaddGestureRecognizer:pan];

}

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

NSTimeInterval?timeInterval?=?[selfavailableDuration];//?計(jì)算緩沖進(jìn)度

CMTime??duration?=?_playerItem.duration;

CGFloat?totalDuration?=?CMTimeGetSeconds(duration);

[_progressViewsetProgress:timeInterval?/?totalDurationanimated:NO];

}

}

}

#pragma?mark??計(jì)算緩存

-?(NSTimeInterval)availableDuration?{

NSArray*loadedTimeRanges?=?[[_playercurrentItem]loadedTimeRanges];

CMTimeRange?timeRange?=?[loadedTimeRanges.firstObjectCMTimeRangeValue];//?獲取緩沖區(qū)域

floatstartSeconds?=?CMTimeGetSeconds(timeRange.start);

floatdurationSeconds?=?CMTimeGetSeconds(timeRange.duration);

NSTimeInterval?result?=?startSeconds?+?durationSeconds;//?計(jì)算緩沖總進(jìn)度

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???平移手勢(shì)

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

//?根據(jù)在Uiview的位置,調(diào)節(jié)音量或者亮度

CGPoint?locationPoint?=?[panlocationInView:self];

NSLog(@"當(dāng)前點(diǎn)的位置--->%@",NSStringFromCGPoint(locationPoint));

//?拖動(dòng)的速度---->返回值就是你拖動(dòng)時(shí)X和Y軸上的速度,速度是矢量,有方向

CGPoint?veloctyPoint?=?[panvelocityInView:self];

NSLog(@"拖動(dòng)的速度--->%@",NSStringFromCGPoint(veloctyPoint));

//?判斷是垂直移動(dòng)還是水平移動(dòng)

switch(pan.state)?{

caseUIGestureRecognizerStateBegan:{//?開始移動(dòng)

CGFloat?x?=?fabs(veloctyPoint.x);

CGFloat?y?=?fabs(veloctyPoint.y);

if(x?>?y)?{//?水平移動(dòng)

_panDirection?=?PanDirectionHorizontalMoved;

CMTime?time?=?_player.currentTime;

_sumTime?=?time.value/time.timescale;

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

}elseif(x?<?y){//?垂直移動(dòng)

_panDirection?=?PanDirectionVerticalMoved;

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

_isVolume?=true;

}else{//?左邊是控制亮度

_isVolume?=false;

}

}

}

break;

caseUIGestureRecognizerStateChanged:{//?正在移動(dòng)

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

[selfhorizontalMoved:veloctyPoint.x];//?水平移動(dòng)的方法只要x方向的值

}else{//?垂直

[selfverticalMoved:veloctyPoint.y];//?垂直移動(dòng)方法只要y方向的值

}

}

break;

caseUIGestureRecognizerStateEnded:{

NSLog(@"移動(dòng)停止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)?{

//轉(zhuǎn)換成CMTime才能給player來控制播放進(jìn)度

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

[_playerpause];

[_playerseekToTime:dragedCMTimecompletionHandler:^(BOOLfinish){

[_playerplay];

}];

//?把sumTime滯空,不然會(huì)越加越多

self.sumTime=0;

}else{

}

}

break;

default:

break;

}

}

#pragma?mark???垂直移動(dòng)處理。

-?(void)verticalMoved:(CGFloat)value{

if(_isVolume)?{//?控制音量

//?更改系統(tǒng)的音量

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

//?這個(gè)就對(duì)手機(jī)有效果,?最大的值為?1??。

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

}else{//?調(diào)節(jié)亮度

[UIScreenmainScreen].brightness-=?value?/10000;

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

_forwardLabel.hidden=NO;

_forwardLabel.text=?brightness;

}

}

//獲取系統(tǒng)音量

-?(void)configureVolume

{

//?系統(tǒng)聲音控制

MPVolumeView*volumeView?=?[[MPVolumeViewalloc]init];

_volumeViewSlider?=nil;

for(UIView*view?in?[volumeViewsubviews]){

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

_volumeViewSlider?=?(UISlider*)view;

break;

}

}

//?使用這個(gè)category的應(yīng)用不會(huì)隨著手機(jī)靜音鍵打開而靜音,可在手機(jī)靜音下播放聲音

NSError*setCategoryError?=nil;

BOOLsuccess?=?[[AVAudioSessionsharedInstance]

setCategory:?AVAudioSessionCategoryPlayback

error:?&setCategoryError];

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

}

#pragma?mark?-?pan水平移動(dòng)的方法

-?(void)horizontalMoved:(CGFloat)value{

//?快進(jìn)快退的方法

NSString*style?=@"";

if(value?<0)?{

style?=@"<<";

}

elseif(value?>0){

style?=@">>";

}

//?每次滑動(dòng)需要疊加時(shí)間

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;

}

//?當(dāng)前快進(jìn)的時(shí)間

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

//?總時(shí)間

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

//?給label賦值

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

_forwardLabel.hidden=NO;

}

#pragma?mark?-?根據(jù)時(shí)長(zhǎng)求出字符串

-?(NSString*)durationStringWithTime:(int)time

{

//?獲取分鐘

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

//?獲取秒數(shù)

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

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

}

@end

視圖只設(shè)置了 ? 6+ 的適配, 其他的沒做處理。

調(diào)用

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];

效果:

實(shí)現(xiàn)了, ?暫停, 拖放,聲音,亮度, 鎖屏。 這一些基本簡(jiǎn)單操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容