使用系统相机录像,使用的AVFoundation框架。首先了解一下框架的使用。
一、录制的相关类有:
1、AVCaptureSession
媒体(音、视频)捕获会话,负责把捕获的音视频数据输出到输出设备中。一个AVCaptureSession可以有多个输入输出。
2、AVCaptureDevice
输入设备,包括麦克风、摄像头,通过该对象可以设置物理设备的一些属性(例如相机聚焦、白平衡等)。
3、AVCaptureDeviceInput
设备输入数据管理对象,可以根据AVCaptureDevice创建对应AVCaptureDeviceInput对象,该对象将会被添加到AVCaptureSession中管理。
4、AVCaptureOutput
输出数据管理对象,用于接收各类输出数据,通常使用对应的子类AVCaptureAudioDataOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureFileOutput,该对象将会被添加到AVCaptureSession中管理。注意:前面几个对象的输出数据都是NSData类型,而AVCaptureFileOutput代表数据以文件形式输出,类似的,AVCcaptureFileOutput也不会直接创建使用,通常会使用其子类:AVCaptureAudioFileOutput、AVCaptureMovieFileOutput。当把一个输入或者输出添加到AVCaptureSession之后AVCaptureSession就会在所有相符的输入、输出设备之间建立连接(AVCaptionConnection)。
5、AVCaptureVideoPreviewLayer
相机拍摄预览图层,是CALayer的子类,使用该对象可以实时查看拍照或视频录制效果,创建该对象需要指定对应的AVCaptureSession对象。

二、使用AVFoundation拍照和录制视频的一般步骤如下:
1、创建AVCaptureSession对象。
2、使用AVCaptureDevice的静态方法获得需要使用的设备,例如拍照和录像就需要获得摄像头设备,录音就要获得麦克风设备。
3、利用输入设备AVCaptureDevice初始化AVCaptureDeviceInput对象。
4、初始化输出数据管理对象,如果要拍照就初始化AVCaptureStillImageOutput对象;如果拍摄视频就初始化AVCaptureMovieFileOutput对象。
5、将数据输入对象AVCaptureDeviceInput、数据输出对象AVCaptureOutput添加到媒体会话管理对象AVCaptureSession中。
6、创建视频预览图层AVCaptureVideoPreviewLayer并指定媒体会话,添加图层到显示容器中,调用AVCaptureSession的startRuning方法开始捕获。
7、将捕获的音频或视频数据输出到指定文件。

介绍完录制视频,要介绍一下播放器的使用。使用的也是AVFoundation框架中的类是AVPlayer
AVPlayer本身并不能显示视频,而且它也不像MPMoviePlayerController有一个view属性。如果AVPlayer要显示必须创建一个播放器层AVPlayerLayer用于展示,播放器层继承于CALayer,有了AVPlayerLayer之添加到控制器视图的layer中即可。要使用AVPlayer首先了解一下几个常用的类:

1、AVAsset:主要用于获取多媒体信息,是一个抽象类,不能直接使用。

2、AVURLAsset:AVAsset的子类,可以根据一个URL路径创建一个包含媒体信息的AVURLAsset对象。

3、AVPlayerItem:一个媒体资源管理对象,管理者视频的一些基本信息和状态,一个AVPlayerItem对应着一个视频资源。

简单介绍AVFoundation框架之后,放上一个自己写的小demo,类似于微信的视频录制。能保存到相册。效果图如下:

