播放视频AVPlayer使用详解

在开发中,单纯使用AVPlayer类是无法显示视频的,要将视频层添加至AVPlayerLayer中,这样才能将视频显示出来。

属性含义:

/* 播放器 */

@property (nonatomic, strong) AVPlayer *player;

// 播放器的Layer

@property (weak, nonatomic) AVPlayerLayer *playerLayer;


//生成layer层
AVPlayerLayer * layer=[AVPlayerLayer playerLayerWithPlayer:_player];

//设置坐标
 layer.frame=CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

//把layer层加入到self.View中
 [self.view.layer addSublayer:layer];


  //进行播放
[_player play];

 //kvo 观察播放状态playerItem.status

[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

//观察缓存现在的进度,KVO进行观察,观察     playerItem.loadedTimeRanges的属性
 [_playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];



使用 AVPlayer 的时候,一定要注意 AVPlayer 、 AVPlayerLayer 和 AVPlayerItem 三者之间的关系。

 AVPlayer 负责控制播放, layer 显示播放, item 提供数据,当前播放时间, 已加载情况。

 Item 中一些基本的属性, status, duration, loadedTimeRanges, currentTime(当前播放时间)。


AVPlayerItemStatus是代表当前播放资源item 的状态(可以理解成这url链接or视频文件。。。可以播放成功/失败)
AVPlayerStatus是代表当前播放器的状态。


addPeriodicTimeObserverForInterval
给AVPlayer 添加time Observer 有利于我们去检测播放进度
但是添加以后一定要记得移除,其实不移除程序不会崩溃,但是这个线程是不会释放的,会占用你大量的内存资源


CMTime 结构体
连接的教程里面 给的参数是CMTimeMake(1, 1),其实就是1s调用一下block,
打个比方CMTimeMake(a, b)就是a/b秒之后调用一下block
介绍一个网站有关这个结构体的:
https://zwo28.wordpress.com/2015/03/06/%E8%A7%86%E9%A2%91%E5%90%88%E6%88%90%E4%B8%ADcmtime%E7%9A%84%E7%90%86%E8%A7%A3%EF%BC%8C%E4%BB%A5%E5%8F%8A%E5%88%A9%E7%94%A8cmtime%E5%AE%9E%E7%8E%B0%E8%BF%87%E6%B8%A1%E6%95%88%E6%9E%9C/


拖动slider 播放跳跃播放,要使用AVPlayer 对象的seekToTime:方法,
举个最简单的例子:假如一个video视频有20s,想要跳到10s进行播放(_palyer 为AVPlayer 对象)
[_player seekToTime:CMTimeMake(10,1)];后面的参数写1,前面的参数写将要播放的秒数,我试验得出的结果,不要问我问什么,需要自己理解。
5.播放到结尾怎么回到开头呢?
[_player seekToTime:kCMTimeZero];


-(void)setupUI{
//创建播放器层
AVPlayerLayer *playerLayer=[AVPlayerLayer playerLayerWithPlayer:self.player];
playerLayer.frame=aview.frame;
playerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//视频填充模式
[aview.layer addSublayer:playerLayer];
}


-(void)addNotification{
//给AVPlayerItem添加播放完成通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:)name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}


////////////////////////////////////////////////////////////////////////////////////////////

AVPlayerItem 使用

1. 初始化

playerItemWithURL 或者 initWithURL:

在使用 AVPlayer 播放视频时,提供视频信息的是 AVPlayerItem,一个 AVPlayerItem 对应着一个URL视频资源。

初始化一个 AVPlayItem 对象后,其属性并不是马上就可以使用。我们必须确保 AVPlayerItem 已经被加载好了,可以播放了,才能使用。 毕竟凡是和网络扯上关系的都需要时间去加载。 那么,什么时候属性才能正常使用呢。 官方文档给出了解决方案:

  1. 直到 AVPlayerItem 的 status 属性为 AVPlayerItemStatusReadyToPlay.

  2. 使用 KVO 键值观察者,其属性。

因此我们在使用的时候,使用 URL 初始化 AVPlayerItem 后,还要给它添加观察者。

2. 添加观察者

AVPlayreItem 的属性需要当 status 为 ReadyToPlay 的时候才可以正常使用。

观察status属性

[_playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil]; // 观察status属性,

播放步骤

1. 布局页面,初始化 AVPlayer 和 AVPlayerLayer

 // setAVPlayer
 self.player = [[AVPlayer alloc] init];
 _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
 [self.playerView.layer addSublayer:_playerLayer];

2. 根据 URL 获取 AVPayerItem,并替换 AVPlayer 的 AVPlayerItem

在第一步,布局初始化时,AVPlayer 并没有 AVPlayerItem,AVPlayer 提供了 - (void)replaceCurrentItemWithPlayerItem:(nullable AVPlayerItem *)item;  方法,用于切换视频。

- (void)updatePlayerWithURL:(NSURL *)url {
    _playerItem = [AVPlayerItem playerItemWithURL:url]; // create item
    [_player  replaceCurrentItemWithPlayerItem:_playerItem]; // replaceCurrentItem
    [self addObserverAndNotification]; // 注册观察者,通知
}

3. KVO 获取视频信息, 观察缓冲进度

观察 AVPlayerItem 的 status 属性,当状态变为 AVPlayerStatusReadyToPlay 时才可以使用。

也可以观察 loadedTimeRanges 获取缓冲进度

注册观察者:

 [_playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil]; // 观察status属性

执行观察者方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    AVPlayerItem *item = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
            AVPlayerStatus status = [[change objectForKey:@"new"] intValue]; // 获取更改后的状态
            if (status == AVPlayerStatusReadyToPlay) {
                CMTime duration = item.duration; // 获取视频长度
                // 设置视频时间
                [self setMaxDuration:CMTimeGetSeconds(duration)];
                // 播放
                [self play];
            } else if (status == AVPlayerStatusFailed) {
                NSLog(@"AVPlayerStatusFailed");
            } else {
                NSLog(@"AVPlayerStatusUnknown");
            }

    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        NSTimeInterval timeInterval = [self availableDurationRanges]; // 缓冲时间
        CGFloat totalDuration = CMTimeGetSeconds(_playerItem.duration); // 总时间
        [self.loadedProgress setProgress:timeInterval / totalDuration animated:YES]; // 更新缓冲条
    }
}

