在iOS中处理视频播放一般可以使用MPMoviePlayerViewController或者AVPlayer

一、MPMoviePlayerViewController的使用

MPMoviePlayerViewController是系统封装的一个播放器控制器,其中对于视频的控制由其属性@property (nonatomic, readonly) MPMoviePlayerController *moviePlayer;负责。

1.创建使用

NSURL *URL = [NSURL fileURLWithPath:_videoPath];
        _player = [[MPMoviePlayerViewController alloc] initWithContentURL:URL];
        _player.moviePlayer.controlStyle = MPMovieControlStyleNone;//不显示控制控件
        _player.moviePlayer.repeatMode = MPMovieRepeatModeNone;//不循环播放
        _player.moviePlayer.scalingMode =MPMovieScalingModeAspectFill;//保存宽高比,填满视图
        [_player.moviePlayer prepareToPlay];
        [_player.moviePlayer play];播放

若要将播放器视图加到某个view上,要这样写

[self.view addSubview:_player.view];

2.播放状态的监控处理

有时候,播放器开始播放的时候,会有一点黑屏的缓冲加载时间,感觉上会先黑屏一下才出现视频,为了视频加载的时候不显示黑屏,一般可先覆盖一张图片(比如视频第一帧),等待视频加载完成才隐藏图片播放视频。这种场景下便需要监听播放器的通知了。

MPMoviePlayerViewController的状态监控可通过moviePlayer的发出的通知来接收。下面介绍下常用到的。

a.状态改变

[self addObserver:@selector(loadStatusChanged:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
- (void)loadStatusChanged:(NSNotification *)notification {
    MPMoviePlayerController *player = notification.object;
    if ([player isEqual: _player.moviePlayer] && (player.loadState & MPMovieLoadStatePlayable)) {
        [player play];//现在才播放
        [_coverView removeFromSuperview];//移除遮盖图片
    }
}

b.视频播放结束(失败)

[self addObserver:@selector(playDidFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
- (void)playDidFinished:(NSNotification *)notification {
    MPMoviePlayerController *player = notification.object;
    if (![player isEqual:_player.moviePlayer]) {
        return;
    }
    NSDictionary *notificationUserInfo = [notification userInfo];
    NSNumber *resultValue = [notificationUserInfo objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
    MPMovieFinishReason reason = [resultValue intValue];
    if (reason == MPMovieFinishReasonPlaybackError)
    {
        NSError *mediaPlayerError = [notificationUserInfo objectForKey:@"error"];
        if (mediaPlayerError) {
            GLLoge(@"动画播放失败: %@", [mediaPlayerError localizedDescription]);
        } else {
            GLLoge(@"动画播放出错了");
        }
    }
}

注意:

不可以同时加载播放两个以上的MPMoviePlayerViewController,多个播放器最终只有一个播放能生效,通知也只能收到一个播放器发出的。

二,AVPlayer的使用

AVPlayer相对于MPMoviePlayerViewController更为底层,功能更强大。

需要引入库#import <AVFoundation/AVFoundation.h>

1.创建使用

@property (nonatomic)AVPlayer *player;
@property (nonatomic)AVPlayerItem *playerItem;

_playerItem=[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"launch" withExtension:@"mp4"]]; //创建播放源对象

_player=[AVPlayer playerWithPlayerItem:self.playerItem];//播放器对象

AVPlayerLayer *layer=[AVPlayerLayer playerLayerWithPlayer:self.player];
    layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
    layer.frame=[UIScreen mainScreen].bounds;
    layer.backgroundColor=[[UIColor whiteColor] CGColor];
    [self.layer addSublayer:layer];//必须使用AVPlayerLayer加到view的layer中,否则看不到视频

[_player play];

2.AVPlayer的状态监控

AVPlayer是没有循环播放模式的,但可以通过状态监控,在视频播放完后,从头再播放。它的播放控制和各种状态是通过其播放源AVPlayerItem来监控的。

a.播放完成监控(可实现循环播放)

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runLoopTheMovie:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
- (void)runLoopTheMovie:(NSNotification *)notification{
    //注册的通知  可以自动把 AVPlayerItem 对象传过来,只要接收一下就OK

    AVPlayerItem * playItem = [notification object];
    //关键代码
    [playItem seekToTime:kCMTimeZero];//时间拨到0,重新开始

    [_player play];
}

b.状态改变和缓冲进度,可处理遮盖图片避免闪黑屏以及加载进度的显示

[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];// 监听status属性
 [self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];// 监听loadedTimeRanges 缓冲属性
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{

    AVPlayerItem *playerItem = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
        if ([playerItem status] == AVPlayerStatusReadyToPlay) {
            NSLog(@"AVPlayerStatusReadyToPlay");

            //隐藏遮盖图片
            [UIView animateWithDuration:0.3 animations:^{
                self.coverImageView.alpha=0;
            } completion:^(BOOL finish){
                if (finish) {
                    self.coverImageView.hidden=YES;
                }

            }];

        } else if ([playerItem status] == AVPlayerStatusFailed) {
            GLLoge(@"动画播放失败");

        }
    }

    else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
     NSTimeInterval timeInterval = [self availableDuration];// 计算缓冲进度
     NSLog(@"Time Interval:%f",timeInterval);
     CMTime duration = self.playerItem.duration;
     CGFloat totalDuration = CMTimeGetSeconds(duration);
     [self.videoProgress setProgress:timeInterval / totalDuration animated:YES];
     }
}

- (NSTimeInterval)availableDuration {
    NSArray *loadedTimeRanges = [[self.playerView.player currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度
    return result;
}

- (NSString *)convertTime:(CGFloat)second{
    NSDate *d = [NSDate dateWithTimeIntervalSince1970:second];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    if (second/3600 >= 1) {
        [formatter setDateFormat:@"HH:mm:ss"];
    } else {
        [formatter setDateFormat:@"mm:ss"];
    }
    NSString *showtimeNew = [formatter stringFromDate:d];
    return showtimeNew;
}

这里附上取视频第一帧的代码:

//获取视频第一帧图像
- (UIImage*)getCoverImage{

    AVURLAsset *asset = [AVURLAsset assetWithURL:[[NSBundle mainBundle] URLForResource:@"launch" withExtension:@"mp4"]];

    NSParameterAssert(asset);

    AVAssetImageGenerator *assetImageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];

    assetImageGenerator.appliesPreferredTrackTransform =YES;

    assetImageGenerator.apertureMode =AVAssetImageGeneratorApertureModeEncodedPixels;

    CGImageRef thumbnailImageRef = NULL;

    NSError *thumbnailImageGenerationError = nil;

    CMTime time = CMTimeMakeWithSeconds(0.0, 600);

    thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:time actualTime:NULL error:&thumbnailImageGenerationError];

    if (!thumbnailImageRef)
        NSLog(@"thumbnailImageGenerationError %@", thumbnailImageGenerationError);



    UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc] initWithCGImage:thumbnailImageRef] :nil;

    CGImageRelease(thumbnailImageRef);

    return thumbnailImage;

}