具体代码如下:
ViewController.m中:

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import "UserDefine.h"typedef NS_ENUM(NSInteger,VideoStatus){VideoStatusEnded = 0,VideoStatusStarted
};@interface ViewController ()<AVCaptureFileOutputRecordingDelegate>{   //拍摄视频相关AVCaptureSession * _captureSession;/**< 是一个会话对象,是设备音频/视频整个录制期间的管理者. */AVCaptureDevice *_videoDevice;/**< 视频设备 */AVCaptureDevice *_audioDevice;/**< 音频设备 */AVCaptureDeviceInput *_videoInput;/**< 视频输入 */AVCaptureDeviceInput *_audioInput;/**< 音频输入 */AVCaptureMovieFileOutput *_movieOutput;/**< 视频输出 */AVCaptureVideoPreviewLayer *_captureVideoPreviewLayer;/**< 预览拍摄过程中的图像 *///播放相关AVPlayer *_player;/**< 播放器对象 */AVPlayerItem *_playItem;/**< 一个媒体资源管理对象,管理者视频的一些基本信息和状态,一个AVPlayerItem对应着一个视频资源 */AVPlayerLayer *_playerLayer;BOOL _isPlaying;}@property (strong, nonatomic) UIView *recordingView;/**<  */@property (strong, nonatomic) UIButton *recordingButton;/**< 录制按钮 */@property (strong, nonatomic) UILabel *timeLabel;/**< 倒计时时间 */@property (strong, nonatomic) UIButton *playButton;/**< 播放按钮 */@property (nonatomic,assign) VideoStatus status;@property (nonatomic,assign) BOOL canSave;@property (nonatomic,strong) CADisplayLink *link;@property (strong, nonatomic) NSURL *videoUrl;/**< 视频URL */
@end@implementation ViewController
static float CountdownTime = 15 * 60;//倒计时时间,时间为15s,* 60 因为CADisplayLink 1/60秒刷新一次
- (void)viewDidLoad {[super viewDidLoad];[self setUILayout];[self getAuthorization];//对视频播放完进行监听[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:)name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}
-(void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];
}
-(void)viewDidDisappear:(BOOL)animated{[super viewDidDisappear:animated];//移除通知[[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}
#pragma mark - ****************  界面布局
-(void)setUILayout{self.view.backgroundColor = RGBColor(245, 245, 245);CGFloat jianGe = 20;CGFloat btnH = 30;CGFloat btnW = 120;CGFloat lblH = 40;CGFloat lblW = 120;CGFloat boFangH = 160;_recordingView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_W, SCREEN_H/2)];_recordingView.backgroundColor = [UIColor blackColor];[self.view addSubview:_recordingView];_timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(self.view.center.x - lblW/2, _recordingView.frame.size.height + _recordingView.frame.origin.y + lblH, lblW, lblH)];_timeLabel.hidden = NO;_timeLabel.text = [NSString stringWithFormat:@"倒计时:%d秒",(int)(CountdownTime/60)];_timeLabel.textAlignment = NSTextAlignmentCenter;_timeLabel.font = [UIFont systemFontOfSize:18.0];_timeLabel.textColor = RGBColor(217, 28, 26);[self.view addSubview:_timeLabel];_recordingButton = [UIButton buttonWithType:UIButtonTypeCustom];_recordingButton.frame = CGRectMake(self.view.center.x - btnW/2, _timeLabel.frame.size.height + _timeLabel.frame.origin.y + jianGe, btnW, btnH);[_recordingButton setTitle:@"开始录制" forState:UIControlStateNormal];[_recordingButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];_recordingButton.backgroundColor = RGBColor(217, 28, 26);_recordingButton.titleLabel.font = [UIFont fontWithName:@"STHeitiSC-Light" size:14.0];_recordingButton.layer.cornerRadius = 3;[_recordingButton addTarget:self action:@selector(recordButton:) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:_recordingButton];_playButton = [UIButton buttonWithType:UIButtonTypeCustom];_playButton.frame = CGRectMake(0, 0, boFangH, boFangH);_playButton.center = _recordingView.center;[_playButton setImage:[UIImage imageNamed:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];_playButton.hidden = YES;[_playButton addTarget:self action:@selector(playButton:) forControlEvents:UIControlEventTouchUpInside];[_recordingView addSubview:_playButton];}
#pragma mark - **************** Button 方法
/***  点击录制**  @param sender*/
-(void)recordButton:(UIButton *)sender{if ([sender.titleLabel.text isEqualToString:@"开始录制"]) {[self startAnimation];}else{[self saveVideo:_videoUrl];}}
/***  点击播放**  @param sender*/
-(void)playButton:(UIButton *)sender{[_player play];_playButton.hidden = YES;
}
- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];// Dispose of any resources that can be recreated.
}
#pragma mark - **************** 视频录制相关
#pragma mark -- 获取授权
-(void)getAuthorization{//此处获取摄像头授权switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) {case AVAuthorizationStatusAuthorized://已授权可以使用{NSLog(@"授权成功!");[self setupAVCaptureInfo];}break;case AVAuthorizationStatusNotDetermined://未授权{//则再次请求授权[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {if (granted) {//授权成功[self setupAVCaptureInfo];return;}else{//授权失败return;}}];}break;default:    //用户拒绝授权/未授权break;}
}
#pragma mark - 设置相关信息
-(void)setupAVCaptureInfo{[self addSession];//开始配置视频的会话对象[_captureSession beginConfiguration];[self addVideo];[self addAudio];[self addPreviewLayer];//提交配置[_captureSession commitConfiguration];//开启会话----> 不等于开始录制[_captureSession startRunning];
}
/***  设置视频的会话对象*/
-(void)addSession{_captureSession = [[AVCaptureSession alloc]init];//设置视频分辨率//注意,这个地方设置的模式/分辨率大小将影响后面的拍摄质量if ([_captureSession canSetSessionPreset:AVAssetExportPreset640x480]) {[_captureSession setSessionPreset:AVAssetExportPreset640x480];}
}
/***  设置视频设备*/
-(void)addVideo{_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];//AVCaptureDevicePositionBack -- 后摄像头[self addVideoInput];[self addMovieOutput];
}
/***  设置视频输入对象*/
-(void)addVideoInput{NSError *videoError;//视频输入对象//根据输入设备初始化输入对象,用户获取输入数据_videoInput = [[AVCaptureDeviceInput alloc]initWithDevice:_videoDevice error:&videoError];if (videoError) {NSLog(@"-------取得摄像头设备时出错---%@",[videoError localizedDescription]);return;}//将视频输入对象添加到会话(AVCaptureSession)中if ([_captureSession canAddInput:_videoInput]) {[_captureSession addInput:_videoInput];}
}
/***  设置视频输出对象*/
-(void)addMovieOutput{//拍摄视频输出对象//初始化输出设备对象,用户获取输出数据_movieOutput = [[AVCaptureMovieFileOutput alloc] init];if ([_captureSession canAddOutput:_movieOutput]) {[_captureSession addOutput:_movieOutput];//设置连接管理对象AVCaptureConnection *captureConnection = [_movieOutput connectionWithMediaType:AVMediaTypeVideo];//视频稳定设置if ([captureConnection isVideoStabilizationSupported]) {captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;}//视频旋转方向的设置captureConnection.videoScaleAndCropFactor = captureConnection.videoMaxScaleAndCropFactor;}
}
/***  设置音频设备*/
-(void)addAudio{NSError *audioError;//添加一个音频设备_audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];// 音频输入对象_audioInput = [[AVCaptureDeviceInput alloc]initWithDevice:_audioDevice error:&audioError];if (audioError) {NSLog(@"取得录音设备时出错 ------ %@",audioError);return;}//将音频输入对象添加到会话 (AVCaptureSession) 中if ([_captureSession canAddInput:_audioInput]) {[_captureSession addInput:_audioInput];}
}
/***  设置预览层*/
-(void)addPreviewLayer{[self.view layoutIfNeeded];//通过会话(AVCaptureSession)创建预览图层_captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:_captureSession];_captureVideoPreviewLayer.frame = self.view.layer.bounds;//如果预览图层和视频方向不一致,可以修改这个_captureVideoPreviewLayer.connection.videoOrientation = [_movieOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation;//设置captureVideoPreviewLayer在父视图中的位置_captureVideoPreviewLayer.position = CGPointMake(self.view.frame.size.width*0.5,self.recordingView.frame.size.height*0.5);//显示在视图表面的图层CALayer *layer = self.recordingView.layer;layer.masksToBounds = YES;[self.view layoutIfNeeded];[layer addSublayer:_captureVideoPreviewLayer];
}
-(void)startAnimation{if (self.status == VideoStatusEnded) {self.status = VideoStatusStarted;[UIView animateWithDuration:0.5 animations:^{} completion:^(BOOL finished) {[self stopLink];[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];}];}
}
-(void)stopAnimation{if (self.status == VideoStatusStarted) {self.status = VideoStatusEnded;[self stopLink];[self stopRecord];_playButton.hidden = NO;[UIView animateWithDuration:0.5 animations:^{[_recordingButton setTitle:@"保存到相册" forState:UIControlStateNormal];} completion:^(BOOL finished) {}];}
}-(CADisplayLink *)link{if (!_link) {_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(refresh:)];[self startRecord];}return _link;
}
-(void)stopLink{_link.paused = YES;[_link invalidate];_link = nil;
}
-(void)refresh:(CADisplayLink *)link{if (CountdownTime <= 0) {CountdownTime = 15 * 60;[self recordComplete];[self stopAnimation];_timeLabel.hidden = YES;return;}CountdownTime -= 1;NSLog(@"%f",CountdownTime);_timeLabel.text = [NSString stringWithFormat:@"倒计时:%d秒",(int)(CountdownTime/60)];
}
/***  获取录制视频的地址**  @return outPutFileURL   */
- (NSURL *)outPutFileURL
{return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"outPut.mov"]];
}- (void)startRecord
{[_movieOutput startRecordingToOutputFileURL:[self outPutFileURL] recordingDelegate:self];
}
- (void)stopRecord
{// 取消视频拍摄[_movieOutput stopRecording];
}- (void)recordComplete
{self.canSave = YES;
}
//这个在完全退出小视频时调用
- (void)quit
{[_captureSession stopRunning];
}- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{NSLog(@"---- 开始录制 ----");
}- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{NSLog(@"---- 录制结束 ---%@-%@ ",outputFileURL,captureOutput.outputFileURL);if (outputFileURL.absoluteString.length == 0 && captureOutput.outputFileURL.absoluteString.length == 0 ) {return;}if (self.canSave) {_videoUrl = outputFileURL;self.canSave = NO;[self creatPlayView];}
}#pragma mark - 获取摄像头-->前/后
-(AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position{NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];AVCaptureDevice *captureDevice = devices.firstObject;for (AVCaptureDevice *device in devices) {if (device.position == position) {captureDevice = device;break;}}return captureDevice;
}
#pragma mark - **************** 播放相关
-(void)creatPlayView{NSLog(@"%@",_videoUrl);[_captureVideoPreviewLayer removeFromSuperlayer];[self.view layoutIfNeeded];_playItem = [AVPlayerItem playerItemWithURL:self.videoUrl];_player = [AVPlayer playerWithPlayerItem:_playItem];_playerLayer =[AVPlayerLayer playerLayerWithPlayer:_player];_playerLayer.frame = _recordingView.frame;_playerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//视频填充模式_playerLayer.position = CGPointMake(self.view.frame.size.width*0.5,self.recordingView.frame.size.height*0.5);CALayer *layer = self.recordingView.layer;layer.masksToBounds = true;[self.view layoutIfNeeded];[layer addSublayer:_playerLayer];[self.recordingView bringSubviewToFront:_playButton];
}
#pragma mark - 视频播放通知回调
-(void)playbackFinished:(NSNotification *)notification
{[_player seekToTime:CMTimeMake(0, 1)];_playButton.hidden = NO;
}
#pragma mark - **************** 压缩保存
- (NSURL *)compressedURL
{return [NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"compressed.mp4"]]];
}- (CGFloat)fileSize:(NSURL *)path
{return [[NSData dataWithContentsOfURL:path] length]/1024.00 /1024.00;
}// 压缩视频
-(void)saveVideoWithUrl:(NSURL *)url
{NSLog(@"开始压缩,压缩前大小 %f MB",[self fileSize:url]);AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:url options:nil];NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:AVAssetExportPreset640x480];exportSession.outputURL = [self compressedURL];//优化网络exportSession.shouldOptimizeForNetworkUse = true;//转换后的格式exportSession.outputFileType = AVFileTypeMPEG4;//异步导出[exportSession exportAsynchronouslyWithCompletionHandler:^{// 如果导出的状态为完成if ([exportSession status] == AVAssetExportSessionStatusCompleted) {NSLog(@"压缩完毕,压缩后大小 %f MB",[self fileSize:[self compressedURL]]);[self saveVideo:[self compressedURL]];}else{NSLog(@"当前压缩进度:%f",exportSession.progress);}}];}
}- (void)saveVideo:(NSURL *)outputFileURL
{ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];[library writeVideoAtPathToSavedPhotosAlbum:outputFileURLcompletionBlock:^(NSURL *assetURL, NSError *error) {if (error) {NSLog(@"保存视频失败:%@",error);} else {NSLog(@"保存视频到相册成功");}}];
}
@end

