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