123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720 |
- //
- // KZVideoViewController.m
- // KZWeChatSmallVideo_OC
- //
- // Created by HouKangzhu on 16/7/18.
- // Copyright © 2016年 侯康柱. All rights reserved.
- //
- #import "KZVideoViewController.h"
- #import "KZVideoSupport.h"
- #import "KZVideoConfig.h"
- #import <AVFoundation/AVFoundation.h>
- #import <AssetsLibrary/AssetsLibrary.h>
- #import <Photos/Photos.h>
- #import <CoreMotion/CoreMotion.h>
- #import "KZVideoListViewController.h"
- @interface KZVideoViewController()<KZControllerBarDelegate,AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate> {
-
- KZStatusBar *_topSlideView;
-
- UIView *_videoView;
- KZFocusView *_focusView;
- UILabel *_statusInfo;
- UILabel *_cancelInfo;
-
- KZControllerBar *_ctrlBar;
-
- AVCaptureSession *_videoSession;
- AVCaptureVideoPreviewLayer *_videoPreLayer;
- AVCaptureDevice *_videoDevice;
-
- AVCaptureVideoDataOutput *_videoDataOut;
- AVCaptureAudioDataOutput *_audioDataOut;
-
- AVAssetWriter *_assetWriter;
- AVAssetWriterInputPixelBufferAdaptor *_assetWriterPixelBufferInput;
- AVAssetWriterInput *_assetWriterVideoInput;
- AVAssetWriterInput *_assetWriterAudioInput;
- CMTime _currentSampleTime;
- BOOL _recoding;
-
- dispatch_queue_t _recoding_queue;
- // dispatch_queue_create("com.video.queue", DISPATCH_QUEUE_SERIAL)
-
- KZVideoModel *_currentRecord;
- BOOL _currentRecordIsCancel;
- UIView *_eyeView;
- }
- @property (nonatomic, assign) KZVideoViewShowType showType;
- @property(nonatomic, strong)AVCaptureStillImageOutput *imageOutput;
- @property(nonatomic,strong) CMMotionManager *motionManager;
- @end
- static KZVideoViewController *__currentVideoVC = nil;
- @implementation KZVideoViewController
- - (void)startAnimationWithType:(KZVideoViewShowType)showType selectExist:(BOOL)selectExist {
- self.motionManager = [[CMMotionManager alloc] init];
- [self.motionManager startAccelerometerUpdates];
- _showType = showType;
- __currentVideoVC = self;
-
- [self setupSubViews];
- self.view.hidden = YES;
- BOOL videoExist = [KZVideoUtil existVideo];
- UIWindow *keyWindow = [UIApplication sharedApplication].delegate.window;
- [keyWindow addSubview:self.view];
- if (_showType == KZVideoViewShowTypeSingle && videoExist && selectExist) {
-
- [self ctrollVideoOpenVideoList:nil];
- kz_dispatch_after(0.4, ^{
- self.view.hidden = NO;
- });
-
- }
- else {
- self.view.hidden = NO;
- self.actionView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, 0, CGRectGetHeight([KZVideoConfig viewFrameWithType:showType]));
- [UIView animateWithDuration:0.3 delay:0.1 options:UIViewAnimationOptionCurveLinear animations:^{
- self.actionView.transform = CGAffineTransformIdentity;
- self.view.backgroundColor = [UIColor colorWithRed: 0.0 green: 0.0 blue: 0.0 alpha: 0.4];
- } completion:^(BOOL finished) {
- [self viewDidAppear];
- }];
- }
- [self setupVideo];
- }
- - (void)endAniamtion {
- [self.motionManager stopAccelerometerUpdates];
- [UIView animateWithDuration:0.3 animations:^{
- self.view.backgroundColor = [UIColor clearColor];
- self.actionView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, 0, CGRectGetHeight([KZVideoConfig viewFrameWithType:_showType]));
- } completion:^(BOOL finished) {
- [self closeView];
- }];
- }
- - (void)closeView {
- [_videoSession stopRunning];
- [_videoPreLayer removeFromSuperlayer];
- _videoPreLayer = nil;
- [_videoView removeFromSuperview];
- _videoView = nil;
-
- _videoDevice = nil;
- _videoDataOut = nil;
- _assetWriter = nil;
- _assetWriterAudioInput = nil;
- _assetWriterVideoInput = nil;
- _assetWriterPixelBufferInput = nil;
- [self.view removeFromSuperview];
- __currentVideoVC = nil;
- }
- - (void)dealloc {
- // NSLog(@"dalloc videoVC");
- }
- - (void)setupSubViews {
- _view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
- self.view.backgroundColor = [UIColor clearColor];
-
- UIPanGestureRecognizer *ges = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveTopBarAction:)];
- [self.view addGestureRecognizer:ges];
-
- _actionView = [[UIView alloc] initWithFrame:[KZVideoConfig viewFrameWithType:_showType]];
- [self.view addSubview:_actionView];
- _actionView.backgroundColor = kzThemeBlackColor;
- _actionView.clipsToBounds = YES;
-
-
- BOOL isSmallStyle = _showType == KZVideoViewShowTypeSmall;
-
- CGSize videoViewSize = [KZVideoConfig videoViewDefaultSize];
- CGFloat topHeight = 64;//isSmallStyle ? 20.0 : 64.0;
-
- CGFloat allHeight = _actionView.frame.size.height;
- CGFloat allWidth = _actionView.frame.size.width;
-
- CGFloat buttomHeight = 280.0;//isSmallStyle ? kzControViewHeight : allHeight - topHeight - videoViewSize.height;
-
-
- _videoView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, videoViewSize.width, videoViewSize.height)];
- [self.actionView addSubview:_videoView];
-
-
- _topSlideView = [[KZStatusBar alloc] initWithFrame:CGRectMake(0, 0, allWidth, topHeight) style:_showType];
-
- if (!isSmallStyle) {
- [_topSlideView addCancelTarget:self selector:@selector(endAniamtion)];
- }
- [self.actionView addSubview:_topSlideView];
-
-
- _ctrlBar = [[KZControllerBar alloc] initWithFrame:CGRectMake(0, allHeight - buttomHeight, allWidth, buttomHeight)];
- [_ctrlBar setupSubViewsWithStyle:_showType];
- _ctrlBar.delegate = self;
- [self.actionView addSubview:_ctrlBar];
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(focusAction:)];
- tapGesture.delaysTouchesBegan = YES;
- [_videoView addGestureRecognizer:tapGesture];
-
- UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(zoomVideo:)];
- doubleTapGesture.numberOfTapsRequired = 2;
- doubleTapGesture.numberOfTouchesRequired = 1;
- doubleTapGesture.delaysTouchesBegan = YES;
- [_videoView addGestureRecognizer:doubleTapGesture];
- [tapGesture requireGestureRecognizerToFail:doubleTapGesture];
-
-
- _focusView = [[KZFocusView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
- _focusView.backgroundColor = [UIColor clearColor];
-
- _statusInfo = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_videoView.frame) - 30, _videoView.frame.size.width, 20)];
- _statusInfo.textAlignment = NSTextAlignmentCenter;
- _statusInfo.font = [UIFont systemFontOfSize:14.0];
- _statusInfo.textColor = [UIColor whiteColor];
- _statusInfo.hidden = YES;
- [self.actionView addSubview:_statusInfo];
-
- _cancelInfo = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 120, 24)];
- _cancelInfo.center = _videoView.center;
- _cancelInfo.textAlignment = NSTextAlignmentCenter;
- _cancelInfo.textColor = kzThemeWhiteColor;
- _cancelInfo.backgroundColor = kzThemeWaringColor;
- _cancelInfo.hidden = YES;
- [self.actionView addSubview:_cancelInfo];
-
-
- [_actionView sendSubviewToBack:_videoView];
- }
- - (void)setupVideo {
- NSString *unUseInfo = nil;
- if (TARGET_IPHONE_SIMULATOR) {
- unUseInfo = @"模拟器不可以的..";
- }
- AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
- if(videoAuthStatus == ALAuthorizationStatusRestricted || videoAuthStatus == ALAuthorizationStatusDenied){
- unUseInfo = @"相机访问受限...";
- }
- AVAuthorizationStatus audioAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
- if(audioAuthStatus == ALAuthorizationStatusRestricted || audioAuthStatus == ALAuthorizationStatusDenied){
- unUseInfo = @"录音访问受限...";
- }
- if (unUseInfo != nil) {
- _statusInfo.text = unUseInfo;
- _statusInfo.hidden = NO;
- _eyeView = [[KZEyeView alloc] initWithFrame:_videoView.bounds];
- [_videoView addSubview:_eyeView];
- return;
- }
-
- _recoding_queue = dispatch_queue_create("com.kzsmallvideo.queue", DISPATCH_QUEUE_SERIAL);
-
- NSArray *devicesVideo = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
- NSArray *devicesAudio = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
-
- AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:devicesVideo[0] error:nil];
- AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:devicesAudio[0] error:nil];
-
- _videoDevice = devicesVideo[0];
-
- _videoDataOut = [[AVCaptureVideoDataOutput alloc] init];
- _videoDataOut.videoSettings = @{(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA)};
- _videoDataOut.alwaysDiscardsLateVideoFrames = YES;
- [_videoDataOut setSampleBufferDelegate:self queue:_recoding_queue];
-
- _audioDataOut = [[AVCaptureAudioDataOutput alloc] init];
- [_audioDataOut setSampleBufferDelegate:self queue:_recoding_queue];
-
- _videoSession = [[AVCaptureSession alloc] init];
- _videoSession.sessionPreset = AVCaptureSessionPresetHigh;
- if ([_videoSession canAddInput:videoInput]) {
- [_videoSession addInput:videoInput];
- }
- if ([_videoSession canAddInput:audioInput]) {
- [_videoSession addInput:audioInput];
- }
- if ([_videoSession canAddOutput:_videoDataOut]) {
- [_videoSession addOutput:_videoDataOut];
- }
-
- if ([_videoSession canAddOutput:self.imageOutput]) {
- [_videoSession addOutput:self.imageOutput];
- }
-
- if ([_videoSession canAddOutput:_audioDataOut]) {
- [_videoSession addOutput:_audioDataOut];
- }
- CGFloat viewWidth = CGRectGetWidth(_actionView.frame);
- CGFloat viewHeight = CGRectGetHeight(_actionView.frame);
- _videoPreLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_videoSession];
- _videoPreLayer.frame = CGRectMake(0, 0, viewWidth, viewHeight);
- _videoPreLayer.position = CGPointMake(viewWidth/2, viewHeight/2);
- _videoPreLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
- [_videoView.layer addSublayer:_videoPreLayer];
-
- [_videoSession startRunning];
-
- [self viewWillAppear];
- }
- - (void)viewWillAppear {
- _eyeView = [[KZEyeView alloc] initWithFrame:_videoView.bounds];
- [_videoView addSubview:_eyeView];
- }
- - (void)viewDidAppear {
-
- if (TARGET_IPHONE_SIMULATOR) return;
-
- UIView *sysSnapshot = [_eyeView snapshotViewAfterScreenUpdates:NO];
- CGFloat videoViewHeight = CGRectGetHeight(_videoView.frame);
- CGFloat viewViewWidth = CGRectGetWidth(_videoView.frame);
- _eyeView.alpha = 0;
- UIView *topView = [sysSnapshot resizableSnapshotViewFromRect:CGRectMake(0, 0, viewViewWidth, videoViewHeight/2) afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
- CGRect btmFrame = CGRectMake(0, videoViewHeight/2, viewViewWidth, videoViewHeight/2);
- UIView *btmView = [sysSnapshot resizableSnapshotViewFromRect:btmFrame afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
- btmView.frame = btmFrame;
- [_videoView addSubview:topView];
- [_videoView addSubview:btmView];
-
- [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
- topView.transform = CGAffineTransformMakeTranslation(0,-videoViewHeight/2);
- btmView.transform = CGAffineTransformMakeTranslation(0, videoViewHeight);
- topView.alpha = 0.3;
- btmView.alpha = 0.3;
- } completion:^(BOOL finished) {
- [topView removeFromSuperview];
- [btmView removeFromSuperview];
- [_eyeView removeFromSuperview];
- _eyeView = nil;
- [self focusInPointAtVideoView:CGPointMake(_videoView.bounds.size.width/2, _videoView.bounds.size.height/2)];
- }];
-
- __block UILabel *zoomLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 20)];
- zoomLab.center = CGPointMake(_videoView.center.x, CGRectGetMaxY(_videoView.frame) - 16);
- zoomLab.font = [UIFont boldSystemFontOfSize:14];
- zoomLab.text = WFCString(@"DoubleClickZoomOut");
- zoomLab.textColor = [UIColor whiteColor];
- zoomLab.textAlignment = NSTextAlignmentCenter;
- [_videoView addSubview:zoomLab];
- [_videoView bringSubviewToFront:zoomLab];
-
- kz_dispatch_after(1.6, ^{
- [zoomLab removeFromSuperview];
- });
- }
- - (void)focusInPointAtVideoView:(CGPoint)point {
- CGPoint cameraPoint= [_videoPreLayer captureDevicePointOfInterestForPoint:point];
- _focusView.center = point;
- [_videoView addSubview:_focusView];
- [_videoView bringSubviewToFront:_focusView];
- [_focusView focusing];
-
- NSError *error = nil;
- if ([_videoDevice lockForConfiguration:&error]) {
- if ([_videoDevice isFocusPointOfInterestSupported]) {
- _videoDevice.focusPointOfInterest = cameraPoint;
- }
- if ([_videoDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
- _videoDevice.focusMode = AVCaptureFocusModeAutoFocus;
- }
- if ([_videoDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]) {
- _videoDevice.exposureMode = AVCaptureExposureModeAutoExpose;
- }
- if ([_videoDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
- _videoDevice.whiteBalanceMode = AVCaptureWhiteBalanceModeAutoWhiteBalance;
- }
- [_videoDevice unlockForConfiguration];
- }
- if (error) {
- NSLog(@"聚焦失败:%@",error);
- }
- kz_dispatch_after(1.0, ^{
- [_focusView removeFromSuperview];
- });
- }
- #pragma mark - Actions --
- - (void)focusAction:(UITapGestureRecognizer *)gesture {
- CGPoint point = [gesture locationInView:_videoView];
- [self focusInPointAtVideoView:point];
- }
- - (void)zoomVideo:(UITapGestureRecognizer *)gesture {
- NSError *error = nil;
- if ([_videoDevice lockForConfiguration:&error]) {
- CGFloat zoom = _videoDevice.videoZoomFactor == 2.0?1.0:2.0;
- _videoDevice.videoZoomFactor = zoom;
- [_videoDevice unlockForConfiguration];
- }
- }
- - (void)moveTopBarAction:(UIPanGestureRecognizer *)gesture {
- CGPoint pointAtView = [gesture locationInView:self.view];
- CGRect dafultFrame = [KZVideoConfig viewFrameWithType:_showType];
-
- if (pointAtView.y < dafultFrame.origin.y) {
- return;
- }
-
- CGPoint pointAtTop = [gesture locationInView:_topSlideView];
- if (pointAtTop.y > -10 && pointAtTop.y < 30) {
- CGRect actionFrame = _actionView.frame;
- actionFrame.origin.y = pointAtView.y;
- _actionView.frame = actionFrame;
-
- CGFloat alpha = 0.4*(kzSCREEN_HEIGHT - pointAtView.y)/CGRectGetHeight(_actionView.frame);
- self.view.backgroundColor = [UIColor colorWithRed: 0.0 green: 0.0 blue: 0.0 alpha: alpha];
- }
- if (gesture.state == UIGestureRecognizerStateEnded) {
- if (pointAtView.y >= CGRectGetMidY(dafultFrame)) {
- [self endAniamtion];
- }
- else {
- [UIView animateWithDuration:0.3 animations:^{
- _actionView.frame = dafultFrame;
- self.view.backgroundColor = [UIColor colorWithRed: 0.0 green: 0.0 blue: 0.0 alpha: 0.4];
- }];
- }
- }
- }
- #pragma mark - controllerBarDelegate
- - (void)ctrollVideoDidStart:(KZControllerBar *)controllerBar {
- _currentRecord = [KZVideoUtil createNewVideo];
- _currentRecordIsCancel = NO;
- NSURL *outURL = [NSURL fileURLWithPath:_currentRecord.videoAbsolutePath];
- [self createWriter:outURL];
-
- _topSlideView.isRecoding = YES;
-
- _statusInfo.textColor = kzThemeTineColor;
- _statusInfo.text = WFCString(@"MoveUpCancel");
- _statusInfo.hidden = NO;
- kz_dispatch_after(0.5, ^{
- _statusInfo.hidden = YES;
- });
-
- _recoding = YES;
- // NSLog(@"视频开始录制");
- }
- - (void)ctrollVideoDidEnd:(KZControllerBar *)controllerBar {
- _topSlideView.isRecoding = NO;
- _recoding = NO;
- [self saveVideo:^(NSURL *outFileURL) {
- if (_delegate) {
- [_delegate videoViewController:self didRecordVideo:_currentRecord];
- [self endAniamtion];
- }
- }];
-
- // NSLog(@"视频录制结束");
- }
- AVCaptureVideoOrientation orientationBaseOnAcceleration(CMAcceleration acceleration) {
- AVCaptureVideoOrientation result;
- if (acceleration.x >= 0.75) { /// UIDeviceOrientationLandscapeRight
- result = AVCaptureVideoOrientationLandscapeLeft;
- }
- else if (acceleration.x <= -0.75) { /// UIDeviceOrientationLandscapeLeft
- result = AVCaptureVideoOrientationLandscapeRight;
- }
- else if (acceleration.y <= -0.75) { /// UIDeviceOrientationPortrait
- result = AVCaptureVideoOrientationPortrait;
- }
- else if (acceleration.y >= 0.75) { ///UIDeviceOrientationPortraitUpsideDown
- result = AVCaptureVideoOrientationPortraitUpsideDown;
- }
- else {
- result = AVCaptureVideoOrientationPortrait;
-
- }
- return result;
- }
- - (void)ctrollImageDidCapture:(KZControllerBar *)controllerBar {
- __weak typeof(self) ws = self;
- CMAcceleration acceleration = self.motionManager.accelerometerData.acceleration;
- AVCaptureVideoOrientation orientation = orientationBaseOnAcceleration(acceleration);
- [self captureStillImage:orientation completion:^(UIImage *image) {
- [ws.delegate videoViewController:self didCaptureImage:image];
- [ws endAniamtion];
- }];
- }
- - (void)ctrollVideoDidCancel:(KZControllerBar *)controllerBar reason:(KZRecordCancelReason)reason{
- _currentRecordIsCancel = YES;
- _topSlideView.isRecoding = NO;
- _recoding = NO;
- if (reason == KZRecordCancelReasonTimeShort) {
- [KZVideoConfig showHinInfo:@"录制时间过短" inView:_videoView frame:CGRectMake(0,CGRectGetHeight(_videoView.frame)/3*2,CGRectGetWidth(_videoView.frame),20) timeLong:1.0];
- }
- // NSLog(@"当前视频录制取消");
- }
- - (void)ctrollVideoWillCancel:(KZControllerBar *)controllerBar {
- if (!_cancelInfo.hidden) {
- return;
- }
- _cancelInfo.text = WFCString(@"ReleaseToCancel");
- _cancelInfo.hidden = NO;
- kz_dispatch_after(0.5, ^{
- _cancelInfo.hidden = YES;
- });
- }
- - (void)ctrollVideoDidRecordSEC:(KZControllerBar *)controllerBar {
- _topSlideView.isRecoding = YES;
- // NSLog(@"视频录又过了 1 秒");
- }
- - (void)ctrollVideoDidClose:(KZControllerBar *)controllerBar {
- // NSLog(@"录制界面关闭");
- if (_delegate && [_delegate respondsToSelector:@selector(videoViewControllerDidCancel:)]) {
- [_delegate videoViewControllerDidCancel:self];
- }
- [self endAniamtion];
- }
- - (void)ctrollVideoOpenVideoList:(KZControllerBar *)controllerBar {
- // NSLog(@"查看视频列表");
- KZVideoListViewController *listVC = [[KZVideoListViewController alloc] init];
- __weak typeof(self) blockSelf = self;
- listVC.selectBlock = ^(KZVideoModel *selectModel) {
- _currentRecord = selectModel;
- if (_delegate) {
- [_delegate videoViewController:blockSelf didRecordVideo:_currentRecord];
- }
- [blockSelf closeView];
- };
-
- listVC.didCloseBlock = ^{
- if (_showType == KZVideoViewShowTypeSingle) {
- [blockSelf viewDidAppear];
- }
- };
- [listVC showAnimationWithType:_showType];
- }
- - (UIImage *)fixOrientationOfImage:(UIImage*)image {
- if (image.imageOrientation == UIImageOrientationUp) return image;
-
- UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
- [image drawInRect:(CGRect){0, 0, image.size}];
- UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return normalizedImage;
- }
- - (void)captureStillImage:(AVCaptureVideoOrientation)orientation
- completion:(void (^)(UIImage *image))completion{
-
- AVCaptureConnection *connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
- static NSUInteger tryCount = 0;
- if (connection.isVideoOrientationSupported) {
- connection.videoOrientation = orientation;
- }
-
- __weak typeof(self) weakSelf = self;
- id handler = ^(CMSampleBufferRef sampleBuffer, NSError *error) {
- if (sampleBuffer != NULL) {
-
- NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBuffer];
- /// 以 Camera 坐标系存储的图片
- UIImage *image = [[UIImage alloc] initWithData:imageData];
- /// 转化以屏幕坐标系存储
- image = [weakSelf fixOrientationOfImage:image];
- tryCount = 0;
- if (completion) {
- completion(image);
- }
-
- } else {
- tryCount++;
- if (tryCount > 3) {
- tryCount = 0;
- completion(nil);
- return;
- }
- NSLog(@"NULL sampleBuffer: %@", [error localizedDescription]);
- [weakSelf captureStillImage:orientation completion:completion];
- }
- };
- // Capture still image
- [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:handler];
- }
- - (AVCaptureStillImageOutput *)imageOutput {
- if (!_imageOutput) {
- _imageOutput = [[AVCaptureStillImageOutput alloc] init];
- _imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};
- }
- return _imageOutput;
- }
- #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate
- - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
-
- if (!_recoding) return;
-
- @autoreleasepool {
- _currentSampleTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer);
- if (_assetWriter.status != AVAssetWriterStatusWriting) {
- [_assetWriter startWriting];
- [_assetWriter startSessionAtSourceTime:_currentSampleTime];
- }
- if (captureOutput == _videoDataOut) {
- if (_assetWriterPixelBufferInput.assetWriterInput.isReadyForMoreMediaData) {
- CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
- BOOL success = [_assetWriterPixelBufferInput appendPixelBuffer:pixelBuffer withPresentationTime:_currentSampleTime];
- if (!success) {
- NSLog(@"Pixel Buffer没有append成功");
- }
- }
- }
- if (captureOutput == _audioDataOut) {
- [_assetWriterAudioInput appendSampleBuffer:sampleBuffer];
- }
- }
- }
- - (void)captureOutput:(AVCaptureOutput *)captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
-
- }
- - (void)createWriter:(NSURL *)assetUrl {
- _assetWriter = [AVAssetWriter assetWriterWithURL:assetUrl fileType:AVFileTypeQuickTimeMovie error:nil];
- int videoWidth = [KZVideoConfig defualtVideoSize].width;
- int videoHeight = [KZVideoConfig defualtVideoSize].height;
- /*
- NSDictionary *videoCleanApertureSettings = @{
- AVVideoCleanApertureWidthKey:@(videoHeight),
- AVVideoCleanApertureHeightKey:@(videoWidth),
- AVVideoCleanApertureHorizontalOffsetKey:@(200),
- AVVideoCleanApertureVerticalOffsetKey:@(0)
- };
- NSDictionary *videoAspectRatioSettings = @{
- AVVideoPixelAspectRatioHorizontalSpacingKey:@(3),
- AVVideoPixelAspectRatioVerticalSpacingKey:@(3)
- };
- NSDictionary *codecSettings = @{
- AVVideoAverageBitRateKey:@(960000),
- AVVideoMaxKeyFrameIntervalKey:@(1),
- AVVideoProfileLevelKey:AVVideoProfileLevelH264Main30,
- AVVideoCleanApertureKey: videoCleanApertureSettings,
- AVVideoPixelAspectRatioKey:videoAspectRatioSettings
- };
- */
- NSDictionary *outputSettings = @{
- AVVideoCodecKey : AVVideoCodecH264,
- AVVideoWidthKey : @(videoHeight),
- AVVideoHeightKey : @(videoWidth),
- AVVideoScalingModeKey:AVVideoScalingModeResizeAspectFill,
- // AVVideoCompressionPropertiesKey:codecSettings
- };
- _assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
- _assetWriterVideoInput.expectsMediaDataInRealTime = YES;
- _assetWriterVideoInput.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
-
-
- NSDictionary *audioOutputSettings = @{
- AVFormatIDKey:@(kAudioFormatMPEG4AAC),
- AVEncoderBitRateKey:@(64000),
- AVSampleRateKey:@(44100),
- AVNumberOfChannelsKey:@(1),
- };
-
- _assetWriterAudioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioOutputSettings];
- _assetWriterAudioInput.expectsMediaDataInRealTime = YES;
-
-
- NSDictionary *SPBADictionary = @{
- (__bridge NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
- (__bridge NSString *)kCVPixelBufferWidthKey : @(videoWidth),
- (__bridge NSString *)kCVPixelBufferHeightKey : @(videoHeight),
- (__bridge NSString *)kCVPixelFormatOpenGLESCompatibility : ((__bridge NSNumber *)kCFBooleanTrue)
- };
- _assetWriterPixelBufferInput = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_assetWriterVideoInput sourcePixelBufferAttributes:SPBADictionary];
- if ([_assetWriter canAddInput:_assetWriterVideoInput]) {
- [_assetWriter addInput:_assetWriterVideoInput];
- }else {
- NSLog(@"不能添加视频writer的input \(assetWriterVideoInput)");
- }
- if ([_assetWriter canAddInput:_assetWriterAudioInput]) {
- [_assetWriter addInput:_assetWriterAudioInput];
- }else {
- NSLog(@"不能添加视频writer的input \(assetWriterVideoInput)");
- }
- }
- - (void)saveVideo:(void(^)(NSURL *outFileURL))complier {
-
- if (_recoding) return;
-
- if (!_recoding_queue){
- complier(nil);
- return;
- };
-
- dispatch_async(_recoding_queue, ^{
- NSURL *outputFileURL = [NSURL fileURLWithPath:_currentRecord.videoAbsolutePath];
- [_assetWriter finishWritingWithCompletionHandler:^{
-
- if (_currentRecordIsCancel) return ;
-
- [KZVideoUtil saveThumImageWithVideoURL:outputFileURL second:1];
-
- if (complier) {
- dispatch_async(dispatch_get_main_queue(), ^{
- complier(outputFileURL);
- });
- }
- if (_savePhotoAlbum) {
- BOOL ios8Later = [[[UIDevice currentDevice] systemVersion] floatValue] >= 8;
- if (ios8Later) {
- [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
- [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputFileURL];
- } completionHandler:^(BOOL success, NSError * _Nullable error) {
- if (!error && success) {
- NSLog(@"保存相册成功!");
- }
- else {
- NSLog(@"保存相册失败! :%@",error);
- }
- }];
-
- }
- else {
- [[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
- if (!error) {
- NSLog(@"保存相册成功!");
- }
- else {
- NSLog(@"保存相册失败!");
- }
- }];
-
- }
-
- }
- }];
- });
-
- }
- @end
|