附上demo下载地址:http://download.csdn.net/detail/qq_34195670/9589592
github下载地址:https://github.com/goingmyway1/RecordingVideoDemo

以上如有错误,请留言指正,谢谢!

调用系统相机录像,压缩保存到相册(附仿微信视频录制demo)相关推荐

  1. android系统相机自动录像,android 调用系统相机录像并保存

    1.在AndroidManifest.xml中添加如下代码 tools:ignore="ProtectedPermissions" /> android:authoritie ...

  2. 安卓调用系统相机录像并上传到后端服务器

    安卓调用系统相机录像并上传到后端服务器 写在前面 一.录像上传的思路 二.添加相关权限 三.按钮设置监听,调用相机录像并回调 1.按钮设置监听: 2.调用代码 3.回调代码(划重点奥) 最后的最后: ...

  3. Android调用系统相机拍照并保存到指定位置

    Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto)void onclick() {Intent intent = new Intent(MediaSt ...

  4. android固定位置拍照,Android调用系统相机拍照并保存到指定位置

    Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto) void onclick() { Intent intent = new Intent(Media ...

  5. 关于调用系统相机以及压缩照片

    style="DISPLAY: none" frameborder="0"> style="Z-INDEX: 9999; POSITION: a ...

  6. android中webview使用打开系统相机录像_有没有什么高效使用微信的经验?

    看了下前面的几个高赞的回答,通过个人习惯达到高效的目的的比较多.关注师兄的都知道,别人都走的路咱不走,就喜欢整点不一样的,因为刺激~ 从 Android 系统上,微信其实还有很多潜力可以挖掘,今天就跟 ...

  7. 如何修改WebUpload上传文件默认调用系统相机,而不是手机相册?

    WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览 ...

  8. Android实现调用系统相机录像及实现录音

    录像实现原理特别简单,先在配置文件中声明一下权限,这个就不说了,然后直接使用Intent跳转就行. Intent intent = new Intent(MediaStore.ACTION_VIDEO ...

  9. WIN10系统相机能正常使用,但第三方软件(微信视频,钉钉会议等)打开摄像头时正常打开,但是黑屏【安装了火绒版】解决方法。

    这是突然要用视频会议考试的时候打不开视频,网上写的重装系统,重装驱动,工具升级之类都试过了都不成, 但是在重装系统之后,我点开了隐藏的图标,熟悉的火绒上有一个红色的提示 在以为他又拦截了什么广告的时候 ...

最新文章

  1. Python 之Re模块(正则表达式)
  2. 2021年的最后7天,和我的伙伴们合个影吧
  3. php sqlsrv 下载,php_sqlsrv_ts.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家...
  4. Xamarin效果第十八篇之GIS中复合型Mark
  5. Java容器Stack
  6. macos安装盘第三方工具制作_简单制作OSXYosemite10.10正式版U盘USB启动安装盘方法教程(全新安装Mac系统)下载|异次元软件世界...
  7. Java快速入门学习笔记7 | Java语言中的类与对象
  8. docker安装文档
  9. 护航亚运|安恒信息推出“九维五星” ,并强调将全面突出“智能亚运”
  10. 笑谈ArcToolbox (5) 非我族类
  11. Android Studio第三十六期 - 模块化Activity管理Fragment
  12. python升级导致yum命令无法使用的解决办法(修改版)
  13. NextPermutation,寻找下一个全排列
  14. 2021-2027全球与中国数控龙门镗铣床市场现状及未来发展趋势
  15. Web全栈工程师应该会什么?
  16. CPU内部看门狗,外部看门狗以及软件看门狗
  17. java学生奖学金管理系统_java毕业设计_springboot框架的高校学生奖学金评定系统...
  18. 献给2012——易水寒的心声
  19. 微信公众号创建菜单注意问题
  20. java 父委托机制优点_Java虚拟机父类委托机制设计的优点

热门文章

  1. 微信小程序组件化开发框架wepy 学习(三)
  2. 怎么把好几行弄成一行_【excle 如何多行变一行】excel中怎么把多行同一个人的数据变成一行?...
  3. vue官方示例_树形视图总结
  4. Anaconda中出现 ImportError: No module named conda.cli
  5. VUE项目打包后posy代理失效Nginx解决
  6. 【CentOS7安装Redis及常用命令】
  7. 《曾有一个人 爱我如生命》——普希金诗词
  8. 安卓生成keystore和查看keystore
  9. 爬虫----b站弹幕
  10. 《阿里巴巴开发手册》读书笔记-编程规约