Working AVFoundationn

This commit is contained in:
l1npengtul
2021-09-23 23:23:40 +09:00
parent 4db43f7197
commit 2bfbda2b93
19 changed files with 723 additions and 311 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
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 */;
}
@@ -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>
@@ -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 &amp;quot;nyokhwa exampwe c-captuwe app&amp;quot; and a &amp;quot;devewopew toow&amp;quot; &amp;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 &quot;nyokhwa exampwe c-captuwe app&quot; and a &quot;devewopew toow&quot; &lt;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()
@@ -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 */;
}
@@ -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>
+5 -2
View File
@@ -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!(
+2
View File
@@ -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"
+261 -187
View File
@@ -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) {
extern "C" fn my_callback_set_index(this: &mut Object, _: Sel, new_index: usize) {
unsafe {
this.set_ivar("_frame_data", ptr);
}
}
extern "C" fn my_callback_get_data_length(this: &Object, _: Sel) -> 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()));
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()
)))
}
println!("tp3");
if data_length == 0 {
return Err(AVFError::ReadFrame("Zero Size Len".to_string()));
},
};
Ok(data)
}
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_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,30 +804,21 @@ 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,
};
for fps in &other.fps_list {
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)
&& (*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
}
+34 -10
View File
@@ -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
View File
@@ -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(),
}
}