在写这个的时候查了好多资料,看了大家写的都基本一样,今天就当笔记一样分享给大家。
1:写一“按下去”按钮;
#import#import "AnnularProgress.h"
@interface PhotographBtu : UIView
@property(nonatomic, strong)AnnularProgress *photoTimeProgressView;
@property(nonatomic, strong)UIButton *photoBtu;
@end
#import "PhotographBtu.h"
#define photoBtuWiDTH 100
@implementation PhotographBtu
-(instancetype)init{
self = [super init];
if (self) {
[self createPhotoBtu];
}
return self;
}
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self createPhotoBtu];}
return self;
}
-(void)awakeFromNib{
[super awakeFromNib];}
-(void)createPhotoBtu{
self.photoBtu = [UIButton buttonWithType:UIButtonTypeCustom];
NSLog(@"%f====%f",self.center.x ,self.center.y);
self.photoBtu.center = self.center;
[self.photoBtu setTitle:@"按住拍" forState:UIControlStateNormal];
[self.photoBtu setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
self.photoBtu.titleLabel.font = [UIFont systemFontOfSize:14];
self.photoBtu.frame = CGRectMake(self.frame.size.width/2-photoBtuWiDTH/2,self.frame.size.height/2-photoBtuWiDTH/2, photoBtuWiDTH, photoBtuWiDTH);
self.photoBtu.backgroundColor = [UIColor whiteColor];
self.photoBtu.layer.masksToBounds = YES;
self.photoBtu.layer.cornerRadius = 50;
[self addSubview:self.photoBtu];
self.photoTimeProgressView = [[AnnularProgress alloc] initWithFrame:CGRectMake(0, 0,150, 150)];
self.photoTimeProgressView.persentage = 0;
// self.photoTimeProgressView.backgroundColor = [UIColor blueColor];
[self addSubview:self.photoTimeProgressView];}
AnnularProgress.h
#import
typedef NS_ENUM (NSInteger, STClockWiseType) {
STClockWiseYes,
STClockWiseNo
};
@interface AnnularProgress: UIView
@property (assign, nonatomic) CGFloat persentage;
// 起始颜色
+ (UIColor *)startColor;
// 中间颜色
+ (UIColor *)centerColor;
// 结束颜色
+ (UIColor *)endColor;
// 背景色
+ (UIColor *)backgroundColor;
// 线宽
+ (CGFloat)lineWidth;
// 起始角度(根据顺时针计算,逆时针则是结束角度)
+ (CGFloat)startAngle;
// 结束角度(根据顺时针计算,逆时针则是起始角度)
+ (CGFloat)endAngle;
// 进度条起始方向(YES为顺时针,NO为逆时针)
+ (STClockWiseType)clockWiseType;
@end
#import "AnnularProgress.h"
#define SELF_WIDTH CGRectGetWidth(self.bounds)
#define SELF_HEIGHT CGRectGetHeight(self.bounds)
#define DEGREES_TO_RADOANS(x) (M_PI * (x) / 180.0) // 将角度转为弧度
@interface AnnularProgress ()
@property (strong, nonatomic) CAShapeLayer *colorMaskLayer; // 渐变色遮罩
@property (strong, nonatomic) CAShapeLayer *colorLayer; // 渐变色
@property (strong, nonatomic) CAShapeLayer *blueMaskLayer; // 蓝色背景遮罩
@end
@implementation AnnularProgress
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [AnnularProgress backgroundColor];
[self setupColorLayer];
[self setupColorMaskLayer];
[self setupBlueMaskLayer];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
self.backgroundColor = [AnnularProgress backgroundColor];
[self setupColorLayer];
[self setupColorMaskLayer];
[self setupBlueMaskLayer];
}
/**
* 设置整个蓝色view的遮罩
*/
- (void)setupBlueMaskLayer {
CAShapeLayer *layer = [self generateMaskLayer];
self.layer.mask = layer;
self.blueMaskLayer = layer;
}
/**
* 设置渐变色,渐变色由左右两个部分组成,左边部分由黄到绿,右边部分由黄到红
*/
- (void)setupColorLayer {
self.colorLayer = [CAShapeLayer layer];
self.colorLayer.frame = self.bounds;
[self.layer addSublayer:self.colorLayer];
CAGradientLayer *leftLayer = [CAGradientLayer layer];
leftLayer.frame = CGRectMake(0, 0, SELF_WIDTH / 2, SELF_HEIGHT);
// 分段设置渐变色
leftLayer.locations = @[@0.3, @0.9, @1];
leftLayer.colors = @[(id)[AnnularProgress centerColor].CGColor, (id)[AnnularProgress startColor].CGColor];
[self.colorLayer addSublayer:leftLayer];
CAGradientLayer *rightLayer = [CAGradientLayer layer];
rightLayer.frame = CGRectMake(SELF_WIDTH / 2, 0, SELF_WIDTH / 2, SELF_HEIGHT);
rightLayer.locations = @[@0.3, @0.9, @1];
rightLayer.colors = @[(id)[AnnularProgress centerColor].CGColor, (id)[AnnularProgress endColor].CGColor];
[self.colorLayer addSublayer:rightLayer];
}
/**
* 设置渐变色的遮罩
*/
- (void)setupColorMaskLayer {
CAShapeLayer *layer = [self generateMaskLayer];
layer.lineWidth = [AnnularProgress lineWidth] + 0.5; // 渐变遮罩线宽较大,防止蓝色遮罩有边露出来
self.colorLayer.mask = layer;
self.colorMaskLayer = layer;
}
/**
* 生成一个圆环形的遮罩层
* 因为蓝色遮罩与渐变遮罩的配置都相同,所以封装出来
*
* @return 环形遮罩
*/
- (CAShapeLayer *)generateMaskLayer {
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = self.bounds;
// 创建一个圆心为父视图中点的圆,半径为父视图宽的2/5
UIBezierPath *path = nil;
if ([AnnularProgress clockWiseType]) {
path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(SELF_WIDTH / 2, SELF_HEIGHT / 2) radius:SELF_WIDTH / 2.5 startAngle:[AnnularProgress startAngle] endAngle:[AnnularProgress endAngle] clockwise:YES];
} else {
path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(SELF_WIDTH / 2, SELF_HEIGHT / 2) radius:SELF_WIDTH / 2.5 startAngle:[AnnularProgress endAngle] endAngle:[AnnularProgress startAngle] clockwise:NO];
}
layer.lineWidth = [AnnularProgress lineWidth];
layer.path = path.CGPath;
layer.fillColor = [UIColor clearColor].CGColor; // 填充色为透明(不设置为黑色)
layer.strokeColor = [UIColor blackColor].CGColor; // 随便设置一个边框颜色
layer.lineCap = kCALineCapRound; // 设置线为圆角
return layer;
}
/**
* 在修改百分比的时候,修改彩色遮罩的大小
*
* @param persentage 百分比
*/
- (void)setPersentage:(CGFloat)persentage {
_persentage = persentage;
self.colorMaskLayer.strokeEnd = persentage;
}
+ (UIColor *)startColor {
return [UIColor whiteColor];
}
+ (UIColor *)centerColor {
return [UIColor whiteColor];
}
+ (UIColor *)endColor {
return [UIColor whiteColor];
}
+ (UIColor *)backgroundColor {
return [UIColor grayColor];
}
+ (CGFloat)lineWidth {
return 10;
}
+ (CGFloat)startAngle {
return DEGREES_TO_RADOANS(-90);
}
+ (CGFloat)endAngle {
return DEGREES_TO_RADOANS(270);
}
+ (STClockWiseType)clockWiseType {
return STClockWiseNo;
}
@end
这样就做出一个需要的按钮,接下来讲一下视频录制的主要方法。
1:导入俩个库:AssetsLibray.framework,AVKit.framework
2:授权摄像头的使用
//获取授权
- (void)getAuthorization
{
/*
AVAuthorizationStatusNotDetermined = 0,// 未进行授权选择
AVAuthorizationStatusRestricted, // 未授权,且用户无法更新,如家长控制情况下
AVAuthorizationStatusDenied, // 用户拒绝App使用
AVAuthorizationStatusAuthorized, // 已授权,可使用
*/
//此处获取摄像头授权
switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
{
case AVAuthorizationStatusAuthorized: //已授权,可使用 The client is authorized to access the hardware supporting a media type.
{
NSLog(@"授权摄像头使用成功");
[self setupAVCaptureInfo];
break;
}
case AVAuthorizationStatusNotDetermined: //未进行授权选择 Indicates that the user has not yet made a choice regarding whether the client can access the hardware.
{
//则再次请求授权
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){ //用户授权成功
[self setupAVCaptureInfo];
return;
} else { //用户拒绝授权
[self pop];
[self showMsgWithTitle:@"出错了" andContent:@"用户拒绝授权摄像头的使用权,返回上一页.请打开\n设置-->隐私/通用等权限设置"];
return;
}
}];
break;
}
default: //用户拒绝授权/未授权
{
[self pop];
[self showMsgWithTitle:@"出错了" andContent:@"拒绝授权,返回上一页.请检查下\n设置-->隐私/通用等权限设置"];
break;}}}}
3:设置视频的分辨率
_captureSession = [[AVCaptureSession alloc] init];
//设置视频分辨率
/* 通常支持如下格式
(
AVAssetExportPresetLowQuality,
AVAssetExportPreset960x540,
AVAssetExportPreset640x480,
AVAssetExportPresetMediumQuality,
AVAssetExportPreset1920x1080,
AVAssetExportPreset1280x720,
AVAssetExportPresetHighestQuality,
AVAssetExportPresetAppleM4A
)*/
//注意,这个地方设置的模式/分辨率大小将影响你后面拍摄照片/视频的大小,
if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
[_captureSession setSessionPreset:AVCaptureSessionPreset640x480];}
4:获取摄像头输入设备
// 获取摄像头输入设备, 创建 AVCaptureDeviceInput 对象
/* MediaType
AVF_EXPORT NSString *const AVMediaTypeVideo NS_AVAILABLE(10_7, 4_0); //视频
AVF_EXPORT NSString *const AVMediaTypeAudio NS_AVAILABLE(10_7, 4_0); //音频
AVF_EXPORT NSString *const AVMediaTypeText NS_AVAILABLE(10_7, 4_0);
AVF_EXPORT NSString *const AVMediaTypeClosedCaption NS_AVAILABLE(10_7, 4_0);
AVF_EXPORT NSString *const AVMediaTypeSubtitle NS_AVAILABLE(10_7, 4_0);
AVF_EXPORT NSString *const AVMediaTypeTimecode NS_AVAILABLE(10_7, 4_0);
AVF_EXPORT NSString *const AVMediaTypeMetadata NS_AVAILABLE(10_8, 6_0);
AVF_EXPORT NSString *const AVMediaTypeMuxed NS_AVAILABLE(10_7, 4_0);
*/
/* AVCaptureDevicePosition
typedef NS_ENUM(NSInteger, AVCaptureDevicePosition) {
AVCaptureDevicePositionUnspecified = 0,
AVCaptureDevicePositionBack = 1, //后置摄像头
AVCaptureDevicePositionFront = 2 //前置摄像头
} NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED;
*/
_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
5:切换闪光灯
BOOL con1 = [_videoDevice hasTorch]; //支持手电筒模式
BOOL con2 = [_videoDevice hasFlash]; //支持闪光模式
if (con1 && con2)
{
[self changeDevicePropertySafety:^(AVCaptureDevice *captureDevice) {
if (_videoDevice.flashMode == AVCaptureFlashModeOn) //闪光灯开
{
[_videoDevice setFlashMode:AVCaptureFlashModeOff];
[_videoDevice setTorchMode:AVCaptureTorchModeOff];
}else if (_videoDevice.flashMode == AVCaptureFlashModeOff) //闪光灯关
{
[_videoDevice setFlashMode:AVCaptureFlashModeOn];
[_videoDevice setTorchMode:AVCaptureTorchModeOn];
}
// else{ //闪光灯自动
// [_videoDevice setFlashMode:AVCaptureFlashModeAuto];
// [_videoDevice setTorchMode:AVCaptureTorchModeAuto];
// }
NSLog(@"现在的闪光模式是AVCaptureFlashModeOn么?是你就扣1, %zd",_videoDevice.flashMode == AVCaptureFlashModeOn);
}];
sender.selected=!sender.isSelected;
}else{
NSLog(@"不能切换闪光模式");}
6:切换前后镜头
switch (_videoDevice.position) {
case AVCaptureDevicePositionBack:
_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionFront];
break;
case AVCaptureDevicePositionFront:
_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
break;
default:
return;
break;
}
[self changeDevicePropertySafety:^(AVCaptureDevice *captureDevice) {
NSError *error;
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:&error];
if (newVideoInput != nil) {
//必选先 remove 才能询问 canAdd
[_captureSession removeInput:_videoInput];
if ([_captureSession canAddInput:newVideoInput]) {
[_captureSession addInput:newVideoInput];
_videoInput = newVideoInput;
}else{
[_captureSession addInput:_videoInput];
}} else if (error) {
NSLog(@"切换前/后摄像头失败, error = %@", error);}}];
7:聚焦
-(void)singleTap:(UITapGestureRecognizer *)tapGesture{
NSLog(@"单击");
CGPoint point= [tapGesture locationInView:self.videoView];
//将UI坐标转化为摄像头坐标,摄像头聚焦点范围0~1
CGPoint cameraPoint= [_captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point];
[self setFocusCursorAnimationWithPoint:point];
[self changeDevicePropertySafety:^(AVCaptureDevice *captureDevice) {
/*
@constant AVCaptureFocusModeLocked 锁定在当前焦距
Indicates that the focus should be locked at the lens' current position.
@constant AVCaptureFocusModeAutoFocus 自动对焦一次,然后切换到焦距锁定
Indicates that the device should autofocus once and then change the focus mode to AVCaptureFocusModeLocked.
@constant AVCaptureFocusModeContinuousAutoFocus 当需要时.自动调整焦距
Indicates that the device should automatically focus when needed.
*/
//聚焦
if ([captureDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
[captureDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
NSLog(@"聚焦模式修改为%zd",AVCaptureFocusModeContinuousAutoFocus);
}else{
NSLog(@"聚焦模式修改失败");
}
//聚焦点的位置
if ([captureDevice isFocusPointOfInterestSupported]) {
[captureDevice setFocusPointOfInterest:cameraPoint];
}
/*
@constant AVCaptureExposureModeLocked 曝光锁定在当前值
Indicates that the exposure should be locked at its current value.
@constant AVCaptureExposureModeAutoExpose 曝光自动调整一次然后锁定
Indicates that the device should automatically adjust exposure once and then change the exposure mode to AVCaptureExposureModeLocked.
@constant AVCaptureExposureModeContinuousAutoExposure 曝光自动调整
Indicates that the device should automatically adjust exposure when needed.
@constant AVCaptureExposureModeCustom 曝光只根据设定的值来
Indicates that the device should only adjust exposure according to user provided ISO, exposureDuration values.
*/
//曝光模式
if ([captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]) {
[captureDevice setExposureMode:AVCaptureExposureModeAutoExpose];
}else{
NSLog(@"曝光模式修改失败");
}
//曝光点的位置
if ([captureDevice isExposurePointOfInterestSupported]) {
[captureDevice setExposurePointOfInterest:cameraPoint];
}
}];}
8:压缩,保存
// 压缩视频
- (void)compressVideo:(UIButton *)sender
{
NSLog(@"压缩前大小 %f MB",[self fileSize:_videoUrl]);
// 创建AVAsset对象
AVAsset* asset = [AVAsset assetWithURL:_videoUrl];
/* 创建AVAssetExportSession对象
压缩的质量
AVAssetExportPresetLowQuality 最low的画质最好不要选择实在是看不清楚
AVAssetExportPresetMediumQuality 使用到压缩的话都说用这个
AVAssetExportPresetHighestQuality 最清晰的画质
*/
AVAssetExportSession * session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];
//优化网络
session.shouldOptimizeForNetworkUse = YES;
//转换后的格式
//拼接输出文件路径 为了防止同名 可以根据日期拼接名字 或者对名字进行MD5加密
NSString* path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"hello.mp4"];
//判断文件是否存在,如果已经存在删除
[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
//设置输出路径
session.outputURL = [NSURL fileURLWithPath:path];
//设置输出类型 这里可以更改输出的类型 具体可以看文档描述
session.outputFileType = AVFileTypeMPEG4;
[session exportAsynchronouslyWithCompletionHandler:^{
NSLog(@"%@",[NSThread currentThread]);
//压缩完成
if (session.status==AVAssetExportSessionStatusCompleted) {
//在主线程中刷新UI界面,弹出控制器通知用户压缩完成
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"导出完成");
NSURL *CompressURL = session.outputURL;
NSLog(@"压缩完毕,压缩后大小 %f MB",[self fileSize:CompressURL]);
[self upLoad:CompressURL];
[self saveVideo:session.outputURL];
});
}
}];
}
主要是这些代码。。。。。。。。
网友评论