iOS 视频播放器开发

时间:2023-02-02 12:52:57

需求设计

做一个小学生教育辅导视频播放器。

参考小猿搜题视频播放器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L0GsyFSt-1675164972791)(https://tva1.sinaimg.cn/large/008vxvgGgy1h9xk4fm5xfj31sx0u0mz0.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZ7e0Z3Z-1675164972792)(https://tva1.sinaimg.cn/large/008vxvgGgy1h9xk4fm5xfj31sx0u0mz0.jpg)]

主要功能

  • 非VIP用户免费播放开头部分;
  • 截屏;
  • 倍速播放;
  • 进度条快进快退;

实现原理

  1. 公开属性
#import "WMPlayer.h"
@property (nonatomic, retain) WMPlayerModel *playerModel;
@property (nonatomic, strong) WMPlayer  *wmPlayer;
  1. 实例化播放器
    //self.wmPlayer = [[WMPlayer alloc] initWithFrame:CGRectMake(0, [WMPlayer IsiPhoneX]?34:0, self.view.frame.size.width, self.view.frame.size.width*(9.0/16))];
    self.wmPlayer = [[WMPlayer alloc] initWithFrame:CGRectMake(0, 44, self.view.frame.size.width, self.view.frame.size.height-88)];
    self.wmPlayer.delegate = self;
    self.wmPlayer.playerModel = self.playerModel;
    [self.view addSubview:self.wmPlayer];
    [self.wmPlayer play];
    
    //旋转屏幕通知
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(onDeviceOrientationChange:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];

  1. VC生命周期
#pragma mark - Life Cycle

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:YES animated:NO];
    self.view.frame = UIScreen.mainScreen.bounds;
    self.wmPlayer.delegate = self;
}

-(void)viewDidDisappear:(BOOL)animated{
    [super viewDidAppear:animated];
    [self.navigationController setNavigationBarHidden:NO animated:NO];
}

- (void)dealloc{
    [self.wmPlayer pause];
    [self.wmPlayer removeFromSuperview];
    self.wmPlayer = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    NSLog(@"DetailViewController dealloc");
}
  1. 播放器代理
#pragma mark - WMPlayerDelegate
///播放器CloseButton
-(void)wmplayer:(WMPlayer *)wmplayer clickedCloseButton:(UIButton *)closeBtn{
    if (wmplayer.isFullscreen) {
        [self exitFullScreen];
    }else{
        if (self.presentingViewController) {
            [self dismissViewControllerAnimated:YES completion:^{
            }];
        }else{
            [self.navigationController popViewControllerAnimated:YES];
        }
    }
}
///全屏按钮
-(void)wmplayer:(WMPlayer *)wmplayer clickedFullScreenButton:(UIButton *)fullScreenBtn{
    if (self.wmPlayer.viewState == PlayerViewStateSmall) {
         [self enterFullScreen];
    }
}

-(void)enterFullScreen{
    if (self.wmPlayer.viewState != PlayerViewStateSmall) {
        return;
    }
    LandscapeRightViewController *rightVC = [[LandscapeRightViewController alloc] init];
    [self presentToVC:rightVC];
}

-(void)exitFullScreen{
    if (self.wmPlayer.viewState!=PlayerViewStateFullScreen) {
        return;
    }
    self.wmPlayer.isFullscreen = NO;
    self.wmPlayer.viewState = PlayerViewStateAnimating;
    [self dismissViewControllerAnimated:YES completion:^{
        self.wmPlayer.viewState  = PlayerViewStateSmall;
    }];
}
  1. 旋转屏幕通知
#pragma mark - NSNotificationCenter
/**
 *  旋转屏幕通知
 */
- (void)onDeviceOrientationChange:(NSNotification *)notification{
    if (self.wmPlayer.viewState!=PlayerViewStateSmall) {
        return;
    }
    if (self.wmPlayer.isLockScreen){
        return;
    }
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    UIInterfaceOrientation interfaceOrientation = (UIInterfaceOrientation)orientation;
    switch (interfaceOrientation) {
        case UIInterfaceOrientationPortraitUpsideDown:{
        }
            break;
        case UIInterfaceOrientationPortrait:{

        }
            break;
        case UIInterfaceOrientationLandscapeLeft:{
            [self presentToVC:[LandscapeLeftViewController new]];
        }
            break;
        case UIInterfaceOrientationLandscapeRight:{
            [self presentToVC:[LandscapeRightViewController new]];
        }
            break;
        default:
            break;
    }
}