4. 播放过程中响应:播放、 暂停、 跳转

AVPlayer 提供了 play , pause, 和 - (void)seekToTime:(CMTime)time completionHandler:(void (^)(BOOL finished))completionHandler 方法。

在看 AVPlayer 的 seekToTime 之前,先来认识一个结构体。

CMTime 是专门用于标识电影时间的结构体.

typedef struct{
    CMTimeValue    value;     // 帧数
    CMTimeScale    timescale;  // 帧率(影片每秒有几帧)
    CMTimeFlags    flags;        
    CMTimeEpoch    epoch;
} CMTime;

AVPlayerItem 的 duration 属性就是一个 CMTime 类型的数据。 如果我们想要获取影片的总秒数那么就可以用 duration.value / duration.timeScale 计算出来。也可以使用 CMTimeGetSeconds 函数

CMTimeGetSeconds(CMtime time)
double seconds = CMTimeGetSeconds(item.duration);  // 相当于 duration.value / duration.timeScale

如果一个影片为60frame(帧)每秒, 当前想要跳转到 120帧的位置,也就是两秒的位置,那么就可以创建一个 CMTime 类型数据。

CMTime,通常用如下两个函数来创建.

CMTimeMake(int64_t value, int32_t scale)
CMTime time1 = CMTimeMake(120, 60);

CMTimeMakeWithSeconds(Flout64 seconds, int32_t scale)
CMTime time2 = CMTimeWithSeconds(120, 60);

CMTimeMakeWithSeconds 和CMTimeMake 区别在于,第一个函数的第一个参数可以是float,其他一样。

拖拽方法如下:

