mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
[Media Picker] Fix some retain cycles and fix implicit self warnings.
This commit is contained in:
parent
fca2437adc
commit
87a6d13855
2 changed files with 144 additions and 120 deletions
|
@ -75,32 +75,10 @@
|
||||||
*/
|
*/
|
||||||
+ (instancetype)mediaPickerViewController;
|
+ (instancetype)mediaPickerViewController;
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet UIScrollView *mainScrollView;
|
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet UIView *captureViewContainer;
|
|
||||||
//@property (weak, nonatomic) IBOutlet NSLayoutConstraint *captureViewContainerHeightConstraint;
|
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet UIView *cameraPreviewContainerView;
|
|
||||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cameraPreviewContainerAspectRatio;
|
|
||||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *cameraActivityIndicator;
|
|
||||||
@property (weak, nonatomic) IBOutlet UIButton *closeButton;
|
|
||||||
@property (weak, nonatomic) IBOutlet UIButton *cameraSwitchButton;
|
|
||||||
@property (weak, nonatomic) IBOutlet UIButton *cameraCaptureButton;
|
|
||||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cameraCaptureButtonWidthConstraint;
|
|
||||||
@property (weak, nonatomic) IBOutlet MXKPieChartView *cameraVideoCaptureProgressView;
|
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet UIView *recentCapturesCollectionContainerView;
|
|
||||||
@property (weak, nonatomic) IBOutlet UICollectionView *recentCapturesCollectionView;
|
|
||||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *recentCapturesCollectionContainerViewHeightConstraint;
|
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet UIView *libraryViewContainer;
|
|
||||||
@property (weak, nonatomic) IBOutlet UITableView *userAlbumsTableView;
|
|
||||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *libraryViewContainerViewHeightConstraint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The delegate for the view controller.
|
The delegate for the view controller.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic) id<MediaPickerViewControllerDelegate> delegate;
|
@property (nonatomic, weak) id<MediaPickerViewControllerDelegate> delegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The array of the media types supported by the picker (default value is an array containing kUTTypeImage).
|
The array of the media types supported by the picker (default value is an array containing kUTTypeImage).
|
||||||
|
|
|
@ -94,6 +94,27 @@ static void *RecordingContext = &RecordingContext;
|
||||||
BOOL isStatusBarHidden;
|
BOOL isStatusBarHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet UIScrollView *mainScrollView;
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet UIView *captureViewContainer;
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet UIView *cameraPreviewContainerView;
|
||||||
|
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cameraPreviewContainerAspectRatio;
|
||||||
|
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *cameraActivityIndicator;
|
||||||
|
@property (weak, nonatomic) IBOutlet UIButton *closeButton;
|
||||||
|
@property (weak, nonatomic) IBOutlet UIButton *cameraSwitchButton;
|
||||||
|
@property (weak, nonatomic) IBOutlet UIButton *cameraCaptureButton;
|
||||||
|
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cameraCaptureButtonWidthConstraint;
|
||||||
|
@property (weak, nonatomic) IBOutlet MXKPieChartView *cameraVideoCaptureProgressView;
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet UIView *recentCapturesCollectionContainerView;
|
||||||
|
@property (weak, nonatomic) IBOutlet UICollectionView *recentCapturesCollectionView;
|
||||||
|
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *recentCapturesCollectionContainerViewHeightConstraint;
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet UIView *libraryViewContainer;
|
||||||
|
@property (weak, nonatomic) IBOutlet UITableView *userAlbumsTableView;
|
||||||
|
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *libraryViewContainerViewHeightConstraint;
|
||||||
|
|
||||||
@property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
|
@property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -163,19 +184,24 @@ static void *RecordingContext = &RecordingContext;
|
||||||
|
|
||||||
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
|
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
|
||||||
|
|
||||||
|
MXWeakify(self);
|
||||||
|
|
||||||
// Observe UIApplicationWillEnterForegroundNotification to refresh captures collection when app leaves the background state.
|
// Observe UIApplicationWillEnterForegroundNotification to refresh captures collection when app leaves the background state.
|
||||||
UIApplicationWillEnterForegroundNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
UIApplicationWillEnterForegroundNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||||
|
|
||||||
|
MXStrongifyAndReturnIfNil(self);
|
||||||
|
|
||||||
[self reloadRecentCapturesCollection];
|
[self reloadRecentCapturesCollection];
|
||||||
[self reloadUserLibraryAlbums];
|
[self reloadUserLibraryAlbums];
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Observe user interface theme change.
|
// Observe user interface theme change.
|
||||||
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||||
|
|
||||||
|
MXStrongifyAndReturnIfNil(self);
|
||||||
|
|
||||||
[self userInterfaceThemeDidChange];
|
[self userInterfaceThemeDidChange];
|
||||||
|
|
||||||
}];
|
}];
|
||||||
[self userInterfaceThemeDidChange];
|
[self userInterfaceThemeDidChange];
|
||||||
}
|
}
|
||||||
|
@ -292,7 +318,7 @@ static void *RecordingContext = &RecordingContext;
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
[self.cameraActivityIndicator stopAnimating];
|
[self.cameraActivityIndicator stopAnimating];
|
||||||
cameraPreviewLayer.hidden = NO;
|
self->cameraPreviewLayer.hidden = NO;
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -318,7 +344,7 @@ static void *RecordingContext = &RecordingContext;
|
||||||
if (granted)
|
if (granted)
|
||||||
{
|
{
|
||||||
// Load recent captures if this is not already done
|
// Load recent captures if this is not already done
|
||||||
if (!recentCaptures.count)
|
if (!self->recentCaptures.count)
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
|
@ -564,9 +590,13 @@ static void *RecordingContext = &RecordingContext;
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MXWeakify(self);
|
||||||
|
|
||||||
dispatch_async(userAlbumsQueue, ^{
|
dispatch_async(userAlbumsQueue, ^{
|
||||||
|
|
||||||
|
MXStrongifyAndReturnIfNil(self);
|
||||||
|
|
||||||
// List user albums which are not empty
|
// List user albums which are not empty
|
||||||
PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
|
PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
|
||||||
|
|
||||||
|
@ -575,9 +605,9 @@ static void *RecordingContext = &RecordingContext;
|
||||||
|
|
||||||
// Set up fetch options.
|
// Set up fetch options.
|
||||||
PHFetchOptions *options = [[PHFetchOptions alloc] init];
|
PHFetchOptions *options = [[PHFetchOptions alloc] init];
|
||||||
if ([_mediaTypes indexOfObject:(NSString *)kUTTypeImage] != NSNotFound)
|
if ([self->_mediaTypes indexOfObject:(NSString *)kUTTypeImage] != NSNotFound)
|
||||||
{
|
{
|
||||||
if ([_mediaTypes indexOfObject:(NSString *)kUTTypeMovie] != NSNotFound)
|
if ([self->_mediaTypes indexOfObject:(NSString *)kUTTypeMovie] != NSNotFound)
|
||||||
{
|
{
|
||||||
options.predicate = [NSPredicate predicateWithFormat:@"(mediaType == %d) || (mediaType == %d)", PHAssetMediaTypeImage, PHAssetMediaTypeVideo];
|
options.predicate = [NSPredicate predicateWithFormat:@"(mediaType == %d) || (mediaType == %d)", PHAssetMediaTypeImage, PHAssetMediaTypeVideo];
|
||||||
}
|
}
|
||||||
|
@ -586,7 +616,7 @@ static void *RecordingContext = &RecordingContext;
|
||||||
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeImage];
|
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeImage];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ([_mediaTypes indexOfObject:(NSString *)kUTTypeMovie] != NSNotFound)
|
else if ([self->_mediaTypes indexOfObject:(NSString *)kUTTypeMovie] != NSNotFound)
|
||||||
{
|
{
|
||||||
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeVideo];
|
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeVideo];
|
||||||
}
|
}
|
||||||
|
@ -626,11 +656,11 @@ static void *RecordingContext = &RecordingContext;
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
userAlbums = updatedUserAlbums;
|
self->userAlbums = updatedUserAlbums;
|
||||||
if (userAlbums.count)
|
if (self->userAlbums.count)
|
||||||
{
|
{
|
||||||
self.userAlbumsTableView.hidden = NO;
|
self.userAlbumsTableView.hidden = NO;
|
||||||
self.libraryViewContainerViewHeightConstraint.constant = (userAlbums.count * 74);
|
self.libraryViewContainerViewHeightConstraint.constant = (self->userAlbums.count * 74);
|
||||||
[self.libraryViewContainer needsUpdateConstraints];
|
[self.libraryViewContainer needsUpdateConstraints];
|
||||||
|
|
||||||
[self.userAlbumsTableView reloadData];
|
[self.userAlbumsTableView reloadData];
|
||||||
|
@ -759,13 +789,13 @@ static void *RecordingContext = &RecordingContext;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
isValidationInProgress = NO;
|
self->isValidationInProgress = NO;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] didSelectAsset: Failed to get image for asset");
|
NSLog(@"[MediaPickerVC] didSelectAsset: Failed to get image for asset");
|
||||||
isValidationInProgress = NO;
|
self->isValidationInProgress = NO;
|
||||||
|
|
||||||
// Alert user
|
// Alert user
|
||||||
NSError *error = info[@"PHImageErrorKey"];
|
NSError *error = info[@"PHImageErrorKey"];
|
||||||
|
@ -815,20 +845,20 @@ static void *RecordingContext = &RecordingContext;
|
||||||
[self.delegate mediaPickerController:self didSelectVideo:[avURLAsset URL]];
|
[self.delegate mediaPickerController:self didSelectVideo:[avURLAsset URL]];
|
||||||
}
|
}
|
||||||
|
|
||||||
isValidationInProgress = NO;
|
self->isValidationInProgress = NO;
|
||||||
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] Selected video asset is not initialized from an URL!");
|
NSLog(@"[MediaPickerVC] Selected video asset is not initialized from an URL!");
|
||||||
isValidationInProgress = NO;
|
self->isValidationInProgress = NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] didSelectAsset: Failed to get image for asset");
|
NSLog(@"[MediaPickerVC] didSelectAsset: Failed to get image for asset");
|
||||||
isValidationInProgress = NO;
|
self->isValidationInProgress = NO;
|
||||||
|
|
||||||
// Alert user
|
// Alert user
|
||||||
NSError *error = info[@"PHImageErrorKey"];
|
NSError *error = info[@"PHImageErrorKey"];
|
||||||
|
@ -1103,8 +1133,12 @@ static void *RecordingContext = &RecordingContext;
|
||||||
|
|
||||||
[self.cameraActivityIndicator startAnimating];
|
[self.cameraActivityIndicator startAnimating];
|
||||||
|
|
||||||
|
MXWeakify(self);
|
||||||
|
|
||||||
dispatch_async(cameraQueue, ^{
|
dispatch_async(cameraQueue, ^{
|
||||||
|
|
||||||
|
MXStrongifyAndReturnIfNil(self);
|
||||||
|
|
||||||
// Get the Camera Device
|
// Get the Camera Device
|
||||||
AVCaptureDevice *frontCamera = nil;
|
AVCaptureDevice *frontCamera = nil;
|
||||||
AVCaptureDevice *backCamera = nil;
|
AVCaptureDevice *backCamera = nil;
|
||||||
|
@ -1151,42 +1185,42 @@ static void *RecordingContext = &RecordingContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCameraInput = nil;
|
self->currentCameraInput = nil;
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
if (frontCamera)
|
if (frontCamera)
|
||||||
{
|
{
|
||||||
frontCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:frontCamera error:&error];
|
self->frontCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:frontCamera error:&error];
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] Error: %@", error);
|
NSLog(@"[MediaPickerVC] Error: %@", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frontCameraInput == nil)
|
if (self->frontCameraInput == nil)
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] Error creating front camera capture input");
|
NSLog(@"[MediaPickerVC] Error creating front camera capture input");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentCameraInput = frontCameraInput;
|
self->currentCameraInput = self->frontCameraInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backCamera)
|
if (backCamera)
|
||||||
{
|
{
|
||||||
error = nil;
|
error = nil;
|
||||||
backCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:backCamera error:&error];
|
self->backCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:backCamera error:&error];
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] Error: %@", error);
|
NSLog(@"[MediaPickerVC] Error: %@", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backCameraInput == nil)
|
if (self->backCameraInput == nil)
|
||||||
{
|
{
|
||||||
NSLog(@"[MediaPickerVC] Error creating back camera capture input");
|
NSLog(@"[MediaPickerVC] Error creating back camera capture input");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentCameraInput = backCameraInput;
|
self->currentCameraInput = self->backCameraInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1194,38 +1228,38 @@ static void *RecordingContext = &RecordingContext;
|
||||||
self.cameraSwitchButton.hidden = (!frontCamera || !backCamera);
|
self.cameraSwitchButton.hidden = (!frontCamera || !backCamera);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (currentCameraInput)
|
if (self->currentCameraInput)
|
||||||
{
|
{
|
||||||
// Create the AVCapture Session
|
// Create the AVCapture Session
|
||||||
captureSession = [[AVCaptureSession alloc] init];
|
self->captureSession = [[AVCaptureSession alloc] init];
|
||||||
|
|
||||||
if (isPictureCaptureEnabled)
|
if (self->isPictureCaptureEnabled)
|
||||||
{
|
{
|
||||||
[captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
|
[self->captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
|
||||||
}
|
}
|
||||||
else if (isVideoCaptureEnabled)
|
else if (self->isVideoCaptureEnabled)
|
||||||
{
|
{
|
||||||
[captureSession setSessionPreset:AVCaptureSessionPresetHigh];
|
[self->captureSession setSessionPreset:AVCaptureSessionPresetHigh];
|
||||||
}
|
}
|
||||||
|
|
||||||
cameraPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
|
self->cameraPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self->captureSession];
|
||||||
cameraPreviewLayer.masksToBounds = NO;
|
self->cameraPreviewLayer.masksToBounds = NO;
|
||||||
cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;//AVLayerVideoGravityResizeAspect;
|
self->cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;//AVLayerVideoGravityResizeAspect;
|
||||||
cameraPreviewLayer.backgroundColor = [[UIColor blackColor] CGColor];
|
self->cameraPreviewLayer.backgroundColor = [[UIColor blackColor] CGColor];
|
||||||
// cameraPreviewLayer.borderWidth = 2;
|
// cameraPreviewLayer.borderWidth = 2;
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
[[cameraPreviewLayer connection] setVideoOrientation:(AVCaptureVideoOrientation)[[UIApplication sharedApplication] statusBarOrientation]];
|
[[self->cameraPreviewLayer connection] setVideoOrientation:(AVCaptureVideoOrientation)[[UIApplication sharedApplication] statusBarOrientation]];
|
||||||
[cameraPreviewLayer connection].videoScaleAndCropFactor = 1.0;
|
[self->cameraPreviewLayer connection].videoScaleAndCropFactor = 1.0;
|
||||||
cameraPreviewLayer.frame = self.cameraPreviewContainerView.bounds;
|
self->cameraPreviewLayer.frame = self.cameraPreviewContainerView.bounds;
|
||||||
cameraPreviewLayer.hidden = YES;
|
self->cameraPreviewLayer.hidden = YES;
|
||||||
|
|
||||||
[self.cameraPreviewContainerView.layer addSublayer:cameraPreviewLayer];
|
[self.cameraPreviewContainerView.layer addSublayer:self->cameraPreviewLayer];
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
[captureSession addInput:currentCameraInput];
|
[self->captureSession addInput:self->currentCameraInput];
|
||||||
|
|
||||||
AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
|
AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
|
||||||
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
|
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
|
||||||
|
@ -1235,36 +1269,36 @@ static void *RecordingContext = &RecordingContext;
|
||||||
NSLog(@"[MediaPickerVC] Error: %@", error);
|
NSLog(@"[MediaPickerVC] Error: %@", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([captureSession canAddInput:audioDeviceInput])
|
if ([self->captureSession canAddInput:audioDeviceInput])
|
||||||
{
|
{
|
||||||
[captureSession addInput:audioDeviceInput];
|
[self->captureSession addInput:audioDeviceInput];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(caughtAVRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(caughtAVRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVCaptureSessionDidStartRunning:) name:AVCaptureSessionDidStartRunningNotification object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVCaptureSessionDidStartRunning:) name:AVCaptureSessionDidStartRunningNotification object:nil];
|
||||||
|
|
||||||
[captureSession startRunning];
|
[self->captureSession startRunning];
|
||||||
|
|
||||||
movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
|
self->movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
|
||||||
if ([captureSession canAddOutput:movieFileOutput])
|
if ([self->captureSession canAddOutput:self->movieFileOutput])
|
||||||
{
|
{
|
||||||
[captureSession addOutput:movieFileOutput];
|
[self->captureSession addOutput:self->movieFileOutput];
|
||||||
AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
|
AVCaptureConnection *connection = [self->movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
|
||||||
if ([connection isVideoStabilizationSupported])
|
if ([connection isVideoStabilizationSupported])
|
||||||
{
|
{
|
||||||
// Available on iOS 8 and later
|
// Available on iOS 8 and later
|
||||||
[connection setPreferredVideoStabilizationMode:YES];
|
[connection setPreferredVideoStabilizationMode:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[movieFileOutput addObserver:self forKeyPath:@"recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
|
[self->movieFileOutput addObserver:self forKeyPath:@"recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
|
||||||
|
|
||||||
stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
|
self->stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
|
||||||
if ([captureSession canAddOutput:stillImageOutput])
|
if ([self->captureSession canAddOutput:self->stillImageOutput])
|
||||||
{
|
{
|
||||||
[stillImageOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
|
[self->stillImageOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
|
||||||
[captureSession addOutput:stillImageOutput];
|
[self->captureSession addOutput:self->stillImageOutput];
|
||||||
}
|
}
|
||||||
[stillImageOutput addObserver:self forKeyPath:@"capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
|
[self->stillImageOutput addObserver:self forKeyPath:@"capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1273,7 +1307,7 @@ static void *RecordingContext = &RecordingContext;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isCaptureSessionSetupInProgress = NO;
|
self->isCaptureSessionSetupInProgress = NO;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1300,23 +1334,24 @@ static void *RecordingContext = &RecordingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_sync(cameraQueue, ^{
|
dispatch_sync(cameraQueue, ^{
|
||||||
frontCameraInput = nil;
|
|
||||||
backCameraInput = nil;
|
self->frontCameraInput = nil;
|
||||||
captureSession = nil;
|
self->backCameraInput = nil;
|
||||||
|
self->captureSession = nil;
|
||||||
|
|
||||||
if (movieFileOutput)
|
if (self->movieFileOutput)
|
||||||
{
|
{
|
||||||
[movieFileOutput removeObserver:self forKeyPath:@"recording" context:RecordingContext];
|
[self->movieFileOutput removeObserver:self forKeyPath:@"recording" context:RecordingContext];
|
||||||
movieFileOutput = nil;
|
self->movieFileOutput = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stillImageOutput)
|
if (self->stillImageOutput)
|
||||||
{
|
{
|
||||||
[stillImageOutput removeObserver:self forKeyPath:@"capturingStillImage" context:CapturingStillImageContext];
|
[self->stillImageOutput removeObserver:self forKeyPath:@"capturingStillImage" context:CapturingStillImageContext];
|
||||||
stillImageOutput = nil;
|
self->stillImageOutput = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCameraInput = nil;
|
self->currentCameraInput = nil;
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureSessionRuntimeErrorNotification object:nil];
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureSessionRuntimeErrorNotification object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureSessionDidStartRunningNotification object:nil];
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureSessionDidStartRunningNotification object:nil];
|
||||||
|
@ -1342,7 +1377,7 @@ static void *RecordingContext = &RecordingContext;
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
[self.cameraActivityIndicator stopAnimating];
|
[self.cameraActivityIndicator stopAnimating];
|
||||||
cameraPreviewLayer.hidden = NO;
|
self->cameraPreviewLayer.hidden = NO;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1357,45 +1392,45 @@ static void *RecordingContext = &RecordingContext;
|
||||||
if (frontCameraInput && backCameraInput)
|
if (frontCameraInput && backCameraInput)
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if (!canToggleCamera)
|
if (!self->canToggleCamera)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
canToggleCamera = NO;
|
self->canToggleCamera = NO;
|
||||||
|
|
||||||
AVCaptureDeviceInput *newInput = nil;
|
AVCaptureDeviceInput *newInput = nil;
|
||||||
AVCaptureDeviceInput *oldInput = nil;
|
AVCaptureDeviceInput *oldInput = nil;
|
||||||
if (currentCameraInput == frontCameraInput)
|
if (self->currentCameraInput == self->frontCameraInput)
|
||||||
{
|
{
|
||||||
newInput = backCameraInput;
|
newInput = self->backCameraInput;
|
||||||
oldInput = frontCameraInput;
|
oldInput = self->frontCameraInput;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newInput = frontCameraInput;
|
newInput = self->frontCameraInput;
|
||||||
oldInput = backCameraInput;
|
oldInput = self->backCameraInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_async(cameraQueue, ^{
|
dispatch_async(self->cameraQueue, ^{
|
||||||
|
|
||||||
[captureSession beginConfiguration];
|
[self->captureSession beginConfiguration];
|
||||||
[captureSession removeInput:oldInput];
|
[self->captureSession removeInput:oldInput];
|
||||||
if ([captureSession canAddInput:newInput]) {
|
if ([self->captureSession canAddInput:newInput]) {
|
||||||
[captureSession addInput:newInput];
|
[self->captureSession addInput:newInput];
|
||||||
currentCameraInput = newInput;
|
self->currentCameraInput = newInput;
|
||||||
}
|
}
|
||||||
[captureSession commitConfiguration];
|
[self->captureSession commitConfiguration];
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
[self.cameraActivityIndicator stopAnimating];
|
[self.cameraActivityIndicator stopAnimating];
|
||||||
cameraPreviewLayer.hidden = NO;
|
self->cameraPreviewLayer.hidden = NO;
|
||||||
canToggleCamera = YES;
|
self->canToggleCamera = YES;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
[self.cameraActivityIndicator startAnimating];
|
[self.cameraActivityIndicator startAnimating];
|
||||||
cameraPreviewLayer.hidden = YES;
|
self->cameraPreviewLayer.hidden = YES;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1404,10 +1439,15 @@ static void *RecordingContext = &RecordingContext;
|
||||||
{
|
{
|
||||||
self.cameraCaptureButton.enabled = NO;
|
self.cameraCaptureButton.enabled = NO;
|
||||||
|
|
||||||
|
MXWeakify(self);
|
||||||
|
|
||||||
dispatch_async(cameraQueue, ^{
|
dispatch_async(cameraQueue, ^{
|
||||||
if (![movieFileOutput isRecording])
|
|
||||||
|
MXStrongifyAndReturnIfNil(self);
|
||||||
|
|
||||||
|
if (![self->movieFileOutput isRecording])
|
||||||
{
|
{
|
||||||
lockInterfaceRotation = YES;
|
self->lockInterfaceRotation = YES;
|
||||||
|
|
||||||
if ([[UIDevice currentDevice] isMultitaskingSupported])
|
if ([[UIDevice currentDevice] isMultitaskingSupported])
|
||||||
{
|
{
|
||||||
|
@ -1425,14 +1465,14 @@ static void *RecordingContext = &RecordingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the orientation on the movie file output video connection before starting recording.
|
// Update the orientation on the movie file output video connection before starting recording.
|
||||||
[[movieFileOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[cameraPreviewLayer connection] videoOrientation]];
|
[[self->movieFileOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[self->cameraPreviewLayer connection] videoOrientation]];
|
||||||
|
|
||||||
// Turning OFF flash for video recording
|
// Turning OFF flash for video recording
|
||||||
[MediaPickerViewController setFlashMode:AVCaptureFlashModeOff forDevice:[currentCameraInput device]];
|
[MediaPickerViewController setFlashMode:AVCaptureFlashModeOff forDevice:[self->currentCameraInput device]];
|
||||||
|
|
||||||
// Start recording to a temporary file.
|
// Start recording to a temporary file.
|
||||||
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[@"movie" stringByAppendingPathExtension:@"mov"]];
|
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[@"movie" stringByAppendingPathExtension:@"mov"]];
|
||||||
[movieFileOutput startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
|
[self->movieFileOutput startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1440,9 +1480,10 @@ static void *RecordingContext = &RecordingContext;
|
||||||
- (void)stopMovieRecording
|
- (void)stopMovieRecording
|
||||||
{
|
{
|
||||||
dispatch_async(cameraQueue, ^{
|
dispatch_async(cameraQueue, ^{
|
||||||
if ([movieFileOutput isRecording])
|
|
||||||
|
if ([self->movieFileOutput isRecording])
|
||||||
{
|
{
|
||||||
[movieFileOutput stopRecording];
|
[self->movieFileOutput stopRecording];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1451,15 +1492,20 @@ static void *RecordingContext = &RecordingContext;
|
||||||
{
|
{
|
||||||
self.cameraCaptureButton.enabled = NO;
|
self.cameraCaptureButton.enabled = NO;
|
||||||
|
|
||||||
|
MXWeakify(self);
|
||||||
|
|
||||||
dispatch_async(cameraQueue, ^{
|
dispatch_async(cameraQueue, ^{
|
||||||
|
|
||||||
|
MXStrongifyAndReturnIfNil(self);
|
||||||
|
|
||||||
// Update the orientation on the still image output video connection before capturing.
|
// Update the orientation on the still image output video connection before capturing.
|
||||||
[[stillImageOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[cameraPreviewLayer connection] videoOrientation]];
|
[[self->stillImageOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[self->cameraPreviewLayer connection] videoOrientation]];
|
||||||
|
|
||||||
// Flash set to Auto for Still Capture
|
// Flash set to Auto for Still Capture
|
||||||
[MediaPickerViewController setFlashMode:AVCaptureFlashModeAuto forDevice:[currentCameraInput device]];
|
[MediaPickerViewController setFlashMode:AVCaptureFlashModeAuto forDevice:[self->currentCameraInput device]];
|
||||||
|
|
||||||
// Capture a still image.
|
// Capture a still image.
|
||||||
[stillImageOutput captureStillImageAsynchronouslyFromConnection:[stillImageOutput connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
|
[self->stillImageOutput captureStillImageAsynchronouslyFromConnection:[self->stillImageOutput connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
|
||||||
|
|
||||||
if (imageDataSampleBuffer)
|
if (imageDataSampleBuffer)
|
||||||
{
|
{
|
||||||
|
@ -1504,10 +1550,10 @@ static void *RecordingContext = &RecordingContext;
|
||||||
- (void)runStillImageCaptureAnimation
|
- (void)runStillImageCaptureAnimation
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[cameraPreviewLayer setOpacity:0.0];
|
[self->cameraPreviewLayer setOpacity:0.0];
|
||||||
|
|
||||||
[UIView animateWithDuration:.25 animations:^{
|
[UIView animateWithDuration:.25 animations:^{
|
||||||
[cameraPreviewLayer setOpacity:1.0];
|
[self->cameraPreviewLayer setOpacity:1.0];
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1535,18 +1581,18 @@ static void *RecordingContext = &RecordingContext;
|
||||||
{
|
{
|
||||||
self.cameraSwitchButton.enabled = NO;
|
self.cameraSwitchButton.enabled = NO;
|
||||||
|
|
||||||
videoRecordStartDate = [NSDate date];
|
self->videoRecordStartDate = [NSDate date];
|
||||||
|
|
||||||
self.cameraVideoCaptureProgressView.hidden = NO;
|
self.cameraVideoCaptureProgressView.hidden = NO;
|
||||||
updateVideoRecordingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateVideoRecordingDuration) userInfo:nil repeats:YES];
|
self->updateVideoRecordingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateVideoRecordingDuration) userInfo:nil repeats:YES];
|
||||||
|
|
||||||
self.cameraCaptureButton.enabled = YES;
|
self.cameraCaptureButton.enabled = YES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.cameraVideoCaptureProgressView.hidden = YES;
|
self.cameraVideoCaptureProgressView.hidden = YES;
|
||||||
[updateVideoRecordingTimer invalidate];
|
[self->updateVideoRecordingTimer invalidate];
|
||||||
updateVideoRecordingTimer = nil;
|
self->updateVideoRecordingTimer = nil;
|
||||||
self.cameraVideoCaptureProgressView.progress = 0;
|
self.cameraVideoCaptureProgressView.progress = 0;
|
||||||
|
|
||||||
// The preview will be restored during captureOutput:didFinishRecordingToOutputFileAtURL: callback.
|
// The preview will be restored during captureOutput:didFinishRecordingToOutputFileAtURL: callback.
|
||||||
|
|
Loading…
Reference in a new issue