-(void)presentToVC:(FullScreenHelperViewController *)aHelperVC{
    self.wmPlayer.viewState = PlayerViewStateAnimating;
    self.wmPlayer.beforeBounds = self.wmPlayer.bounds;
    self.wmPlayer.beforeCenter = self.wmPlayer.center;
    self.wmPlayer.parentView = self.wmPlayer.superview;
    self.wmPlayer.isFullscreen = YES;
    aHelperVC.wmPlayer = self.wmPlayer;
    aHelperVC.modalPresentationStyle = UIModalPresentationFullScreen;
    aHelperVC.transitioningDelegate = self;
    [self presentViewController:aHelperVC animated:YES completion:^{
        self.wmPlayer.viewState = PlayerViewStateFullScreen;
    }];
}
  1. 调用播放器
        VideoDataModel *videoModel = self.videoDataAry[indexPath.row];
        WMPlayerModel *playerModel = [WMPlayerModel new];
        playerModel.videoURL = [NSURL URLWithString:videoModel.video_url];
        //playerModel.videoURL = [NSURL URLWithString:@"http://static.tripbe.com/videofiles/20121214/9533522808.f4v.mp4"];
        //playerModel.videoURL = [NSURL URLWithString:@"http://img.zhuoqi.tech/test_h264_level30_480_360.mp4"];
        playerModel.title = videoModel.nickname;
        DetailViewController *detailVC = [DetailViewController new];
        detailVC.playerModel = playerModel;
        [self.navigationController pushViewController:detailVC animated:YES];

基本概念

一个在线视频能够播放,大致是经过了如下步骤:

iOS 视频播放器开发

HLS(Http Live Streaming)

HLS是苹果推出,实现的基于HTTP的流媒体传输协议:

优点:

1、通过m3u8索引文件可实现针对当前浏览设备的智能选择播放源

2、通过m3u8索引文件可实现添加备份索引文件,防止服务器崩溃视频播放失败

3、和http视频一样不需要太多服务器额外配置

缺点:

1、并非真正实时视频,30s左右时间差

2、需要视频处理

3、因为需要请求索引文件(ts视频文件)请求次数相对较多,对服务器负载较大

AVPlayer支持哪些视频格式

苹果设备支持音视频格式并不是就代表AVPlayer也支持那么多格式,确定AVPlayer的支持格式,我们可以查看AVKit中的一个API:

//展示当前支持的音视频格式
let asset = AVURLAsset.audiovisualTypes()
//打印asset可以得到(已经转过展示格式)
asset type (
    "audio/aacp",
    "video/3gpp2",
    "audio/mpeg3",
    "audio/mp3",
    "audio/x-caf",
    "audio/mpeg",
    "video/quicktime",
    "audio/x-mpeg3",
    "video/mp4",
    "audio/wav",
    "video/avi",
    "audio/scpls",
    "audio/mp4",
    "audio/x-mpg",
    "video/x-m4v",
    "audio/x-wav",
    "audio/x-aiff",
    "application/vnd.apple.mpegurl",
    "video/3gpp",
    "text/vtt",
    "audio/x-mpeg",
    "audio/wave",
    "audio/x-m4r",
    "audio/x-mp3",
    "audio/AMR",
    "audio/aiff",
    "audio/3gpp2",
    "audio/aac",
    "audio/mpg",
    "audio/mpegurl",
    "audio/x-m4b",
    "application/mp4",
    "audio/x-m4p",
    "audio/x-scpls",
    "audio/x-mpegurl",
    "audio/x-aac",
    "audio/3gpp",
    "audio/basic",
    "audio/x-m4a",
    "application/x-mpegurl"
)

AVPlayer支持的

视频编码格式:H.264、HEVC(iPhone7及以后设备)、MPEG-4。
视频封装格式:.mp4、.mov、.m4v、.3gp、.avi等。
如果想支持更多的视频格式,可以使用使用第三方的框架,常用的视频编码和解码框架有VLC和ffmpeg。

AVPlayerItem的控制

AVPlayerItem作为资源管理对象,它控制着视频从创建到销毁的诸多状态。

播放状态 status

typedef NS_ENUM(NSInteger,AVPlayerItemStatus) {
        AVPlayerItemStatusUnknown,//未知
        AVPlayerItemStatusReadyToPlay,//准备播放
        AVPlayerItemStatusFailed//播放失败
};

我们使用KVO监测playItem.status,可以获取播放状态的变化

[self.playerItem addObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:nil];

在监听回调中:

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context{
    if([object isKindOfClass:[AVPlayerItemclass]]) {
        if([keyPath isEqualToString:@"status"]) {
            switch(_playerItem.status) {
                caseAVPlayerItemStatusReadyToPlay://推荐将视频播放放这里
                    [self play];
                    break;
                caseAVPlayerItemStatusUnknown:
                    NSLog(@"AVPlayerItemStatusUnknown");
                    break;
                caseAVPlayerItemStatusFailed:
                    NSLog(@"AVPlayerItemStatusFailed");
                    break;
                default:
                    break;
             }
        }
    }
}

虽然设置完播放配置我们可以直接调用[self.player play];进行播放,但是更稳妥的方法是在回调收到AVPlayerItemStatusReadyToPlay时进行播放。

参考文章

HTTP Streaming Architecture

HTTP Live Streaming

WMPlayer

WeChat

SJVideoPlayer

DouYin

TBPlayer

iOS视频播放器开发

iOS视频播放的基本方法

上传到阿里云OSS的视频如何实现在线播放

ZFPlayer 3.0解析

AVPlayer支持的视频格式

iOS音视频播放指南(一)

iOS音视频开发学习指南

iOS视频开发(一):视频采集