- (IBAction)playerSliderValueChanged:(id)sender {
    _isSliding = YES;
    [self pause];    // 跳转到拖拽秒处
    // self.playProgress.maxValue = value / timeScale
    // value = progress.value * timeScale
    // CMTimemake(value, timeScale) =  (progress.value, 1.0)
    CMTime changedTime = CMTimeMakeWithSeconds(self.playProgress.value, 1.0);
    [_playerItem seekToTime:changedTime completionHandler:^(BOOL finished) {        
    // 跳转完成后
    }];
}

5. 观察 AVPlayer 播放进度

AVPlayerItem 是使用 KVO 模式观察状态,和 缓冲进度。而 AVPlayer 给我们直接提供了 观察播放进度更为方便的方法。

- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;

方法名如其意, “添加周期时间观察者” ,参数1 interal 为CMTime 类型的,参数2 为一个 返回值为空,参数为 CMTime 的block类型。

简而言之就是,每隔一段时间后执行 block。

比如: 我把时间间隔设置为, 1/ 30 秒,然后 block 里面更新 UI。就是一秒钟更新 30次UI。

播放进度代码如下:

// 观察播放进度
- (void)monitoringPlayback:(AVPlayerItem *)item {
    __weak typeof(self)WeakSelf = self;

    // 观察间隔, CMTime 为30分之一秒
    _playTimeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 30.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        if (_touchMode != TouchPlayerViewModeHorizontal) {
            // 获取 item 当前播放秒
            float currentPlayTime = (double)item.currentTime.value/ item.currentTime.timescale;
            // 更新slider, 如果正在滑动则不更新
            if (_isSliding == NO) {
                [WeakSelf updateVideoSlider:currentPlayTime];
            }
        } else {
            return;
        }
    }];
}

注意: 给 palyer 添加了 timeObserver 后,不使用的时候记得移除 removeTimeObserver 否则会占用大量内存。

比如,我在dealloc里面做了移除:

- (void)dealloc {
    [self removeObserveAndNOtification];
    [_player removeTimeObserver:_playTimeObserver]; // 移除playTimeObserver}

6. AVPlayerItem 通知

AVPlaerItem 播放完成后,系统会自动发送通知,通知的定义详情请见 AVPlayerItem.h.

/* Note that NSNotifications posted by AVPlayerItem may be posted on a different thread from the one on which the observer was registered. */

// notifications                                                                                description
AVF_EXPORT NSString *const AVPlayerItemTimeJumpedNotification             NS_AVAILABLE(10_7, 5_0);    // the item's current time has changed discontinuously
AVF_EXPORT NSString *const AVPlayerItemDidPlayToEndTimeNotification      NS_AVAILABLE(10_7, 4_0);   // item has played to its end time
AVF_EXPORT NSString *const AVPlayerItemFailedToPlayToEndTimeNotification NS_AVAILABLE(10_7, 4_3);   // item has failed to play to its end time
AVF_EXPORT NSString *const AVPlayerItemPlaybackStalledNotification       NS_AVAILABLE(10_9, 6_0);    // media did not arrive in time to continue playback
AVF_EXPORT NSString *const AVPlayerItemNewAccessLogEntryNotification     NS_AVAILABLE(10_9, 6_0);    // a new access log entry has been added
AVF_EXPORT NSString *const AVPlayerItemNewErrorLogEntryNotification         NS_AVAILABLE(10_9, 6_0);    // a new error log entry has been added

// notification userInfo key                                                                    type
AVF_EXPORT NSString *const AVPlayerItemFailedToPlayToEndTimeErrorKey     NS_AVAILABLE(10_7, 4_3);   // NSError

因此,如果我们想要在某个状态下,执行某些操作。监听 AVPlayerItem 的相关通知就行了。 比如,我想要播放完成后,暂停播放。 给AVPlayerItemDidPlayToEndTimeNotification 添加观察者。

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

 // 播放完成后
 - (void)playbackFinished:(NSNotification *)notification {
    NSLog(@"视频播放完成通知");
    _playerItem = [notification object];
    [_playerItem seekToTime:kCMTimeZero]; // item 跳转到初始
      //[_player play]; // 循环播放
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


在cell中写的一个视频播放的代理方法:

 

  if ([self.delegate respondsToSelector:@selector(clickVideoButton:)]) {

        [self.delegate clickVideoButton:self.indexPath];

    }


播放视频AVPlayer使用详解_第1张图片

点击图片的播放按钮会执行代理方法。代理方法的内容如下:


#pragma mark VideoTableViewCell的代理方法

-(void)clickVideoButton:(NSIndexPath *)indexPath {

    [self.playView resetPlayView];


    VideoTableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

    self.currentSelectedCell = cell;

    VideoPlayView *playView = [VideoPlayView videoPlayView];

// TTVideo里面主要是一些模型数据

    TTVideo *video = self.videoArray[indexPath.row];

    playView.frame = video.videoFrame;

    [cell addSubview:playView];

    cell.playView = playView;

    self.playView = playView;

    self.playView.delegate = self;


// AVPlayerItem的初始化,根据URL获取AVPlayerItem

    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:video.videouri]];

    self.playView.playerItem = item;

}


