iOS技术收藏iOS工程实践iOS开发

iOS 仿微信小视频做的一些东西

2016-09-26  本文已影响1608人  icc_tips

在写这个的时候查了好多资料,看了大家写的都基本一样,今天就当笔记一样分享给大家。

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];

});

}

}];

}

主要是这些代码。。。。。。。。

上一篇下一篇

猜你喜欢

热点阅读