在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;
}