//////////////////////////////////////////////////////////////////////////////////////////////////////


最主要的VideoPlayView的文件有VideoPlayView.h,ViewPlayView.m,VideoPlayView.xib.


其中VideoPlayView.xib的样子如下:

播放视频AVPlayer使用详解_第2张图片

VideoPlayView.h的文件如下:


#import

#import


@protocol VideoPlayViewDelegate <NSObject>


@optional

- (void)videoplayViewSwitchOrientation:(BOOL)isFull;


@end


@interface VideoPlayView : UIView


+ (instancetype)videoPlayView;


@property (weak, nonatomic) id<VideoPlayViewDelegate> delegate;


@property (nonatomic, strong) AVPlayerItem *playerItem;


-(void)suspendPlayVideo;


-(void)resetPlayView;

@end


VideoPlayView.m的文件如下:



#import "VideoPlayView.h"


@interface VideoPlayView()


/* 播放器 */

@property (nonatomic, strong) AVPlayer *player;


// 播放器的Layer

@property (weak, nonatomic) AVPlayerLayer *playerLayer;


@property (weak, nonatomic) IBOutlet UIImageView *imageView; //底部图片

@property (weak, nonatomic) IBOutlet UIView *toolView;

@property (weak, nonatomic) IBOutlet UIButton *playOrPauseBtn;

@property (weak, nonatomic) IBOutlet UISlider *progressSlider;

@property (weak, nonatomic) IBOutlet UILabel *timeLabel;

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *progressView; //转的梅花


@property (nonatomic, weak) UITableView *tableView;

@property (nonatomic, assign) NSIndexPath *indexPath;



// 记录当前是否显示了工具栏

@property (assign, nonatomic) BOOL isShowToolView;


/* 时器 */

@property (nonatomic, strong) NSTimer *progressTimer;


#pragma mark - 监听事件的处理

- (IBAction)playOrPause:(UIButton *)sender;

- (IBAction)switchOrientation:(UIButton *)sender;

- (IBAction)slider;

- (IBAction)startSlider;

- (IBAction)tapAction:(UITapGestureRecognizer *)sender;

- (IBAction)sliderValueChange;


@end


@implementation VideoPlayView


// 快速创建View的方法

+ (instancetype)videoPlayView

{

    return [[[NSBundle mainBundle] loadNibNamed:@"VideoPlayView" owner:nil options:nil] firstObject];

}


// 采用了xib,读取xib时候会调用这个方法

- (void)awakeFromNib

