iOS仿微信相机拍照、视频录制功能

2020-01-21 05:33:08王振洲

网上有很多自定义相机的例子,这里只是我临时写的一个iOS自定义相机(仿微信)拍照、视频录制demo,仅供参考:

用到了下面几个库:


#import <AVFoundation/AVFoundation.h> 
#import <AssetsLibrary/AssetsLibrary.h>

在使用的时候需要在Info.plist中把相关权限写进去:


Privacy - Microphone Usage Description 
Privacy - Photo Library Usage Description 
Privacy - Camera Usage Description

我在写这个demo时,是按照微信的样式写的,同样是点击拍照、长按录制视频,视频录制完直接进行播放,这里封装了一个简易的播放器:

m文件


#import "HAVPlayer.h"
#import <AVFoundation/AVFoundation.h>

@interface HAVPlayer ()

@property (nonatomic,strong) AVPlayer *player;//播放器对象

@end

@implementation HAVPlayer

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
 // Drawing code
}
*/

- (instancetype)initWithFrame:(CGRect)frame withShowInView:(UIView *)bgView url:(NSURL *)url {
 if (self = [self initWithFrame:frame]) {
  //创建播放器层
  AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
  playerLayer.frame = self.bounds;

  [self.layer addSublayer:playerLayer];
  if (url) {
   self.videoUrl = url;
  }

  [bgView addSubview:self];
 }
 return self;
}

- (void)dealloc {
 [self removeAvPlayerNtf];
 [self stopPlayer];
 self.player = nil;
}

- (AVPlayer *)player {
 if (!_player) {
  _player = [AVPlayer playerWithPlayerItem:[self getAVPlayerItem]];
  [self addAVPlayerNtf:_player.currentItem];

 }

 return _player;
}

- (AVPlayerItem *)getAVPlayerItem {
 AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:self.videoUrl];
 return playerItem;
}

- (void)setVideoUrl:(NSURL *)videoUrl {
 _videoUrl = videoUrl;
 [self removeAvPlayerNtf];
 [self nextPlayer];
}

- (void)nextPlayer {
 [self.player seekToTime:CMTimeMakeWithSeconds(0, _player.currentItem.duration.timescale)];
 [self.player replaceCurrentItemWithPlayerItem:[self getAVPlayerItem]];
 [self addAVPlayerNtf:self.player.currentItem];
 if (self.player.rate == 0) {
  [self.player play];
 }
}

- (void) addAVPlayerNtf:(AVPlayerItem *)playerItem {
 //监控状态属性
 [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
 //监控网络加载情况属性
 [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}

- (void)removeAvPlayerNtf {
 AVPlayerItem *playerItem = self.player.currentItem;
 [playerItem removeObserver:self forKeyPath:@"status"];
 [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
 [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)stopPlayer {
 if (self.player.rate == 1) {
  [self.player pause];//如果在播放状态就停止
 }
}

/**
 * 通过KVO监控播放器状态
 *
 * @param keyPath 监控属性
 * @param object 监视器
 * @param change 状态改变
 * @param context 上下文
 */
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
 AVPlayerItem *playerItem = object;
 if ([keyPath isEqualToString:@"status"]) {
  AVPlayerStatus status= [[change objectForKey:@"new"] intValue];
  if(status==AVPlayerStatusReadyToPlay){
   NSLog(@"正在播放...,视频总长度:%.2f",CMTimeGetSeconds(playerItem.duration));
  }
 }else if([keyPath isEqualToString:@"loadedTimeRanges"]){
  NSArray *array=playerItem.loadedTimeRanges;
  CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围
  float startSeconds = CMTimeGetSeconds(timeRange.start);
  float durationSeconds = CMTimeGetSeconds(timeRange.duration);
  NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
  NSLog(@"共缓冲:%.2f",totalBuffer);
 }
}

- (void)playbackFinished:(NSNotification *)ntf {
 Plog(@"视频播放完成");
 [self.player seekToTime:CMTimeMake(0, 1)];
 [self.player play];
}

@end