mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
Working AVFoundationn
This commit is contained in:
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -6,30 +6,22 @@
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
D8F9800B26FA41F6001C02B4 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
/* Begin PBXBuildFile section */
|
||||
D8C007EC26FAE33C00FFB741 /* capture in Resources */ = {isa = PBXBuildFile; fileRef = D8C007EB26FAE33C00FFB741 /* capture */; };
|
||||
D8C007EE26FAFFDC00FFB741 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C007ED26FAFFDC00FFB741 /* main.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D8F9800D26FA41F6001C02B4 /* example-capture */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "example-capture"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D8F9801826FA4230001C02B4 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
|
||||
D8F9801A26FA4238001C02B4 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
|
||||
D8F9801C26FA4244001C02B4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D8F9801E26FA42E2001C02B4 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = ../src; sourceTree = "<group>"; };
|
||||
D8F9802326FA4607001C02B4 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = ../../src; sourceTree = "<group>"; };
|
||||
D8F9802526FA462E001C02B4 /* Cargo.toml */ = {isa = PBXFileReference; lastKnownFileType = text; name = Cargo.toml; path = ../../Cargo.toml; sourceTree = "<group>"; };
|
||||
D8C007C026FAE25E00FFB741 /* example-capture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-capture.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D8C007CA26FAE25F00FFB741 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D8C007CB26FAE25F00FFB741 /* example_capture.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = example_capture.entitlements; sourceTree = "<group>"; };
|
||||
D8C007E726FAE29D00FFB741 /* rustpack-capture.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "rustpack-capture.xcodeproj"; path = "rustpack-capture/rustpack-capture.xcodeproj"; sourceTree = "<group>"; };
|
||||
D8C007EB26FAE33C00FFB741 /* capture */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = capture; path = ../../target/debug/capture; sourceTree = "<group>"; };
|
||||
D8C007ED26FAFFDC00FFB741 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D8F9800A26FA41F6001C02B4 /* Frameworks */ = {
|
||||
D8C007BD26FAE25E00FFB741 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -39,54 +31,51 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D8F9800426FA41F6001C02B4 = {
|
||||
D8C007B726FAE25E00FFB741 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D8F9801E26FA42E2001C02B4 /* src */,
|
||||
D8F9800F26FA41F6001C02B4 /* example-capture */,
|
||||
D8F9800E26FA41F6001C02B4 /* Products */,
|
||||
D8F9801726FA422F001C02B4 /* Frameworks */,
|
||||
D8C007E726FAE29D00FFB741 /* rustpack-capture.xcodeproj */,
|
||||
D8C007C226FAE25E00FFB741 /* example-capture */,
|
||||
D8C007C126FAE25E00FFB741 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D8F9800E26FA41F6001C02B4 /* Products */ = {
|
||||
D8C007C126FAE25E00FFB741 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D8F9800D26FA41F6001C02B4 /* example-capture */,
|
||||
D8C007C026FAE25E00FFB741 /* example-capture.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D8F9800F26FA41F6001C02B4 /* example-capture */ = {
|
||||
D8C007C226FAE25E00FFB741 /* example-capture */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D8F9801C26FA4244001C02B4 /* Info.plist */,
|
||||
D8F9802526FA462E001C02B4 /* Cargo.toml */,
|
||||
D8F9802326FA4607001C02B4 /* src */,
|
||||
D8C007EB26FAE33C00FFB741 /* capture */,
|
||||
D8C007CA26FAE25F00FFB741 /* Info.plist */,
|
||||
D8C007CB26FAE25F00FFB741 /* example_capture.entitlements */,
|
||||
D8C007ED26FAFFDC00FFB741 /* main.swift */,
|
||||
);
|
||||
path = "example-capture";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D8F9801726FA422F001C02B4 /* Frameworks */ = {
|
||||
D8C007E826FAE29D00FFB741 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D8F9801A26FA4238001C02B4 /* CoreMedia.framework */,
|
||||
D8F9801826FA4230001C02B4 /* AVFoundation.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D8F9800C26FA41F6001C02B4 /* example-capture */ = {
|
||||
D8C007BF26FAE25E00FFB741 /* example-capture */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D8F9801426FA41F6001C02B4 /* Build configuration list for PBXNativeTarget "example-capture" */;
|
||||
buildConfigurationList = D8C007CE26FAE25F00FFB741 /* Build configuration list for PBXNativeTarget "example-capture" */;
|
||||
buildPhases = (
|
||||
D8F9802126FA438F001C02B4 /* Sources */,
|
||||
D8F9802726FA465F001C02B4 /* Run Script */,
|
||||
D8F9800A26FA41F6001C02B4 /* Frameworks */,
|
||||
D8F9800B26FA41F6001C02B4 /* CopyFiles */,
|
||||
D8C007BC26FAE25E00FFB741 /* Sources */,
|
||||
D8C007BD26FAE25E00FFB741 /* Frameworks */,
|
||||
D8C007BE26FAE25E00FFB741 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -94,24 +83,26 @@
|
||||
);
|
||||
name = "example-capture";
|
||||
productName = "example-capture";
|
||||
productReference = D8F9800D26FA41F6001C02B4 /* example-capture */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
productReference = D8C007C026FAE25E00FFB741 /* example-capture.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
D8F9800526FA41F6001C02B4 /* Project object */ = {
|
||||
D8C007B826FAE25E00FFB741 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1170;
|
||||
LastUpgradeCheck = 1170;
|
||||
ORGANIZATIONNAME = "l1npengtul-nokhwa";
|
||||
TargetAttributes = {
|
||||
D8F9800C26FA41F6001C02B4 = {
|
||||
D8C007BF26FAE25E00FFB741 = {
|
||||
CreatedOnToolsVersion = 11.7;
|
||||
LastSwiftMigration = 1170;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = D8F9800826FA41F6001C02B4 /* Build configuration list for PBXProject "example-capture" */;
|
||||
buildConfigurationList = D8C007BB26FAE25E00FFB741 /* Build configuration list for PBXProject "example-capture" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
@@ -119,50 +110,46 @@
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = D8F9800426FA41F6001C02B4;
|
||||
productRefGroup = D8F9800E26FA41F6001C02B4 /* Products */;
|
||||
mainGroup = D8C007B726FAE25E00FFB741;
|
||||
productRefGroup = D8C007C126FAE25E00FFB741 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = D8C007E826FAE29D00FFB741 /* Products */;
|
||||
ProjectRef = D8C007E726FAE29D00FFB741 /* rustpack-capture.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D8F9800C26FA41F6001C02B4 /* example-capture */,
|
||||
D8C007BF26FAE25E00FFB741 /* example-capture */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
D8F9802726FA465F001C02B4 /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
D8C007BE26FAE25E00FFB741 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/capture",
|
||||
D8C007EC26FAE33C00FFB741 /* capture in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\ncargo +nightly build --features \"input-avfoundation\" --out-dir . -Z unstable-options\ncargo clean\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D8F9802126FA438F001C02B4 /* Sources */ = {
|
||||
D8C007BC26FAE25E00FFB741 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D8C007EE26FAFFDC00FFB741 /* main.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
D8F9801226FA41F6001C02B4 /* Debug */ = {
|
||||
D8C007CC26FAE25F00FFB741 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
@@ -217,10 +204,12 @@
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D8F9801326FA41F6001C02B4 /* Release */ = {
|
||||
D8C007CD26FAE25F00FFB741 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
@@ -268,49 +257,72 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D8F9801526FA41F6001C02B4 /* Debug */ = {
|
||||
D8C007CF26FAE25F00FFB741 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "example-capture/example_capture.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/example-capture/Info.plist";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
INFOPLIST_FILE = "example-capture/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "l1npengtul-nokhwa.example-capture";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D8F9801626FA41F6001C02B4 /* Release */ = {
|
||||
D8C007D026FAE25F00FFB741 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "example-capture/example_capture.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/example-capture/Info.plist";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
INFOPLIST_FILE = "example-capture/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "l1npengtul-nokhwa.example-capture";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
D8F9800826FA41F6001C02B4 /* Build configuration list for PBXProject "example-capture" */ = {
|
||||
D8C007BB26FAE25E00FFB741 /* Build configuration list for PBXProject "example-capture" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D8F9801226FA41F6001C02B4 /* Debug */,
|
||||
D8F9801326FA41F6001C02B4 /* Release */,
|
||||
D8C007CC26FAE25F00FFB741 /* Debug */,
|
||||
D8C007CD26FAE25F00FFB741 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D8F9801426FA41F6001C02B4 /* Build configuration list for PBXNativeTarget "example-capture" */ = {
|
||||
D8C007CE26FAE25F00FFB741 /* Build configuration list for PBXNativeTarget "example-capture" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D8F9801526FA41F6001C02B4 /* Debug */,
|
||||
D8F9801626FA41F6001C02B4 /* Release */,
|
||||
D8C007CF26FAE25F00FFB741 /* Debug */,
|
||||
D8C007D026FAE25F00FFB741 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = D8F9800526FA41F6001C02B4 /* Project object */;
|
||||
rootObject = D8C007B826FAE25E00FFB741 /* Project object */;
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
+16
-6
@@ -14,8 +14,8 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D8F9800C26FA41F6001C02B4"
|
||||
BuildableName = "example-capture"
|
||||
BlueprintIdentifier = "D8C007BF26FAE25E00FFB741"
|
||||
BuildableName = "example-capture.app"
|
||||
BlueprintName = "example-capture"
|
||||
ReferencedContainer = "container:example-capture.xcodeproj">
|
||||
</BuildableReference>
|
||||
@@ -44,12 +44,22 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D8F9800C26FA41F6001C02B4"
|
||||
BuildableName = "example-capture"
|
||||
BlueprintIdentifier = "D8C007BF26FAE25E00FFB741"
|
||||
BuildableName = "example-capture.app"
|
||||
BlueprintName = "example-capture"
|
||||
ReferencedContainer = "container:example-capture.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-q AVF"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-d"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
@@ -61,8 +71,8 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D8F9800C26FA41F6001C02B4"
|
||||
BuildableName = "example-capture"
|
||||
BlueprintIdentifier = "D8C007BF26FAE25E00FFB741"
|
||||
BuildableName = "example-capture.app"
|
||||
BlueprintName = "example-capture"
|
||||
ReferencedContainer = "container:example-capture.xcodeproj">
|
||||
</BuildableReference>
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>D8F9800C26FA41F6001C02B4</key>
|
||||
<key>D8C007BF26FAE25E00FFB741</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
|
||||
Binary file not shown.
@@ -6,8 +6,6 @@
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
@@ -20,17 +18,23 @@
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>we *notices buldge* wiww s-s-steaw aww youw webcam and pewsonyaw infowmation undew the x3 guise of b-being a &quot;nyokhwa exampwe c-captuwe app&quot; and a &quot;devewopew toow&quot; &lt;3 :3 *nyuzzwes yuwu*</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>steawing yuwu dawta uwu owo</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copywight © :3 2021 w1npengtuw, the x3 Nyokhwa Contwibutews. Wicensed undew the x3 MPL-2.0. *looks at you* You shouwd have weceived a copy with this softwawe, but if nyot i-it c-can be found at You c-can obtain onye at https://mozilla.org/MPL/2.0/. *huggles tightly*</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>we *notices buldge* wiww s-s-steaw aww youw webcam and pewsonyaw infowmation undew the x3 guise of b-being a "nyokhwa exampwe c-captuwe app" and a "devewopew toow" <3 :3 *nyuzzwes yuwu*</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSSupportsAutomaticTermination</key>
|
||||
<true/>
|
||||
<key>NSSupportsSuddenTermination</key>
|
||||
<true/>
|
||||
<key>RustBinName</key>
|
||||
<string>capture</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.usb</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,15 +0,0 @@
|
||||
//
|
||||
// main.c
|
||||
// example-capture
|
||||
//
|
||||
// Created by pengg on 2021/09/22.
|
||||
// Copyright © 2021 l1npengtul-nokhwa. All rights reserved.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
// insert code here...
|
||||
printf("Hello, World!\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// main.swift
|
||||
// example-capture
|
||||
//
|
||||
// Created by pengg on 2021/09/22.
|
||||
// Copyright © 2021 l1npengtul-nokhwa. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
func log(_ data: Data) {
|
||||
if let message = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
|
||||
print(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let task = Process()
|
||||
let bundle = Bundle.main
|
||||
let rustBinName = bundle.infoDictionary?["RustBinName"] as! String
|
||||
task.launchPath = bundle.path(forResource: rustBinName, ofType: nil)
|
||||
task.environment = ["RUST_BACKTRACE": "1"]
|
||||
|
||||
let arguments = CommandLine.arguments
|
||||
var passed_arguments = ""
|
||||
for argument in arguments {
|
||||
if !(argument.starts(with: "/") || argument.starts(with: "-NS")) && argument != "YES" && argument != "NO" {
|
||||
passed_arguments += " "
|
||||
passed_arguments += argument
|
||||
}
|
||||
}
|
||||
|
||||
print(passed_arguments)
|
||||
|
||||
let stdOut = Pipe()
|
||||
let stdErr = Pipe()
|
||||
|
||||
stdOut.fileHandleForReading.readabilityHandler = { log($0.availableData) }
|
||||
stdErr.fileHandleForReading.readabilityHandler = { log($0.availableData) }
|
||||
|
||||
task.standardOutput = stdOut
|
||||
task.standardError = stdErr
|
||||
|
||||
task.terminationHandler = { task in
|
||||
(task.standardOutput as AnyObject?)?.fileHandleForReading.readabilityHandler = nil
|
||||
(task.standardError as AnyObject?)?.fileHandleForReading.readabilityHandler = nil
|
||||
}
|
||||
|
||||
task.launch()
|
||||
task.waitUntilExit()
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D8C007DC26FAE29D00FFB741 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXLegacyTarget section */
|
||||
D8C007E126FAE29D00FFB741 /* rustpack-capture */ = {
|
||||
isa = PBXLegacyTarget;
|
||||
buildArgumentsString = "$(ACTION)";
|
||||
buildConfigurationList = D8C007E426FAE29D00FFB741 /* Build configuration list for PBXLegacyTarget "rustpack-capture" */;
|
||||
buildPhases = (
|
||||
);
|
||||
buildToolPath = /usr/bin/make;
|
||||
dependencies = (
|
||||
);
|
||||
name = "rustpack-capture";
|
||||
passBuildSettingsInEnvironment = 1;
|
||||
productName = "rustpack-capture";
|
||||
};
|
||||
/* End PBXLegacyTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
D8C007DD26FAE29D00FFB741 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1170;
|
||||
ORGANIZATIONNAME = "l1npengtul-nokhwa";
|
||||
TargetAttributes = {
|
||||
D8C007E126FAE29D00FFB741 = {
|
||||
CreatedOnToolsVersion = 11.7;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = D8C007E026FAE29D00FFB741 /* Build configuration list for PBXProject "rustpack-capture" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = D8C007DC26FAE29D00FFB741;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D8C007E126FAE29D00FFB741 /* rustpack-capture */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
D8C007E226FAE29D00FFB741 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D8C007E326FAE29D00FFB741 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D8C007E526FAE29D00FFB741 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEBUGGING_SYMBOLS = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
OTHER_CFLAGS = "";
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D8C007E626FAE29D00FFB741 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
OTHER_CFLAGS = "";
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
D8C007E026FAE29D00FFB741 /* Build configuration list for PBXProject "rustpack-capture" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D8C007E226FAE29D00FFB741 /* Debug */,
|
||||
D8C007E326FAE29D00FFB741 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D8C007E426FAE29D00FFB741 /* Build configuration list for PBXLegacyTarget "rustpack-capture" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D8C007E526FAE29D00FFB741 /* Debug */,
|
||||
D8C007E626FAE29D00FFB741 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = D8C007DD26FAE29D00FFB741 /* Project object */;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>rustpack-capture.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -107,6 +107,8 @@ fn main() {
|
||||
use_backend = CaptureAPIBackend::AVFoundation;
|
||||
}
|
||||
|
||||
println!("www");
|
||||
|
||||
match query_devices(use_backend) {
|
||||
Ok(devs) => {
|
||||
for (idx, camera) in devs.iter().enumerate() {
|
||||
@@ -119,8 +121,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
println!("a");
|
||||
|
||||
if matches.is_present("capture") {
|
||||
let backend_value = {
|
||||
match matches.value_of("capture-backend").unwrap() {
|
||||
@@ -196,8 +196,11 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
println!("www");
|
||||
|
||||
// open stream
|
||||
camera.open_stream().unwrap();
|
||||
println!("wwww");
|
||||
loop {
|
||||
if let Ok(frame) = camera.frame() {
|
||||
println!(
|
||||
|
||||
@@ -14,3 +14,5 @@ core-media-sys = "0.1.2"
|
||||
cocoa-foundation = "0.1.0"
|
||||
objc = { version = "0.2.7", features = ["exception"] }
|
||||
block = "0.1.6"
|
||||
flume = "0.10.9"
|
||||
dashmap = "4.0.2"
|
||||
+268
-194
@@ -54,24 +54,29 @@ pub enum AVFError {
|
||||
any(target_os = "macos", target_os = "ios"),
|
||||
link(name = "AVFoundation", kind = "framework")
|
||||
)]
|
||||
#[allow(non_snake_case)]
|
||||
pub mod core_media {
|
||||
// all of this is stolen from bindgen
|
||||
// steal it idc
|
||||
use core_media_sys::{
|
||||
CMBlockBufferRef, CMFormatDescriptionRef, CMSampleBufferRef, CMTime, CMVideoDimensions,
|
||||
FourCharCode,
|
||||
};
|
||||
use objc::runtime::Object;
|
||||
use objc::{runtime::Object, Message};
|
||||
use std::ops::Deref;
|
||||
|
||||
pub type id = *mut Object;
|
||||
pub type Id = *mut Object;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
pub struct NSObject(pub id);
|
||||
impl std::ops::Deref for NSObject {
|
||||
pub struct NSObject(pub Id);
|
||||
impl Deref for NSObject {
|
||||
type Target = objc::runtime::Object;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.0 }
|
||||
}
|
||||
}
|
||||
unsafe impl objc::Message for NSObject {}
|
||||
unsafe impl Message for NSObject {}
|
||||
impl NSObject {
|
||||
pub fn alloc() -> Self {
|
||||
Self(unsafe { msg_send!(objc::class!(NSObject), alloc) })
|
||||
@@ -80,14 +85,14 @@ pub mod core_media {
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
pub struct NSString(pub id);
|
||||
impl std::ops::Deref for NSString {
|
||||
pub struct NSString(pub Id);
|
||||
impl Deref for NSString {
|
||||
type Target = objc::runtime::Object;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.0 }
|
||||
}
|
||||
}
|
||||
unsafe impl objc::Message for NSString {}
|
||||
unsafe impl Message for NSString {}
|
||||
impl NSString {
|
||||
pub fn alloc() -> Self {
|
||||
Self(unsafe { msg_send!(objc::class!(NSString), alloc) })
|
||||
@@ -95,34 +100,17 @@ pub mod core_media {
|
||||
}
|
||||
|
||||
pub type AVMediaType = NSString;
|
||||
|
||||
extern "C" {
|
||||
pub static AVMediaTypeVideo: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeAudio: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeText: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeClosedCaption: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeSubtitle: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeTimecode: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeMetadata: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeMuxed: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeMetadataObject: AVMediaType;
|
||||
}
|
||||
extern "C" {
|
||||
pub static AVMediaTypeDepthData: AVMediaType;
|
||||
}
|
||||
|
||||
@@ -146,49 +134,116 @@ pub mod core_media {
|
||||
pub fn CMSampleBufferGetDataBuffer(sbuf: CMSampleBufferRef) -> CMBlockBufferRef;
|
||||
}
|
||||
|
||||
pub type dispatch_queue_t = NSObject;
|
||||
|
||||
extern "C" {
|
||||
pub fn dispatch_queue_create(
|
||||
label: *const ::std::os::raw::c_char,
|
||||
attr: NSObject,
|
||||
) -> dispatch_queue_t;
|
||||
) -> NSObject;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn dispatch_release(object: NSObject);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct __CVBuffer {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
pub type CVBufferRef = *mut __CVBuffer;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
extern "C" {
|
||||
pub fn CMSampleBufferGetImageBuffer(sbuf: CMSampleBufferRef) -> CVImageBufferRef;
|
||||
}
|
||||
|
||||
pub type CVImageBufferRef = CVBufferRef;
|
||||
pub type CVPixelBufferRef = CVImageBufferRef;
|
||||
pub type CVPixelBufferLockFlags = u64;
|
||||
pub type CVReturn = i32;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
extern "C" {
|
||||
pub fn CVPixelBufferLockBaseAddress(
|
||||
pixelBuffer: CVPixelBufferRef,
|
||||
lockFlags: CVPixelBufferLockFlags,
|
||||
) -> CVReturn;
|
||||
|
||||
pub fn CVPixelBufferUnlockBaseAddress(
|
||||
pixelBuffer: CVPixelBufferRef,
|
||||
unlockFlags: CVPixelBufferLockFlags,
|
||||
) -> CVReturn;
|
||||
|
||||
pub fn CVPixelBufferGetDataSize(pixelBuffer: CVPixelBufferRef) -> std::os::raw::c_ulong;
|
||||
|
||||
pub fn CVPixelBufferGetBaseAddress(
|
||||
pixelBuffer: CVPixelBufferRef,
|
||||
) -> *mut ::std::os::raw::c_void;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub static AVVideoCodecKey: NSString;
|
||||
}
|
||||
pub type OSType = FourCharCode;
|
||||
pub type AVVideoCodecType = NSString;
|
||||
extern "C" {
|
||||
pub static AVVideoCodecTypeHEVC: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeH264: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeJPEG: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeAppleProRes4444: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeAppleProRes422: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeAppleProRes422HQ: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeAppleProRes422LT: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeAppleProRes422Proxy: AVVideoCodecType;
|
||||
pub static AVVideoCodecTypeHEVCWithAlpha: AVVideoCodecType;
|
||||
pub static AVVideoCodecHEVC: NSString;
|
||||
pub static AVVideoCodecH264: NSString;
|
||||
pub static AVVideoCodecJPEG: NSString;
|
||||
pub static AVVideoCodecAppleProRes4444: NSString;
|
||||
pub static AVVideoCodecAppleProRes422: NSString;
|
||||
pub static AVVideoWidthKey: NSString;
|
||||
pub static AVVideoHeightKey: NSString;
|
||||
pub static AVVideoExpectedSourceFrameRateKey: NSString;
|
||||
pub fn CVPixelBufferGetPixelFormatType(pixelBuffer: CVPixelBufferRef) -> OSType;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
pub mod avfoundation {
|
||||
use crate::core_media::{dispatch_queue_create, dispatch_release, AVMediaTypeVideo, NSObject};
|
||||
use crate::core_media::{
|
||||
AVMediaTypeAudio, AVMediaTypeClosedCaption, AVMediaTypeDepthData, AVMediaTypeMetadata,
|
||||
AVMediaTypeMetadataObject, AVMediaTypeMuxed, AVMediaTypeSubtitle, AVMediaTypeText,
|
||||
AVMediaTypeTimecode, CVPixelBufferGetPixelFormatType,
|
||||
};
|
||||
use crate::{
|
||||
core_media::{
|
||||
CMBlockBufferCopyDataBytes, CMBlockBufferGetDataLength, CMSampleBufferGetDataBuffer,
|
||||
CMTimeMake, CMVideoFormatDescriptionGetDimensions,
|
||||
dispatch_queue_create, AVMediaTypeVideo, CMSampleBufferGetImageBuffer,
|
||||
CMVideoFormatDescriptionGetDimensions, CVImageBufferRef, CVPixelBufferGetBaseAddress,
|
||||
CVPixelBufferGetDataSize, CVPixelBufferLockBaseAddress, CVPixelBufferUnlockBaseAddress,
|
||||
NSObject,
|
||||
},
|
||||
AVFError,
|
||||
};
|
||||
use block::ConcreteBlock;
|
||||
use cocoa_foundation::foundation::{NSArray, NSInteger, NSString, NSUInteger};
|
||||
use core_media_sys::{
|
||||
kCMVideoCodecType_422YpCbCr8, kCMVideoCodecType_JPEG, CMBlockBufferRef,
|
||||
CMFormatDescriptionGetMediaSubType, CMSampleBufferRef, CMTime, CMVideoDimensions,
|
||||
kCMPixelFormat_422YpCbCr8_yuvs, kCMVideoCodecType_422YpCbCr8, kCMVideoCodecType_JPEG,
|
||||
kCMVideoCodecType_JPEG_OpenDML, CMFormatDescriptionGetMediaSubType, CMSampleBufferRef,
|
||||
CMVideoDimensions,
|
||||
};
|
||||
use dashmap::DashMap;
|
||||
use flume::{Receiver, Sender};
|
||||
use objc::{
|
||||
declare::ClassDecl,
|
||||
runtime::{Class, Object, Protocol, Sel, BOOL, YES},
|
||||
};
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
use std::{
|
||||
borrow::{Borrow, Cow},
|
||||
borrow::Cow,
|
||||
cmp::Ordering,
|
||||
convert::TryFrom,
|
||||
error::Error,
|
||||
ffi::{c_void, CStr},
|
||||
os::raw::c_int,
|
||||
ffi::{c_void, CStr, CString},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering as MemOrdering},
|
||||
Arc, Mutex, TryLockError,
|
||||
@@ -306,82 +361,91 @@ pub mod avfoundation {
|
||||
Ok(out_vec)
|
||||
}
|
||||
|
||||
fn compare_ns_string(this: *mut Object, other: crate::core_media::NSString) -> bool {
|
||||
unsafe {
|
||||
let equal: BOOL = msg_send![this, isEqualToString: other];
|
||||
equal == YES
|
||||
}
|
||||
}
|
||||
|
||||
fn default_callback(_: bool) {}
|
||||
|
||||
pub type CompressionData<'a> = (Cow<'a, [u8]>, AVFourCC);
|
||||
pub type DataPipe<'a> = (Sender<CompressionData<'a>>, Receiver<CompressionData<'a>>);
|
||||
|
||||
lazy_static! {
|
||||
static ref CAMERA_AUTHORIZED: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
|
||||
static ref USER_CALLBACK_FN: Arc<Mutex<fn(bool)>> = Arc::new(Mutex::new(default_callback));
|
||||
static ref PIPE_MAP: Arc<DashMap<usize, DataPipe<'static>>> = Arc::new(DashMap::new());
|
||||
static ref CALLBACK_CLASS: &'static Class = {
|
||||
let mut decl = ClassDecl::new("MyCaptureCallback", class!(NSObject)).unwrap();
|
||||
|
||||
// frame stack
|
||||
decl.add_ivar::<*mut c_void>("_frame_data");
|
||||
decl.add_ivar::<usize>("_frame_length");
|
||||
decl.add_ivar::<usize>("_index");
|
||||
|
||||
extern "C" fn my_callback_get_data_ptr(this: &mut Object, _: Sel) -> *mut c_void {
|
||||
extern "C" fn my_callback_get_index(this: &Object, _: Sel) -> usize {
|
||||
unsafe {
|
||||
*this.get_ivar("_frame_data")
|
||||
*this.get_ivar("_index")
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn my_callback_set_data_ptr(this: &mut Object, _: Sel, ptr: *mut c_void) {
|
||||
unsafe {
|
||||
this.set_ivar("_frame_data", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn my_callback_get_data_length(this: &Object, _: Sel) -> usize {
|
||||
extern "C" fn my_callback_set_index(this: &mut Object, _: Sel, new_index: usize) {
|
||||
unsafe {
|
||||
*this.get_ivar("_frame_length")
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn my_callback_set_data_length(this: &mut Object, _: Sel, new_length: usize) {
|
||||
unsafe {
|
||||
this.set_ivar("_frame_length", new_length);
|
||||
this.set_ivar("_index", new_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate compliance method
|
||||
// SAFETY: This assumes that the buffer byte size is a u8. Any other size will cause unsafety.
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
extern fn capture_out_callback(this: &mut Object, _: Sel, _: *mut Object, didOutputSampleBuffer: CMSampleBufferRef, _: *mut Object) {
|
||||
println!("aaa");
|
||||
let data_buffer: CMBlockBufferRef = unsafe { CMSampleBufferGetDataBuffer(didOutputSampleBuffer) };
|
||||
let length = unsafe { CMBlockBufferGetDataLength(data_buffer) } as usize;
|
||||
let ptr: *mut c_void = unsafe { msg_send![this, dataPointer] };
|
||||
let _: c_int = unsafe { CMBlockBufferCopyDataBytes(data_buffer, 0, length, ptr) };
|
||||
let _: () = unsafe { msg_send![this, setDataLength:length] };
|
||||
let image_buffer: CVImageBufferRef = unsafe { CMSampleBufferGetImageBuffer(didOutputSampleBuffer) };
|
||||
unsafe { CVPixelBufferLockBaseAddress(image_buffer, 0); };
|
||||
|
||||
let buffer_codec = unsafe { CVPixelBufferGetPixelFormatType(image_buffer) };
|
||||
|
||||
let fourcc = match buffer_codec {
|
||||
kCMVideoCodecType_422YpCbCr8 | kCMPixelFormat_422YpCbCr8_yuvs => AVFourCC::YUV2,
|
||||
kCMVideoCodecType_JPEG | kCMVideoCodecType_JPEG_OpenDML => AVFourCC::MJPEG,
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let buffer_length = unsafe { CVPixelBufferGetDataSize(image_buffer) };
|
||||
let buffer_ptr = unsafe { CVPixelBufferGetBaseAddress(image_buffer) };
|
||||
let buffer_as_vec = unsafe { std::slice::from_raw_parts_mut(buffer_ptr as *mut u8, buffer_length as usize).to_vec() };
|
||||
|
||||
unsafe { CVPixelBufferUnlockBaseAddress(image_buffer, 0) };
|
||||
let index: usize = unsafe { msg_send![this, index] };
|
||||
let pipes = &PIPE_MAP.get(&index);
|
||||
if let Some(pipe) = pipes {
|
||||
let _ = pipe.value().0.send((Cow::from(buffer_as_vec), fourcc));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
extern fn capture_drop_callback(_: &mut Object, _: Sel, _: *mut Object, _: *mut Object, _: *mut Object) {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
decl.add_protocol(Protocol::get("AVCaptureVideoDataOutputSampleBufferDelegate").unwrap());
|
||||
|
||||
decl.add_method(
|
||||
sel!(dataPointer), my_callback_get_data_ptr as extern "C" fn(&mut Object, Sel) -> *mut c_void
|
||||
sel!(index), my_callback_get_index as extern "C" fn(&Object, Sel) -> usize
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(setDataPointer:), my_callback_set_data_ptr as extern "C" fn(&mut Object, Sel, *mut c_void)
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(dataLength), my_callback_get_data_length as extern "C" fn(&Object, Sel) -> usize
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(setDataLength:), my_callback_set_data_length as extern "C" fn(&mut Object, Sel, usize)
|
||||
sel!(setIndex:), my_callback_set_index as extern "C" fn(&mut Object, Sel, usize)
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(captureOutput:didOutputSampleBuffer:fromConnection:), capture_out_callback as extern "C" fn(&mut Object, Sel, *mut Object, CMSampleBufferRef, *mut Object)
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(captureOutput:didDropSampleBuffer:fromConnection:), capture_drop_callback as extern "C" fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object)
|
||||
);
|
||||
|
||||
decl.add_protocol(Protocol::get("AVCaptureVideoDataOutputSampleBufferDelegate").unwrap());
|
||||
}
|
||||
|
||||
decl.register()
|
||||
};
|
||||
static ref OS_DISPATCH_CLASS: &'static Class = {
|
||||
let mut decl = ClassDecl::new("MyDispatchQueueSerial", class!(NSObject)).unwrap();
|
||||
|
||||
// decl.add_protocol(Protocol::get("OS_dispatch_object").unwrap());
|
||||
// decl.add_protocol(Protocol::get("OS_dispatch_queue").unwrap());
|
||||
decl.add_protocol(Protocol::get("OS_dispatch_queue_serial").unwrap());
|
||||
|
||||
decl.register()
|
||||
};
|
||||
}
|
||||
@@ -526,16 +590,16 @@ pub mod avfoundation {
|
||||
impl From<AVMediaType> for *mut Object {
|
||||
fn from(media_type: AVMediaType) -> Self {
|
||||
match media_type {
|
||||
AVMediaType::Audio => str_to_nsstr("AVMediaTypeAudio"),
|
||||
AVMediaType::ClosedCaption => str_to_nsstr("AVMediaTypeClosedCaption"),
|
||||
AVMediaType::DepthData => str_to_nsstr("AVMediaTypeDepthData"),
|
||||
AVMediaType::Metadata => str_to_nsstr("AVMediaTypeMetadata"),
|
||||
AVMediaType::MetadataObject => str_to_nsstr("AVMediaTypeMetadataObject"),
|
||||
AVMediaType::Muxed => str_to_nsstr("AVMediaTypeMuxed"),
|
||||
AVMediaType::Subtitle => str_to_nsstr("AVMediaTypeSubtitle"),
|
||||
AVMediaType::Text => str_to_nsstr("AVMediaTypeText"),
|
||||
AVMediaType::Timecode => str_to_nsstr("AVMediaTypeTimecode"),
|
||||
AVMediaType::Video => str_to_nsstr("AVMediaTypeVideo"),
|
||||
AVMediaType::Audio => unsafe { AVMediaTypeAudio.0 },
|
||||
AVMediaType::ClosedCaption => unsafe { AVMediaTypeClosedCaption.0 },
|
||||
AVMediaType::DepthData => unsafe { AVMediaTypeDepthData.0 },
|
||||
AVMediaType::Metadata => unsafe { AVMediaTypeMetadata.0 },
|
||||
AVMediaType::MetadataObject => unsafe { AVMediaTypeMetadataObject.0 },
|
||||
AVMediaType::Muxed => unsafe { AVMediaTypeMuxed.0 },
|
||||
AVMediaType::Subtitle => unsafe { AVMediaTypeSubtitle.0 },
|
||||
AVMediaType::Text => unsafe { AVMediaTypeText.0 },
|
||||
AVMediaType::Timecode => unsafe { AVMediaTypeTimecode.0 },
|
||||
AVMediaType::Video => unsafe { AVMediaTypeVideo.0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -544,28 +608,34 @@ pub mod avfoundation {
|
||||
type Error = AVFError;
|
||||
|
||||
fn try_from(value: *mut Object) -> Result<Self, Self::Error> {
|
||||
let borrow_str = nsstr_to_str(value);
|
||||
let value_str: &str = borrow_str.borrow();
|
||||
let v = match value_str {
|
||||
"AVMediaTypeAudio" => Ok(AVMediaType::Audio),
|
||||
"AVMediaTypeClosedCaption" => Ok(AVMediaType::ClosedCaption),
|
||||
"AVMediaTypeDepthData" => Ok(AVMediaType::DepthData),
|
||||
"AVMediaTypeMetadata" => Ok(AVMediaType::Metadata),
|
||||
"AVMediaTypeMetadataObject" => Ok(AVMediaType::MetadataObject),
|
||||
"AVMediaTypeMuxed" => Ok(AVMediaType::Muxed),
|
||||
"AVMediaTypeSubtitle" => Ok(AVMediaType::Subtitle),
|
||||
"AVMediaTypeText" => Ok(AVMediaType::Text),
|
||||
"AVMediaTypeTimecode" => Ok(AVMediaType::Timecode),
|
||||
"AVMediaTypeVideo" => Ok(AVMediaType::Video),
|
||||
_ => {
|
||||
return Err(AVFError::InvalidValue {
|
||||
found: value_str.to_string(),
|
||||
unsafe {
|
||||
if compare_ns_string(value, (AVMediaTypeAudio).clone()) {
|
||||
Ok(AVMediaType::Audio)
|
||||
} else if compare_ns_string(value, (AVMediaTypeClosedCaption).clone()) {
|
||||
Ok(AVMediaType::ClosedCaption)
|
||||
} else if compare_ns_string(value, (AVMediaTypeDepthData).clone()) {
|
||||
Ok(AVMediaType::DepthData)
|
||||
} else if compare_ns_string(value, (AVMediaTypeMetadata).clone()) {
|
||||
Ok(AVMediaType::Metadata)
|
||||
} else if compare_ns_string(value, (AVMediaTypeMetadataObject).clone()) {
|
||||
Ok(AVMediaType::MetadataObject)
|
||||
} else if compare_ns_string(value, (AVMediaTypeMuxed).clone()) {
|
||||
Ok(AVMediaType::Muxed)
|
||||
} else if compare_ns_string(value, (AVMediaTypeSubtitle).clone()) {
|
||||
Ok(AVMediaType::Subtitle)
|
||||
} else if compare_ns_string(value, (AVMediaTypeText).clone()) {
|
||||
Ok(AVMediaType::Text)
|
||||
} else if compare_ns_string(value, (AVMediaTypeTimecode).clone()) {
|
||||
Ok(AVMediaType::Timecode)
|
||||
} else if compare_ns_string(value, (AVMediaTypeVideo).clone()) {
|
||||
Ok(AVMediaType::Video)
|
||||
} else {
|
||||
let name = nsstr_to_str(value);
|
||||
Err(AVFError::InvalidValue {
|
||||
found: name.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let _: *mut std::ffi::c_void = unsafe { msg_send![value, autorelease] };
|
||||
v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,8 +665,8 @@ pub mod avfoundation {
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[repr(u32)]
|
||||
pub enum AVFourCC {
|
||||
YUV2 = kCMVideoCodecType_JPEG,
|
||||
MJPEG = kCMVideoCodecType_422YpCbCr8,
|
||||
YUV2,
|
||||
MJPEG,
|
||||
}
|
||||
|
||||
// Localized Name
|
||||
@@ -636,36 +706,66 @@ pub mod avfoundation {
|
||||
}
|
||||
|
||||
pub struct AVCaptureVideoCallback {
|
||||
index: usize,
|
||||
delegate: *mut Object,
|
||||
queue: *mut Object,
|
||||
}
|
||||
|
||||
impl AVCaptureVideoCallback {
|
||||
pub fn new() -> Self {
|
||||
AVCaptureVideoCallback::default()
|
||||
pub fn new(index: usize) -> Self {
|
||||
let cls = &CALLBACK_CLASS as &Class;
|
||||
let delegate: *mut Object = unsafe { msg_send![cls, alloc] };
|
||||
let delegate: *mut Object = unsafe { msg_send![delegate, init] };
|
||||
|
||||
let data_pipe: DataPipe = flume::unbounded();
|
||||
let _ = &PIPE_MAP.insert(index, data_pipe);
|
||||
|
||||
AVCaptureVideoCallback { index, delegate }
|
||||
}
|
||||
|
||||
pub fn index(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
|
||||
pub fn data_len(&self) -> usize {
|
||||
unsafe { msg_send![self.delegate, dataLength] }
|
||||
}
|
||||
|
||||
pub fn frame_to_slice<'a>(&self) -> Result<Cow<'a, [u8]>, AVFError> {
|
||||
let data_ptr: *mut c_void = unsafe { msg_send![self.delegate, dataPointer] };
|
||||
println!("tp1");
|
||||
let data_ptr = data_ptr as *mut u8 as *const u8;
|
||||
let data_length = self.data_len();
|
||||
println!("tp2");
|
||||
if data_ptr.is_null() {
|
||||
return Err(AVFError::ReadFrame("Nullptr".to_string()));
|
||||
}
|
||||
println!("tp3");
|
||||
if data_length == 0 {
|
||||
return Err(AVFError::ReadFrame("Zero Size Len".to_string()));
|
||||
}
|
||||
println!("tp4");
|
||||
let cow_slice = Cow::from(unsafe { std::slice::from_raw_parts(data_ptr, data_length) });
|
||||
println!("tp5");
|
||||
Ok(cow_slice)
|
||||
pub fn frame_to_slice<'a>(&self) -> Result<CompressionData<'a>, AVFError> {
|
||||
let pipe_map = &PIPE_MAP.get(&self.index); // why rust
|
||||
let pipe_recv = match pipe_map {
|
||||
Some(pipe) => &pipe.value().1,
|
||||
None => return Err(AVFError::ReadFrame("Data Pipe None".to_string())),
|
||||
};
|
||||
let data = match pipe_recv.drain().last() {
|
||||
Some(frame) => frame,
|
||||
None => match pipe_recv.recv() {
|
||||
Ok(f) => f,
|
||||
Err(why) => {
|
||||
return Err(AVFError::ReadFrame(format!(
|
||||
"Failed to read frame from pipe: {}",
|
||||
why.to_string()
|
||||
)))
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn frame_to_slice_no_block<'a>(&self) -> Result<CompressionData<'a>, AVFError> {
|
||||
let pipe_map = &PIPE_MAP.get(&self.index); // why rust
|
||||
let pipe_recv = match pipe_map {
|
||||
Some(pipe) => &pipe.value().1,
|
||||
None => return Err(AVFError::ReadFrame("Data Pipe None".to_string())),
|
||||
};
|
||||
let data = match pipe_recv.drain().last() {
|
||||
Some(frame) => frame,
|
||||
None => {
|
||||
return Err(AVFError::ReadFrame(
|
||||
"Failed to read frame from pipe: None".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> *mut Object {
|
||||
@@ -673,29 +773,6 @@ pub mod avfoundation {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AVCaptureVideoCallback {
|
||||
fn default() -> Self {
|
||||
println!("b");
|
||||
let cls = &CALLBACK_CLASS as &Class;
|
||||
let delegate: *mut Object = unsafe { msg_send![cls, alloc] };
|
||||
let delegate: *mut Object = unsafe { msg_send![delegate, init] };
|
||||
println!("c");
|
||||
let ptr: *mut c_void = std::ptr::null_mut();
|
||||
let len = 0_usize;
|
||||
|
||||
let queue_cls = &OS_DISPATCH_CLASS as &Class;
|
||||
let queue: *mut Object = unsafe { msg_send![queue_cls, new] };
|
||||
|
||||
unsafe {
|
||||
let _: () = msg_send![delegate, setDataPointer: ptr];
|
||||
let _: () = msg_send![delegate, setDataLength: len];
|
||||
}
|
||||
println!("c");
|
||||
|
||||
AVCaptureVideoCallback { delegate, queue }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AVCaptureVideoCallback {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
@@ -727,29 +804,20 @@ pub mod avfoundation {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct CaptureDeviceFormatDescriptor {
|
||||
pub resolution: AVVideoResolution,
|
||||
pub fps: f64,
|
||||
pub fps: u32,
|
||||
pub fourcc: AVFourCC,
|
||||
}
|
||||
|
||||
impl CaptureDeviceFormatDescriptor {
|
||||
pub fn compatible_with_capture_format(&self, other: &AVCaptureDeviceFormat) -> bool {
|
||||
let lower_fps = match other.fps_list.get(0) {
|
||||
Some(fps) => fps,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let higher_fps = match other.fps_list.get(1) {
|
||||
Some(fps) => fps,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
if self.resolution.height == other.resolution.height
|
||||
&& self.resolution.width == other.resolution.width
|
||||
&& self.fourcc == other.fourcc
|
||||
&& ((self.fps - *lower_fps).abs() < f64::EPSILON
|
||||
|| (self.fps - *higher_fps).abs() < f64::EPSILON)
|
||||
{
|
||||
return true;
|
||||
for fps in &other.fps_list {
|
||||
if self.resolution.height == other.resolution.height
|
||||
&& self.resolution.width == other.resolution.width
|
||||
&& self.fourcc == other.fourcc
|
||||
&& (*fps as u32) == self.fps
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -791,8 +859,8 @@ pub mod avfoundation {
|
||||
unsafe { CMFormatDescriptionGetMediaSubType(description_obj as *mut c_void) };
|
||||
#[allow(non_upper_case_globals)]
|
||||
let fourcc = match fcc_raw {
|
||||
kCMVideoCodecType_422YpCbCr8 => AVFourCC::YUV2,
|
||||
kCMVideoCodecType_JPEG => AVFourCC::MJPEG,
|
||||
kCMVideoCodecType_422YpCbCr8 | kCMPixelFormat_422YpCbCr8_yuvs => AVFourCC::YUV2,
|
||||
kCMVideoCodecType_JPEG | kCMVideoCodecType_JPEG_OpenDML => AVFourCC::MJPEG,
|
||||
_ => {
|
||||
return Err(AVFError::InvalidValue {
|
||||
found: fcc_raw.to_string(),
|
||||
@@ -851,7 +919,7 @@ pub mod avfoundation {
|
||||
|
||||
pub fn devices(&self) -> Vec<AVCaptureDeviceDescriptor> {
|
||||
let device_ns_array: *mut Object = unsafe { msg_send![self.inner, devices] };
|
||||
let objects_len: NSUInteger = unsafe { device_ns_array.count() };
|
||||
let objects_len: NSUInteger = unsafe { NSArray::count(device_ns_array) };
|
||||
let mut devices = vec![AVCaptureDeviceDescriptor::default(); objects_len as usize];
|
||||
for index in 0..objects_len {
|
||||
let device = unsafe { device_ns_array.objectAtIndex(index) };
|
||||
@@ -958,14 +1026,7 @@ pub mod avfoundation {
|
||||
unsafe { msg_send![self.inner, unlockForConfiguration] }
|
||||
}
|
||||
|
||||
pub fn set_frame_rate(&mut self, fps: u32) {
|
||||
let mut time = unsafe { CMTimeMake(1, fps as i32) };
|
||||
let time_ptr: *mut CMTime = &mut time;
|
||||
unsafe {
|
||||
let _: () = msg_send![self.inner, activeVideoMinFrameDuration: time_ptr];
|
||||
let _: () = msg_send![self.inner, activeVideoMaxFrameDuration: time_ptr];
|
||||
}
|
||||
}
|
||||
pub fn set_frame_rate(&mut self, _: u32) {}
|
||||
|
||||
pub fn set_all(
|
||||
&mut self,
|
||||
@@ -1031,24 +1092,30 @@ pub mod avfoundation {
|
||||
|
||||
pub fn add_delegate(&self, delegate: &AVCaptureVideoCallback) -> Result<(), AVFError> {
|
||||
unsafe {
|
||||
let avf_queue_str = match CString::new("avf_queue") {
|
||||
Ok(avf) => avf.into_raw(),
|
||||
Err(_) => {
|
||||
// should not happen
|
||||
return Err(AVFError::StreamOpen("String contains null? This is a bug, please report it https://github.com/l1npengtul/nokhwa".to_string()));
|
||||
}
|
||||
};
|
||||
let queue = dispatch_queue_create(avf_queue_str, NSObject(std::ptr::null_mut()));
|
||||
|
||||
let _: () = msg_send![
|
||||
self.inner,
|
||||
setSampleBufferDelegate: delegate.delegate
|
||||
queue: delegate.queue
|
||||
queue: queue
|
||||
];
|
||||
}
|
||||
println!("e");
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AVCaptureVideoDataOutput {
|
||||
fn default() -> Self {
|
||||
println!("d");
|
||||
let cls = class!(AVCaptureVideoDataOutput);
|
||||
let inner: *mut Object = unsafe { msg_send![cls, alloc] };
|
||||
let inner: *mut Object = unsafe { msg_send![inner, init] };
|
||||
println!("d");
|
||||
let inner: *mut Object = unsafe { msg_send![cls, new] };
|
||||
|
||||
AVCaptureVideoDataOutput { inner }
|
||||
}
|
||||
}
|
||||
@@ -1064,8 +1131,15 @@ pub mod avfoundation {
|
||||
AVCaptureSession::default()
|
||||
}
|
||||
|
||||
pub fn begin_configuration(&self) {
|
||||
unsafe { msg_send![self.inner, beginConfiguration] }
|
||||
}
|
||||
|
||||
pub fn commit_configuration(&self) {
|
||||
unsafe { msg_send![self.inner, commitConfiguration] }
|
||||
}
|
||||
|
||||
pub fn can_add_input(&self, input: &AVCaptureDeviceInput) -> bool {
|
||||
println!("{:?}", unsafe { self.inner.as_ref() }.unwrap().class());
|
||||
let result: BOOL = unsafe { msg_send![self.inner, canAddInput:input.inner] };
|
||||
result == YES
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
use image::{ImageBuffer, Rgb};
|
||||
use nokhwa_bindings_macos::avfoundation::{
|
||||
query_avfoundation, AVCaptureDevice, AVCaptureDeviceInput, AVCaptureSession,
|
||||
AVCaptureVideoCallback, AVCaptureVideoDataOutput,
|
||||
AVCaptureVideoCallback, AVCaptureVideoDataOutput, AVFourCC,
|
||||
};
|
||||
use std::{any::Any, borrow::Cow, collections::HashMap};
|
||||
|
||||
@@ -20,6 +20,8 @@ use std::{any::Any, borrow::Cow, collections::HashMap};
|
||||
/// # Quirks
|
||||
/// - While working with `iOS` is allowed, it is not officially supported and may not work.
|
||||
/// - You **must** call [`nokhwa_initialize`](crate::nokhwa_initialize) **before** doing anything with `AVFoundation`.
|
||||
/// - This only works on 64 bit platforms.
|
||||
/// - FPS adjustment does not work.
|
||||
pub struct AVFoundationCaptureDevice {
|
||||
device: AVCaptureDevice,
|
||||
dev_input: Option<AVCaptureDeviceInput>,
|
||||
@@ -52,7 +54,9 @@ impl AVFoundationCaptureDevice {
|
||||
}
|
||||
};
|
||||
|
||||
let device = AVCaptureDevice::from_id(&device_descriptor.misc())?;
|
||||
let mut device = AVCaptureDevice::from_id(&device_descriptor.misc())?;
|
||||
device.lock()?;
|
||||
device.set_all(camera_format.into())?;
|
||||
|
||||
Ok(AVFoundationCaptureDevice {
|
||||
device,
|
||||
@@ -95,10 +99,8 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
|
||||
}
|
||||
|
||||
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
||||
self.device.lock()?;
|
||||
self.device.set_all(new_fmt.into())?;
|
||||
self.format = new_fmt;
|
||||
self.device.unlock();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -208,11 +210,13 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
let input = AVCaptureDeviceInput::new(&self.device)?;
|
||||
let session = AVCaptureSession::new();
|
||||
session.begin_configuration();
|
||||
session.add_input(&input)?;
|
||||
let callback = AVCaptureVideoCallback::new();
|
||||
let callback = AVCaptureVideoCallback::new(self.info.index());
|
||||
let output = AVCaptureVideoDataOutput::new();
|
||||
output.add_delegate(&callback)?;
|
||||
session.add_output(&output)?;
|
||||
session.commit_configuration();
|
||||
session.start()?;
|
||||
|
||||
self.dev_input = Some(input);
|
||||
@@ -238,11 +242,7 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
|
||||
|
||||
fn frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
|
||||
let cam_fmt = self.camera_format();
|
||||
let raw_frame = self.frame_raw()?;
|
||||
let conv = match cam_fmt.format() {
|
||||
FrameFormat::MJPEG => mjpeg_to_rgb888(&raw_frame)?,
|
||||
FrameFormat::YUYV => yuyv422_to_rgb888(&raw_frame)?,
|
||||
};
|
||||
let conv = self.frame_raw()?.to_vec();
|
||||
let image_buf =
|
||||
match ImageBuffer::from_vec(cam_fmt.width(), cam_fmt.height(), conv) {
|
||||
Some(buf) => {
|
||||
@@ -258,9 +258,33 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
|
||||
}
|
||||
|
||||
fn frame_raw(&mut self) -> Result<Cow<[u8]>, NokhwaError> {
|
||||
match &self.session {
|
||||
Some(session) => {
|
||||
if !session.is_running() {
|
||||
return Err(NokhwaError::ReadFrameError(
|
||||
"Stream Not Started".to_string(),
|
||||
));
|
||||
}
|
||||
if session.is_interrupted() {
|
||||
return Err(NokhwaError::ReadFrameError(
|
||||
"Stream Interrupted".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(NokhwaError::ReadFrameError(
|
||||
"Stream Not Started".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
match &self.data_collect {
|
||||
Some(collector) => {
|
||||
let data = collector.frame_to_slice()?;
|
||||
let data = match data.1 {
|
||||
AVFourCC::YUV2 => Cow::from(yuyv422_to_rgb888(&data.0)?),
|
||||
AVFourCC::MJPEG => Cow::from(mjpeg_to_rgb888(&data.0)?),
|
||||
};
|
||||
Ok(data)
|
||||
}
|
||||
None => Err(NokhwaError::ReadFrameError(
|
||||
|
||||
+1
-1
@@ -372,7 +372,7 @@ impl From<CameraFormat> for CaptureDeviceFormatDescriptor {
|
||||
width: cf.width() as i32,
|
||||
height: cf.height() as i32,
|
||||
},
|
||||
fps: cf.frame_rate() as f64,
|
||||
fps: cf.frame_rate(),
|
||||
fourcc: cf.format().into(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user