{

    [super awakeFromNib];

    

 //////////////////////////////////////////////////////

    

    //第一步:初始化AVPlayerAVPlayerLayer

    self.player = [[AVPlayer alloc] init]; //AVPlayer的初始化

    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; // AVPlayerLayer的初始化

    //单纯使用AVPlayer类是无法显示视频的,要将视频层添加至AVPlayerLayer中,这样才能将视频显示出来

    [self.imageView.layer addSublayer:self.playerLayer];

    

 ////////////////////////////////////////////////////////////

    

    self.toolView.alpha = 0;

    self.isShowToolView = NO;

    

    [self.progressSlider setThumbImage:[UIImage imageNamed:@"thumbImage"] forState:UIControlStateNormal];

    [self.progressSlider setMaximumTrackImage:[UIImage imageNamed:@"MaximumTrackImage"] forState:UIControlStateNormal];

    [self.progressSlider setMinimumTrackImage:[UIImage imageNamed:@"MinimumTrackImage"] forState:UIControlStateNormal];

    

    [self removeProgressTimer];

    [self addProgressTimer];

    

    self.playOrPauseBtn.selected = YES;

}


- (void)layoutSubviews

{

    [super layoutSubviews];

    

    self.playerLayer.frame = self.bounds;

}


#pragma mark - 设置播放的视频

//实例化playerItem对象的时候执行这个方法

- (void)setPlayerItem:(AVPlayerItem *)playerItem

{

    _playerItem = playerItem;

 

////////////////////////////////////////////////////////////////////////////////

    

    //这是在执行第二步,在第一步,布局初始化时,AVPlayer 并没有 AVPlayerItemAVPlayer 提供了 - (void)replaceCurrentItemWithPlayerItem:(nullable AVPlayerItem *)item;  方法,用于切换视频。

    [self.player replaceCurrentItemWithPlayerItem:playerItem];

    

////////////////////////////////////////////////////////////////////////////////

    

    //第三步,注册观察者,观察status属性。

    [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

    //播放

    [self.player play];

}


    // 执行观察者方法

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {

    AVPlayerItem *item = (AVPlayerItem *)object;

    if (item.status == AVPlayerItemStatusReadyToPlay) {

        [self.progressView stopAnimating];

    }

}


///////////////////////////////////////////////////////////////////////////////////////


// 是否显示工具的View

- (IBAction)tapAction:(UITapGestureRecognizer *)sender {

    [UIView animateWithDuration:0.5 animations:^{

        if (self.isShowToolView) {

            self.toolView.alpha = 0;//隐藏

            self.isShowToolView = NO;

        } else {

            self.toolView.alpha = 1;

            self.isShowToolView = YES;

        }

    }];

}

//

-(void)dealloc {

    [self.playerItem removeObserver:self forKeyPath:@"status"];

    [self.player replaceCurrentItemWithPlayerItem:nil];

}


/////////////////////////////////////////////////////////////////////////


//第四步:播放过程中响应:播放、 暂停、

// 暂停按钮的监听

- (IBAction)playOrPause:(UIButton *)sender {

    sender.selected = !sender.selected;

    if (sender.selected) {

        [self.player play];

        [self addProgressTimer];

    } else {

        [self.progressView stopAnimating];

        [self.player pause];

        [self removeProgressTimer];

    }

}


/////////////////////////////////////////////////////////////////////////


- (void)suspendPlayVideo {

    [self.progressView stopAnimating];

    

    self.playOrPauseBtn.selected = NO;

    self.toolView.alpha = 1;

    self.isShowToolView = YES;

    

    [self.player pause];

    

    [self removeProgressTimer];

}


#pragma mark - 时器操作

- (void)addProgressTimer

{

    self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgressInfo) userInfo:nil repeats:YES];

    [[NSRunLoop mainRunLoop] addTimer:self.progressTimer forMode:NSRunLoopCommonModes];

}


- (void)removeProgressTimer

{

    [self.progressTimer invalidate];

    self.progressTimer = nil;

}


- (void)updateProgressInfo

{

    // 1.更新时间

    self.timeLabel.text = [self timeString];

    

    // 2.设置进度条的value,CMTimeGetSeconds(self.player.currentItem.duration)的意思是获取要播放的视频的总秒数

    

    self.progressSlider.value = CMTimeGetSeconds(self.player.currentTime) / CMTimeGetSeconds(self.player.currentItem.duration);

}


- (NSString *)timeString

{

    NSTimeInterval duration = CMTimeGetSeconds(self.player.currentItem.duration);

    NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentTime);

    

    return [self stringWithCurrentTime:currentTime duration:duration];

}


