-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ios video logic #86
Ios video logic #86
Changes from 12 commits
9541f35
d7341ae
279743a
57af3b3
32dd7cb
7ac1815
d37631a
933b35d
cfc7057
cf831ce
5b9aa6e
25eac64
a4e07db
6a864f4
c360b81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -10,6 +10,7 @@ - (CameraSessionManager *)init { | |||||
[self.session setSessionPreset:AVCaptureSessionPresetPhoto]; | ||||||
} | ||||||
self.filterLock = [[NSLock alloc] init]; | ||||||
self.movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason why this line is not done in the Im taking the example of AVCapturePhotoOutput *imageOutput = [[AVCapturePhotoOutput alloc] init];
if ([self.session canAddOutput:imageOutput]) {
[self.session addOutput:imageOutput];
self.imageOutput = imageOutput;
} |
||||||
} | ||||||
return self; | ||||||
} | ||||||
|
@@ -101,6 +102,19 @@ - (void) setupSession:(NSString *)defaultCamera completion:(void(^)(BOOL started | |||||
} | ||||||
|
||||||
AVCaptureVideoDataOutput *dataOutput = [[AVCaptureVideoDataOutput alloc] init]; | ||||||
|
||||||
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; | ||||||
NSError *audioError = nil; | ||||||
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&audioError]; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should |
||||||
if (audioInput && [self.session canAddInput:audioInput]) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Will this be enough? When looking at similar code blocks, only this check is done. For example on line 93: if ([self.session canAddInput:videoDeviceInput]) {
[self.session addInput:videoDeviceInput];
self.videoDeviceInput = videoDeviceInput;
} |
||||||
[self.session addInput:audioInput]; | ||||||
} else { | ||||||
NSLog(@"Error adding audio input: %@", audioError.localizedDescription); | ||||||
} | ||||||
|
||||||
if ([self.session canAddOutput:self.movieFileOutput]) { | ||||||
[self.session addOutput:self.movieFileOutput]; | ||||||
} | ||||||
if ([self.session canAddOutput:dataOutput]) { | ||||||
self.dataOutput = dataOutput; | ||||||
[dataOutput setAlwaysDiscardsLateVideoFrames:YES]; | ||||||
|
@@ -225,6 +239,22 @@ - (void)switchCameraTo:(NSString*)cameraMode completion:(void (^)(BOOL success)) | |||||
}); | ||||||
} | ||||||
|
||||||
- (void)startRecordingToOutputFileURL:(NSURL *)fileURL recordingDelegate:(id<AVCaptureFileOutputRecordingDelegate>)recordingDelegate { | ||||||
if (!self.movieFileOutput.isRecording) { | ||||||
AVCaptureConnection *connection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo]; | ||||||
if ([connection isVideoOrientationSupported]) { | ||||||
connection.videoOrientation = [self getCurrentOrientation]; | ||||||
} | ||||||
[self.movieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:recordingDelegate]; | ||||||
Comment on lines
+243
to
+248
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we do an early return? if (self.movieFileOutput.isRecording) return;
// logic to start recording |
||||||
} | ||||||
} | ||||||
|
||||||
- (void)stopRecording { | ||||||
if (self.movieFileOutput.isRecording) { | ||||||
[self.movieFileOutput stopRecording]; | ||||||
} | ||||||
} | ||||||
|
||||||
- (BOOL)deviceHasUltraWideCamera { | ||||||
if (@available(iOS 13.0, *)) { | ||||||
AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInUltraWideCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -358,4 +358,104 @@ - (void)deallocateMemory { | |
locationManager = nil; | ||
} | ||
|
||
- (void) initVideoCallback:(CDVInvokedUrlCommand*)command { | ||
self.videoCallbackContext = command; | ||
NSDictionary *data = @{ @"videoCallbackInitialized" : @true }; | ||
|
||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:data]; | ||
[pluginResult setKeepCallbackAsBool:true]; | ||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; | ||
} | ||
|
||
- (void)startVideoCapture:(CDVInvokedUrlCommand*)command { | ||
if (self.sessionManager != nil && !self.sessionManager.movieFileOutput.isRecording) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can invert the condition and make an early return instead of having an if (self.sessionManager == nil || self.sessionManager.movieFileOutput.isRecording) {
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Session not initialized or already recording"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}
// other logic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The condition should be an |
||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); | ||
NSString *libraryDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"NoCloud"]; | ||
NSString* uniqueFileName = [NSString stringWithFormat:@"%@.mp4",[[NSUUID UUID] UUIDString]]; | ||
NSString *dataPath = [libraryDirectory stringByAppendingPathComponent:uniqueFileName]; | ||
NSURL *fileURL = [NSURL fileURLWithPath:dataPath]; | ||
[self.sessionManager startRecordingToOutputFileURL:fileURL recordingDelegate:self]; | ||
} else { | ||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Session not initialized or already recording"]; | ||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. setKeepCallback true same in the other methods There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we keep it same logic as with Androids and the single callback |
||
} | ||
} | ||
|
||
- (void)stopVideoCapture:(CDVInvokedUrlCommand*)command { | ||
if (self.sessionManager != nil && self.sessionManager.movieFileOutput.isRecording) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comments for the |
||
[self.sessionManager stopRecording]; | ||
} else { | ||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Session not initialized or not recording"]; | ||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; | ||
} | ||
} | ||
|
||
- (NSString*)generateThumbnailForVideoAtURL:(NSURL *)videoURL { | ||
AVAsset *asset = [AVAsset assetWithURL:videoURL]; | ||
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset]; | ||
imageGenerator.appliesPreferredTrackTransform = YES; | ||
CMTime time = CMTimeMakeWithSeconds(1.0, 600); | ||
NSError *error = nil; | ||
CMTime actualTime; | ||
CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:&actualTime error:&error]; | ||
|
||
if (error) { | ||
NSLog(@"Error generating thumbnail: %@", error.localizedDescription); | ||
YushraJewon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil; | ||
} | ||
|
||
UIImage *thumbnail = [[UIImage alloc] initWithCGImage:imageRef]; | ||
CGImageRelease(imageRef); | ||
|
||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); | ||
NSString *libraryDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"NoCloud"]; | ||
|
||
NSError *directoryError = nil; | ||
if (![[NSFileManager defaultManager] fileExistsAtPath:libraryDirectory]) { | ||
[[NSFileManager defaultManager] createDirectoryAtPath:libraryDirectory withIntermediateDirectories:YES attributes:nil error:&directoryError]; | ||
|
||
if (directoryError) { | ||
NSLog(@"Error creating NoCloud directory: %@", directoryError.localizedDescription); | ||
YushraJewon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil; | ||
} | ||
} | ||
|
||
NSString *uniqueFileName = [NSString stringWithFormat:@"video_thumb_%@.jpg", [[NSUUID UUID] UUIDString]]; | ||
NSString *filePath = [libraryDirectory stringByAppendingPathComponent:uniqueFileName]; | ||
|
||
NSData *jpegData = UIImageJPEGRepresentation(thumbnail, 1.0); | ||
|
||
if ([jpegData writeToFile:filePath atomically:YES]) { | ||
NSLog(@"Thumbnail saved successfully at path: %@", filePath); | ||
} else { | ||
NSLog(@"Failed to save thumbnail."); | ||
YushraJewon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil; | ||
} | ||
return filePath; | ||
} | ||
|
||
|
||
- (void)captureOutput:(AVCaptureFileOutput *)output didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections { | ||
NSDictionary *result = @{@"recording": @TRUE}; | ||
|
||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result]; | ||
[pluginResult setKeepCallbackAsBool:true]; | ||
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.videoCallbackContext.callbackId]; | ||
} | ||
|
||
- (void)captureOutput:(AVCaptureFileOutput *)output didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error { | ||
if (error) { | ||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.localizedDescription]; | ||
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.videoCallbackContext.callbackId]; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can add a |
||
NSString *thumbnail = [self generateThumbnailForVideoAtURL:outputFileURL]; | ||
NSString *filePath = [outputFileURL path]; | ||
NSDictionary *result = @{@"nativePath": filePath, @"thumbnail": thumbnail}; | ||
YushraJewon marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check if we actually have the thumbnail generated before adding it to the dictionary? we can return null if we get errors from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can remove |
||
|
||
YushraJewon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result]; | ||
[pluginResult setKeepCallbackAsBool:true]; | ||
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.videoCallbackContext.callbackId]; | ||
} | ||
} | ||
|
||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this method be renamed to
startRecording
?