diff --git a/docs/installation.md b/docs/installation.md
index eee8256cd..c1322c49b 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -4,6 +4,7 @@ title: Installation
---
This document is split into two main sections:
+
1. Required installation steps for basic usage of `react-native-camera`
2. Additional installation steps for usage of Face Detection/Text Recognition/BarCode with [MLKit](https://developers.google.com/ml-kit)
@@ -40,16 +41,16 @@ _These steps assume installation for iOS/Android. To install it with Windows, se
3. Append the following lines to `android/settings.gradle`:
- ```gradle
- include ':react-native-camera'
- project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
- ```
+```gradle
+include ':react-native-camera'
+project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
+```
4. Insert the following lines in `android/app/build.gradle` inside the dependencies block:
- ```gradle
- implementation project(':react-native-camera')
- ```
+```gradle
+implementation project(':react-native-camera')
+```
## iOS - other required steps
@@ -76,38 +77,39 @@ Add permissions with usage descriptions to your app `Info.plist`:
Additional information in case of problems
- You might need to adjust your Podfile following the example below:
-
- ```ruby
- target 'yourTargetName' do
- # See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
- pod 'React', :path => '../node_modules/react-native', :subspecs => [
- 'Core',
- 'CxxBridge', # Include this for RN >= 0.47
- 'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
- 'RCTText',
- 'RCTNetwork',
- 'RCTWebSocket', # Needed for debugging
- 'RCTAnimation', # Needed for FlatList and animations running on native UI thread
- # Add any other subspecs you want to use in your project
- ]
-
- # Explicitly include Yoga if you are using RN >= 0.42.0
- pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
-
- # Third party deps podspec link
- pod 'react-native-camera', path: '../node_modules/react-native-camera'
-
- end
+You might need to adjust your Podfile following the example below:
- post_install do |installer|
- installer.pods_project.targets.each do |target|
- if target.name == "React"
- target.remove_from_project
- end
+```ruby
+target 'yourTargetName' do
+ # See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
+ pod 'React', :path => '../node_modules/react-native', :subspecs => [
+ 'Core',
+ 'CxxBridge', # Include this for RN >= 0.47
+ 'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
+ 'RCTText',
+ 'RCTNetwork',
+ 'RCTWebSocket', # Needed for debugging
+ 'RCTAnimation', # Needed for FlatList and animations running on native UI thread
+ # Add any other subspecs you want to use in your project
+ ]
+
+ # Explicitly include Yoga if you are using RN >= 0.42.0
+ pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
+
+ # Third party deps podspec link
+ pod 'react-native-camera', path: '../node_modules/react-native-camera'
+
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ if target.name == "React"
+ target.remove_from_project
end
end
- ```
+end
+```
+
## Android - other required steps
@@ -141,18 +143,19 @@ android {
Additional information in case of problems
- 1. Make sure you use `JDK >= 1.7` and your `buildToolsVersion >= 25.0.2`
+1. Make sure you use `JDK >= 1.7` and your `buildToolsVersion >= 25.0.2`
- 2. Make sure you have jitpack added in `android/build.gradle`
+2. Make sure you have jitpack added in `android/build.gradle`
+
+```gradle
+allprojects {
+ repositories {
+ maven { url "https://www.jitpack.io" }
+ maven { url "https://maven.google.com" }
+ }
+}
+```
- ```gradle
- allprojects {
- repositories {
- maven { url "https://www.jitpack.io" }
- maven { url "https://maven.google.com" }
- }
- }
- ```
# Additional installation steps
@@ -170,7 +173,7 @@ If you want any of these optional features, you will need to use CocoaPods.
Add dependency towards `react-native-camera` in your `Podfile` with `subspecs` using one of the following:
-* For Face Detection:
+- For Face Detection:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
@@ -178,7 +181,7 @@ pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs
]
```
-* For Text Recognition:
+- For Text Recognition:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
@@ -186,7 +189,7 @@ pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs
]
```
-* For BarCode Recognition:
+- For BarCode Recognition:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
@@ -194,7 +197,7 @@ pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs
]
```
-* For all possible detections:
+- For all possible detections:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
@@ -231,10 +234,9 @@ In short, you would need to
Additional information in case of problems
- - If you have issues with duplicate symbols you will need to enable dead code stripping option in your Xcode (Target > Build Settings > search for "Dead code stripping") [see here](https://github.com/firebase/quickstart-ios/issues/487#issuecomment-415313053).
- - If you are using `pod Firebase/Core` with a version set below 5.13 you might want to add `pod 'GoogleAppMeasurement', '~> 5.3.0'` to your podfile
-
-
+- If you have issues with duplicate symbols you will need to enable dead code stripping option in your Xcode (Target > Build Settings > search for "Dead code stripping") [see here](https://github.com/firebase/quickstart-ios/issues/487#issuecomment-415313053).
+- If you are using `pod Firebase/Core` with a version set below 5.13 you might want to add `pod 'GoogleAppMeasurement', '~> 5.3.0'` to your podfile
+
## Android
@@ -291,157 +293,165 @@ apply plugin: 'com.google.gms.google-services'
Additional information in case of problems
The current Android library defaults to the below values for the Google SDK and Libraries,
- ```gradle
- def DEFAULT_COMPILE_SDK_VERSION = 26
- def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
- def DEFAULT_TARGET_SDK_VERSION = 26
- def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
- def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
- ```
-
- You can override this settings by adding a Project-wide gradle configuration properties for
- use by all modules in your ReactNative project by adding the below to `android/build.gradle`
- file,
-
- ```gradle
- buildscript {...}
-
- allprojects {...}
-
- /**
- * Project-wide gradle configuration properties for use by all modules
- */
- ext {
- compileSdkVersion = 26
- targetSdkVersion = 26
- buildToolsVersion = "26.0.2"
- googlePlayServicesVersion = "12.0.1"
- googlePlayServicesVisionVersion = "15.0.2"
- supportLibVersion = "27.1.0"
- }
- ```
+```gradle
+def DEFAULT_COMPILE_SDK_VERSION = 26
+def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
+def DEFAULT_TARGET_SDK_VERSION = 26
+def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
+def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
+```
- The above settings in the ReactNative project over-rides the values present in the `react-native-camera`
- module. For your reference below is the `android/build.gradle` file of the module.
+You can override this settings by adding a Project-wide gradle configuration properties for
+use by all modules in your ReactNative project by adding the below to `android/build.gradle`
+file,
- ```gradle
- def safeExtGet(prop, fallback) {
- rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
- }
+```gradle
+buildscript {...}
+
+allprojects {...}
+
+/**
+* Project-wide gradle configuration properties for use by all modules
+*/
+ext {
+ compileSdkVersion = 26
+ targetSdkVersion = 26
+ buildToolsVersion = "26.0.2"
+ googlePlayServicesVersion = "12.0.1"
+ googlePlayServicesVisionVersion = "15.0.2"
+ supportLibVersion = "27.1.0"
+}
+```
- buildscript {
- repositories {
- google()
- maven {
- url 'https://maven.google.com'
- }
- jcenter()
- }
+The above settings in the ReactNative project over-rides the values present in the `react-native-camera`
+module. For your reference below is the `android/build.gradle` file of the module.
- dependencies {
- classpath 'com.android.tools.build:gradle:3.3.1'
+```gradle
+def safeExtGet(prop, fallback) {
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+}
+
+buildscript {
+ repositories {
+ google()
+ maven {
+ url 'https://maven.google.com'
}
+ jcenter()
}
- apply plugin: 'com.android.library'
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.3.1'
+ }
+}
- android {
- compileSdkVersion safeExtGet('compileSdkVersion', 28)
- buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
+apply plugin: 'com.android.library'
- defaultConfig {
- minSdkVersion safeExtGet('minSdkVersion', 16)
- targetSdkVersion safeExtGet('targetSdkVersion', 28)
- }
+android {
+ compileSdkVersion safeExtGet('compileSdkVersion', 28)
+ buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
- flavorDimensions "react-native-camera"
+ defaultConfig {
+ minSdkVersion safeExtGet('minSdkVersion', 16)
+ targetSdkVersion safeExtGet('targetSdkVersion', 28)
+ }
- productFlavors {
- general {
- dimension "react-native-camera"
- }
- mlkit {
- dimension "react-native-camera"
- }
- }
+ flavorDimensions "react-native-camera"
- sourceSets {
- main {
- java.srcDirs = ['src/main/java']
- }
- general {
- java.srcDirs = ['src/general/java']
- }
- mlkit {
- java.srcDirs = ['src/mlkit/java']
- }
+ productFlavors {
+ general {
+ dimension "react-native-camera"
}
-
- lintOptions {
- abortOnError false
- warning 'InvalidPackage'
+ mlkit {
+ dimension "react-native-camera"
}
}
- repositories {
- google()
- jcenter()
- maven {
- url 'https://maven.google.com'
+ sourceSets {
+ main {
+ java.srcDirs = ['src/main/java']
}
- maven { url "https://jitpack.io" }
- maven {
- // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
- url "$rootDir/../node_modules/react-native/android"
+ general {
+ java.srcDirs = ['src/general/java']
+ }
+ mlkit {
+ java.srcDirs = ['src/mlkit/java']
}
}
- dependencies {
- def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
-
- implementation 'com.facebook.react:react-native:+'
- implementation "com.google.zxing:core:3.3.3"
- implementation "com.drewnoakes:metadata-extractor:2.11.0"
- generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"
- implementation "com.android.support:exifinterface:${safeExtGet('supportLibVersion', '28.0.0')}"
- implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '28.0.0')}"
- implementation "com.android.support:support-v4:${safeExtGet('supportLibVersion', '28.0.0')}"
- mlkitImplementation "com.google.firebase:firebase-ml-vision:${safeExtGet('firebase-ml-vision', '19.0.3')}"
- mlkitImplementation "com.google.firebase:firebase-ml-vision-face-model:${safeExtGet('firebase-ml-vision-face-model', '17.0.2')}"
+ lintOptions {
+ abortOnError false
+ warning 'InvalidPackage'
}
- ```
-
- If you are using a version of `googlePlayServicesVersion` that does not have `play-services-vision`, you can specify a different version of `play-services-vision` by adding `googlePlayServicesVisionVersion` to the project-wide properties
-
- ```gradle
- ext {
- compileSdkVersion = 26
- targetSdkVersion = 26
- buildToolsVersion = "26.0.2"
- googlePlayServicesVersion = "16.0.1"
- googlePlayServicesVisionVersion = "15.0.2"
- supportLibVersion = "27.1.0"
+}
+
+repositories {
+ google()
+ jcenter()
+ maven {
+ url 'https://maven.google.com'
}
- ```
+ maven { url "https://jitpack.io" }
+ maven {
+ // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
+ url "$rootDir/../node_modules/react-native/android"
+ }
+}
+
+dependencies {
+ def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
+
+ implementation 'com.facebook.react:react-native:+'
+ implementation "com.google.zxing:core:3.3.3"
+ implementation "com.drewnoakes:metadata-extractor:2.11.0"
+ generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"
+ implementation "com.android.support:exifinterface:${safeExtGet('supportLibVersion', '28.0.0')}"
+ implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '28.0.0')}"
+ implementation "com.android.support:support-v4:${safeExtGet('supportLibVersion', '28.0.0')}"
+ mlkitImplementation "com.google.firebase:firebase-ml-vision:${safeExtGet('firebase-ml-vision', '19.0.3')}"
+ mlkitImplementation "com.google.firebase:firebase-ml-vision-face-model:${safeExtGet('firebase-ml-vision-face-model', '17.0.2')}"
+}
+```
+
+If you are using a version of `googlePlayServicesVersion` that does not have `play-services-vision`, you can specify a different version of `play-services-vision` by adding `googlePlayServicesVisionVersion` to the project-wide properties
+
+```gradle
+ext {
+ compileSdkVersion = 26
+ targetSdkVersion = 26
+ buildToolsVersion = "26.0.2"
+ googlePlayServicesVersion = "16.0.1"
+ googlePlayServicesVisionVersion = "15.0.2"
+ supportLibVersion = "27.1.0"
+}
+```
+
# Windows
-## Windows RNW C++/WinRT details
+## Manual linking for RNW 0.62
+
1. `yarn install react-native-camera`
2. Link the library as described below:
- windows/myapp.sln
- Add the ReactNativeCamera project to your solution.
- Open the solution in Visual Studio 2019
- Right-click Solution icon in Solution Explorer > Add > Existing Project Select node_modules\react-native-camera\windows\ReactNativeCameraCPP\ReactNativeCameraCPP.vcxproj
- windows/myapp/myapp.vcxproj
- Add a reference to ReactNativeCameraCPP to your main application project. From Visual Studio 2019:
- Right-click main application project > Add > Reference... Check ReactNativeCameraCPP from Solution Projects.
-3. Modify files below to add the Camera package providers to your main application project
- pch.h
- Add #include "winrt/ReactNativeCameraCPP.h".
- app.cpp
- Add PackageProviders().Append(winrt::ReactNativeCameraCPP::ReactPackageProvider()); before InitializeComponent();
-3. Add the capabilities (permissions) for the webcam and microphone as described here: [docs.microsoft / audio-video-camera](https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access#add-capability-declarations-to-the-app-manifest)
+ 1. Add the _ReactNativeCameraCPP_ project to your solution (eg. `windows\yourapp.sln`)
+ 1. Open your solution in Visual Studio 2019
+ 2. Right-click Solution icon in Solution Explorer > Add > Existing Project...
+ 3. Select `node_modules\react-native-camera\windows\ReactNativeCameraCPP\ReactNativeCameraCPP.vcxproj`
+ 2. Add a reference to _ReactNativeCameraCPP_ to your main application project (eg. `windows\yourapp\yourapp.vcxproj`)
+ 1. Open your solution in Visual Studio 2019
+ 2. Right-click main application project > Add > Reference...
+ 3. Check _ReactNativeCameraCPP_ from Solution Projects
+3. Modify files below to add the package providers to your main application project
+ 1. `pch.h`
+ 1. Add `#include "winrt/ReactNativeCameraCPP.h"`
+ 2. `App.cpp`
+ 1. Add `PackageProviders().Append(winrt::ReactNativeCameraCPP::ReactPackageProvider());` before `InitializeComponent();`
+4. Add the capabilities (permissions) for the webcam and microphone as described here: [Add capability declarations to the app manifest](https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access#add-capability-declarations-to-the-app-manifest)
+5. If you plan on capturing images to the Pictures Library, or videos to the Videos Library, be sure to enable those capabilities too
+
+## Manual linking for RNW 0.61
+
+Follow the same manual steps for RNW 0.62 above, but for step 2 substitute _ReactNativeCameraCPP61_ for _ReactNativeCameraCPP_.
Follow the [Q & A](QA.md) section if you are having compilation issues.
diff --git a/src/RNCamera.js b/src/RNCamera.js
index d3c6d4830..be2318593 100644
--- a/src/RNCamera.js
+++ b/src/RNCamera.js
@@ -364,6 +364,7 @@ export default class Camera extends React.Component {
GoogleVisionBarcodeDetection: CameraManager.GoogleVisionBarcodeDetection,
FaceDetection: CameraManager.FaceDetection,
CameraStatus,
+ CaptureTarget: CameraManager.CaptureTarget,
RecordAudioPermissionStatus: RecordAudioPermissionStatusEnum,
VideoStabilization: CameraManager.VideoStabilization,
Orientation: {
diff --git a/windows/.clang-format b/windows/.clang-format
new file mode 100644
index 000000000..42d7289d3
--- /dev/null
+++ b/windows/.clang-format
@@ -0,0 +1,92 @@
+---
+AccessModifierOffset: -1
+AlignAfterOpenBracket: AlwaysBreak
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: true
+AlignOperands: false
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Empty
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Attach
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit: 120
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ]
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: 'pch.h'
+ Priority: -1
+ - Regex: '.*\.g\..*'
+ Priority: 1
+ - Regex: '^<.*\.h(pp)?>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 8
+UseTab: Never
+...
diff --git a/windows/.gitignore b/windows/.gitignore
index cbf7e7f42..4ea0c7b5a 100644
--- a/windows/.gitignore
+++ b/windows/.gitignore
@@ -1,6 +1,5 @@
*AppPackages*
*BundleArtifacts*
-*ReactAssets*
#OS junk files
[Tt]humbs.db
@@ -36,6 +35,17 @@ ipch/
[Rr]elease*/
Ankh.NoLoad
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
#MonoDevelop
*.pidb
*.userprefs
@@ -76,3 +86,7 @@ packages/
*.DotSettings
.vs/
*project.lock.json
+
+#Files generated by the VS build
+**/Generated Files/**
+
diff --git a/windows/README.md b/windows/README.md
new file mode 100644
index 000000000..573452970
--- /dev/null
+++ b/windows/README.md
@@ -0,0 +1,33 @@
+# React Native Camera (Windows)
+
+React Native Camera is currently maintained for React Native Windows (RNW) >= 0.61.
+
+There are two implementations of `react-native-camera` in this folder:
+
+1. _ReactNativeCameraCPP_ is the currently maintained implementation:
+ 1. Use _ReactNativeCameraCPP_ for RNW >= 0.62.
+ 2. Use _ReactNativeCameraCPP61_ for RNW 0.61.
+2. _RNCamera_ is a legacy implementation for `react-native-windows@0.59.0-legacy.2`. It is no longer maintained.
+
+## Why all the different versions?
+
+RNW was originally implemented in C#, where development stopped at version 0.59. _RNCamera_ is the version of React Native Camera written in C# against that (now "legacy") RNW.
+
+RNW was then rebuilt from scratch in C++, and version 0.61 was the first release to support native community modules. _ReactNativeCameraCPP_ is the version of React Native Camera written in C++ against the current RNW.
+
+RNW 0.62 brought a variety of build improvements, but now requires both Visual Studio 2019 and a newer Windows SDK. So while the native module APIs are 99% forward-compatible, it's currently necessary to maintain a separate `ReactNativeCameraCPP61.vcxproj` project for RNW 0.61 users. The `ReactNativeCameraCPP.vcxproj` project targets RNW >= 0.62 users.
+
+# Local Development Setup (RNW >= 0.62)
+
+In order to work on _ReactNativeCameraCPP_, you'll need to install the [Windows Development Dependencies](https://microsoft.github.io/react-native-windows/docs/rnw-dependencies).
+
+In addition, `react-native-camera` targets React Native 0.59 and doesn't include React Native Windows as a dependency. So in order to build _ReactNativeCameraCPP_ locally you'll need to temporarily upgrade the development dependencies:
+
+```
+yarn upgrade react-native@^0.62.2
+yarn add react-native-windows@^0.62.0 --dev
+```
+
+Now you should be able to open `ReactNativeCameraCPP.sln` in Visual Studio and build the project.
+
+> _Note:_ In order to test your code changes don't break RNW 0.61, you'll want to do the above steps but targeting RN/RNW 0.61, and using `ReactNativeCameraCPP61.sln`.
diff --git a/windows/ReactNativeCameraCPP.sln b/windows/ReactNativeCameraCPP.sln
new file mode 100644
index 000000000..e7ba91465
--- /dev/null
+++ b/windows/ReactNativeCameraCPP.sln
@@ -0,0 +1,250 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactNativeCameraCPP", "ReactNativeCameraCPP\ReactNativeCameraCPP.vcxproj", "{7432C343-CC07-4BC7-9BD0-8C467BE0F018}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{4F6E56C3-12C5-4457-9239-0ACF0B7150A8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "..\node_modules\react-native-windows\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Shared", "..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactWindowsCore", "..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxproj", "{11C084A3-A57C-4296-A679-CAC17B603144}"
+EndProject
+Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxitems*{11c084a3-a57c-4296-a679-cac17b603144}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ WinUI3|ARM = WinUI3|ARM
+ WinUI3|ARM64 = WinUI3|ARM64
+ WinUI3|x64 = WinUI3|x64
+ WinUI3|x86 = WinUI3|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|ARM.ActiveCfg = Debug|ARM
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|ARM.Build.0 = Debug|ARM
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|ARM64.Build.0 = Debug|ARM64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|x64.ActiveCfg = Debug|x64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|x64.Build.0 = Debug|x64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|x86.ActiveCfg = Debug|Win32
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Debug|x86.Build.0 = Debug|Win32
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|ARM.ActiveCfg = Release|ARM
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|ARM.Build.0 = Release|ARM
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|ARM64.ActiveCfg = Release|ARM64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|ARM64.Build.0 = Release|ARM64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|x64.ActiveCfg = Release|x64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|x64.Build.0 = Release|x64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|x86.ActiveCfg = Release|Win32
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.Release|x86.Build.0 = Release|Win32
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|ARM.ActiveCfg = Release|ARM
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|ARM.Build.0 = Release|ARM
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|ARM64.ActiveCfg = Release|ARM64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|ARM64.Build.0 = Release|ARM64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|x64.ActiveCfg = Release|x64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|x64.Build.0 = Release|x64
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|x86.ActiveCfg = Release|Win32
+ {7432C343-CC07-4BC7-9BD0-8C467BE0F018}.WinUI3|x86.Build.0 = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.Build.0 = Debug|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.ActiveCfg = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.Build.0 = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|ARM.ActiveCfg = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|ARM.Build.0 = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|ARM64.ActiveCfg = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|ARM64.Build.0 = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|x64.ActiveCfg = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|x64.Build.0 = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|x86.ActiveCfg = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.WinUI3|x86.Build.0 = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.Build.0 = Debug|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.ActiveCfg = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.Build.0 = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|ARM.ActiveCfg = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|ARM.Build.0 = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|ARM64.ActiveCfg = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|ARM64.Build.0 = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|x64.ActiveCfg = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|x64.Build.0 = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|x86.ActiveCfg = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.WinUI3|x86.Build.0 = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.Build.0 = Debug|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.ActiveCfg = Debug|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.Build.0 = Debug|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.ActiveCfg = Debug|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.Build.0 = Debug|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.ActiveCfg = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.Build.0 = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.Build.0 = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.ActiveCfg = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.Build.0 = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.ActiveCfg = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.Build.0 = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|ARM.ActiveCfg = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|ARM.Build.0 = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|ARM64.ActiveCfg = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|ARM64.Build.0 = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|x64.ActiveCfg = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|x64.Build.0 = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|x86.ActiveCfg = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.WinUI3|x86.Build.0 = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.ActiveCfg = Debug|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.Build.0 = Debug|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.ActiveCfg = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.Build.0 = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|ARM.ActiveCfg = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|ARM.Build.0 = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|ARM64.ActiveCfg = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|ARM64.Build.0 = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|x64.ActiveCfg = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|x64.Build.0 = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|x86.ActiveCfg = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.WinUI3|x86.Build.0 = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.Build.0 = Debug|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.ActiveCfg = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.Build.0 = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|ARM.ActiveCfg = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|ARM.Build.0 = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|ARM64.ActiveCfg = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|ARM64.Build.0 = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|x64.ActiveCfg = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|x64.Build.0 = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|x86.ActiveCfg = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.WinUI3|x86.Build.0 = Release|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM.ActiveCfg = Debug|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM.Build.0 = Debug|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM64.Build.0 = Debug|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x64.ActiveCfg = Debug|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x64.Build.0 = Debug|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x86.ActiveCfg = Debug|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x86.Build.0 = Debug|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM.ActiveCfg = Release|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM.Build.0 = Release|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM64.ActiveCfg = Release|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM64.Build.0 = Release|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x64.ActiveCfg = Release|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x64.Build.0 = Release|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x86.ActiveCfg = Release|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x86.Build.0 = Release|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|ARM.ActiveCfg = WinUI3|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|ARM.Build.0 = WinUI3|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|ARM64.ActiveCfg = WinUI3|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|ARM64.Build.0 = WinUI3|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|x64.ActiveCfg = WinUI3|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|x64.Build.0 = WinUI3|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|x86.ActiveCfg = WinUI3|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.WinUI3|x86.Build.0 = WinUI3|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {0CC28589-39E4-4288-B162-97B959F8B843} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ {11C084A3-A57C-4296-A679-CAC17B603144} = {4F6E56C3-12C5-4457-9239-0ACF0B7150A8}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {1E57BD63-8052-4EAD-9EEB-BD1A60F44A67}
+ EndGlobalSection
+EndGlobal
diff --git a/windows/ReactNativeCameraCPP/CameraRotationHelper.cpp b/windows/ReactNativeCameraCPP/CameraRotationHelper.cpp
index 34b6fb7bc..1f90b7253 100644
--- a/windows/ReactNativeCameraCPP/CameraRotationHelper.cpp
+++ b/windows/ReactNativeCameraCPP/CameraRotationHelper.cpp
@@ -3,240 +3,215 @@
#include "CameraRotationHelper.g.cpp"
namespace winrt {
- using namespace Windows::Devices::Enumeration;
- using namespace Windows::Devices::Sensors;
- using namespace Windows::Storage::FileProperties;
- using namespace Windows::Graphics::Display;
-} //namespace winrt
-
-namespace winrt::ReactNativeCameraCPP::implementation
-{
- CameraRotationHelper::CameraRotationHelper(EnclosureLocation location)
- {
- m_cameraEnclosureLocation = location;
-
- if (!IsEnclosureLocationExternal(m_cameraEnclosureLocation) && m_orientationSensor != nullptr)
- {
- m_sensorOrientationChanged_revoker = m_orientationSensor.OrientationChanged(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args)
- {
- if (auto self = ref.get()) {
- self->SimpleOrientationSensor_OrientationChanged(sender, args);
- }
- });
- }
- m_displayOrientationChanged_revoker = m_displayInformation.OrientationChanged(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args)
- {
- if (auto self = ref.get()) {
- self->DisplayInformation_OrientationChanged(sender, args);
- }
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Devices::Sensors;
+using namespace Windows::Storage::FileProperties;
+using namespace Windows::Graphics::Display;
+} // namespace winrt
+
+namespace winrt::ReactNativeCameraCPP::implementation {
+CameraRotationHelper::CameraRotationHelper(EnclosureLocation location) {
+ m_cameraEnclosureLocation = location;
+
+ if (!IsEnclosureLocationExternal(m_cameraEnclosureLocation) && m_orientationSensor != nullptr) {
+ m_sensorOrientationChanged_revoker = m_orientationSensor.OrientationChanged(
+ winrt::auto_revoke, [ref = get_weak()](auto const &sender, auto const &args) {
+ if (auto self = ref.get()) {
+ self->SimpleOrientationSensor_OrientationChanged(sender, args);
+ }
});
- }
-
- PhotoOrientation CameraRotationHelper::GetConvertedCameraCaptureOrientation()
- {
- auto orientation = GetCameraCaptureOrientation();
- return ConvertSimpleOrientationToPhotoOrientation(orientation);
- }
-
- SimpleOrientation CameraRotationHelper::GetCameraCaptureOrientation()
- {
- if (IsEnclosureLocationExternal(m_cameraEnclosureLocation))
- {
- // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
- return SimpleOrientation::NotRotated;
+ }
+ m_displayOrientationChanged_revoker = m_displayInformation.OrientationChanged(
+ winrt::auto_revoke, [ref = get_weak()](auto const &sender, auto const &args) {
+ if (auto self = ref.get()) {
+ self->DisplayInformation_OrientationChanged(sender, args);
}
+ });
+}
- // Get the device orientation offset by the camera hardware offset
- auto deviceOrientation = m_orientationSensor ? m_orientationSensor.GetCurrentOrientation() : SimpleOrientation::NotRotated;
- auto result = SubtractOrientations(deviceOrientation, GetCameraOrientationRelativeToNativeOrientation());
+PhotoOrientation CameraRotationHelper::GetConvertedCameraCaptureOrientation() {
+ auto orientation = GetCameraCaptureOrientation();
+ return ConvertSimpleOrientationToPhotoOrientation(orientation);
+}
- // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
- if (ShouldMirrorPreview())
- {
- result = MirrorOrientation(result);
- }
- return result;
- }
-
- SimpleOrientation CameraRotationHelper::GetCameraPreviewOrientation()
- {
- if (IsEnclosureLocationExternal(m_cameraEnclosureLocation))
- {
- // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
- return SimpleOrientation::NotRotated;
- }
+SimpleOrientation CameraRotationHelper::GetCameraCaptureOrientation() {
+ if (IsEnclosureLocationExternal(m_cameraEnclosureLocation)) {
+ // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
+ return SimpleOrientation::NotRotated;
+ }
+
+ // Get the device orientation offset by the camera hardware offset
+ auto deviceOrientation =
+ m_orientationSensor ? m_orientationSensor.GetCurrentOrientation() : SimpleOrientation::NotRotated;
+ auto result = SubtractOrientations(deviceOrientation, GetCameraOrientationRelativeToNativeOrientation());
+
+ // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
+ if (ShouldMirrorPreview()) {
+ result = MirrorOrientation(result);
+ }
+ return result;
+}
- // Get the app display rotation offset by the camera hardware offset
- auto result = ConvertDisplayOrientationToSimpleOrientation(m_displayInformation.CurrentOrientation());
- result = SubtractOrientations(result, GetCameraOrientationRelativeToNativeOrientation());
+SimpleOrientation CameraRotationHelper::GetCameraPreviewOrientation() {
+ if (IsEnclosureLocationExternal(m_cameraEnclosureLocation)) {
+ // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
+ return SimpleOrientation::NotRotated;
+ }
+
+ // Get the app display rotation offset by the camera hardware offset
+ auto result = ConvertDisplayOrientationToSimpleOrientation(m_displayInformation.CurrentOrientation());
+ result = SubtractOrientations(result, GetCameraOrientationRelativeToNativeOrientation());
+
+ // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
+ if (ShouldMirrorPreview()) {
+ result = MirrorOrientation(result);
+ }
+ return result;
+}
- // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
- if (ShouldMirrorPreview())
- {
- result = MirrorOrientation(result);
- }
- return result;
- }
-
- int CameraRotationHelper::GetCameraPreviewClockwiseDegrees()
- {
- auto rotation = GetCameraPreviewOrientation();
- return ConvertSimpleOrientationToClockwiseDegrees(rotation);
- }
-
- PhotoOrientation CameraRotationHelper::ConvertSimpleOrientationToPhotoOrientation(SimpleOrientation orientation)
- {
- switch (orientation)
- {
- case SimpleOrientation::Rotated90DegreesCounterclockwise:
- return PhotoOrientation::Rotate90;
- case SimpleOrientation::Rotated180DegreesCounterclockwise:
- return PhotoOrientation::Rotate180;
- case SimpleOrientation::Rotated270DegreesCounterclockwise:
- return PhotoOrientation::Rotate270;
- case SimpleOrientation::NotRotated:
- default:
- return PhotoOrientation::Normal;
- }
- }
-
- int CameraRotationHelper::ConvertSimpleOrientationToClockwiseDegrees(SimpleOrientation orientation)
- {
- switch (orientation)
- {
- case SimpleOrientation::Rotated90DegreesCounterclockwise:
- return 270;
- case SimpleOrientation::Rotated180DegreesCounterclockwise:
- return 180;
- case SimpleOrientation::Rotated270DegreesCounterclockwise:
- return 90;
- case SimpleOrientation::NotRotated:
- default:
- return 0;
- }
- }
-
- SimpleOrientation CameraRotationHelper::ConvertDisplayOrientationToSimpleOrientation(DisplayOrientations orientation)
- {
- SimpleOrientation result;
- switch (orientation)
- {
- case DisplayOrientations::Landscape:
- result = SimpleOrientation::NotRotated;
- break;
- case DisplayOrientations::PortraitFlipped:
- result = SimpleOrientation::Rotated90DegreesCounterclockwise;
- break;
- case DisplayOrientations::LandscapeFlipped:
- result = SimpleOrientation::Rotated180DegreesCounterclockwise;
- break;
- case DisplayOrientations::Portrait:
- default:
- result = SimpleOrientation::Rotated270DegreesCounterclockwise;
- break;
- }
+int CameraRotationHelper::GetCameraPreviewClockwiseDegrees() {
+ auto rotation = GetCameraPreviewOrientation();
+ return ConvertSimpleOrientationToClockwiseDegrees(rotation);
+}
- // Above assumes landscape; offset is needed if native orientation is portrait
- if (m_displayInformation.NativeOrientation() == DisplayOrientations::Portrait)
- {
- result = AddOrientations(result, SimpleOrientation::Rotated90DegreesCounterclockwise);
- }
+PhotoOrientation CameraRotationHelper::ConvertSimpleOrientationToPhotoOrientation(SimpleOrientation orientation) {
+ switch (orientation) {
+ case SimpleOrientation::Rotated90DegreesCounterclockwise:
+ return PhotoOrientation::Rotate90;
+ case SimpleOrientation::Rotated180DegreesCounterclockwise:
+ return PhotoOrientation::Rotate180;
+ case SimpleOrientation::Rotated270DegreesCounterclockwise:
+ return PhotoOrientation::Rotate270;
+ case SimpleOrientation::NotRotated:
+ default:
+ return PhotoOrientation::Normal;
+ }
+}
- return result;
- }
-
- SimpleOrientation CameraRotationHelper::SubtractOrientations(SimpleOrientation a, SimpleOrientation b)
- {
- auto aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
- auto bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
- // Add 360 to ensure the modulus operator does not operate on a negative
- auto result = (360 + (aRot - bRot)) % 360;
- return ConvertClockwiseDegreesToSimpleOrientation(result);
- }
-
- SimpleOrientation CameraRotationHelper::MirrorOrientation(SimpleOrientation orientation)
- {
- // This only affects the 90 and 270 degree cases, because rotating 0 and 180 degrees is the same clockwise and counter-clockwise
- switch (orientation)
- {
- case SimpleOrientation::Rotated90DegreesCounterclockwise:
- return SimpleOrientation::Rotated270DegreesCounterclockwise;
- case SimpleOrientation::Rotated270DegreesCounterclockwise:
- return SimpleOrientation::Rotated90DegreesCounterclockwise;
- }
- return orientation;
- }
-
- SimpleOrientation CameraRotationHelper::AddOrientations(SimpleOrientation a, SimpleOrientation b)
- {
- auto aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
- auto bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
- auto result = (aRot + bRot) % 360;
- return ConvertClockwiseDegreesToSimpleOrientation(result);
- }
-
- SimpleOrientation CameraRotationHelper::ConvertClockwiseDegreesToSimpleOrientation(int orientation)
- {
- switch (orientation)
- {
- case 270:
- return SimpleOrientation::Rotated90DegreesCounterclockwise;
- case 180:
- return SimpleOrientation::Rotated180DegreesCounterclockwise;
- case 90:
- return SimpleOrientation::Rotated270DegreesCounterclockwise;
- case 0:
- default:
- return SimpleOrientation::NotRotated;
- }
- }
-
- void CameraRotationHelper::SimpleOrientationSensor_OrientationChanged(IInspectable const&, IInspectable const&)
- {
- if (m_orientationSensor.GetCurrentOrientation() != SimpleOrientation::Faceup && m_orientationSensor.GetCurrentOrientation() != SimpleOrientation::Facedown)
- {
- // Only raise the OrientationChanged event if the device is not parallel to the ground. This allows users to take pictures of documents (FaceUp)
- // or the ceiling (FaceDown) in portrait or landscape, by first holding the device in the desired orientation, and then pointing the camera
- // either up or down, at the desired subject.
- //Note: This assumes that the camera is either facing the same way as the screen, or the opposite way. For devices with cameras mounted
- // on other panels, this logic should be adjusted.
- m_orientationChangedEvent(*this, false);
- }
- }
-
- void CameraRotationHelper::DisplayInformation_OrientationChanged(IInspectable const&, IInspectable const&)
- {
- m_orientationChangedEvent(*this, true);
- }
-
- bool CameraRotationHelper::ShouldMirrorPreview()
- {
- // It is recommended that applications mirror the preview for front-facing cameras, as it gives users a more natural experience, since it behaves more like a mirror
- return (m_cameraEnclosureLocation.Panel() == Panel::Front);
- }
-
- SimpleOrientation CameraRotationHelper::GetCameraOrientationRelativeToNativeOrientation()
- {
- // Get the rotation angle of the camera enclosure as it is mounted in the device hardware
- auto enclosureAngle = ConvertClockwiseDegreesToSimpleOrientation(static_cast(m_cameraEnclosureLocation.RotationAngleInDegreesClockwise()));
-
- // Account for the fact that, on portrait-first devices, the built in camera sensor is read at a 90 degree offset to the native orientation
- if (m_displayInformation.NativeOrientation() == DisplayOrientations::Portrait &&
- !IsEnclosureLocationExternal(m_cameraEnclosureLocation))
- {
- enclosureAngle = AddOrientations(SimpleOrientation::Rotated90DegreesCounterclockwise, enclosureAngle);
- }
+int CameraRotationHelper::ConvertSimpleOrientationToClockwiseDegrees(SimpleOrientation orientation) {
+ switch (orientation) {
+ case SimpleOrientation::Rotated90DegreesCounterclockwise:
+ return 270;
+ case SimpleOrientation::Rotated180DegreesCounterclockwise:
+ return 180;
+ case SimpleOrientation::Rotated270DegreesCounterclockwise:
+ return 90;
+ case SimpleOrientation::NotRotated:
+ default:
+ return 0;
+ }
+}
+
+SimpleOrientation CameraRotationHelper::ConvertDisplayOrientationToSimpleOrientation(DisplayOrientations orientation) {
+ SimpleOrientation result;
+ switch (orientation) {
+ case DisplayOrientations::Landscape:
+ result = SimpleOrientation::NotRotated;
+ break;
+ case DisplayOrientations::PortraitFlipped:
+ result = SimpleOrientation::Rotated90DegreesCounterclockwise;
+ break;
+ case DisplayOrientations::LandscapeFlipped:
+ result = SimpleOrientation::Rotated180DegreesCounterclockwise;
+ break;
+ case DisplayOrientations::Portrait:
+ default:
+ result = SimpleOrientation::Rotated270DegreesCounterclockwise;
+ break;
+ }
+
+ // Above assumes landscape; offset is needed if native orientation is portrait
+ if (m_displayInformation.NativeOrientation() == DisplayOrientations::Portrait) {
+ result = AddOrientations(result, SimpleOrientation::Rotated90DegreesCounterclockwise);
+ }
+
+ return result;
+}
+
+SimpleOrientation CameraRotationHelper::SubtractOrientations(SimpleOrientation a, SimpleOrientation b) {
+ auto aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
+ auto bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
+ // Add 360 to ensure the modulus operator does not operate on a negative
+ auto result = (360 + (aRot - bRot)) % 360;
+ return ConvertClockwiseDegreesToSimpleOrientation(result);
+}
+
+SimpleOrientation CameraRotationHelper::MirrorOrientation(SimpleOrientation orientation) {
+ // This only affects the 90 and 270 degree cases, because rotating 0 and 180 degrees is the same clockwise and
+ // counter-clockwise
+ switch (orientation) {
+ case SimpleOrientation::Rotated90DegreesCounterclockwise:
+ return SimpleOrientation::Rotated270DegreesCounterclockwise;
+ case SimpleOrientation::Rotated270DegreesCounterclockwise:
+ return SimpleOrientation::Rotated90DegreesCounterclockwise;
+ }
+ return orientation;
+}
+
+SimpleOrientation CameraRotationHelper::AddOrientations(SimpleOrientation a, SimpleOrientation b) {
+ auto aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
+ auto bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
+ auto result = (aRot + bRot) % 360;
+ return ConvertClockwiseDegreesToSimpleOrientation(result);
+}
+
+SimpleOrientation CameraRotationHelper::ConvertClockwiseDegreesToSimpleOrientation(int orientation) {
+ switch (orientation) {
+ case 270:
+ return SimpleOrientation::Rotated90DegreesCounterclockwise;
+ case 180:
+ return SimpleOrientation::Rotated180DegreesCounterclockwise;
+ case 90:
+ return SimpleOrientation::Rotated270DegreesCounterclockwise;
+ case 0:
+ default:
+ return SimpleOrientation::NotRotated;
+ }
+}
+
+void CameraRotationHelper::SimpleOrientationSensor_OrientationChanged(IInspectable const &, IInspectable const &) {
+ if (m_orientationSensor.GetCurrentOrientation() != SimpleOrientation::Faceup &&
+ m_orientationSensor.GetCurrentOrientation() != SimpleOrientation::Facedown) {
+ // Only raise the OrientationChanged event if the device is not parallel to the ground. This allows users to take
+ // pictures of documents (FaceUp) or the ceiling (FaceDown) in portrait or landscape, by first holding the device in
+ // the desired orientation, and then pointing the camera either up or down, at the desired subject.
+ // Note: This assumes that the camera is either facing the same way as the screen, or the opposite way. For devices
+ // with cameras mounted
+ // on other panels, this logic should be adjusted.
+ m_orientationChangedEvent(*this, false);
+ }
+}
+
+void CameraRotationHelper::DisplayInformation_OrientationChanged(IInspectable const &, IInspectable const &) {
+ m_orientationChangedEvent(*this, true);
+}
+
+bool CameraRotationHelper::ShouldMirrorPreview() {
+ // It is recommended that applications mirror the preview for front-facing cameras, as it gives users a more natural
+ // experience, since it behaves more like a mirror
+ return (m_cameraEnclosureLocation.Panel() == Panel::Front);
+}
- return enclosureAngle;
- }
-
- winrt::event_token CameraRotationHelper::OrientationChanged(Windows::Foundation::EventHandler const& handler)
- {
- return m_orientationChangedEvent.add(handler);
- }
+SimpleOrientation CameraRotationHelper::GetCameraOrientationRelativeToNativeOrientation() {
+ // Get the rotation angle of the camera enclosure as it is mounted in the device hardware
+ auto enclosureAngle = ConvertClockwiseDegreesToSimpleOrientation(
+ static_cast(m_cameraEnclosureLocation.RotationAngleInDegreesClockwise()));
+
+ // Account for the fact that, on portrait-first devices, the built in camera sensor is read at a 90 degree offset to
+ // the native orientation
+ if (m_displayInformation.NativeOrientation() == DisplayOrientations::Portrait &&
+ !IsEnclosureLocationExternal(m_cameraEnclosureLocation)) {
+ enclosureAngle = AddOrientations(SimpleOrientation::Rotated90DegreesCounterclockwise, enclosureAngle);
+ }
+
+ return enclosureAngle;
+}
+
+winrt::event_token CameraRotationHelper::OrientationChanged(Windows::Foundation::EventHandler const &handler) {
+ return m_orientationChangedEvent.add(handler);
+}
- void CameraRotationHelper::OrientationChanged(winrt::event_token const& token) noexcept
- {
- m_orientationChangedEvent.remove(token);
- }
+void CameraRotationHelper::OrientationChanged(winrt::event_token const &token) noexcept {
+ m_orientationChangedEvent.remove(token);
}
+} // namespace winrt::ReactNativeCameraCPP::implementation
diff --git a/windows/ReactNativeCameraCPP/CameraRotationHelper.h b/windows/ReactNativeCameraCPP/CameraRotationHelper.h
index bdc28bfc9..b318d33c2 100644
--- a/windows/ReactNativeCameraCPP/CameraRotationHelper.h
+++ b/windows/ReactNativeCameraCPP/CameraRotationHelper.h
@@ -1,62 +1,69 @@
#pragma once
+
#include "winrt/Windows.Graphics.Display.h"
+
#include "CameraRotationHelper.g.h"
// This is a Cpp/WinRT implementation of the Camera Rotation Helper class(C#) on MSDN:
// https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/handle-device-orientation-with-mediacapture#camerarotationhelper-full-code-listing
-namespace winrt::ReactNativeCameraCPP::implementation
-{
- struct CameraRotationHelper : CameraRotationHelperT
- {
- public:
- CameraRotationHelper(winrt::Windows::Devices::Enumeration::EnclosureLocation location);
- winrt::event_token OrientationChanged(Windows::Foundation::EventHandler const& handler);
- void OrientationChanged(winrt::event_token const& token) noexcept;
-
- winrt::Windows::Devices::Sensors::SimpleOrientation GetCameraCaptureOrientation();
- winrt::Windows::Storage::FileProperties::PhotoOrientation GetConvertedCameraCaptureOrientation();
- winrt::Windows::Devices::Sensors::SimpleOrientation GetCameraPreviewOrientation();
- int GetCameraPreviewClockwiseDegrees();
-
- private:
-
- bool IsEnclosureLocationExternal(winrt::Windows::Devices::Enumeration::EnclosureLocation enclosureLocation)
- {
- return (enclosureLocation == nullptr || enclosureLocation.Panel() == winrt::Windows::Devices::Enumeration::Panel::Unknown);
- }
- bool ShouldMirrorPreview();
- winrt::Windows::Devices::Sensors::SimpleOrientation GetCameraOrientationRelativeToNativeOrientation();
-
- winrt::Windows::Devices::Sensors::SimpleOrientation SubtractOrientations(
- winrt::Windows::Devices::Sensors::SimpleOrientation a,
- winrt::Windows::Devices::Sensors::SimpleOrientation b);
- winrt::Windows::Devices::Sensors::SimpleOrientation MirrorOrientation(winrt::Windows::Devices::Sensors::SimpleOrientation orientation);
- winrt::Windows::Devices::Sensors::SimpleOrientation AddOrientations(winrt::Windows::Devices::Sensors::SimpleOrientation a, winrt::Windows::Devices::Sensors::SimpleOrientation b);
-
- winrt::Windows::Devices::Sensors::SimpleOrientation ConvertDisplayOrientationToSimpleOrientation(Windows::Graphics::Display::DisplayOrientations orientation);
-
- static winrt::Windows::Storage::FileProperties::PhotoOrientation ConvertSimpleOrientationToPhotoOrientation(
- winrt::Windows::Devices::Sensors::SimpleOrientation orientation);
- static int ConvertSimpleOrientationToClockwiseDegrees(winrt::Windows::Devices::Sensors::SimpleOrientation orientation);
- static winrt::Windows::Devices::Sensors::SimpleOrientation ConvertClockwiseDegreesToSimpleOrientation(int orientation);
-
- void SimpleOrientationSensor_OrientationChanged(IInspectable const& sender, IInspectable const& args);
- void DisplayInformation_OrientationChanged(IInspectable const& sender, IInspectable const& args);
-
- winrt::Windows::Devices::Sensors::SimpleOrientationSensor::OrientationChanged_revoker m_sensorOrientationChanged_revoker{};
- winrt::Windows::Graphics::Display::DisplayInformation::OrientationChanged_revoker m_displayOrientationChanged_revoker{};
-
- winrt::Windows::Devices::Enumeration::EnclosureLocation m_cameraEnclosureLocation{nullptr};
- winrt::event> m_orientationChangedEvent;
- winrt::Windows::Devices::Sensors::SimpleOrientationSensor m_orientationSensor{ winrt::Windows::Devices::Sensors::SimpleOrientationSensor::GetDefault() };
- winrt::Windows::Graphics::Display::DisplayInformation m_displayInformation{ winrt::Windows::Graphics::Display::DisplayInformation::GetForCurrentView() };
- };
-}
-
-namespace winrt::ReactNativeCameraCPP::factory_implementation
-{
- struct CameraRotationHelper : CameraRotationHelperT
- {
- };
-}
+namespace winrt::ReactNativeCameraCPP::implementation {
+struct CameraRotationHelper : CameraRotationHelperT {
+ public:
+ CameraRotationHelper(winrt::Windows::Devices::Enumeration::EnclosureLocation location);
+ winrt::event_token OrientationChanged(Windows::Foundation::EventHandler const &handler);
+ void OrientationChanged(winrt::event_token const &token) noexcept;
+
+ winrt::Windows::Devices::Sensors::SimpleOrientation GetCameraCaptureOrientation();
+ winrt::Windows::Storage::FileProperties::PhotoOrientation GetConvertedCameraCaptureOrientation();
+ winrt::Windows::Devices::Sensors::SimpleOrientation GetCameraPreviewOrientation();
+ int GetCameraPreviewClockwiseDegrees();
+
+ private:
+ bool IsEnclosureLocationExternal(winrt::Windows::Devices::Enumeration::EnclosureLocation enclosureLocation) {
+ return (
+ enclosureLocation == nullptr ||
+ enclosureLocation.Panel() == winrt::Windows::Devices::Enumeration::Panel::Unknown);
+ }
+ bool ShouldMirrorPreview();
+ winrt::Windows::Devices::Sensors::SimpleOrientation GetCameraOrientationRelativeToNativeOrientation();
+
+ winrt::Windows::Devices::Sensors::SimpleOrientation SubtractOrientations(
+ winrt::Windows::Devices::Sensors::SimpleOrientation a,
+ winrt::Windows::Devices::Sensors::SimpleOrientation b);
+ winrt::Windows::Devices::Sensors::SimpleOrientation MirrorOrientation(
+ winrt::Windows::Devices::Sensors::SimpleOrientation orientation);
+ winrt::Windows::Devices::Sensors::SimpleOrientation AddOrientations(
+ winrt::Windows::Devices::Sensors::SimpleOrientation a,
+ winrt::Windows::Devices::Sensors::SimpleOrientation b);
+
+ winrt::Windows::Devices::Sensors::SimpleOrientation ConvertDisplayOrientationToSimpleOrientation(
+ Windows::Graphics::Display::DisplayOrientations orientation);
+
+ static winrt::Windows::Storage::FileProperties::PhotoOrientation ConvertSimpleOrientationToPhotoOrientation(
+ winrt::Windows::Devices::Sensors::SimpleOrientation orientation);
+ static int ConvertSimpleOrientationToClockwiseDegrees(
+ winrt::Windows::Devices::Sensors::SimpleOrientation orientation);
+ static winrt::Windows::Devices::Sensors::SimpleOrientation ConvertClockwiseDegreesToSimpleOrientation(
+ int orientation);
+
+ void SimpleOrientationSensor_OrientationChanged(IInspectable const &sender, IInspectable const &args);
+ void DisplayInformation_OrientationChanged(IInspectable const &sender, IInspectable const &args);
+
+ winrt::Windows::Devices::Sensors::SimpleOrientationSensor::OrientationChanged_revoker
+ m_sensorOrientationChanged_revoker{};
+ winrt::Windows::Graphics::Display::DisplayInformation::OrientationChanged_revoker
+ m_displayOrientationChanged_revoker{};
+
+ winrt::Windows::Devices::Enumeration::EnclosureLocation m_cameraEnclosureLocation{nullptr};
+ winrt::event> m_orientationChangedEvent;
+ winrt::Windows::Devices::Sensors::SimpleOrientationSensor m_orientationSensor{
+ winrt::Windows::Devices::Sensors::SimpleOrientationSensor::GetDefault()};
+ winrt::Windows::Graphics::Display::DisplayInformation m_displayInformation{
+ winrt::Windows::Graphics::Display::DisplayInformation::GetForCurrentView()};
+};
+} // namespace winrt::ReactNativeCameraCPP::implementation
+
+namespace winrt::ReactNativeCameraCPP::factory_implementation {
+struct CameraRotationHelper : CameraRotationHelperT {};
+} // namespace winrt::ReactNativeCameraCPP::factory_implementation
diff --git a/windows/ReactNativeCameraCPP/CameraRotationHelper.idl b/windows/ReactNativeCameraCPP/CameraRotationHelper.idl
index a35f1ea46..7a86c2315 100644
--- a/windows/ReactNativeCameraCPP/CameraRotationHelper.idl
+++ b/windows/ReactNativeCameraCPP/CameraRotationHelper.idl
@@ -1,9 +1,11 @@
namespace ReactNativeCameraCPP
{
+ [webhosthidden]
[default_interface]
runtimeclass CameraRotationHelper
{
CameraRotationHelper(Windows.Devices.Enumeration.EnclosureLocation location);
+
Windows.Devices.Sensors.SimpleOrientation GetCameraCaptureOrientation();
Windows.Devices.Sensors.SimpleOrientation GetCameraPreviewOrientation();
Windows.Storage.FileProperties.PhotoOrientation GetConvertedCameraCaptureOrientation();
diff --git a/windows/ReactNativeCameraCPP/ReactCameraConstants.h b/windows/ReactNativeCameraCPP/ReactCameraConstants.h
index bc9ab1be7..b96606105 100644
--- a/windows/ReactNativeCameraCPP/ReactCameraConstants.h
+++ b/windows/ReactNativeCameraCPP/ReactCameraConstants.h
@@ -2,138 +2,153 @@
#include
-namespace winrt::ReactNativeCameraCPP
-{
- class ReactCameraContants
- {
- public:
- static const int CameraAspectFill = 0;
- static const int CameraAspectFit = 1;
- static const int CameraAspectStretch = 2;
- static const int CameraCaptureTargetMemory = 0;
- static const int CameraCaptureTargetDisk = 1;
- static const int CameraCaptureTargetCameraRoll = 2;
- static const int CameraCaptureTargetTemp = 3;
- static const int CameraOrientationAuto = UINT_MAX;
- static const int CameraOrientationPortrait = (int)winrt::Windows::Devices::Sensors::SimpleOrientation::NotRotated;
- static const int CameraOrientationPortraitUpsideDown = (int)winrt::Windows::Devices::Sensors::SimpleOrientation::Rotated180DegreesCounterclockwise;
- static const int CameraOrientationLandscapeLeft = (int)winrt::Windows::Devices::Sensors::SimpleOrientation::Rotated90DegreesCounterclockwise;
- static const int CameraOrientationLandscapeRight = (int)winrt::Windows::Devices::Sensors::SimpleOrientation::Rotated270DegreesCounterclockwise;
- static const int CameraTypeFront = (int)winrt::Windows::Devices::Enumeration::Panel::Front;
- static const int CameraTypeBack = (int)winrt::Windows::Devices::Enumeration::Panel::Back;
- static const int CameraFlashModeOff = 0;
- static const int CameraFlashModeOn = 1;
- static const int CameraFlashModeAuto = 2;
- static const int CameraTorchModeOff = 0;
- static const int CameraTorchModeOn = 1;
- static const int CameraTorchModeAuto = 2;
- static const int CameraAutoFocusOff = 0;
- static const int CameraAutoFocusOn = 1;
- static const int CameraWhiteBalanceAuto = 0;
- static const int CameraWhiteBalanceSunny = 1;
- static const int CameraWhiteBalanceCloudy = 2;
- static const int CameraWhiteBalanceShadow = 3;
- static const int CameraWhiteBalanceIncandescent = 4;
- static const int CameraWhiteBalanceFluorescent = 5;
- static const int CameraCaptureQualityHigh = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::HD1080p;
- static const int CameraCaptureQualityLow = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::HD720p;
- static const int CameraCaptureQuality1080p = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::HD1080p;
- static const int CameraCaptureQuality720p = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::HD720p;
- static const int MediaTypeImage = 1;
- static const int MediaTypeVideo = 2;
+namespace winrt::ReactNativeCameraCPP {
+class ReactCameraConstants {
+ public:
+ static const int CameraAspectFill = 0;
+ static const int CameraAspectFit = 1;
+ static const int CameraAspectStretch = 2;
+ static const int CameraCaptureTargetMemory = 0;
+ static const int CameraCaptureTargetDisk = 1;
+ static const int CameraCaptureTargetCameraRoll = 2;
+ static const int CameraCaptureTargetTemp = 3;
+ static const int CameraOrientationAuto = UINT_MAX;
+ static const int CameraOrientationPortrait = (int)winrt::Windows::Devices::Sensors::SimpleOrientation::NotRotated;
+ static const int CameraOrientationPortraitUpsideDown =
+ (int)winrt::Windows::Devices::Sensors::SimpleOrientation::Rotated180DegreesCounterclockwise;
+ static const int CameraOrientationLandscapeLeft =
+ (int)winrt::Windows::Devices::Sensors::SimpleOrientation::Rotated90DegreesCounterclockwise;
+ static const int CameraOrientationLandscapeRight =
+ (int)winrt::Windows::Devices::Sensors::SimpleOrientation::Rotated270DegreesCounterclockwise;
+ static const int CameraTypeUnknown = (int)winrt::Windows::Devices::Enumeration::Panel::Unknown;
+ static const int CameraTypeFront = (int)winrt::Windows::Devices::Enumeration::Panel::Front;
+ static const int CameraTypeBack = (int)winrt::Windows::Devices::Enumeration::Panel::Back;
+ static const int CameraTypeTop = (int)winrt::Windows::Devices::Enumeration::Panel::Top;
+ static const int CameraTypeBottom = (int)winrt::Windows::Devices::Enumeration::Panel::Bottom;
+ static const int CameraTypeLeft = (int)winrt::Windows::Devices::Enumeration::Panel::Left;
+ static const int CameraTypeRight = (int)winrt::Windows::Devices::Enumeration::Panel::Right;
+ static const int CameraFlashModeOff = 0;
+ static const int CameraFlashModeOn = 1;
+ static const int CameraFlashModeAuto = 2;
+ static const int CameraAutoFocusOff = (int)winrt::Windows::Media::Devices::FocusPreset::Manual;
+ static const int CameraAutoFocusOn = (int)winrt::Windows::Media::Devices::FocusPreset::Auto;
+ static const int CameraWhiteBalanceAuto = (int)winrt::Windows::Media::Devices::ColorTemperaturePreset::Auto;
+ static const int CameraWhiteBalanceSunny = (int)winrt::Windows::Media::Devices::ColorTemperaturePreset::Daylight;
+ static const int CameraWhiteBalanceCloudy = (int)winrt::Windows::Media::Devices::ColorTemperaturePreset::Cloudy;
+ static const int CameraWhiteBalanceShadow = (int)winrt::Windows::Media::Devices::ColorTemperaturePreset::Candlelight;
+ static const int CameraWhiteBalanceIncandescent = (int)winrt::Windows::Media::Devices::ColorTemperaturePreset::Tungsten;
+ static const int CameraWhiteBalanceFluorescent =
+ (int)winrt::Windows::Media::Devices::ColorTemperaturePreset::Fluorescent;
+ static const int CameraVideoQualityAuto =
+ (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::Auto;
+ static const int CameraVideoQuality2160P =
+ (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::Uhd2160p;
+ static const int CameraVideoQuality1080P =
+ (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::HD1080p;
+ static const int CameraVideoQuality720P = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::HD720p;
+ static const int CameraVideoQualityWVGA = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::Wvga;
+ static const int CameraVideoQualityVGA = (int)winrt::Windows::Media::MediaProperties::VideoEncodingQuality::Vga;
+ static const int CameraVideoCodecH264 = 0;
+ static const int CameraVideoCodecHEVC = 1;
+ static const int CameraVideoCodecWMV = 2;
+ static const int MediaTypeJPG = 1;
+ static const int MediaTypeMP4 = 2;
+ static const int MediaTypeWMV = 3;
- static std::map GetAspectConstants() noexcept {
- return std::map
- {
- { L"stretch", CameraAspectStretch },
- { L"fit", CameraAspectFit },
- { L"fill", CameraAspectFill }
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetAspectConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"stretch", CameraAspectStretch},
+ {"fit", CameraAspectFit},
+ {"fill", CameraAspectFill}
+ };
+ }
- static std::map GetBarcodeConstants() noexcept {
- return std::map
- {
- { L"UPC_E", L"32768" },
- { L"CODE_39", L"4" },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValue GetBarcodeConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValue::EmptyObject.Copy();
+ }
- static std::map GetAutoFocusConstants() noexcept {
- return std::map
- {
- { L"off", CameraAutoFocusOff },
- { L"on", CameraAutoFocusOn },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetFaceDetectionConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"Mode", winrt::Microsoft::ReactNative::JSValue::EmptyObject.Copy()},
+ {"Landmarks", winrt::Microsoft::ReactNative::JSValue::EmptyObject.Copy()},
+ {"Classifications", winrt::Microsoft::ReactNative::JSValue::EmptyObject.Copy()},
+ };
+ }
- static std::map GetWhiteBalanceConstants() noexcept {
- return std::map
- {
- { L"auto", CameraWhiteBalanceAuto },
- { L"sunny", CameraWhiteBalanceSunny },
- { L"cloudy", CameraWhiteBalanceCloudy },
- { L"shadow", CameraWhiteBalanceShadow },
- { L"incandescent", CameraWhiteBalanceIncandescent },
- { L"fluorescent", CameraWhiteBalanceFluorescent },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetAutoFocusConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"off", CameraAutoFocusOff},
+ {"on", CameraAutoFocusOn},
+ };
+ }
+
+ static winrt::Microsoft::ReactNative::JSValueObject GetWhiteBalanceConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"auto", CameraWhiteBalanceAuto},
+ {"sunny", CameraWhiteBalanceSunny},
+ {"cloudy", CameraWhiteBalanceCloudy},
+ {"shadow", CameraWhiteBalanceShadow},
+ {"incandescent", CameraWhiteBalanceIncandescent},
+ {"fluorescent", CameraWhiteBalanceFluorescent},
+ };
+ }
- static std::map GetTypeConstants() noexcept {
- return std::map
- {
- { L"front", CameraTypeFront },
- { L"back", CameraTypeBack },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetTypeConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"unknown", CameraTypeUnknown},
+ {"front", CameraTypeFront},
+ {"back", CameraTypeBack},
+ {"top", CameraTypeTop},
+ {"bottom", CameraTypeBottom},
+ {"left", CameraTypeLeft},
+ {"right", CameraTypeRight},
+ };
+ }
- static std::map GetCaptureQualityConstants() noexcept {
- return std::map
- {
- { L"low", CameraCaptureQualityLow },
- { L"high", CameraCaptureQualityHigh },
- { L"720p", CameraCaptureQuality720p },
- { L"1080p", CameraCaptureQuality1080p },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetCaptureQualityConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"auto", CameraVideoQualityAuto},
+ {"2160p", CameraVideoQuality2160P},
+ {"1080p", CameraVideoQuality1080P},
+ {"720p", CameraVideoQuality720P},
+ {"480p", CameraVideoQualityWVGA},
+ {"4:3", CameraVideoQualityVGA},
+ };
+ }
- static std::map GetCaptureTargetConstants() noexcept {
- return std::map
- {
- { L"memory", CameraCaptureTargetMemory },
- { L"disk", CameraCaptureTargetDisk },
- { L"cameraRoll", CameraCaptureTargetCameraRoll },
- { L"temp", CameraCaptureTargetTemp },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetCaptureCodecConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"H264", CameraVideoCodecH264},
+ {"HEVC", CameraVideoCodecHEVC},
+ {"WMV", CameraVideoCodecWMV},
+ };
+ }
- static std::map GetOrientationConstants() noexcept {
- return std::map
- {
- { L"auto", CameraOrientationAuto },
- { L"landscapeLeft", CameraOrientationLandscapeLeft },
- { L"landscapeRight", CameraOrientationLandscapeRight },
- { L"portrait", CameraOrientationPortrait },
- { L"portraitUpsideDown", CameraOrientationPortraitUpsideDown },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetCaptureTargetConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"memory", CameraCaptureTargetMemory},
+ {"disk", CameraCaptureTargetDisk},
+ {"cameraRoll", CameraCaptureTargetCameraRoll},
+ {"temp", CameraCaptureTargetTemp},
+ };
+ }
- static std::map GetFlashModeConstants() noexcept {
- return std::map
- {
- { L"off", CameraFlashModeOff },
- { L"on", CameraFlashModeOn },
- { L"auto", CameraOrientationAuto },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetOrientationConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"auto", CameraOrientationAuto},
+ {"landscapeLeft", CameraOrientationLandscapeLeft},
+ {"landscapeRight", CameraOrientationLandscapeRight},
+ {"portrait", CameraOrientationPortrait},
+ {"portraitUpsideDown", CameraOrientationPortraitUpsideDown},
+ };
+ }
- static std::map GetTorchModeConstants() noexcept {
- return std::map
- {
- { L"off", CameraTorchModeOff },
- { L"on", CameraTorchModeOn },
- { L"auto", CameraTorchModeAuto },
- };
- }
+ static winrt::Microsoft::ReactNative::JSValueObject GetFlashModeConstants() noexcept {
+ return winrt::Microsoft::ReactNative::JSValueObject{
+ {"off", CameraFlashModeOff},
+ {"on", CameraFlashModeOn},
+ {"auto", CameraOrientationAuto},
};
-};
\ No newline at end of file
+ }
+};
+}; // namespace winrt::ReactNativeCameraCPP
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP/ReactCameraModule.h b/windows/ReactNativeCameraCPP/ReactCameraModule.h
index b338a12a4..5d569ec09 100644
--- a/windows/ReactNativeCameraCPP/ReactCameraModule.h
+++ b/windows/ReactNativeCameraCPP/ReactCameraModule.h
@@ -3,13 +3,16 @@
#include "pch.h"
#include
+#include
+#include
-#include "NativeModules.h"
-#include
#include
+#include
#include
-#include
#include
+#include
+
+#include "NativeModules.h"
#include "JSValueTreeWriter.h"
#include "ReactCameraConstants.h"
@@ -17,82 +20,126 @@
using namespace winrt::Microsoft::ReactNative;
+#ifdef RNW61
+#define JSVALUEOBJECTPARAMETER
+#else
+#define JSVALUEOBJECTPARAMETER const&
+#endif
+
namespace winrt {
- using namespace Windows::UI::Xaml;
- using namespace Windows::UI::Xaml::Media;
- using namespace Windows::Media::MediaProperties;
- using namespace Windows::UI::Xaml::Controls;
- using namespace Windows::Foundation;
- using namespace winrt::Windows::UI::Core;
- using namespace winrt::Windows::Storage::Streams;
-} //namespace winrt
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Media;
+using namespace Windows::Media::MediaProperties;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::Foundation;
+using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::Storage::Streams;
+} // namespace winrt
namespace winrt::ReactNativeCameraCPP {
- REACT_MODULE(RNCameraModule);
- struct RNCameraModule {
- const std::string Name = "RNCameraModule";
+REACT_MODULE(RNCameraModule);
+struct RNCameraModule {
+ const std::string Name = "RNCameraModule";
#pragma region Constants
- REACT_CONSTANT_PROVIDER(ConstantProvider)
- void ConstantProvider(ReactConstantProvider& provider) noexcept {
- provider.Add(L"Aspect", ReactCameraContants::GetAspectConstants());
- provider.Add(L"BarCodeType", ReactCameraContants::GetBarcodeConstants());
- provider.Add(L"AutoFocus", ReactCameraContants::GetAutoFocusConstants());
- provider.Add(L"WhiteBalance", ReactCameraContants::GetWhiteBalanceConstants());
- provider.Add(L"Type", ReactCameraContants::GetTypeConstants());
- provider.Add(L"VideoQuality", ReactCameraContants::GetCaptureQualityConstants());
- provider.Add(L"CaptureTarget", ReactCameraContants::GetCaptureTargetConstants());
- provider.Add(L"Orientation", ReactCameraContants::GetOrientationConstants());
- provider.Add(L"FlashMode", ReactCameraContants::GetFlashModeConstants());
- provider.Add(L"TorchMode", ReactCameraContants::GetTorchModeConstants());
- }
-
- REACT_METHOD(record)
- void record(
- std::map&& options,
- int viewTag,
- winrt::Microsoft::ReactNative::ReactPromise&& result) noexcept
- {
- try {
- winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::RecordAsync(
- options,
- viewTag, result).get(); //block on IAsyncAction
- }
- catch (winrt::hresult_error const& ex)
- {
- result.Reject(ex.message().c_str());
- }
- }
-
- REACT_METHOD(takePicture)
- void takePicture(
- std::map&& options,
- int viewTag,
- winrt::Microsoft::ReactNative::ReactPromise&& result) noexcept
- {
- try {
- winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::TakePictureAsync(
- options,
- viewTag, result).get(); //block on IAsyncAction
- }
- catch (winrt::hresult_error const& ex)
- {
- result.Reject(ex.message().c_str());
- }
- }
-
- REACT_METHOD(checkMediaCapturePermission)
- void checkMediaCapturePermission(winrt::Microsoft::ReactNative::ReactPromise&& result) noexcept
- {
- winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::CheckMediaCapturePermissionAsync(result).get(); //block on IAsyncAction
- }
+
+ REACT_CONSTANT_PROVIDER(ConstantProvider)
+ void ConstantProvider(ReactConstantProvider &provider) noexcept {
+ provider.Add(L"Aspect", ReactCameraConstants::GetAspectConstants());
+ provider.Add(L"BarCodeType", ReactCameraConstants::GetBarcodeConstants());
+ provider.Add(L"FaceDetection", ReactCameraConstants::GetFaceDetectionConstants());
+ provider.Add(L"AutoFocus", ReactCameraConstants::GetAutoFocusConstants());
+ provider.Add(L"WhiteBalance", ReactCameraConstants::GetWhiteBalanceConstants());
+ provider.Add(L"Type", ReactCameraConstants::GetTypeConstants());
+ provider.Add(L"VideoQuality", ReactCameraConstants::GetCaptureQualityConstants());
+ provider.Add(L"VideoCodec", ReactCameraConstants::GetCaptureCodecConstants());
+ provider.Add(L"CaptureTarget", ReactCameraConstants::GetCaptureTargetConstants());
+ provider.Add(L"Orientation", ReactCameraConstants::GetOrientationConstants());
+ provider.Add(L"FlashMode", ReactCameraConstants::GetFlashModeConstants());
+ }
#pragma endregion
- public:
- RNCameraModule() = default;
+#pragma region Methods
- ~RNCameraModule() = default;
+ template
+ winrt::AsyncActionCompletedHandler MakeAsyncActionCompletedHandler(
+ winrt::Microsoft::ReactNative::ReactPromise const &promise) {
+ return [promise](winrt::IAsyncAction action, winrt::AsyncStatus status) {
+ if (status == winrt::AsyncStatus::Error) {
+ std::stringstream errorCode;
+ errorCode << "0x" << std::hex << action.ErrorCode() << std::endl;
+ auto error = winrt::Microsoft::ReactNative::ReactError();
+ error.Message = "HRESULT " + errorCode.str() + ": " + std::system_category().message(action.ErrorCode());
+ promise.Reject(error);
+ }
};
+ }
+
+ REACT_METHOD(record)
+ void record(
+ winrt::Microsoft::ReactNative::JSValueObject JSVALUEOBJECTPARAMETER options,
+ int viewTag,
+ winrt::Microsoft::ReactNative::ReactPromise const
+ &result) noexcept {
+ auto asyncOp =
+ winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::RecordAsync(options, viewTag, result);
+ asyncOp.Completed(MakeAsyncActionCompletedHandler(result));
+ }
+
+ REACT_METHOD(stopRecording)
+ void stopRecording(int viewTag) noexcept {
+ auto asyncOp =
+ winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::StopRecordAsync(viewTag);
+ }
+
+ REACT_METHOD(isRecording)
+ void isRecording(int viewTag, winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept {
+ auto asyncOp = winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::IsRecordingAsync(viewTag, result);
+ asyncOp.Completed(MakeAsyncActionCompletedHandler(result));
+ }
+
+ REACT_METHOD(pausePreview)
+ void pausePreview(int viewTag) noexcept {
+ auto asyncOp = winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::PausePreviewAsync(viewTag);
+ }
+
+ REACT_METHOD(resumePreview)
+ void resumePreview(int viewTag) noexcept {
+ auto asyncOp = winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::ResumePreviewAsync(viewTag);
+ }
+
+ REACT_METHOD(takePicture)
+ void takePicture(
+ winrt::Microsoft::ReactNative::JSValueObject JSVALUEOBJECTPARAMETER options,
+ int viewTag,
+ winrt::Microsoft::ReactNative::ReactPromise const
+ &result) noexcept {
+ auto asyncOp =
+ winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::TakePictureAsync(options, viewTag, result);
+ asyncOp.Completed(MakeAsyncActionCompletedHandler(result));
+ }
+
+ REACT_METHOD(checkMediaCapturePermission)
+ void checkMediaCapturePermission(winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept {
+ auto asyncOp =
+ winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::CheckMediaCapturePermissionAsync(result);
+ asyncOp.Completed(MakeAsyncActionCompletedHandler(result));
+ }
+
+ REACT_METHOD(getCameraIds)
+ void getCameraIds(winrt::Microsoft::ReactNative::ReactPromise const
+ &result) noexcept {
+ auto asyncOp = winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::GetCameraIdsAsync(result);
+ asyncOp.Completed(MakeAsyncActionCompletedHandler(result));
+ }
+
+#pragma endregion
+
+ public:
+ RNCameraModule() = default;
+
+ ~RNCameraModule() = default;
+};
-} // namespace ReactNativeCameraCPP
+} // namespace winrt::ReactNativeCameraCPP
diff --git a/windows/ReactNativeCameraCPP/ReactCameraView.cpp b/windows/ReactNativeCameraCPP/ReactCameraView.cpp
index 3ec647f5c..4620b00a7 100644
--- a/windows/ReactNativeCameraCPP/ReactCameraView.cpp
+++ b/windows/ReactNativeCameraCPP/ReactCameraView.cpp
@@ -1,537 +1,967 @@
#include "pch.h"
-#include "ReactCameraView.h"
-#include "ReactCameraViewManager.h"
+
#include "NativeModules.h"
+
#include "ReactCameraConstants.h"
+#include "ReactCameraView.h"
+#include "ReactCameraViewManager.h"
namespace winrt {
- using namespace Windows::UI::Xaml;
- using namespace Windows::UI::Xaml::Media;
- using namespace Windows::UI::Xaml::Controls;
- using namespace Windows::Devices::Enumeration;
- using namespace Windows::Foundation;
- using namespace Windows::Foundation::Collections;
- using namespace Windows::Media::MediaProperties;
- using namespace Windows::Storage;
- using namespace Windows::Storage::Streams;
- using namespace Windows::UI::Core;
- using namespace Windows::Media::Core;
- using namespace Windows::Media::Playback;
- using namespace Windows::Media::Capture;
- using namespace Windows::Graphics::Imaging;
- using namespace Windows::Media::Devices;
- using namespace Windows::System::Display;
- using namespace Microsoft::ReactNative;
-} //namespace winrt
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Media;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::Media::MediaProperties;
+using namespace Windows::Storage;
+using namespace Windows::Storage::Streams;
+using namespace Windows::UI::Core;
+using namespace Windows::Media::Core;
+using namespace Windows::Media::Playback;
+using namespace Windows::Media::Capture;
+using namespace Windows::Graphics::Imaging;
+using namespace Windows::Media::Devices;
+using namespace Windows::System::Display;
+using namespace Microsoft::ReactNative;
+} // namespace winrt
using namespace std::chrono;
namespace winrt::ReactNativeCameraCPP {
- /*static*/ winrt::com_ptr ReactCameraView::Create() {
- auto view = winrt::make_self();
- view->Initialize();
- return view;
+/*static*/ winrt::com_ptr ReactCameraView::Create() {
+ auto view = winrt::make_self();
+ view->Initialize();
+ return view;
+}
+
+ReactCameraView::~ReactCameraView() {
+ m_unloadedEventToken.revoke();
+}
+
+void ReactCameraView::Initialize() {
+ m_childElement = winrt::CaptureElement();
+ Children().Append(m_childElement);
+ // RNW does not support DropView yet, so we need to manually register to Unloaded event and remove self
+ // from the static view list
+ m_unloadedEventToken = Unloaded(winrt::auto_revoke, [ref = get_weak()](auto const &, auto const &) {
+ if (auto self = ref.get()) {
+ auto unloadedAction{self->OnUnloaded()};
+ unloadedAction.Completed([self](auto && /*sender*/, AsyncStatus const /* args */) {
+ winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::RemoveViewFromList(self);
+ });
}
-
- ReactCameraView::~ReactCameraView()
- {
- m_unloadedEventToken.revoke();
+ });
+}
+
+void ReactCameraView::UpdateProperties(IJSValueReader const &propertyMapReader) noexcept {
+ const JSValueObject &propertyMap = JSValue::ReadObjectFrom(propertyMapReader);
+
+ for (auto const &pair : propertyMap) {
+ auto const &propertyName = pair.first;
+ auto const &propertyValue = pair.second;
+ if (!propertyValue.IsNull()) {
+ if (propertyName == "flashMode") {
+ UpdateFlashMode(propertyValue.AsInt32());
+ } else if (propertyName == "autoFocus") {
+ UpdateAutoFocus(propertyValue.AsInt32());
+ } else if (propertyName == "whiteBalance") {
+ UpdateWhiteBalance(propertyValue.AsInt32());
+ } else if (propertyName == "type") {
+ UpdateDeviceType(propertyValue.AsInt32());
+ } else if (propertyName == "cameraId") {
+ UpdateDeviceId(propertyValue.AsString());
+ } else if (propertyName == "keepAwake") {
+ UpdateKeepAwake(propertyValue.AsBoolean());
+ } else if (propertyName == "mirrorVideo") {
+ UpdateMirrorVideo(propertyValue.AsBoolean());
+ } else if (propertyName == "aspect") {
+ UpdateAspect(propertyValue.AsInt32());
+ } else if (propertyName == "defaultVideoQuality") {
+ UpdateDefaultVideoQuality(propertyValue.AsInt32());
+ }
+ }
+ }
+}
+
+IAsyncAction ReactCameraView::UpdateFilePropertiesAsync(StorageFile storageFile, JSValueObject const &options) {
+ auto props = co_await storageFile.Properties().GetImagePropertiesAsync();
+ auto searchTitle = options.find("title");
+ if (searchTitle != options.end()) {
+ const auto &titleValue = options.at("title");
+ if (titleValue.Type() == JSValueType::String) {
+ auto titleString = titleValue.AsString();
+ props.Title(winrt::to_hstring(titleString));
+ } else {
+ throw winrt::hresult_invalid_argument();
+ }
+ co_await props.SavePropertiesAsync();
+ }
+}
+
+IAsyncAction ReactCameraView::TakePictureAsync(
+ JSValueObject const &options,
+ ReactPromise const &result) noexcept {
+ auto capturedPromise = result;
+ auto capturedOptions = options.Copy();
+
+ if (!m_isInitialized) {
+ capturedPromise.Reject(L"Media device is not initialized.");
+ return;
+ }
+
+ #ifdef RNW61
+ // Necessary to switch to the UI thread in RNW61
+ auto dispatcher = Dispatcher();
+ co_await resume_foreground(dispatcher);
+ #endif
+
+ if (auto mediaCapture = m_childElement.Source()) {
+ // Default with no options is to save the image to the temp folder and return the uri
+ // This follows the expectations of RNCamera without requiring extra app capabilities
+
+ // Devs who want to only capture to memory (and get a base64 encoded image) can specify:
+ // 1. doNotSave = true and base64 = true OR
+ // 2. target = "memory"
+
+ // Devs who want to capture to the Camera Roll can specify:
+ // 1. target = "cameraRoll"
+ // Devs who want to capture to the Pictures Library can specify:
+ // 1. target = "disk"
+ // Both will require the Pictures Library app capability to succeed
+
+ bool doNotSave;
+ TryGetValueAsBool(capturedOptions, "doNotSave", doNotSave, false);
+
+ int target;
+ TryGetValueAsInt(
+ capturedOptions,
+ "target",
+ target,
+ doNotSave ? ReactCameraConstants::CameraCaptureTargetMemory : ReactCameraConstants::CameraCaptureTargetTemp);
+
+ // Prepare encoder options
+ auto encoderPropertySet = winrt::BitmapPropertySet();
+
+ // JPEG image quality
+ float quality;
+ TryGetValueAsFloat(capturedOptions, "quality", quality, 1.0f);
+ auto imageQualityValue = winrt::BitmapTypedValue(winrt::box_value(quality), PropertyType::Single);
+ encoderPropertySet.Insert(hstring(L"ImageQuality"), imageQualityValue);
+
+ // Capture the image and relevant EXIF metadata
+ auto lowLagCapture = co_await mediaCapture.PrepareLowLagPhotoCaptureAsync(
+ winrt::ImageEncodingProperties().CreateUncompressed(winrt::MediaPixelFormat::Bgra8));
+ auto capturedPhoto = co_await lowLagCapture.CaptureAsync();
+
+ auto softwareBitmap = capturedPhoto.Frame().SoftwareBitmap();
+ auto capturedProperties = capturedPhoto.Frame().BitmapProperties();
+
+ co_await lowLagCapture.FinishAsync();
+
+ // writeExif allows callers to (not) save EXIF metadata
+ // TODO: writeExif can also be passed an object to allow callers to specify additional EXIF
+ // metadata, however we don't have an easy API for doing so at the moment
+ bool writeExif;
+ TryGetValueAsBool(capturedOptions, "writeExif", writeExif, true);
+
+ // Add additional metadata to what the camera provided
+ auto photoOrientation = m_rotationHelper.GetConvertedCameraCaptureOrientation();
+ auto photoOrientationValue = winrt::BitmapTypedValue(winrt::box_value(photoOrientation), winrt::PropertyType::UInt16);
+ capturedProperties.Insert(hstring(L"System.Photo.Orientation"), photoOrientationValue);
+
+ // Get transform options
+
+ auto targetWidth = softwareBitmap.PixelWidth();
+ auto targetHeight = softwareBitmap.PixelHeight();
+
+ auto bitmapTransform = winrt::BitmapTransform();
+
+ int resizeWidth;
+ if (TryGetValueAsInt(capturedOptions, "width", resizeWidth, 0) && resizeWidth > 0 &&
+ resizeWidth != softwareBitmap.PixelWidth()) {
+ targetWidth = resizeWidth;
+ targetHeight = static_cast(
+ (static_cast(targetWidth) / static_cast(softwareBitmap.PixelWidth())) *
+ static_cast(softwareBitmap.PixelHeight()));
+
+ // Resize output
+ bitmapTransform.ScaledWidth(targetWidth);
+ bitmapTransform.ScaledHeight(targetHeight);
+ bitmapTransform.InterpolationMode(BitmapInterpolationMode::Fant);
}
- void ReactCameraView::Initialize()
- {
- m_childElement = winrt::CaptureElement();
- Children().Append(m_childElement);
- // RNW does not support DropView yet, so we need to manually register to Unloaded event and remove self
- // from the static view list
- m_unloadedEventToken = Unloaded(winrt::auto_revoke, [ref = get_weak()](auto const&, auto const&) {
- if (auto self = ref.get()) {
- auto unloadedAction{ self->OnUnloaded() };
- unloadedAction.Completed([self](auto&& /*sender*/, AsyncStatus const /* args */) {
- winrt::ReactNativeCameraCPP::implementation::ReactCameraViewManager::RemoveViewFromList(self);
- });
- }
- });
+ bool mirrorImage;
+ if (TryGetValueAsBool(capturedOptions, "mirrorImage", mirrorImage, false) && mirrorImage) {
+ bitmapTransform.Flip(winrt::BitmapFlip::Horizontal);
}
- void ReactCameraView::UpdateProperties(IJSValueReader const& propertyMapReader)
- {
- const JSValueObject& propertyMap = JSValue::ReadObjectFrom(propertyMapReader);
-
- for (auto const& pair : propertyMap) {
- auto const& propertyName = pair.first;
- auto const& propertyValue = pair.second;
- if (!propertyValue.IsNull()) {
- if (propertyName == "torchMode") {
- UpdateTorchMode(static_cast(propertyValue.AsDouble()));
- }
- if (propertyName == "flashMode") {
- UpdateFlashMode(static_cast(propertyValue.AsDouble()));
- }
- else if (propertyName == "type") {
- UpdateDeviceType(static_cast(propertyValue.AsDouble()));
- }
- else if (propertyName == "keepAwake") {
- UpdateKeepAwake(propertyValue.AsBoolean());
- }
- else if (propertyName == "aspect") {
- UpdateAspect(static_cast(propertyValue.AsDouble()));
- }
- }
- }
+ // Start creating result
+ winrt::JSValueObject resultObject;
+ resultObject["width"] = targetWidth;
+ resultObject["height"] = targetHeight;
+
+ // Return exif data in result
+ bool exif;
+ TryGetValueAsBool(capturedOptions, "exif", exif, false);
+
+ if (exif) {
+ resultObject["exif"] = GetExifObject(capturedProperties);
}
- IAsyncAction ReactCameraView::UpdateFilePropertiesAsync(StorageFile storageFile, std::map const& options)
- {
- auto props = co_await storageFile.Properties().GetImagePropertiesAsync();
- auto searchTitle = options.find(L"title");
- if (searchTitle != options.end()) {
- const auto& titleValue = options.at(L"title");
- if (titleValue.Type() == JSValueType::String)
- {
- auto titleString = titleValue.AsString();
- props.Title(winrt::to_hstring(titleString));
- }
- else
- {
- throw winrt::hresult_invalid_argument();
- }
- co_await props.SavePropertiesAsync();
+ if (target == ReactCameraConstants::CameraCaptureTargetMemory) {
+ // Get memory output stream
+ auto outputStream = winrt::InMemoryRandomAccessStream();
+
+ // Encode Jpeg to output stream
+ auto encoder = co_await winrt::BitmapEncoder::CreateAsync(
+ winrt::BitmapEncoder::JpegEncoderId(), outputStream, encoderPropertySet);
+ encoder.SetSoftwareBitmap(softwareBitmap);
+
+ // Copy transformation
+ encoder.BitmapTransform().ScaledWidth(bitmapTransform.ScaledWidth());
+ encoder.BitmapTransform().ScaledHeight(bitmapTransform.ScaledHeight());
+ encoder.BitmapTransform().InterpolationMode(bitmapTransform.InterpolationMode());
+ encoder.BitmapTransform().Flip(bitmapTransform.Flip());
+
+ if (writeExif) {
+ co_await encoder.BitmapProperties().SetPropertiesAsync(capturedProperties);
+ }
+
+ co_await encoder.FlushAsync();
+
+ // Get base64-encoded data to return
+ auto base64String = co_await GetBase64DataAsync(outputStream);
+
+ // Resolve promise with base64 encoded image
+ resultObject["base64"] = winrt::to_string(base64String);
+ capturedPromise.Resolve(resultObject);
+ } else {
+ try {
+ auto storageFile = co_await GetOutputStorageFileAsync(ReactCameraConstants::MediaTypeJPG, target);
+
+ if (storageFile) {
+ // Get file output stream
+ auto outputStream = co_await storageFile.OpenAsync(FileAccessMode::ReadWrite);
+
+ // Encode Jpeg to output stream
+ auto encoder = co_await winrt::BitmapEncoder::CreateAsync(
+ winrt::BitmapEncoder::JpegEncoderId(), outputStream, encoderPropertySet);
+ encoder.SetSoftwareBitmap(softwareBitmap);
+
+ // Copy transformation
+ encoder.BitmapTransform().ScaledWidth(bitmapTransform.ScaledWidth());
+ encoder.BitmapTransform().ScaledHeight(bitmapTransform.ScaledHeight());
+ encoder.BitmapTransform().InterpolationMode(bitmapTransform.InterpolationMode());
+ encoder.BitmapTransform().Flip(bitmapTransform.Flip());
+
+ if (writeExif) {
+ co_await encoder.BitmapProperties().SetPropertiesAsync(capturedProperties);
+ }
+
+ co_await encoder.FlushAsync();
+
+ co_await UpdateFilePropertiesAsync(storageFile, capturedOptions);
+
+ // Resolve promise with uri, and optionally the base64 encoded image
+ resultObject["uri"] = winrt::to_string(storageFile.Path());
+
+ bool includeBase64 = false;
+ TryGetValueAsBool(capturedOptions, "base64", includeBase64, false);
+ if (includeBase64) {
+ auto base64String = co_await GetBase64DataAsync(outputStream);
+ resultObject["base64"] = winrt::to_string(base64String);
+ }
+
+ capturedPromise.Resolve(resultObject);
}
+ } catch (...) {
+ capturedPromise.Reject(L"Unable to capture to disk, check app capabilities.");
+ }
+ }
+ } else {
+ capturedPromise.Reject(L"Media device is not initialized.");
+ }
+
+ #ifdef RNW61
+ // Necessary to switch back to bacground thread in RNW61
+ co_await resume_background();
+ #endif
+}
+
+IAsyncAction ReactCameraView::RecordAsync(
+ JSValueObject const &options,
+ ReactPromise const &result) noexcept {
+ auto capturedPromise = result;
+ auto capturedOptions = options.Copy();
+
+ if (!m_isInitialized) {
+ capturedPromise.Reject(L"Media device is not initialized.");
+ co_return;
+ }
+
+ #ifdef RNW61
+ // Necessary to switch to the UI thread in RNW61
+ auto dispatcher = Dispatcher();
+ co_await resume_foreground(dispatcher);
+ #endif
+
+ if (auto mediaCapture = m_childElement.Source()) {
+ int quality;
+ TryGetValueAsInt(capturedOptions, "quality", quality, m_defaultVideoQuality);
+
+ // Update the stream with the requested quality
+ co_await UpdateMediaStreamPropertiesAsync(quality);
+
+ // Create an encoding profile for the requested codec
+ int mediaType;
+ winrt::MediaEncodingProfile encodingProfile = nullptr;
+
+ int videoCodec;
+ TryGetValueAsInt(capturedOptions, "codec", videoCodec, ReactCameraConstants::CameraVideoCodecH264);
+
+ switch (videoCodec) {
+ case ReactCameraConstants::CameraVideoCodecHEVC:
+ encodingProfile = winrt::MediaEncodingProfile::CreateHevc(static_cast(quality));
+ mediaType = ReactCameraConstants::MediaTypeMP4;
+ break;
+ case ReactCameraConstants::CameraVideoCodecWMV:
+ encodingProfile = winrt::MediaEncodingProfile::CreateWmv(static_cast(quality));
+ mediaType = ReactCameraConstants::MediaTypeWMV;
+ break;
+ default:
+ videoCodec = ReactCameraConstants::CameraVideoCodecH264;
+ encodingProfile = winrt::MediaEncodingProfile::CreateMp4(static_cast(quality));
+ mediaType = ReactCameraConstants::MediaTypeMP4;
+ break;
}
-
- // RNW has a bug where the numeric value is set as int in debug but double in release
- // ToDo: remove this function once bug https://github.com/microsoft/react-native-windows/issues/4225 is fixed.
- bool ReactCameraView::TryGetValueAsInt(std::map const& options, const std::wstring key, int &value)
- {
- bool found = false;
- auto search = options.find(key);
- if (search != options.end())
- {
- const auto& searchValue = options.at(key);
- const bool valueIsInt = (searchValue.Type() == JSValueType::Int64);
- const bool valueIsDouble = (searchValue.Type() == JSValueType::Double);
- if (valueIsInt || valueIsDouble)
- {
- found = true;
- if (valueIsInt)
- {
- value = static_cast(searchValue.AsInt64());
- }
- else
- {
- value = static_cast(searchValue.AsDouble());
- }
- }
- }
- return found;
+ int videoBitrate;
+ if (TryGetValueAsInt(capturedOptions, "videoBitrate", videoBitrate, 0) && videoBitrate > 0) {
+ encodingProfile.Video().Bitrate(videoBitrate);
}
- IAsyncAction ReactCameraView::TakePictureAsync(std::map const& options
- , ReactPromise& result)
- {
- if (!m_isInitialized)
- {
- result.Reject(L"Media device is not initialized.");
- return;
- }
+ bool muteAudio;
+ TryGetValueAsBool(capturedOptions, "mute", muteAudio, false);
+ mediaCapture.AudioDeviceController().Muted(muteAudio);
- auto dispatcher = Dispatcher();
- co_await resume_foreground(dispatcher); // Jump to UI thread
- if (auto mediaCapture = m_childElement.Source())
- {
- auto encoding = winrt::ImageEncodingProperties().CreateJpeg();
- auto randomStream = winrt::InMemoryRandomAccessStream();
- co_await mediaCapture.CapturePhotoToStreamAsync(encoding, randomStream);
- int target = ReactCameraContants::CameraCaptureTargetDisk;
- TryGetValueAsInt(options, L"target", target);
- if (target == ReactCameraContants::CameraCaptureTargetMemory)
- {
- // In memeory returns a base64 string for the captured image
- auto string = co_await GetBase64DataAsync(randomStream);
- JSValueObject jsObject;
- jsObject["base64"] = winrt::to_string(string);
- result.Resolve(jsObject);
- }
- else
- {
- auto storageFile = co_await GetOutputStorageFileAsync(ReactCameraContants::MediaTypeImage, target);
- {
- auto photoOrientation = m_rotationHelper.GetConvertedCameraCaptureOrientation();
- auto decoder = co_await winrt::BitmapDecoder::CreateAsync(randomStream);
- auto outputStream = co_await storageFile.OpenAsync(FileAccessMode::ReadWrite);
- auto encoder = co_await winrt::BitmapEncoder::CreateForTranscodingAsync(outputStream, decoder);
- auto bitmapTypedValue = winrt::BitmapTypedValue(winrt::box_value(photoOrientation), PropertyType::UInt16);
- auto properties = winrt::BitmapPropertySet();
- properties.Insert(hstring(L"System.Photo.Orientation"), bitmapTypedValue);
- co_await encoder.BitmapProperties().SetPropertiesAsync(properties);
- co_await encoder.FlushAsync();
- }
-
- co_await UpdateFilePropertiesAsync(storageFile, options);
- JSValueObject jsObject;
- jsObject["uri"] = winrt::to_string(storageFile.Path());
- result.Resolve(jsObject);
- }
- }
- else
- {
- result.Reject(L"Media device is not initialized.");
- }
+ float maxDurationInSeconds;
+ TryGetValueAsFloat(capturedOptions, "maxDuration", maxDurationInSeconds, FLT_MAX);
- co_await resume_background();
- }
+ // Default with no options is to save the video to the temp folder and return the uri
+ // This follows the expectations of RNCamera without requiring extra app capabilities
- IAsyncAction ReactCameraView::RecordAsync(std::map const& options, ReactPromise& result)
- {
- if (!m_isInitialized)
- {
- result.Reject(L"Media device is not initialized.");
- return;
- }
+ // Devs who want to only capture to memory (and get a base64 encoded video) can specify:
+ // 1. target = "memory"
- auto dispatcher = Dispatcher();
- co_await resume_foreground(dispatcher); // Jump to UI thread
- if (auto mediaCapture = m_childElement.Source())
- {
- int quality = static_cast(VideoEncodingQuality::Auto);
- TryGetValueAsInt(options, L"quality", quality);
- auto encodingProfile = winrt::MediaEncodingProfile();
- auto encoding = encodingProfile.CreateMp4(static_cast(quality));
-
- auto searchAudio = options.find(L"audio");
- if (searchAudio != options.end())
- {
- const auto& audioValue = options.at(L"audio");
- mediaCapture.AudioDeviceController().Muted(audioValue.AsBoolean());
- }
+ // Devs who want to capture to the Camera Roll can specify:
+ // 1. target = "cameraRoll"
+ // This will require the Pictures Library app capability to succeed
- int totalSeconds = INT_MAX;
- TryGetValueAsInt(options, L"totalSeconds", totalSeconds);
+ // Devs who want to capture to the Videos Library can specify:
+ // 1. target = "disk"
+ // This will require the Videos Library app capability to succeed
- int target;
- if (!TryGetValueAsInt(options, L"target", target))
- {
- result.Reject(L"target parameter not specified.");
- return;
- }
- if (target == ReactCameraContants::CameraCaptureTargetMemory)
- {
- auto randomStream = winrt::InMemoryRandomAccessStream();
- m_mediaRecording = co_await mediaCapture.PrepareLowLagRecordToStreamAsync(
- encoding, randomStream);
- co_await m_mediaRecording.StartAsync();
- co_await DelayStopRecording(totalSeconds);
- co_await WaitAndStopRecording();
-
- auto string = co_await GetBase64DataAsync(randomStream);
- JSValueObject jsObject;
- jsObject["data"] = winrt::to_string(string);
- result.Resolve(jsObject);
- }
- else
- {
- auto storageFile = co_await GetOutputStorageFileAsync(ReactCameraContants::MediaTypeVideo, target);
- m_mediaRecording = co_await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
- encoding, storageFile);
- co_await m_mediaRecording.StartAsync();
- co_await DelayStopRecording(totalSeconds);
- co_await WaitAndStopRecording();
- co_await UpdateFilePropertiesAsync(storageFile, options);
-
- JSValueObject jsObject;
- jsObject["path"] = winrt::to_string(storageFile.Path());
- result.Resolve(jsObject);
- }
- }
- else
- {
- result.Reject("No media capture device found");
- }
- co_await resume_background();
- }
-
- // async function to wait for specified seconds before signaling to stop recording
- IAsyncAction ReactCameraView::DelayStopRecording(int totalRecordingInSecs)
- {
- ResetEvent(m_signal.get());
- std::chrono::duration secs(totalRecordingInSecs);
- co_await secs;
- SetEvent(m_signal.get());
- }
+ int target;
+ TryGetValueAsInt(capturedOptions, "target", target, ReactCameraConstants::CameraCaptureTargetTemp);
- IAsyncAction ReactCameraView::WaitAndStopRecording()
- {
- co_await resume_on_signal(m_signal.get());
- auto dispatcher = Dispatcher();
- co_await resume_foreground(dispatcher);
- co_await m_mediaRecording.StopAsync();
- co_await resume_background();
- }
+ // Start creating result
+ winrt::JSValueObject resultObject;
+ resultObject["codec"] = videoCodec;
- // Switch between front and back cameras, need to clean up and reinitialize the mediaCapture object
- fire_and_forget ReactCameraView::UpdateDeviceType(int type)
- {
- winrt::Windows::Devices::Enumeration::Panel newPanelType = static_cast(type);
- if (m_panelType == newPanelType && m_isInitialized)
- {
- return;
- }
+ m_isRecording = true;
+ if (target == ReactCameraConstants::CameraCaptureTargetMemory) {
+ auto randomStream = winrt::InMemoryRandomAccessStream();
+ m_mediaRecording = co_await mediaCapture.PrepareLowLagRecordToStreamAsync(encodingProfile, randomStream);
- m_panelType = newPanelType;
- if (m_isInitialized)
- {
- co_await CleanupMediaCaptureAsync();
- }
- co_await InitializeAsync();
- }
+ co_await m_mediaRecording.StartAsync();
+ DelayStopRecording(maxDurationInSeconds);
+ co_await WaitAndStopRecording();
- // Request monitor to not turn off if keepAwake is true
- void ReactCameraView::UpdateKeepAwake(bool keepAwake)
- {
- if (m_keepAwake != keepAwake)
- {
- m_keepAwake = keepAwake;
- if (m_keepAwake)
- {
- if (m_displayRequest == nullptr)
- {
- m_displayRequest = DisplayRequest();
- m_displayRequest.RequestActive();
- }
- }
- else
- {
- m_displayRequest.RequestRelease();
- }
- }
- }
+ auto string = co_await GetBase64DataAsync(randomStream);
+ resultObject["base64"] = winrt::to_string(string);
+ capturedPromise.Resolve(resultObject);
+ } else {
+ try {
+ auto storageFile = co_await GetOutputStorageFileAsync(mediaType, target);
+ m_mediaRecording = co_await mediaCapture.PrepareLowLagRecordToStorageFileAsync(encodingProfile, storageFile);
- void ReactCameraView::UpdateTorchMode(int torchMode)
- {
- m_torchMode = torchMode;
- if (auto mediaCapture = m_childElement.Source())
- {
- auto torchControl = mediaCapture.VideoDeviceController().TorchControl();
- if (torchControl.Supported())
- {
- torchControl.Enabled(torchMode == ReactCameraContants::CameraTorchModeOn);
- }
- }
- }
+ co_await m_mediaRecording.StartAsync();
+ DelayStopRecording(maxDurationInSeconds);
+ co_await WaitAndStopRecording();
- void ReactCameraView::UpdateFlashMode(int flashMode)
- {
- m_flashMode = flashMode;
- if (auto mediaCapture = m_childElement.Source())
- {
- auto flashControl = mediaCapture.VideoDeviceController().FlashControl();
- if (flashControl.Supported())
- {
- flashControl.Enabled(flashMode == ReactCameraContants::CameraFlashModeOn);
- flashControl.Auto(flashMode == ReactCameraContants::CameraFlashModeAuto);
- }
- }
- }
+ co_await UpdateFilePropertiesAsync(storageFile, capturedOptions);
- void ReactCameraView::UpdateAspect(int aspect)
- {
- switch (aspect)
- {
- case ReactCameraContants::CameraAspectFill:
- m_childElement.Stretch(Stretch::Uniform);
- break;
- case ReactCameraContants::CameraAspectFit:
- m_childElement.Stretch(Stretch::UniformToFill);
- break;
- case ReactCameraContants::CameraAspectStretch:
- m_childElement.Stretch(Stretch::Fill);
- break;
- default:
- m_childElement.Stretch(Stretch::None);
- break;
- }
+ resultObject["uri"] = winrt::to_string(storageFile.Path());
+ capturedPromise.Resolve(resultObject);
+ } catch (...) {
+ capturedPromise.Reject(L"Unable to capture to disk, check app capabilities.");
+ }
}
-
- // Intialization takes care few things below:
- // 1. Register rotation helper to update preview if rotation changes.
- // 2. Takes care connected standby scenarios to cleanup and reintialize when suspend/resume
- IAsyncAction ReactCameraView::InitializeAsync()
- {
- try {
- auto device = co_await FindCameraDeviceByPanelAsync();
- if (device != nullptr)
- {
- auto settings = winrt::Windows::Media::Capture::MediaCaptureInitializationSettings();
- settings.VideoDeviceId(device.Id());
- auto mediaCapture = winrt::Windows::Media::Capture::MediaCapture();
- co_await mediaCapture.InitializeAsync(settings);
- m_childElement.Source(mediaCapture);
- UpdateTorchMode(m_torchMode);
- UpdateFlashMode(m_flashMode);
- UpdateKeepAwake(m_keepAwake);
- co_await mediaCapture.StartPreviewAsync();
- m_rotationHelper = CameraRotationHelper(device.EnclosureLocation());
- m_rotationEventToken = m_rotationHelper.OrientationChanged([ref = get_weak()](const auto&, const bool updatePreview)
- {
- if (auto self = ref.get()) {
- self->OnOrientationChanged(updatePreview);
- }
- });
- co_await UpdatePreviewOrientationAsync();
-
- m_applicationSuspendingEventToken = winrt::Application::Current().Suspending(winrt::auto_revoke, [ref = get_weak()](auto const&, auto const&) {
- if (auto self = ref.get()) {
- self->OnApplicationSuspending();
- }
- });
-
- m_applicationResumingEventToken = winrt::Application::Current().Resuming(winrt::auto_revoke, [ref = get_weak()](auto const&, auto const&) {
- if (auto self = ref.get()) {
- self->OnApplicationResuming();
- }
- });
-
- m_isInitialized = true;
- }
- }
- catch (winrt::hresult_error const&)
- {
- m_isInitialized = false;
- }
+ m_isRecording = false;
+
+ } else {
+ capturedPromise.Reject("No media capture device found");
+ }
+
+ #ifdef RNW61
+ // Necessary to switch back to bacground thread in RNW61
+ co_await resume_background();
+ #endif
+}
+
+IAsyncAction ReactCameraView::StopRecordAsync() noexcept {
+ if (!m_isInitialized) {
+ co_return;
+ }
+
+ SetEvent(m_signal.get());
+}
+
+IAsyncAction ReactCameraView::IsRecordingAsync(
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept {
+ auto capturedPromise = result;
+
+ if (!m_isInitialized) {
+ capturedPromise.Reject(L"Media device is not initialized.");
+ co_return;
+ }
+
+ capturedPromise.Resolve(m_isRecording);
+}
+
+IAsyncAction ReactCameraView::PausePreviewAsync() noexcept {
+ if (!m_isInitialized) {
+ co_return;
+ }
+
+ if (auto mediaCapture = m_childElement.Source()) {
+ if (m_isPreview) {
+ co_await mediaCapture.StopPreviewAsync();
+ m_isPreview = false;
+ }
+ }
+}
+
+IAsyncAction ReactCameraView::ResumePreviewAsync() noexcept {
+ if (!m_isInitialized) {
+ co_return;
+ }
+
+ if (auto mediaCapture = m_childElement.Source()) {
+ if (!m_isPreview) {
+ co_await mediaCapture.StartPreviewAsync();
+ m_isPreview = true;
+ }
+ }
+}
+
+// start a timer to end the recording after the specified time
+void ReactCameraView::DelayStopRecording(float totalRecordingInSecs) {
+ ResetEvent(m_signal.get());
+ std::chrono::duration secs(static_cast(1000 * totalRecordingInSecs));
+ m_recordTimer = winrt::Windows::System::Threading::ThreadPoolTimer::CreateTimer(
+ [this](const winrt::Windows::System::Threading::ThreadPoolTimer) noexcept { SetEvent(m_signal.get()); }, secs);
+}
+
+IAsyncAction ReactCameraView::WaitAndStopRecording() {
+ co_await resume_on_signal(m_signal.get());
+
+ if (m_recordTimer) {
+ m_recordTimer.Cancel();
+ }
+
+ // Switch to UI thread to stop recording
+ auto dispatcher = Dispatcher();
+ co_await resume_foreground(dispatcher);
+ co_await m_mediaRecording.StopAsync();
+
+ // Reset stream to default
+ co_await UpdateMediaStreamPropertiesAsync();
+ co_await resume_background();
+}
+
+// Select a particular camera, need to clean up and reinitialize the mediaCapture object
+fire_and_forget ReactCameraView::UpdateDeviceId(std::string cameraId) {
+ if (m_cameraId == cameraId && m_isInitialized) {
+ return;
+ }
+
+ m_cameraId = cameraId;
+ if (m_isInitialized) {
+ co_await CleanupMediaCaptureAsync();
+ }
+ co_await InitializeAsync();
+}
+
+// Switch between front and back cameras, need to clean up and reinitialize the mediaCapture object
+fire_and_forget ReactCameraView::UpdateDeviceType(int type) {
+ winrt::Windows::Devices::Enumeration::Panel newPanelType =
+ static_cast(type);
+ if (m_panelType == newPanelType && m_isInitialized) {
+ return;
+ }
+
+ m_panelType = newPanelType;
+ if (m_isInitialized) {
+ co_await CleanupMediaCaptureAsync();
+ }
+ co_await InitializeAsync();
+}
+
+// Request monitor to not turn off if keepAwake is true
+void ReactCameraView::UpdateKeepAwake(bool keepAwake) {
+ if (m_keepAwake != keepAwake) {
+ m_keepAwake = keepAwake;
+ if (m_keepAwake) {
+ if (m_displayRequest == nullptr) {
+ m_displayRequest = DisplayRequest();
+ m_displayRequest.RequestActive();
+ }
+ } else {
+ m_displayRequest.RequestRelease();
+ }
+ }
+}
+
+void ReactCameraView::UpdateFlashMode(int flashMode) {
+ m_flashMode = flashMode;
+ if (auto mediaCapture = m_childElement.Source()) {
+ auto flashControl = mediaCapture.VideoDeviceController().FlashControl();
+ if (flashControl.Supported()) {
+ flashControl.Enabled(flashMode == ReactCameraConstants::CameraFlashModeOn);
+ flashControl.Auto(flashMode == ReactCameraConstants::CameraFlashModeAuto);
+ }
+ }
+}
+
+void ReactCameraView::UpdateAutoFocus(int focusMode) {
+ m_focusMode = focusMode;
+ if (auto mediaCapture = m_childElement.Source()) {
+ auto focusControl = mediaCapture.VideoDeviceController().FocusControl();
+ if (focusControl.Supported()) {
+ auto asyncOp = focusControl.SetPresetAsync(static_cast(focusMode));
}
+ }
+}
+
+void ReactCameraView::UpdateWhiteBalance(int whiteBalance) {
+ m_whiteBalance = whiteBalance;
+ if (auto mediaCapture = m_childElement.Source()) {
+ auto whiteBalanceControl = mediaCapture.VideoDeviceController().WhiteBalanceControl();
+ if (whiteBalanceControl.Supported()) {
+ auto asyncOp = whiteBalanceControl.SetPresetAsync(static_cast(whiteBalance));
+ }
+ }
+}
+
+void ReactCameraView::UpdateMirrorVideo(bool mirrorVideo) {
+ m_mirrorVideo = mirrorVideo;
+ m_childElement.FlowDirection(mirrorVideo ? winrt::FlowDirection::RightToLeft :winrt::FlowDirection::LeftToRight);
+}
+
+void ReactCameraView::UpdateAspect(int aspect) {
+ switch (aspect) {
+ case ReactCameraConstants::CameraAspectFill:
+ m_childElement.Stretch(Stretch::Uniform);
+ break;
+ case ReactCameraConstants::CameraAspectFit:
+ m_childElement.Stretch(Stretch::UniformToFill);
+ break;
+ case ReactCameraConstants::CameraAspectStretch:
+ m_childElement.Stretch(Stretch::Fill);
+ break;
+ default:
+ m_childElement.Stretch(Stretch::None);
+ break;
+ }
+}
+
+void ReactCameraView::UpdateDefaultVideoQuality(int videoQuality) {
+ if (m_defaultVideoQuality != videoQuality) {
+ m_defaultVideoQuality = videoQuality;
+ auto asyncOp = UpdateMediaStreamPropertiesAsync();
+ }
+}
+
+// Intialization takes care few things below:
+// 1. Register rotation helper to update preview if rotation changes.
+// 2. Takes care connected standby scenarios to cleanup and reintialize when suspend/resume
+IAsyncAction ReactCameraView::InitializeAsync() {
+ try {
+ auto device = co_await FindCameraDeviceAsync();
+ if (device != nullptr) {
+ auto settings = winrt::Windows::Media::Capture::MediaCaptureInitializationSettings();
+ settings.VideoDeviceId(device.Id());
+
+ auto mediaCapture = winrt::Windows::Media::Capture::MediaCapture();
+ co_await mediaCapture.InitializeAsync(settings);
+
+ m_availableVideoEncodingProperties =
+ mediaCapture.VideoDeviceController().GetAvailableMediaStreamProperties(winrt::MediaStreamType::VideoPreview);
+
+ m_childElement.Source(mediaCapture);
+
+ co_await UpdateMediaStreamPropertiesAsync();
+
+ UpdateFlashMode(m_flashMode);
+ UpdateAutoFocus(m_focusMode);
+ UpdateWhiteBalance(m_whiteBalance);
+ UpdateKeepAwake(m_keepAwake);
+ UpdateMirrorVideo(m_mirrorVideo);
+
+ co_await mediaCapture.StartPreviewAsync();
+ m_isPreview = true;
+
+ m_rotationHelper = CameraRotationHelper(device.EnclosureLocation());
+ m_rotationEventToken =
+ m_rotationHelper.OrientationChanged([ref = get_weak()](const auto &, const bool updatePreview) {
+ if (auto self = ref.get()) {
+ self->OnOrientationChanged(updatePreview);
+ }
+ });
+ co_await UpdatePreviewOrientationAsync();
- IAsyncAction ReactCameraView::CleanupMediaCaptureAsync()
- {
- if (m_isInitialized)
- {
- SetEvent(m_signal.get()); // In case recording is still going on
- if (auto mediaCapture = m_childElement.Source())
- {
- co_await mediaCapture.StopPreviewAsync();
- if (m_rotationHelper != nullptr)
- {
- m_rotationHelper.OrientationChanged(m_rotationEventToken);
- m_rotationHelper = nullptr;
- }
- m_childElement.Source(nullptr);
+ m_applicationSuspendingEventToken =
+ winrt::Application::Current().Suspending(winrt::auto_revoke, [ref = get_weak()](auto const &, auto const &) {
+ if (auto self = ref.get()) {
+ self->OnApplicationSuspending();
}
- m_isInitialized = false;
- }
- }
+ });
- IAsyncOperation ReactCameraView::FindCameraDeviceByPanelAsync()
- {
- // Get available devices for capturing pictures
- auto allVideoDevices = co_await winrt::DeviceInformation::FindAllAsync(winrt::DeviceClass::VideoCapture);
- for (auto cameraDeviceInfo : allVideoDevices)
- {
- if (cameraDeviceInfo.EnclosureLocation() != nullptr && cameraDeviceInfo.EnclosureLocation().Panel() == m_panelType)
- {
- co_return cameraDeviceInfo;
+ m_applicationResumingEventToken =
+ winrt::Application::Current().Resuming(winrt::auto_revoke, [ref = get_weak()](auto const &, auto const &) {
+ if (auto self = ref.get()) {
+ self->OnApplicationResuming();
}
- }
- // Nothing matched, just return the first
- if (allVideoDevices.Size() > 0)
- {
- co_return allVideoDevices.GetAt(0);
- }
- // We didn't find any devices, so return a null instance
- co_return nullptr;
+ });
+
+ m_isInitialized = true;
}
- // update preview if display orientation changes.
- void ReactCameraView::OnOrientationChanged(const bool updatePreview)
- {
- if (updatePreview)
- {
- UpdatePreviewOrientationAsync();
+ } catch (winrt::hresult_error const &) {
+ m_isInitialized = false;
+ }
+}
+
+IAsyncAction ReactCameraView::UpdateMediaStreamPropertiesAsync() {
+ co_await UpdateMediaStreamPropertiesAsync(m_defaultVideoQuality);
+}
+
+IAsyncAction ReactCameraView::UpdateMediaStreamPropertiesAsync(int videoQuality) {
+ if (auto mediaCapture = m_childElement.Source()) {
+ winrt::VideoEncodingProperties foundProperties = nullptr;
+ uint32_t foundResolution = 0;
+ uint32_t foundFrameRate = 0;
+
+ winrt::VideoEncodingProperties bestProperties = nullptr;
+ uint32_t bestResolution = 0;
+ uint32_t bestFrameRate = 0;
+
+ for (auto mediaEncodingProperties : m_availableVideoEncodingProperties) {
+ if (auto videoEncodingProperties = mediaEncodingProperties.try_as()) {
+ auto resolution = videoEncodingProperties.Width() * videoEncodingProperties.Height();
+ auto frameRate = videoEncodingProperties.FrameRate().Denominator() > 0
+ ? videoEncodingProperties.FrameRate().Numerator() / videoEncodingProperties.FrameRate().Denominator() : 0;
+
+ // Save the best encoding for later, in case the target cannot be found
+ if (bestProperties == nullptr || (resolution >= bestResolution && frameRate >= bestFrameRate)) {
+ bestProperties = videoEncodingProperties;
+ bestResolution = resolution;
+ bestFrameRate = frameRate;
}
- }
- void ReactCameraView::OnApplicationSuspending()
- {
- if (m_keepAwake)
- {
- m_displayRequest.RequestRelease();
+ bool resolutionMatch =
+ (videoQuality == ReactCameraConstants::CameraVideoQuality2160P &&
+ videoEncodingProperties.Width() == 3840 && videoEncodingProperties.Height() == 2160) ||
+ (videoQuality == ReactCameraConstants::CameraVideoQuality1080P &&
+ videoEncodingProperties.Width() == 1920 && videoEncodingProperties.Height() == 1080) ||
+ (videoQuality == ReactCameraConstants::CameraVideoQuality720P &&
+ videoEncodingProperties.Width() == 1280 && videoEncodingProperties.Height() == 720) ||
+ (videoQuality == ReactCameraConstants::CameraVideoQualityWVGA &&
+ videoEncodingProperties.Width() == 800 && videoEncodingProperties.Height() == 480) ||
+ (videoQuality == ReactCameraConstants::CameraVideoQualityVGA &&
+ videoEncodingProperties.Width() == 640 && videoEncodingProperties.Height() == 480);
+
+ // Save this encoding if it:
+ // 1. Has the correct resolution AND
+ // 2. Has a better framerate
+ if (resolutionMatch && frameRate >= foundFrameRate) {
+ foundProperties = videoEncodingProperties;
+ foundResolution = resolution;
+ foundFrameRate = frameRate;
}
- CleanupMediaCaptureAsync();
+ }
}
- IAsyncAction ReactCameraView::OnUnloaded()
- {
- co_await CleanupMediaCaptureAsync();
+ // Default to the best encoding if the target could not be found, or if auto was requested
+ if (foundProperties == nullptr || videoQuality == ReactCameraConstants::CameraVideoQualityAuto) {
+ foundProperties = bestProperties;
}
- void ReactCameraView::OnApplicationResuming()
- {
- if (m_keepAwake)
- {
- m_displayRequest.RequestActive();
- }
- InitializeAsync();
+ if (foundProperties) {
+ co_await mediaCapture.VideoDeviceController().SetMediaStreamPropertiesAsync(winrt::MediaStreamType::VideoPreview, foundProperties);
}
- // update preview considering current orientation
- IAsyncAction ReactCameraView::UpdatePreviewOrientationAsync()
- {
- if (m_isInitialized)
- {
- if (auto mediaCapture = m_childElement.Source())
- {
- const GUID RotationKey = { 0xC380465D, 0x2271, 0x428C, {0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1} };
- auto props = mediaCapture.VideoDeviceController().GetMediaStreamProperties(MediaStreamType::VideoPreview);
- props.Properties().Insert(RotationKey, winrt::box_value(m_rotationHelper.GetCameraPreviewClockwiseDegrees()));
- co_await mediaCapture.SetEncodingPropertiesAsync(MediaStreamType::VideoPreview, props, nullptr);
- }
- }
+ }
+ co_return;
+}
+
+IAsyncAction ReactCameraView::CleanupMediaCaptureAsync() {
+ if (m_isInitialized) {
+ SetEvent(m_signal.get()); // In case recording is still going on
+ if (auto mediaCapture = m_childElement.Source()) {
+
+ if (m_isPreview) {
+ co_await mediaCapture.StopPreviewAsync();
+ m_isPreview = false;
+ }
+
+ if (m_rotationHelper != nullptr) {
+ m_rotationHelper.OrientationChanged(m_rotationEventToken);
+ m_rotationHelper = nullptr;
+ }
+ m_childElement.Source(nullptr);
}
-
- IAsyncOperation ReactCameraView::GetBase64DataAsync(winrt::Windows::Storage::Streams::IRandomAccessStream stream)
- {
- auto streamSize = static_cast(stream.Size());
- auto inputStream = stream.GetInputStreamAt(0);
- auto dataReader = winrt::Windows::Storage::Streams::DataReader(inputStream);
- co_await dataReader.LoadAsync(streamSize);
- auto buffer = dataReader.ReadBuffer(streamSize);
- co_return winrt::Windows::Security::Cryptography::CryptographicBuffer::EncodeToBase64String(buffer);
+ m_isInitialized = false;
+ }
+}
+
+IAsyncOperation ReactCameraView::FindCameraDeviceAsync() {
+ // Get available devices for capturing pictures
+ auto allVideoDevices = co_await winrt::DeviceInformation::FindAllAsync(winrt::DeviceClass::VideoCapture);
+
+ winrt::DeviceInformation targetDevice = nullptr;
+
+ // Id specified, search by Id
+ if (m_cameraId != nullptr && m_cameraId != "") {
+ for (auto cameraDeviceInfo : allVideoDevices) {
+ if (cameraDeviceInfo.IsEnabled() && m_cameraId == winrt::to_string(cameraDeviceInfo.Id())) {
+ // Exact id match
+ targetDevice = cameraDeviceInfo;
+ break;
+ }
}
-
- IAsyncOperation ReactCameraView::GetOutputStorageFileAsync(int type, int target)
- {
- auto ext = type == ReactCameraContants::MediaTypeImage ? ".jpg" : ".mp4";
- auto now = winrt::clock::now();
- auto ttnow = winrt::clock::to_time_t(now);
- struct tm time;
- _localtime64_s(&time, &ttnow);
- wchar_t buf[35];
- swprintf_s(buf, ARRAYSIZE(buf), L"%04d%02d%02d_%02d%02d%02d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
- auto filename = winrt::to_hstring(buf) + winrt::to_hstring(ext);
-
- switch (target)
- {
- case ReactCameraContants::CameraCaptureTargetMemory:
- case ReactCameraContants::CameraCaptureTargetTemp:
- return winrt::ApplicationData::Current().TemporaryFolder().CreateFileAsync(filename);
- case ReactCameraContants::CameraCaptureTargetCameraRoll:
- return winrt::KnownFolders::CameraRoll().CreateFileAsync(filename);
- case ReactCameraContants::CameraCaptureTargetDisk:
- if (type == ReactCameraContants::MediaTypeImage)
- {
- return winrt::KnownFolders::PicturesLibrary().CreateFileAsync(filename);
- }
- else
- {
- return winrt::KnownFolders::VideosLibrary().CreateFileAsync(filename);
- }
+ }
+
+ // Target not found by id, search by type
+ if (targetDevice == nullptr) {
+ for (auto cameraDeviceInfo : allVideoDevices) {
+ if (cameraDeviceInfo.IsEnabled()) {
+ if (
+ cameraDeviceInfo.EnclosureLocation() != nullptr &&
+ cameraDeviceInfo.EnclosureLocation().Panel() == m_panelType) {
+ // Device matches the panel requested (front/back/etc), take it
+ targetDevice = cameraDeviceInfo;
+ break;
+ } else if (
+ cameraDeviceInfo.EnclosureLocation() == nullptr ||
+ m_panelType == winrt::Windows::Devices::Enumeration::Panel::Unknown) {
+ // Device has no panel info, save it but keep looking
+ targetDevice = cameraDeviceInfo;
}
- return nullptr;
+ }
}
-
- void ReactCameraView::SetContext(winrt::Microsoft::ReactNative::IReactContext const& reactContext)
- {
- m_reactContext = reactContext;
+ }
+
+ // Target not found by id or by type, take the first enabled camera
+ if (targetDevice == nullptr) {
+ for (auto cameraDeviceInfo : allVideoDevices) {
+ if (cameraDeviceInfo.IsEnabled()) {
+ targetDevice = cameraDeviceInfo;
+ break;
+ }
+ }
+ }
+
+ // Return whichever device we've found
+ co_return targetDevice;
+}
+
+// update preview if display orientation changes.
+void ReactCameraView::OnOrientationChanged(const bool updatePreview) {
+ if (updatePreview) {
+ UpdatePreviewOrientationAsync();
+ }
+}
+
+void ReactCameraView::OnApplicationSuspending() {
+ if (m_keepAwake) {
+ m_displayRequest.RequestRelease();
+ }
+ CleanupMediaCaptureAsync();
+}
+
+IAsyncAction ReactCameraView::OnUnloaded() {
+ co_await CleanupMediaCaptureAsync();
+}
+
+void ReactCameraView::OnApplicationResuming() {
+ if (m_keepAwake) {
+ m_displayRequest.RequestActive();
+ }
+ InitializeAsync();
+}
+
+// update preview considering current orientation
+IAsyncAction ReactCameraView::UpdatePreviewOrientationAsync() {
+ if (m_isInitialized) {
+ if (auto mediaCapture = m_childElement.Source()) {
+ const GUID RotationKey = {0xC380465D, 0x2271, 0x428C, {0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1}};
+ auto props = mediaCapture.VideoDeviceController().GetMediaStreamProperties(MediaStreamType::VideoPreview);
+ props.Properties().Insert(RotationKey, winrt::box_value(m_rotationHelper.GetCameraPreviewClockwiseDegrees()));
+ co_await mediaCapture.SetEncodingPropertiesAsync(MediaStreamType::VideoPreview, props, nullptr);
}
+ }
+}
+
+IAsyncOperation ReactCameraView::GetBase64DataAsync(
+ winrt::Windows::Storage::Streams::IRandomAccessStream stream) {
+ auto streamSize = static_cast(stream.Size());
+ auto inputStream = stream.GetInputStreamAt(0);
+ auto dataReader = winrt::Windows::Storage::Streams::DataReader(inputStream);
+ co_await dataReader.LoadAsync(streamSize);
+ auto buffer = dataReader.ReadBuffer(streamSize);
+ co_return winrt::Windows::Security::Cryptography::CryptographicBuffer::EncodeToBase64String(buffer);
+}
+
+IAsyncOperation ReactCameraView::GetOutputStorageFileAsync(int type, int target) {
+ std::string ext;
+ switch (type) {
+ case ReactCameraConstants::MediaTypeJPG:
+ ext = ".jpg";
+ break;
+ case ReactCameraConstants::MediaTypeMP4:
+ ext = ".mp4";
+ break;
+ case ReactCameraConstants::MediaTypeWMV:
+ ext = ".wmv";
+ break;
+ }
+
+ auto now = winrt::clock::now();
+ auto ttnow = winrt::clock::to_time_t(now);
+ struct tm time;
+ _localtime64_s(&time, &ttnow);
+ wchar_t buf[35];
+ swprintf_s(
+ buf,
+ ARRAYSIZE(buf),
+ L"%04d%02d%02d_%02d%02d%02d",
+ 1900 + time.tm_year,
+ 1 + time.tm_mon,
+ time.tm_mday,
+ time.tm_hour,
+ time.tm_min,
+ time.tm_sec);
+ auto filename = winrt::to_hstring(buf) + winrt::to_hstring(ext);
+
+ switch (target) {
+ case ReactCameraConstants::CameraCaptureTargetMemory:
+ case ReactCameraConstants::CameraCaptureTargetTemp:
+ return winrt::ApplicationData::Current().TemporaryFolder().CreateFileAsync(filename);
+ case ReactCameraConstants::CameraCaptureTargetCameraRoll:
+ return winrt::KnownFolders::CameraRoll().CreateFileAsync(filename);
+ case ReactCameraConstants::CameraCaptureTargetDisk:
+ if (type == ReactCameraConstants::MediaTypeJPG) {
+ auto result = winrt::KnownFolders::PicturesLibrary().CreateFileAsync(filename);
+ return result;
+ } else {
+ return winrt::KnownFolders::VideosLibrary().CreateFileAsync(filename);
+ }
+ }
+
+ return nullptr;
+}
+
+void ReactCameraView::SetContext(winrt::Microsoft::ReactNative::IReactContext const &reactContext) {
+ m_reactContext = reactContext;
+}
+
+winrt::JSValueObject ReactCameraView::GetExifObject(winrt::BitmapPropertySet const& properties) noexcept {
+ winrt::JSValueObject exifObject;
+
+ for (auto it : properties) {
+ auto key = winrt::to_string(it.Key());
+ auto value = it.Value();
+
+ switch (value.Type()) {
+ case PropertyType::Boolean:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::Single:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::Double:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::Int16:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::Int32:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::Int64:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::UInt16:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::UInt32:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::UInt64:
+ exifObject[key] = JSValue(unbox_value(value.Value()));
+ break;
+ case PropertyType::String:
+ exifObject[key] = JSValue(winrt::to_string(unbox_value(value.Value())));
+ break;
+ }
+ }
+
+ return exifObject;
+}
+
+bool ReactCameraView::TryGetValueAsInt(
+ winrt::JSValueObject const &options,
+ const std::string key,
+ int &value,
+ const int defaultValue) noexcept {
+ auto search = options.find(key);
+
+ bool found = search != options.end();
+
+ value = found ? options[key].AsInt32() : defaultValue;
+
+ return found;
+}
+
+bool ReactCameraView::TryGetValueAsBool(
+ winrt::JSValueObject const &options,
+ const std::string key,
+ bool &value,
+ const bool defaultValue) noexcept {
+ auto search = options.find(key);
+
+ bool found = search != options.end();
+
+ value = found ? options[key].AsBoolean() : defaultValue;
+
+ return found;
+}
+
+bool ReactCameraView::TryGetValueAsFloat(
+ winrt::JSValueObject const &options,
+ const std::string key,
+ float &value,
+ const float defaultValue) noexcept {
+ auto search = options.find(key);
+
+ bool found = search != options.end();
+
+ value = found ? options[key].AsSingle() : defaultValue;
+
+ return found;
+}
-} // namespace winrt::ReactNativeVideoCPP
+} // namespace winrt::ReactNativeCameraCPP
diff --git a/windows/ReactNativeCameraCPP/ReactCameraView.h b/windows/ReactNativeCameraCPP/ReactCameraView.h
index 40f1daaa2..3434cd12e 100644
--- a/windows/ReactNativeCameraCPP/ReactCameraView.h
+++ b/windows/ReactNativeCameraCPP/ReactCameraView.h
@@ -1,68 +1,126 @@
#pragma once
#include
+
#include "NativeModules.h"
-#include "JSValueTreeWriter.h"
+
#include "CameraRotationHelper.h"
+#include "JSValueTreeWriter.h"
#include "ReactCameraConstants.h"
namespace winrt::ReactNativeCameraCPP {
- struct ReactCameraView : winrt::Windows::UI::Xaml::Controls::GridT {
- public:
- ReactCameraView() = default;
- ~ReactCameraView();
- void SetContext(winrt::Microsoft::ReactNative::IReactContext const &reactContext);
- void Initialize();
- void UpdateProperties(winrt::Microsoft::ReactNative::IJSValueReader const &propertyMapReader);
-
- winrt::Windows::Foundation::IAsyncAction TakePictureAsync(std::map const& options,
- winrt::Microsoft::ReactNative::ReactPromise &result);
- winrt::Windows::Foundation::IAsyncAction RecordAsync(std::map const& options, winrt::Microsoft::ReactNative::ReactPromise& result);
-
- public:
- static winrt::com_ptr Create();
-
- private:
- void UpdateKeepAwake(bool keepAwake);
- void UpdateTorchMode(int torchMode);
- void UpdateFlashMode(int flashMode);
- void UpdateAspect(int aspect);
- fire_and_forget UpdateDeviceType(int type);
-
- winrt::Windows::Foundation::IAsyncAction InitializeAsync();
- winrt::Windows::Foundation::IAsyncAction CleanupMediaCaptureAsync();
- winrt::Windows::Foundation::IAsyncOperation FindCameraDeviceByPanelAsync();
- winrt::Windows::Foundation::IAsyncOperation GetBase64DataAsync(winrt::Windows::Storage::Streams::IRandomAccessStream stream);
- winrt::Windows::Foundation::IAsyncOperation GetOutputStorageFileAsync(int type, int target);
- winrt::Windows::Foundation::IAsyncAction DelayStopRecording(int totalRecordingInSecs);
- winrt::Windows::Foundation::IAsyncAction WaitAndStopRecording();
- winrt::Windows::Foundation::IAsyncAction UpdatePreviewOrientationAsync();
- winrt::Windows::Foundation::IAsyncAction UpdateFilePropertiesAsync(winrt::Windows::Storage::StorageFile storageFile,
- std::map const& options);
-
- void OnOrientationChanged(const bool updatePreview);
- void OnApplicationSuspending();
- void OnApplicationResuming();
- winrt::Windows::Foundation::IAsyncAction OnUnloaded();
-
- bool TryGetValueAsInt(std::map const& options, const std::wstring key, int& value);
-
- winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
- winrt::Windows::UI::Xaml::Controls::CaptureElement m_childElement;
-
- handle m_signal{ CreateEvent(nullptr, true, false, nullptr) };
- winrt::Windows::Media::Capture::LowLagMediaRecording m_mediaRecording{ nullptr};
- winrt::ReactNativeCameraCPP::CameraRotationHelper m_rotationHelper{nullptr};
- winrt::Windows::System::Display::DisplayRequest m_displayRequest{ nullptr };
-
- winrt::event_token m_rotationEventToken{};
- winrt::Windows::UI::Xaml::Application::Suspending_revoker m_applicationSuspendingEventToken;
- winrt::Windows::UI::Xaml::Application::Resuming_revoker m_applicationResumingEventToken;
- winrt::Windows::UI::Xaml::FrameworkElement::Unloaded_revoker m_unloadedEventToken;
-
- bool m_isInitialized{ false };
- bool m_keepAwake{ false };
- int m_torchMode{ ReactCameraContants::CameraTorchModeOff };
- int m_flashMode{ ReactCameraContants::CameraFlashModeOff };
- winrt::Windows::Devices::Enumeration::Panel m_panelType{ winrt::Windows::Devices::Enumeration::Panel::Unknown };
- };
-} // namespace winrt::ReactNativeVideoCPP
+struct ReactCameraView : winrt::Windows::UI::Xaml::Controls::GridT {
+ public:
+ ReactCameraView() = default;
+ ~ReactCameraView();
+ void SetContext(winrt::Microsoft::ReactNative::IReactContext const &reactContext);
+ void Initialize();
+ void UpdateProperties(winrt::Microsoft::ReactNative::IJSValueReader const &propertyMapReader) noexcept;
+
+ winrt::Windows::Foundation::IAsyncAction TakePictureAsync(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+ winrt::Windows::Foundation::IAsyncAction RecordAsync(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+ winrt::Windows::Foundation::IAsyncAction StopRecordAsync() noexcept;
+ winrt::Windows::Foundation::IAsyncAction IsRecordingAsync(
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+ winrt::Windows::Foundation::IAsyncAction PausePreviewAsync() noexcept;
+ winrt::Windows::Foundation::IAsyncAction ResumePreviewAsync() noexcept;
+
+ public:
+ static winrt::com_ptr Create();
+
+ private:
+ void UpdateKeepAwake(bool keepAwake);
+ void UpdateFlashMode(int flashMode);
+ void UpdateAutoFocus(int focusMode);
+ void UpdateWhiteBalance(int whiteBalance);
+ void UpdateMirrorVideo(bool mirrorVideo);
+ void UpdateAspect(int aspect);
+ void UpdateDefaultVideoQuality(int videoQuality);
+
+ fire_and_forget UpdateDeviceId(std::string cameraId);
+ fire_and_forget UpdateDeviceType(int type);
+
+ winrt::Windows::Foundation::IAsyncAction InitializeAsync();
+
+ winrt::Windows::Foundation::IAsyncAction UpdateMediaStreamPropertiesAsync();
+ winrt::Windows::Foundation::IAsyncAction UpdateMediaStreamPropertiesAsync(int videoQuality);
+
+ winrt::Windows::Foundation::IAsyncAction CleanupMediaCaptureAsync();
+ winrt::Windows::Foundation::IAsyncOperation
+ FindCameraDeviceAsync();
+ winrt::Windows::Foundation::IAsyncOperation GetBase64DataAsync(
+ winrt::Windows::Storage::Streams::IRandomAccessStream stream);
+ winrt::Windows::Foundation::IAsyncOperation GetOutputStorageFileAsync(
+ int type,
+ int target);
+ void DelayStopRecording(float totalRecordingInSecs);
+ winrt::Windows::Foundation::IAsyncAction WaitAndStopRecording();
+ winrt::Windows::Foundation::IAsyncAction UpdatePreviewOrientationAsync();
+ winrt::Windows::Foundation::IAsyncAction UpdateFilePropertiesAsync(
+ winrt::Windows::Storage::StorageFile storageFile,
+ winrt::Microsoft::ReactNative::JSValueObject const &options);
+
+ void OnOrientationChanged(const bool updatePreview);
+ void OnApplicationSuspending();
+ void OnApplicationResuming();
+ winrt::Windows::Foundation::IAsyncAction OnUnloaded();
+
+ winrt::Microsoft::ReactNative::JSValueObject GetExifObject(
+ winrt::Windows::Graphics::Imaging::BitmapPropertySet const &properties) noexcept;
+
+ bool TryGetValueAsInt(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ const std::string key,
+ int &value,
+ const int defaultValue) noexcept;
+
+ bool TryGetValueAsBool(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ const std::string key,
+ bool &value,
+ const bool defaultValue) noexcept;
+
+ bool TryGetValueAsFloat(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ const std::string key,
+ float &value,
+ const float defaultValue) noexcept;
+
+ winrt::Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
+ winrt::Windows::UI::Xaml::Controls::CaptureElement m_childElement;
+
+ handle m_signal{CreateEvent(nullptr, true, false, nullptr)};
+ winrt::Windows::Media::Capture::LowLagMediaRecording m_mediaRecording{nullptr};
+ winrt::ReactNativeCameraCPP::CameraRotationHelper m_rotationHelper{nullptr};
+ winrt::Windows::System::Display::DisplayRequest m_displayRequest{nullptr};
+
+ winrt::Windows::System::Threading::ThreadPoolTimer m_recordTimer{nullptr};
+
+ winrt::event_token m_rotationEventToken{};
+ winrt::Windows::UI::Xaml::Application::Suspending_revoker m_applicationSuspendingEventToken;
+ winrt::Windows::UI::Xaml::Application::Resuming_revoker m_applicationResumingEventToken;
+ winrt::Windows::UI::Xaml::FrameworkElement::Unloaded_revoker m_unloadedEventToken;
+
+ bool m_isInitialized{false};
+ bool m_keepAwake{false};
+ bool m_isRecording{false};
+ int m_flashMode{ReactCameraConstants::CameraFlashModeOff};
+ int m_whiteBalance{ReactCameraConstants::CameraWhiteBalanceAuto};
+ int m_focusMode{ReactCameraConstants::CameraAutoFocusOn};
+ bool m_isPreview{false};
+ bool m_mirrorVideo{false};
+
+ std::string m_cameraId;
+
+ winrt::Windows::Devices::Enumeration::Panel m_panelType{winrt::Windows::Devices::Enumeration::Panel::Unknown};
+
+ winrt::Windows::Foundation::Collections::IVectorView
+ m_availableVideoEncodingProperties;
+
+ int m_defaultVideoQuality{ReactCameraConstants::CameraVideoQualityAuto};
+
+};
+} // namespace winrt::ReactNativeCameraCPP
diff --git a/windows/ReactNativeCameraCPP/ReactCameraViewManager.cpp b/windows/ReactNativeCameraCPP/ReactCameraViewManager.cpp
index 7a690055f..dd0e09376 100644
--- a/windows/ReactNativeCameraCPP/ReactCameraViewManager.cpp
+++ b/windows/ReactNativeCameraCPP/ReactCameraViewManager.cpp
@@ -5,152 +5,213 @@
#include
namespace winrt {
- using namespace Windows::UI::Xaml;
- using namespace Windows::UI::Xaml::Media;
- using namespace Windows::UI::Xaml::Controls;
- using namespace Windows::Devices::Enumeration;
- using namespace Windows::Foundation;
- using namespace Windows::Foundation::Collections;
- using namespace Windows::Media::MediaProperties;
- using namespace Windows::Storage;
- using namespace Windows::Storage::Streams;
- using namespace Microsoft::ReactNative;
-} //namespace winrt
-
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Media;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::Media::MediaProperties;
+using namespace Windows::Storage;
+using namespace Windows::Storage::Streams;
+using namespace Microsoft::ReactNative;
+} // namespace winrt
namespace winrt::ReactNativeCameraCPP::implementation {
- // static vector to contain all currently active camera view instances
- // This is a temporary workaround to map the view tag to view instance, since
- // Method call from ReactCameraModule constains view tag as parameter and we need
- // to forward the call to CameraView instance.
- std::vector> ReactCameraViewManager::m_cameraViewInstances;
-
- ReactCameraViewManager::ReactCameraViewManager() {}
-
- // IViewManager
- hstring ReactCameraViewManager::Name() noexcept {
- return L"RNCamera";
- }
-
- FrameworkElement ReactCameraViewManager::CreateView() noexcept {
- auto const& view = ReactNativeCameraCPP::ReactCameraView::Create();
- view->SetContext(m_reactContext);
- m_cameraViewInstances.emplace_back(view);
-
- return view.as();
- }
-
- // IViewManagerWithReactContext
- IReactContext ReactCameraViewManager::ReactContext() noexcept {
- return m_reactContext;
- }
-
- void ReactCameraViewManager::ReactContext(IReactContext reactContext) noexcept {
- m_reactContext = reactContext;
- }
-
- // IViewManagerWithNativeProperties
- IMapView ReactCameraViewManager::NativeProps() noexcept {
- auto nativeProps = winrt::single_threaded_map();
-
- nativeProps.Insert(L"aspect", ViewManagerPropertyType::Number);
- nativeProps.Insert(L"type", ViewManagerPropertyType::Number);
- nativeProps.Insert(L"autoFocus", ViewManagerPropertyType::Boolean);
- nativeProps.Insert(L"whiteBalance", ViewManagerPropertyType::Number);
- nativeProps.Insert(L"torchMode", ViewManagerPropertyType::Number);
- nativeProps.Insert(L"flashMode", ViewManagerPropertyType::Number);
- // nativeProps.Insert(L"barcodeScannerEnabled", ViewManagerPropertyType::Boolean);
- // nativeProps.Insert(L"barCodeTypes", ViewManagerPropertyType::Array);
- nativeProps.Insert(L"keepAwake", ViewManagerPropertyType::Boolean);
-
- return nativeProps.GetView();
- }
-
- void ReactCameraViewManager::UpdateProperties(
- FrameworkElement const& view,
- IJSValueReader const& propertyMapReader) noexcept {
- if (auto reactCameraView = view.try_as()) {
- reactCameraView->UpdateProperties(propertyMapReader);
- }
+// static vector to contain all currently active camera view instances
+// This is a temporary workaround to map the view tag to view instance, since
+// Method call from ReactCameraModule constains view tag as parameter and we need
+// to forward the call to CameraView instance.
+std::vector> ReactCameraViewManager::m_cameraViewInstances;
+
+ReactCameraViewManager::ReactCameraViewManager() {}
+
+// IViewManager
+hstring ReactCameraViewManager::Name() noexcept {
+ return L"RNCamera";
+}
+
+FrameworkElement ReactCameraViewManager::CreateView() noexcept {
+ auto const &view = ReactNativeCameraCPP::ReactCameraView::Create();
+ view->SetContext(m_reactContext);
+ m_cameraViewInstances.emplace_back(view);
+
+ return view.as();
+}
+
+// IViewManagerWithReactContext
+IReactContext ReactCameraViewManager::ReactContext() noexcept {
+ return m_reactContext;
+}
+
+void ReactCameraViewManager::ReactContext(IReactContext reactContext) noexcept {
+ m_reactContext = reactContext;
+}
+
+// IViewManagerWithNativeProperties
+IMapView ReactCameraViewManager::NativeProps() noexcept {
+ auto nativeProps = winrt::single_threaded_map();
+
+ nativeProps.Insert(L"aspect", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"type", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"cameraId", ViewManagerPropertyType::String);
+ nativeProps.Insert(L"autoFocus", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"whiteBalance", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"torchMode", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"flashMode", ViewManagerPropertyType::Number);
+ // nativeProps.Insert(L"barcodeScannerEnabled", ViewManagerPropertyType::Boolean);
+ // nativeProps.Insert(L"barCodeTypes", ViewManagerPropertyType::Array);
+ nativeProps.Insert(L"keepAwake", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"mirrorVideo", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"defaultVideoQuality", ViewManagerPropertyType::Number);
+
+ return nativeProps.GetView();
+}
+
+void ReactCameraViewManager::UpdateProperties(
+ FrameworkElement const &view,
+ IJSValueReader const &propertyMapReader) noexcept {
+ if (auto reactCameraView = view.try_as()) {
+ reactCameraView->UpdateProperties(propertyMapReader);
+ }
+}
+
+void ReactCameraViewManager::RemoveViewFromList(winrt::com_ptr view) {
+ auto it = std::find(m_cameraViewInstances.begin(), m_cameraViewInstances.end(), view);
+ if (it != m_cameraViewInstances.end())
+ m_cameraViewInstances.erase(it);
+}
+
+IAsyncAction ReactCameraViewManager::TakePictureAsync(
+ JSValueObject const &options,
+ int viewTag,
+ ReactPromise const &result) noexcept {
+ auto capturedPromise = result;
+ auto capturedOptions = options.Copy();
+
+ auto index = co_await FindCamera(viewTag);
+ if (index != -1) {
+ auto cameraView = m_cameraViewInstances.at(index);
+ co_await cameraView->TakePictureAsync(capturedOptions, capturedPromise);
+ } else {
+ capturedPromise.Reject("No camera instance found.");
+ }
+}
+
+IAsyncAction ReactCameraViewManager::RecordAsync(
+ JSValueObject const &options,
+ int viewTag,
+ ReactPromise const &result) noexcept {
+ auto capturedPromise = result;
+ auto capturedOptions = options.Copy();
+
+ auto index = co_await FindCamera(viewTag);
+ if (index != -1) {
+ auto cameraView = m_cameraViewInstances.at(index);
+ co_await cameraView->RecordAsync(capturedOptions, capturedPromise);
+ } else {
+ capturedPromise.Reject("No camera instance found.");
+ }
+}
+
+IAsyncAction ReactCameraViewManager::StopRecordAsync(int viewTag) noexcept {
+ auto index = co_await FindCamera(viewTag);
+ if (index != -1) {
+ auto cameraView = m_cameraViewInstances.at(index);
+ co_await cameraView->StopRecordAsync();
+ }
+}
+
+IAsyncAction ReactCameraViewManager::IsRecordingAsync(
+ int viewTag,
+ winrt::Microsoft::ReactNative::ReactPromise const& result) noexcept {
+ auto capturedPromise = result;
+
+ auto index = co_await FindCamera(viewTag);
+ if (index != -1) {
+ auto cameraView = m_cameraViewInstances.at(index);
+ co_await cameraView->IsRecordingAsync(capturedPromise);
+ } else {
+ capturedPromise.Reject("No camera instance found.");
+ }
+}
+
+IAsyncAction ReactCameraViewManager::PausePreviewAsync(int viewTag) noexcept {
+ auto index = co_await FindCamera(viewTag);
+ if (index != -1) {
+ auto cameraView = m_cameraViewInstances.at(index);
+ co_await cameraView->PausePreviewAsync();
+ }
+}
+
+IAsyncAction ReactCameraViewManager::ResumePreviewAsync(int viewTag) noexcept {
+ auto index = co_await FindCamera(viewTag);
+ if (index != -1) {
+ auto cameraView = m_cameraViewInstances.at(index);
+ co_await cameraView->ResumePreviewAsync();
+ }
+}
+
+// Intialize MediaCapture and will bring up the constent dialog if this
+// is the first time. RNC will display a progress indicator while waiting
+// for user click. This method will resolve as no permission if user does
+// not grant the permission or App does not have the appx capabilities for
+// Microphone and WebCam specified in its Package.Appxmanifest.
+IAsyncAction ReactCameraViewManager::CheckMediaCapturePermissionAsync(
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept {
+ auto capturedPromise = result;
+
+ auto mediaCapture = winrt::Windows::Media::Capture::MediaCapture();
+ bool hasPermission = true;
+ try {
+ co_await mediaCapture.InitializeAsync();
+ } catch (winrt::hresult_error const &) {
+ hasPermission = false;
+ }
+
+ capturedPromise.Resolve(hasPermission);
+}
+
+winrt::IAsyncAction ReactCameraViewManager::GetCameraIdsAsync(
+ winrt::ReactPromise const& result) noexcept {
+ auto capturedPromise = result;
+
+ auto allVideoDevices = co_await winrt::DeviceInformation::FindAllAsync(winrt::DeviceClass::VideoCapture);
+
+ winrt::JSValueArray resultArray;
+
+ for (auto cameraDeviceInfo : allVideoDevices) {
+ if (cameraDeviceInfo.IsEnabled()) {
+ resultArray.push_back(winrt::JSValueObject{
+ {"id", winrt::to_string(cameraDeviceInfo.Id())},
+ {"name", winrt::to_string(cameraDeviceInfo.Name())},
+ {"type",
+ cameraDeviceInfo.EnclosureLocation() ? static_cast(cameraDeviceInfo.EnclosureLocation().Panel())
+ : ReactCameraConstants::CameraTypeUnknown},
+ });
}
-
- void ReactCameraViewManager::RemoveViewFromList(winrt::com_ptr view)
- {
- auto it = std::find(m_cameraViewInstances.begin(), m_cameraViewInstances.end(), view);
- if (it != m_cameraViewInstances.end())
- m_cameraViewInstances.erase(it);
- }
-
- IAsyncAction ReactCameraViewManager::TakePictureAsync(
- std::map const& options,
- int viewTag,
- ReactPromise& result)
- {
- auto index = co_await FindCamera(viewTag);
- if (index != -1)
- {
- auto cameraView = m_cameraViewInstances.at(index);
- co_await cameraView->TakePictureAsync(options, result);
- }
- else
- {
- result.Reject("No camera instance found.");
- }
- }
-
- IAsyncAction ReactCameraViewManager::RecordAsync(
- std::map const& options,
- int viewTag,
- ReactPromise& result)
- {
- auto index = co_await FindCamera(viewTag);
- if (index != -1)
- {
- auto cameraView = m_cameraViewInstances.at(index);
- co_await cameraView->RecordAsync(options, result);
- }
- else
- {
- result.Reject("No camera instance found.");
- }
- }
-
- // Intialize MediaCapture and will bring up the constent dialog if this
- // is the first time. RNC will display a progress indicator while waiting
- // for user click. This method will resolve as no permission if user does
- // not grant the permission or App does not have the appx capabilities for
- // Microphone and WebCam specified in its Package.Appxmanifest.
- IAsyncAction ReactCameraViewManager::CheckMediaCapturePermissionAsync(
- winrt::Microsoft::ReactNative::ReactPromise& result)
- {
- auto mediaCapture = winrt::Windows::Media::Capture::MediaCapture();
- bool hasPermission = true;
- try {
- co_await mediaCapture.InitializeAsync();
- }
- catch (winrt::hresult_error const&) {
- hasPermission = false;
- }
- result.Resolve(hasPermission);
- }
-
- IAsyncOperation ReactCameraViewManager::FindCamera(int viewTag)
- {
- int index = 0;
- for (const auto& cameraView : m_cameraViewInstances)
- {
- auto element = cameraView.as();
- auto dispatcher = element.Dispatcher();
- co_await resume_foreground(dispatcher);
- int currentTag = static_cast(element.GetValue(winrt::FrameworkElement::TagProperty()).as().GetInt64());
- if (currentTag == viewTag)
- {
- co_return index;
- }
- co_await resume_background();
- index++;
- }
- co_return -1;
+ }
+
+ capturedPromise.Resolve(resultArray);
+
+ co_return;
+}
+
+IAsyncOperation ReactCameraViewManager::FindCamera(int viewTag) noexcept {
+ int index = 0;
+ for (const auto &cameraView : m_cameraViewInstances) {
+ auto element = cameraView.as();
+ auto dispatcher = element.Dispatcher();
+ co_await resume_foreground(dispatcher);
+ int currentTag = static_cast(
+ element.GetValue(winrt::FrameworkElement::TagProperty()).as().GetInt64());
+ if (currentTag == viewTag) {
+ co_return index;
}
+ co_await resume_background();
+ index++;
+ }
+ co_return - 1;
+}
} // namespace winrt::ReactNativeCameraCPP::implementation
diff --git a/windows/ReactNativeCameraCPP/ReactCameraViewManager.h b/windows/ReactNativeCameraCPP/ReactCameraViewManager.h
index 13f461b6d..02d278b71 100644
--- a/windows/ReactNativeCameraCPP/ReactCameraViewManager.h
+++ b/windows/ReactNativeCameraCPP/ReactCameraViewManager.h
@@ -3,53 +3,64 @@
namespace winrt::ReactNativeCameraCPP::implementation {
- struct ReactCameraViewManager
- : winrt::implements<
- ReactCameraViewManager,
- winrt::Microsoft::ReactNative::IViewManager,
- winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
- winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties> {
- public:
- ReactCameraViewManager();
-
- // IViewManager
- winrt::hstring Name() noexcept;
- winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
-
- // IViewManagerWithReactContext
- winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
- void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;
-
- // IViewManagerWithNativeProperties
- winrt::Windows::Foundation::Collections::
- IMapView
- NativeProps() noexcept;
-
- void UpdateProperties(
- winrt::Windows::UI::Xaml::FrameworkElement const &view,
- winrt::Microsoft::ReactNative::IJSValueReader const &propertyMapReader) noexcept;
-
- static winrt::Windows::Foundation::IAsyncAction TakePictureAsync(
- std::map const& options,
- int viewTag,
- winrt::Microsoft::ReactNative::ReactPromise &result);
-
- static winrt::Windows::Foundation::IAsyncAction RecordAsync(
- std::map const& options,
- int viewTag,
- winrt::Microsoft::ReactNative::ReactPromise &result);
-
- static winrt::Windows::Foundation::IAsyncAction CheckMediaCapturePermissionAsync(
- winrt::Microsoft::ReactNative::ReactPromise& result);
-
- static void RemoveViewFromList(winrt::com_ptr);
-
- private:
-
- static winrt::Windows::Foundation::IAsyncOperation FindCamera(int viewTag);
-
- winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
- static std::vector> m_cameraViewInstances;
- };
+struct ReactCameraViewManager : winrt::implements<
+ ReactCameraViewManager,
+ winrt::Microsoft::ReactNative::IViewManager,
+ winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
+ winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties> {
+ public:
+ ReactCameraViewManager();
+
+ // IViewManager
+ winrt::hstring Name() noexcept;
+ winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
+
+ // IViewManagerWithReactContext
+ winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
+ void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;
+
+ // IViewManagerWithNativeProperties
+ winrt::Windows::Foundation::Collections::
+ IMapView
+ NativeProps() noexcept;
+
+ void UpdateProperties(
+ winrt::Windows::UI::Xaml::FrameworkElement const &view,
+ winrt::Microsoft::ReactNative::IJSValueReader const &propertyMapReader) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction TakePictureAsync(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ int viewTag,
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction RecordAsync(
+ winrt::Microsoft::ReactNative::JSValueObject const &options,
+ int viewTag,
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction StopRecordAsync(int viewTag) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction IsRecordingAsync(
+ int viewTag,
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction PausePreviewAsync(int viewTag) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction ResumePreviewAsync(int viewTag) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction CheckMediaCapturePermissionAsync(
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+
+ static winrt::Windows::Foundation::IAsyncAction GetCameraIdsAsync(
+ winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept;
+
+ static void RemoveViewFromList(winrt::com_ptr);
+
+ private:
+ static winrt::Windows::Foundation::IAsyncOperation FindCamera(int viewTag) noexcept;
+
+ winrt::Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
+ static std::vector> m_cameraViewInstances;
+};
} // namespace winrt::ReactNativeCameraCPP::implementation
diff --git a/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj b/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj
index 4affa4b8f..0d12a8684 100644
--- a/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj
+++ b/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj
@@ -1,6 +1,6 @@
-
-
+
+
true
true
@@ -9,19 +9,26 @@
ReactNativeCameraCPP
ReactNativeCameraCPP
en-US
- 14.0
+ 16.0
true
Windows Store
10.0
10.0.18362.0
- 10.0.15063.0
+ 10.0.16299.0
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\
+
Debug
ARM
+
+ Debug
+ ARM64
+
Debug
Win32
@@ -34,6 +41,10 @@
Release
ARM
+
+ Release
+ ARM64
+
Release
Win32
@@ -45,9 +56,6 @@
DynamicLibrary
- v140
- v141
- v142
Unicode
false
@@ -63,15 +71,15 @@
-
-
-
+
+
+
@@ -143,21 +151,25 @@
-
-
- {f7d32bd0-2749-483e-9a0d-1635ef7e3136}
- false
-
-
+
+
+
+
+
+ This project references targets in your node_modules\react-native-windows folder. The missing file is {0}.
+
+
+
+
-
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
+
+
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj.filters b/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj.filters
index 0f97461ff..dd9f1501d 100644
--- a/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj.filters
+++ b/windows/ReactNativeCameraCPP/ReactNativeCameraCPP.vcxproj.filters
@@ -35,5 +35,6 @@
+
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP/ReactPackageProvider.cpp b/windows/ReactNativeCameraCPP/ReactPackageProvider.cpp
index f6397fdbe..2e7a6c9a9 100644
--- a/windows/ReactNativeCameraCPP/ReactPackageProvider.cpp
+++ b/windows/ReactNativeCameraCPP/ReactPackageProvider.cpp
@@ -4,18 +4,16 @@
#include "ReactPackageProvider.g.cpp"
#endif
-#include "ReactCameraViewManager.h"
#include "ReactCameraModule.h"
+#include "ReactCameraViewManager.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::ReactNativeCameraCPP::implementation {
- void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
- AddAttributedModules(packageBuilder);
- packageBuilder.AddViewManager(L"ReactCameraViewManager", []() {
- return winrt::make();
- });
- }
+void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
+ AddAttributedModules(packageBuilder);
+ packageBuilder.AddViewManager(L"ReactCameraViewManager", []() { return winrt::make(); });
+}
} // namespace winrt::ReactNativeCameraCPP::implementation
diff --git a/windows/ReactNativeCameraCPP/ReactPackageProvider.h b/windows/ReactNativeCameraCPP/ReactPackageProvider.h
index 215a90e9b..6ad247700 100644
--- a/windows/ReactNativeCameraCPP/ReactPackageProvider.h
+++ b/windows/ReactNativeCameraCPP/ReactPackageProvider.h
@@ -5,16 +5,16 @@ using namespace winrt::Microsoft::ReactNative;
namespace winrt::ReactNativeCameraCPP::implementation {
- struct ReactPackageProvider : ReactPackageProviderT {
- ReactPackageProvider() = default;
+struct ReactPackageProvider : ReactPackageProviderT {
+ ReactPackageProvider() = default;
- void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
- };
+ void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
+};
} // namespace winrt::ReactNativeCameraCPP::implementation
namespace winrt::ReactNativeCameraCPP::factory_implementation {
- struct ReactPackageProvider : ReactPackageProviderT {};
+struct ReactPackageProvider : ReactPackageProviderT {};
} // namespace winrt::ReactNativeCameraCPP::factory_implementation
diff --git a/windows/ReactNativeCameraCPP/ReactPackageProvider.idl b/windows/ReactNativeCameraCPP/ReactPackageProvider.idl
index 7ba53915d..25f17972d 100644
--- a/windows/ReactNativeCameraCPP/ReactPackageProvider.idl
+++ b/windows/ReactNativeCameraCPP/ReactPackageProvider.idl
@@ -1,5 +1,9 @@
-namespace ReactNativeCameraCPP {
-[webhosthidden][default_interface] runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider {
- ReactPackageProvider();
-};
-} // namespace ReactNativeCameraCPP
+namespace ReactNativeCameraCPP
+{
+ [webhosthidden]
+ [default_interface]
+ runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
+ {
+ ReactPackageProvider();
+ };
+}
diff --git a/windows/ReactNativeCameraCPP/packages.config b/windows/ReactNativeCameraCPP/packages.config
index 9a69657f6..9dcb059fe 100644
--- a/windows/ReactNativeCameraCPP/packages.config
+++ b/windows/ReactNativeCameraCPP/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP/pch.h b/windows/ReactNativeCameraCPP/pch.h
index af0f28afb..d67b926d8 100644
--- a/windows/ReactNativeCameraCPP/pch.h
+++ b/windows/ReactNativeCameraCPP/pch.h
@@ -1,9 +1,22 @@
#pragma once
#include
+#include
+#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
+#include
#include
#include
#include
@@ -11,21 +24,8 @@
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
#include "winrt/Microsoft.ReactNative.h"
+
#include "JSValueTreeWriter.h"
#include "ReactCameraView.h"
diff --git a/windows/ReactNativeCameraCPP61.sln b/windows/ReactNativeCameraCPP61.sln
new file mode 100644
index 000000000..28a754931
--- /dev/null
+++ b/windows/ReactNativeCameraCPP61.sln
@@ -0,0 +1,199 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29215.179
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactWindowsCore", "..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxproj", "{11C084A3-A57C-4296-A679-CAC17B603144}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Shared", "..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "..\node_modules\react-native-windows\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.ReactNative.SharedManaged", "..\node_modules\react-native-windows\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.shproj", "{67A1076F-7790-4203-86EA-4402CCB5E782}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactNativeCameraCPP61", "ReactNativeCameraCPP61\ReactNativeCameraCPP61.vcxproj", "{5898D41D-92CC-48D0-95CD-9954572C266D}"
+EndProject
+Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxitems*{11c084a3-a57c-4296-a679-cac17b603144}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.projitems*{67a1076f-7790-4203-86ea-4402ccb5e782}*SharedItemsImports = 13
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{5898d41d-92cc-48d0-95cd-9954572c266d}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.Build.0 = Debug|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.ActiveCfg = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.Build.0 = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.Build.0 = Debug|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.ActiveCfg = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.Build.0 = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM.ActiveCfg = Debug|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM.Build.0 = Debug|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|ARM64.Build.0 = Debug|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x64.ActiveCfg = Debug|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x64.Build.0 = Debug|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x86.ActiveCfg = Debug|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Debug|x86.Build.0 = Debug|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM.ActiveCfg = Release|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM.Build.0 = Release|ARM
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM64.ActiveCfg = Release|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|ARM64.Build.0 = Release|ARM64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x64.ActiveCfg = Release|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x64.Build.0 = Release|x64
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x86.ActiveCfg = Release|Win32
+ {11C084A3-A57C-4296-A679-CAC17B603144}.Release|x86.Build.0 = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.ActiveCfg = Debug|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.Build.0 = Debug|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.ActiveCfg = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.Build.0 = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.Build.0 = Debug|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.ActiveCfg = Debug|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.Build.0 = Debug|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.ActiveCfg = Debug|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.Build.0 = Debug|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.ActiveCfg = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.Build.0 = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.Build.0 = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.ActiveCfg = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.Build.0 = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.ActiveCfg = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.Build.0 = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.Build.0 = Debug|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.ActiveCfg = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.Build.0 = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|ARM.Build.0 = Debug|ARM
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|ARM64.ActiveCfg = Debug|Win32
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|x64.ActiveCfg = Debug|x64
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|x64.Build.0 = Debug|x64
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|x86.ActiveCfg = Debug|Win32
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Debug|x86.Build.0 = Debug|Win32
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|ARM.ActiveCfg = Release|ARM
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|ARM.Build.0 = Release|ARM
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|ARM64.ActiveCfg = Release|Win32
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|x64.ActiveCfg = Release|x64
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|x64.Build.0 = Release|x64
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|x86.ActiveCfg = Release|Win32
+ {5898D41D-92CC-48D0-95CD-9954572C266D}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {11C084A3-A57C-4296-A679-CAC17B603144} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {0CC28589-39E4-4288-B162-97B959F8B843} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {67A1076F-7790-4203-86EA-4402CCB5E782} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}
+ EndGlobalSection
+EndGlobal
diff --git a/windows/ReactNativeCameraCPP61/PropertySheet.props b/windows/ReactNativeCameraCPP61/PropertySheet.props
new file mode 100644
index 000000000..5942ba395
--- /dev/null
+++ b/windows/ReactNativeCameraCPP61/PropertySheet.props
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP61/ReactNativeCameraCPP61.vcxproj b/windows/ReactNativeCameraCPP61/ReactNativeCameraCPP61.vcxproj
new file mode 100644
index 000000000..96ae99be0
--- /dev/null
+++ b/windows/ReactNativeCameraCPP61/ReactNativeCameraCPP61.vcxproj
@@ -0,0 +1,166 @@
+
+
+
+
+ true
+ true
+ true
+ {5898d41d-92cc-48d0-95cd-9954572c266d}
+ ReactNativeCameraCPP61
+ ReactNativeCameraCPP
+ en-US
+ 14.0
+ true
+ Windows Store
+ 10.0
+ 10.0.18362.0
+ 10.0.15063.0
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ DynamicLibrary
+ v140
+ v141
+ v142
+ Unicode
+ false
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+
+ /DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)
+ 28204
+ _WINRT_DLL;RNW61;%(PreprocessorDefinitions)
+ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)
+
+
+ Console
+ true
+ ReactNativeCameraCPP.def
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+
+
+
+
+ ..\ReactNativeCameraCPP\ReactPackageProvider.idl
+
+
+ ..\ReactNativeCameraCPP\CameraRotationHelper.idl
+
+
+
+
+
+
+
+ Create
+
+
+ ..\ReactNativeCameraCPP\ReactPackageProvider.idl
+
+
+ ..\ReactNativeCameraCPP\CameraRotationHelper.idl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {f7d32bd0-2749-483e-9a0d-1635ef7e3136}
+ false
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP61/ReactNativeCameraCPP61.vcxproj.filters b/windows/ReactNativeCameraCPP61/ReactNativeCameraCPP61.vcxproj.filters
new file mode 100644
index 000000000..ae4035aac
--- /dev/null
+++ b/windows/ReactNativeCameraCPP61/ReactNativeCameraCPP61.vcxproj.filters
@@ -0,0 +1,40 @@
+
+
+
+
+ accd3aa8-1ba0-4223-9bbe-0c431709210b
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {926ab91d-31b5-48c3-b9a4-e681349f27f0}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/windows/ReactNativeCameraCPP61/packages.config b/windows/ReactNativeCameraCPP61/packages.config
new file mode 100644
index 000000000..790637cec
--- /dev/null
+++ b/windows/ReactNativeCameraCPP61/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file