// 换屏幕的方向

- (IBAction)switchOrientation:(UIButton *)sender {

    sender.selected = !sender.selected;

    if ([self.delegate respondsToSelector:@selector(videoplayViewSwitchOrientation:)]) {

        [self.delegate videoplayViewSwitchOrientation:sender.selected];

    }

}


- (IBAction)slider {

    [self addProgressTimer];

    NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * self.progressSlider.value;

    

    // 设置当前播放时间,NSEC_PER_SEC是默认值为1

    [self.player seekToTime:CMTimeMakeWithSeconds(currentTime, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];

    

    [self.player play];

}


- (IBAction)startSlider {

    [self removeProgressTimer];

}


- (IBAction)sliderValueChange {

    NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * self.progressSlider.value;

    NSTimeInterval duration = CMTimeGetSeconds(self.player.currentItem.duration);

    self.timeLabel.text = [self stringWithCurrentTime:currentTime duration:duration];

}


- (NSString *)stringWithCurrentTime:(NSTimeInterval)currentTime duration:(NSTimeInterval)duration

{

    

    NSInteger dMin = duration / 60// 要播放的视频的总分数。

    NSInteger dSec = (NSInteger)duration % 60; // 总的分数取出后剩余要播放的秒数

    

    NSInteger cMin = currentTime / 60// 现在播放的分数。

    NSInteger cSec = (NSInteger)currentTime % 60; // 现在播放了的秒数

    

    dMin = dMin<0?0:dMin;

    dSec = dSec<0?0:dSec;

    cMin = cMin<0?0:cMin;

    cSec = cSec<0?0:cSec;


    NSString *durationString = [NSString stringWithFormat:@"%02ld:%02ld", (long)dMin, (long)dSec];

    NSString *currentString = [NSString stringWithFormat:@"%02ld:%02ld", (long)cMin, (long)cSec];

    

    return [NSString stringWithFormat:@"%@/%@", currentString, durationString];

}


-(void)resetPlayView {

    [self suspendPlayVideo];

    

    [self.playerLayer removeFromSuperlayer];

    // PlayerItemnil

    [self.player replaceCurrentItemWithPlayerItem:nil];

    // playernil

    self.player = nil;

    

    [self removeFromSuperview];


}


@end



播放视频AVPlayer使用详解_第3张图片

其中上面有一个代理方法是

[self.delegate videoplayViewSwitchOrientation:sender.selected];这个方法的实现在另一个控制器中,内容为:

#pragma mark VideoPlayViewDelegate 视频播放时窗口模式与全屏模式切换

- (void)videoplayViewSwitchOrientation:(BOOL)isFull

{

    if (isFull) {

        self.isFullScreenPlaying = YES;

        [self presentViewController:self.fullVc animated:YES completion:^{

            self.playView.frame = self.fullVc.view.bounds;

            [self.fullVc.view addSubview:self.playView];

        }];

    } else {

        [self.fullVc dismissViewControllerAnimated:YES completion:^{

            self.playView.frame = self.currentSelectedCell.video.videoFrame;

            [self.currentSelectedCell addSubview:self.playView];

            self.isFullScreenPlaying = NO;


        }];

        

    }

}


#pragma mark - 懒加载代码

- (FullViewController *)fullVc

{

    if (_fullVc == nil) {

        self.fullVc = [[FullViewController alloc] init];

    }

    

    return _fullVc;

}


FullViewController 控制器里面的内容是:


#import "FullViewController.h"


@interface FullViewController ()


@end


@implementation FullViewController


- (instancetype)init

{

    if (self = [super init]) {

        // self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

    }

    return self;

}


// 当点击了那个按钮后,进入这个控制器的时候会自动执行这个方法,屏幕旋转后播放视频。


- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

    return UIInterfaceOrientationMaskLandscapeLeft;

}


@end


控制器的frame已经给了,view也给了,就不用写什么内容了。



你可能感兴趣的:(播放视频AVPlayer使用详解)