From c0d5aabf0b32f71326ff153d31e3cb5c588062da Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Mon, 12 Mar 2018 09:52:20 +0100 Subject: [PATCH 1/2] feat(rn-camera): add codec option for ios --- ios/RN/RNCamera.h | 1 + ios/RN/RNCamera.m | 24 ++++++++++++++++++++++-- ios/RN/RNCameraManager.h | 1 + ios/RN/RNCameraManager.m | 19 +++++++++++++++++++ src/RNCamera.js | 2 ++ 5 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ios/RN/RNCamera.h b/ios/RN/RNCamera.h index 5c27af8..83efe6d 100644 --- a/ios/RN/RNCamera.h +++ b/ios/RN/RNCamera.h @@ -30,6 +30,7 @@ @property (assign, nonatomic) float focusDepth; @property (assign, nonatomic) NSInteger whiteBalance; @property (nonatomic, assign, getter=isReadingBarCodes) BOOL barCodeReading; +@property(assign, nonatomic) AVVideoCodecType videoCodecType; - (id)initWithBridge:(RCTBridge *)bridge; - (void)updateType; diff --git a/ios/RN/RNCamera.m b/ios/RN/RNCamera.m index e81d252..be792e3 100644 --- a/ios/RN/RNCamera.m +++ b/ios/RN/RNCamera.m @@ -404,7 +404,21 @@ static NSDictionary *defaultFaceDetectorOptions = nil; AVCaptureConnection *connection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo]; [connection setVideoOrientation:[RNCameraUtils videoOrientationForInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation]]]; - + + if (options[@"codec"]) { + AVVideoCodecType videoCodecType = options[@"codec"]; + if (@available(iOS 10, *)) { + if ([self.movieFileOutput.availableVideoCodecTypes containsObject:videoCodecType]) { + [self.movieFileOutput setOutputSettings:@{AVVideoCodecKey:videoCodecType} forConnection:connection]; + self.videoCodecType = videoCodecType; + } else { + RCTLogWarn(@"%s: Video Codec '%@' is not supported on this device.", __func__, videoCodecType); + } + } else { + RCTLogWarn(@"%s: Setting videoCodec is only supported above iOS version 10.", __func__); + } + } + dispatch_async(self.sessionQueue, ^{ NSString *path = [RNFileSystem generatePathInDirectory:[[RNFileSystem cacheDirectoryPath] stringByAppendingString:@"Camera"] withExtension:@".mov"]; NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:path]; @@ -714,12 +728,18 @@ static NSDictionary *defaultFaceDetectorOptions = nil; } } if (success && self.videoRecordedResolve != nil) { - self.videoRecordedResolve(@{ @"uri": outputFileURL.absoluteString }); + AVVideoCodecType videoCodec = self.videoCodecType; + if (videoCodec == nil) { + videoCodec = [self.movieFileOutput.availableVideoCodecTypes firstObject]; + } + + self.videoRecordedResolve(@{ @"uri": outputFileURL.absoluteString, @"codec":videoCodec }); } else if (self.videoRecordedReject != nil) { self.videoRecordedReject(@"E_RECORDING_FAILED", @"An error occurred while recording a video.", error); } self.videoRecordedResolve = nil; self.videoRecordedReject = nil; + self.videoCodecType = nil; [self cleanupMovieFileCapture]; // If face detection has been running prior to recording to file diff --git a/ios/RN/RNCameraManager.h b/ios/RN/RNCameraManager.h index 91a6b13..52bc556 100644 --- a/ios/RN/RNCameraManager.h +++ b/ios/RN/RNCameraManager.h @@ -49,6 +49,7 @@ typedef NS_ENUM(NSInteger, RNCameraVideoResolution) { @interface RNCameraManager : RCTViewManager + (NSDictionary *)validBarCodeTypes; ++ (NSDictionary *)validCodecTypes; @end diff --git a/ios/RN/RNCameraManager.m b/ios/RN/RNCameraManager.m index 3ff8f41..ec4adcd 100644 --- a/ios/RN/RNCameraManager.m +++ b/ios/RN/RNCameraManager.m @@ -55,6 +55,7 @@ RCT_EXPORT_VIEW_PROPERTY(onFacesDetected, RCTDirectEventBlock); @"480p": @(RNCameraVideo4x3), @"4:3": @(RNCameraVideo4x3), }, + @"VideoCodec": [[self class] validCodecTypes], @"BarCodeType" : [[self class] validBarCodeTypes], @"FaceDetection" : [[self class] faceDetectorConstants] }; @@ -65,6 +66,24 @@ RCT_EXPORT_VIEW_PROPERTY(onFacesDetected, RCTDirectEventBlock); return @[@"onCameraReady", @"onMountError", @"onBarCodeRead", @"onFacesDetected"]; } ++ (NSDictionary *)validCodecTypes +{ + if (@available(iOS 11, *)) { + return @{ + @"H264": AVVideoCodecTypeH264, + @"HVEC": AVVideoCodecTypeHEVC, + @"JPEG": AVVideoCodecTypeJPEG, + @"AppleProRes422": AVVideoCodecTypeAppleProRes422, + @"AppleProRes4444": AVVideoCodecTypeAppleProRes4444 + }; + } else { + return @{ + @"H264": AVVideoCodecH264, + @"JPEG": AVVideoCodecJPEG + }; + } +} + + (NSDictionary *)validBarCodeTypes { return @{ diff --git a/src/RNCamera.js b/src/RNCamera.js index 829e47f..a7aafb3 100644 --- a/src/RNCamera.js +++ b/src/RNCamera.js @@ -35,6 +35,7 @@ type RecordingOptions = { maxDuration?: number, maxFileSize?: number, quality?: number | string, + codec?: string, mute?: boolean, }; @@ -96,6 +97,7 @@ export default class Camera extends React.Component { AutoFocus: CameraManager.AutoFocus, WhiteBalance: CameraManager.WhiteBalance, VideoQuality: CameraManager.VideoQuality, + VideoCodec: CameraManager.VideoCodec, BarCodeType: CameraManager.BarCodeType, FaceDetection: CameraManager.FaceDetection, }; From 2b9d8db21389af624fd7ee3fe0eafa8348a3b776 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Mon, 12 Mar 2018 21:44:53 +0100 Subject: [PATCH 2/2] docs(codec): document ios codec option --- docs/RNCamera.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/RNCamera.md b/docs/RNCamera.md index 3dfb0f2..8b886d9 100644 --- a/docs/RNCamera.md +++ b/docs/RNCamera.md @@ -284,8 +284,13 @@ The promise will be fulfilled with an object with some of the following properti - `ios` Specifies capture settings suitable for VGA quality (640x480 pixel) video output. (Same as RNCamera.Constants.VideoQuality.480p). - `android` Quality level corresponding to the 480p (720 x 480) resolution but with video frame width set to 640. - If nothing is passed the device's highest camera quality will be used as default. - + If nothing is passed the device's highest camera quality will be used as default. + - `iOS` `codec`. This option specifies the codec of the output video. Setting the codec is only supported on `iOS >= 10`. The possible values are: + - `RNCamera.Constants.VideoCodec['H264']` + - `RNCamera.Constants.VideoCodec['JPEG']` + - `RNCamera.Constants.VideoCodec['HVEC']` (`iOS >= 11`) + - `RNCamera.Constants.VideoCodec['AppleProRes422']` (`iOS >= 11`) + - `RNCamera.Constants.VideoCodec['AppleProRes4444']` (`iOS >= 11`) - `maxDuration` (float greater than 0). Specifies the maximum duration of the video to be recorded in seconds. If nothing is specified, no time limit will be used. - `maxFileSize` (int greater than 0). Specifies the maximum file size, in bytes, of the video to be recorded. For 1mb, for example, use 1*1024*1024. If nothing is specified, no size limit will be used. @@ -296,6 +301,8 @@ The promise will be fulfilled with an object with some of the following properti - `uri`: returns the path to the video saved on your app's cache directory. + - `iOS` `codec`: the codec of the recorded video. One of `RNCamera.Constants.VideoCodec` + #### `stopRecording: void` Should be called after recordAsync() to make the promise be fulfilled and get the video uri.