GitHub地址
公司做視頻服務(wù)的,寫了一個播放器Demo。主要功能都已經(jīng)實現(xiàn),自己再插入幾個控制控件。
先梳理幾個問題:
1.AVplayer的播放
2.uislider進(jìn)度條
3.全屏模式
4.單個頁面強(qiáng)制橫屏
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
自定義一個view用來播放視頻。
//// PlayerView.m// videodemo//// Created by meipaipai on 17/2/3.// Copyright © 2017年 meipaipai. All rights reserved.//#import "PlayerView.h"#import "LykSlider.h"@interface PlayerView ()@PRoperty (nonatomic, strong) AVPlayer *player;@property (nonatomic, strong) AVPlayerItem *playerItem;@property (nonatomic ,strong) id playbackTimeObserver;@property (nonatomic, strong) NSString *totalTime;//視頻總時間@property (nonatomic, strong) NSDateFormatter *dateFormatter;//時間格式//控制臺@property (nonatomic, strong) UIView *controlView;//控制臺視圖@property (nonatomic, strong) UIButton *playButton;//播放按鈕@property (nonatomic, strong) LykSlider *playSlider;//進(jìn)度條@property (nonatomic, strong) UILabel *playTime;//播放時間@property (nonatomic, strong) UIButton *fullScreen;//全屏@endstatic UIImage *thumbImage;@implementation PlayerView-(void)dealloc{ [self.playerItem removeObserver:self forKeyPath:@"status" context:nil]; [self.playerItem removeObserver:self forKeyPath:@"loadedTimeRanges" context:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem]; [self.player removeTimeObserver:self.playbackTimeObserver];}-(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { NSURL *videoUrl = [NSURL URLWithString:@"http://v.jxvdy.com/sendfile/w5bgP3A8JgiQQo5l0hvoNGE2H16WbN09X-ONHPq3P3C1BISgf7C-qVs6_c8oaw3zKScO78I--b0BGFBRxlpw13sf2e54QA"]; self.playerItem = [AVPlayerItem playerItemWithURL:videoUrl]; self.player = [AVPlayer playerWithPlayerItem:self.playerItem]; //解決iOS 10偶爾播放不了的問題 if([[UIDevice currentDevice] systemVersion].intValue>=10){ // 增加下面這行可以解決ios10兼容性問題了 self.player.automaticallyWaitsToMinimizeStalling = NO; } // 添加視頻播放結(jié)束通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem]; // 監(jiān)聽status屬性 [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; // 監(jiān)聽loadedTimeRanges屬性 [self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil]; [self.player play]; } return self;}//重寫layer方法+ (Class)layerClass { return [AVPlayerLayer class];}//重寫get方法- (AVPlayer *)player { return [(AVPlayerLayer *)[self layer] player];}//重寫set方法- (void)setPlayer:(AVPlayer *)player { [(AVPlayerLayer *)[self layer] setPlayer:player];}//KVO-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ AVPlayerItem *playerItem = (AVPlayerItem *)object; if ([keyPath isEqualToString:@"status"]) { //準(zhǔn)備播放 if (playerItem.status == AVPlayerItemStatusReadyToPlay) { // 轉(zhuǎn)換成秒 CGFloat totalSecond = playerItem.duration.value / playerItem.duration.timescale; // 轉(zhuǎn)換成播放時間 self.totalTime = [self convertTime:totalSecond]; // 監(jiān)聽播放狀態(tài) [self monitoringPlayback:self.playerItem]; //控制臺UI [self customVideoSlider:totalSecond]; } else if (playerItem.status == AVPlayerStatusFailed) { NSLog(@"播放失敗"); } } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) { NSTimeInterval timeInterval = [self availableDuration];// 計算緩沖進(jìn)度 NSLog(@"Time Interval:%f",timeInterval); CGFloat currentSecond = playerItem.currentTime.value / playerItem.currentTime.timescale; //緩沖好后自動播放 if (timeInterval > currentSecond && self.playButton.selected == NO) { [self.player play]; } }}//緩沖- (NSTimeInterval)availableDuration { NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges]; CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩沖區(qū)域 float startSeconds = CMTimeGetSeconds(timeRange.start); float durationSeconds = CMTimeGetSeconds(timeRange.duration); NSTimeInterval result = startSeconds + durationSeconds;// 計算緩沖總進(jìn)度 return result;}//視頻總時間轉(zhuǎn)換- (NSString *)convertTime:(CGFloat)second{ NSDate *d = [NSDate dateWithTimeIntervalSince1970:second]; if (second/3600 >= 1) { [[self dateFormatter] setDateFormat:@"HH:mm:ss"]; } else { [[self dateFormatter] setDateFormat:@"mm:ss"]; } NSString *showtimeNew = [[self dateFormatter] stringFromDate:d]; return showtimeNew;}//dateFormatter懶加載- (NSDateFormatter *)dateFormatter { if (!_dateFormatter) { _dateFormatter = [[NSDateFormatter alloc] init]; } return _dateFormatter;}//監(jiān)聽播放狀態(tài)- (void)monitoringPlayback:(AVPlayerItem *)playerItem { __weak typeof(self) weakSelf = self; self.playbackTimeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) { // 計算當(dāng)前在第幾秒 CGFloat currentSecond = playerItem.currentTime.value / playerItem.currentTime.timescale; NSString *timeString = [weakSelf convertTime:currentSecond]; NSLog(@"%@", timeString); weakSelf.playSlider.value = currentSecond; weakSelf.playTime.text = [NSString stringWithFormat:@"%@/%@", timeString, weakSelf.totalTime]; }];}//自定義控制臺- (void)customVideoSlider:(CGFloat)second { //控制臺視圖 self.controlView = [[UIView alloc] init]; self.controlView.alpha = 0.8; self.controlView.backgroundColor = [UIColor blackColor]; [self addSubview:self.controlView]; //播放按鈕 float itemY = self.controlView.bounds.size.height / 6; self.playButton = [UIButton buttonWithType:UIButtonTypeCustom]; if (self.playButton.selected) { [self.playButton setImage:[UIImage imageNamed:@"videoPlay"] forState:UIControlStateNormal]; } else { [self.playButton setImage:[UIImage imageNamed:@"videoStop"] forState:UIControlStateNormal]; } [self.playButton addTarget:self action:@selector(clickButton:) forControlEvents:UIControlEventTouchDown]; [self.controlView addSubview:self.playButton]; //視頻時間 self.playTime = [[UILabel alloc] init]; self.playTime.textColor = [UIColor whiteColor]; self.playTime.font = [UIFont systemFontOfSize:itemY * 2]; self.playTime.text = [NSString stringWithFormat:@"00:00/%@", self.totalTime]; [self.controlView addSubview:self.playTime]; //全屏 self.fullScreen = [UIButton buttonWithType:UIButtonTypeCustom]; [self.fullScreen setImage:[UIImage imageNamed:@"videoBig"] forState:UIControlStateNormal]; [self.fullScreen addTarget:self action:@selector(clickFullButton:) forControlEvents:UIControlEventTouchDown]; [self.controlView addSubview:self.fullScreen]; //進(jìn)度條 self.playSlider = [[LykSlider alloc] init]; self.playSlider.minimumValue = 0;// 設(shè)置最小值 self.playSlider.maximumValue = second;// 設(shè)置最大值 self.playSlider.value = 0;// 設(shè)置初始值 self.playSlider.continuous = NO;// 設(shè)置可連續(xù)變化,yes連續(xù)變化會觸發(fā)方法,no當(dāng)滑塊拖動停止會觸發(fā)方法 [self.playSlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; [self.controlView addSubview:self.playSlider]; [self changeFrame:self.frame];}//控制臺按鈕點擊事件-(void)clickButton:(UIButton *)sender{ sender.selected = !sender.selected; if (sender.selected) { [self.playButton setImage:[UIImage imageNamed:@"videoPlay"] forState:UIControlStateNormal]; [self.player pause]; } else { [self.playButton setImage:[UIImage imageNamed:@"videoStop"] forState:UIControlStateNormal]; [self.player play]; }}//全屏按鈕點擊事件-(void)clickFullButton:(UIButton *)sender{ sender.selected = !sender.selected; if (sender.selected) { [self.fullScreen setImage:[UIImage imageNamed:@"videoSmall"] forState:UIControlStateNormal]; //調(diào)用全屏block self.pushBlockWithView(); } else { [self.fullScreen setImage:[UIImage imageNamed:@"videoBig"] forState:UIControlStateNormal]; //調(diào)用小屏block self.popBlockWithView(); }}//改變frame-(void)changeFrame:(CGRect)frame{ self.frame = frame; self.controlView.frame = CGRectMake(0, self.bounds.size.height / 7 * 6, self.bounds.size.width, self.bounds.size.height / 7); float itemY = self.controlView.bounds.size.height / 6; self.playButton.frame = CGRectMake(itemY, itemY, self.controlView.bounds.size.height - itemY * 2, self.controlView.bounds.size.height - itemY * 2); self.playTime.frame = CGRectMake(self.playButton.frame.size.width + itemY * 6, itemY * 2, 200, itemY * 2); self.playTime.font = [UIFont systemFontOfSize:itemY * 2]; self.fullScreen.frame = CGRectMake(self.bounds.size.width - self.controlView.bounds.size.height, itemY, self.controlView.bounds.size.height - itemY * 2, self.controlView.bounds.size.height - itemY * 2); self.playSlider.frame = CGRectMake(0, -itemY, self.controlView.bounds.size.width, itemY * 2); thumbImage = [self OriginImage:[UIImage imageNamed:@"videoThum"] scaleToSize:CGSizeMake(itemY * 2, itemY * 2)]; [self.playSlider setThumbImage:thumbImage forState:UIControlStateNormal];}//裁剪圖片大小-(UIImage *)OriginImage:(UIImage *)image scaleToSize:(CGSize)size { UIGraphicsBeginImageContext(size); //size 為CGSize類型,即你所需要的圖片尺寸 [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return scaledImage; //返回的就是已經(jīng)改變的圖片}//進(jìn)度條拖動方法-(void)sliderValueChanged:(UISlider *)sender{ [self.player seekToTime:CMTimeMake(sender.value,1)];}//播放完成處理- (void)moviePlayDidEnd:(NSNotification *)notification { [self.player seekToTime:kCMTimeZero completionHandler:^(BOOL finished) { }];}@end-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
解決問題:
1.uislider滑塊大小無法控制
解決:
自定義圖片更改滑塊圖片
- (void)setThumbImage:(nullable UIImage *)image forState:(UIControlState)state;
通過控制圖片大小來改變滑塊大小
//裁剪圖片大小-(UIImage *)OriginImage:(UIImage *)image scaleToSize:(CGSize)size { UIGraphicsBeginImageContext(size); //size 為CGSize類型,即你所需要的圖片尺寸 [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return scaledImage; //返回的就是已經(jīng)改變的圖片}2.uislider滑塊拖動不靈敏,有時點不中解決:傳言都說uislider frame的高度沒用,實際高度是一個范圍,只是對樣式?jīng)]有改變,問題的原因就是高度值太小,點不中。
3.視頻播放不了
解決:iOS 10版本問題,avplayer新增屬性automaticallyWaitsToMinimizeStalling,設(shè)置為no就可以
4.全屏強(qiáng)制橫屏
解決:
appdelegate.h
#import <UIKit/UIKit.h>@interface AppDelegate : UIResponder <UIapplicationDelegate>@property (strong, nonatomic) UIWindow *window;/** * 是否強(qiáng)制橫屏 */@property BOOL isForceLandscape;/** * 是否強(qiáng)制豎屏 */@property BOOL isForcePortrait;@endappdelegate.mstatic AppDelegate *_appDelegate;+(AppDelegate *)appDelegate{ return _appDelegate;}-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{ if (self.isForceLandscape) { return UIInterfaceOrientationMaskLandscape; }else if (self.isForcePortrait){ return UIInterfaceOrientationMaskPortrait; } return UIInterfaceOrientationMaskAll;}需要橫屏的viewcontroller加入下列代碼-(void)viewWillAppear:(BOOL)animated{ [self forceOrientationLandscape];}/** * 強(qiáng)制橫屏 */-(void)forceOrientationLandscape{ //這段代碼,只能旋轉(zhuǎn)屏幕不能達(dá)到強(qiáng)制橫屏的效果 if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) { SEL selector = NSSelectorFromString(@"setOrientation:"); NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]]; [invocation setSelector:selector]; [invocation setTarget:[UIDevice currentDevice]]; int val = UIInterfaceOrientationLandscapeRight; [invocation setArgument:&val atIndex:2]; [invocation invoke]; } //加上代理類里的方法,旋轉(zhuǎn)屏幕可以達(dá)到強(qiáng)制橫屏的效果 AppDelegate *appdelegate=(AppDelegate *)[UIApplication sharedApplication].delegate; appdelegate.isForceLandscape=YES; [appdelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];}-(void)viewWillDisappear:(BOOL)animated{ AppDelegate *appdelegate=(AppDelegate *)[UIApplication sharedApplication].delegate; appdelegate.isForcePortrait=NO; appdelegate.isForceLandscape=NO;}
|
新聞熱點
疑難解答