AVCaptureSession //
AVCaptureVideoPreviewLayer // , AVCaptureDevice // / AVCaptureDeviceInput // / AVCaptureSession AVCaptureMovieFileOutput // AVCaptureSession
#import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #import <CoreMedia/CoreMedia.h> #import <AVFoundation/AVFoundation.h> #import <AudioToolbox/AudioToolbox.h> #import <AVKit/AVKit.h> @protocol VideoRecorderDelegate <NSObject> // , - (void)videoRecorderDidFinishRecordingVideoWithOutputPath:(NSString *)outputPath; // , - (void)videoRecorderDidCancelRecordingVideo; @end @interface VideoRecorderController : UIViewController @property (nonatomic, retain) NSString *outputPath; // @property (nonatomic, assign) id<VideoRecorderDelegate> delegate; @end
#import "VideoRecorderController.h" #define TOTAL_RECORDING_TIME 60*20 // #define FRAMES_PER_SECOND 30 // #define FREE_DISK_SPACE_LIMIT 1024 * 1024 // () #define MAX_VIDEO_FILE_SIZE 160 * 1024 * 1024 // () #define CAPTURE_SESSION_PRESET AVCaptureSessionPreset352x288 // #define BeginVideoRecording 1117 // #define EndVideoRecording 1118 // @interface VideoRecorderController () <AVCaptureFileOutputRecordingDelegate> { BOOL WeAreRecording; // , AVCaptureSession *CaptureSession; AVCaptureMovieFileOutput *MovieFileOutput; AVCaptureDeviceInput *VideoInputDevice; } // @property (retain) IBOutlet UILabel *timeLabel; // @property (retain) IBOutlet UIButton *startButton; // Start / Stop @property (retain) IBOutlet UIImageView *circleImage; // Start @property (retain) IBOutlet UIButton *cancelButton; // Cancel @property (retain) IBOutlet UIButton *useVideoButton; // Use Video @property (retain) IBOutlet UIView *bottomView; // @property (retain) IBOutlet UIButton *playVideoButton; // Play Video - (IBAction)startStopButtonPressed:(id)sender; // Start / Stop - (IBAction)cancel:(id)sender; // Cancel - (IBAction)useVideo:(id)sender; // Use Video - (IBAction)playVideo:(id)sender; // Play Video @property (retain) AVCaptureVideoPreviewLayer *PreviewLayer; // @property (retain) NSTimer *videoTimer; @property (assign) NSTimeInterval elapsedTime; @end
@implementation VideoRecorderController - (void)viewDidLoad { [super viewDidLoad]; self.outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; [self deleteVideoFile]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationDidEnterBackground:) name: UIApplicationDidEnterBackgroundNotification object: nil]; CaptureSession = [[AVCaptureSession alloc] init]; AVCaptureDevice *VideoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if (VideoDevice) { NSError *error = nil; VideoInputDevice = [AVCaptureDeviceInput deviceInputWithDevice:VideoDevice error:&error]; if (!error) { [CaptureSession beginConfiguration]; if ([CaptureSession canAddInput:VideoInputDevice]) { [CaptureSession addInput:VideoInputDevice]; } [CaptureSession commitConfiguration]; } } AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; NSError *error = nil; AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error]; if (audioInput) { [CaptureSession addInput:audioInput]; } [self setPreviewLayer:[[AVCaptureVideoPreviewLayer alloc] initWithSession:CaptureSession]]; [self.PreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; [self setupLayoutInRect:[[[self view] layer] bounds]]; UIView *CameraView = [[UIView alloc] init]; [[self view] addSubview:CameraView]; [self.view sendSubviewToBack:CameraView]; [[CameraView layer] addSublayer:self.PreviewLayer]; MovieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; CMTime maxDuration = CMTimeMakeWithSeconds(TOTAL_RECORDING_TIME, FRAMES_PER_SECOND); MovieFileOutput.maxRecordedDuration = maxDuration; MovieFileOutput.maxRecordedFileSize = MAX_VIDEO_FILE_SIZE; MovieFileOutput.minFreeDiskSpaceLimit = FREE_DISK_SPACE_LIMIT; if ([CaptureSession canAddOutput:MovieFileOutput]) { [CaptureSession addOutput:MovieFileOutput]; } if ([CaptureSession canSetSessionPreset:CAPTURE_SESSION_PRESET]) { [CaptureSession setSessionPreset:CAPTURE_SESSION_PRESET]; } [self cameraSetOutputProperties]; } - (void)applicationDidEnterBackground:(UIApplication *)application { if (WeAreRecording) { [self stopRecording]; } } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (![[NSFileManager defaultManager] fileExistsAtPath:self.outputPath]) { WeAreRecording = NO; [CaptureSession startRunning]; } }
- (BOOL)shouldAutorotate { return (CaptureSession.isRunning && !WeAreRecording); } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape | UIInterfaceOrientationMaskPortraitUpsideDown); } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [self setupLayoutInRect:CGRectMake(0, 0, size.width, size.height)]; [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { [self cameraSetOutputProperties]; }]; } // // viewWillTransitionToSize, iOS 7 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self setupLayoutInRect:[[[self view] layer] bounds]]; [self cameraSetOutputProperties]; } // - (void)setupLayoutInRect:(CGRect)layoutRect { [self.PreviewLayer setBounds:layoutRect]; [self.PreviewLayer setPosition:CGPointMake(CGRectGetMidX(layoutRect), CGRectGetMidY(layoutRect))]; } // - (void)cameraSetOutputProperties { AVCaptureConnection *videoConnection = nil; for ( AVCaptureConnection *connection in [MovieFileOutput connections] ) { for ( AVCaptureInputPort *port in [connection inputPorts] ) { if ( [[port mediaType] isEqual:AVMediaTypeVideo] ) { videoConnection = connection; } } } if ([videoConnection isVideoOrientationSupported]) { if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait) { self.PreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait; [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait]; } else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) { self.PreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown]; } else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { self.PreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft; [videoConnection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft]; } else { self.PreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; [videoConnection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight]; } } }
- (IBAction)startStopButtonPressed:(id)sender { if (!WeAreRecording) { [self startRecording]; } else { [self stopRecording]; } } - (IBAction)cancel:(id)sender { if ([CaptureSession isRunning]) { if (self.delegate) { [self.delegate videoRecorderDidCancelRecordingVideo]; } } else { self.circleImage.hidden = NO; self.startButton.hidden = NO; self.useVideoButton.hidden = YES; [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; self.timeLabel.text = @"00:00"; self.elapsedTime = 0; [CaptureSession startRunning]; } } - (IBAction)useVideo:(id)sender { if (self.delegate) { [self.delegate videoRecorderDidFinishRecordingVideoWithOutputPath:self.outputPath]; } } - (IBAction)playVideo:(id)sender { if ([[NSFileManager defaultManager] fileExistsAtPath:self.outputPath]) { NSURL *outputFileURL = [[NSURL alloc] initFileURLWithPath:self.outputPath]; AVPlayer *player = [AVPlayer playerWithURL:outputFileURL]; AVPlayerViewController *controller = [[AVPlayerViewController alloc] init]; [self presentViewController:controller animated:YES completion:nil]; controller.player = player; controller.allowsPictureInPicturePlayback = NO; [player play]; } } // - (void)startRecording { // AudioServicesPlaySystemSound(BeginVideoRecording); WeAreRecording = YES; [self.cancelButton setHidden:YES]; [self.bottomView setHidden:YES]; [self.startButton setImage:[UIImage imageNamed:@"StopVideo"] forState:UIControlStateNormal]; self.timeLabel.text = @"00:00"; self.elapsedTime = 0; self.videoTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTime) userInfo:nil repeats:YES]; // , , [self deleteVideoFile]; // NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:self.outputPath]; [MovieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self]; } - (void)deleteVideoFile { NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:self.outputPath]) { NSError *error = nil; if ([fileManager removeItemAtPath:self.outputPath error:&error] == NO) { // } } } // - (void)stopRecording { // AudioServicesPlaySystemSound(EndVideoRecording); WeAreRecording = NO; [CaptureSession stopRunning]; self.circleImage.hidden = YES; self.startButton.hidden = YES; [self.cancelButton setTitle:@"Retake" forState:UIControlStateNormal]; [self.cancelButton setHidden:NO]; [self.bottomView setHidden:NO]; [self.startButton setImage:[UIImage imageNamed:@"StartVideo"] forState:UIControlStateNormal]; // [self.videoTimer invalidate]; self.videoTimer = nil; // [MovieFileOutput stopRecording]; } - (void)updateTime { self.elapsedTime += self.videoTimer.timeInterval; NSInteger seconds = (NSInteger)self.elapsedTime % 60; NSInteger minutes = ((NSInteger)self.elapsedTime / 60) % 60; self.timeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld", (long)minutes, (long)seconds]; } - (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error { if (WeAreRecording) { [self stopRecording]; } BOOL RecordedSuccessfully = YES; if ([error code] != noErr) { // , , // , id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey]; if (value != nil) { RecordedSuccessfully = [value boolValue]; } } if (RecordedSuccessfully) { // , Use Video self.useVideoButton.hidden = NO; } } - (void)viewDidUnload { [super viewDidUnload]; CaptureSession = nil; MovieFileOutput = nil; VideoInputDevice = nil; } @end
Source: https://habr.com/ru/post/316862/
All Articles