Demo地址:https://github.com/xttxqjfg/videoDemo,喜歡的可以星星~
爲了適應項目的需要,參照網上的例子,對MobileVLCKit做了一個二次封裝。
主要功能有全屏、關閉全屏、自動全屏、暫停、播放、快進等基本功能。
項目中用到的是pods來集成MobileVLCKit。pods中的包下載下來在本地看有700多M,集成時保證好網絡環境,不然要等很久,不過這700M不會全部加到ipa包中,編譯後只有很小的幾M。
platform:ios,’8.0’
target “videoDemo” do
pod 'MobileVLCKit', '~> 2.2.2'
end
下面是封裝的源代碼段//
// SMAVideoPlayerConst.h
// videoDemo
//
#define kMediaLength self.player.media.length
#define kRGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
#define kSCREEN_BOUNDS [[UIScreen mainScreen] bounds]
static const CGFloat SMA_ProgressWidth = 3.0f;
static const CGFloat SMA_VideoControlBarHeight = 40.0;
static const CGFloat SMA_VideoControlSliderHeight = 10.0;
static const CGFloat SMA_VideoControlAnimationTimeinterval = 0.3;
static const CGFloat SMA_VideoControlTimeLabelFontSize = 10.0;
static const CGFloat SMA_VideoControlBarAutoFadeOutTimeinterval = 4.0;
static const CGFloat SMA_VideoControlCorrectValue = 3;
static const CGFloat SMA_VideoControlAlertAlpha = 0.75;
#import <UIKit/UIKit.h>
@interface SMAVideoToolsView : UIView
//頂部的工具欄,目前包含關閉按鈕
@property (nonatomic,strong) UIView *topBar;
//底部的工具欄,目前包含播放、暫停、全屏、進度條、時間等
@property (nonatomic,strong) UIView *bottomBar;
//播放按鈕
@property (nonatomic,strong) UIButton *playBtn;
//暫停按鈕
@property (nonatomic,strong) UIButton *pauseBtn;
//全屏按鈕
@property (nonatomic, strong) UIButton *fullScreenBtn;
//退出全屏按鈕
@property (nonatomic, strong) UIButton *smallScreenBtn;
//進度條
@property (nonatomic, strong) UISlider *progressSlider;
//退出按鈕
@property (nonatomic, strong) UIButton *closeBtn;
//時間
@property (nonatomic, strong) UILabel *timeLabel;
//背景層
@property (nonatomic, strong) CALayer *bgLayer;
//動畫消失
- (void)animateHide;
//動畫顯示
- (void)animateShow;
//取消延時執行
- (void)autoFadeOutControlBar;
//取消延時執行
- (void)cancelAutoFadeOutControlBar;
@end
//
// SMAVideoToolsView.m
// videoDemo
//
#import "SMAVideoToolsView.h"
#import <MediaPlayer/MediaPlayer.h>
#import "SMAVideoPlayerConst.h"
@interface SMAVideoToolsView()
//點擊手勢
@property (nonatomic, strong) UIPanGestureRecognizer *tapGesture;
@end
@implementation SMAVideoToolsView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupView];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
self.topBar.frame = CGRectMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), CGRectGetWidth(self.bounds), SMA_VideoControlBarHeight);
self.closeBtn.frame = CGRectMake(0, CGRectGetMinX(self.topBar.bounds), CGRectGetWidth(self.closeBtn.bounds), CGRectGetHeight(self.closeBtn.bounds));
self.bottomBar.frame = CGRectMake(CGRectGetMinX(self.bounds), CGRectGetHeight(self.bounds) - SMA_VideoControlBarHeight, CGRectGetWidth(self.bounds), SMA_VideoControlBarHeight);
self.progressSlider.frame = CGRectMake(0, -0, CGRectGetWidth(self.bounds), SMA_VideoControlSliderHeight);
self.playBtn.frame = CGRectMake(CGRectGetMinX(self.bottomBar.bounds), CGRectGetHeight(self.bottomBar.bounds)/2 - CGRectGetHeight(self.playBtn.bounds)/2 + CGRectGetHeight(self.progressSlider.frame) * 0.6, CGRectGetWidth(self.playBtn.bounds), CGRectGetHeight(self.playBtn.bounds));
self.pauseBtn.frame = self.playBtn.frame;
self.fullScreenBtn.frame = CGRectMake(CGRectGetWidth(self.bottomBar.bounds) - CGRectGetWidth(self.fullScreenBtn.bounds) - 5, self.playBtn.frame.origin.y, CGRectGetWidth(self.fullScreenBtn.bounds), CGRectGetHeight(self.fullScreenBtn.bounds));
self.smallScreenBtn.frame = self.fullScreenBtn.frame;
self.timeLabel.frame = CGRectMake(CGRectGetMaxX(self.playBtn.frame), self.playBtn.frame.origin.y, CGRectGetWidth(self.bottomBar.bounds), CGRectGetHeight(self.timeLabel.bounds));
}
#pragma mark - 私有方法
- (void)setupView {
self.backgroundColor = [UIColor clearColor];
[self.layer addSublayer:self.bgLayer];
[self addSubview:self.topBar];
[self addSubview:self.bottomBar];
[self.topBar addSubview:self.closeBtn];
[self.bottomBar addSubview:self.playBtn];
[self.bottomBar addSubview:self.pauseBtn];
[self.bottomBar addSubview:self.fullScreenBtn];
[self.bottomBar addSubview:self.smallScreenBtn];
[self.bottomBar addSubview:self.progressSlider];
[self.bottomBar addSubview:self.timeLabel];
self.pauseBtn.hidden = YES;
self.smallScreenBtn.hidden = YES;
[self addGestureRecognizer:self.tapGesture];
}
- (void)responseTapImmediately {
self.bottomBar.alpha == 0 ? [self animateShow] : [self animateHide];
}
#pragma mark - 代理方法
#pragma mark - 接口方法
/**
隱藏工具欄,全屏效果
*/
- (void)animateHide
{
[UIView animateWithDuration:SMA_VideoControlAnimationTimeinterval animations:^{
self.topBar.alpha = 0;
self.bottomBar.alpha = 0;
} completion:^(BOOL finished) {
}];
}
/**
顯示工具欄
*/
- (void)animateShow
{
[UIView animateWithDuration:SMA_VideoControlAnimationTimeinterval animations:^{
self.topBar.alpha = 1;
self.bottomBar.alpha = 1;
} completion:^(BOOL finished) {
[self autoFadeOutControlBar];
}];
}
- (void)autoFadeOutControlBar
{
//如果有延遲執行在隊列中,則取消延時執行
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(animateHide) object:nil];
//開始延遲執行
[self performSelector:@selector(animateHide) withObject:nil afterDelay:SMA_VideoControlBarAutoFadeOutTimeinterval];
}
- (void)cancelAutoFadeOutControlBar
{
//如果有延遲執行在隊列中,則取消延時執行
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(animateHide) object:nil];
}
#pragma mark - 屏幕觸摸事件
- (void)tapGestureAction:(UIPanGestureRecognizer *)pan {
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch.tapCount > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
[self responseTapImmediately];
});
}
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self responseTapImmediately];
}
#pragma mark - 懶加載
- (UIView *)topBar
{
if (!_topBar) {
_topBar = [UIView new];
_topBar.backgroundColor = [UIColor clearColor];
}
return _topBar;
}
- (UIView *)bottomBar
{
if (!_bottomBar) {
_bottomBar = [UIView new];
_bottomBar.backgroundColor = kRGB(27, 27, 27);
}
return _bottomBar;
}
- (UIButton *)playBtn
{
if (!_playBtn) {
_playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_playBtn setImage:[UIImage imageNamed:@"Play"] forState:UIControlStateNormal];
_playBtn.bounds = CGRectMake(0, 0, SMA_VideoControlBarHeight, SMA_VideoControlBarHeight);
}
return _playBtn;
}
- (UIButton *)pauseBtn
{
if (!_pauseBtn) {
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_pauseBtn setImage:[UIImage imageNamed:@"Pause"] forState:UIControlStateNormal];
_pauseBtn.bounds = CGRectMake(0, 0, SMA_VideoControlBarHeight, SMA_VideoControlBarHeight);
}
return _pauseBtn;
}
- (UIButton *)fullScreenBtn
{
if (!_fullScreenBtn) {
_fullScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_fullScreenBtn setImage:[UIImage imageNamed:@"FullScreen"] forState:UIControlStateNormal];
_fullScreenBtn.bounds = CGRectMake(0, 0, SMA_VideoControlBarHeight, SMA_VideoControlBarHeight);
}
return _fullScreenBtn;
}
- (UIButton *)smallScreenBtn
{
if (!_smallScreenBtn) {
_smallScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_smallScreenBtn setImage:[UIImage imageNamed:@"MinScreen"] forState:UIControlStateNormal];
_smallScreenBtn.bounds = CGRectMake(0, 0, SMA_VideoControlBarHeight, SMA_VideoControlBarHeight);
}
return _smallScreenBtn;
}
- (UISlider *)progressSlider
{
if (!_progressSlider) {
_progressSlider = [[UISlider alloc] init];
[_progressSlider setThumbImage:[UIImage imageNamed:@"PlayerNob"] forState:UIControlStateNormal];
[_progressSlider setMinimumTrackTintColor:kRGB(239, 71, 94)];
[_progressSlider setMaximumTrackTintColor:kRGB(157, 157, 157)];
[_progressSlider setBackgroundColor:[UIColor clearColor]];
_progressSlider.value = 0.f;
_progressSlider.continuous = YES;
}
return _progressSlider;
}
- (UIButton *)closeBtn
{
if (!_closeBtn) {
_closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_closeBtn setImage:[UIImage imageNamed:@"PlayerClose"] forState:UIControlStateNormal];
_closeBtn.bounds = CGRectMake(0, 0, SMA_VideoControlBarHeight, SMA_VideoControlBarHeight);
}
return _closeBtn;
}
- (UILabel *)timeLabel
{
if (!_timeLabel) {
_timeLabel = [UILabel new];
_timeLabel.backgroundColor = [UIColor clearColor];
_timeLabel.font = [UIFont systemFontOfSize:SMA_VideoControlTimeLabelFontSize];
_timeLabel.textColor = [UIColor lightGrayColor];
_timeLabel.textAlignment = NSTextAlignmentLeft;
_timeLabel.bounds = CGRectMake(0, 0, SMA_VideoControlTimeLabelFontSize, SMA_VideoControlBarHeight);
}
return _timeLabel;
}
- (CALayer *)bgLayer {
if (!_bgLayer) {
_bgLayer = [CALayer layer];
_bgLayer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"VideoBg"]].CGColor;
_bgLayer.bounds = self.frame;
_bgLayer.position = CGPointMake(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2);
}
return _bgLayer;
}
- (UIPanGestureRecognizer *)tapGesture {
if (!_tapGesture) {
_tapGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction:)];
}
return _tapGesture;
}
@end
#import <UIKit/UIKit.h>
@interface SMAVideoPlayer : UIView
@property (nonatomic,strong) NSURL *mediaURL;
@property (nonatomic,assign) BOOL isFullscreenModel;
- (void)showInView:(UIView *)view;
@end
//
// SMAVideoPlayer.m
// videoDemo
//
#import "SMAVideoPlayer.h"
#import <MobileVLCKit/MobileVLCKit.h>
#import "SMAVideoToolsView.h"
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#import "SMAVideoPlayerConst.h"
@interface SMAVideoPlayer()<VLCMediaPlayerDelegate>
{
CGRect _originFrame;
}
@property (nonatomic,strong) VLCMediaPlayer *player;
@property (nonatomic, nonnull,strong) SMAVideoToolsView *toolsView;
@end
@implementation SMAVideoPlayer
- (instancetype)init {
if (self = [super init]) {
[self setupNotification];
}
return self;
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPlayer];
[self setupView];
[self setupControlView];
}
#pragma mark - 接口方法
- (void)showInView:(UIView *)view {
NSAssert(_mediaURL != nil, @"MRVLCPlayer Exception: mediaURL could not be nil!");
[view addSubview:self];
self.alpha = 0.0;
[UIView animateWithDuration:SMA_VideoControlAnimationTimeinterval animations:^{
self.alpha = 1.0;
} completion:^(BOOL finished) {
[self play];
}];
}
- (void)dismiss {
[self.player stop];
self.player.delegate = nil;
self.player.drawable = nil;
self.player = nil;
// 註銷通知
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self removeFromSuperview];
}
#pragma mark - Private Method
- (void)setupView {
[self setBackgroundColor:[UIColor blackColor]];
}
- (void)setupPlayer {
[self.player setDrawable:self];
self.player.media = [[VLCMedia alloc] initWithURL:self.mediaURL];
}
- (void)setupControlView {
[self addSubview:self.toolsView];
//添加控制界面的監聽方法
[self.toolsView.playBtn addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.toolsView.pauseBtn addTarget:self action:@selector(pauseButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.toolsView.closeBtn addTarget:self action:@selector(closeButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.toolsView.fullScreenBtn addTarget:self action:@selector(fullScreenButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.toolsView.smallScreenBtn addTarget:self action:@selector(shrinkScreenButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.toolsView.progressSlider addTarget:self action:@selector(progressClick) forControlEvents:UIControlEventTouchUpInside];
}
- (void)setupNotification {
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationHandler)
name:UIDeviceOrientationDidChangeNotification
object:nil
];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive)
name:UIApplicationWillResignActiveNotification
object:nil];
}
/**
* 強制橫屏
*
* @param orientation 橫屏方向
*/
- (void)forceChangeOrientation:(UIInterfaceOrientation)orientation
{
int val = orientation;
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
#pragma mark Notification Handler
/**
* 屏幕旋轉處理
*/
- (void)orientationHandler {
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
self.isFullscreenModel = YES;
}else {
self.isFullscreenModel = NO;
}
[self.toolsView autoFadeOutControlBar];
}
/**
* 即將進入後臺的處理
*/
- (void)applicationWillEnterForeground {
[self play];
}
/**
* 即將返回前臺的處理
*/
- (void)applicationWillResignActive {
[self pause];
}
#pragma mark Button Event
- (void)playButtonClick {
[self play];
}
- (void)pauseButtonClick {
[self pause];
}
- (void)closeButtonClick {
[self dismiss];
}
- (void)fullScreenButtonClick {
[self forceChangeOrientation:UIInterfaceOrientationLandscapeRight];
}
- (void)shrinkScreenButtonClick {
[self forceChangeOrientation:UIInterfaceOrientationPortrait];;
}
- (void)progressClick {
int targetIntvalue = (int)(self.toolsView.progressSlider.value * (float)kMediaLength.intValue);
VLCTime *targetTime = [[VLCTime alloc] initWithInt:targetIntvalue];
[self.player setTime:targetTime];
[self.toolsView autoFadeOutControlBar];
}
#pragma mark Player Logic
- (void)play {
[self.player play];
self.toolsView.playBtn.hidden = YES;
self.toolsView.pauseBtn.hidden = NO;
[self.toolsView autoFadeOutControlBar];
}
- (void)pause {
[self.player pause];
self.toolsView.playBtn.hidden = NO;
self.toolsView.pauseBtn.hidden = YES;
[self.toolsView autoFadeOutControlBar];
}
- (void)stop {
[self.player stop];
self.toolsView.progressSlider.value = 1;
self.toolsView.playBtn.hidden = NO;
self.toolsView.pauseBtn.hidden = YES;
}
#pragma mark - Delegate
#pragma mark VLC
- (void)mediaPlayerStateChanged:(NSNotification *)aNotification {
// Every Time change the state,The VLC will draw video layer on this layer.
[self bringSubviewToFront:self.toolsView];
if (self.player.media.state == VLCMediaStateBuffering) {
self.toolsView.bgLayer.hidden = NO;
}else if (self.player.media.state == VLCMediaStatePlaying) {
self.toolsView.bgLayer.hidden = YES;
}else if (self.player.state == VLCMediaPlayerStateStopped) {
[self stop];
}else {
self.toolsView.bgLayer.hidden = NO;
}
}
- (void)mediaPlayerTimeChanged:(NSNotification *)aNotification {
[self bringSubviewToFront:self.toolsView];
if (self.toolsView.progressSlider.state != UIControlStateNormal) {
return;
}
float precentValue = ([self.player.time.numberValue floatValue]) / ([kMediaLength.numberValue floatValue]);
[self.toolsView.progressSlider setValue:precentValue animated:YES];
[self.toolsView.timeLabel setText:[NSString stringWithFormat:@"%@/%@",_player.time.stringValue,kMediaLength.stringValue]];
}
#pragma mark - 懶加載
- (VLCMediaPlayer *)player {
if (!_player) {
_player = [[VLCMediaPlayer alloc] init];
_player.delegate = self;
}
return _player;
}
- (SMAVideoToolsView *)toolsView {
if (!_toolsView) {
_toolsView = [[SMAVideoToolsView alloc] initWithFrame:self.bounds];
}
return _toolsView;
}
- (void)setIsFullscreenModel:(BOOL)isFullscreenModel {
if (_isFullscreenModel == isFullscreenModel) {
return;
}
_isFullscreenModel = isFullscreenModel;
if (isFullscreenModel) {
_originFrame = self.frame;
CGFloat height = kSCREEN_BOUNDS.size.width;
CGFloat width = kSCREEN_BOUNDS.size.height;
CGRect frame = CGRectMake((height - width) / 2, (width - height) / 2, width, height);
[UIView animateWithDuration:SMA_VideoControlAnimationTimeinterval animations:^{
/**
* 此判斷是爲了適配項目在Deployment Info中是否勾選了橫屏
*/
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
self.frame = frame;
self.transform = CGAffineTransformMakeRotation(M_PI_2);
}else {
self.frame = self.frame = kSCREEN_BOUNDS;
}
self.toolsView.frame = self.bounds;
[self.toolsView layoutIfNeeded];
self.toolsView.fullScreenBtn.hidden = YES;
self.toolsView.smallScreenBtn.hidden = NO;
} completion:^(BOOL finished) {}];
}else {
[UIView animateWithDuration:SMA_VideoControlAnimationTimeinterval animations:^{
self.transform = CGAffineTransformIdentity;
self.frame = _originFrame;
self.toolsView.frame = self.bounds;
[self.toolsView layoutIfNeeded];
self.toolsView.fullScreenBtn.hidden = NO;
self.toolsView.smallScreenBtn.hidden = YES;
} completion:^(BOOL finished) {}];
}
}
@end
vc中使用
//播放遠端視頻
- (IBAction)playRemoteVideo:(UIButton *)sender {
SMAVideoPlayer *player = [[SMAVideoPlayer alloc] init];
player.bounds = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.width / 16 * 9);
player.center = self.view.center;
player.mediaURL = [NSURL URLWithString:@"http://172.20.90.117/www2/video/1.mp4"];
[player showInView:self.view.window];
[self prefersStatusBarHidden];
}
-(BOOL)prefersStatusBarHidden
{
return YES;
}
效果圖如下