比较提交
24
次代码提交
13821366a5
..
main
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
42fecaa3b5 | ||
|
|
20896de9ee | ||
|
|
edf64ace6b | ||
|
|
75e7f4a00d | ||
|
|
524f536a53 | ||
|
|
79710f17b3 | ||
|
|
a0c5357efd | ||
|
|
623dcb878b | ||
|
|
b58fec1a86 | ||
|
|
8a70d38b7c | ||
|
|
767bba8ac1 | ||
|
|
47f6e55ecd | ||
|
|
d1137edd83 | ||
|
|
2faf7de779 | ||
|
|
e47736222d | ||
|
|
6a29d52a9a | ||
|
|
cd2e608ec6 | ||
|
|
b35b4a5d1c | ||
|
|
83ed140c2e | ||
|
|
7fa3298e02 | ||
|
|
58f09e5756 | ||
|
|
730d1755ca | ||
|
|
2f2c081980 | ||
|
|
2e79602761 |
没有与搜索条件相匹配的文件
+6
@@ -40,3 +40,9 @@ reference-binaries/
|
||||
|
||||
# Reviewed signed release installer (intentional distribution artifact)
|
||||
!releases/1.2.0/*.pkg
|
||||
|
||||
!releases/1.3.1/*.pkg
|
||||
|
||||
!releases/1.3.2/*.pkg
|
||||
|
||||
!releases/1.3.3/*.pkg
|
||||
+48
-48
@@ -8,7 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
6945FC8F3088B7220013E108 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC8E3088B7220013E108 /* Cocoa.framework */; };
|
||||
6945FC973088B7220013E108 /* beatygril XPC Service.pluginkit in Embed PlugIns */ = {isa = PBXBuildFile; fileRef = 6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
6945FC973088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit in Embed PlugIns */ = {isa = PBXBuildFile; fileRef = 6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
6945FC9B3088B7220013E108 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9A3088B7220013E108 /* Foundation.framework */; };
|
||||
6945FC9D3088B7220013E108 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9C3088B7220013E108 /* AppKit.framework */; };
|
||||
6945FC9F3088B7220013E108 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6945FC9E3088B7220013E108 /* Accelerate.framework */; };
|
||||
@@ -22,14 +22,14 @@
|
||||
containerPortal = 6945FC833088B7220013E108 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 6945FC953088B7220013E108;
|
||||
remoteInfo = "XPC Service";
|
||||
remoteInfo = "FCP-BeautyGirl XPC Service";
|
||||
};
|
||||
6945FCA43088B7220013E108 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6945FC833088B7220013E108 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 6945FC953088B7220013E108;
|
||||
remoteInfo = "XPC Service";
|
||||
remoteInfo = "FCP-BeautyGirl XPC Service";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
@@ -39,16 +39,16 @@
|
||||
dstPath = "";
|
||||
dstSubfolder = PlugIns;
|
||||
files = (
|
||||
6945FC973088B7220013E108 /* beatygril XPC Service.pluginkit in Embed PlugIns */,
|
||||
6945FC973088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit in Embed PlugIns */,
|
||||
);
|
||||
name = "Embed PlugIns";
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
6945FC8B3088B7220013E108 /* beatygril.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = beatygril.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6945FC8B3088B7220013E108 /* FCP-BeautyGirl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FCP-BeautyGirl.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6945FC8E3088B7220013E108 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "beatygril XPC Service.pluginkit"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "FCP-BeautyGirl XPC Service.pluginkit"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6945FC9A3088B7220013E108 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
6945FC9C3088B7220013E108 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
6945FC9E3088B7220013E108 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
|
||||
@@ -57,12 +57,12 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
6945FCCB3088B7220013E108 /* Exceptions for "beatygril" folder in "Wrapper Application" target */ = {
|
||||
6945FCCB3088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "Wrapper Application" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
"/Localized: Plugin/InfoPlist.strings",
|
||||
"/Localized: Plugin/Localizable.strings",
|
||||
Plugin/beatygrilPlugIn.m,
|
||||
Plugin/FCPBeautyGirlPlugIn.m,
|
||||
Plugin/Info.plist,
|
||||
Plugin/main.m,
|
||||
Plugin/PGBeautyRenderer.m,
|
||||
@@ -74,7 +74,7 @@
|
||||
);
|
||||
target = 6945FC8A3088B7220013E108 /* Wrapper Application */;
|
||||
};
|
||||
6945FCD33088B7220013E108 /* Exceptions for "beatygril" folder in "XPC Service" target */ = {
|
||||
6945FCD33088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "XPC Service" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
"/Localized: Wrapper Application/Credits.rtf",
|
||||
@@ -91,13 +91,13 @@
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
6945FCA63088B7220013E108 /* beatygril */ = {
|
||||
6945FCA63088B7220013E108 /* FCP-BeautyGirl */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
6945FCCB3088B7220013E108 /* Exceptions for "beatygril" folder in "Wrapper Application" target */,
|
||||
6945FCD33088B7220013E108 /* Exceptions for "beatygril" folder in "XPC Service" target */,
|
||||
6945FCCB3088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "Wrapper Application" target */,
|
||||
6945FCD33088B7220013E108 /* Exceptions for "FCP-BeautyGirl" folder in "XPC Service" target */,
|
||||
);
|
||||
path = beatygril;
|
||||
path = FCP-BeautyGirl;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
@@ -125,7 +125,7 @@
|
||||
6945FC823088B7220013E108 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6945FCA63088B7220013E108 /* beatygril */,
|
||||
6945FCA63088B7220013E108 /* FCP-BeautyGirl */,
|
||||
6945FC8D3088B7220013E108 /* Frameworks */,
|
||||
6945FC8C3088B7220013E108 /* Products */,
|
||||
);
|
||||
@@ -134,8 +134,8 @@
|
||||
6945FC8C3088B7220013E108 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6945FC8B3088B7220013E108 /* beatygril.app */,
|
||||
6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */,
|
||||
6945FC8B3088B7220013E108 /* FCP-BeautyGirl.app */,
|
||||
6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -172,11 +172,11 @@
|
||||
6945FCA53088B7220013E108 /* PBXTargetDependency */,
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
6945FCA63088B7220013E108 /* beatygril */,
|
||||
6945FCA63088B7220013E108 /* FCP-BeautyGirl */,
|
||||
);
|
||||
name = "Wrapper Application";
|
||||
productName = "Wrapper Application";
|
||||
productReference = 6945FC8B3088B7220013E108 /* beatygril.app */;
|
||||
name = "FCP-BeautyGirl";
|
||||
productName = "FCP-BeautyGirl";
|
||||
productReference = 6945FC8B3088B7220013E108 /* FCP-BeautyGirl.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
6945FC953088B7220013E108 /* XPC Service */ = {
|
||||
@@ -192,11 +192,11 @@
|
||||
buildRules = (
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
6945FCA63088B7220013E108 /* beatygril */,
|
||||
6945FCA63088B7220013E108 /* FCP-BeautyGirl */,
|
||||
);
|
||||
name = "XPC Service";
|
||||
productName = "XPC Service";
|
||||
productReference = 6945FC963088B7220013E108 /* beatygril XPC Service.pluginkit */;
|
||||
name = "FCP-BeautyGirl XPC Service";
|
||||
productName = "FCP-BeautyGirl XPC Service";
|
||||
productReference = 6945FC963088B7220013E108 /* FCP-BeautyGirl XPC Service.pluginkit */;
|
||||
productType = "com.apple.product-type.bundle";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
@@ -216,7 +216,7 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 6945FC863088B7220013E108 /* Build configuration list for PBXProject "beatygril" */;
|
||||
buildConfigurationList = 6945FC863088B7220013E108 /* Build configuration list for PBXProject "FCP-BeautyGirl" */;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
@@ -316,15 +316,15 @@
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
INFOPLIST_FILE = beatygril/Plugin/Info.plist;
|
||||
INFOPLIST_FILE = FCP-BeautyGirl/Plugin/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@loader_path/../Frameworks",
|
||||
);
|
||||
MACH_O_TYPE = mh_execute;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril.fxplug;
|
||||
PRODUCT_NAME = "beatygril $(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Plugin/XPC Service-Bridging-Header.h";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl.fxplug;
|
||||
PRODUCT_NAME = "FCP-BeautyGirl XPC Service";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Plugin/XPC Service-Bridging-Header.h";
|
||||
WRAPPER_EXTENSION = pluginkit;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -339,15 +339,15 @@
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
INFOPLIST_FILE = beatygril/Plugin/Info.plist;
|
||||
INFOPLIST_FILE = FCP-BeautyGirl/Plugin/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@loader_path/../Frameworks",
|
||||
);
|
||||
MACH_O_TYPE = mh_execute;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril.fxplug;
|
||||
PRODUCT_NAME = "beatygril $(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Plugin/XPC Service-Bridging-Header.h";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl.fxplug;
|
||||
PRODUCT_NAME = "FCP-BeautyGirl XPC Service";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Plugin/XPC Service-Bridging-Header.h";
|
||||
WRAPPER_EXTENSION = pluginkit;
|
||||
};
|
||||
name = Release;
|
||||
@@ -355,7 +355,7 @@
|
||||
6945FCD13088B7220013E108 /* Debug configuration for PBXNativeTarget "Wrapper Application" */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "beatygril/Wrapper Application/SandboxEntitlements.entitlements";
|
||||
CODE_SIGN_ENTITLEMENTS = "FCP-BeautyGirl/Wrapper Application/SandboxEntitlements.entitlements";
|
||||
OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, );
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
||||
@@ -363,17 +363,17 @@
|
||||
DEVELOPMENT_TEAM = B3W25FX5H5;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
INFOPLIST_FILE = "beatygril/Wrapper Application/Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril;
|
||||
PRODUCT_NAME = beatygril;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Wrapper Application/Wrapper Application-Bridging-Header.h";
|
||||
INFOPLIST_FILE = "FCP-BeautyGirl/Wrapper Application/Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl;
|
||||
PRODUCT_NAME = FCP-BeautyGirl;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Wrapper Application/Wrapper Application-Bridging-Header.h";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6945FCD23088B7220013E108 /* Release configuration for PBXNativeTarget "Wrapper Application" */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "beatygril/Wrapper Application/SandboxEntitlements.entitlements";
|
||||
CODE_SIGN_ENTITLEMENTS = "FCP-BeautyGirl/Wrapper Application/SandboxEntitlements.entitlements";
|
||||
OTHER_LDFLAGS = ("$(inherited)", "-framework", CoreServices, );
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
||||
@@ -381,14 +381,14 @@
|
||||
DEVELOPMENT_TEAM = B3W25FX5H5;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
INFOPLIST_FILE = "beatygril/Wrapper Application/Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.beatygril;
|
||||
PRODUCT_NAME = beatygril;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "beatygril/Wrapper Application/Wrapper Application-Bridging-Header.h";
|
||||
INFOPLIST_FILE = "FCP-BeautyGirl/Wrapper Application/Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dayu.fcpbeautygirl;
|
||||
PRODUCT_NAME = FCP-BeautyGirl;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "FCP-BeautyGirl/Wrapper Application/Wrapper Application-Bridging-Header.h";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
6945FCD43088B7220013E108 /* Debug configuration for PBXProject "beatygril" */ = {
|
||||
6945FCD43088B7220013E108 /* Debug configuration for PBXProject "FCP-BeautyGirl" */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk;
|
||||
@@ -461,7 +461,7 @@
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6945FCD53088B7220013E108 /* Release configuration for PBXProject "beatygril" */ = {
|
||||
6945FCD53088B7220013E108 /* Release configuration for PBXProject "FCP-BeautyGirl" */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ADDITIONAL_SDKS = /Library/Developer/SDKs/FxPlug.sdk;
|
||||
@@ -531,11 +531,11 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
6945FC863088B7220013E108 /* Build configuration list for PBXProject "beatygril" */ = {
|
||||
6945FC863088B7220013E108 /* Build configuration list for PBXProject "FCP-BeautyGirl" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
6945FCD43088B7220013E108 /* Debug configuration for PBXProject "beatygril" */,
|
||||
6945FCD53088B7220013E108 /* Release configuration for PBXProject "beatygril" */,
|
||||
6945FCD43088B7220013E108 /* Debug configuration for PBXProject "FCP-BeautyGirl" */,
|
||||
6945FCD53088B7220013E108 /* Release configuration for PBXProject "FCP-BeautyGirl" */,
|
||||
);
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
文件已重命名,内容未更改。
+1
-1
@@ -2,7 +2,7 @@
|
||||
#import <FxPlug/FxPlugSDK.h>
|
||||
#import "PGBeautyTypes.h"
|
||||
|
||||
@interface beatygrilPlugIn : NSObject <FxTileableEffect, FxAnalyzer, FxCustomParameterViewHost_v2>
|
||||
@interface FCPBeautyGirlPlugIn : NSObject <FxTileableEffect, FxAnalyzer, FxCustomParameterViewHost_v2>
|
||||
@property (nonatomic, assign) id<PROAPIAccessing> apiManager;
|
||||
- (PGBeautySettings)settingsAtTime:(CMTime)time;
|
||||
- (void)analyzeForward;
|
||||
+19
-8
@@ -1,4 +1,4 @@
|
||||
#import "beatygrilPlugIn.h"
|
||||
#import "FCPBeautyGirlPlugIn.h"
|
||||
#import "PGParameterIDs.h"
|
||||
#import "PGBeautyRenderer.h"
|
||||
#import "PGFaceProcessor.h"
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
static os_log_t PGRenderLog(void) {
|
||||
static os_log_t log; static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{ log=os_log_create("com.dayu.beatygril", "render"); });
|
||||
dispatch_once(&once, ^{ log=os_log_create("com.dayu.fcpbeautygirl", "render"); });
|
||||
return log;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ static const PGSlider PGSliders[] = {
|
||||
PGS(PGEyeBright,"眼睛提亮",eyeBrightening,0,1,.01,YES),
|
||||
PGS(PGHighPass,"高频细节平滑",highPassDetail,0,1,.01,YES),
|
||||
PGS(PGSharpness,"锐化",sharpness,0,1,.01,YES),
|
||||
PGS(PGFeatureProtectionAmount,"五官保护强度",featureProtectionAmount,0,1,.01,YES),
|
||||
PGS(PGNonSkinProtection,"非肤色区保护",nonSkinProtection,0,1,.01,YES),
|
||||
PGS(PGMicroDetail,"微细锐化",microDetail,0,1,.01,YES),
|
||||
PGS(PGThin,"瘦脸",faceThin,0,1,.01,YES),
|
||||
PGS(PGBigEye,"大眼",faceBigEye,0,1,.01,YES),
|
||||
PGS(PGShort,"短脸",faceShort,-1,1,.01,NO),
|
||||
@@ -81,7 +84,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
|
||||
return [image imageByApplyingTransform:CGAffineTransformMakeTranslation(b.left,b.bottom)];
|
||||
}
|
||||
|
||||
@interface beatygrilPlugIn ()
|
||||
@interface FCPBeautyGirlPlugIn ()
|
||||
@property (strong) PGBeautyRenderer *beautyRenderer;
|
||||
@property (strong) PGFaceProcessor *faceProcessor;
|
||||
@property (strong) PGFaceProcessor *analysisFaceProcessor;
|
||||
@@ -96,7 +99,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
|
||||
@property (strong) NSHashTable<PGInspectorView *> *inspectorViews;
|
||||
@end
|
||||
|
||||
@implementation beatygrilPlugIn
|
||||
@implementation FCPBeautyGirlPlugIn
|
||||
- (instancetype)initWithAPIManager:(id<PROAPIAccessing>)manager {
|
||||
if ((self=[super init])) {
|
||||
_apiManager=manager;
|
||||
@@ -141,6 +144,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
|
||||
void (^end)(void)=^{ok=[api endParameterSubGroup]&&ok;};
|
||||
group(@"磨皮",100); toggle(@"启用磨皮",PGSmoothingEnabled,YES);
|
||||
slider(PGAmount); slider(PGMidtone); slider(PGRadius); toggle(@"保护五官",PGFeatureProtect,YES); end();
|
||||
group(@"磨皮保护与细节",106); slider(PGFeatureProtectionAmount); slider(PGNonSkinProtection); slider(PGMicroDetail); end();
|
||||
group(@"肤色",101); toggle(@"启用肤色",PGColorEnabled,YES);
|
||||
ok=[api addPopupMenuWithName:@"肤色风格" parameterID:PGTonePreset defaultValue:0 menuEntries:@[@"原色",@"自然白",@"冷白",@"暖白",@"红润白",@"小麦",@"古铜"] parameterFlags:kFxParameterFlag_HIDDEN]&&ok;
|
||||
slider(PGBrightness); slider(PGHue); slider(PGSaturation); slider(PGEvenTone); slider(PGTeeth); slider(PGEyeBright); end();
|
||||
@@ -207,7 +211,7 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
|
||||
double x=.5,y=.5; [api getXValue:&x YValue:&y fromParameter:PGSelection atTime:time];
|
||||
s.selectionX=isfinite(x)?fmin(1,fmax(0,x)):.5; s.selectionY=isfinite(y)?fmin(1,fmax(0,y)):.5;
|
||||
BOOL enabled=YES;
|
||||
[api getBoolValue:&enabled fromParameter:PGSmoothingEnabled atTime:time]; if(!enabled) s.amount=s.midtoneDetail=0;
|
||||
[api getBoolValue:&enabled fromParameter:PGSmoothingEnabled atTime:time]; if(!enabled) s.amount=s.midtoneDetail=s.microDetail=0;
|
||||
enabled=YES; [api getBoolValue:&enabled fromParameter:PGColorEnabled atTime:time];
|
||||
if(!enabled) {s.skinBrightness=s.skinHue=s.skinSaturation=s.skinEvenTone=s.teethWhitening=s.eyeBrightening=0;s.skinTonePreset=0;}
|
||||
enabled=YES; [api getBoolValue:&enabled fromParameter:PGDetailEnabled atTime:time]; if(!enabled) s.highPassDetail=s.sharpness=0;
|
||||
@@ -263,9 +267,16 @@ static CIImage *PGImageFromTile(FxImageTile *tile) {
|
||||
- (BOOL)renderDestinationImage:(FxImageTile *)destination sourceImages:(NSArray<FxImageTile *> *)sources pluginState:(NSData *)state atTime:(CMTime)time error:(NSError **)error {
|
||||
if(sources.count==0||!sources.firstObject.ioSurface||!destination.ioSurface||![state isKindOfClass:NSData.class]||state.length==0||state.length>320*1024*1024) return PGFail(error,@"宿主传入的画面或状态无效。");
|
||||
NSDictionary *plist=[NSPropertyListSerialization propertyListWithData:state options:NSPropertyListImmutable format:nil error:error];
|
||||
if(![plist isKindOfClass:NSDictionary.class]||![plist[@"settings"] isKindOfClass:NSData.class]||[plist[@"settings"] length]!=sizeof(PGBeautySettings)) return PGFail(error,@"渲染状态版本无效。");
|
||||
PGBeautySettings s;[plist[@"settings"] getBytes:&s length:sizeof(s)];
|
||||
if(s.version!=1) return PGFail(error,@"此版本不支持保存的渲染状态。");
|
||||
if(![plist isKindOfClass:NSDictionary.class]||![plist[@"settings"] isKindOfClass:NSData.class]) return PGFail(error,@"渲染状态版本无效。");
|
||||
NSData *encoded=plist[@"settings"]; uint32_t version=0;
|
||||
if(encoded.length<sizeof(version)) return PGFail(error,@"渲染状态版本无效。");
|
||||
[encoded getBytes:&version length:sizeof(version)];
|
||||
PGBeautySettings s=PGBeautyDefaults();
|
||||
if(version==1 && encoded.length==PGBeautySettingsV1Size) {
|
||||
[encoded getBytes:&s length:PGBeautySettingsV1Size];s.version=PGBeautySettingsVersion;
|
||||
} else if(version==PGBeautySettingsVersion && encoded.length==sizeof(s)) {
|
||||
[encoded getBytes:&s length:sizeof(s)];
|
||||
} else return PGFail(error,@"此版本不支持保存的渲染状态。");
|
||||
s.trackingEnabled=0;s.singleFace=0;
|
||||
CIImage *input=PGImageFromTile(sources.firstObject); if(!input) return PGFail(error,@"无法读取 IOSurface。");
|
||||
@synchronized(self) {
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.0</string>
|
||||
<string>1.3.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>14</string>
|
||||
<string>18</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string></string>
|
||||
<key>PlugInKit</key>
|
||||
@@ -57,7 +57,7 @@
|
||||
<array>
|
||||
<dict>
|
||||
<key>className</key>
|
||||
<string>beatygrilPlugIn</string>
|
||||
<string>FCPBeautyGirlPlugIn</string>
|
||||
<key>displayName</key>
|
||||
<string>大鱼人像美化</string>
|
||||
<key>group</key>
|
||||
@@ -72,7 +72,7 @@
|
||||
<key>uuid</key>
|
||||
<string>FB14B0E6-59B2-4836-916F-CD0C559E9241</string>
|
||||
<key>version</key>
|
||||
<string>1.2.0</string>
|
||||
<string>1.3.3</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>className</key>
|
||||
@@ -84,7 +84,7 @@
|
||||
<key>uuid</key>
|
||||
<string>E0E432C8-3D71-4ABA-B006-E7F519E06C87</string>
|
||||
<key>version</key>
|
||||
<string>1.2.0</string>
|
||||
<string>1.3.3</string>
|
||||
<key>protocolNames</key>
|
||||
<array>
|
||||
<string>FxOnScreenControl</string>
|
||||
文件已重命名,内容未更改。
+48
-4
@@ -82,6 +82,26 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
|
||||
"kernel vec4 pgMaskedMix(__sample source,__sample effect,__sample mask,float amount) {"
|
||||
"vec4 s=unpremultiply(source); vec4 e=unpremultiply(effect);"
|
||||
"return premultiply(vec4(mix(s.rgb,e.rgb,clamp(mask.r*amount,0.0,1.0)),s.a)); }");
|
||||
// Keep smoothing support separate from the exposure/color mask. The
|
||||
// two new controls independently release feature cutouts and background.
|
||||
k[@"smoothingSupport"] = PGKernel(@
|
||||
"kernel vec4 pgSmoothingSupport(__sample protectedMask,__sample baseMask,float featureProtection,float skinProtection) {"
|
||||
"float base=clamp(baseMask.r,0.0,1.0);float protectedValue=clamp(protectedMask.r,0.0,1.0);"
|
||||
"float value=mix(base,protectedValue,featureProtection);"
|
||||
"if(skinProtection<1.0){float extended=1.0-skinProtection*(1.0-base);"
|
||||
"float retention=base>0.00001?clamp(protectedValue/base,0.0,1.0):1.0;"
|
||||
"value=extended*mix(1.0,retention,featureProtection);}"
|
||||
"return vec4(value,value,value,1.0); }");
|
||||
k[@"microDetail"] = PGKernel(@
|
||||
"kernel vec4 pgMicroDetail(__sample processed,__sample original,__sample low,__sample coverage,float amount) {"
|
||||
"vec4 outPixel=unpremultiply(processed);vec3 src=unpremultiply(original).rgb;"
|
||||
"vec3 high=src-unpremultiply(low).rgb;vec3 weights=vec3(0.299,0.587,0.114);"
|
||||
"float y=dot(src,weights);float detailY=dot(high,weights);float size=length(high);"
|
||||
"float lightGate=smoothstep(0.07,0.22,y)*(1.0-smoothstep(0.86,0.99,y));"
|
||||
"float textureGate=smoothstep(0.0015,0.010,size)*(1.0-smoothstep(0.16,0.36,size));"
|
||||
"float gain=amount*clamp(coverage.r,0.0,1.0)*lightGate*textureGate*1.18;"
|
||||
"vec3 detail=vec3(detailY*0.92)+(high-vec3(detailY))*0.28;"
|
||||
"return premultiply(vec4(clamp(outPixel.rgb+detail*gain,0.0,1.0),outPixel.a)); }");
|
||||
k[@"colorCoverage"] = PGKernel(@
|
||||
"kernel vec4 pgColorCoverage(__sample coverage,__sample image,float invert) {"
|
||||
"vec3 c=unpremultiply(image).rgb; float y=dot(c,vec3(0.299,0.587,0.114));"
|
||||
@@ -157,7 +177,7 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
|
||||
float mix = PGClamp(s.mix, 0, 1);
|
||||
if (mix == 0 && !s.showMask) return image;
|
||||
NSDictionary *k = PGKernels();
|
||||
if (k.count != 11) {
|
||||
if (k.count != 13) {
|
||||
if (error) *error = [NSError errorWithDomain:@"PGBeautyRenderer" code:2
|
||||
userInfo:@{NSLocalizedDescriptionKey:@"The beauty image kernels could not be compiled."}];
|
||||
return nil;
|
||||
@@ -173,7 +193,10 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
|
||||
float sharpness = PGClamp(s.sharpness,0,2);
|
||||
float teeth = PGClamp(s.teethWhitening,0,1);
|
||||
float eyes = PGClamp(s.eyeBrightening,0,1);
|
||||
BOOL needsSkin = local*amount>0 || brightness>0 || hue!=0 || saturation!=0 || even>0 ||
|
||||
float protection = s.featureProtection ? PGClamp(s.featureProtectionAmount,0,1) : 0;
|
||||
float skinProtection = PGClamp(s.nonSkinProtection,0,1);
|
||||
float micro = PGClamp(s.microDetail,0,1)*amount;
|
||||
BOOL needsSkin = local*amount>0 || micro>0 || brightness>0 || hue!=0 || saturation!=0 || even>0 ||
|
||||
(s.skinTonePreset>0 && s.skinTonePreset<=6) || (s.showMask && s.debugChannel==0);
|
||||
CIImage *black = [[CIImage imageWithColor:[CIColor colorWithRed:0 green:0 blue:0 alpha:1]] imageByCroppingToRect:extent];
|
||||
CIImage *teethInput = teethMask ? [teethMask imageByCroppingToRect:extent] : black;
|
||||
@@ -200,12 +223,29 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
|
||||
float invert = s.debugChannel==1 || s.debugChannel==2 ? (s.invertMask ? 1 : 0) : 0;
|
||||
return PGApply(k[@"debug"],extent,@[image,preview,@(invert)]);
|
||||
}
|
||||
CIImage *smoothingMask=mask;
|
||||
if((local*amount>0 || micro>0) && (protection<1 || skinProtection<1)) {
|
||||
CIImage *baseRaw=colorMask ? [colorMask imageByCroppingToRect:extent] : raw;
|
||||
float soft=PGClamp(s.maskSoftness,0,1);
|
||||
CIImage *baseMask=PGApply(k[@"mask"],extent,@[baseRaw,PGBlur(baseRaw,0.35+soft*radius*0.35,extent),
|
||||
image,PGBlur(image,1.5,extent),eyeInput,teethInput,
|
||||
@(PGClamp(s.maskThreshold,0,255)/255.f),@(soft),@(PGClamp(s.maskEdgeProtect,0,1)),@0,@(s.invertMask?1:0)]);
|
||||
smoothingMask=PGApply(k[@"smoothingSupport"],extent,@[mask,baseMask,@(protection),@(skinProtection)]);
|
||||
}
|
||||
// Detail protection may contain small eye, brow, nose and lip cutouts.
|
||||
// Exposure and color must not reuse those holes or sharpen a face ellipse
|
||||
// with the detail threshold; that creates visible rings and islands.
|
||||
CIImage *toneMask=mask;
|
||||
BOOL changesColor=brightness>0 || hue!=0 || saturation!=0 || even>0 ||
|
||||
(s.skinTonePreset>0 && s.skinTonePreset<=6);
|
||||
if(!colorMask && changesColor && s.featureProtection) {
|
||||
// Standalone callers may not supply the separate uncut coverage.
|
||||
// At least keep our eye/teeth cutouts out of their color adjustment.
|
||||
float soft=PGClamp(s.maskSoftness,0,1);
|
||||
toneMask=PGApply(k[@"mask"],extent,@[raw,PGBlur(raw,0.35+soft*radius*0.35,extent),
|
||||
image,PGBlur(image,1.5,extent),eyeInput,teethInput,
|
||||
@(PGClamp(s.maskThreshold,0,255)/255.f),@(soft),@(PGClamp(s.maskEdgeProtect,0,1)),@0,@(s.invertMask?1:0)]);
|
||||
}
|
||||
if(colorMask && changesColor) {
|
||||
CGFloat feather=MAX(3,MIN(extent.size.width,extent.size.height)*0.03);
|
||||
CIImage *support=[colorMask imageByCroppingToRect:extent];
|
||||
@@ -219,8 +259,12 @@ static NSDictionary<NSString *, CIColorKernel *> *PGKernels(void) {
|
||||
CGFloat broad = fmin(16,(2.55+0.45*local)*fine+1.1+1.3*local);
|
||||
float compression = 0.12+2.4*powf(local,2.15)+1.25*local;
|
||||
CIImage *detail = PGApply(k[@"detail"],extent,@[result,PGBlur(result,fine,extent),
|
||||
PGBlur(result,broad,extent),@(compression),@(s.featureProtection ? 1 : 0)]);
|
||||
result = PGApply(k[@"maskedMix"],extent,@[result,detail,mask,@(amount)]);
|
||||
PGBlur(result,broad,extent),@(compression),@(protection)]);
|
||||
result = PGApply(k[@"maskedMix"],extent,@[result,detail,smoothingMask,@(amount)]);
|
||||
}
|
||||
if(micro>0) {
|
||||
CGFloat fine=fmin(7.4,2.275+3.15*pow(local,0.72)+0.95*local);
|
||||
result=PGApply(k[@"microDetail"],extent,@[result,image,PGBlur(image,fine,extent),smoothingMask,@(micro)]);
|
||||
}
|
||||
CIImage *color = result;
|
||||
if (brightness>0) {
|
||||
+11
-1
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <math.h>
|
||||
|
||||
// Persisted FxPlug render state. Append fields and bump version for migrations.
|
||||
typedef struct {
|
||||
@@ -12,11 +14,17 @@ typedef struct {
|
||||
float faceJumpGuardRange, selectionX, selectionY;
|
||||
uint32_t featureProtection, skinTonePreset, showMask, invertMask, debugChannel;
|
||||
uint32_t showFaceBoxes, showTrackBox, singleFace, fastMultiFace, trackingEnabled, targetIndex;
|
||||
// v2 keeps the entire 160-byte v1 prefix, including legacy bool/strength IDs.
|
||||
float featureProtectionAmount, nonSkinProtection, microDetail;
|
||||
} PGBeautySettings;
|
||||
|
||||
enum { PGBeautySettingsV1Size = 160, PGBeautySettingsVersion = 2 };
|
||||
_Static_assert(offsetof(PGBeautySettings,featureProtectionAmount)==PGBeautySettingsV1Size,
|
||||
"The v1 render-state prefix must remain stable");
|
||||
|
||||
static inline PGBeautySettings PGBeautyDefaults(void) {
|
||||
PGBeautySettings s = {0};
|
||||
s.version = 1;
|
||||
s.version = PGBeautySettingsVersion;
|
||||
s.amount = 1.0f;
|
||||
s.radius = 8.0f;
|
||||
s.mix = 1.0f;
|
||||
@@ -24,6 +32,8 @@ static inline PGBeautySettings PGBeautyDefaults(void) {
|
||||
s.maskSoftness = 0.6f;
|
||||
s.maskEdgeProtect = 0.4f;
|
||||
s.featureProtection = 1;
|
||||
s.featureProtectionAmount = 1;
|
||||
s.nonSkinProtection = 1;
|
||||
s.faceJumpGuardRange = 1.8f;
|
||||
s.selectionX = s.selectionY = 0.5f;
|
||||
return s;
|
||||
文件已重命名,内容未更改。
+356
-161
@@ -5,7 +5,7 @@
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
static NSString * const PGFaceErrorDomain = @"media.dayu.PaintFCP.Face";
|
||||
static NSString * const PGFaceErrorDomain = @"com.dayu.fcpbeautygirl.face";
|
||||
// Contour origin / internal anchor, in the reference's recovered pin order.
|
||||
// The unused middle entry of each reference triplet is intentionally omitted.
|
||||
static const uint8_t PGThinPins[17][2] = {
|
||||
@@ -14,6 +14,8 @@ static const uint8_t PGThinPins[17][2] = {
|
||||
{69,49},{65,49},{68,52},{66,52},{67,47}
|
||||
};
|
||||
static const uint8_t PGChinPins[3][2] = {{68,38},{67,37},{66,36}};
|
||||
// Lower contour to lip anchors, in the 2.4.0 V-face shader's update order.
|
||||
static const uint8_t PGVFacePins[4][2] = {{69,39},{65,35},{70,26},{64,34}};
|
||||
// Origin and radius neighbour; all six directions point toward landmark 29.
|
||||
static const uint8_t PGJawPins[6][2] = {{72,71},{62,63},{71,70},{63,64},{70,71},{64,63}};
|
||||
|
||||
@@ -88,7 +90,7 @@ static NSArray *PGSanitizedPoints76(id value) {
|
||||
return [points copy];
|
||||
}
|
||||
static NSArray *PGFullPoints76(VNFaceLandmarkRegion2D *region, CGRect box) {
|
||||
if (region.pointCount != 76 || !region.normalizedPoints) return nil;
|
||||
if (region.pointCount < 76 || !region.normalizedPoints) return nil;
|
||||
const CGPoint *raw = region.normalizedPoints;
|
||||
NSMutableArray *points = [NSMutableArray arrayWithCapacity:76];
|
||||
for (NSUInteger i=0; i<76; i++) {
|
||||
@@ -108,6 +110,7 @@ static NSDictionary *PGGeometry(VNFaceObservation *observation) {
|
||||
@"mouth": PGRegion(lm.innerLips, box), @"contour": PGRegion(lm.faceContour, box)} mutableCopy];
|
||||
NSArray *points = PGFullPoints76(lm.allPoints, box);
|
||||
if (points) geometry[@"points76"] = points;
|
||||
geometry[@"landmarkConfidence"] = @(lm ? lm.confidence : 0);
|
||||
return [geometry copy];
|
||||
}
|
||||
static NSDictionary *PGSanitizedGeometry(id value) {
|
||||
@@ -131,6 +134,7 @@ static NSDictionary *PGSanitizedGeometry(id value) {
|
||||
// thin/chin/jaw/short fields without discarding otherwise usable old records.
|
||||
NSArray *points76 = PGSanitizedPoints76(value[@"points76"]);
|
||||
if (points76) result[@"points76"] = points76;
|
||||
if ([value[@"landmarkConfidence"] isKindOfClass:NSNumber.class]) result[@"landmarkConfidence"] = value[@"landmarkConfidence"];
|
||||
return [result copy];
|
||||
}
|
||||
static CGRect PGRegionBounds(NSDictionary *geometry, NSString *name, CGRect fallback) {
|
||||
@@ -176,154 +180,270 @@ static CGPoint PGRemapPoint(NSArray *point, CGRect old, CGRect current) {
|
||||
return CGPointMake(current.origin.x+([point[0] doubleValue]-old.origin.x)*current.size.width/old.size.width,
|
||||
current.origin.y+([point[1] doubleValue]-old.origin.y)*current.size.height/old.size.height);
|
||||
}
|
||||
static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previous, double dt, BOOL stabilizePoints76) {
|
||||
CGRect old=PGArrayRect(previous[@"box"]),box=PGArrayRect(current[@"box"]);
|
||||
if(!PGValidRect(old) || !PGValidRect(box))return current;
|
||||
// Independent stabilization: translate/scale old landmarks into the current
|
||||
// detection box first, so normal head motion does not accumulate box lag.
|
||||
double weight=.9*fmin(1,fmax(0,dt/.03));
|
||||
CGPoint oldLE=PGCenter(PGRegionBounds(previous,@"leftEye",PGInFace(old,.16,.53,.25,.15)));
|
||||
CGPoint oldRE=PGCenter(PGRegionBounds(previous,@"rightEye",PGInFace(old,.59,.53,.25,.15)));
|
||||
CGPoint newLE=PGCenter(PGRegionBounds(current,@"leftEye",PGInFace(box,.16,.53,.25,.15)));
|
||||
CGPoint newRE=PGCenter(PGRegionBounds(current,@"rightEye",PGInFace(box,.59,.53,.25,.15)));
|
||||
double ox=oldRE.x-oldLE.x,oy=oldRE.y-oldLE.y,nx=newRE.x-newLE.x,ny=newRE.y-newLE.y;
|
||||
double oldLength=hypot(ox,oy),newLength=hypot(nx,ny);
|
||||
BOOL axisHold=oldLength>MAX(.003,.055*MIN(old.size.height,box.size.height)) &&
|
||||
newLength>MAX(.003,.055*MIN(old.size.height,box.size.height)) &&
|
||||
(ox*nx+oy*ny)/(oldLength*newLength)<-.18;
|
||||
NSMutableDictionary *stable=[NSMutableDictionary dictionaryWithObject:current[@"box"] forKey:@"box"];
|
||||
for(NSString *name in PGGeometryRegions()) {
|
||||
NSArray *a=previous[name],*b=current[name];
|
||||
if(!a.count || (!axisHold && a.count!=b.count)) {stable[name]=b;continue;}
|
||||
NSMutableArray *points=[NSMutableArray arrayWithCapacity:a.count];
|
||||
for(NSUInteger i=0;i<a.count;i++) {
|
||||
CGPoint p=PGRemapPoint(a[i],old,box);
|
||||
if(!axisHold) {p.x+=( [b[i][0] doubleValue]-p.x)*weight;p.y+=([b[i][1] doubleValue]-p.y)*weight;}
|
||||
[points addObject:@[@(p.x),@(p.y)]];
|
||||
}
|
||||
stable[name]=[points copy];
|
||||
// 2.4.0's default pin path accepts good points without a temporal blend.
|
||||
// Geometry remains in our existing bottom-left coordinate convention; distances,
|
||||
// dot products and the two-axis sign test are invariant to the reference's Y flip.
|
||||
static CGPoint PGPoint(NSArray *p) { return CGPointMake([p[0] doubleValue], [p[1] doubleValue]); }
|
||||
static CGPoint PGMeanPoints(NSArray *points, NSUInteger first, NSUInteger count) {
|
||||
if (!count || first+count>points.count) return CGPointMake(NAN,NAN);
|
||||
CGPoint sum=CGPointZero;
|
||||
for(NSUInteger i=first;i<first+count;i++) {CGPoint p=PGPoint(points[i]);sum.x+=p.x;sum.y+=p.y;}
|
||||
return CGPointMake(sum.x/count,sum.y/count);
|
||||
}
|
||||
static CGPoint PGLocalPoint(CGPoint p,CGRect box) {
|
||||
return CGPointMake((p.x-box.origin.x)/box.size.width,(p.y-box.origin.y)/box.size.height);
|
||||
}
|
||||
static NSString *PGGeometryQualityReason(NSDictionary *g) {
|
||||
CGRect box=PGArrayRect(g[@"box"]);NSArray *points=PGSanitizedPoints76(g[@"points76"]),*contour=g[@"contour"];
|
||||
if(!PGValidRect(box)||points.count!=76)return @"incomplete76";
|
||||
if(contour.count<=10)return @"contour";
|
||||
double confidence=g[@"landmarkConfidence"]?[g[@"landmarkConfidence"] doubleValue]:1;
|
||||
if(!isfinite(confidence)||confidence<.55)return @"confidence";
|
||||
for(NSArray *point in points) {
|
||||
CGPoint p=PGLocalPoint(PGPoint(point),box);
|
||||
if(!isfinite(p.x)||!isfinite(p.y)||p.x<-.35||p.x>1.35||p.y<-.35||p.y>1.35)return @"localBounds";
|
||||
}
|
||||
NSArray *current76 = PGSanitizedPoints76(current[@"points76"]);
|
||||
NSArray *previous76 = PGSanitizedPoints76(previous[@"points76"]);
|
||||
if (current76) {
|
||||
if (stabilizePoints76 && previous76) {
|
||||
NSMutableArray *points = [NSMutableArray arrayWithCapacity:76];
|
||||
for (NSUInteger i=0; i<76; i++) {
|
||||
CGPoint p = PGRemapPoint(previous76[i], old, box);
|
||||
if (!axisHold) {
|
||||
p.x += ([current76[i][0] doubleValue]-p.x)*weight;
|
||||
p.y += ([current76[i][1] doubleValue]-p.y)*weight;
|
||||
}
|
||||
[points addObject:@[@(p.x),@(p.y)]];
|
||||
}
|
||||
stable[@"points76"] = [points copy];
|
||||
} else {
|
||||
// Reacquired detections and changes from/to incomplete topology do
|
||||
// not borrow a held face's old projected pose or invent missing points.
|
||||
stable[@"points76"] = current76;
|
||||
}
|
||||
CGPoint centers[5];NSArray *names=@[@"leftEye",@"rightEye",@"nose",@"lips"];
|
||||
for(NSUInteger i=0;i<4;i++) {
|
||||
NSArray *region=g[names[i]];if(!region.count)return @"missingRegion";
|
||||
centers[i]=PGLocalPoint(PGMeanPoints(region,0,region.count),box);
|
||||
if(!isfinite(centers[i].x)||!isfinite(centers[i].y))return @"regionBounds";
|
||||
}
|
||||
return [stable copy];
|
||||
centers[4]=PGLocalPoint(PGMeanPoints(contour,contour.count/2-1,3),box);
|
||||
CGPoint left=centers[0],right=centers[1],nose=centers[2],mouth=centers[3],chin=centers[4];
|
||||
double dx=right.x-left.x,dy=right.y-left.y,length=hypot(dx,dy);
|
||||
if(!isfinite(length)||length<.1)return @"eyeDistance";
|
||||
dx/=length;dy/=length;
|
||||
CGPoint eye=CGPointMake((left.x+right.x)*.5,(left.y+right.y)*.5);
|
||||
double vx=-dy,vy=dx;
|
||||
if(vx*(mouth.x-eye.x)+vy*(mouth.y-eye.y)<0){vx=-vx;vy=-vy;}
|
||||
double mouthProjection=vx*(mouth.x-eye.x)+vy*(mouth.y-eye.y);
|
||||
double noseProjection=vx*(nose.x-eye.x)+vy*(nose.y-eye.y);
|
||||
double chinProjection=vx*(chin.x-eye.x)+vy*(chin.y-eye.y);
|
||||
double lateral=dx*(chin.x-eye.x)+dy*(chin.y-eye.y);
|
||||
if(!isfinite(chinProjection)||mouthProjection<.08||chinProjection-mouthProjection<.06||chinProjection<.2)return @"anatomy";
|
||||
if(noseProjection<-.12||noseProjection>mouthProjection+.16||fabs(lateral)>length*.5+.3)return @"anatomy";
|
||||
return @"";
|
||||
}
|
||||
static double PGBoxIoU(CGRect a,CGRect b) {
|
||||
CGRect intersection=CGRectIntersection(a,b);double area=CGRectIsNull(intersection)?0:intersection.size.width*intersection.size.height;
|
||||
double total=a.size.width*a.size.height+b.size.width*b.size.height-area;return total>0?area/total:0;
|
||||
}
|
||||
static BOOL PGCompatibleBoxes(CGRect a,CGRect b) {
|
||||
if(!PGValidRect(a)||!PGValidRect(b))return NO;
|
||||
CGPoint x=PGCenter(a),y=PGCenter(b);
|
||||
return hypot(x.x-y.x,x.y-y.y)<=MAX(.04,.82*MAX(b.size.width,b.size.height))||PGBoxIoU(a,b)>=.08;
|
||||
}
|
||||
static CGPoint PGChinAxis(NSDictionary *g) {
|
||||
NSArray *p=g[@"points76"];if(p.count!=76)return CGPointMake(NAN,NAN);
|
||||
CGPoint a=PGPoint(p[66]),b=PGPoint(p[67]),c=PGPoint(p[68]),center=PGCenter(PGArrayRect(g[@"box"]));
|
||||
return CGPointMake((a.x+1.65*b.x+c.x)/3.65-center.x,(a.y+1.65*b.y+c.y)/3.65-center.y);
|
||||
}
|
||||
static BOOL PGGeometryAxisFlip(NSDictionary *current,NSDictionary *previous) {
|
||||
CGRect a=PGArrayRect(current[@"box"]),b=PGArrayRect(previous[@"box"]);
|
||||
if(!PGCompatibleBoxes(a,b))return NO;
|
||||
CGPoint x=PGChinAxis(current),y=PGChinAxis(previous);double lx=hypot(x.x,x.y),ly=hypot(y.x,y.y);
|
||||
double threshold=MAX(.003,.055*MIN(a.size.height,b.size.height));
|
||||
if(!isfinite(lx)||!isfinite(ly)||lx<.0008||ly<.0008||lx<threshold||ly<threshold)return NO;
|
||||
if(x.y*y.y>=0||fabs(x.y)<.35*threshold||fabs(y.y)<.35*threshold)return NO;
|
||||
double cosine=fmax(-1,fmin(1,(x.x*y.x+x.y*y.y)/(lx*ly)));
|
||||
return cosine<=-.18||fabs(x.y-y.y)>=threshold;
|
||||
}
|
||||
static NSDictionary *PGRemappedGeometry(NSDictionary *previous,CGRect box) {
|
||||
CGRect old=PGArrayRect(previous[@"box"]);if(!PGValidRect(old)||!PGValidRect(box))return previous;
|
||||
NSMutableDictionary *result=[previous mutableCopy];result[@"box"]=PGRectArray(box);
|
||||
NSMutableArray *names=[PGGeometryRegions() mutableCopy];[names addObject:@"points76"];
|
||||
for(NSString *name in names) {
|
||||
NSMutableArray *points=[NSMutableArray new];
|
||||
for(NSArray *point in previous[name]) {CGPoint p=PGRemapPoint(point,old,box);[points addObject:@[@(p.x),@(p.y)]];}
|
||||
if(points.count)result[name]=points;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Reference hold validation uses the 76 points plus the box center. Keep our
|
||||
// persisted topology at 76 and reconstruct the center rather than changing archives.
|
||||
static BOOL PGValidHeldGeometry(NSDictionary *g) {
|
||||
CGRect box=PGArrayRect(g[@"box"]);NSArray *p=PGSanitizedPoints76(g[@"points76"]);
|
||||
if(!PGValidRect(box)||p.count!=76)return NO;
|
||||
CGRect expanded=CGRectInset(box,-.4*box.size.width,-.4*box.size.height);
|
||||
double minX=CGRectGetMidX(box),maxX=minX,minY=CGRectGetMidY(box),maxY=minY;
|
||||
double contourMinX=DBL_MAX,contourMaxX=-DBL_MAX,contourMinY=DBL_MAX,contourMaxY=-DBL_MAX,left=0,mid=0,right=0;
|
||||
for(NSUInteger i=0;i<76;i++) {
|
||||
CGPoint point=PGPoint(p[i]);
|
||||
if(point.x<-.25||point.x>1.25||point.y<-.25||point.y>1.25)return NO;
|
||||
minX=MIN(minX,point.x);maxX=MAX(maxX,point.x);minY=MIN(minY,point.y);maxY=MAX(maxY,point.y);
|
||||
if(i<59)continue;
|
||||
if(!CGRectContainsPoint(expanded,point))return NO;
|
||||
contourMinX=MIN(contourMinX,point.x);contourMaxX=MAX(contourMaxX,point.x);
|
||||
contourMinY=MIN(contourMinY,point.y);contourMaxY=MAX(contourMaxY,point.y);
|
||||
if(i<66)left+=point.x;else if(i<=68)mid+=point.x;else right+=point.x;
|
||||
}
|
||||
double w=box.size.width,h=box.size.height,cw=contourMaxX-contourMinX,ch=contourMaxY-contourMinY;
|
||||
left/=7;mid/=3;right/=7;
|
||||
return maxX-minX>=.25*w&&maxY-minY>=.25*h&&cw>=.2*w&&ch>=.04*h&&cw<=1.85*w&&ch<=1.85*h&&
|
||||
fabs(right-left)>=.12*w&&mid>=MIN(left,right)-.35*w&&mid<=MAX(left,right)+.35*w;
|
||||
}
|
||||
static NSString *PGGeometryTransitionReason(NSDictionary *current,NSDictionary *previous) {
|
||||
CGRect box=PGArrayRect(current[@"box"]),old=PGArrayRect(previous[@"box"]);
|
||||
if(!PGCompatibleBoxes(box,old))return @"";
|
||||
if(PGGeometryAxisFlip(current,previous))return @"axisFlip";
|
||||
NSArray *a=current[@"points76"],*b=previous[@"points76"];
|
||||
if(a.count!=76||b.count!=76)return @"";
|
||||
NSMutableArray *distances=[NSMutableArray new];double scale=MAX(box.size.width,box.size.height);
|
||||
for(NSUInteger i=0;i<76;i++) {
|
||||
CGPoint p=PGRemapPoint(b[i],old,box),q=PGPoint(a[i]);
|
||||
[distances addObject:@(hypot(p.x-q.x,p.y-q.y)/scale)];
|
||||
}
|
||||
[distances sortUsingSelector:@selector(compare:)];
|
||||
return [distances[38] doubleValue]>.30||[distances[67] doubleValue]>.58?@"pointJump":@"";
|
||||
}
|
||||
static CIImage *PGPreparedVisionImage(CIImage *image,CGFloat limit) {
|
||||
CGRect e=image.extent;
|
||||
CIImage *prepared=[image imageByApplyingTransform:CGAffineTransformMakeTranslation(-e.origin.x,-e.origin.y)];
|
||||
CGFloat scale=MIN(1,limit/MAX(e.size.width,e.size.height));
|
||||
if(scale<1)prepared=[prepared imageByApplyingTransform:CGAffineTransformMakeScale(scale,scale)];
|
||||
return [prepared imageByCroppingToRect:CGRectMake(0,0,MAX(1,floor(e.size.width*scale)),MAX(1,floor(e.size.height*scale)))];
|
||||
}
|
||||
|
||||
// This live selector is deliberately independent of _targets. Its past-only
|
||||
// .35s reference window is a documented project policy, not a recovered exact
|
||||
// vendor formula. Continuous held outputs advance time, so this is not a hold
|
||||
// timeout. Locks protect state, not global render-order equivalence: a cold seek
|
||||
// cannot reconstruct frames the host has never supplied.
|
||||
@interface PGRealtimeFaceTracker : NSObject {
|
||||
NSLock *_mutex;
|
||||
NSMutableArray<NSDictionary *> *_entries;
|
||||
NSUInteger _estimatedBytes;
|
||||
NSDictionary *_liveReference;
|
||||
VNSequenceRequestHandler *_sequence;
|
||||
VNTrackObjectRequest *_objectRequest;
|
||||
CGRect _objectBox;
|
||||
CMTime _objectTime;
|
||||
BOOL _objectValid;
|
||||
}
|
||||
- (NSDictionary *)resultForGeometry:(NSArray<NSDictionary *> *)raw settings:(PGBeautySettings)settings time:(CMTime)time extent:(CGRect)extent;
|
||||
- (NSDictionary *)resultForGeometry:(NSArray<NSDictionary *> *)raw settings:(PGBeautySettings)settings time:(CMTime)time extent:(CGRect)extent image:(CIImage *)image;
|
||||
- (CGRect)trackedBoxForImage:(CIImage *)image time:(CMTime)time seedBox:(CGRect)seed;
|
||||
- (void)reset;
|
||||
- (void)removeCachedResult:(NSDictionary *)result;
|
||||
- (NSDictionary *)cacheStatistics;
|
||||
@end
|
||||
@implementation PGRealtimeFaceTracker
|
||||
- (instancetype)init {if((self=[super init])){_mutex=[NSLock new];_entries=[NSMutableArray new];}return self;}
|
||||
- (void)reset {[_mutex lock];[_entries removeAllObjects];_estimatedBytes=0;[_mutex unlock];}
|
||||
- (instancetype)init {if((self=[super init])){_mutex=[NSLock new];_entries=[NSMutableArray new];_objectTime=kCMTimeInvalid;}return self;}
|
||||
- (void)resetObjectTracker { _sequence=[VNSequenceRequestHandler new];_objectRequest=nil;_objectBox=CGRectNull;_objectTime=kCMTimeInvalid;_objectValid=NO; }
|
||||
- (void)reset {[_mutex lock];[_entries removeAllObjects];_estimatedBytes=0;_liveReference=nil;[self resetObjectTracker];[_mutex unlock];}
|
||||
- (void)removeCachedResult:(NSDictionary *)result {
|
||||
[_mutex lock];
|
||||
for(NSInteger i=(NSInteger)_entries.count-1;i>=0;i--) {
|
||||
NSDictionary *entry=_entries[(NSUInteger)i];
|
||||
if([entry[@"context"] isEqual:result[@"context"]]&&[entry[@"scope"] isEqual:result[@"scope"]]&&[entry[@"key"] isEqual:result[@"key"]]) {
|
||||
_estimatedBytes-=[entry[@"bytes"] unsignedIntegerValue];[_entries removeObjectAtIndex:(NSUInteger)i];
|
||||
}
|
||||
}
|
||||
[_mutex unlock];
|
||||
}
|
||||
- (NSDictionary *)cacheStatistics {[_mutex lock];NSDictionary *stats=@{@"frames":@(_entries.count),@"estimatedBytes":@(_estimatedBytes)};[_mutex unlock];return stats;}
|
||||
- (NSDictionary *)resultForGeometry:(NSArray<NSDictionary *> *)input settings:(PGBeautySettings)s time:(CMTime)time extent:(CGRect)extent {
|
||||
- (CGRect)trackedBoxForImage:(CIImage *)image time:(CMTime)time seedBox:(CGRect)seed {
|
||||
if(!image||!PGTimeKey(time)){[self resetObjectTracker];return CGRectNull;}
|
||||
BOOL hasSeed=PGValidRect(seed),hasBox=PGValidRect(_objectBox);
|
||||
double dt=PGTimeKey(_objectTime)?CMTimeGetSeconds(CMTimeSubtract(time,_objectTime)):NAN;
|
||||
BOOL backward=isfinite(dt)&&dt<0;
|
||||
if(hasBox&&_objectValid&&isfinite(dt)&&fabs(dt)<=.0005)return _objectBox;
|
||||
if(!_sequence)_sequence=[VNSequenceRequestHandler new];
|
||||
if(!_objectRequest||!_objectValid||backward||(isfinite(dt)&&dt>.2)) {
|
||||
if(!backward&&hasBox&&!_objectValid&&isfinite(dt)&&dt<=.45&&(!hasSeed||!PGCompatibleBoxes(seed,_objectBox)))return _objectBox;
|
||||
if(!hasSeed){_objectValid=NO;_objectRequest=nil;_sequence=[VNSequenceRequestHandler new];return CGRectNull;}
|
||||
_sequence=[VNSequenceRequestHandler new];
|
||||
_objectRequest=[[VNTrackObjectRequest alloc] initWithDetectedObjectObservation:[VNDetectedObjectObservation observationWithBoundingBox:seed]];
|
||||
NSUInteger revision=VNTrackObjectRequest.defaultRevision;
|
||||
if(![VNTrackObjectRequest.supportedRevisions containsIndex:revision])revision=VNTrackObjectRequest.currentRevision;
|
||||
if([VNTrackObjectRequest.supportedRevisions containsIndex:revision])_objectRequest.revision=revision;
|
||||
_objectRequest.trackingLevel=VNRequestTrackingLevelAccurate;
|
||||
_objectBox=seed;_objectTime=time;_objectValid=YES;return seed;
|
||||
}
|
||||
NSError *error=nil;
|
||||
BOOL ok=[_sequence performRequests:@[_objectRequest] onCIImage:PGPreparedVisionImage(image,960) orientation:kCGImagePropertyOrientationUp error:&error];
|
||||
VNDetectedObjectObservation *result=ok?_objectRequest.results.firstObject:nil;
|
||||
CGRect box=result.boundingBox;
|
||||
if(result&&result.confidence>=.22&&PGValidRect(box)) {
|
||||
_objectRequest.inputObservation=result;_objectRequest.trackingLevel=VNRequestTrackingLevelAccurate;
|
||||
_objectBox=box;_objectTime=time;_objectValid=YES;return box;
|
||||
}
|
||||
_objectRequest=nil;_sequence=[VNSequenceRequestHandler new];_objectValid=NO;
|
||||
return hasBox?_objectBox:(hasSeed?seed:CGRectNull);
|
||||
}
|
||||
- (NSDictionary *)resultForGeometry:(NSArray<NSDictionary *> *)raw settings:(PGBeautySettings)s time:(CMTime)time extent:(CGRect)extent {
|
||||
return [self resultForGeometry:raw settings:s time:time extent:extent image:nil];
|
||||
}
|
||||
- (NSDictionary *)resultForGeometry:(NSArray<NSDictionary *> *)input settings:(PGBeautySettings)s time:(CMTime)time extent:(CGRect)extent image:(CIImage *)image {
|
||||
NSMutableArray *valid=[NSMutableArray new];
|
||||
for(id item in input) {NSDictionary *g=PGSanitizedGeometry(item);if(g && valid.count<16)[valid addObject:g];}
|
||||
NSArray *raw=[valid copy];
|
||||
NSUInteger mode=s.fastMultiFace?2:(s.singleFace?1:0);
|
||||
for(id item in input) {NSDictionary *g=PGSanitizedGeometry(item);if(g&&valid.count<16)[valid addObject:g];}
|
||||
NSArray *raw=[valid copy];NSUInteger mode=s.fastMultiFace?2:(s.singleFace?1:0);
|
||||
NSString *key=PGTimeKey(time);
|
||||
NSString *context=[NSString stringWithFormat:@"%lu/%u/%lld/%.17g/%.17g/%.17g/%.17g/%.9g",(unsigned long)mode,s.targetIndex,
|
||||
(long long)time.epoch,extent.origin.x,extent.origin.y,extent.size.width,extent.size.height,s.faceJumpGuardRange];
|
||||
[_mutex lock];
|
||||
NSDictionary *head=nil;
|
||||
for(NSDictionary *record in _entries) if([record[@"context"] isEqual:context] &&
|
||||
(!head || CMTimeCompare(PGRecordTime(record),PGRecordTime(head))>=0)) head=record;
|
||||
NSString *scope=@"automatic";
|
||||
BOOL contextChanged=![_liveReference[@"context"] isEqual:context];
|
||||
NSDictionary *reference=contextChanged?nil:_liveReference;
|
||||
if(contextChanged) {
|
||||
// Fast-multi bypasses pin selection. Returning to a prior mode can use
|
||||
// its accepted shape, but must never continue another mode's VN sequence.
|
||||
for(NSDictionary *record in _entries)if([record[@"context"] isEqual:context]&&CMTimeCompare(PGRecordTime(record),time)<=0&&
|
||||
(!reference||CMTimeCompare(PGRecordTime(record),PGRecordTime(reference))>0))reference=record;
|
||||
}
|
||||
double seedX=PGClamp(s.selectionX,0,1),seedY=PGClamp(s.selectionY,0,1);
|
||||
if(mode==1) {
|
||||
// A real point change (> .01) starts a new identity scope. Older render
|
||||
// snapshots may use their own past scope, but never replace a newer head.
|
||||
NSDictionary *seedRecord=head;
|
||||
if(seedRecord && CMTimeCompare(time,PGRecordTime(seedRecord))<0) {
|
||||
seedRecord=nil;
|
||||
for(NSDictionary *record in _entries) if([record[@"context"] isEqual:context] && PGSeedDistance(record,s)<=.01 &&
|
||||
CMTimeCompare(PGRecordTime(record),time)<=0 && (!seedRecord || CMTimeCompare(PGRecordTime(record),PGRecordTime(seedRecord))>=0))seedRecord=record;
|
||||
}
|
||||
if(seedRecord && PGSeedDistance(seedRecord,s)<=.01) {
|
||||
scope=seedRecord[@"scope"];seedX=[seedRecord[@"seedX"] doubleValue];seedY=[seedRecord[@"seedY"] doubleValue];
|
||||
} else scope=[NSString stringWithFormat:@"%@/%.9g/%.9g",key?:@"invalid",seedX,seedY];
|
||||
}
|
||||
NSDictionary *reference=nil;
|
||||
if(key) for(NSDictionary *record in _entries) {
|
||||
if(![record[@"context"] isEqual:context] || ![record[@"scope"] isEqual:scope])continue;
|
||||
if([record[@"key"] isEqual:key] && [record[@"raw"] isEqual:raw]) {[_mutex unlock];return record;}
|
||||
CMTime stored=PGRecordTime(record);
|
||||
// Same-time changed detections recompute from an earlier frame, never
|
||||
// feed an already smoothed result into another pass at that same time.
|
||||
if(CMTimeCompare(stored,time)>=0)continue;
|
||||
double dt=CMTimeGetSeconds(CMTimeSubtract(time,stored));
|
||||
if(dt<=.35 && (!reference || CMTimeCompare(stored,PGRecordTime(reference))>0))reference=record;
|
||||
}
|
||||
NSArray *prior=reference[@"output"];
|
||||
NSDictionary *previous=prior.count?prior.firstObject:nil;
|
||||
NSString *scope=mode==1?[NSString stringWithFormat:@"%.9g/%.9g",seedX,seedY]:@"automatic";
|
||||
if(mode==1&&reference&&PGSeedDistance(reference,s)<=.01){scope=reference[@"scope"];seedX=[reference[@"seedX"] doubleValue];seedY=[reference[@"seedY"] doubleValue];}
|
||||
if(reference&&![reference[@"scope"] isEqual:scope])reference=nil;
|
||||
// Exact frame reuse is independent of a second Vision result or render count.
|
||||
// A new uncached rewind clears live geometry and the stateful sequence handler.
|
||||
NSDictionary *cached=nil;
|
||||
if(key)for(NSDictionary *record in _entries)if([record[@"context"] isEqual:context]&&[record[@"scope"] isEqual:scope]&&[record[@"key"] isEqual:key]){cached=record;break;}
|
||||
BOOL backward=reference&&CMTimeCompare(time,PGRecordTime(reference))<0;
|
||||
if(contextChanged||!reference||backward)[self resetObjectTracker];
|
||||
if(cached){_liveReference=cached;[_mutex unlock];return cached;}
|
||||
if(backward||!key)reference=nil;
|
||||
NSDictionary *previous=reference[@"accepted"];
|
||||
CGRect previousBox=PGArrayRect(previous[@"box"]);
|
||||
CGRect tracked=mode==2?CGRectNull:[self trackedBoxForImage:image time:time seedBox:CGRectNull];
|
||||
CGRect selectionBox=PGValidRect(tracked)?tracked:previousBox;
|
||||
NSInteger index=-1;double best=-DBL_MAX;
|
||||
if(mode!=2) for(NSUInteger i=0;i<raw.count;i++) {
|
||||
if(mode!=2)for(NSUInteger i=0;i<raw.count;i++) {
|
||||
CGRect box=PGArrayRect(raw[i][@"box"]);CGPoint center=PGCenter(box);double score;
|
||||
if(PGValidRect(previousBox)) {
|
||||
CGFloat factor=PGClamp(s.faceJumpGuardRange,1,4);
|
||||
CGRect guard=CGRectIntersection(CGRectMake(0,0,1,1),CGRectInset(previousBox,-previousBox.size.width*(factor-1)*.5,-previousBox.size.height*(factor-1)*.5));
|
||||
if(center.x<CGRectGetMinX(guard)||center.x>CGRectGetMaxX(guard)||center.y<CGRectGetMinY(guard)||center.y>CGRectGetMaxY(guard))continue;
|
||||
CGPoint p=PGCenter(previousBox);score=-((center.x-p.x)*(center.x-p.x)+(center.y-p.y)*(center.y-p.y));
|
||||
} else if(mode==1) score=-((center.x-seedX)*(center.x-seedX)+(center.y-seedY)*(center.y-seedY));
|
||||
if(!CGRectContainsPoint(guard,center))continue;
|
||||
}
|
||||
if(PGValidRect(selectionBox)) {
|
||||
CGPoint p=PGCenter(selectionBox);double distance=hypot(center.x-p.x,center.y-p.y);
|
||||
score=8*PGBoxIoU(box,selectionBox)+3.2*(1-MIN(1,distance/.32))-.35*distance;
|
||||
if(CGRectContainsPoint(box,p))score+=1.2;
|
||||
}else if(mode==1)score=-hypot(center.x-seedX,center.y-seedY);
|
||||
else {CGRect clipped=CGRectIntersection(box,CGRectMake(0,0,1,1));CGPoint p=PGCenter(clipped);
|
||||
score=1.8*fmin(1,clipped.size.width*clipped.size.height)+1.1*(1-fmin(1,hypot(p.x-.5,p.y-.5)/.72));}
|
||||
if(index<0 || score>best) {index=(NSInteger)i;best=score;}
|
||||
if(index<0||score>best){index=(NSInteger)i;best=score;}
|
||||
}
|
||||
NSDictionary *current=index>=0?raw[(NSUInteger)index]:nil;
|
||||
if(mode!=2&&!PGValidRect(tracked)&¤t)tracked=[self trackedBoxForImage:image time:time seedBox:PGArrayRect(current[@"box"])];
|
||||
NSString *reason=current?PGGeometryQualityReason(current):@"missingFace";
|
||||
if(!reason.length&&previous)reason=PGGeometryTransitionReason(current,previous);
|
||||
BOOL held=NO;NSArray *output=@[];NSDictionary *accepted=previous;
|
||||
if(mode==2){output=raw;accepted=nil;reason=@"fastMulti";}
|
||||
else if(!reason.length){output=@[current];accepted=current;}
|
||||
else if(previous) {
|
||||
CGRect box=PGValidRect(tracked)?tracked:(current?PGArrayRect(current[@"box"]):previousBox);
|
||||
NSDictionary *mapped=PGRemappedGeometry(previous,box);
|
||||
output=@[PGValidHeldGeometry(mapped)?mapped:previous];held=YES;
|
||||
}
|
||||
NSArray *output;BOOL held=NO;
|
||||
if(mode==2) output=raw;
|
||||
else if(index>=0) {
|
||||
NSDictionary *current=raw[(NSUInteger)index];
|
||||
double dt=reference?CMTimeGetSeconds(CMTimeSubtract(time,PGRecordTime(reference))):0;
|
||||
output=@[previous?PGStableGeometry(current,previous,dt,![reference[@"held"] boolValue]):current];
|
||||
} else {output=prior?:@[];held=output.count>0;}
|
||||
NSMutableDictionary *record=[@{@"context":context,@"scope":scope,@"key":key?:@"invalid",@"value":@(time.value),@"scale":@(time.timescale),@"epoch":@(time.epoch),
|
||||
@"seedX":@(seedX),@"seedY":@(seedY),@"raw":raw,@"output":output,@"index":@(index),@"held":@(held),@"referenceKey":reference[@"key"]?:@""} mutableCopy];
|
||||
@"seedX":@(seedX),@"seedY":@(seedY),@"raw":raw,@"output":output,@"index":@(index),@"held":@(held),@"reason":reason,
|
||||
@"trackedBox":PGValidRect(tracked)?PGRectArray(tracked):@[],@"referenceKey":reference[@"key"]?:@""} mutableCopy];
|
||||
if(accepted)record[@"accepted"]=accepted;
|
||||
// Keep the accepted time distinct from the output/held time for diagnostics.
|
||||
record[@"acceptedKey"]=(!reason.length?key:reference[@"acceptedKey"])?:@"";
|
||||
if(key) {
|
||||
NSData *serialized=[NSPropertyListSerialization dataWithPropertyList:record format:NSPropertyListBinaryFormat_v1_0 options:0 error:nil];
|
||||
NSUInteger bytes=serialized.length+512;
|
||||
record[@"bytes"]=@(bytes);
|
||||
// Replace changed raw geometry at the same timestamp rather than letting
|
||||
// callbacks grow history or make smoothing depend on redraw count.
|
||||
for(NSInteger i=(NSInteger)_entries.count-1;i>=0;i--) {
|
||||
NSDictionary *old=_entries[(NSUInteger)i];
|
||||
if([old[@"context"] isEqual:context] && [old[@"scope"] isEqual:scope] && [old[@"key"] isEqual:key]) {
|
||||
_estimatedBytes-=[old[@"bytes"] unsignedIntegerValue];[_entries removeObjectAtIndex:(NSUInteger)i];
|
||||
}
|
||||
}
|
||||
if(bytes<=16*1024*1024) {[_entries addObject:[record copy]];_estimatedBytes+=bytes;}
|
||||
while(_entries.count>1200 || _estimatedBytes>16*1024*1024) {
|
||||
_estimatedBytes-=[_entries.firstObject[@"bytes"] unsignedIntegerValue];[_entries removeObjectAtIndex:0];
|
||||
}
|
||||
}
|
||||
NSUInteger bytes=serialized.length+512;record[@"bytes"]=@(bytes);
|
||||
if(bytes<=16*1024*1024){[_entries addObject:[record copy]];_estimatedBytes+=bytes;}
|
||||
while(_entries.count>1200||_estimatedBytes>16*1024*1024){_estimatedBytes-=[_entries.firstObject[@"bytes"] unsignedIntegerValue];[_entries removeObjectAtIndex:0];}
|
||||
_liveReference=[record copy];
|
||||
}else{_liveReference=nil;[self resetObjectTracker];}
|
||||
[_mutex unlock];return [record copy];
|
||||
}
|
||||
@end
|
||||
@@ -336,6 +456,8 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
CIColorKernel *_subtract;
|
||||
CIColorKernel *_box;
|
||||
PGRealtimeFaceTracker *_realtime;
|
||||
NSMutableArray<NSDictionary *> *_observationCache;
|
||||
CIContext *_visionContext;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -346,12 +468,14 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
if (self) {
|
||||
_lock = [[NSLock alloc] init];
|
||||
_realtime = [PGRealtimeFaceTracker new];
|
||||
_observationCache = [NSMutableArray new];
|
||||
_visionContext = [CIContext contextWithOptions:@{kCIContextCacheIntermediates:@NO}];
|
||||
_targets = [NSMutableArray arrayWithObjects:[NSMutableDictionary dictionary], [NSMutableDictionary dictionary], [NSMutableDictionary dictionary], nil];
|
||||
// Thin/chin/jaw/short reconstruct the recovered local coordinate math.
|
||||
// The other five controls retain this project's analytic approximation.
|
||||
// Recovered jaw -> chin -> short order follows the reference. The other
|
||||
// analytic body controls still precede jaw, so the full combined chain
|
||||
// (narrow/V/cheek/small-head/eyes) is not claimed reference-equivalent.
|
||||
// Thin/V/chin/jaw/short reconstruct recovered local coordinate math.
|
||||
// Narrow/cheek/small-head retain this project's analytic approximation.
|
||||
// Recovered V -> jaw -> chin -> short order follows the reference. Other
|
||||
// analytic body controls still precede V, so the full combined chain
|
||||
// with narrow/cheek/small-head/eyes is not claimed reference-equivalent.
|
||||
// Each pin changes the sampling coordinate, with only one image resample.
|
||||
NSMutableString *source = [NSMutableString stringWithString:
|
||||
@"vec2 pgThinPin(vec2 q, vec4 control, float ratio) {"
|
||||
@@ -371,8 +495,9 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
" float dy=b.y-a.y; if(abs(dy)<=0.000001) dy=dy<0.0?-0.000001:0.000001;"
|
||||
" if(q.x<a.x+(b.x-a.x)*(q.y-a.y)/dy) crossing=1.0; }"
|
||||
" return vec2(distance,crossing); }"
|
||||
" kernel vec2 pgFaceWarp(vec2 c, vec2 size, vec2 le, vec2 re, vec2 er, float thinRatio, float bigEye, float shortRatio, float narrow, float chinRatio, float vFace, float jawRatio, float cheek, float smallHead, float headRange, vec2 imageOrigin, vec2 imageSize"];
|
||||
" kernel vec2 pgFaceWarp(vec2 c, vec2 size, vec2 le, vec2 re, vec2 er, float thinRatio, float bigEye, float shortRatio, float narrow, float chinRatio, float vRatio, float jawRatio, float cheek, float smallHead, float headRange, vec2 imageOrigin, vec2 imageSize"];
|
||||
for (NSUInteger i=0; i<17; i++) [source appendFormat:@", vec4 pin%lu",(unsigned long)i];
|
||||
for (NSUInteger i=0; i<4; i++) [source appendFormat:@", vec4 vPin%lu",(unsigned long)i];
|
||||
for (NSUInteger i=0; i<3; i++) [source appendFormat:@", vec4 chinPin%lu",(unsigned long)i];
|
||||
[source appendString:@", vec2 jawAnchor, vec2 shortAxis"];
|
||||
for (NSUInteger i=0; i<6; i++) [source appendFormat:@", vec4 jawPin%lu",(unsigned long)i];
|
||||
@@ -383,14 +508,14 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
[source appendString:@" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
" vec2 n = (p-c)/size;"
|
||||
" float body = 1.0-smoothstep(0.38,0.76,length(n*vec2(1.0,0.82)));"
|
||||
" float lower = (1.0-smoothstep(-0.12,0.27,n.y))*body;"
|
||||
" float sides = smoothstep(0.08,0.32,abs(n.x));"
|
||||
" float j=(n.y+0.23)/0.22; float jawBand = exp(-j*j)*body;"
|
||||
" float ch=(n.y-0.02)/0.19; float cheekBand = exp(-ch*ch)*body;"
|
||||
" float head = 1.0-smoothstep(0.38,0.75+0.32*headRange,length(n*vec2(0.9,0.65)));"
|
||||
" p += (p-c)*smallHead*0.18*head;"
|
||||
" p.x += size.x*n.x*(narrow*0.30*body + vFace*0.24*jawBand + cheek*0.18*cheekBand)*sides;"
|
||||
" p.y += size.y*(-vFace*0.025*lower);"
|
||||
" p.x += size.x*n.x*(narrow*0.30*body + cheek*0.18*cheekBand)*sides;"
|
||||
" if(vRatio>0.000001) { vec2 q=(p-imageOrigin)/imageSize; q.y=1.0-q.y;"];
|
||||
for (NSUInteger i=0; i<4; i++) [source appendFormat:@" q=pgThinPin(q,vPin%lu,vRatio);",(unsigned long)i];
|
||||
[source appendString:@" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
" if(abs(jawRatio)>0.000001) { vec2 q=(p-imageOrigin)/imageSize; q.y=1.0-q.y;"];
|
||||
for (NSUInteger i=0; i<6; i++) [source appendFormat:@" q=pgJawPin(q,jawPin%lu,jawAnchor,jawRatio);",(unsigned long)i];
|
||||
[source appendString:@" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
@@ -404,10 +529,10 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
[source appendString:@" float weight=mod(crossings,2.0)>0.5?1.0:clamp(1.0-nearest/length(shortAxis),0.0,1.0);"
|
||||
" q=clamp(q-shortAxis*shortRatio*weight,vec2(0.0),vec2(1.0));"
|
||||
" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
" vec2 dl = (p-le)/er; float wl = 1.0-smoothstep(0.0,1.0,length(dl));"
|
||||
" p -= (p-le)*bigEye*0.33*wl*wl;"
|
||||
" vec2 dr = (p-re)/er; float wr = 1.0-smoothstep(0.0,1.0,length(dr));"
|
||||
" p -= (p-re)*bigEye*0.33*wr*wr; return p; }"];
|
||||
" vec2 dl=p-le; float lr=er.x;"
|
||||
" if(lr>0.0001) { float wl=clamp(1.0-dot(dl,dl)/(lr*lr),0.0,1.0); p=le+dl*(1.0-bigEye*wl); }"
|
||||
" vec2 dr=p-re; float rr=er.y;"
|
||||
" if(rr>0.0001) { float wr=clamp(1.0-dot(dr,dr)/(rr*rr),0.0,1.0); p=re+dr*(1.0-bigEye*wr); } return p; }"];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
_warp = [CIWarpKernel kernelWithString:source];
|
||||
@@ -420,26 +545,53 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
}
|
||||
|
||||
- (NSArray<VNFaceObservation *> *)observationsInImage:(CIImage *)image settings:(PGBeautySettings)settings error:(NSError **)error {
|
||||
CGRect extent = image.extent;
|
||||
CGFloat longest = MAX(extent.size.width, extent.size.height);
|
||||
CGFloat scale = MIN(1.0, (settings.fastMultiFace ? 720.0 : 1280.0) / longest);
|
||||
CIImage *prepared = [image imageByApplyingTransform:CGAffineTransformMakeTranslation(-extent.origin.x, -extent.origin.y)];
|
||||
prepared = [prepared imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)];
|
||||
VNDetectFaceLandmarksRequest *request = [[VNDetectFaceLandmarksRequest alloc] init];
|
||||
request.revision = VNDetectFaceLandmarksRequestRevision3;
|
||||
request.constellation = VNRequestFaceLandmarksConstellation76Points;
|
||||
// An image request handler is intentionally local to one invocation. A shared
|
||||
// sequence handler would make parallel / reverse render order observable.
|
||||
VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithCIImage:prepared options:@{}];
|
||||
if (![handler performRequests:@[request] error:error]) return nil;
|
||||
NSArray<VNFaceObservation *> *faces = request.results ?: @[];
|
||||
return [faces sortedArrayUsingComparator:^NSComparisonResult(VNFaceObservation *a, VNFaceObservation *b) {
|
||||
CGRect x = a.boundingBox, y = b.boundingBox;
|
||||
if (CGRectGetMidX(x) != CGRectGetMidX(y)) return CGRectGetMidX(x) < CGRectGetMidX(y) ? NSOrderedAscending : NSOrderedDescending;
|
||||
if (CGRectGetMidY(x) != CGRectGetMidY(y)) return CGRectGetMidY(x) < CGRectGetMidY(y) ? NSOrderedAscending : NSOrderedDescending;
|
||||
return x.size.width > y.size.width ? NSOrderedAscending : NSOrderedDescending;
|
||||
// 2.4.0 defaults to a 960-pixel long edge (its configurable downsample
|
||||
// limit), not the former 1280-pixel path. The explicit fast mode keeps its
|
||||
// lower-cost detector. Both handlers receive an upright, zero-origin image.
|
||||
CIImage *prepared=PGPreparedVisionImage(image,settings.fastMultiFace?720:960);
|
||||
VNDetectFaceLandmarksRequest *(^newRequest)(void)=^{
|
||||
VNDetectFaceLandmarksRequest *r=[VNDetectFaceLandmarksRequest new];
|
||||
r.revision=VNDetectFaceLandmarksRequestRevision3;r.constellation=VNRequestFaceLandmarksConstellation76Points;return r;
|
||||
};
|
||||
VNDetectFaceLandmarksRequest *request=newRequest();NSError *firstError=nil;
|
||||
VNImageRequestHandler *handler=[[VNImageRequestHandler alloc] initWithCIImage:prepared orientation:kCGImagePropertyOrientationUp options:@{}];
|
||||
BOOL ok=[handler performRequests:@[request] error:&firstError];
|
||||
NSArray<VNFaceObservation *> *faces=ok?(request.results?:@[]):@[];
|
||||
NSUInteger count=0;for(VNFaceObservation *face in faces)count=MAX(count,face.landmarks.allPoints.pointCount);
|
||||
if(!ok||!faces.count||count<76) {
|
||||
// The reference retries a materialized RGBA image, not the same lazy
|
||||
// CIImage request. Retain a successful first result if retry finds none.
|
||||
CGColorSpaceRef space=CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
|
||||
CGImageRef cg=[_visionContext createCGImage:prepared fromRect:prepared.extent format:kCIFormatRGBA8 colorSpace:space];
|
||||
CGColorSpaceRelease(space);
|
||||
if(cg) {
|
||||
VNDetectFaceLandmarksRequest *retry=newRequest();NSError *retryError=nil;
|
||||
VNImageRequestHandler *fallback=[[VNImageRequestHandler alloc] initWithCGImage:cg orientation:kCGImagePropertyOrientationUp options:@{}];
|
||||
BOOL retried=[fallback performRequests:@[retry] error:&retryError];CGImageRelease(cg);
|
||||
if(retried){ok=YES;firstError=nil;if(retry.results.count)faces=retry.results;}
|
||||
else if(!ok)firstError=retryError?:firstError;
|
||||
}
|
||||
}
|
||||
if(!ok){if(error)*error=firstError;return nil;}
|
||||
return [faces sortedArrayUsingComparator:^NSComparisonResult(VNFaceObservation *a,VNFaceObservation *b) {
|
||||
CGRect x=a.boundingBox,y=b.boundingBox;
|
||||
if(CGRectGetMidX(x)!=CGRectGetMidX(y))return CGRectGetMidX(x)<CGRectGetMidX(y)?NSOrderedAscending:NSOrderedDescending;
|
||||
if(CGRectGetMidY(x)!=CGRectGetMidY(y))return CGRectGetMidY(x)<CGRectGetMidY(y)?NSOrderedAscending:NSOrderedDescending;
|
||||
return x.size.width>y.size.width?NSOrderedAscending:NSOrderedDescending;
|
||||
}];
|
||||
}
|
||||
- (NSArray<VNFaceObservation *> *)cachedObservationsInImage:(CIImage *)image settings:(PGBeautySettings)settings time:(CMTime)time error:(NSError **)error {
|
||||
NSString *key=PGTimeKey(time);CGRect e=image.extent;
|
||||
NSString *context=[NSString stringWithFormat:@"%u/%.17g/%.17g/%.17g/%.17g",settings.fastMultiFace,e.origin.x,e.origin.y,e.size.width,e.size.height];
|
||||
@synchronized(_observationCache) {
|
||||
if(key)for(NSDictionary *entry in _observationCache)if([entry[@"key"] isEqual:key]&&[entry[@"context"] isEqual:context])return entry[@"faces"];
|
||||
NSArray *faces=[self observationsInImage:image settings:settings error:error];
|
||||
// A transient API error is retriable; a successful empty result is a
|
||||
// real frame result and is cached, so redraws cannot toggle the effect.
|
||||
if(key&&faces){[_observationCache addObject:@{@"key":key,@"context":context,@"faces":faces}];while(_observationCache.count>120)[_observationCache removeObjectAtIndex:0];}
|
||||
return faces;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)recordForTime:(CMTime)time target:(NSUInteger)target nearest:(BOOL)nearest {
|
||||
NSString *key = PGTimeKey(time);
|
||||
@@ -505,7 +657,7 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
if (error) *error = [NSError errorWithDomain:PGFaceErrorDomain code:1 userInfo:@{NSLocalizedDescriptionKey:@"Face analysis requires a finite image and valid frame time."}];
|
||||
return NO;
|
||||
}
|
||||
NSArray *observations = [self observationsInImage:image settings:settings error:error];
|
||||
NSArray *observations = [self cachedObservationsInImage:image settings:settings time:time error:error];
|
||||
if (!observations) return NO;
|
||||
NSUInteger target = MIN((NSUInteger)settings.targetIndex, 2);
|
||||
NSDictionary *prior = [self recordForTime:time target:target nearest:YES];
|
||||
@@ -527,7 +679,7 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
for (NSDictionary *face in geometry) {
|
||||
CGRect box = PGArrayRect(face[@"box"]), pixels = PGToPixels(box, extent);
|
||||
NSArray *points76 = PGSanitizedPoints76(face[@"points76"]);
|
||||
float thinRatio = 0, chinRatio = 0, jawRatio = 0, shortRatio = 0;
|
||||
float thinRatio = 0, chinRatio = 0, jawRatio = 0, shortRatio = 0, vRatio = 0;
|
||||
if (points76) {
|
||||
double width = hypot(([points76[75][0] doubleValue]-[points76[59][0] doubleValue])*extent.size.width,
|
||||
([points76[75][1] doubleValue]-[points76[59][1] doubleValue])*extent.size.height);
|
||||
@@ -536,23 +688,37 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
double height = 2*hypot(([points76[67][0] doubleValue]-midX)*extent.size.width,
|
||||
([points76[67][1] doubleValue]-midY)*extent.size.height);
|
||||
double gain = fmin(2.25,fmax(1,280/fmax(1,fmax(width,height))));
|
||||
thinRatio = PGClamp(s.faceThin,0,1)*.025*gain;
|
||||
// The 2.4.0 pin shader consumes this CPU coefficient directly;
|
||||
// its thin field no longer applies the older 280-pixel size gain.
|
||||
thinRatio = PGClamp(s.faceThin,0,1)*.025;
|
||||
float chin = PGClamp(s.faceChin,-1,1);
|
||||
chinRatio = chin*(chin>0 ? .04 : .02)*gain;
|
||||
jawRatio = PGClamp(s.faceJaw,0,1)*.05*gain;
|
||||
shortRatio = PGClamp(s.faceShort,-1,1)*.25*gain;
|
||||
// The specified 2.4.0 shader takes the CPU-scaled .065 V ratio
|
||||
// directly; it no longer applies the older shader's size gain.
|
||||
vRatio = PGClamp(s.faceV,0,1)*.065;
|
||||
}
|
||||
BOOL otherControls = s.faceBigEye || s.faceNarrow || s.faceV || s.faceCheekbone || s.faceSmallHead;
|
||||
// No full topology means no guessed bbox thin/chin/jaw/short deformation. Legacy
|
||||
BOOL otherControls = s.faceBigEye || s.faceNarrow || s.faceCheekbone || s.faceSmallHead;
|
||||
// No full topology means no guessed bbox thin/V/chin/jaw/short deformation. Legacy
|
||||
// archives using only those controls remain exact image/mask pass-through.
|
||||
if (thinRatio <= .000001 && fabsf(chinRatio) <= .000001 && fabsf(jawRatio) <= .000001 && fabsf(shortRatio) <= .000001 && !otherControls) continue;
|
||||
if (thinRatio <= .000001 && vRatio <= .000001 && fabsf(chinRatio) <= .000001 && fabsf(jawRatio) <= .000001 && fabsf(shortRatio) <= .000001 && !otherControls) continue;
|
||||
CGRect le = PGRegionBounds(face, @"leftEye", PGInFace(box, 0.16, 0.53, 0.25, 0.15));
|
||||
CGRect re = PGRegionBounds(face, @"rightEye", PGInFace(box, 0.59, 0.53, 0.25, 0.15));
|
||||
CGPoint left = PGCenter(PGToPixels(le, extent)), right = PGCenter(PGToPixels(re, extent));
|
||||
double leftRadius=MAX(2,pixels.size.width*.24),rightRadius=MAX(2,pixels.size.width*.24);
|
||||
if(points76) {
|
||||
CGPoint lp=PGPoint(points76[6]),rp=PGPoint(points76[13]);
|
||||
left=CGPointMake(extent.origin.x+lp.x*extent.size.width,extent.origin.y+lp.y*extent.size.height);
|
||||
right=CGPointMake(extent.origin.x+rp.x*extent.size.width,extent.origin.y+rp.y*extent.size.height);
|
||||
CGPoint a=PGPoint(points76[0]),b=PGPoint(points76[1]),c=PGPoint(points76[7]),d=PGPoint(points76[8]);
|
||||
leftRadius=hypot((a.x-b.x)*extent.size.width,(a.y-b.y)*extent.size.height);
|
||||
rightRadius=hypot((c.x-d.x)*extent.size.width,(c.y-d.y)*extent.size.height);
|
||||
}
|
||||
NSMutableArray *arguments = [@[PGVector(PGCenter(pixels)), [CIVector vectorWithX:pixels.size.width Y:pixels.size.height],
|
||||
PGVector(left), PGVector(right), [CIVector vectorWithX:MAX(2, pixels.size.width * 0.24) Y:MAX(2, pixels.size.height * 0.17)],
|
||||
@(thinRatio), @(PGClamp(s.faceBigEye, 0, 1)), @(shortRatio),
|
||||
@(PGClamp(s.faceNarrow, -1, 1)), @(chinRatio), @(PGClamp(s.faceV, 0, 1)),
|
||||
PGVector(left), PGVector(right), [CIVector vectorWithX:leftRadius Y:rightRadius],
|
||||
@(thinRatio), @(PGClamp(s.faceBigEye, 0, 1)*.15), @(shortRatio),
|
||||
@(PGClamp(s.faceNarrow, -1, 1)), @(chinRatio), @(vRatio),
|
||||
@(jawRatio), @(PGClamp(s.faceCheekbone, 0, 1)), @(PGClamp(s.faceSmallHead, 0, 1)), @(PGClamp(s.faceSmallHeadRange, 0, 1)),
|
||||
[CIVector vectorWithX:extent.origin.x Y:extent.origin.y], [CIVector vectorWithX:extent.size.width Y:extent.size.height]] mutableCopy];
|
||||
for (NSUInteger i=0; i<17; i++) {
|
||||
@@ -564,6 +730,15 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
}
|
||||
[arguments addObject:[CIVector vectorWithX:ox Y:oy Z:ax W:ay]];
|
||||
}
|
||||
for (NSUInteger i=0; i<4; i++) {
|
||||
double ox=0,oy=0,ax=0,ay=0;
|
||||
if (points76) {
|
||||
NSArray *origin=points76[PGVFacePins[i][0]],*anchor=points76[PGVFacePins[i][1]];
|
||||
ox=[origin[0] doubleValue];oy=1-[origin[1] doubleValue];
|
||||
ax=[anchor[0] doubleValue];ay=1-[anchor[1] doubleValue];
|
||||
}
|
||||
[arguments addObject:[CIVector vectorWithX:ox Y:oy Z:ax W:ay]];
|
||||
}
|
||||
for (NSUInteger i=0; i<3; i++) {
|
||||
double ox=0,oy=0,ax=0,ay=0;
|
||||
if (points76) {
|
||||
@@ -613,8 +788,14 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
for (NSDictionary *face in geometry) [restored addObject:[VNFaceObservation faceObservationWithRequestRevision:VNDetectFaceLandmarksRequestRevision3 boundingBox:PGArrayRect(face[@"box"]) roll:nil yaw:nil pitch:nil]];
|
||||
observations = restored;
|
||||
} else {
|
||||
NSArray *detected = [self observationsInImage:image settings:settings error:error];
|
||||
if (!detected) return nil;
|
||||
NSArray *detected = [self cachedObservationsInImage:image settings:settings time:time error:error];
|
||||
BOOL transientDetectionFailure=detected==nil;
|
||||
if (!detected) {
|
||||
if(settings.trackingEnabled)return nil;
|
||||
// A failed live detection takes the same shape-hold path as a lost
|
||||
// observation; it must not fail the host's entire render request.
|
||||
detected=@[];if(error)*error=nil;
|
||||
}
|
||||
if(settings.trackingEnabled) {
|
||||
// Preserve the explicit offline-analysis contract. Its stored
|
||||
// identity fallback never reads or writes realtime temporal state.
|
||||
@@ -630,7 +811,10 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
for(VNFaceObservation *observation in detected) if(PGValidRect(observation.boundingBox) && raw.count<16) {
|
||||
[raw addObject:PGGeometry(observation)];[validObservations addObject:observation];
|
||||
}
|
||||
NSDictionary *live=[_realtime resultForGeometry:raw settings:settings time:time extent:extent];
|
||||
NSDictionary *live=[_realtime resultForGeometry:raw settings:settings time:time extent:extent image:image];
|
||||
// A successful empty detection is frozen; an API error is not. Its
|
||||
// temporary held output must allow a same-time retry to acquire a face.
|
||||
if(transientDetectionFailure)[_realtime removeCachedResult:live];
|
||||
geometry=live[@"output"];
|
||||
if(settings.singleFace && !settings.fastMultiFace) {
|
||||
NSInteger index=[live[@"index"] integerValue];
|
||||
@@ -650,6 +834,16 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
// skin/teeth/eyes support, which still covers the detected group.
|
||||
appearance=raw;observations=validObservations;
|
||||
}
|
||||
if(([live[@"held"] boolValue] || transientDetectionFailure) && geometry.count) {
|
||||
// Keep beauty masks on the same held primary shape as the warp,
|
||||
// while retaining support for independently detected secondary faces.
|
||||
NSMutableArray *supported=[appearance mutableCopy];
|
||||
NSInteger index=[live[@"index"] integerValue];
|
||||
if(!settings.singleFace && index>=0 && (NSUInteger)index<supported.count) supported[(NSUInteger)index]=geometry.firstObject;
|
||||
else if(settings.singleFace || !supported.count) supported=[geometry mutableCopy];
|
||||
else [supported addObjectsFromArray:geometry];
|
||||
appearance=supported;
|
||||
}
|
||||
}
|
||||
}
|
||||
CIImage *skin = PGBlack(extent), *teeth = PGBlack(extent), *eyes = PGBlack(extent), *protection = PGBlack(extent), *overlay = PGTransparent(extent);
|
||||
@@ -709,6 +903,7 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
for (NSMutableDictionary *target in _targets) [target removeAllObjects];
|
||||
[_lock unlock];
|
||||
[_realtime reset];
|
||||
@synchronized(_observationCache) { [_observationCache removeAllObjects]; }
|
||||
}
|
||||
|
||||
- (NSData *)trackingDataForTarget:(NSUInteger)target {
|
||||
文件已重命名,内容未更改。
文件已重命名,内容未更改。
+29
-8
@@ -11,9 +11,10 @@ NSArray<NSDictionary *> *PGInspectorControls(void) {
|
||||
#define ITEM(ID,NAME,FIELD,SECTION,KIND,FORMAT,MIN,MAX,BYPASS,STORAGE) \
|
||||
[items addObject:@{@"id":@(ID),@"name":@NAME,@"section":@SECTION,@"kind":@KIND,@"format":@FORMAT,@"min":@(MIN),@"max":@(MAX),@"default":@(defaults.FIELD),@"bypass":@(BYPASS),@"offset":@(offsetof(PGBeautySettings,FIELD)),@"storage":@STORAGE}]
|
||||
ITEM(PGSmoothingEnabled,"磨皮",featureProtection,"smooth","master","integer",0,1,NO,"master");
|
||||
ITEM(PGMidtone,"局部磨皮",midtoneDetail,"smooth","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGHighPass,"全局磨皮",highPassDetail,"smooth","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGFeatureProtect,"五官保护",featureProtection,"smooth","toggle","integer",0,1,NO,"uint");
|
||||
ITEM(PGMidtone,"磨皮程度",midtoneDetail,"smooth","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGMicroDetail,"微细锐化",microDetail,"smooth","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGFeatureProtectionAmount,"五官保护",featureProtectionAmount,"smooth","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGNonSkinProtection,"非肤色区保护",nonSkinProtection,"smooth","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGColorEnabled,"美白",featureProtection,"color","master","integer",0,1,NO,"master");
|
||||
ITEM(PGTonePreset,"肤色",skinTonePreset,"color","preset","integer",0,6,NO,"uint");
|
||||
NSMutableDictionary *preset=[items.lastObject mutableCopy];
|
||||
@@ -22,9 +23,10 @@ NSArray<NSDictionary *> *PGInspectorControls(void) {
|
||||
ITEM(PGTeeth,"白牙",teethWhitening,"color","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGHue,"皮肤色相",skinHue,"color","slider","degrees",-30,30,YES,"float");
|
||||
ITEM(PGShapeEnabled,"瘦脸",featureProtection,"shape","master","integer",0,1,NO,"master");
|
||||
ITEM(PGTrackBoxes,"人脸框预览",showTrackBox,"shape","toggle","integer",0,1,NO,"uint");
|
||||
ITEM(PGTrackBoxes,"检测框预览",showTrackBox,"shape","toggle","integer",0,1,NO,"uint");
|
||||
ITEM(PGFastMulti,"多人模式",fastMultiFace,"shape","toggle","integer",0,1,NO,"uint");
|
||||
ITEM(PGJumpGuard,"防跳脸范围",faceJumpGuardRange,"shape","slider","percent",1,4,NO,"float");
|
||||
NSMutableDictionary *multi=[items.lastObject mutableCopy];
|
||||
multi[@"tooltip"]=@"多人模式易抖动,请谨慎使用";items[items.count-1]=multi;
|
||||
ITEM(PGThin,"瘦脸",faceThin,"shape","slider","signed",0,1,YES,"float");
|
||||
ITEM(PGBigEye,"大眼",faceBigEye,"shape","slider","signed",0,1,YES,"float");
|
||||
ITEM(PGShort,"短脸",faceShort,"shape","slider","signed",-1,1,YES,"float");
|
||||
@@ -36,11 +38,13 @@ NSArray<NSDictionary *> *PGInspectorControls(void) {
|
||||
ITEM(PGSmallHead,"小头",faceSmallHead,"shape","slider","signed",0,1,YES,"float");
|
||||
ITEM(PGSmallHeadRange,"小头范围",faceSmallHeadRange,"shape","slider","percent",0,1,NO,"float");
|
||||
ITEM(PGAmount,"磨皮强度",amount,"more","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGHighPass,"全局磨皮",highPassDetail,"more","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGRadius,"磨皮半径",radius,"more","slider","radius",1,30,NO,"float");
|
||||
ITEM(PGSaturation,"肤色饱和度",skinSaturation,"more","slider","percent",-100,100,YES,"float");
|
||||
ITEM(PGEvenTone,"均匀肤色",skinEvenTone,"more","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGEyeBright,"眼睛提亮",eyeBrightening,"more","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGSharpness,"锐化",sharpness,"more","slider","percent",0,1,YES,"float");
|
||||
ITEM(PGJumpGuard,"防跳脸范围",faceJumpGuardRange,"more","slider","percent",1,4,NO,"float");
|
||||
ITEM(PGMix,"整体混合",mix,"more","slider","percent",0,1,NO,"float");
|
||||
#undef ITEM
|
||||
controls=[items copy];
|
||||
@@ -62,7 +66,12 @@ static double PGControlValue(id raw,NSDictionary *d) {
|
||||
+ (instancetype)stateWithValues:(NSDictionary *)values disabledParameters:(NSSet *)disabled hasEdits:(BOOL)edited {
|
||||
PGInspectorState *state=[self new]; NSMutableDictionary *safe=[NSMutableDictionary new];NSMutableSet *bypassed=[NSMutableSet new];
|
||||
for(NSDictionary *d in PGInspectorControls()) {
|
||||
NSNumber *key=d[@"id"];safe[key]=@(PGControlValue(values[key],d));
|
||||
NSNumber *key=d[@"id"];id raw=values[key];
|
||||
// Schema 1 documents stored five-feature protection as the legacy bool.
|
||||
// New numeric values win when present; old archives gain its exact 0/1.
|
||||
if(key.unsignedIntValue==PGFeatureProtectionAmount && !raw && [values[@(PGFeatureProtect)] isKindOfClass:NSNumber.class])
|
||||
raw=@([values[@(PGFeatureProtect)] boolValue]?1:0);
|
||||
safe[key]=@(PGControlValue(raw,d));
|
||||
if([d[@"bypass"] boolValue] && [disabled containsObject:key]) [bypassed addObject:key];
|
||||
}
|
||||
state->_values=[safe copy];state->_disabledParameters=[bypassed copy];state->_hasEdits=edited;return state;
|
||||
@@ -115,7 +124,8 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
|
||||
if([storage isEqual:@"float"]) *(float *)((uint8_t *)&s+offset)=value;
|
||||
else *(uint32_t *)((uint8_t *)&s+offset)=(uint32_t)value;
|
||||
}
|
||||
if(![state valueForParameter:PGSmoothingEnabled])s.amount=s.midtoneDetail=s.highPassDetail=0;
|
||||
s.featureProtection=s.featureProtectionAmount>0;
|
||||
if(![state valueForParameter:PGSmoothingEnabled])s.amount=s.midtoneDetail=s.highPassDetail=s.microDetail=0;
|
||||
if(![state valueForParameter:PGColorEnabled]) {s.skinBrightness=s.skinHue=s.skinSaturation=s.skinEvenTone=s.teethWhitening=s.eyeBrightening=0;s.skinTonePreset=0;}
|
||||
if(![state valueForParameter:PGShapeEnabled]) {s.faceThin=s.faceBigEye=s.faceShort=s.faceNarrow=s.faceChin=s.faceV=s.faceJaw=s.faceCheekbone=s.faceSmallHead=0;s.showTrackBox=0;}
|
||||
return s;
|
||||
@@ -189,6 +199,12 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
|
||||
else [api getFloatValue:&value fromParameter:key atTime:time];
|
||||
values[@(key)]=@(value);
|
||||
}
|
||||
// The old bool can still disable protection. A true value must preserve a
|
||||
// numeric setting already read above; its registered default is one for
|
||||
// old documents that have no independently stored numeric parameter.
|
||||
BOOL legacyFeatureProtection=YES;
|
||||
if([api getBoolValue:&legacyFeatureProtection fromParameter:PGFeatureProtect atTime:time] && !legacyFeatureProtection)
|
||||
values[@(PGFeatureProtectionAmount)]=@0;
|
||||
BOOL legacyDetail=YES;[api getBoolValue:&legacyDetail fromParameter:PGDetailEnabled atTime:time];
|
||||
NSMutableSet *disabled=legacyDetail?[NSMutableSet set]:[NSMutableSet setWithObjects:@(PGHighPass),@(PGSharpness),nil];
|
||||
// Earlier versions put high-pass smoothing under a different group. Keep
|
||||
@@ -196,7 +212,7 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
|
||||
// off, rather than turning a still-active global effect off on first edit.
|
||||
if(![values[@(PGSmoothingEnabled)] boolValue] && legacyDetail && [values[@(PGHighPass)] doubleValue]>0) {
|
||||
values[@(PGSmoothingEnabled)]=@YES;
|
||||
[disabled addObject:@(PGMidtone)];[disabled addObject:@(PGAmount)];
|
||||
[disabled addObject:@(PGMidtone)];[disabled addObject:@(PGAmount)];[disabled addObject:@(PGMicroDetail)];
|
||||
}
|
||||
_state=[PGInspectorState stateWithValues:values disabledParameters:disabled hasEdits:NO];
|
||||
}
|
||||
@@ -232,6 +248,11 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat
|
||||
else if([d[@"kind"] isEqual:@"toggle"] || [d[@"kind"] isEqual:@"master"]) [api setBoolValue:value!=0 toParameter:key atTime:time];
|
||||
else [api setFloatValue:value toParameter:key atTime:time];
|
||||
}
|
||||
BOOL featureProtection=[next isParameterEnabled:PGFeatureProtectionAmount] && [next valueForParameter:PGFeatureProtectionAmount]>0;
|
||||
id<FxParameterRetrievalAPI_v6> reader=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)];
|
||||
BOOL previousProtection=!featureProtection;
|
||||
if(![reader getBoolValue:&previousProtection fromParameter:PGFeatureProtect atTime:time] || previousProtection!=featureProtection)
|
||||
[api setBoolValue:featureProtection toParameter:PGFeatureProtect atTime:time];
|
||||
_state=next;_pendingUntil=NSDate.timeIntervalSinceReferenceDate+.35;_pendingTime=time;_statusMessage=@"";return YES;
|
||||
}
|
||||
- (BOOL)setValue:(double)value forParameter:(UInt32)identifier {
|
||||
文件已重命名,内容未更改。
+5
-3
@@ -202,6 +202,8 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
|
||||
}
|
||||
}
|
||||
NSString *key=[descriptor[@"id"]stringValue];
|
||||
NSString *tooltip=descriptor[@"tooltip"];
|
||||
if(tooltip.length){self.toolTip=tooltip;_label.toolTip=tooltip;_toggle.toolTip=tooltip;_slider.toolTip=tooltip;_valueField.toolTip=tooltip;}
|
||||
_slider.identifier=[@"pg.value."stringByAppendingString:key];_valueField.identifier=[@"pg.number."stringByAppendingString:key];
|
||||
_toggle.identifier=[@"pg.toggle."stringByAppendingString:key];_eye.identifier=[@"pg.enable."stringByAppendingString:key];_reset.identifier=[@"pg.reset."stringByAppendingString:key];
|
||||
}return self;
|
||||
@@ -282,11 +284,11 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
|
||||
@implementation PGInspectorCard
|
||||
- (BOOL)isFlipped { return YES; }
|
||||
- (CGFloat)heightForWidth:(CGFloat)width {
|
||||
if(!_expanded)return 44;CGFloat height=49;for(PGInspectorRow *row in _rows){height+=[row heightForWidth:MAX(0,width-24)];if([row.descriptor[@"id"]unsignedIntValue]==PGJumpGuard)height+=8;}return height+7;
|
||||
if(!_expanded)return 44;CGFloat height=49;for(PGInspectorRow *row in _rows){height+=[row heightForWidth:MAX(0,width-24)];if([row.descriptor[@"id"]unsignedIntValue]==PGFastMulti)height+=8;}return height+7;
|
||||
}
|
||||
- (void)layout {
|
||||
[super layout];CGFloat w=NSWidth(self.bounds);_titleLabel.frame=NSMakeRect(25,13,MAX(70,w-80),22);_master.frame=NSMakeRect(w-39,10,25,25);
|
||||
CGFloat y=49;for(PGInspectorRow *row in _rows){row.hidden=!_expanded;if(!_expanded)continue;CGFloat h=[row heightForWidth:w-24];row.frame=NSMakeRect(12,y,w-24,h);y+=h;if([row.descriptor[@"id"]unsignedIntValue]==PGJumpGuard)y+=8;}
|
||||
CGFloat y=49;for(PGInspectorRow *row in _rows){row.hidden=!_expanded;if(!_expanded)continue;CGFloat h=[row heightForWidth:w-24];row.frame=NSMakeRect(12,y,w-24,h);y+=h;if([row.descriptor[@"id"]unsignedIntValue]==PGFastMulti)y+=8;}
|
||||
}
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
(void)dirtyRect;NSBezierPath *shape=[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(self.bounds,.5,.5) xRadius:13 yRadius:13];
|
||||
@@ -294,7 +296,7 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t
|
||||
[[_accent colorWithAlphaComponent:.22]setStroke];shape.lineWidth=.8;[shape stroke];
|
||||
NSRect pill=NSMakeRect(12,10,MAX(53,[_heading length]*13+20),25);[[_accent colorWithAlphaComponent:.10]setFill];NSBezierPath *p=[NSBezierPath bezierPathWithRoundedRect:pill xRadius:8 yRadius:8];[p fill];[[_accent colorWithAlphaComponent:.32]setStroke];p.lineWidth=.7;[p stroke];
|
||||
if(_expanded){[[PGUIMuted() colorWithAlphaComponent:.20]setStroke];NSBezierPath *line=[NSBezierPath bezierPath];[line moveToPoint:NSMakePoint(12,43)];[line lineToPoint:NSMakePoint(NSWidth(self.bounds)-12,43)];line.lineWidth=.5;[line stroke];
|
||||
for(PGInspectorRow *row in _rows)if([row.descriptor[@"id"]unsignedIntValue]==PGJumpGuard){CGFloat y=NSMaxY(row.frame)+4;[line removeAllPoints];[line moveToPoint:NSMakePoint(12,y)];[line lineToPoint:NSMakePoint(NSWidth(self.bounds)-12,y)];[line stroke];}
|
||||
for(PGInspectorRow *row in _rows)if([row.descriptor[@"id"]unsignedIntValue]==PGFastMulti){CGFloat y=NSMaxY(row.frame)+4;[line removeAllPoints];[line moveToPoint:NSMakePoint(12,y)];[line lineToPoint:NSMakePoint(NSWidth(self.bounds)-12,y)];[line stroke];}
|
||||
}
|
||||
}
|
||||
@end
|
||||
+1
@@ -14,5 +14,6 @@ enum {
|
||||
PGTrackData1=60, PGTrackData2=61, PGTrackData3=62,
|
||||
PGSmoothingEnabled=70, PGColorEnabled=71, PGShapeEnabled=72,
|
||||
PGDetailEnabled=73, PGHelp=74,
|
||||
PGFeatureProtectionAmount=75, PGNonSkinProtection=76, PGMicroDetail=77,
|
||||
PGInspectorPanel=210
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
"FCP-BeautyGirl::FxPlug Name" = "大鱼人像美化";
|
||||
@@ -0,0 +1 @@
|
||||
"FCP-BeautyGirl::FxPlug Description" = "Portrait smoothing, skin tone, face shaping and automatic face tracking.";
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// beatygril
|
||||
// FCP-BeautyGirl
|
||||
//
|
||||
// Created by dayu on 2026/10/21.
|
||||
//
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
@implementation AppDelegate
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
self.window.title = @"大鱼人像美化 · 免费开源";
|
||||
self.window.title = @"FCP-BeautyGirl · 大鱼人像美化";
|
||||
[self.window setContentSize:NSMakeSize(800, 450)];
|
||||
self.window.styleMask &= ~NSWindowStyleMaskResizable;
|
||||
self.window.backgroundColor = [NSColor colorWithRed:0.94 green:0.92 blue:0.85 alpha:1];
|
||||
+7
-7
@@ -20,11 +20,11 @@
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="beatygril" id="1Xt-HY-uBw">
|
||||
<menuItem title="FCP-BeautyGirl" id="1Xt-HY-uBw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="beatygril" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<menu key="submenu" title="FCP-BeautyGirl" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<items>
|
||||
<menuItem title="About beatygril" id="5kV-Vb-QxS">
|
||||
<menuItem title="About FCP-BeautyGirl" id="5kV-Vb-QxS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
|
||||
@@ -38,7 +38,7 @@
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||
<menuItem title="Hide beatygril" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<menuItem title="Hide FCP-BeautyGirl" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<connections>
|
||||
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
||||
</connections>
|
||||
@@ -56,7 +56,7 @@
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||
<menuItem title="Quit beatygril" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<menuItem title="Quit FCP-BeautyGirl" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<connections>
|
||||
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
||||
</connections>
|
||||
@@ -669,7 +669,7 @@
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||
<items>
|
||||
<menuItem title="beatygril Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||
<menuItem title="FCP-BeautyGirl Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||
<connections>
|
||||
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
|
||||
</connections>
|
||||
@@ -679,7 +679,7 @@
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<window title="beatygril" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
|
||||
<window title="FCP-BeautyGirl" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
|
||||
+4
-2
@@ -4,6 +4,8 @@
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>FCP-BeautyGirl · 大鱼人像美化</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
@@ -17,9 +19,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.0</string>
|
||||
<string>1.3.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>14</string>
|
||||
<string>18</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
文件已重命名,内容未更改。
@@ -1,4 +1,4 @@
|
||||
# 大鱼人像美化 · beatygril
|
||||
# 大鱼人像美化 · FCP-BeautyGirl
|
||||
|
||||
基于本仓库的 FxPlug4 初始工程制作的人像美化滤镜,支持 Motion 和 Final Cut Pro。源码使用 Objective-C、Vision、Core Image 与 Metal。
|
||||
|
||||
@@ -6,9 +6,19 @@
|
||||
|
||||
功能包括磨皮、肤色、细节、牙齿美白、眼睛提亮、九类脸型调整、自动人脸跟随和多人处理。原版 MSE18V2 的静态分析依据、近似实现与尚未对齐的部分见 [分析说明](docs/analysis/REA-分析与复刻说明.md)。本版尚未完成原版逐像素与复杂运动跟踪对照。
|
||||
|
||||
1.3.2(17)已统一工程、APP、插件类名和应用ID,正式安装为 `FCP-BeautyGirl.app` / `com.dayu.fcpbeautygirl`,嵌套插件ID为 `com.dayu.fcpbeautygirl.fxplug`。旧APP已迁移清理,滤镜UUID、参数编号和归档格式保持兼容。1901项自动回归及身份迁移检查通过;APP和含配套模板的PKG均已签名、公证、粘附票据和验证。更名后的旧工程重开仍由用户实测。
|
||||
|
||||
1.3.3(18)已对齐目标2.4.0的默认pin跟踪主链,并改用新版瘦脸/大眼局部公式。完整点、质量筛选、连续框、坏帧保持及同帧复用已补齐;同点合成场与目标Metal最大误差约0.005523像素。草帽素材469帧的离线采样不代表原生时间线的闪烁已经修复,仍需同段实测。详见[本轮分析与验证](docs/analysis/跟踪闪烁对齐分析.md)。2122项自动回归通过。APP和包含指定四项模板资源的PKG均已签名、公证Accepted并验证票据;1.3.3已安装到唯一正式路径,签名、票据、Gatekeeper和PluginKit发现通过,本次临时APP与公证ZIP已清理。原生视觉仍待同段素材实测。
|
||||
|
||||
## 使用
|
||||
|
||||
正式安装路径为 `/Library/Plug-Ins/FxPlug/beatygril.app`。Motion 滤镜分类为「大鱼」,滤镜名「大鱼人像美化」。Final Cut Pro 在「效果 → 大鱼磨皮瘦脸 → 大鱼人像美化」中使用配套 Motion 效果,模板目录必须同时保留 `.moef` 与 `Drop Zone.tiff`。美化会随当前帧的人脸自动更新,不需要点击分析。界面以磨皮、美白、瘦脸三张卡片呈现,默认跟随主要人脸;多人模式对多脸变形。单项眼睛可暂时停用并保留数值,右侧箭头恢复默认;磨皮半径、饱和度、锐化和整体混合等收在「更多设置」。旧手动分析与调试参数仅保留隐藏兼容,实际输出统一使用实时自动跟随。
|
||||
正式安装路径为 `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app`。Motion 滤镜分类为「大鱼」,滤镜名「大鱼人像美化」。Final Cut Pro 在「效果 → 大鱼磨皮瘦脸 → 大鱼人像美化」中使用配套 Motion 效果,模板目录必须同时保留 `.moef` 与 `Drop Zone.tiff`。美化会随当前帧的人脸自动更新,不需要点击分析。界面以磨皮、美白、瘦脸三张卡片呈现,默认跟随主要人脸;多人模式对多脸变形。单项眼睛可暂时停用并保留数值,右侧箭头恢复默认;磨皮半径、饱和度、锐化和整体混合等收在「更多设置」。旧手动分析与调试参数仅保留隐藏兼容,实际输出统一使用实时自动跟随。
|
||||
|
||||
1.3.0 的磨皮卡片依次提供「磨皮程度、微细锐化、五官保护、非肤色区保护」。两种保护默认 100%;降低五官保护让五官区域参与更多磨皮,降低非肤色区保护则扩大磨皮范围,均不扩大肤色提亮范围。微细锐化在局部支持区域恢复纹理;旧全局磨皮和全局锐化仍保留在更多设置,旧工程的参数与归档继续兼容。迁移证据、实现边界与验证见[新版磨皮参数迁移](docs/analysis/新版磨皮参数迁移.md)。1.3.0 的新增参数已随 1.3.1 一并提供。
|
||||
|
||||
1.3.1(16)修复 V 脸影响眼区的问题,改为四组下颌轮廓到外唇的局部采样,并对齐新目标的 0.065 强度映射。1901 项自动检查通过,APP 与本机 PKG 工坊制作的安装包均已签名、公证和验证。正式 APP 已安装;新效果的原生宿主视觉仍由用户实测。原理与边界见 [V 脸下颌区域修复](docs/analysis/V脸下颌区域修复.md)。
|
||||
|
||||
当前 [1.3.3 发行入口](https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.3) 与 [大鱼文章](https://dayu.media/15593/) 是本版发布入口,安装包包含「大鱼磨皮瘦脸」分类的配套效果及资源,源码快照也已同步。
|
||||
|
||||
## 开发和恢复
|
||||
|
||||
@@ -16,14 +26,14 @@
|
||||
|
||||
```sh
|
||||
./scripts/test.sh
|
||||
PAINTFCP_HOST_ASAN=1 ./scripts/test-host.sh
|
||||
PAINTFCP_OSC_ASAN=1 ./scripts/test-osc.sh
|
||||
xcodebuild -project beatygril/beatygril.xcodeproj -scheme 'Wrapper Application' -configuration Release -derivedDataPath /tmp/paintfcp-build -destination 'generic/platform=macOS' build
|
||||
FCP_BEAUTYGIRL_HOST_ASAN=1 ./scripts/test-host.sh
|
||||
FCP_BEAUTYGIRL_OSC_ASAN=1 ./scripts/test-osc.sh
|
||||
xcodebuild -project FCP-BeautyGirl/FCP-BeautyGirl.xcodeproj -scheme 'FCP-BeautyGirl' -configuration Release -derivedDataPath /tmp/fcp-beautygirl-build -destination 'generic/platform=macOS' build
|
||||
```
|
||||
|
||||
工程从 `/Library/Developer/SDKs/FxPlug.sdk` 读取头文件与链接信息,从 `/Library/Developer/Frameworks` 嵌入可运行的 Apple 框架。构建默认使用团队 B3W25FX5H5 的 Developer ID Application 身份;正式交付使用 `python3 scripts/deliver.py` 完成公证、粘附和安装;安装前先关闭 Motion 与 FCP,脚本在检测到宿主仍运行时保留原安装版并停止。原生验收完成后继续脚本的清理阶段,清除临时注册与 APP 副本。
|
||||
|
||||
公开源码:[GitHub · FCP-BeatyGril](https://github.com/FAMEDaYu/FCP-BeatyGril)。大鱼站备份:`https://dayu.media/git/dayu/paintfcp-fxplug.git`。恢复入口见 [RECOVERY.md](RECOVERY.md),当前验证记录见 [验证记录](docs/验证记录.md)。原始模板保存在 `baseline-20261021` 标签。
|
||||
公开源码:[GitHub · FCP-BeautyGirl](https://github.com/dayumeida/FCP-BeautyGirl)。大鱼站备份:`https://dayu.media/git/dayu/paintfcp-fxplug.git`。恢复入口见 [RECOVERY.md](RECOVERY.md),当前验证记录见 [验证记录](docs/验证记录.md)。原始模板保存在 `baseline-20261021` 标签。
|
||||
|
||||
继续开发或移交时先读[项目交接文档](docs/项目交接.md),包含当前发布状态、源码入口、坐标与交互约定、验收边界,以及签名打包和双远端保存流程。
|
||||
|
||||
@@ -61,4 +71,4 @@ xcodebuild -project beatygril/beatygril.xcodeproj -scheme 'Wrapper Application'
|
||||
|
||||
`large.png`(640×360)和 `small.png`(192×108)与 `.moef` 同目录,安装器安装后重新锁定。手动复制或从 Git 恢复模板时,需对这两个 PNG 重新执行 `chflags uchg`,不能锁定整个模板目录。FCP 当前分类为「大鱼磨皮瘦脸」,Motion 原生滤镜分类仍为「大鱼」。
|
||||
|
||||
GitHub 提供公开源码、提交历史和版本标签;[1.2.0 Release](https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0) 提供正式签名公证安装包。大鱼站 Git 备份仍受站点登录与会员网关限制,发布文章另提供公开源码快照;安装包始终免费。
|
||||
GitHub 提供公开源码、提交历史和版本标签;[1.2.0 Release](https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.2.0) 提供正式签名公证安装包。大鱼站 Git 备份仍受站点登录与会员网关限制,发布文章另提供公开源码快照;安装包始终免费。
|
||||
+57
-2
@@ -1,7 +1,10 @@
|
||||
# 恢复说明
|
||||
|
||||
当前产品身份自1.3.2(17)统一为FCP-BeautyGirl:工程 `FCP-BeautyGirl/FCP-BeautyGirl.xcodeproj`、scheme `FCP-BeautyGirl`、APP `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app`、主ID `com.dayu.fcpbeautygirl`、插件ID `com.dayu.fcpbeautygirl.fxplug`。签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`,APP公证Accepted `559eedf0-048f-4d0e-b013-6a187695f2da`,已安装并迁移清理旧APP;程序与滤镜参数、UUID保持兼容。中央身份定义见product.json,旧名称只用于经过ID、签名团队和滤镜UUID验证的迁移。下文历史版本保留各自当时的名称与路径。
|
||||
|
||||
|
||||
- 大鱼备份远程(origin):`https://dayu.media/git/dayu/paintfcp-fxplug.git`
|
||||
- GitHub 公开远程(github):`https://github.com/FAMEDaYu/FCP-BeatyGril.git`
|
||||
- GitHub 公开远程(github):`https://github.com/dayumeida/FCP-BeautyGirl.git`
|
||||
- 本地项目根:`/Users/dayu/Documents/PaintFCP`
|
||||
- 工作分支:`main`
|
||||
- 修改前版本标签:`baseline-20261021`,完整 SHA:`1746f38398588e2367abb37a5c2b31cb64042429`
|
||||
@@ -104,4 +107,56 @@ Motion/FCP原生验收范围及未完成项见`docs/verification/v1.1.2/native-q
|
||||
|
||||
## GitHub 公开恢复副本
|
||||
|
||||
GitHub 远端 `https://github.com/FAMEDaYu/FCP-BeatyGril.git` 已完成完整历史与七个标签的推送,`origin` 及其 main 上游保持大鱼仓库。独立匿名克隆恢复节点为 `356683b41af702d6c0143ad7fa5f540d752d6e14`,197 文件逐字节核验、strict/full fsck 和全部标签回读通过。后续 main 补充发布说明与验证文档,产品源码保持相同。GitHub Release 的公证安装包已匿名下载核对哈希、签名和票据。详见 `docs/GitHub同步说明.md` 和 `docs/verification/github/`。
|
||||
GitHub 远端 `https://github.com/dayumeida/FCP-BeautyGirl.git` 已完成完整历史与七个标签的推送,`origin` 及其 main 上游保持大鱼仓库。独立匿名克隆恢复节点为 `356683b41af702d6c0143ad7fa5f540d752d6e14`,197 文件逐字节核验、strict/full fsck 和全部标签回读通过。后续 main 补充发布说明与验证文档,产品源码保持相同。GitHub Release 的公证安装包已匿名下载核对哈希、签名和票据。详见 `docs/GitHub同步说明.md` 和 `docs/verification/github/`。
|
||||
|
||||
|
||||
## 1.3.0 新面板参数恢复
|
||||
|
||||
签名源码节点 `2f2c081980dc610ac810f8daf92da8966f310802` 已推送并读回核验 origin 与 github 的 `codex/new-beauty-controls` 分支。两个远端地址沿用本文既有配置。独立远端克隆与 strict/full fsck、205 个受跟踪文件逐字节比较通过,见 `docs/verification/v1.3.0/recovery-verification.json`。无 LFS、子模块;依赖与签名凭据仍需单独恢复。
|
||||
|
||||
本节点增加五官保护强度、非肤色区保护和局部微细锐化,PGBeautySettings v2 兼容旧 160 字节 v1 状态,面板归档仍为 schema 1。测试命令不变,1636 项通过。恢复签名源码时克隆并切换该分支,或 `git switch --detach 2f2c081980dc610ac810f8daf92da8966f310802`。
|
||||
|
||||
1.3.0(15)已正式安装到 `/Library/Plug-Ins/FxPlug/beatygril.app`。签名、通用架构、公证票据、Gatekeeper 和 PluginKit 正式路径均通过,已清理本次构建、旧 APP 备份和公证 ZIP。最终回执见 `docs/verification/v1.3.0/delivery-receipt.json`、`installed-verification.json`;`prepared-release.json` 保留安装前状态。`v1.3.0` 标签包含签名源码及后续交付文档。本次没有生成新 PKG 或更新文章,1.2.0 的公开发行资料继续有效;新滑杆的原生宿主视觉仍由用户测试。
|
||||
|
||||
|
||||
## 1.3.1 V 脸下颌修复恢复
|
||||
|
||||
签名源码完整 SHA 为 `7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f`,APP 1.3.1(16),分支 `codex/v-face-jaw-fix`。origin 与 github 同名分支已推送并回读一致。已从 origin 独立克隆该节点,219个受跟踪文件字节和执行位一致、strict/full fsck及Xcode工程读取通过,无LFS或子模块;见 `docs/verification/v1.3.1/recovery-verification.json`。恢复依赖和签名入口沿用本文现有配置,用户帧和私钥不作为源码依赖保存。
|
||||
|
||||
V 脸现在为四组下颌到外唇局部 pin,映射为 V×0.065,无新版目标已取消的旧尺寸增益。此前瘦脸/下巴/短脸/下颌骨仍保留旧版本映射,大眼/窄脸/颧骨/小头和整体组合保留近似边界。1901项全套及1561项重叠真实帧几何ASan通过。Apple公证 Accepted `e353b701-2fc2-4fcc-b03e-69af7735400f`、staple/validate通过;已在用户确认退出宿主后完成1.3.1正式安装、身份/票据/注册核验和临时副本清理。后续FCP仍有后台进程,通过正常退出菜单结束后才替换APP。PKG由本机PKG工坊CLI制作,包含用户指定分类4项资源,Installer签名、公证Accepted 78105340-306f-4629-8670-772760d4cb9a、票据、Gatekeeper、载荷及隔离脚本均通过;详见同版本交付回执和验证记录。
|
||||
|
||||
|
||||
1.3.1最终发行标签为 `v1.3.1`,完整SHA `b35b4a5d1ca252d2f83c798613560a768274de3c`。GitHub已匿名独立克隆恢复并比对232个受跟踪文件的字节/执行位、strict/full fsck和恢复PKG签名/票据;产品源码与签名节点7fa3298完全一致。见 `docs/verification/v1.3.1/final-tag-recovery.json`。两个远端main纳入该标签后继续记录交付文档,不移动标签。文章15593和GitHub/大鱼Release已更新,GitHub与文章安装包/源码下载字节均校验,完整入口见 `docs/GitHub同步说明.md`。
|
||||
|
||||
|
||||
GitHub于2026-10-22更正仓库名为 `FCP-BeautyGirl`,远端为 `https://github.com/dayumeida/FCP-BeautyGirl.git`。更名后的恢复检查点 `6a29d52a9ad667665da4acf75017c008fa0a566d` 已通过新地址匿名独立克隆、239个文件字节/执行位和strict/full fsck核验,产品源码与此前正式版相同。Release、附件和原有标签保留,文章及本地远程/仓库目录表均已更新;详见 `docs/verification/github/rename-recovery-20261022.json`。
|
||||
|
||||
|
||||
GitHub用户名现为 `dayumeida`,账号ID117798680保持一致。当前公开远端 `https://github.com/dayumeida/FCP-BeautyGirl.git` 的恢复检查点 `2faf7de77929cf7707645ebb38095b03d5729647` 已通过匿名独立克隆、241文件字节/执行位和strict/full fsck核验,产品源码与账号更名前一致。两个仓库的全部分支/标签及Release附件均保留;当前文章、本地github远端和仓库目录表已同步。回执见 `docs/verification/github/username-recovery-20261022.json`。
|
||||
|
||||
|
||||
## 1.3.2 统一产品身份
|
||||
|
||||
发行入口为 `v1.3.2`;正式 APP 源码为 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新机器按 `product.json` 的工程、scheme 与路径恢复,运行 `python3 scripts/deliver.py --wait-for-hosts --user-tests`;旧产品先验证 Bundle ID、签名团队和滤镜 UUID,再迁移并支持失败回滚。最终包为 `releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg`,SHA-256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`,签名、公证 Accepted `4a831775-2317-4372-a4cc-102415657ea3`、票据和 Gatekeeper 均通过。正式 APP 已安装并清理旧身份。1901 项自动回归、8 项 APP 迁移、8 项最终 PKG 身份脚本迁移与模板隔离测试通过;未运行真实 installer,原生旧工程重开仍待用户检查。
|
||||
|
||||
源码包须从发行标签导出,排除 PKG 二进制并加入 SOURCE-SNAPSHOT.json。发布与独立克隆恢复回执位于 `docs/verification/v1.3.2/`,不包含用户人脸素材、签名私钥或公证凭据。历史标签和旧版本安装包保留,不覆盖。
|
||||
|
||||
|
||||
1.3.2 发行标签完整 SHA 为 `8a70d38b7cd17e0ea530c5226f2be8c2df4308b3`。独立匿名 GitHub 克隆 271 个文件的字节/blob/执行位、strict/full fsck、Xcode 工程读取和恢复包签名/票据/Gatekeeper 均通过,无 LFS/子模块,临时克隆已清理。见 `docs/verification/v1.3.2/final-tag-recovery.json`。GitHub 与文章的安装包、源码快照已匿名下载核对哈希,源 ZIP 对应本标签;后续 main 补充回执,不移动发行标签或改变已签名产品源码。
|
||||
|
||||
|
||||
## 1.3.2 后续跟踪闪烁分析
|
||||
|
||||
分析节点 `a0c5357efd87a63dbee6269d9335e6aa3ba78799` 保留新目标2.4.0静态证据、实际当前FCP草帽素材的469帧独立采样摘要与两个通用诊断入口;产品源码和安装版仍为v1.3.2,未宣布闪烁修复。独立匿名克隆284文件/fsck/合成诊断重建复现通过,无LFS或子模块。具体运行与边界见 `docs/analysis/跟踪闪烁对齐分析.md`,用户素材和完整真实关键点不在仓库中。
|
||||
|
||||
|
||||
## 1.3.3 跟踪稳定链
|
||||
|
||||
签名产品源码为 `edf64ace6bc17f4db3b2dba71897997809c1029d`,工作分支 `codex/tracking-stability-240`,发行入口 `v1.3.3`。Release通用APP保持固定身份与路径,公证Accepted `379a432b-ccca-4676-9567-30dc49bb2400`;PKG由本机PKG工坊基础包加入已验证的身份迁移脚本后重新签名,公证Accepted `3b44edbb-612d-47b2-8b11-e79874b2c635`,4,905,560 bytes,SHA-256 `214c109af60bce72046c89ff12b364938b6c00c3a348fa3740dabef661649e0d`。包含用户指定“大鱼磨皮瘦脸”分类的moef、Drop Zone.tiff与两张锁定缩略图,payload字节及隔离安装/回滚核验通过;没有执行真实installer。
|
||||
|
||||
用户保存退出后,已用 `python3 scripts/deliver.py --resume-prepared --wait-for-hosts --user-tests` 安装到唯一正式路径,已核验签名、Team ID/Bundle ID、票据、Gatekeeper与PluginKit;本次构建、公证ZIP和旧APP备份已清理。新机器不存在本机暂存APP时,从标签恢复并按既有 `deliver.py --wait-for-hosts --user-tests` 重新编译签名公证,或安装发行PKG;不要复制本机prepared回执当作新机器已安装证明。
|
||||
|
||||
独立匿名GitHub克隆签名源码节点304文件字节/模式及strict/full fsck通过,重建跟踪87项和眼部126项;无需目标APP、用户视频或Apple私钥即可运行这两组合成检查。完整正常回归2122项;目标同点坐标场40例最大误差0.005523px。469帧离线草帽采样均通过质量筛选,不能代表原生时间线闪烁已消除。无LFS/子模块;SDK、签名私钥和公证凭据按本文既有说明独立恢复。最终标签恢复与发布回执补充至 `docs/verification/v1.3.3/`,历史标签不移动。
|
||||
|
||||
|
||||
1.3.3发行标签固定为 `20896de9ee9390d8e6f8ee113cfb04d4461ecc3e`;匿名独立恢复320文件的字节/blob/模式、strict/full fsck、Xcode工程与恢复PKG签名/票据/Gatekeeper通过,临时克隆已删除。GitHub/文章安装包及源码ZIP四项匿名下载字节核验通过,源ZIP为上述标签排除PKG后的316文件快照,SHA256 `c0870136466e402d05cf6f1014b9da40ef7630e9ddaefc9311a9d8057a6cc3e7`。后续main补充安装、发布与副本清理回执,不移动标签或改变签名产品源码;正式安装结果以 `docs/verification/v1.3.3/delivery-receipt.json` 与 `installed-verification.json` 为准。原生时间线闪烁改善仍待用户同段实测。
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
"beatygril::FxPlug Name" = "beatygril";
|
||||
@@ -1,4 +0,0 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
"beatygril::FxPlug Description" = "A helpful description of\nwhat this plugin does.";
|
||||
|
||||
+39
-5
@@ -1,10 +1,10 @@
|
||||
# GitHub 同步与恢复
|
||||
|
||||
公开源码:https://github.com/FAMEDaYu/FCP-BeatyGril
|
||||
公开源码:https://github.com/dayumeida/FCP-BeautyGirl
|
||||
|
||||
正式安装包:https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.2.0
|
||||
正式安装包:https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.3
|
||||
|
||||
本地 `github` 远端指向上述 GitHub 仓库,`origin` 继续指向大鱼仓库,`main` 仍跟随 `origin/main`。当前项目的完整提交历史、main 和七个版本标签已推送,两端引用与本地一致;未改写历史或覆盖标签。后续更新需要分别推送到 origin 和 github,不会自动定时同步。
|
||||
本地 `github` 远端指向上述 GitHub 仓库,`origin` 继续指向大鱼仓库,`main` 仍跟随 `origin/main`。当前项目的完整提交历史、main 和全部现有版本标签已推送,两端引用与本地一致;未改写历史或覆盖标签。后续更新需要分别推送到 origin 和 github,不会自动定时同步。
|
||||
|
||||
## 已验证的 GitHub 恢复节点
|
||||
|
||||
@@ -13,11 +13,45 @@
|
||||
安装包:`Dayu-Portrait-1.2.0.pkg`,5,011,005 bytes,SHA-256 `5bd77c28b3a7e54f3d4060be1f16bcb145d9bc4d6b9cfb9eb137c01130440243`。Release 标签 `v1.2.0` 仍指向 `3c7261c3a861b9f4704cfb36055d7b500c239dab`,没有重新编译或改动正式安装包。
|
||||
|
||||
```sh
|
||||
git clone https://github.com/FAMEDaYu/FCP-BeatyGril.git
|
||||
cd FCP-BeatyGril
|
||||
git clone https://github.com/dayumeida/FCP-BeautyGirl.git
|
||||
cd FCP-BeautyGirl
|
||||
git switch --detach 356683b41af702d6c0143ad7fa5f540d752d6e14
|
||||
```
|
||||
|
||||
本项目没有 LFS 或子模块。编译仍需自行安装 Xcode 和 Apple FxPlug SDK;签名私钥与公证凭据不在 Git 内。GitHub 公共克隆无需登录;大鱼备份仍受站点登录和会员网关限制。两边都只承诺已经提交、推送并核验的节点。
|
||||
|
||||
源代码编写署名:代码由 OpenAI + Codex 全程编写,站长仅参与调试和测试。
|
||||
|
||||
|
||||
## 1.3.1 发行与恢复
|
||||
|
||||
main已快进纳入1.3.0磨皮参数和1.3.1的V脸下颌修复;origin和github的main及v1.3.1引用已回读核验。v1.3.1固定完整SHA为 `b35b4a5d1ca252d2f83c798613560a768274de3c`,签名APP源码为 `7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f`。独立匿名GitHub克隆232文件字节与执行位一致、strict/full fsck和恢复PKG签名/票据通过。无LFS或子模块。后续main仅补充发布记录,不改写标签。
|
||||
|
||||
GitHub Release已提供 `Dayu-Portrait-1.3.1.pkg`(5,011,286 bytes,SHA256 `a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927`)和源码ZIP(9,682,532 bytes,SHA256 `7c335f54717a73e710ef484fc9f7b90864211c128a0f217bf170aa092333f228`)。两者匿名重新下载哈希一致,PKG签名和票据通过。源码快照基于上述v1.3.1节点,排除PKG本体而保留全部构建源码、模板、素材与验证文档。
|
||||
|
||||
大鱼站同名Release附件上传与名称/大小回读通过,下载入口仍受站点登录保护;未宣称API令牌可直接回读该浏览器附件入口。文章15593已就地更新,主包和源码链接的新文件哈希通过,免费规则、封面、作者、分类及未修改资源字段保持一致。正常URL和新请求的前台版本、安装/使用/故障说明及三项SEO均核验,未登录页面显示免费及登录获取入口;未下测试订单。详见verification/v1.3.1。
|
||||
|
||||
|
||||
## 2026-10-22 仓库名称拼写更正
|
||||
|
||||
GitHub仓库从 `FAMEDaYu/FCP-BeatyGril` 更名为 `FAMEDaYu/FCP-BeautyGirl`,仓库ID `1428817365` 保持一致。更名前后全部分支/标签SHA、Release与附件ID/大小一致,未另建仓库或改写历史。本地github远端已改为 `https://github.com/dayumeida/FCP-BeautyGirl.git`,origin和main上游仍为原大鱼仓库。现有发布标签、已公证APP/PKG及源码快照保留原始字节,旧快照里的旧链接由GitHub重定向到新地址;当前文档、文章和Release说明使用新地址。插件APP产品名、Bundle ID和安装路径沿用原配置。更名核验见verification/github/rename-20261022.json。
|
||||
|
||||
|
||||
## 2026-10-22 用户名更改
|
||||
|
||||
用户将GitHub登录名从 `FAMEDaYu` 改为 `dayumeida`,账号ID117798680保持不变。两个公开仓库迁移到dayumeida名下:FCP-BeautyGirl(ID1428817365)和FCPX-(ID904215594)。更名前后全部分支/标签SHA及Release/附件ID、名称、大小一致。当前项目github远端为 `https://github.com/dayumeida/FCP-BeautyGirl.git`,origin及main上游保持原大鱼仓库;文章15593、活动文档和Release说明更新为新地址。正式版本标签、公证APP/PKG和源码快照保留原始字节,不为账号更名重新构建。个人主页新地址为 `https://github.com/dayumeida`,旧个人主页不提供重定向;仓库旧地址由GitHub重定向。历史验证回执保留当时用户名。账号更名核验见verification/github/username-20261022.json。
|
||||
|
||||
|
||||
## 1.3.2 产品身份统一
|
||||
|
||||
发行标签 `v1.3.2`,正式 APP 签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新工程和 APP 名为 FCP-BeautyGirl,应用标识及安装路径见 product.json;旧身份仅保留经过验证的迁移入口。GitHub、大鱼 Release 和文章 15593 使用新名称安装包及源码快照,历史发行资料不改写。当前交付与发布核验保存在 verification/v1.3.2。
|
||||
|
||||
|
||||
1.3.2 标签完整 SHA `8a70d38b7cd17e0ea530c5226f2be8c2df4308b3`,双远端引用回读一致。已匿名独立克隆核对 271 个文件、strict/full fsck、Xcode 工程和恢复包签名/票据/Gatekeeper。正式包 SHA256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`,源码 ZIP SHA256 `c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834`;GitHub 与文章四项匿名下载均与本地字节一致。文章作者、封面和免费规则保留,正常及新请求前台版本/路径/SEO通过。大鱼 Release 只回读附件名称/大小,未绕过站点登录网关。
|
||||
|
||||
|
||||
## 1.3.3 跟踪稳定链发行
|
||||
|
||||
发行标签 `v1.3.3` 固定SHA `20896de9ee9390d8e6f8ee113cfb04d4461ecc3e`,签名产品源码 `edf64ace6bc17f4db3b2dba71897997809c1029d`。双远端main、工作分支和标签已同步并回读;后续main补充交付回执,不移动标签。匿名独立恢复320文件字节/blob/模式、strict/full fsck、Xcode工程和恢复PKG签名/票据/Gatekeeper通过,签名源码节点另重建跟踪87项和眼部126项,临时克隆已清理。
|
||||
|
||||
GitHub与大鱼Release提供 `FCP-BeautyGirl-1.3.3.pkg`(4,905,560 bytes,SHA256 `214c109af60bce72046c89ff12b364938b6c00c3a348fa3740dabef661649e0d`)与标签源码ZIP(10,089,451 bytes,SHA256 `c0870136466e402d05cf6f1014b9da40ef7630e9ddaefc9311a9d8057a6cc3e7`)。GitHub及文章四项匿名下载字节核验通过;大鱼Release仍只回读附件名/大小,未绕过登录网关。文章15593保留封面、作者、分类和免费规则,正常/新请求前台版本、原生代码区块与SEO通过。APP已正式安装,原生时间线闪烁改善尚待用户实测;详见 verification/v1.3.3。
|
||||
@@ -0,0 +1,42 @@
|
||||
# V 脸下颌区域修复
|
||||
|
||||
2026-10-22,针对用户报告「V 脸作用到眼睛,应作用于下颌」。目标为本机 MSE18V2 2.4.0(20260724150000),产品修复版本为 1.3.1(16)。
|
||||
|
||||
## 原因与修改
|
||||
|
||||
1.3.0 仍使用脸框上的宽范围高斯带及纵向位移近似 V 脸。它不依赖真实下颌轮廓,在真实人像上能测到眼区变化。不是面板标签或参数 ID 接错;本次只替换 V 脸几何场。
|
||||
|
||||
新版目标的 AIR 按 `69→39、65→35、70→26、64→34` 顺序执行四组局部逆向采样。起点都是下颌轮廓,锚点都是外唇。每步使用前一步更新后的 q:
|
||||
|
||||
```text
|
||||
r = length(anchor − origin)
|
||||
if r > 0.0001:
|
||||
weight = clamp(1 − length(q − origin) / r, 0, 1)
|
||||
q = clamp(q − (anchor − origin) × ratio × weight, 0, 1)
|
||||
```
|
||||
|
||||
CPU 函数 `0x10002fb74` 从参数 `+0x90` 读取 V 值,乘位于 `0x100085ea0` 的 double `0.065` 和公共强度,再转 float 写入 shape 结构的 `+8`。新版三个 shader helper 都没有旧版的 `280/尺寸` 增益;本项目 V 使用 `clamp(faceV,0,1)×0.065`,整体混合沿用现有产品链。公共强度各调用方的完整来源尚未追踪,不将整体混合宣称为原版该参数的等价重建。
|
||||
|
||||
生产实现复用局部 pin 核心,四步严格顺序更新,与图像/四张支持蒙版共享同一坐标场;完整 76 点缺失或不合法时安全直通。Core Image 坐标和关键点一起转换到 Y 向下的全图 UV,结束后一起转回,支持非零图像原点、横竖画幅和歪头。
|
||||
|
||||
## 静态证据与复现
|
||||
|
||||
原始 APP、metallib、完整 AIR 与用户帧仅留本机 build,不是构建依赖。源码没有嵌入目标二进制、私有模型或授权逻辑。
|
||||
|
||||
- 原 APP 嵌套 Mach-O(fat)SHA-256:`577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`。
|
||||
- arm64 切片 SHA-256:`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。
|
||||
- metallib SHA-256:`856849c45cea2c8f083eeba06a9e318c450f4a56694b438d1a5ba8ef752a0ee0`。
|
||||
- `xcrun metal-objdump --metallib --disassemble` 输出 SHA-256:`1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9`;V 分支 3364–3431 行,四组点索引在 3374、3376、3378、3380 行。
|
||||
- 精简 AIR 摘录:[vface-air.txt](vface-air.txt);CPU 字段/系数与分析条件:[vface-findings.json](vface-findings.json);REA CPU 汇编和常量证据:[rea-vface-evidence.json](rea-vface-evidence.json)。REA 操作为只读,未运行原 APP 或原 shader。
|
||||
|
||||
## 验证
|
||||
|
||||
修改前隔离 V 测试复现:NASA 人像瞳孔 6 的位移约 0.031493 像素;宿主物理行序测试四种原点组合的 V 输出与独立 upright 参考均不符。原宿主输出两眼区像素变化量分别为 12824、19304,下颌为 195206。
|
||||
|
||||
修改后瞳孔检查通过;宿主四种原点组合的 V 眼区像素变化量均为 0,下颌为 39246,独立 upright 对照最大差 1/255、均差 0.000124/255。数值场覆盖 4 种画幅、正侧脸和歪头、半强度、小脸不带旧增益、顺序组合、缺点/坏点以及四张蒙版同步。独立的真实解剖位置检查要求下颌有位移且两瞳孔位移小于 0.002 像素,避免只用复制实现的数值公式验收。
|
||||
|
||||
完整自动回归:1901 项通过(57 Beauty、116 Face、1033 几何、370 Host ASan、98 OSC ASan、227 Inspector ASan)。真实用户帧专项另记交付验证;与基础用例重叠,不相加。正式安装和原生宿主 V 脸视觉验收状态见 [验证记录](../验证记录.md)。
|
||||
|
||||
## 范围
|
||||
|
||||
V 脸现在加入已恢复的五项局部控制。瘦脸、下巴、短脸、下颌骨沿用此前版本的尺寸增益;未将新版目标的其他差异混入本次修复。大眼、窄脸、颧骨和小头仍为近似,整条混合控制链的数学、顺序和最终像素尚未全部对齐。静态重建、离屏/接口检查不等于原版 shader 的运行时逐像素比较,也不等于 Motion/FCP 原生视觉验收。
|
||||
@@ -0,0 +1 @@
|
||||
{"artifacts":[{"architecture":"arm64","digest":{"sha256":"afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df"},"format":"mach-o"}],"captures":[],"environments":[],"providers":[{"id":"ghidra","name":"Ghidra","version":"12.1.4"}],"records":[{"analysis_profile":{"digest":"20565088524a2d0359b9b96f46ac48e679d774c7b0092c56abc06de8fdbec11c","parameters":{"analyzer_preset":"ghidra-default","annotation_policy":"atomic-function-entry-metadata-v1","architecture":"arm64","available_architectures":["arm64"],"compiler_spec_id":"auto-default","decompiler_jump_loads":true,"function_body_evidence":"complete-inclusive-ranges-v1","function_boundary_observations":"ghidra-terminal-call-limitations-v1","function_references":"complete-body-and-entry-reference-manager-v2","import_mode":"ephemeral-source-immutable","instruction_flow_evidence":"decoded-return-pcode-v1","jump_table_evidence":"typed-case-default-blocks-v1","language_id":"auto-from-header","load_image_observations":"source-mappings-entry-context-v2","loader":"auto-from-header","location_resolution":"explicit-address-exact-entry-symbol-first-v3","no_return_repair":"returning-imports-decoded-return-v2","process_launch":"inspected-jvm-launch-support-v1","string_inventory_evidence":"defined-data-coverage-v1","target_format":"mach-o","target_kind":"executable"},"provider":{"id":"ghidra","name":"Ghidra","version":"12.1.4"}},"authority":"shipped-artifact","confidence":"observed","environment":null,"evidence_id":"ev_32b6ee46d4fb5eab563883ba73e35a458d5da21229b8977fddcb4df656517152","evidence_links":[],"limitations":["The session serves operations only after Ghidra reports default auto-analysis complete; incomplete analysis does not expose partial results.","The imported Program and temporary project are ephemeral and deleted on close. Annotation operations edit session database metadata; original executable bytes are never written.","Cancelling an active Ghidra request terminates its ephemeral database and discards session annotations. The selected target remains open; the next provider query imports the original artifact again.","Default-space addresses use lowercase 0x-prefixed hexadecimal; other address spaces use <percent-encoded-space>:0x<hex>.","Bytes reflect Ghidra's initialized memory, including loader fixups. Reads stop at an unmapped or uninitialized byte and report completeness explicitly.","macOS sessions require a matching executable Ghidra native decompiler; REA checks for it but does not build native components or change Gatekeeper quarantine state."],"locations":[],"normalized_result":{"address":"0x100085ea0","bytes_hex":"a4703d0ad7a3b03f9a9999999999a93f","complete":true,"requested_bytes":16,"returned_bytes":16},"operation":"read_bytes","parameters":{"address":"0x100085ea0","length":16},"predicate_type":"rea.analysis","provider":{"id":"ghidra","name":"Ghidra","version":"12.1.4"},"raw_result":{"address":"0x100085ea0","bytes_hex":"a4703d0ad7a3b03f9a9999999999a93f","complete":true,"requested_bytes":16,"returned_bytes":16},"subject":{"architecture":"arm64","digest":{"sha256":"afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df"},"format":"mach-o","local_path":"/Users/dayu/Documents/PaintFCP/build/body-analysis/MSE18V2-arm64","name":"MSE18V2-arm64"}},{"analysis_profile":{"digest":"20565088524a2d0359b9b96f46ac48e679d774c7b0092c56abc06de8fdbec11c","parameters":{"analyzer_preset":"ghidra-default","annotation_policy":"atomic-function-entry-metadata-v1","architecture":"arm64","available_architectures":["arm64"],"compiler_spec_id":"auto-default","decompiler_jump_loads":true,"function_body_evidence":"complete-inclusive-ranges-v1","function_boundary_observations":"ghidra-terminal-call-limitations-v1","function_references":"complete-body-and-entry-reference-manager-v2","import_mode":"ephemeral-source-immutable","instruction_flow_evidence":"decoded-return-pcode-v1","jump_table_evidence":"typed-case-default-blocks-v1","language_id":"auto-from-header","load_image_observations":"source-mappings-entry-context-v2","loader":"auto-from-header","location_resolution":"explicit-address-exact-entry-symbol-first-v3","no_return_repair":"returning-imports-decoded-return-v2","process_launch":"inspected-jvm-launch-support-v1","string_inventory_evidence":"defined-data-coverage-v1","target_format":"mach-o","target_kind":"executable"},"provider":{"id":"ghidra","name":"Ghidra","version":"12.1.4"}},"authority":"shipped-artifact","confidence":"observed","environment":null,"evidence_id":"ev_6a88310573f4dfd2f23feef7d12c3f58eba366db1717861770656d55375e07a1","evidence_links":[],"limitations":["The session serves operations only after Ghidra reports default auto-analysis complete; incomplete analysis does not expose partial results.","The imported Program and temporary project are ephemeral and deleted on close. Annotation operations edit session database metadata; original executable bytes are never written.","Cancelling an active Ghidra request terminates its ephemeral dataLine truncated
|
||||
@@ -0,0 +1,321 @@
|
||||
{
|
||||
"decodedSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"decodeOrVisionErrors": 0,
|
||||
"duplicateSourceFramePairs": 0,
|
||||
"durationSeconds": 18.752066666666668,
|
||||
"emptyDetectionFrames": 0,
|
||||
"frames": 469,
|
||||
"heldFrames": 0,
|
||||
"landmarkConfidenceBelow055Frames": 0,
|
||||
"largestContourChanges": [
|
||||
{
|
||||
"actualSeconds": 18.651966666666667,
|
||||
"bboxCenterStep": 0.010619987358574903,
|
||||
"bboxRelativeSizeStep": 0.05204244367729771,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 467,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.817047119140625,
|
||||
"outputAllShapeStep": 0.061719217959260164,
|
||||
"outputContourShapeStep": 0.06457580929340678,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.061719217959260164,
|
||||
"rawContourShapeStep": 0.06457580929340678,
|
||||
"rawEyeShapeStep": 0.057909273674708016,
|
||||
"requestedSeconds": 18.68,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 6.3063,
|
||||
"bboxCenterStep": 0.009772060063233024,
|
||||
"bboxRelativeSizeStep": 0.013879898508151411,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 158,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.842681884765625,
|
||||
"outputAllShapeStep": 0.0594987598669281,
|
||||
"outputContourShapeStep": 0.059070265481990666,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.0594987598669281,
|
||||
"rawContourShapeStep": 0.059070265481990666,
|
||||
"rawEyeShapeStep": 0.059058695174623185,
|
||||
"requestedSeconds": 6.32,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 0.9342666666666667,
|
||||
"bboxCenterStep": 0.005945873831186665,
|
||||
"bboxRelativeSizeStep": 0.04857391780763898,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 24,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.860382080078125,
|
||||
"outputAllShapeStep": 0.03990833410408158,
|
||||
"outputContourShapeStep": 0.05205992923951523,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.03990833410408158,
|
||||
"rawContourShapeStep": 0.05205992923951523,
|
||||
"rawEyeShapeStep": 0.03331563844059785,
|
||||
"requestedSeconds": 0.96,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 1.0343666666666667,
|
||||
"bboxCenterStep": 0.0035810993172984357,
|
||||
"bboxRelativeSizeStep": 0.07745302528191012,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 26,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.86907958984375,
|
||||
"outputAllShapeStep": 0.04015940118859808,
|
||||
"outputContourShapeStep": 0.05153229113886389,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.04015940118859808,
|
||||
"rawContourShapeStep": 0.05153229113886389,
|
||||
"rawEyeShapeStep": 0.04106869710572574,
|
||||
"requestedSeconds": 1.04,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 6.8735333333333335,
|
||||
"bboxCenterStep": 0.011081990813070965,
|
||||
"bboxRelativeSizeStep": 0.041020958444265565,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 172,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.861907958984375,
|
||||
"outputAllShapeStep": 0.04919706037542044,
|
||||
"outputContourShapeStep": 0.047788293575915936,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.04919706037542044,
|
||||
"rawContourShapeStep": 0.047788293575915936,
|
||||
"rawEyeShapeStep": 0.04811240328922642,
|
||||
"requestedSeconds": 6.88,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 5.538866666666666,
|
||||
"bboxCenterStep": 0.009174106285954426,
|
||||
"bboxRelativeSizeStep": 0.0696669648408832,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 139,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.86724853515625,
|
||||
"outputAllShapeStep": 0.04712320285757311,
|
||||
"outputContourShapeStep": 0.047267593615817144,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.04712320285757311,
|
||||
"rawContourShapeStep": 0.047267593615817144,
|
||||
"rawEyeShapeStep": 0.04635983371628053,
|
||||
"requestedSeconds": 5.56,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 5.5055,
|
||||
"bboxCenterStep": 0.009205666419765468,
|
||||
"bboxRelativeSizeStep": 0.04702815798474558,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 138,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.8653411865234375,
|
||||
"outputAllShapeStep": 0.04678117299069693,
|
||||
"outputContourShapeStep": 0.0464975192908153,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.04678117299069693,
|
||||
"rawContourShapeStep": 0.0464975192908153,
|
||||
"rawEyeShapeStep": 0.044731979492293225,
|
||||
"requestedSeconds": 5.52,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 6.2729333333333335,
|
||||
"bboxCenterStep": 0.010523844047228498,
|
||||
"bboxRelativeSizeStep": 0.04067544887614405,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 157,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.835052490234375,
|
||||
"outputAllShapeStep": 0.05580485366082702,
|
||||
"outputContourShapeStep": 0.045154734035835926,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.05580485366082702,
|
||||
"rawContourShapeStep": 0.045154734035835926,
|
||||
"rawEyeShapeStep": 0.06010488116983429,
|
||||
"requestedSeconds": 6.28,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 18.7187,
|
||||
"bboxCenterStep": 0.00847507465061345,
|
||||
"bboxRelativeSizeStep": 0.001839415731091032,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 468,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.81689453125,
|
||||
"outputAllShapeStep": 0.039795819667405995,
|
||||
"outputContourShapeStep": 0.043322334703151985,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.039795819667405995,
|
||||
"rawContourShapeStep": 0.043322334703151985,
|
||||
"rawEyeShapeStep": 0.033949487128638954,
|
||||
"requestedSeconds": 18.72,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 6.973633333333333,
|
||||
"bboxCenterStep": 0.004802853824391058,
|
||||
"bboxRelativeSizeStep": 0.0033162879732389072,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 175,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.850616455078125,
|
||||
"outputAllShapeStep": 0.029986598311175987,
|
||||
"outputContourShapeStep": 0.042164697332718326,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.029986598311175987,
|
||||
"rawContourShapeStep": 0.042164697332718326,
|
||||
"rawEyeShapeStep": 0.026900138652230798,
|
||||
"requestedSeconds": 7,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 6.740066666666666,
|
||||
"bboxCenterStep": 0.008964342160362288,
|
||||
"bboxRelativeSizeStep": 0.018475143321662002,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 169,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.857940673828125,
|
||||
"outputAllShapeStep": 0.04248999607570733,
|
||||
"outputContourShapeStep": 0.04199222726351612,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.04248999607570733,
|
||||
"rawContourShapeStep": 0.04199222726351612,
|
||||
"rawEyeShapeStep": 0.0441200591307651,
|
||||
"requestedSeconds": 6.76,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
},
|
||||
{
|
||||
"actualSeconds": 6.172833333333333,
|
||||
"bboxCenterStep": 0.006930516638962855,
|
||||
"bboxRelativeSizeStep": 0.031192722054552036,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 155,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.8632049560546875,
|
||||
"outputAllShapeStep": 0.03366104158267517,
|
||||
"outputContourShapeStep": 0.04180684654646812,
|
||||
"points76Count": 76,
|
||||
"qualityReason": "",
|
||||
"rawAllShapeStep": 0.03366104158267517,
|
||||
"rawContourShapeStep": 0.04180684654646812,
|
||||
"rawEyeShapeStep": 0.029757180729629833,
|
||||
"requestedSeconds": 6.2,
|
||||
"resultReason": "",
|
||||
"trackedBoxAvailable": 1
|
||||
}
|
||||
],
|
||||
"multipleFaceFrames": 0,
|
||||
"nominalSourceFPS": 29.970029830932617,
|
||||
"outputWithout76Frames": 0,
|
||||
"partial76Frames": 0,
|
||||
"samplingFPS": 25,
|
||||
"scope": "Independent offline decoding and the current production detector/tracker; not FCP render logs or target execution. Shape steps remove previous bbox translation/scale, but still include actual pose/expression changes.",
|
||||
"sourceBasename": "girl-in-sun-hat-smiling-in-rural-field-2026-10-03-13-54-14-utc.mov",
|
||||
"statistics": {
|
||||
"bboxCenterStep": {
|
||||
"max": 0.011081990813070965,
|
||||
"median": 0.002747360384438056,
|
||||
"min": 0.00014653804115170532,
|
||||
"n": 468,
|
||||
"p95": 0.006589111497080662
|
||||
},
|
||||
"bboxRelativeSizeStep": {
|
||||
"max": 0.07745302528191012,
|
||||
"median": 0.009236047113881152,
|
||||
"min": 9.126808167081446e-05,
|
||||
"n": 468,
|
||||
"p95": 0.03867668227601517
|
||||
},
|
||||
"landmarkConfidence": {
|
||||
"max": 0.9249267578125,
|
||||
"median": 0.867706298828125,
|
||||
"min": 0.81689453125,
|
||||
"n": 469,
|
||||
"p95": 0.9015045166015625
|
||||
},
|
||||
"outputAllShapeStep": {
|
||||
"max": 0.061719217959260164,
|
||||
"median": 0.011493205285858545,
|
||||
"min": 0.003266396399148707,
|
||||
"n": 468,
|
||||
"p95": 0.03265326908712946
|
||||
},
|
||||
"outputContourShapeStep": {
|
||||
"max": 0.06457580929340678,
|
||||
"median": 0.013767751423829355,
|
||||
"min": 0.0022585721609373914,
|
||||
"n": 468,
|
||||
"p95": 0.03343570504134135
|
||||
},
|
||||
"rawAllShapeStep": {
|
||||
"max": 0.061719217959260164,
|
||||
"median": 0.011493205285858545,
|
||||
"min": 0.003266396399148707,
|
||||
"n": 468,
|
||||
"p95": 0.03265326908712946
|
||||
},
|
||||
"rawContourShapeStep": {
|
||||
"max": 0.06457580929340678,
|
||||
"median": 0.013767751423829355,
|
||||
"min": 0.0022585721609373914,
|
||||
"n": 468,
|
||||
"p95": 0.03343570504134135
|
||||
},
|
||||
"rawEyeShapeStep": {
|
||||
"max": 0.06010488116983429,
|
||||
"median": 0.010554830995294154,
|
||||
"min": 0.0018890160668284224,
|
||||
"n": 468,
|
||||
"p95": 0.03347895433098691
|
||||
}
|
||||
},
|
||||
"timelineOffsetSeconds": 18.72
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
{
|
||||
"decodedSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"decodeOrVisionErrors": 0,
|
||||
"duplicateSourceFramePairs": 0,
|
||||
"durationSeconds": 18.752066666666668,
|
||||
"emptyDetectionFrames": 0,
|
||||
"frames": 469,
|
||||
"heldFrames": 0,
|
||||
"landmarkConfidenceBelow055Frames": 0,
|
||||
"largestContourChanges": [
|
||||
{
|
||||
"actualSeconds": 5.7057,
|
||||
"bboxCenterStep": 0.010612391844050412,
|
||||
"bboxRelativeSizeStep": 0.07225176667426436,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 143,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.85870361328125,
|
||||
"outputAllShapeStep": 0.05320087993361461,
|
||||
"outputContourShapeStep": 0.0524041977802718,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.06465122287331607,
|
||||
"rawContourShapeStep": 0.06330400492305996,
|
||||
"rawEyeShapeStep": 0.07106297705037405,
|
||||
"requestedSeconds": 5.72
|
||||
},
|
||||
{
|
||||
"actualSeconds": 5.538866666666666,
|
||||
"bboxCenterStep": 0.011085862886644501,
|
||||
"bboxRelativeSizeStep": 0.06308677201537605,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 139,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.86663818359375,
|
||||
"outputAllShapeStep": 0.05242709853363116,
|
||||
"outputContourShapeStep": 0.046564814499130476,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.06161259278352428,
|
||||
"rawContourShapeStep": 0.05478966859045086,
|
||||
"rawEyeShapeStep": 0.06493439304604706,
|
||||
"requestedSeconds": 5.56
|
||||
},
|
||||
{
|
||||
"actualSeconds": 5.6723333333333334,
|
||||
"bboxCenterStep": 0.009899754844891629,
|
||||
"bboxRelativeSizeStep": 0.07041863176014063,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 142,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.86846923828125,
|
||||
"outputAllShapeStep": 0.0504812129727618,
|
||||
"outputContourShapeStep": 0.04661140849311553,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.05657646866920014,
|
||||
"rawContourShapeStep": 0.05209665662633769,
|
||||
"rawEyeShapeStep": 0.0633232078503364,
|
||||
"requestedSeconds": 5.68
|
||||
},
|
||||
{
|
||||
"actualSeconds": 18.7187,
|
||||
"bboxCenterStep": 0.012083635671277248,
|
||||
"bboxRelativeSizeStep": 0.045801810508214524,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 468,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.813995361328125,
|
||||
"outputAllShapeStep": 0.034052174045594144,
|
||||
"outputContourShapeStep": 0.043147628575738506,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.04111983043006513,
|
||||
"rawContourShapeStep": 0.05091513919680358,
|
||||
"rawEyeShapeStep": 0.029191044989766733,
|
||||
"requestedSeconds": 18.72
|
||||
},
|
||||
{
|
||||
"actualSeconds": 5.739066666666667,
|
||||
"bboxCenterStep": 0.0096878552974905,
|
||||
"bboxRelativeSizeStep": 0.050414751769179866,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 144,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.86083984375,
|
||||
"outputAllShapeStep": 0.036875562148072825,
|
||||
"outputContourShapeStep": 0.036457754092126635,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.0466359793805061,
|
||||
"rawContourShapeStep": 0.04577259881583104,
|
||||
"rawEyeShapeStep": 0.05000862947922753,
|
||||
"requestedSeconds": 5.76
|
||||
},
|
||||
{
|
||||
"actualSeconds": 0.8675333333333334,
|
||||
"bboxCenterStep": 0.003874961092189615,
|
||||
"bboxRelativeSizeStep": 0.07178938570952054,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 22,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.8583984375,
|
||||
"outputAllShapeStep": 0.031532331820470494,
|
||||
"outputContourShapeStep": 0.0381074357036598,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.03707185765347939,
|
||||
"rawContourShapeStep": 0.04568537667821508,
|
||||
"rawEyeShapeStep": 0.034575716035532285,
|
||||
"requestedSeconds": 0.88
|
||||
},
|
||||
{
|
||||
"actualSeconds": 18.651966666666667,
|
||||
"bboxCenterStep": 0.007272824106484237,
|
||||
"bboxRelativeSizeStep": 0.03719342311108376,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 467,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.8199462890625,
|
||||
"outputAllShapeStep": 0.03952595504917539,
|
||||
"outputContourShapeStep": 0.0403761896420276,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.04399124673462057,
|
||||
"rawContourShapeStep": 0.0450952404425199,
|
||||
"rawEyeShapeStep": 0.04542945579876513,
|
||||
"requestedSeconds": 18.68
|
||||
},
|
||||
{
|
||||
"actualSeconds": 0.9009,
|
||||
"bboxCenterStep": 0.0017162987254983866,
|
||||
"bboxRelativeSizeStep": 0.014351427482534596,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 23,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.85809326171875,
|
||||
"outputAllShapeStep": 0.026103724683818753,
|
||||
"outputContourShapeStep": 0.04109990769809984,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.028649663225073875,
|
||||
"rawContourShapeStep": 0.04465304774876588,
|
||||
"rawEyeShapeStep": 0.02979010461963986,
|
||||
"requestedSeconds": 0.92
|
||||
},
|
||||
{
|
||||
"actualSeconds": 0.7007,
|
||||
"bboxCenterStep": 0.007675079557145801,
|
||||
"bboxRelativeSizeStep": 0.059965605197173644,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 18,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.877166748046875,
|
||||
"outputAllShapeStep": 0.038188462475739905,
|
||||
"outputContourShapeStep": 0.040855905682333056,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.04142583196750897,
|
||||
"rawContourShapeStep": 0.04413941822893812,
|
||||
"rawEyeShapeStep": 0.04424396634844577,
|
||||
"requestedSeconds": 0.72
|
||||
},
|
||||
{
|
||||
"actualSeconds": 0.8341666666666666,
|
||||
"bboxCenterStep": 0.0019315279136915449,
|
||||
"bboxRelativeSizeStep": 0.03041757827231506,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 21,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.861602783203125,
|
||||
"outputAllShapeStep": 0.023950562918532762,
|
||||
"outputContourShapeStep": 0.0391113963086702,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.026769304364061126,
|
||||
"rawContourShapeStep": 0.043656761461571575,
|
||||
"rawEyeShapeStep": 0.021617825564847367,
|
||||
"requestedSeconds": 0.84
|
||||
},
|
||||
{
|
||||
"actualSeconds": 5.9726333333333335,
|
||||
"bboxCenterStep": 0.0076538482284609945,
|
||||
"bboxRelativeSizeStep": 0.009531954788836172,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 150,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.85198974609375,
|
||||
"outputAllShapeStep": 0.03696981884576201,
|
||||
"outputContourShapeStep": 0.038389239030267384,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.04143716031529852,
|
||||
"rawContourShapeStep": 0.042871635488955444,
|
||||
"rawEyeShapeStep": 0.0428226737500748,
|
||||
"requestedSeconds": 6
|
||||
},
|
||||
{
|
||||
"actualSeconds": 16.649966666666668,
|
||||
"bboxCenterStep": 0.006605729070676864,
|
||||
"bboxRelativeSizeStep": 0.025478189396700213,
|
||||
"faceConfidence": 1,
|
||||
"faceCount": 1,
|
||||
"frame": 417,
|
||||
"held": false,
|
||||
"landmarkConfidence": 0.8674774169921875,
|
||||
"outputAllShapeStep": 0.03284710686769975,
|
||||
"outputContourShapeStep": 0.036339332152690744,
|
||||
"points76Count": 76,
|
||||
"rawAllShapeStep": 0.037116421558418974,
|
||||
"rawContourShapeStep": 0.04240155312389841,
|
||||
"rawEyeShapeStep": 0.03197382659897345,
|
||||
"requestedSeconds": 16.68
|
||||
}
|
||||
],
|
||||
"multipleFaceFrames": 0,
|
||||
"nominalSourceFPS": 29.970029830932617,
|
||||
"outputWithout76Frames": 0,
|
||||
"partial76Frames": 0,
|
||||
"samplingFPS": 25,
|
||||
"scope": "Independent offline decoding and the current production detector/tracker; not FCP render logs or target execution. Shape steps remove previous bbox translation/scale, but still include actual pose/expression changes.",
|
||||
"sourceBasename": "girl-in-sun-hat-smiling-in-rural-field-2026-10-03-13-54-14-utc.mov",
|
||||
"statistics": {
|
||||
"bboxCenterStep": {
|
||||
"max": 0.012083635671277248,
|
||||
"median": 0.0025497870742485452,
|
||||
"min": 0.00020005997144872253,
|
||||
"n": 468,
|
||||
"p95": 0.006821726779186577
|
||||
},
|
||||
"bboxRelativeSizeStep": {
|
||||
"max": 0.07225176667426436,
|
||||
"median": 0.009157247402053037,
|
||||
"min": 6.255832853296894e-06,
|
||||
"n": 468,
|
||||
"p95": 0.03431959948374386
|
||||
},
|
||||
"landmarkConfidence": {
|
||||
"max": 0.9240875244140625,
|
||||
"median": 0.867706298828125,
|
||||
"min": 0.813995361328125,
|
||||
"n": 469,
|
||||
"p95": 0.902191162109375
|
||||
},
|
||||
"outputAllShapeStep": {
|
||||
"max": 0.05320087993361461,
|
||||
"median": 0.009735492145012412,
|
||||
"min": 0.0029755122029975372,
|
||||
"n": 468,
|
||||
"p95": 0.026782532902396017
|
||||
},
|
||||
"outputContourShapeStep": {
|
||||
"max": 0.0524041977802718,
|
||||
"median": 0.011810624254892923,
|
||||
"min": 0.002450992809745613,
|
||||
"n": 468,
|
||||
"p95": 0.028720841841711312
|
||||
},
|
||||
"rawAllShapeStep": {
|
||||
"max": 0.06465122287331607,
|
||||
"median": 0.01108023509780489,
|
||||
"min": 0.0031002818411607846,
|
||||
"n": 468,
|
||||
"p95": 0.030464142596339925
|
||||
},
|
||||
"rawContourShapeStep": {
|
||||
"max": 0.06330400492305996,
|
||||
"median": 0.013550650249078297,
|
||||
"min": 0.002692092571665042,
|
||||
"n": 468,
|
||||
"p95": 0.03357642027607019
|
||||
},
|
||||
"rawEyeShapeStep": {
|
||||
"max": 0.07106297705037405,
|
||||
"median": 0.010302814344493833,
|
||||
"min": 0.0013460890263982167,
|
||||
"n": 468,
|
||||
"p95": 0.02979010461963986
|
||||
}
|
||||
},
|
||||
"timelineOffsetSeconds": 18.72,
|
||||
"nativeContext": {
|
||||
"app": "Final Cut Pro",
|
||||
"project": "大鱼人像美化验收-20261021",
|
||||
"format": "1080p25",
|
||||
"selectedClipStartTimecode": "00:00:18:18",
|
||||
"selectedClipEndTimecode": "00:00:37:11",
|
||||
"timelinePlayheadAX": "00:00:24:11",
|
||||
"viewerLCD": "00:00:35:22",
|
||||
"faceThin": 1,
|
||||
"faceBigEye": 0.9035486629353234,
|
||||
"fastMultiFace": false,
|
||||
"sourceResolvedBy": "Selected timeline clip > File > Reveal in Finder",
|
||||
"timelineMediaMapping": "Offset18.72 is inferred from clip placement; source in-point/retiming not exported, so source5.72 -> timeline24:11 is approximate. Viewer LCD differs from AX playhead; displayed frame not asserted."
|
||||
},
|
||||
"interpretation": {
|
||||
"partialTopologySwitchObserved": false,
|
||||
"candidate": "Fully detected geometry changes retained by the current box-remapping and 90% current-frame point blend; eye effect also active",
|
||||
"notProven": [
|
||||
"Observed geometric change includes actual head motion, rotation and expression; not all measured change is detector noise",
|
||||
"No target output frames or live target internal geometry captured",
|
||||
"Native FCP arrival order and detection/color/scale can differ from the independent decode",
|
||||
"Big-eye contribution not measured independently on the native timeline"
|
||||
]
|
||||
},
|
||||
"referenceProcessIdentity": {
|
||||
"observedAlreadyRunning": true,
|
||||
"outerApp": "/Library/Plug-Ins/FxPlug/MSE18V2.app",
|
||||
"version": "2.4.0",
|
||||
"pluginSha256": "577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109",
|
||||
"matchesRequestedDownloadsBinary": true,
|
||||
"analysisLaunchedTarget": false,
|
||||
"internalTargetGeometryCaptured": false
|
||||
}
|
||||
}
|
||||
文件差异过大,未显示。
加载差异
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"scope": "Current source review, isolated authored diagnostics, static REA of requested2.4.0, and independent25fps scan of the user-selected current clip; no native dual-plugin comparison",
|
||||
"sourceBaseline": "b58fec1a86db7a2e474e1cc65a5911447b5906b9",
|
||||
"installedVersion": "1.3.2 (17)",
|
||||
"productSourceUnchanged": true,
|
||||
"selectedTarget": {
|
||||
"path": "/Users/dayu/Downloads/MSE18V2.app",
|
||||
"version": "2.4.0",
|
||||
"build": "20260724150000",
|
||||
"universalPluginSha256": "577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109",
|
||||
"arm64Sha256": "afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df"
|
||||
},
|
||||
"comparisonCaution": "Existing auto-follow-report.json describes the older /Applications target; its temporal weights/history must not be asserted as 2.4.0 default behavior",
|
||||
"evidenceRecordsRetained": 17,
|
||||
"checks": {
|
||||
"FCP-BeautyGirl/FCP-BeautyGirl/Plugin/PGFaceProcessor.m": "cca826d5602b45b2c79ea3c3c78be7c78ad1defe7b062ed8ec54c311d53ac395",
|
||||
"FCP-BeautyGirl/FCP-BeautyGirl/Plugin/FCPBeautyGirlPlugIn.m": "9d3d30d1f7f6467c634e8d6e832d2330618b9ff240de37f57de9bc48e2792de8",
|
||||
"scripts/diagnose-tracking.m": "bc758bf5ec4825006930be8997889404f63c28da1fe06ad8872b0901b2795d2c",
|
||||
"docs/analysis/tracking-flicker-20261022/synthetic-results.json": "5fdbad4887dd78658c06f5c6d8e70c9e53fd7b54e11a9cc31ee1958631cbc1a8",
|
||||
"docs/analysis/tracking-flicker-20261022/rea-evidence.json": "4b367759388c8e061e138623184ae8a6875dbab22659eefd4e474b141b8868fa",
|
||||
"scripts/diagnose-tracking.sh": "c1993ca91cee596a21db1e4f86ba224be85c37495c783f9c3b21872aff210765",
|
||||
"scripts/inspect-tracking-sequence.m": "0b94fc92669acf4d36861ccb25077b767189b8a72647e0d304627dbda5d052eb",
|
||||
"docs/analysis/tracking-flicker-20261022/current-clip-summary.json": "043ba688c606fb9e56449fd02108b34789fd41c4d9a2552cd07f4d3bf78a00f0"
|
||||
},
|
||||
"limits": [
|
||||
"Static reachable/default-configuration branches do not prove runtime branch execution",
|
||||
"Same-frame raw cache, hold and out-of-order behavior were isolated using our actual current implementation",
|
||||
"No APP rebuild, install, package or article publication for this analysis",
|
||||
"User source decoded only locally; no source frames or complete real landmark arrays uploaded",
|
||||
"User current FCP clip confirmed, all469 offline samples have full76; earlier missing-point synthetic case is not established as this clip cause",
|
||||
"Only scalar clip summary retained; full scalar per-frame diagnostics remain in ignored build",
|
||||
"Approximate timeline offset is not a substitute for verified source in-point/retiming",
|
||||
"Reference was already running; only process executable identity read. Native UI read/reveal/raise only, no effect/timeline edits; no target launch, debugger or geometry trace."
|
||||
],
|
||||
"currentClipSummary": "current-clip-summary.json"
|
||||
}
|
||||
文件差异过大,未显示。
加载差异
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"repository": "https://github.com/dayumeida/FCP-BeautyGirl.git",
|
||||
"anonymousClone": true,
|
||||
"commit": "a0c5357efd87a63dbee6269d9335e6aa3ba78799",
|
||||
"trackedFilesByteBlobAndModeCompared": 284,
|
||||
"strictFullFsck": true,
|
||||
"syntheticDiagnosticRebuiltAndReproduced": true,
|
||||
"productSourceUnchangedFromRelease": "v1.3.2",
|
||||
"lfs": false,
|
||||
"submodules": false,
|
||||
"temporaryCloneRemoved": true,
|
||||
"mediaBoundary": "User source clip not included; clip scalar summary and static/synthetic evidence retained"
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
# 2.4.0 region / pin branch review
|
||||
|
||||
2026-10-23. Independent read-only review of the existing AIR and local arm64
|
||||
slice. No shared REA operation, target execution, product edit, Git operation,
|
||||
or user image/landmark extraction was performed.
|
||||
|
||||
## The default-path correction
|
||||
|
||||
**The inspected main encoders and both direct fallback callers select mode 0
|
||||
(pin), not region. Fragment buffer 8 is sampleFlipY, not faceThinMode.**
|
||||
|
||||
AIR file: `build/vface-analysis/new-face-thin.air.txt`, SHA-256
|
||||
`1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9`.
|
||||
Arm64 slice: `build/tracking-audit/MSE18V2-arm64`, SHA-256
|
||||
`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`.
|
||||
|
||||
AIR metadata lines 4126–4135 give the actual Metal binding indices:
|
||||
|
||||
| Fragment buffer | Name | AIR parameter |
|
||||
| --- | --- | --- |
|
||||
| 0 | facePoints | `%3` |
|
||||
| 1 | faceCount | `%4` |
|
||||
| 2 | faceThinStrength | `%5` |
|
||||
| 4 | faceThinMode | `%6` |
|
||||
| 7 | faceShapeParams | `%7` |
|
||||
| 8 | sampleFlipY | `%8` |
|
||||
| 9 | warpFlipY | `%9` |
|
||||
| 10 | sourceSampleRect | `%10` |
|
||||
|
||||
This is not merely a name inference: lines 447–465 load `%6`, test it `>0`,
|
||||
and choose region. Lines 569–583 load `%8` and perform the final sample Y flip.
|
||||
|
||||
The independent native instruction check used Xcode llvm-objdump on that exact
|
||||
slice; addresses below are original virtual addresses. The ObjC stub
|
||||
`0x100081d00` is `setFragmentBytes:length:atIndex:` in the saved REA pseudocode.
|
||||
|
||||
| Native path | Source of buffer 4 data | Binding instructions | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| `FUN_100030084` | `0x1000300d0: str wzr,[sp,#0x70]` | `0x100030524 add x2,sp,#0x70`; `0x100030530 mov w4,#4`; call `0x100030534` | mode 0 |
|
||||
| `FUN_100030840` | `0x100030888: str wzr,[sp,#0x70]` | `0x100030bf4 add x2,sp,#0x70`; `0x100030c00 mov w4,#4`; call `0x100030c04` | mode 0 |
|
||||
| `FUN_10003127c`, called at `0x100027a34` | caller `0x1000279f8 str wzr,[sp,#0x18]` | callee `0x10003156c add x2,x29,#0x28`; `0x100031578 mov w4,#4`; call `0x10003157c` | mode 0 |
|
||||
| `FUN_10003127c`, called at `0x10002be14` | `0x10002bd04 str wzr,[sp,#0xbc]`; `0x10002bdb4 ldr w9,[sp,#0xbc]`; `0x10002bde0 str w9,[sp,#0x18]` | same callee binding | mode 0 |
|
||||
| inline fallback in `FUN_10002b8a4` | same zero at `0x10002bd04` | `0x10002bf74 add x2,sp,#0xbc`; `0x10002bf80 mov w4,#4`; call `0x10002bf84` | mode 0 |
|
||||
|
||||
The callee creates a 0x110-byte frame and sets fp=sp+0x100, so its fp+0x28
|
||||
is the caller's sp+0x18. The whole decoded executable text contains exactly
|
||||
the two direct `bl 0x10003127c` calls listed above. This bounds the conclusion:
|
||||
the inspected default/fallback paths do not establish any fixed region=1 path;
|
||||
this is not an exhaustive exclusion of arbitrary indirect calls or runtime
|
||||
buffer replacement.
|
||||
|
||||
Saved provider corroboration in `renderpath-evidence.json`:
|
||||
|
||||
- `0x100030084`: `ev_f6e9622db324900aa5bc7d21598097df4abfb2f1270503751af959c61d7c8405`.
|
||||
- `0x100030840`: `ev_30343763e68d261f018fb476b50a8695ca677d85cbcea9eda709c4e46c89ada6`.
|
||||
- `0x10003127c`: `ev_537b8f52a769c64a08223b18f0fb2fd1a0b1daa0f44ffeb9b5c132513a9bcaf8`.
|
||||
- inline fallback `0x10002b8a4`: `ev_4a2bf9e0530d651ae929ef861a2c52bfdf691445def0a16d8bbe07d723ce0c0e`.
|
||||
|
||||
## Exact shader branch contract
|
||||
|
||||
`faceThinFragmentShader` lines 388–587:
|
||||
|
||||
1. `warpFlipY` optionally flips the working UV before deformation (389–402).
|
||||
2. Source texture width/height are read and clamped to >=1 (427–434).
|
||||
3. If any shape parameter is active, iterate faces with **stride77** (454).
|
||||
With mode>0, run region with `clamp(abs(shoulian)*40,0,1)` (458–465), then
|
||||
run the other shape pins with thin forced to0 (470–474). With mode0, run
|
||||
`mssFaceShapePinCoordinate` with the original thin parameter (478).
|
||||
4. If the shape structure is inactive but the separate faceThinStrength is
|
||||
active, mode>0 uses region directly with clamped overall strength (506);
|
||||
mode0 calls the old thin pin with `0.025*clamp(strength,0,1)` (510–512).
|
||||
5. Clamp UV, undo warpFlipY, map sourceSampleRect, clamp again, apply sampleFlipY,
|
||||
then sample the source (521–583). These are separate coordinate operations.
|
||||
|
||||
The active-shape pin helper's thin branch at 3168–3268 uses its incoming thin
|
||||
ratio directly in the sequential17 pin field. Its pixel-size vector is not
|
||||
used in that branch. This does not alone prove the CPU supplies no size gain;
|
||||
CPU parameter generation remains a separate evidence question.
|
||||
|
||||
Therefore region should not replace the default field based on buffer8=1.
|
||||
The current frame's qualified points may be accepted as-is without implying
|
||||
that its spatial warp must be changed to region.
|
||||
|
||||
## Region function, retained as an optional-path analysis
|
||||
|
||||
`mssFaceThinRegionCoordinate` is lines 706–2835 (another copy appears at
|
||||
4369 onward inside the offset-map shader). Its inputs are working UV, readonly
|
||||
point array, face offset, strength, and source texture size. There is **no time,
|
||||
previous frame, previous point set, persistent buffer write, texture history,
|
||||
atomic, or other temporal input**. All stores in this function initialize local
|
||||
index arrays. It is a pure spatial function of the supplied points/parameters.
|
||||
|
||||
Use `S=(sourceTextureWidth,sourceTextureHeight)`; the point buffer stores UVs.
|
||||
The function loads `P76` as center (747–750), obtains contour bounds from all
|
||||
17 points59..75 (714–793), and computes `W/H` as contour spans multiplied by S
|
||||
(757–772). It returns identity for W<=1 or H<=1 (773–776).
|
||||
|
||||
Query `p=uv*S` at810. Radius, distance, axis normalization, and most amplitude
|
||||
caps are calculated in **pixel space**. The contour center and all point
|
||||
positions must be multiplied componentwise by S before such operations.
|
||||
Displacements are divided componentwise by S to return to UV. Substituting UV
|
||||
Euclidean distance for pixel Euclidean distance changes the aspect behavior.
|
||||
|
||||
The main axis is normalized `P67*S - P76*S`, falling back to (0,1); its
|
||||
perpendicular is `(axis.y,-axis.x)` (863–894). This is based on chin and center,
|
||||
not a fixed vertical image direction, and follows head roll.
|
||||
|
||||
Strength `s=clamp(input,0,1)` is nonlinearly mapped:
|
||||
`u=mix(s,s*s*(3-2*s),.28)`, `a=.105*u*(1.08-.08*u)` (795–805).
|
||||
Aspect and asymmetric left/right center-to-contour spans modulate the field
|
||||
(812–841). These are spatial shape adaptations, not temporal smoothing.
|
||||
|
||||
The output is a combination of:
|
||||
|
||||
- An analytic side contraction with head-local horizontal/vertical smooth
|
||||
envelopes and analytic face support (862–1117).
|
||||
- A neighbor-aware17-contour weighted field (1133–1638), with protected center
|
||||
anchors, smooth radial/directional support, weight-sum normalization and a
|
||||
pixel amplitude cap.
|
||||
- Another17-contour field with strength-dependent neighboring-point averaging
|
||||
(`mix(Pi,(Pprev+2*Pi+Pnext)/4,alpha)`,1683–1699); contour index distance from
|
||||
chin67 affects weights (1704 onward); contributions are accumulated before
|
||||
normalization rather than sequentially updating the query (1905–1939).
|
||||
- Additional lower-face/chin components using65..69, including a three-point
|
||||
chin mean and roll-aware local envelopes (1954–2765).
|
||||
|
||||
Final group caps include `(0.04+.066*s)*W` and `(0.064+.058*s)*W`
|
||||
(2785–2814). The final face envelope multiplies the total by
|
||||
`.32+.68*analyticMask`, then returns `clamp(uv-totalUVDisplacement,0,1)`
|
||||
(2815–2829). This is an inverse sampling field.
|
||||
|
||||
These features can reduce sensitivity to an isolated spatial point perturbation
|
||||
if this mode is selected; that is an inference about the mathematics, not a
|
||||
measured temporal improvement or evidence that the default path uses it.
|
||||
|
||||
## Protection formulas
|
||||
|
||||
Below `smooth(a,b,x)` means smoothstep with clamped input. All dimensions and
|
||||
distances here are in pixels, and decimal constants are decoded AIR float
|
||||
constants (small float rounding retained in the original text).
|
||||
|
||||
Let `C=P76*S`, `D=normalize(P67*S-C)`, `T=(D.y,-D.x)`.
|
||||
|
||||
Analytic face mask, lines2839–2916:
|
||||
|
||||
```
|
||||
q = p-C-.12*H*D
|
||||
x = dot(q,T)/max(.5*W,1)
|
||||
y = dot(q,D)/max(.7*H,1)
|
||||
r = sqrt(x*x+y*y)
|
||||
mask = (1-smooth(.88,1.03,r)) * smooth(-.92,-.72,y)
|
||||
* (1-smooth(1.02,1.16,y))
|
||||
```
|
||||
|
||||
Temple factor, lines3047–3149:
|
||||
|
||||
```
|
||||
x = abs(dot(p-C,T))/max(.52*W,1)
|
||||
y = dot(p-C,D)/max(.60*H,1)
|
||||
k = smooth(-.28,-.02,y) * (1-smooth(.42,.72,y))
|
||||
factor = clamp(1
|
||||
-.62*smooth(.50,.80,x)*(1-smooth(-.46,-.14,y))*(1-.86*k)
|
||||
-.20*smooth(.34,.70,x)*(1-smooth(-.72,-.34,y))*(1-.70*k), .30,1)
|
||||
```
|
||||
|
||||
Anchor factor, lines2993–3043: indices47/48/49/52/76; radius
|
||||
`R=max(12,.28*min(W,H))`; take the minimum
|
||||
`smooth(.34*R,R,distance(p,Pi*S))`, then clamp to [.12,1].
|
||||
|
||||
Chin/mouth factor, lines2929–2977: indices47/48/49/52; radius
|
||||
`R=max(10,.16*min(W,H))`; take the minimum
|
||||
`smooth(.38*R,R,distance(p,Pi*S))`, then clamp to [.24,1].
|
||||
|
||||
The floors protect without hard disabling the whole field. Several region
|
||||
subcomponents additionally interpolate these factors by their local support,
|
||||
so merely multiplying an old17-pin warp by these factors is not equivalent.
|
||||
|
||||
## Smallest justified alignment path
|
||||
|
||||
For the inspected default: keep the pin family and validate the actual CPU
|
||||
ratios, point layout/UV orientation, operation order and optional offset-map
|
||||
processing. Do not insert region or stronger point smoothing as an asserted
|
||||
fix for the user's clip. The large eye control and any offset-map spatial
|
||||
filter need their own evidence; this review has not established their exact
|
||||
runtime contribution.
|
||||
|
||||
Only if a separate reachable region-mode path is later established should its
|
||||
field be reconstructed. A faithful implementation needs the pure coordinate
|
||||
function, all four protections, pixel-space geometry, contour accumulation and
|
||||
caps, followed by the remaining shape pins with thin=0. Evaluate that same
|
||||
coordinate map for RGB and every mask. A generated float2 offset texture plus
|
||||
one inverse sampler is a viable integration boundary; a reduced grid introduces
|
||||
an approximation and needs measured UV error. Temporal state belongs upstream.
|
||||
|
||||
No region=1 runtime path or target output has been observed by this audit.
|
||||
文件差异过大,未显示。
加载差异
@@ -0,0 +1,453 @@
|
||||
{
|
||||
"cases" : [
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 0,
|
||||
"maximum_independent_error_pixels" : 0,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose0 size0 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0.25,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 0.35382923640349639,
|
||||
"maximum_independent_error_pixels" : 0.0026882437460426967,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose0 size0 eye-only",
|
||||
"target_rms_error_pixels" : 2.1921713206428187e-05,
|
||||
"thin" : 0,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 7.0728000415791215,
|
||||
"maximum_independent_error_pixels" : 0.002755077444486212,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose0 size0 thin-only",
|
||||
"target_rms_error_pixels" : 0.00011702992366181097,
|
||||
"thin" : 1,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0.25,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 7.0728000415791215,
|
||||
"maximum_independent_error_pixels" : 0.0027413680285147649,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose0 size0 thin+eye",
|
||||
"target_rms_error_pixels" : 0.0001240079365079365,
|
||||
"thin" : 1,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.3980817331903381e-14,
|
||||
"maximum_independent_error_pixels" : 9.830249857363302e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose0 size1 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0.25,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 0.53075330293307399,
|
||||
"maximum_independent_error_pixels" : 0.0027120972635748626,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose0 size1 eye-only",
|
||||
"target_rms_error_pixels" : 7.0133057212432167e-05,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 8.2005901709704148,
|
||||
"maximum_independent_error_pixels" : 0.0027728968676576145,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose0 size1 thin-only",
|
||||
"target_rms_error_pixels" : 0.00023521707359494627,
|
||||
"thin" : 1,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0.25,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 8.2005901709704148,
|
||||
"maximum_independent_error_pixels" : 0.0027728968676576145,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose0 size1 thin+eye",
|
||||
"target_rms_error_pixels" : 0.00024352479987655608,
|
||||
"thin" : 1,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 1.7763568394002505e-14,
|
||||
"maximum_independent_error_pixels" : 8.5299224090530028e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose0 size2 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0.25,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 0.26537789376221338,
|
||||
"maximum_independent_error_pixels" : 0.0026286369668807358,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose0 size2 eye-only",
|
||||
"target_rms_error_pixels" : 5.0712301697452399e-05,
|
||||
"thin" : 0,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 8.8528177374135399,
|
||||
"maximum_independent_error_pixels" : 0.0027577518479714133,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose0 size2 thin-only",
|
||||
"target_rms_error_pixels" : 0.0002095422906842435,
|
||||
"thin" : 1,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0.25,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 8.8528177374135399,
|
||||
"maximum_independent_error_pixels" : 0.0027577518479714133,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose0 size2 thin+eye",
|
||||
"target_rms_error_pixels" : 0.00021076686089680123,
|
||||
"thin" : 1,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 0,
|
||||
"maximum_independent_error_pixels" : 0,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose1 size0 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0.90354866293532343,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 1.4980655360450705,
|
||||
"maximum_independent_error_pixels" : 0.002736966310374967,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose1 size0 eye-only",
|
||||
"target_rms_error_pixels" : 3.7969521062487261e-05,
|
||||
"thin" : 0,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 8.2983365210307376,
|
||||
"maximum_independent_error_pixels" : 0.0027466016331799312,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose1 size0 thin-only",
|
||||
"target_rms_error_pixels" : 0.00012969060431145763,
|
||||
"thin" : 1,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0.90354866293532343,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 8.2983365210307376,
|
||||
"maximum_independent_error_pixels" : 0.0027466016331799312,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose1 size0 thin+eye",
|
||||
"target_rms_error_pixels" : 0.0001249729933702032,
|
||||
"thin" : 1,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.3980817331903381e-14,
|
||||
"maximum_independent_error_pixels" : 9.830249857363302e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose1 size1 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0.90354866293532343,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.1744460803927361,
|
||||
"maximum_independent_error_pixels" : 0.002720070336115162,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose1 size1 eye-only",
|
||||
"target_rms_error_pixels" : 9.2332938119698104e-05,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 10.38677748064452,
|
||||
"maximum_independent_error_pixels" : 0.0027597851282901023,
|
||||
"maximum_target_error_pixels" : 0.0055219139903783798,
|
||||
"name" : "pose1 size1 thin-only",
|
||||
"target_rms_error_pixels" : 0.00026077041763909807,
|
||||
"thin" : 1,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0.90354866293532343,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 10.38677748064452,
|
||||
"maximum_independent_error_pixels" : 0.0027597851282901023,
|
||||
"maximum_target_error_pixels" : 0.0055219139903783798,
|
||||
"name" : "pose1 size1 thin+eye",
|
||||
"target_rms_error_pixels" : 0.00026150911830191969,
|
||||
"thin" : 1,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 1.7763568394002505e-14,
|
||||
"maximum_independent_error_pixels" : 8.5299224090530028e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose1 size2 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0.90354866293532343,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 1.2129269895950687,
|
||||
"maximum_independent_error_pixels" : 0.0027074615946477646,
|
||||
"maximum_target_error_pixels" : 0.003910064697265625,
|
||||
"name" : "pose1 size2 eye-only",
|
||||
"target_rms_error_pixels" : 4.5346296046615942e-05,
|
||||
"thin" : 0,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 10.144258143830054,
|
||||
"maximum_independent_error_pixels" : 0.0027638516828663376,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose1 size2 thin-only",
|
||||
"target_rms_error_pixels" : 0.00022775554094271662,
|
||||
"thin" : 1,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0.90354866293532343,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 10.144258143830054,
|
||||
"maximum_independent_error_pixels" : 0.0027638516828663376,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose1 size2 thin+eye",
|
||||
"target_rms_error_pixels" : 0.00022830552736565732,
|
||||
"thin" : 1,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 0,
|
||||
"maximum_independent_error_pixels" : 0,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose2 size0 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 1.9006110949587283,
|
||||
"maximum_independent_error_pixels" : 0.0026860115231048072,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose2 size0 eye-only",
|
||||
"target_rms_error_pixels" : 4.1011770074785939e-05,
|
||||
"thin" : 0,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 9.5084281896725376,
|
||||
"maximum_independent_error_pixels" : 0.0027749358063331774,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose2 size0 thin-only",
|
||||
"target_rms_error_pixels" : 0.00017673850215450427,
|
||||
"thin" : 1,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 256,
|
||||
"maximum_displacement_pixels" : 9.5084281896725376,
|
||||
"maximum_independent_error_pixels" : 0.0027749358063331774,
|
||||
"maximum_target_error_pixels" : 0.00390625,
|
||||
"name" : "pose2 size0 thin+eye",
|
||||
"target_rms_error_pixels" : 0.00017399820437006796,
|
||||
"thin" : 1,
|
||||
"width" : 256
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.3980817331903381e-14,
|
||||
"maximum_independent_error_pixels" : 9.830249857363302e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose2 size1 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.65191960410192,
|
||||
"maximum_independent_error_pixels" : 0.0026956562280248753,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose2 size1 eye-only",
|
||||
"target_rms_error_pixels" : 0.00010205516806844121,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 12.235777303453091,
|
||||
"maximum_independent_error_pixels" : 0.002741529812605142,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose2 size1 thin-only",
|
||||
"target_rms_error_pixels" : 0.0002526036292317462,
|
||||
"thin" : 1,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 12.235777303453091,
|
||||
"maximum_independent_error_pixels" : 0.0027522254693324445,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "pose2 size1 thin+eye",
|
||||
"target_rms_error_pixels" : 0.00025965073459259622,
|
||||
"thin" : 1,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 1.7763568394002505e-14,
|
||||
"maximum_independent_error_pixels" : 8.5299224090530028e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "pose2 size2 passthrough",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 1.6564609111123645,
|
||||
"maximum_independent_error_pixels" : 0.002608603255927031,
|
||||
"maximum_target_error_pixels" : 0.003910064697265625,
|
||||
"name" : "pose2 size2 eye-only",
|
||||
"target_rms_error_pixels" : 3.5839771916069625e-05,
|
||||
"thin" : 0,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 0,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 11.320027734419691,
|
||||
"maximum_independent_error_pixels" : 0.0027770856999663083,
|
||||
"maximum_target_error_pixels" : 0.0055225868709385395,
|
||||
"name" : "pose2 size2 thin-only",
|
||||
"target_rms_error_pixels" : 0.00022890932538955193,
|
||||
"thin" : 1,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 320,
|
||||
"maximum_displacement_pixels" : 11.320027734419691,
|
||||
"maximum_independent_error_pixels" : 0.0027770856999663083,
|
||||
"maximum_target_error_pixels" : 0.0055225868709385395,
|
||||
"name" : "pose2 size2 thin+eye",
|
||||
"target_rms_error_pixels" : 0.0002305974089591263,
|
||||
"thin" : 1,
|
||||
"width" : 192
|
||||
},
|
||||
{
|
||||
"eye" : 1,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.6925237951548051,
|
||||
"maximum_independent_error_pixels" : 0.0027203383917974236,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "indexed eye centers",
|
||||
"target_rms_error_pixels" : 8.2559591202410913e-05,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : -0.5,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.3980817331903381e-14,
|
||||
"maximum_independent_error_pixels" : 9.830249857363302e-06,
|
||||
"maximum_target_error_pixels" : 0,
|
||||
"name" : "negative eye strength clamps to zero",
|
||||
"target_rms_error_pixels" : 0,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 2,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 2.6925237951548051,
|
||||
"maximum_independent_error_pixels" : 0.0027203383917974236,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "high eye strength clamps to one",
|
||||
"target_rms_error_pixels" : 8.2559591202410913e-05,
|
||||
"thin" : 0,
|
||||
"width" : 384
|
||||
},
|
||||
{
|
||||
"eye" : 0.90000000000000002,
|
||||
"height" : 216,
|
||||
"maximum_displacement_pixels" : 6.9857867334571617,
|
||||
"maximum_independent_error_pixels" : 0.0027701099063711732,
|
||||
"maximum_target_error_pixels" : 0.00391387939453125,
|
||||
"name" : "overlapping sequential eyes",
|
||||
"target_rms_error_pixels" : 0.00024035192027544236,
|
||||
"thin" : 0.69999999999999996,
|
||||
"width" : 384
|
||||
}
|
||||
],
|
||||
"checks" : 211,
|
||||
"device" : "Apple M1 Max",
|
||||
"maximum_independent_error_pixels" : 0.0027770856999663083,
|
||||
"maximum_target_error_pixels" : 0.0055225868709385395,
|
||||
"mode_buffer4" : 0,
|
||||
"sample_flip_y_buffer8" : 0,
|
||||
"scope" : "Authored synthetic Vision76 geometry; thin and big-eye controls only; no user media or target binaries embedded",
|
||||
"target_oracle_executed" : 1,
|
||||
"warp_flip_y_buffer9" : 0
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"authoredTwoFaceCrossing" : {
|
||||
"rawIndex0" : "same authored identity A moved by .10",
|
||||
"rawIndex1" : "different authored identity B moved within .01 of old center",
|
||||
"selectedRawIndex" : 1
|
||||
},
|
||||
"defaultAppearanceOnDetectionLoss" : {
|
||||
"geometryFacesAfter" : 1,
|
||||
"geometryFacesBefore" : 1,
|
||||
"meanColorMaskAfter" : 0,
|
||||
"meanColorMaskBefore" : 0.39522577568114048,
|
||||
"meanSkinMaskAfter" : 0,
|
||||
"meanSkinMaskBefore" : 0.29670316041502076
|
||||
},
|
||||
"landmarkWeightsByFrameRate" : [
|
||||
{
|
||||
"currentLandmarkWeight" : 0.89999999999999925,
|
||||
"fps" : 25
|
||||
},
|
||||
{
|
||||
"currentLandmarkWeight" : 0.89999999999999925,
|
||||
"fps" : 30
|
||||
},
|
||||
{
|
||||
"currentLandmarkWeight" : 0.5,
|
||||
"fps" : 60
|
||||
},
|
||||
{
|
||||
"currentLandmarkWeight" : 0.25,
|
||||
"fps" : 120
|
||||
}
|
||||
],
|
||||
"outOfOrderCachedMissingFrame" : {
|
||||
"initial40OutputFaces" : 0,
|
||||
"ordered0Then40OutputFaces" : 1,
|
||||
"replay40AfterAdding0OutputFaces" : 0
|
||||
},
|
||||
"pureBBoxTranslationJitter" : {
|
||||
"fps" : 25,
|
||||
"frames" : 20,
|
||||
"maximumOutputVsRawPointError" : 0,
|
||||
"outputOverRawAmplitude" : 1,
|
||||
"outputStepNormalized" : 0.0080000000000000071,
|
||||
"rawStepNormalized" : 0.0080000000000000071
|
||||
},
|
||||
"reacquisition" : {
|
||||
"continuousPoint69x" : 0.60288473677011323,
|
||||
"rawPoint69x" : 0.60568473677011325,
|
||||
"reacquiredPoint69x" : 0.60568473677011325
|
||||
},
|
||||
"scope" : "Authored synthetic geometry and image only; actual current PGFaceProcessor implementation linked; no target binary or user media.",
|
||||
"topologyValidMissingValid" : {
|
||||
"held" : [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"pixelDifferencesFromUnwarpedInput" : [
|
||||
{
|
||||
"changedChannelsAbove1e_6" : 85835,
|
||||
"maxChannelDifference" : 0.89999997615814209,
|
||||
"meanChannelDifference" : 0.055795646515334418
|
||||
},
|
||||
{
|
||||
"changedChannelsAbove1e_6" : 0,
|
||||
"maxChannelDifference" : 0,
|
||||
"meanChannelDifference" : 0
|
||||
},
|
||||
{
|
||||
"changedChannelsAbove1e_6" : 85835,
|
||||
"maxChannelDifference" : 0.89999997615814209,
|
||||
"meanChannelDifference" : 0.055795646515334418
|
||||
}
|
||||
],
|
||||
"points76Counts" : [
|
||||
76,
|
||||
0,
|
||||
76
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
MSE18V2 2.4.0 AIR excerpt; original complete-text line numbers.
|
||||
SHA256: 1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9
|
||||
|
||||
3364: 158: ; preds = %109, %85
|
||||
3365: %159 = phi <2 x float> [ %155, %109 ], [ %86, %85 ]
|
||||
3366: %160 = tail call fast float @air.fast_fabs.f32(float %5) #2
|
||||
3367: %161 = fcmp fast ogt float %160, 0x3EB0C6F7A0000000
|
||||
3368: br i1 %161, label %162, label %209
|
||||
3369:
|
||||
3370: 162: ; preds = %158
|
||||
3371: %163 = bitcast [4 x <2 x i32>]* %17 to i8*
|
||||
3372: call void @llvm.lifetime.start.p0i8(i64 32, i8* nonnull %163) #10
|
||||
3373: %164 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 0
|
||||
3374: store <2 x i32> <i32 69, i32 39>, <2 x i32>* %164, align 8
|
||||
3375: %165 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 1
|
||||
3376: store <2 x i32> <i32 65, i32 35>, <2 x i32>* %165, align 8
|
||||
3377: %166 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 2
|
||||
3378: store <2 x i32> <i32 70, i32 26>, <2 x i32>* %166, align 8
|
||||
3379: %167 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 3
|
||||
3380: store <2 x i32> <i32 64, i32 34>, <2 x i32>* %167, align 8
|
||||
3381: %168 = insertelement <2 x float> undef, float %5, i64 0
|
||||
3382: %169 = shufflevector <2 x float> %168, <2 x float> undef, <2 x i32> zeroinitializer
|
||||
3383: br label %171
|
||||
3384:
|
||||
3385: 170: ; preds = %205
|
||||
3386: call void @llvm.lifetime.end.p0i8(i64 32, i8* nonnull %163) #10
|
||||
3387: br label %209
|
||||
3388:
|
||||
3389: 171: ; preds = %205, %162
|
||||
3390: %172 = phi <2 x float> [ %159, %162 ], [ %206, %205 ]
|
||||
3391: %173 = phi i32 [ 0, %162 ], [ %207, %205 ]
|
||||
3392: %174 = zext i32 %173 to i64
|
||||
3393: %175 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 %174
|
||||
3394: %176 = load <2 x i32>, <2 x i32>* %175, align 8
|
||||
3395: %177 = extractelement <2 x i32> %176, i64 0
|
||||
3396: %178 = add nsw i32 %177, %2
|
||||
3397: %179 = sext i32 %178 to i64
|
||||
3398: %180 = getelementptr inbounds %struct.MSSFaceThinPoint, %struct.MSSFaceThinPoint addrspace(2)* %1, i64 %179, i32 0
|
||||
3399: %181 = load <2 x float>, <2 x float> addrspace(2)* %180, align 8, !tbaa !74
|
||||
3400: %182 = extractelement <2 x i32> %176, i64 1
|
||||
3401: %183 = add nsw i32 %182, %2
|
||||
3402: %184 = sext i32 %183 to i64
|
||||
3403: %185 = getelementptr inbounds %struct.MSSFaceThinPoint, %struct.MSSFaceThinPoint addrspace(2)* %1, i64 %184, i32 0
|
||||
3404: %186 = load <2 x float>, <2 x float> addrspace(2)* %185, align 8, !tbaa !74
|
||||
3405: %187 = fsub fast <2 x float> %181, %186
|
||||
3406: %188 = tail call fast float @air.dot.v2f32(<2 x float> %187, <2 x float> %187) #2
|
||||
3407: %189 = tail call fast float @air.fast_sqrt.f32(float %188) #2
|
||||
3408: %190 = fcmp fast ugt float %189, 0x3F1A36E2E0000000
|
||||
3409: br i1 %190, label %191, label %205
|
||||
3410:
|
||||
3411: 191: ; preds = %171
|
||||
3412: %192 = fsub fast <2 x float> %186, %181
|
||||
3413: %193 = fsub fast <2 x float> %172, %181
|
||||
3414: %194 = tail call fast float @air.dot.v2f32(<2 x float> %193, <2 x float> %193) #2
|
||||
3415: %195 = tail call fast float @air.fast_sqrt.f32(float %194) #2
|
||||
3416: %196 = fdiv fast float %195, %189
|
||||
3417: %197 = fsub fast float 1.000000e+00, %196
|
||||
3418: %198 = tail call fast float @air.fast_clamp.f32(float %197, float 0.000000e+00, float 1.000000e+00) #2
|
||||
3419: %199 = insertelement <2 x float> undef, float %198, i64 0
|
||||
3420: %200 = shufflevector <2 x float> %199, <2 x float> undef, <2 x i32> zeroinitializer
|
||||
3421: %201 = fmul fast <2 x float> %192, %169
|
||||
3422: %202 = fmul fast <2 x float> %201, %200
|
||||
3423: %203 = fsub fast <2 x float> %172, %202
|
||||
3424: %204 = tail call fast <2 x float> @air.fast_clamp.v2f32(<2 x float> %203, <2 x float> zeroinitializer, <2 x float> <float 1.000000e+00, float 1.000000e+00>) #2
|
||||
3425: br label %205
|
||||
3426:
|
||||
3427: 205: ; preds = %191, %171
|
||||
3428: %206 = phi <2 x float> [ %204, %191 ], [ %172, %171 ]
|
||||
3429: %207 = add nuw nsw i32 %173, 1
|
||||
3430: %208 = icmp eq i32 %207, 4
|
||||
3431: br i1 %208, label %170, label %171, !llvm.loop !89
|
||||
@@ -0,0 +1,258 @@
|
||||
{
|
||||
"authority": "Static shipped Apple AIR and Mach-O byte/assembly inspection; target app and shaders not executed",
|
||||
"sources": {
|
||||
"metallib": "/Users/dayu/Downloads/MSE18V2.app/Contents/PlugIns/MSE18V2.pluginkit/Contents/Resources/default.metallib",
|
||||
"metallib_sha256": "856849c45cea2c8f083eeba06a9e318c450f4a56694b438d1a5ba8ef752a0ee0",
|
||||
"command": [
|
||||
"xcrun",
|
||||
"metal-objdump",
|
||||
"--metallib",
|
||||
"--disassemble",
|
||||
"/Users/dayu/Downloads/MSE18V2.app/Contents/PlugIns/MSE18V2.pluginkit/Contents/Resources/default.metallib"
|
||||
],
|
||||
"air_sha256": "1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9",
|
||||
"binary": "/Users/dayu/Downloads/MSE18V2.app/Contents/PlugIns/MSE18V2.pluginkit/Contents/MacOS/MSE18V2",
|
||||
"binary_arm64_sha256": "afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df",
|
||||
"double065_file_offsets_in_arm64_slice": [
|
||||
548512
|
||||
]
|
||||
},
|
||||
"new_version_vface": {
|
||||
"struct_field": "MSSFaceShapeParams.vlian offset8; helper parameter5",
|
||||
"render_params_field": "faceV double offset0x90",
|
||||
"cpu_function": "0x10002fb74",
|
||||
"cpu_coefficient_address": "0x100085ea0",
|
||||
"cpu_coefficient": 0.065,
|
||||
"cpu_ratio": "float(clamp(faceV,0,1)*0.065*double(float(clamp(commonStrength,0,1))))",
|
||||
"pin_order": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"pin_fields": [
|
||||
"origin",
|
||||
"direction/radius anchor"
|
||||
],
|
||||
"coordinate_system": "full-image normalized UV; q and points must share the same vertical axis",
|
||||
"radius": "length(Panchor-Porigin), unscaled UV metric; skip radius<=0.0001",
|
||||
"weight": "clamp(1-length(q-Porigin)/radius,0,1)",
|
||||
"step": "q=clamp(q-(Panchor-Porigin)*ratio*weight,0,1)",
|
||||
"sequential": true,
|
||||
"ratio_threshold": 1e-06,
|
||||
"shader_lines": {
|
||||
"helper": 3159,
|
||||
"vface_gate": 3364,
|
||||
"pins": [
|
||||
3374,
|
||||
3376,
|
||||
3378,
|
||||
3380
|
||||
],
|
||||
"loop": 3389,
|
||||
"radius": 3405,
|
||||
"offset": 3412,
|
||||
"clamp": 3424,
|
||||
"count": 3430,
|
||||
"metadata": 4132
|
||||
},
|
||||
"order": "thin17 -> narrow16 -> V4 -> jaw6 -> cheek6 -> chin3 -> short -> smallHead -> bigEye",
|
||||
"helper_copies": [
|
||||
{
|
||||
"start_line": 3159,
|
||||
"v_pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"has_old_pixel_gain_constant": false
|
||||
},
|
||||
{
|
||||
"start_line": 6840,
|
||||
"v_pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"has_old_pixel_gain_constant": false
|
||||
},
|
||||
{
|
||||
"start_line": 8682,
|
||||
"v_pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"has_old_pixel_gain_constant": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"version_difference": {
|
||||
"old_air": "build/pose-analysis/face-thin.air.txt",
|
||||
"old_gain_lines": [
|
||||
592,
|
||||
633
|
||||
],
|
||||
"old_vface_lines": [
|
||||
830,
|
||||
897
|
||||
],
|
||||
"old_cpu_coefficient_address": "0x10005f9a0",
|
||||
"coefficient_unchanged": true,
|
||||
"old_extra_gain": "clamp(280/max(length((P75-P59)*pixelSize),2*length((P67-(P74+P60)/2)*pixelSize),1),1,2.25)",
|
||||
"new_extra_gain": "Absent from all3 new shader helper copies and the complete new AIR text; CPU helper is plain clamped-control*.065*commonStrength",
|
||||
"anatomy": "Origin indices64,65,69,70 are lower contour; anchor indices26,34,35,39 are outer lips; eyes0..13 are not controls."
|
||||
},
|
||||
"eye_support_probe": {
|
||||
"authority": "Derived from existing local public-API Vision probe; no new image coordinates or original plug-in execution",
|
||||
"settings": {
|
||||
"vface": 1,
|
||||
"common_strength": 1,
|
||||
"coefficient": 0.065,
|
||||
"pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
]
|
||||
},
|
||||
"samples": [
|
||||
{
|
||||
"seconds": 0,
|
||||
"minimum_eye_distance_over_pin_radius": 2.86112178668839,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 2,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7386373955689196,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 4,
|
||||
"minimum_eye_distance_over_pin_radius": 2.0723834235969316,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 6,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7994186406360964,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 8,
|
||||
"minimum_eye_distance_over_pin_radius": 2.720538093620307,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 10,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7459899006401245,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 12,
|
||||
"minimum_eye_distance_over_pin_radius": 2.8522571566241655,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 14,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7849986024852744,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 16,
|
||||
"minimum_eye_distance_over_pin_radius": 2.86097776991491,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 18,
|
||||
"minimum_eye_distance_over_pin_radius": 2.4994391012873294,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 20,
|
||||
"minimum_eye_distance_over_pin_radius": 2.3076941598447127,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"limits": [
|
||||
"No reference shader runtime or pixel comparison performed.",
|
||||
"The commonStrength caller-source semantics are not fully traced; formula reports the helper input.",
|
||||
"CPU prechecks/license/module gates are observed but are outside the independently authored geometry reconstruction.",
|
||||
"Eye support results apply to the11 existing saved Vision samples, not every possible pose.",
|
||||
"No product sources, app build, host session or Git were changed."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# 2.4.0 面板参数迁移
|
||||
|
||||
2026-10-22(Asia/Shanghai)。用户通过截图纠正原需求:迁移新版面板参数,并非新增身体瘦身。此前[瘦身目标核对](瘦身迁移目标核对.md)保留为历史调查;本次继续工作使用 `codex/new-beauty-controls`,不再等待其他目标包。
|
||||
|
||||
## 参考与证据
|
||||
|
||||
目标:`/Users/dayu/Downloads/MSE18V2.app`,2.4.0 / 20260724150000;插件通用二进制 SHA-256:`577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`;arm64 切片:`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。分析使用 Ghidra 12.1.4 与只读 Mach-O 元数据/反汇编,原文件未改。
|
||||
|
||||
| 参考面板 | 目标字段/转换 | 本项目入口 |
|
||||
| --- | --- | --- |
|
||||
| 磨皮程度 | ID12 → midtoneDetail,直接 0–100% | 保留 PGMidtone 12,调整名称 |
|
||||
| 微细锐化 | ID4 → sharpness,局部细节恢复 | 新 PGMicroDetail 77;原全局锐化 4 留在更多设置 |
|
||||
| 五官保护 | ID30 → featureProtectionRelease = 1 − UI;旧 bool 随 release 接近 1 而关闭 | 新 PGFeatureProtectionAmount 75,直接保护量;旧 bool 30 保留类型与读取 |
|
||||
| 非肤色区保护 | ID17 → highPassDetail = 1 − UI;新主路径用于肤色蒙版扩展 | 新 PGNonSkinProtection 76;原独立全局磨皮 17 留在更多设置 |
|
||||
| 白牙、检测框预览、多人及脸型 | 截图中的这些项已经存在 | 保留;检测框名称调整、多人模式增加提示 |
|
||||
|
||||
两个新保护量默认为 100%,微细锐化默认为 0%。内部使用直接保护量,不直接复用参考包的反向 release 数值。
|
||||
|
||||
`setFloatValue:parameterID:minValue:maxValue:`(`0x1000116d8`)分别反转 17/30 的输入;Evidence:`ev_1fb7d2361dabf814edd6f22d217265b63efa9af24739741772ad5f579e0c67e3`。`valuesForControlPanelValue:` 返回相应原始字段;Evidence:`ev_20da8abf4eb5101b0902627255c643a783b7a15337aa4a757820ab71616f33e7`。显示格式 `strength` 是直接乘 100,只有 `protectionInverse` 格式自身反转;17/30 在绘制与交互同步时提前反转,不能把所有 strength 控制都解释为反向。格式函数汇编 Evidence:`ev_8e2a143f81d173c7643ecee2f1dac4a02145edbf82f113c8a48271428baf747c`。
|
||||
|
||||
目标原生处理入口 `applySkinSmoothingToImage:…`(`0x1000358d8`)把 params+0x50 用于非肤色参与,把 params+0x48 用于五官保护释放。Evidence:`ev_34eb4fe26dbaed9fc37d664d9363db903339c1447b6cd7fdb1980dcd61e99572`。可读 CI 内核字符串建立两个关键关系:肤色蒙版向白色线性扩展;保护蒙版与未保护蒙版按 release 线性混合。细节恢复使用原画与低频图的差,并受局部蒙版和亮度/纹理门控。字符串证据:`ev_d02bfe8046953e9287bd46c5403e6585354a5aa6df782a775d6a6fd0d96f1d62`。这里只记录公式和含义,不提交目标模型、metallib 或资源。
|
||||
|
||||
## 实施与兼容
|
||||
|
||||
本项目继续使用自研 Vision 几何蒙版与 Core Image 管线。新的平滑支持蒙版通过现有未保护/已保护覆盖率恢复五官衰减比例,再对非肤色区域扩展;两个控制独立于曝光/肤色蒙版。默认 100%/100% 直接沿用原覆盖路径。微细锐化在局部支持区域恢复亮度细节与少量色彩细节,可在磨皮量为零时独立使用。
|
||||
|
||||
原目标的语义蒙版、特征形状、纹理处理和复杂组合尚未全链对齐,因此本次是参数含义、连续控制和对应局部处理的迁移,不表示整个新版已逐像素复刻。旧版全局磨皮/全局锐化仍可通过更多设置使用,不与新保护项偷换含义;历史工程保留原强度。
|
||||
|
||||
PGBeautySettings v2 尾部增加三个 float,保留 v1 的 160 字节前缀。解码只接受 v1+160 字节或 v2+新完整长度;旧状态补中性默认值。PGInspectorState 仍使用 schema 1 数值字典,旧 bool 30 迁移到缺失的 75,新数值存在时优先采用新值。面板提交先保存权威对象 210,成功后再镜像旧 bool;每次拖动步进仍使用独立宿主 action。
|
||||
|
||||
模板继续发布原 210 对象与两项署名。新隐藏参数由插件注册和缺省值补齐,原 `.moef` 字节未改,无须覆盖用户模板。固定 Bundle ID、滤镜 UUID、安装路径及宣传资源不变。
|
||||
|
||||
## 验证
|
||||
|
||||
最终通过 1636 项:Beauty 57、Face 116、几何 796、宿主适配 ASan 341、OSC ASan 98、Inspector ASan 228(其中 1 项为可选离屏 PNG 输出)。新增检查包含保护量 0/50/100 的像素响应、非肤色保护只改变局部磨皮支持、微细锐化区域、颜色覆盖隔离、v1 状态迁移与错误长度拒绝、新滑杆归档/插值/输入/重置/旁路/主开关、松手前中间状态发布。离屏 AppKit 面板在多种宽度检查;原生宿主视觉验收需另记实际结果。
|
||||
|
||||
完整 REA 证据仅在忽略的 `build/body-analysis/new-controls-evidence.json`。本文保留目标身份、入口、公式与边界,恢复构建不依赖该本地调查目录。
|
||||
@@ -0,0 +1,53 @@
|
||||
# 瘦身迁移:目标版本核对
|
||||
|
||||
核对日期:2026-10-22(Asia/Shanghai)。开发分支:`codex/body-slimming`;源码基线:`13821366a5baee9beea40972118d7fe634b5c735`。
|
||||
|
||||
**后续已澄清**:用户通过截图确认记错了,实际需求是迁移新增面板参数。后续以[新版磨皮参数迁移](新版磨皮参数迁移.md)为准,下面保留纠正前的有界调查结论,不再表示当前等待其他插件包。
|
||||
|
||||
## 当前结果
|
||||
|
||||
用户指定的新目标为 `/Users/dayu/Downloads/MSE18V2.app`。已读取项目交接并检查目标包,**尚未定位到可迁移的新增“瘦身”板块**。当前只完成目标核对与接入点调查,未修改产品源码、模板或正式安装的 1.2.0 APP,未编译或执行目标程序。
|
||||
|
||||
接续时先请用户确认瘦身控制的具体名称、面板画面或包含该功能的目标包路径。不能把现有“瘦脸”误当作“瘦身”,也不能自行设计身体变形后称为已迁移原版算法。
|
||||
|
||||
## 目标身份
|
||||
|
||||
| 项目 | 新下载目标 | 旧安装参考 |
|
||||
| --- | --- | --- |
|
||||
| APP 路径 | `/Users/dayu/Downloads/MSE18V2.app` | `/Applications/MSE18V2.app` |
|
||||
| 外层与插件版本 | `2.4.0` / `20260724150000` | `1.0.20260617-170517` / `20260617170517` |
|
||||
| 插件 Bundle ID | `com.ms.plugins.mse18v2` | `com.ms.plugins.mse18v2` |
|
||||
| 插件通用二进制 SHA-256 | `577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109` | `6c5d74bc844a5c5f745718b48ea10ec6635d08aa08a5b6dc6e62653980849f8a` |
|
||||
|
||||
新插件 arm64 切片 SHA-256:`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。插件二进制位于各 APP 的 `Contents/PlugIns/MSE18V2.pluginkit/Contents/MacOS/MSE18V2`。
|
||||
|
||||
## 已观察证据与范围
|
||||
|
||||
- 对新旧包的外层和插件、arm64 与 x86_64 切片,静态检查 `__ustring`、`__cstring`、`__objc_methname`、`__objc_classname`。在这些段内未发现“瘦身、瘦腰、瘦腿、身体”及对应 body/slim/waist/slender/stretch/shoushen 功能命名。可读板块仍为磨皮、美白、瘦脸;新包另有“预览设置、肤色范围、非肤色区保护”等文字。这是有界字符串检查,不能排除动态生成或其他未解释数据。
|
||||
- 新插件 arm64 的 Ghidra 参数注册函数 `MSSuperSkinSmoothingPlugIn::addParametersWithError:`(`0x10001fc10`)注册面板 210、磨皮/肤色/现有脸型参数和三模块开关,所见注册列表没有身体参数。Evidence:`ev_4d3e7e7dc8aa21347adbd0f0847fab13e8b69462bd5e6adf3657cbc0c1998266`。
|
||||
- 面板值类的方法包括 `faceThin`、`faceNarrow`、`faceChin`、`faceJaw`、`faceSmallHead` 等,以及 skin/tone/face 三个模块开关。过程名称搜索没有返回身体变形入口;不能由名称负结果断言所有匿名函数均不存在身体算法。Evidence:`ev_446e4a969ff46db0600fe15988d0f396f394641aaeac760d6372a0c0509bf177`、`ev_157df22ee7802216f3581c9842a9629c69ee66097db068b825695bdfd99385d1`。
|
||||
- 所见几何 GPU 管线仍为 `faceThin*`;新旧 metallib 的 12 个命名函数集合相同。文件变大不能证明新增身体算法,也不能由相同函数名断言函数内容相同。
|
||||
- REA 对提供者已定义字符串对象的搜索只返回无关的 `URLRequest.httpBody`。Ghidra 未在该搜索中解码中文 UTF-16 常量,因此中文检查另使用实际 Mach-O 字节,未把 REA 空结果当作整个包不含中文的证据。Evidence:`ev_015a585ce5565d874f5b55af0c363bed634f09a29088ef660d3ca1c547626c26`。
|
||||
|
||||
REA 使用 Ghidra 12.1.4。通用 Mach-O 不支持该提供者直接选架构,故只读提取 arm64 切片分析。会话已关闭;切片、完整证据和快照仅保存在忽略的 `build/body-analysis/`,不作为构建或远端恢复依赖,不上传原版 APP、模型或 metallib。上述地址与 Evidence ID 仅对应本次 SHA,目标改变后需重新核对。
|
||||
|
||||
## 已完成与待定事项
|
||||
|
||||
| 问题 | 状态 |
|
||||
| --- | --- |
|
||||
| 项目交接、Git 基线、现有正式安装身份 | 已核对,产品源码未改 |
|
||||
| 新下载包身份及与旧包差异 | 已核对;确为不同内容 |
|
||||
| 新增瘦身控制、默认值、范围、画布操作 | 未定位,需确认正确目标 |
|
||||
| 身体算法、处理顺序、跟随与蒙版行为 | 未建立证据,未实施 |
|
||||
| 产品编译、回归、签名、公证、安装 | 本次未执行 |
|
||||
|
||||
## 确认目标后的接入提示
|
||||
|
||||
现有工程只有人脸几何,新增身体效果应有独立状态与总开关,不能依赖人脸检测成功。具体控制数量、范围、算法和顺序以正确目标的证据为准。
|
||||
|
||||
- `PGInspectorState.m` 的描述表同时驱动面板、归档和插值。保留参数 210 及既有 ID;数值字典缺失项会补默认值。新增卡片时,`PGInspectorView.m` 需按 section 识别“更多设置”,不能继续依赖 `index==3`。
|
||||
- `PGBeautySettings` 当前是 160 字节 v1 裸结构体。若追加字段,应保留旧前缀并明确接受旧版本/长度组合,补齐新默认值;同步修改宿主解码,拒绝截断、超长或未知版本。不要只更改 `sizeof` 检查。
|
||||
- OSC 必须同步完整面板对象 210,单写隐藏参数会被已编辑的面板状态覆盖。OSC 回调使用宿主已建立的参数上下文,不能套用面板的 `startAction/endAction` 路径;保留原选脸 ID 和 UUID。
|
||||
- 身体变形需核对与外观处理、四类蒙版及整体混合的先后关系;验证无人脸、非零 extent、原点标签、极端参数、旧归档、撤销、连续拖动与保存重开。
|
||||
|
||||
本次分支基线已在 `origin` 和 `github` 读回核验。两端的最新研究记录以当前分支引用为准;尚无瘦身功能交付标签。
|
||||
@@ -0,0 +1,112 @@
|
||||
# 瘦脸跟踪闪烁:1.3.2 与目标 2.4.0 的对齐缺口
|
||||
|
||||
最新状态(2026-10-23):1.3.3(18)已实施下文记录的稳定链与瘦脸/大眼局部场修正,签名公证后正式安装并同步双仓/文章。2122项正常回归通过;原生时间线闪烁改善仍待用户复测。本文开头保留1.3.2诊断基线,实施与数值场结论见后续章节及 `../verification/v1.3.3/`。
|
||||
|
||||
2026-10-22。用户实测同一段素材,本插件瘦脸跟踪闪烁,目标插件稳定。本次分析基线为 `b58fec1a86db7a2e474e1cc65a5911447b5906b9`,已安装版仍为 1.3.2(17)。完成源码审查、隔离合成复现、静态二进制对照和当前素材的独立连续帧采样;通过宿主界面读取状态并定位源文件,没有修改参数/片段、产品源码或重新编译 APP。
|
||||
|
||||
主要缺口在跨帧几何的有效性判定、坏帧保持与缓存更新。此前恢复单帧瘦脸位移场,并没有完整对齐新版目标的连续跟踪链。以下区分已经复现的本品行为、目标的静态分支,以及尚未定位到用户素材具体帧的部分。
|
||||
|
||||
## 目标版本与旧分析的边界
|
||||
|
||||
本次目标是用户指定的 `/Users/dayu/Downloads/MSE18V2.app`,版本 **2.4.0 / 20260724150000**。插件通用二进制 SHA-256 为 `577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`,arm64 切片为 `afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。切片逐字节核对过本次目标,REA 使用 Ghidra 12.1.4。随后仅读取已运行的系统 FxPlug 目标进程,其2.4.0可执行文件摘要与Downloads目标一致;本次没有启动目标、附加调试器或采集其内部几何。
|
||||
|
||||
原有 [auto-follow-report.json](auto-follow-report.json) 分析的是 `/Applications/MSE18V2.app` 的旧版 `1.0.20260617-170517`,通用二进制 SHA 为 `6c5d74bc844a5c5f745718b48ea10ec6635d08aa08a5b6dc6e62653980849f8a`。其中 temporal 混合系数和历史优先级不能直接当成 2.4.0 的默认瘦脸实现。
|
||||
|
||||
新版 `renderDestinationImage`(`0x10002179c`)的单主要人脸几何分支直接调用 **`mss_pinStyleFacePoints…`(`0x10003d69c`)**。后者在筛选当前几何后,选择接纳新点或回用上一组有效点,并可向 `trackedFaceBox…`(`0x10003cc78`)请求连续跟踪框。旧 `temporalFacePoints…` 方法仍存在,但当前提供者没有解析到它的直接调用者;这不能排除任意 Objective-C 间接调用,却足以纠正“只按旧 temporal 方法调平滑系数即可对齐新版”的假设。
|
||||
|
||||
对应 Evidence:render `ev_2330b66132cd6539b8c66313c8dc43ca6ff5eb3e0881abbbe26857f99de6a83b`;pin-style `ev_58dee36fddf4e4c98ce3d880a0bb98190351d1269c960b3ccc275aef81265e8f`;直接调用关系 `ev_568a93f2165e5dc5046e610f47c23e9cebc33f55b5d12d3ee005a1e99a7191f6`、`ev_a8cf6f3aec6fbcf2b698ab8ec52313e20a6a5e0d636bc922c4293e436861db7e`、`ev_7c53c39d245e0063cab89358ab8948cdd734488460464d5f455674bb80a1515a`。
|
||||
|
||||
## 当前时间线素材的连续帧核对
|
||||
|
||||
用户补充截图后,在 Final Cut Pro 当前时间线选中片段,通过“文件 → 在访达中显示”确认源视频为 `girl-in-sun-hat-smiling-in-rural-field-2026-10-03-13-54-14-utc.mov`。项目为 1080p25,选中片段从18:18到37:11,瘦脸1.00、大眼0.90355、多人模式关闭。没有修改参数或片段;检查结束返回 FCP。
|
||||
|
||||
直接调用当前产品检测器与跟踪器,在独立1920×1080解码上按25fps采样源文件全长18.752秒,共 **469帧**。源帧率为29.97003,因此这里模拟项目的采样节奏,并非逐一处理所有源帧,也不等同于FCP的实时请求/色彩/尺寸路径。
|
||||
|
||||
- 469帧全部为单脸且完整76点;空检测、部分点、held、Vision/解码错误均为0,关键点置信度最低0.814。**本段离线检查没有触发上文合成的“缺点使瘦脸归零”路径,也没有触发低于0.55的置信度条件。不能将它直接认定为当前素材的主因。**
|
||||
- 最大轮廓形状步幅出现在请求源时间5.72秒(实际取到5.7057秒)附近。扣除前后检测框的平移/缩放后,raw轮廓RMS步幅为脸框尺度的6.33%,当前稳定输出仍为5.24%;眼部区域步幅7.11%。同一步检测框尺寸变化7.23%,框中心变化0.01061(全图归一化距离)。
|
||||
- 变化较大的连续区间包括源5.56–5.76秒,另有0.7–0.92秒与片尾。按照所选片段位置、假设源入点为0且未变速,5.72秒约对应时间线24:11,与AX播放头24:11相近;未导出源入点/重定时,且检视器LCD同时为35:22,不能断言用户截图就是该源帧。
|
||||
- 数值包含真实头部旋转和表情变化;平移/缩放抵消并未消除这些运动。因此它证明“检测仍成功时,几何变化大部分继续进入变形”,尚未量出其中多少属于错误检测。瘦脸和接近0.90的大眼都开启,大眼实现仍为近似,需要独立排查其视觉贡献。
|
||||
|
||||
这次素材的排查优先级应先放在**完整有效帧的框/点变化如何进入瘦脸,以及高强度大眼叠加**,再核对新版目标的连续框、几何质量判定与时间状态。一般性的部分失检、空缓存和蒙版缺口仍成立,但不能拿其他情境的合成失败代替这段素材的逐帧归因。
|
||||
|
||||
[当前素材标量摘要](tracking-flicker-20261022/current-clip-summary.json) 保存计数、分布和峰值时间;原视频、截图和完整真实关键点没有上传。通用诊断源码为 `scripts/inspect-tracking-sequence.m`;包含生产 .m 以复用真实静态几何转换和跟踪器,编译时只编译该诊断入口,不再重复链接 PGFaceProcessor.m。
|
||||
|
||||
## 已确定的差异
|
||||
|
||||
| 环节 | 当前 1.3.2 | 目标 2.4.0 的静态证据 | 对闪烁的意义 |
|
||||
| --- | --- | --- | --- |
|
||||
| 部分关键点失效 | 有合法脸框就接纳;当前缺 76 点时删去完整拓扑,且不标为 held | 接纳前要求足量点、轮廓、有限坐标、有效五官布局和置信度;不合格时可回用上一组有效点 | 当前会在部分失效帧直接关闭瘦脸,目标有完整形状保持路径 |
|
||||
| 框与几何稳定 | 每次重新检测,旧点先映射到当前原始框;没有连续对象框跟踪器 | pin-style 可调用 VNSequenceRequestHandler / VNTrackObjectRequest,坏帧可把旧点映射到可用跟踪框 | 当前框噪声完全进入几何;目标另外维护连续框和上次有效形状 |
|
||||
| 异常姿态与跳点 | 主要判断眼轴翻转;合法有限 76 点一般直接进入混合 | 额外检查眼/鼻/口/下轮廓结构、前后几何兼容及归一化点位跳变的中位数/P90 | 当前会接受点数足够但位置不可靠的帧 |
|
||||
| 同帧检测复用 | 每个请求新建 Vision handler;几何缓存要求 raw 也完全相同才命中 | 人脸检测有按帧时间、输入范围和 tile 范围复用的缓存,并有重试分支 | 当前重复请求可能产生不同 raw 后重新计算;未测得其在用户素材中的发生频率 |
|
||||
| 丢检时的外观支持 | 默认几何可以保持,但皮肤/牙齿/眼睛蒙版仍取 raw 检测 | 本次只完整核对目标的瘦脸主路径,未恢复其全部外观蒙版稳定策略 | 本品已复现几何保持时外观蒙版清零,可能叠加视觉闪烁;不把目标外观路径宣称为已完全对齐 |
|
||||
|
||||
pin-style 的接纳分支复制本帧合格点,保持分支使用旧有效点并尝试框重映射。因此**不能据旧报告把“目标平滑更强”或某个固定混合权重当作这次原因**。应优先恢复它筛掉坏几何、保留有效几何的机制。
|
||||
|
||||
目标跟踪器还有开关与时间管理:静态初始化检查 `MSE18_DISABLE_FACE_THIN_VISION_TRACKER`,通常未设置时启用;已核对初始化汇编的 OR/EOR 写入。跟踪方法包含同帧复用、时间倒退/间隔后的重置、跟踪结果置信度检查和短期保框分支。这里证明默认配置下的可达控制流,没有记录用户宿主内实际环境变量或运行命中次数,不能称为运行验证,也不能仅添加一个 VNTrackObjectRequest 就声称完整复刻。
|
||||
|
||||
## 隔离复现结果
|
||||
|
||||
探针直接链接当前 `PGFaceProcessor.m`,用自造 256×256 图与合成关键点调用实际选择器、变形和蒙版实现。没有使用用户画面、真实人脸点阵或目标运行结果。运行 `zsh scripts/diagnose-tracking.sh` 输出 JSON;它是诊断统计,退出码 0 只表示执行完成。
|
||||
|
||||
1. **76 → 缺 76 → 76,瘦脸中间一帧完全归零。** 三帧一直有输出脸框,点数为 `76/0/76`,held 全为 false。只开瘦脸时,相对原图的变化通道数为 `85835/0/85835`,中间帧像素完全直通。源码入口:`PGFaceProcessor.m` 208–227、308、532–554、645–646。这证明了一个足以造成闪烁的路径;没有测量它在用户视频中的出现率。
|
||||
2. **纯脸框抖动衰减为 0%。** 25fps、20 帧,框的 X 方向交替 ±0.004,框内点保持一致;输入和稳定后的点位步幅均为 0.008,输出/输入振幅比 `1.0`。源码 177–186、196、214–217 的重映射原样继承了框平移。目标对各种轻微框噪声的最终响应尚未做数值对照,不能把此数值直接说成两插件的实测差值。
|
||||
3. **当前点混合在 25/30fps 时采用 90% 新点。** 60fps 为 50%,120fps 为 25%;现有 10ms 用例只检查 30% 新点。掉检后重获还跳过 76 点混合而直接采用 raw。源码 186、211–225、308;现有 `slim_tests.m` 408–410 明确要求重获采用 raw。这解释当前实现为何对扰动敏感,不是目标 2.4.0 权重的证据。
|
||||
4. **空缓存会保留第一次请求顺序的结果。** 先请求 40ms 空帧,再补入 0ms 有效脸,重播 40ms 仍输出 0 脸;按 0→40ms 请求则输出 1 脸。源码 279 的命中直接返回,插入早期帧不会更新后续结果。宿主锁只串行化到达顺序;并发测试只验证安全和重复一致,没有要求不同到达顺序获得相同几何。尚未记录用户宿主实际请求顺序。
|
||||
5. **几何保持不等于美容蒙版保持。** 默认路径掉检时几何脸数仍为 1,colorMask 均值从 `0.3952` 变为 `0`,skinMask 从 `0.2967` 变为 `0`。生产入口强制 singleFace=0,走源码 664–666 的 raw 外观支持;单人 held 外观分支并未在该默认路径使用。
|
||||
6. **多人仍有额外边界。** 默认关联只按防跳区域内距上一框中心最近者选脸;自造交叉可选到陌生人。fastMulti 直接返回 raw,不做当前单主要人脸的保持。此项没有证明用户单人素材发生了换脸,修复时应单列验收。
|
||||
|
||||
原 1901 项回归主要证明单帧图像、几何和接口行为。已有跟随测试检查完全空检测、10ms 扰动与缓存重复安全,没有覆盖“76 点短暂不完整”的连续帧,也没有以常用帧率约束抖动幅度。此前每两秒取一帧、共 11 帧的真实视频检查同样不能替代连续序列稳定性验收。
|
||||
|
||||
## 建议修复顺序与验证要求
|
||||
|
||||
- **先处理部分失效和异常几何。** 在接纳新主脸前检查完整拓扑与五官布局;不合格时进入上一组有效形状的保持/重映射路径。明确区分有效检测时间、输出时间和保持状态,避免仅靠刷新输出时间无限保持。
|
||||
- **再对齐连续框、重获和时间管理。** 结合新版默认可达跟踪链处理同帧、倒退、跳时、正常运动及重获;从转头、遮挡恢复检查形状是否突然跳回 raw。先逐条核对机制,再决定系数,避免用增加滞后来掩盖坏点。
|
||||
- **补齐缓存和外观同步。** 明确同帧结果与新增前帧历史的失效关系、源切换隔离及默认蒙版跟随;以顺序/倒序/重复/多线程请求对照输出。
|
||||
- **用同一段素材做连续帧验收。** 锁定宿主、原始帧率、预览/导出条件和相同单项参数;记录检测有效性、保持原因、框/点扰动与效果开关变化,和目标逐帧对照。单张图正常、自动用例通过都不足以宣布闪烁修复。
|
||||
|
||||
当前素材、宿主和可见参数已确认,并完成469帧独立采样;有效点短暂缺失未在该采样中出现。实现缺口与几何变化已定位,目标与本品的原生同帧输出、源入点映射和大眼贡献仍未分离,尚未认定唯一原因。本次不构建新 APP,不更新安装包或文章。
|
||||
|
||||
## 保留资料
|
||||
|
||||
- [诊断结果](tracking-flicker-20261022/synthetic-results.json)
|
||||
- [目标版本、源码指纹和范围](tracking-flicker-20261022/manifest.json)
|
||||
- [选取的完整 REA Evidence 记录](tracking-flicker-20261022/rea-evidence.json),含原始/规范化结果与提供者限制;为互操作研究资料,不包括目标 APP 或 metallib。
|
||||
- 探针源码 `scripts/diagnose-tracking.m` 与入口 `scripts/diagnose-tracking.sh`。构建依赖与项目一致,需 macOS 的 Core Image/Vision;生成文件位于忽略的 build 下。
|
||||
|
||||
Ghidra 对部分 CGRect、CMTime 和返回寄存器的恢复不完整。报告依据渲染调用关系、完整点门槛、接纳/保持内存分支及初始化汇编作结构判断;未声称所有阈值布尔表达式与目标逐条等价。REA 会话已保存并关闭,证据可离线复查。
|
||||
|
||||
|
||||
## 连续帧诊断恢复与复用
|
||||
|
||||
在项目根执行(先创建 build 目录):
|
||||
|
||||
```sh
|
||||
mkdir -p build/tracking-diagnostics
|
||||
xcrun clang -fobjc-arc -fmodules -mmacosx-version-min=13.0 \
|
||||
-framework Foundation -framework AVFoundation -framework CoreImage \
|
||||
-framework CoreGraphics -framework CoreMedia -framework Metal \
|
||||
-framework Vision -framework ImageIO scripts/inspect-tracking-sequence.m \
|
||||
-o build/tracking-diagnostics/inspect-sequence
|
||||
build/tracking-diagnostics/inspect-sequence '/绝对路径/源素材.mov' \
|
||||
build/tracking-diagnostics/sequence.json 25 1920 18.72
|
||||
```
|
||||
|
||||
最后三个参数是采样帧率、解码最长边与诊断时间偏移;18.72只来自本次所选片段位置,分析其他素材按实际设置。程序不导出图片或完整真实点阵,输出含逐帧标量;本次只提交汇总,详细本地数据保持在 build。用户视频和目标二进制均未随仓库分发,重跑具体素材需要自行提供原文件;二者不是产品构建依赖。源码、合成诊断及本次标量/静态证据均随 Git 保存。
|
||||
|
||||
|
||||
分析与连续帧诊断的可恢复节点为 `a0c5357efd87a63dbee6269d9335e6aa3ba78799`,已推送并读回双远端。从 GitHub 匿名独立克隆核对284个文件的字节/blob/执行位、strict/full fsck,并重新构建合成诊断、逐项复现保存的JSON;产品源码与v1.3.2相同,无LFS/子模块。见[恢复回执](tracking-flicker-20261022/recovery.json)。后续main仅补充恢复说明,不改变已安装版或历史标签。
|
||||
|
||||
|
||||
## 2.4.0 对齐实施中(2026-10-22)
|
||||
|
||||
用户已要求实施。新增静态证据见 `tracking-flicker-20261022/implementation-evidence.json`。补核对检测长边默认960(0x1000bd1f8),失败/空结果/不足76点时使用RGBA CGImage重试;下巴轴为点66、67、68按1:1.65:1加权减脸框中心,并非眼轴。接纳分支仍为原样复制合格点。新代码已加入对应检测、连续框、质量门槛、下巴轴/中位数/P90保护和保持重映射,反向/模式变化重置对象跟踪,同帧检测和几何复用。
|
||||
|
||||
同一草帽素材1920解码、25fps离线重跑469帧:连续框469帧可用,检测/完整76/结构/置信均合格,held为0。输出轮廓步幅P95为0.03344、峰值0.06458;旧输出P95为0.02872、峰值0.05240。两者包含真实动作,不能把更大的输出步幅称为闪烁改善,也不能用合成坏点测试代替此片段的最终视觉验收。实施继续追查关键点后的变形路径;尚未发布或替换已安装版。完整实拍点阵/帧不入仓,仅保留标量摘要。
|
||||
|
||||
|
||||
### 后续变形核对与范围纠正
|
||||
|
||||
新shader虽含region算法,但本次确认的主encoder与fallback将buffer4(faceThinMode)写0;buffer8=1是sampleFlipY。不能因region函数存在或buffer8值为1,就称其默认启用。见 `tracking-flicker-20261022/region-mode-review.md` 与 `renderpath-evidence.json`(完整主render指令、encoder汇编及CPU参数)。本轮保留实际可达pin算法,未移植region。
|
||||
|
||||
另查明与当前片段叠加相关的两处差异:2.4.0的CPU thin系数为user×0.025,pin shader直接使用,移除本品旧版280像素sizeGain;大眼采用点6/13瞳孔为中心、点0–1/7–8的像素距离为半径,user×0.15与圆形二次权重,先左后右。本品原来使用眼区外框中心、脸框椭圆和smoothstep²,已改为上述明确公式。当前片段大眼约0.90355,不能将其影响全部归于瘦脸跟踪。其余窄脸/颧骨/小头近似与下巴/短脸/下颌既有尺寸增益不在本轮逐像素对齐范围内。
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"repositoryId": 1428817365,
|
||||
"oldName": "FAMEDaYu/FCP-BeatyGril",
|
||||
"newName": "FAMEDaYu/FCP-BeautyGirl",
|
||||
"url": "https://github.com/FAMEDaYu/FCP-BeautyGirl",
|
||||
"baselineCommit": "cd2e608ec6bb92bb6bb0923e4fb4b7728404c67a",
|
||||
"allBranchAndTagRefsUnchanged": true,
|
||||
"releaseAndAssetIdsUnchanged": true,
|
||||
"githubRemote": "https://github.com/FAMEDaYu/FCP-BeautyGirl.git",
|
||||
"sourceProductUnchanged": true,
|
||||
"date": "2026-10-22",
|
||||
"links": {
|
||||
"redirects": [
|
||||
{
|
||||
"old": "https://github.com/FAMEDaYu/FCP-BeatyGril",
|
||||
"new": "https://github.com/FAMEDaYu/FCP-BeautyGirl",
|
||||
"redirectCode": 301,
|
||||
"newURLStatus": 200
|
||||
},
|
||||
{
|
||||
"old": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.3.1",
|
||||
"new": "https://github.com/FAMEDaYu/FCP-BeautyGirl/releases/tag/v1.3.1",
|
||||
"redirectCode": 301,
|
||||
"newURLStatus": 200
|
||||
}
|
||||
],
|
||||
"articleCanonicalLinksVerified": true
|
||||
},
|
||||
"globalRepositoryIndex": {
|
||||
"remote": "https://dayu.media/git/dayu/codex-global-rules.git",
|
||||
"baseline": "8d3558429efd22af8bad49c03060da326cb231d3",
|
||||
"commit": "750b430b75e4ccdf5badae8ee3f88a07144b3a9e",
|
||||
"trackedFilesCompared": 11,
|
||||
"independentCloneAndFsck": true,
|
||||
"changedFile": "REPOSITORIES.md"
|
||||
},
|
||||
"githubReleaseNotes": [
|
||||
{
|
||||
"id": 420500792,
|
||||
"tag": "v1.3.1",
|
||||
"assetsUnchanged": true
|
||||
}
|
||||
],
|
||||
"dayuReleaseNotes": [
|
||||
{
|
||||
"id": 136,
|
||||
"tag": "v1.3.1",
|
||||
"assetsUnchanged": true
|
||||
}
|
||||
],
|
||||
"article": {
|
||||
"id": 15593,
|
||||
"url": "https://dayu.media/15593/",
|
||||
"change": "GitHub repository name/URL only",
|
||||
"downloadCoverSeoAndAccessPreserved": true
|
||||
},
|
||||
"immutableArtifacts": "Existing version tags, notarized APP/PKG and published source ZIP bytes retained; no rebuild or installer upload."
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"remote": "https://github.com/FAMEDaYu/FCP-BeautyGirl.git",
|
||||
"commit": "6a29d52a9ad667665da4acf75017c008fa0a566d",
|
||||
"anonymousClone": true,
|
||||
"trackedFilesCompared": 239,
|
||||
"bytesAndExecutableModesMatched": true,
|
||||
"gitFsckFullStrict": true,
|
||||
"productSourceUnchangedFrom": "cd2e608ec6bb92bb6bb0923e4fb4b7728404c67a",
|
||||
"lfs": false,
|
||||
"submodules": false,
|
||||
"temporaryCloneRemoved": true
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"oldLogin": "FAMEDaYu",
|
||||
"newLogin": "dayumeida",
|
||||
"accountId": 117798680,
|
||||
"profileURL": "https://github.com/dayumeida",
|
||||
"repositories": [
|
||||
{
|
||||
"id": 1428817365,
|
||||
"oldName": "FAMEDaYu/FCP-BeautyGirl",
|
||||
"newName": "dayumeida/FCP-BeautyGirl",
|
||||
"allRefsUnchanged": true,
|
||||
"releasesAndAssetsUnchanged": true
|
||||
},
|
||||
{
|
||||
"id": 904215594,
|
||||
"oldName": "FAMEDaYu/FCPX-",
|
||||
"newName": "dayumeida/FCPX-",
|
||||
"allRefsUnchanged": true,
|
||||
"releasesAndAssetsUnchanged": true
|
||||
}
|
||||
],
|
||||
"localGithubRemote": "https://github.com/dayumeida/FCP-BeautyGirl.git",
|
||||
"date": "2026-10-22",
|
||||
"links": {
|
||||
"redirects": [
|
||||
{
|
||||
"old": "https://github.com/FAMEDaYu/FCP-BeautyGirl",
|
||||
"final": "https://github.com/dayumeida/FCP-BeautyGirl",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"old": "https://github.com/FAMEDaYu/FCP-BeatyGril",
|
||||
"final": "https://github.com/dayumeida/FCP-BeautyGirl",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"old": "https://github.com/FAMEDaYu/FCP-BeautyGirl/releases/tag/v1.3.1",
|
||||
"final": "https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.1",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"old": "https://github.com/FAMEDaYu/FCPX-",
|
||||
"final": "https://github.com/dayumeida/FCPX-",
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"newProfileStatus": 200,
|
||||
"articleLinksVerified": true
|
||||
},
|
||||
"globalRepositoryIndex": {
|
||||
"remote": "https://dayu.media/git/dayu/codex-global-rules.git",
|
||||
"baseline": "750b430b75e4ccdf5badae8ee3f88a07144b3a9e",
|
||||
"commit": "dde7e2ee26eae18627eefda9b956a6aca52354ad",
|
||||
"trackedFilesCompared": 11,
|
||||
"independentCloneAndFsck": true,
|
||||
"changedFile": "REPOSITORIES.md"
|
||||
},
|
||||
"githubReleaseNotes": [
|
||||
{
|
||||
"id": 420500792,
|
||||
"tag": "v1.3.1",
|
||||
"assetsUnchanged": true
|
||||
}
|
||||
],
|
||||
"dayuReleaseNotes": [
|
||||
{
|
||||
"id": 136,
|
||||
"tag": "v1.3.1",
|
||||
"assetsUnchanged": true
|
||||
}
|
||||
],
|
||||
"article": {
|
||||
"id": 15593,
|
||||
"url": "https://dayu.media/15593/",
|
||||
"change": "GitHub owner URL only",
|
||||
"downloadCoverSeoAndAccessPreserved": true
|
||||
},
|
||||
"sourceArtifacts": "No change to product source or APP/PKG/source ZIP bytes. Historical verification evidence retains the prior username."
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"remote": "https://github.com/dayumeida/FCP-BeautyGirl.git",
|
||||
"commit": "2faf7de77929cf7707645ebb38095b03d5729647",
|
||||
"anonymousClone": true,
|
||||
"trackedFilesCompared": 241,
|
||||
"bytesAndExecutableModesMatched": true,
|
||||
"gitFsckFullStrict": true,
|
||||
"productSourceUnchangedFrom": "e47736222d3cbf5edadab26b2a28c82987327043",
|
||||
"lfs": false,
|
||||
"submodules": false,
|
||||
"temporaryCloneRemoved": true
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"date": "2026-10-22",
|
||||
"timezone": "Asia/Shanghai",
|
||||
"version": "1.3.0",
|
||||
"build": "15",
|
||||
"status": "passed",
|
||||
"checks": {
|
||||
"beauty": 57,
|
||||
"face": 116,
|
||||
"geometry": 796,
|
||||
"host_adapter_asan": 341,
|
||||
"osc_asan": 98,
|
||||
"inspector_asan_including_optional_preview": 228
|
||||
},
|
||||
"total": 1636,
|
||||
"commands": [
|
||||
"./scripts/test.sh",
|
||||
"PAINTFCP_HOST_ASAN=1 ./scripts/test-host.sh",
|
||||
"PAINTFCP_OSC_ASAN=1 ./scripts/test-osc.sh",
|
||||
"PAINTFCP_INSPECTOR_ASAN=1 PAINTFCP_INSPECTOR_PNG=<local-path> ./scripts/test-inspector.sh"
|
||||
],
|
||||
"notes": [
|
||||
"OSC passed before the later standalone beauty fallback and legacy inspector numeric-read fixes; those fixes do not change OSC code.",
|
||||
"Core, host adapter and inspector rerun after all source fixes.",
|
||||
"Inspector includes one optional offscreen PNG write assertion.",
|
||||
"No native Motion/FCP interaction test performed for this version; active user hosts are preserved.",
|
||||
"Reference interpretation and implementation limitations are in docs/analysis/新版磨皮参数迁移.md."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"status": "installed_user_qa_pending",
|
||||
"bundleIdentifier": "com.dayu.beatygril",
|
||||
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"options": {
|
||||
"waitForHosts": true,
|
||||
"userTests": true
|
||||
},
|
||||
"nativeEffectQA": {
|
||||
"status": "pending_user",
|
||||
"performedByScript": false
|
||||
},
|
||||
"source": {
|
||||
"commit": "2f2c081980dc610ac810f8daf92da8966f310802",
|
||||
"trackedWorktreeChanges": []
|
||||
},
|
||||
"updatedAt": "2026-10-22T07:15:35.383726+00:00",
|
||||
"version": "1.3.0",
|
||||
"build": "15",
|
||||
"stagingSignature": "Executable=/private/tmp/paintfcp-build-20261021/Build/Products/Release/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nCandidateCDHashFull sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nHash choices=sha256\nCMSDigest=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nCMSDigestType=2\nCDHash=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 15:07:35\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
|
||||
"notarization": {
|
||||
"id": "ca96837f-bf33-44fa-8d58-799026ce5c7d",
|
||||
"message": "Processing complete",
|
||||
"status": "Accepted"
|
||||
},
|
||||
"signingVerified": true,
|
||||
"stapleValidated": true,
|
||||
"stagingPluginUnregistered": true,
|
||||
"runningHosts": [],
|
||||
"installedSignature": "Executable=/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nCandidateCDHashFull sha256=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nHash choices=sha256\nCMSDigest=93e3245cafc8ced5f2c01b8a72c8e0c3933eee837831a2d779233e4364dded7c\nCMSDigestType=2\nCDHash=93e3245cafc8ced5f2c01b8a72c8e0c3933eee83\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 15:07:35\nNotarization Ticket=stapled\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
|
||||
"installedSignatureVerified": true,
|
||||
"installedStapleValidated": true,
|
||||
"gatekeeperAccepted": true,
|
||||
"pluginDiscovery": {
|
||||
"bundleIdentifier": "com.dayu.beatygril.fxplug",
|
||||
"formalPath": "/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit",
|
||||
"output": " com.dayu.beatygril.fxplug(1.1)\t97262612-DD61-47F2-B25E-D82B95C893EE\t2026-10-22 07:15:35 +0000\t/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit\n (1 plug-in)\n"
|
||||
},
|
||||
"removedGeneratedPaths": [
|
||||
"/Users/dayu/Documents/PaintFCP/build/delivery/previous-beatygril.app",
|
||||
"/tmp/paintfcp-build-20261021",
|
||||
"/Users/dayu/Documents/PaintFCP/build/delivery/notarization.zip"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"date": "2026-10-22",
|
||||
"timezone": "Asia/Shanghai",
|
||||
"installedProduct": {
|
||||
"path": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"version": "1.3.0",
|
||||
"build": "15"
|
||||
},
|
||||
"signatureAllArchitecturesVerified": true,
|
||||
"duplicateInventory": {
|
||||
"scope": "Listed local paths and existing explicit related PaintFCP paths on mounted volumes; Spotlight additionally queried. Not a full scan of every volume.",
|
||||
"roots": [
|
||||
"/Applications",
|
||||
"/Library/Plug-Ins/FxPlug",
|
||||
"/Users/dayu/Library/Plug-Ins/FxPlug",
|
||||
"/Users/dayu/Documents/PaintFCP",
|
||||
"/Users/dayu/Desktop",
|
||||
"/Users/dayu/Downloads",
|
||||
"/Users/dayu/Library/Developer/Xcode/DerivedData",
|
||||
"/tmp/paintfcp-build-20261021"
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"path": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"version": "1.3.0",
|
||||
"build": "15"
|
||||
}
|
||||
],
|
||||
"errors": []
|
||||
},
|
||||
"temporaryPathsRemoved": [
|
||||
"/tmp/paintfcp-build-20261021",
|
||||
"build/delivery/previous-beatygril.app",
|
||||
"build/delivery/notarization.zip"
|
||||
],
|
||||
"nativeEffectQA": "pending_user"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"status": "waiting_for_host_exit",
|
||||
"bundleIdentifier": "com.dayu.beatygril",
|
||||
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"version": "1.3.0",
|
||||
"build": "15",
|
||||
"source": {
|
||||
"commit": "2f2c081980dc610ac810f8daf92da8966f310802",
|
||||
"trackedWorktreeChanges": []
|
||||
},
|
||||
"notarization": {
|
||||
"id": "ca96837f-bf33-44fa-8d58-799026ce5c7d",
|
||||
"message": "Processing complete",
|
||||
"status": "Accepted"
|
||||
},
|
||||
"signingVerified": true,
|
||||
"stapleValidated": true,
|
||||
"stagingPluginUnregistered": true,
|
||||
"nativeEffectQA": "pending_user",
|
||||
"note": "Prepared Release is Accepted and stapled; installation is waiting for existing user hosts to close. The installed product has not been replaced."
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"date": "2026-10-22",
|
||||
"commit": "2f2c081980dc610ac810f8daf92da8966f310802",
|
||||
"remote": "https://dayu.media/git/dayu/paintfcp-fxplug.git",
|
||||
"branch": "codex/new-beauty-controls",
|
||||
"trackedFilesCompared": 205,
|
||||
"gitFsckFullStrict": true,
|
||||
"lfs": false,
|
||||
"submodules": false,
|
||||
"resources": "All tracked source, template and artwork bytes match; user QA media/signing credentials are external and not required to compile source."
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"url": "https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.3.1",
|
||||
"tag": "v1.3.1",
|
||||
"uploadAndMetadataReadbackVerified": true,
|
||||
"assets": [
|
||||
{
|
||||
"name": "Dayu-Portrait-1.3.1-source.zip",
|
||||
"bytes": 9682532
|
||||
},
|
||||
{
|
||||
"name": "Dayu-Portrait-1.3.1.pkg",
|
||||
"bytes": 5011286
|
||||
}
|
||||
],
|
||||
"assetByteReadback": "Not verified through the browser download gateway: API token request was redirected to site login. GitHub and article asset bytes were independently verified; installer is also stored in Git and restored from the release tag.",
|
||||
"anonymousAccess": "Site Git gateway continues to require login/membership."
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"status": "installed_user_qa_pending",
|
||||
"bundleIdentifier": "com.dayu.beatygril",
|
||||
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"options": {
|
||||
"waitForHosts": true,
|
||||
"userTests": true
|
||||
},
|
||||
"nativeEffectQA": {
|
||||
"status": "pending_user",
|
||||
"performedByScript": false
|
||||
},
|
||||
"source": {
|
||||
"commit": "7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f",
|
||||
"trackedWorktreeChanges": []
|
||||
},
|
||||
"updatedAt": "2026-10-22T08:52:41.382516+00:00",
|
||||
"version": "1.3.1",
|
||||
"build": "16",
|
||||
"stagingSignature": "Executable=/private/tmp/paintfcp-build-20261021/Build/Products/Release/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=d3bf91f8c8589b1acc19779f5578cc4f4055d267\nCandidateCDHashFull sha256=d3bf91f8c8589b1acc19779f5578cc4f4055d2678f10767fbb5d935ffea426a6\nHash choices=sha256\nCMSDigest=d3bf91f8c8589b1acc19779f5578cc4f4055d2678f10767fbb5d935ffea426a6\nCMSDigestType=2\nCDHash=d3bf91f8c8589b1acc19779f5578cc4f4055d267\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 16:27:24\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
|
||||
"notarization": {
|
||||
"message": "Processing complete",
|
||||
"status": "Accepted",
|
||||
"id": "e353b701-2fc2-4fcc-b03e-69af7735400f"
|
||||
},
|
||||
"signingVerified": true,
|
||||
"stapleValidated": true,
|
||||
"stagingPluginUnregistered": true,
|
||||
"runningHosts": [],
|
||||
"installedSignature": "Executable=/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=d3bf91f8c8589b1acc19779f5578cc4f4055d267\nCandidateCDHashFull sha256=d3bf91f8c8589b1acc19779f5578cc4f4055d2678f10767fbb5d935ffea426a6\nHash choices=sha256\nCMSDigest=d3bf91f8c8589b1acc19779f5578cc4f4055d2678f10767fbb5d935ffea426a6\nCMSDigestType=2\nCDHash=d3bf91f8c8589b1acc19779f5578cc4f4055d267\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 16:27:24\nNotarization Ticket=stapled\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
|
||||
"installedSignatureVerified": true,
|
||||
"installedStapleValidated": true,
|
||||
"gatekeeperAccepted": true,
|
||||
"pluginDiscovery": {
|
||||
"bundleIdentifier": "com.dayu.beatygril.fxplug",
|
||||
"formalPath": "/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit",
|
||||
"output": " com.dayu.beatygril.fxplug(1.1)\t330605B9-A653-4D3C-BB2D-D87F041A2071\t2026-10-22 08:52:41 +0000\t/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit\n (1 plug-in)\n"
|
||||
},
|
||||
"removedGeneratedPaths": [
|
||||
"/Users/dayu/Documents/PaintFCP/build/delivery/previous-beatygril.app",
|
||||
"/tmp/paintfcp-build-20261021",
|
||||
"/Users/dayu/Documents/PaintFCP/build/delivery/notarization.zip"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"tag": "v1.3.1",
|
||||
"commit": "b35b4a5d1ca252d2f83c798613560a768274de3c",
|
||||
"anonymousGitHubClone": true,
|
||||
"trackedFilesCompared": 232,
|
||||
"byteAndExecutableModesMatch": true,
|
||||
"gitFsckFullStrict": true,
|
||||
"productMatchesSignedSource": "7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f",
|
||||
"restoredPkgSignatureAndTicketVerified": true,
|
||||
"lfs": false,
|
||||
"submodules": false
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Beauty renderer: 57 checks, 0 failures (Metal).
|
||||
2026-10-22 16:24:20.836 face-tests[22582:8025448] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
Face processing: 116 checks passed
|
||||
2026-10-22 16:24:34.977 slim-tests[22589:8025534] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
PASS: 1033 slim alignment checks; maximum UV oracle error 1.09828022e-05
|
||||
@@ -0,0 +1,37 @@
|
||||
2026-10-22 16:21:55.726 host-tests[22385:8017721] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
Default IOSurface maximum byte difference: 0
|
||||
Alternate destination tag maximum byte difference: 0
|
||||
Anatomy default 0/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 0/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 1/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 1/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy big-eye 0/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 0/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 1/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 1/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy chin-positive 0/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 0/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 1/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 1/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-negative 0/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 0/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 1/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 1/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy short-positive 0/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 0/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 1/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 1/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-negative 0/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 0/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 1/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 1/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy jaw 0/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 0/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 1/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 1/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy v-face 0/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 0/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 1/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 1/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Legacy fallback upright comparison: max=2 mean=0.0010357
|
||||
Host adapter: 370 checks, 0 failures
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"url": "https://github.com/FAMEDaYu/FCP-BeatyGril/releases/tag/v1.3.1",
|
||||
"tag": "v1.3.1",
|
||||
"assets": [
|
||||
{
|
||||
"name": "Dayu-Portrait-1.3.1-source.zip",
|
||||
"bytes": 9682532,
|
||||
"sha256": "7c335f54717a73e710ef484fc9f7b90864211c128a0f217bf170aa092333f228",
|
||||
"anonymousDownloadVerified": true
|
||||
},
|
||||
{
|
||||
"name": "Dayu-Portrait-1.3.1.pkg",
|
||||
"bytes": 5011286,
|
||||
"sha256": "a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927",
|
||||
"anonymousDownloadVerified": true
|
||||
}
|
||||
],
|
||||
"installerSignatureAndTicketVerified": true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Inspector: 227 checks, 0 failures
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"date": "2026-10-22",
|
||||
"installedProduct": {
|
||||
"path": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"version": "1.3.1",
|
||||
"build": "16"
|
||||
},
|
||||
"signatureAllArchitecturesVerified": true,
|
||||
"duplicateInventory": {
|
||||
"scope": "Listed local roots only; not a full scan of all mounted volumes.",
|
||||
"roots": [
|
||||
"/Applications",
|
||||
"/Library/Plug-Ins/FxPlug",
|
||||
"/Users/dayu/Library/Plug-Ins/FxPlug",
|
||||
"/Users/dayu/Documents/PaintFCP",
|
||||
"/Users/dayu/Desktop",
|
||||
"/Users/dayu/Downloads",
|
||||
"/Users/dayu/Library/Developer/Xcode/DerivedData",
|
||||
"/tmp/paintfcp-build-20261021"
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"path": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"version": "1.3.1",
|
||||
"build": "16"
|
||||
}
|
||||
],
|
||||
"errors": []
|
||||
},
|
||||
"temporaryPathsRemoved": [
|
||||
"/tmp/paintfcp-build-20261021",
|
||||
"build/delivery/previous-beatygril.app",
|
||||
"build/delivery/notarization.zip",
|
||||
"build/release-input-1.3.1",
|
||||
"build/pkg-expanded-1.3.1"
|
||||
],
|
||||
"nativeEffectQA": "pending_user",
|
||||
"hostExit": "Motion exited by user; FCP remained running and was quit normally via UI after the user confirmed exit. No project edits."
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
2026-10-22 16:24:26.444 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
|
||||
2026-10-22 16:24:26.452 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,180) surface=320x240 origin=0
|
||||
2026-10-22 16:24:26.887 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.8,0.3) setter=(1152,-432) readback=(0.8,0.3) mode=centered-pixels verified=1
|
||||
2026-10-22 16:24:26.887 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.7,0.4) objectBounds=(-1920,-1080,3840,2160) canvas=(152,78) surface=320x240 origin=0
|
||||
2026-10-22 16:24:26.944 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.8,0.3) setter=(0.8,0.3) readback=(0.12345,0.87654) mode=normalized verified=0
|
||||
2026-10-22 16:24:26.944 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.75,0.25) setter=(0.75,0.25) readback=(0.75,0.25) mode=normalized verified=1
|
||||
2026-10-22 16:24:26.944 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.75,0.25) objectBounds=(-100,-50,200,100) canvas=(160,60) surface=320x240 origin=0
|
||||
2026-10-22 16:24:26.994 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.625,0.375) setter=(0.625,0.375) readback=(0.625,0.375) mode=normalized verified=1
|
||||
2026-10-22 16:24:26.994 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.625,0.375) objectBounds=(-100,-50,200,100) canvas=(240,60) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.043 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.043 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(144,180) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.094 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.094 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0,1) objectBounds=(-100,-50,200,100) canvas=(100,140) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.144 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(nan,nan) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.194 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.194 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(inf,nan) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.242 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.242 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,nan) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.304 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.304 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
OSC adapter: 98 checks, 0 failures
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"sourceApp": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"sourceCommit": "7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f",
|
||||
"motionSource": "/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸",
|
||||
"motionFiles": {
|
||||
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
|
||||
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
|
||||
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
|
||||
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
|
||||
},
|
||||
"lockedFiles": [
|
||||
"大鱼人像美化/large.png",
|
||||
"大鱼人像美化/small.png"
|
||||
],
|
||||
"package": "releases/1.3.1/大鱼人像美化-1.3.1.pkg",
|
||||
"bytes": 5011286,
|
||||
"sha256": "a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927",
|
||||
"notarization": {
|
||||
"createdDate": "2026-10-22T08:54:34.655Z",
|
||||
"message": "Successfully received submission info",
|
||||
"id": "78105340-306f-4629-8670-772760d4cb9a",
|
||||
"status": "Accepted",
|
||||
"name": "大鱼人像美化-1.3.1.pkg"
|
||||
},
|
||||
"checks": {
|
||||
"installerSignature": "Package \"大鱼人像美化-1.3.1.pkg\":\n Status: signed by a developer certificate issued by Apple for distribution\n Notarization: trusted by the Apple notary service\n Signed with a trusted timestamp on: 2026-10-22 08:54:32 +0000\n Certificate Chain:\n 1. Developer ID Installer: zhong luo (B3W25FX5H5)\n Expires: 2027-02-01 22:12:15 +0000\n SHA256 Fingerprint:\n 4D AC CD 04 A5 4C 7E F8 13 13 A2 ED D1 C2 C0 D0 29 EF FA BF 7B 53 \n 5A 43 C8 72 4D C4 0A A3 94 34\n ------------------------------------------------------------------------\n 2. Developer ID Certification Authority\n Expires: 2027-02-01 22:12:15 +0000\n SHA256 Fingerprint:\n 7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68 09 0D 2D E1 8D 03 \n F2 9C 88 CF B0 B1 BA 63 58 7F\n ------------------------------------------------------------------------\n 3. Apple Root CA\n Expires: 2035-02-09 21:40:36 +0000\n SHA256 Fingerprint:\n B0 B1 73 0E CB C7 FF 45 05 14 2C 49 F1 29 5E 6E DA 6B CA ED 7E 2C \n 68 C5 BE 91 B5 A1 10 01 F0 24\n\n",
|
||||
"ticket": "Processing: /Users/dayu/Documents/PaintFCP/releases/1.3.1/大鱼人像美化-1.3.1.pkg\nThe validate action worked!\n",
|
||||
"gatekeeper": "/Users/dayu/Documents/PaintFCP/releases/1.3.1/大鱼人像美化-1.3.1.pkg: accepted\nsource=Notarized Developer ID\norigin=Developer ID Installer: zhong luo (B3W25FX5H5)\n"
|
||||
},
|
||||
"realInstallerExecuted": false
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"logFormatVersion": 1,
|
||||
"jobId": "78105340-306f-4629-8670-772760d4cb9a",
|
||||
"status": "Accepted",
|
||||
"statusSummary": "Ready for distribution",
|
||||
"statusCode": 0,
|
||||
"archiveFilename": "大鱼人像美化-1.3.1.pkg",
|
||||
"uploadDate": "2026-10-22T08:54:36.516Z",
|
||||
"sha256": "e64eda56bedc889bdab4759ad5118beaa83e56aaa92d24c7f96fe993caaa10ff",
|
||||
"ticketContents": [
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "70b387db43f4fd65efc5ebd5f1795f72561dc523",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "d3bf91f8c8589b1acc19779f5578cc4f4055d267",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "00d0b69489a21f9c4464b38d284a0b8be7fd73c3",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "8411931c0e2f6fd7b21a168a268b641808cdb558",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/FxPlug.framework/Versions/Current",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "54cf6701245852c5c86f0c664fae4ce99f3e9346",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/FxPlug.framework/Versions/Current",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "0eb927b742d37499cd49b950b2c88dca9af31987",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/PluginManager.framework/Versions/Current",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "b018110c18ea61de312c47ca584e020d6e307bfd",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/PluginManager.framework/Versions/Current",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "26bcc6c218f15e8d6c96eec52104de495b8de2ff",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "70b387db43f4fd65efc5ebd5f1795f72561dc523",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/MacOS/beatygril",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "d3bf91f8c8589b1acc19779f5578cc4f4055d267",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/MacOS/beatygril XPC Service",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "00d0b69489a21f9c4464b38d284a0b8be7fd73c3",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/MacOS/beatygril XPC Service",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "8411931c0e2f6fd7b21a168a268b641808cdb558",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/PluginManager.framework/Versions/B/PluginManager",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "b018110c18ea61de312c47ca584e020d6e307bfd",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/PluginManager.framework/Versions/B/PluginManager",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "26bcc6c218f15e8d6c96eec52104de495b8de2ff",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/FxPlug.framework/Versions/A/FxPlug",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "54cf6701245852c5c86f0c664fae4ce99f3e9346",
|
||||
"arch": "x86_64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg/Payload.pkg Contents/Payload/Library/Plug-Ins/FxPlug/beatygril.app/Contents/PlugIns/beatygril XPC Service.pluginkit/Contents/Frameworks/FxPlug.framework/Versions/A/FxPlug",
|
||||
"digestAlgorithm": "SHA-256",
|
||||
"cdhash": "0eb927b742d37499cd49b950b2c88dca9af31987",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"path": "大鱼人像美化-1.3.1.pkg",
|
||||
"digestAlgorithm": "SHA-1",
|
||||
"cdhash": "99c6067f2b58a458edfc534895b160317ba13c65"
|
||||
}
|
||||
],
|
||||
"issues": null
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"package": "releases/1.3.1/大鱼人像美化-1.3.1.pkg",
|
||||
"bytes": 5011286,
|
||||
"sha256": "a6bb7262c9066e7abca8d1f21eaeaf1ba6a1d0d51b4859d39307aa7d7b0bc927",
|
||||
"version": "1.3.1",
|
||||
"build": "16",
|
||||
"app_files_compared": 34,
|
||||
"app_byte_and_symlink_equality": true,
|
||||
"template_files": {
|
||||
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
|
||||
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
|
||||
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
|
||||
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
|
||||
},
|
||||
"locked_relative_paths": [
|
||||
"大鱼人像美化/large.png",
|
||||
"大鱼人像美化/small.png"
|
||||
],
|
||||
"script_sha256": {
|
||||
"preinstall": "b0562f7705c84a2f34e31df67a4f0d429e60083bab122dad99f56a4b266c0174",
|
||||
"postinstall": "f7a1cedbac82d8c7946adc4767d253268bf5e9bbf6aa5b492264f6965092fccb"
|
||||
},
|
||||
"isolated_script_tests": [
|
||||
"fresh install",
|
||||
"replace old locked thumbnail",
|
||||
"partial copy failure restores old bytes and locks"
|
||||
],
|
||||
"isolation_changes": [
|
||||
"Console identity/home redirected to task fixture",
|
||||
"chown replaced with true",
|
||||
"FxPlug verification skipped; formal app signature and discovery verified separately"
|
||||
],
|
||||
"real_installer_execution": false,
|
||||
"app_and_template_installed": "APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG",
|
||||
"fonts": "No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed."
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
识别到 2 个安装内容:
|
||||
- beatygril.app
|
||||
类型:FxPlug 插件
|
||||
目录:/Library/Plug-Ins/FxPlug
|
||||
状态:已签名并公证,保留隔离属性,自动验证并修复注册;失败时打开 APP 所在目录
|
||||
- 大鱼磨皮瘦脸
|
||||
类型:FCP 效果
|
||||
目录:~/Movies/Motion Templates.localized/Effects.localized
|
||||
状态:非 APP,保留隔离属性
|
||||
|
||||
本次唯一标识:com.dayu.fcppackage.b20261022085430796.tqa79fqb
|
||||
安装包版本:1.3.1(继承 beatygril.app)
|
||||
[正在准备内容]
|
||||
正在整理 2 个内容项
|
||||
[正在生成安装包]
|
||||
正在构建组件包
|
||||
[正在签名]
|
||||
正在使用 Developer ID Installer 签名
|
||||
[正在等待 Apple 公证]
|
||||
已提交 Apple,公证通常需要几分钟
|
||||
[正在粘附公证票据]
|
||||
公证已通过,正在粘附票据
|
||||
[正在验证结果]
|
||||
正在检查签名和安装包结构
|
||||
签名、包结构与公证票据验证通过
|
||||
|
||||
完成:/Users/dayu/Documents/PaintFCP/releases/1.3.1/大鱼人像美化-1.3.1.pkg
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"status": "waiting_for_host_exit",
|
||||
"bundleIdentifier": "com.dayu.beatygril",
|
||||
"installationPath": "/Library/Plug-Ins/FxPlug/beatygril.app",
|
||||
"options": {
|
||||
"waitForHosts": true,
|
||||
"userTests": true
|
||||
},
|
||||
"nativeEffectQA": {
|
||||
"status": "pending_user",
|
||||
"performedByScript": false
|
||||
},
|
||||
"source": {
|
||||
"commit": "7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f",
|
||||
"trackedWorktreeChanges": []
|
||||
},
|
||||
"updatedAt": "2026-10-22T08:27:51.067234+00:00",
|
||||
"version": "1.3.1",
|
||||
"build": "16",
|
||||
"stagingSignature": "Executable=/private/tmp/paintfcp-build-20261021/Build/Products/Release/beatygril.app/Contents/MacOS/beatygril\nIdentifier=com.dayu.beatygril\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=478 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=d3bf91f8c8589b1acc19779f5578cc4f4055d267\nCandidateCDHashFull sha256=d3bf91f8c8589b1acc19779f5578cc4f4055d2678f10767fbb5d935ffea426a6\nHash choices=sha256\nCMSDigest=d3bf91f8c8589b1acc19779f5578cc4f4055d2678f10767fbb5d935ffea426a6\nCMSDigestType=2\nCDHash=d3bf91f8c8589b1acc19779f5578cc4f4055d267\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 16:27:24\nInfo.plist entries=22\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=180\nTotal signatures=1\nChosen signature=1\n",
|
||||
"notarization": {
|
||||
"message": "Processing complete",
|
||||
"status": "Accepted",
|
||||
"id": "e353b701-2fc2-4fcc-b03e-69af7735400f"
|
||||
},
|
||||
"signingVerified": true,
|
||||
"stapleValidated": true,
|
||||
"stagingPluginUnregistered": true,
|
||||
"runningHosts": [
|
||||
{
|
||||
"pid": 15637,
|
||||
"executable": "/Applications/Final Cut Pro.app/Contents/MacOS/Final Cut Pro"
|
||||
},
|
||||
{
|
||||
"pid": 21055,
|
||||
"executable": "/Applications/Motion.app/Contents/MacOS/Motion"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"articleId": 15593,
|
||||
"url": "https://dayu.media/15593/",
|
||||
"status": "publish",
|
||||
"version": "1.3.1",
|
||||
"author": 1,
|
||||
"categories": [
|
||||
3
|
||||
],
|
||||
"featuredMedia": 15595,
|
||||
"free": true,
|
||||
"accessAndCoverPreserved": true,
|
||||
"packageURL": "https://dayu.media/wp-content/uploads/2026/10/1792659519-b628139c96a5fa6.pkg",
|
||||
"packageBytesAndHashVerifiedByPublisher": true,
|
||||
"sourceURL": "https://dayu.media/wp-content/uploads/2026/10/1792659515-d487b0a421aacc6.zip",
|
||||
"frontends": [
|
||||
{
|
||||
"request": "normal URL",
|
||||
"title": "大鱼人像美化 1.3.1|FCP / Motion 免费开源自动美颜插件",
|
||||
"description": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,1.3.1 修复 V 脸下颌作用区域,并加入微细锐化、五官保护与非肤色区保护。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,附安装使用及故障排查说明。",
|
||||
"keywords": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源",
|
||||
"singleSeoTags": true,
|
||||
"versionAndInstructionsPresent": true,
|
||||
"anonymousPrice": "free; theme requires login to get package"
|
||||
},
|
||||
{
|
||||
"request": "fresh query",
|
||||
"title": "大鱼人像美化 1.3.1|FCP / Motion 免费开源自动美颜插件",
|
||||
"description": "大鱼人像美化是适用于 Final Cut Pro 和 Motion 的免费开源 FxPlug4 插件,1.3.1 修复 V 脸下颌作用区域,并加入微细锐化、五官保护与非肤色区保护。提供 Apple 签名公证 PKG 安装包和源码,安装自动注册,无需激活码,附安装使用及故障排查说明。",
|
||||
"keywords": "大鱼人像美化,FCP美颜插件,Motion磨皮,自动瘦脸,自动跟随,FxPlug4,免费开源",
|
||||
"singleSeoTags": true,
|
||||
"versionAndInstructionsPresent": true,
|
||||
"anonymousPrice": "free; theme requires login to get package"
|
||||
}
|
||||
],
|
||||
"fcpxAppSync": "disabled as before; not requested",
|
||||
"nativeVisualQA": "pending_user"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
2026-10-22 16:25:35.195 slim-tests[22704:8027100] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
PASS: 1561 slim alignment checks; maximum UV oracle error 1.09828022e-05
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"date": "2026-10-22",
|
||||
"commit": "7fa3298e022946e77dfd8cfba1bb5ff2c2a6361f",
|
||||
"remote": "https://dayu.media/git/dayu/paintfcp-fxplug.git",
|
||||
"branch": "codex/v-face-jaw-fix",
|
||||
"trackedFilesCompared": 219,
|
||||
"gitFsckFullStrict": true,
|
||||
"xcodeProjectReadable": true,
|
||||
"lfs": false,
|
||||
"submodules": false,
|
||||
"resources": "All tracked bytes and executable modes matched, including source/template/artwork. Private QA inputs and signing credentials are external."
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"version": "1.3.1",
|
||||
"build": "16",
|
||||
"checks": {
|
||||
"beauty": 57,
|
||||
"face": 116,
|
||||
"geometry": 1033,
|
||||
"hostASan": 370,
|
||||
"oscASan": 98,
|
||||
"inspectorASan": 227
|
||||
},
|
||||
"total": 1901,
|
||||
"extraRealPoseASan": {
|
||||
"checks": 1561,
|
||||
"inputs": "NASA astronaut plus 11 local user frames; frame images and full Vision points not uploaded",
|
||||
"overlapsBaseline": true
|
||||
},
|
||||
"maximumUVOracleError": 1.09828022e-05,
|
||||
"isolatedV": {
|
||||
"eyeChange": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"lowerFaceChange": 39246,
|
||||
"originsCompared": 4,
|
||||
"uprightMax255": 1,
|
||||
"uprightMean255": 0.000124
|
||||
},
|
||||
"nativeVisualQA": "pending user"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"sourceCommit": "b35b4a5d1ca252d2f83c798613560a768274de3c",
|
||||
"tag": "v1.3.1",
|
||||
"files": 230,
|
||||
"bytes": 9682532,
|
||||
"sha256": "7c335f54717a73e710ef484fc9f7b90864211c128a0f217bf170aa092333f228",
|
||||
"excludes": [
|
||||
"releases/**/*.pkg"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Beauty renderer: 57 checks, 0 failures (Metal).
|
||||
2026-10-22 18:30:09.786 face-tests[35177:8446323] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
Face processing: 116 checks passed
|
||||
2026-10-22 18:30:23.734 slim-tests[35267:8446747] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
PASS: 1033 slim alignment checks; maximum UV oracle error 1.09828022e-05
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"status": "installed_user_qa_pending",
|
||||
"bundleIdentifier": "com.dayu.fcpbeautygirl",
|
||||
"installationPath": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
|
||||
"options": {
|
||||
"waitForHosts": true,
|
||||
"userTests": true
|
||||
},
|
||||
"nativeEffectQA": {
|
||||
"status": "pending_user",
|
||||
"performedByScript": false
|
||||
},
|
||||
"source": {
|
||||
"commit": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
|
||||
"trackedWorktreeChanges": []
|
||||
},
|
||||
"updatedAt": "2026-10-22T10:38:29.383549+00:00",
|
||||
"version": "1.3.2",
|
||||
"build": "17",
|
||||
"stagingSignature": "Executable=/private/tmp/fcp-beautygirl-release/Build/Products/Release/FCP-BeautyGirl.app/Contents/MacOS/FCP-BeautyGirl\nIdentifier=com.dayu.fcpbeautygirl\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=482 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=28f0e84981124d854690d9be80e8ecb7a855ed02\nCandidateCDHashFull sha256=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nHash choices=sha256\nCMSDigest=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nCMSDigestType=2\nCDHash=28f0e84981124d854690d9be80e8ecb7a855ed02\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 18:38:05\nInfo.plist entries=23\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=184\nTotal signatures=1\nChosen signature=1\n",
|
||||
"notarization": {
|
||||
"id": "559eedf0-048f-4d0e-b013-6a187695f2da",
|
||||
"message": "Processing complete",
|
||||
"status": "Accepted"
|
||||
},
|
||||
"signingVerified": true,
|
||||
"stapleValidated": true,
|
||||
"stagingPluginUnregistered": true,
|
||||
"runningHosts": [],
|
||||
"installedSignature": "Executable=/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app/Contents/MacOS/FCP-BeautyGirl\nIdentifier=com.dayu.fcpbeautygirl\nFormat=app bundle with Mach-O universal (x86_64 arm64)\nCodeDirectory v=20500 size=482 flags=0x10000(runtime) hashes=4+7 location=embedded\nHash type=sha256 size=32\nCandidateCDHash sha256=28f0e84981124d854690d9be80e8ecb7a855ed02\nCandidateCDHashFull sha256=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nHash choices=sha256\nCMSDigest=28f0e84981124d854690d9be80e8ecb7a855ed02e3de84009119fc616e22aecd\nCMSDigestType=2\nCDHash=28f0e84981124d854690d9be80e8ecb7a855ed02\nSignature size=8968\nAuthority=Developer ID Application: zhong luo (B3W25FX5H5)\nAuthority=Developer ID Certification Authority\nAuthority=Apple Root CA\nTimestamp=Oct 22, 2026 at 18:38:05\nNotarization Ticket=stapled\nInfo.plist entries=23\nTeamIdentifier=B3W25FX5H5\nRuntime Version=27.0.0\nSealed Resources version=2 rules=13 files=5\nInternal requirements count=1 size=184\nTotal signatures=1\nChosen signature=1\n",
|
||||
"installedSignatureVerified": true,
|
||||
"installedStapleValidated": true,
|
||||
"gatekeeperAccepted": true,
|
||||
"identityMigration": {
|
||||
"legacyInstallationsRemoved": [
|
||||
"/Library/Plug-Ins/FxPlug/beatygril.app"
|
||||
],
|
||||
"filterUUIDPreserved": "FB14B0E6-59B2-4836-916F-CD0C559E9241"
|
||||
},
|
||||
"pluginDiscovery": {
|
||||
"bundleIdentifier": "com.dayu.fcpbeautygirl.fxplug",
|
||||
"formalPath": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app/Contents/PlugIns/FCP-BeautyGirl XPC Service.pluginkit",
|
||||
"output": " com.dayu.fcpbeautygirl.fxplug(1.1)\t6C990AD2-B58E-4C2F-91A4-927849E7AA10\t2026-10-22 10:38:29 +0000\t/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app/Contents/PlugIns/FCP-BeautyGirl XPC Service.pluginkit\n (1 plug-in)\n"
|
||||
},
|
||||
"removedGeneratedPaths": [
|
||||
"/Users/dayu/Documents/PaintFCP/build/delivery/legacy-beatygril.app",
|
||||
"/tmp/fcp-beautygirl-release",
|
||||
"/Users/dayu/Documents/PaintFCP/build/delivery/notarization.zip"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"repository": "https://github.com/dayumeida/FCP-BeautyGirl.git",
|
||||
"anonymousClone": true,
|
||||
"tag": "v1.3.2",
|
||||
"commit": "8a70d38b7cd17e0ea530c5226f2be8c2df4308b3",
|
||||
"trackedFilesByteBlobAndExecutableModeCompared": 271,
|
||||
"resourceEntries": 13,
|
||||
"strictFullFsck": true,
|
||||
"lfs": false,
|
||||
"submodules": false,
|
||||
"xcodeProjectRead": true,
|
||||
"signedProductSourceUnchangedFrom": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
|
||||
"packageSha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||
"recoveredPackageSignatureTicketAndGatekeeper": true,
|
||||
"temporaryCloneRemoved": true
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"remote": "https://dayu.media/git/dayu/codex-global-rules.git",
|
||||
"before": "dde7e2ee26eae18627eefda9b956a6aca52354ad",
|
||||
"commit": "4c3085861e26d34d82973483d0aae636b5fc7487",
|
||||
"remoteRefVerified": true,
|
||||
"independentCloneVerified": true,
|
||||
"filesByteAndModeCompared": 11,
|
||||
"strictFullFsck": true,
|
||||
"temporaryCloneRemoved": true
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
2026-10-22 18:30:11.816 host-tests[35227:8446515] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
Default IOSurface maximum byte difference: 0
|
||||
Alternate destination tag maximum byte difference: 0
|
||||
Anatomy default 0/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 0/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 1/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 1/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy big-eye 0/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 0/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 1/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 1/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy chin-positive 0/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 0/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 1/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 1/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-negative 0/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 0/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 1/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 1/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy short-positive 0/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 0/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 1/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 1/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-negative 0/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 0/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 1/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 1/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy jaw 0/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 0/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 1/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 1/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy v-face 0/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 0/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 1/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 1/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Legacy fallback upright comparison: max=2 mean=0.0010357
|
||||
Host adapter: 370 checks, 0 failures
|
||||
@@ -0,0 +1 @@
|
||||
Inspector: 227 checks, 0 failures
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"installedProduct": {
|
||||
"path": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
|
||||
"bundleId": "com.dayu.fcpbeautygirl",
|
||||
"version": "1.3.2"
|
||||
},
|
||||
"signatureAllArchitecturesVerified": true,
|
||||
"scopedInventory": {
|
||||
"roots": [
|
||||
"/Applications",
|
||||
"/Library/Plug-Ins/FxPlug",
|
||||
"/Users/dayu/Library/Plug-Ins/FxPlug",
|
||||
"/Users/dayu/Documents/PaintFCP",
|
||||
"/Users/dayu/Desktop",
|
||||
"/Users/dayu/Downloads",
|
||||
"/Users/dayu/Library/Developer/Xcode/DerivedData",
|
||||
"/tmp/fcp-beautygirl-release",
|
||||
"/tmp/paintfcp-build-20261021"
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"path": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
|
||||
"bundleId": "com.dayu.fcpbeautygirl",
|
||||
"version": "1.3.2"
|
||||
}
|
||||
],
|
||||
"errors": [],
|
||||
"scope": "Listed roots only; not all mounted volumes"
|
||||
},
|
||||
"legacyPluginOriginalPathAbsent": true,
|
||||
"filterUUIDPreserved": "FB14B0E6-59B2-4836-916F-CD0C559E9241",
|
||||
"templateBytesUnchanged": true,
|
||||
"nativeOldProjectReopen": "pending_user",
|
||||
"afterPackagingCleanup": {
|
||||
"buildPackageWorkAbsent": true,
|
||||
"spotlightIndexedProductPaths": [
|
||||
{
|
||||
"path": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
|
||||
"bundleId": "com.dayu.fcpbeautygirl"
|
||||
}
|
||||
],
|
||||
"newFormalPluginRegistered": true,
|
||||
"legacyFormalPluginNotRegistered": true,
|
||||
"appSignatureAndTicketRechecked": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
........
|
||||
----------------------------------------------------------------------
|
||||
Ran 8 tests in 2.805s
|
||||
|
||||
OK
|
||||
@@ -0,0 +1,5 @@
|
||||
........
|
||||
----------------------------------------------------------------------
|
||||
Ran 8 tests in 0.029s
|
||||
|
||||
OK
|
||||
@@ -0,0 +1,21 @@
|
||||
2026-10-22 18:30:08.818 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
|
||||
2026-10-22 18:30:08.826 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,180) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.311 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.8,0.3) setter=(1152,-432) readback=(0.8,0.3) mode=centered-pixels verified=1
|
||||
2026-10-22 18:30:09.311 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.7,0.4) objectBounds=(-1920,-1080,3840,2160) canvas=(152,78) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.359 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.8,0.3) setter=(0.8,0.3) readback=(0.12345,0.87654) mode=normalized verified=0
|
||||
2026-10-22 18:30:09.359 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.75,0.25) setter=(0.75,0.25) readback=(0.75,0.25) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.360 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.75,0.25) objectBounds=(-100,-50,200,100) canvas=(160,60) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.409 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.625,0.375) setter=(0.625,0.375) readback=(0.625,0.375) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.409 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.625,0.375) objectBounds=(-100,-50,200,100) canvas=(240,60) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.457 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.457 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(144,180) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.506 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.506 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0,1) objectBounds=(-100,-50,200,100) canvas=(100,140) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.574 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(nan,nan) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.628 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.629 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(inf,nan) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.689 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.690 osc-tests[35208:8446417] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,nan) surface=320x240 origin=0
|
||||
2026-10-22 18:30:09.742 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 18:30:09.742 osc-tests[35208:8446417] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
OSC adapter: 98 checks, 0 failures
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"version": "1.3.2",
|
||||
"build": "17",
|
||||
"package": "releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg",
|
||||
"bytes": 4889706,
|
||||
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||
"sourceApp": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
|
||||
"sourceCommit": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
|
||||
"motionSource": "/Users/dayu/Movies/Motion Templates.localized/Effects.localized/大鱼磨皮瘦脸",
|
||||
"motionFiles": [
|
||||
{
|
||||
"file": "大鱼人像美化/Drop Zone.tiff",
|
||||
"sha256": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"file": "大鱼人像美化/large.png",
|
||||
"sha256": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
|
||||
"locked": true
|
||||
},
|
||||
{
|
||||
"file": "大鱼人像美化/small.png",
|
||||
"sha256": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5",
|
||||
"locked": true
|
||||
},
|
||||
{
|
||||
"file": "大鱼人像美化/大鱼人像美化.moef",
|
||||
"sha256": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
|
||||
"locked": false
|
||||
}
|
||||
],
|
||||
"packager": "/Applications/PKG工坊.app/Contents/MacOS/PKG工坊",
|
||||
"productMigration": "PKG Forge base plus identity-checked backup/rollback block; final package freshly signed, notarized and stapled",
|
||||
"notarization": {
|
||||
"message": "Processing complete",
|
||||
"id": "4a831775-2317-4372-a4cc-102415657ea3",
|
||||
"status": "Accepted"
|
||||
},
|
||||
"realInstallerExecuted": false
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
/Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg: accepted
|
||||
source=Notarized Developer ID
|
||||
origin=Developer ID Installer: zhong luo (B3W25FX5H5)
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"message": "Processing complete",
|
||||
"id": "4a831775-2317-4372-a4cc-102415657ea3",
|
||||
"status": "Accepted"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
Package "FCP-BeautyGirl-1.3.2.pkg":
|
||||
Status: signed by a developer certificate issued by Apple for distribution
|
||||
Notarization: trusted by the Apple notary service
|
||||
Signed with a trusted timestamp on: 2026-10-22 10:40:28 +0000
|
||||
Certificate Chain:
|
||||
1. Developer ID Installer: zhong luo (B3W25FX5H5)
|
||||
Expires: 2027-02-01 22:12:15 +0000
|
||||
SHA256 Fingerprint:
|
||||
4D AC CD 04 A5 4C 7E F8 13 13 A2 ED D1 C2 C0 D0 29 EF FA BF 7B 53
|
||||
5A 43 C8 72 4D C4 0A A3 94 34
|
||||
------------------------------------------------------------------------
|
||||
2. Developer ID Certification Authority
|
||||
Expires: 2027-02-01 22:12:15 +0000
|
||||
SHA256 Fingerprint:
|
||||
7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68 09 0D 2D E1 8D 03
|
||||
F2 9C 88 CF B0 B1 BA 63 58 7F
|
||||
------------------------------------------------------------------------
|
||||
3. Apple Root CA
|
||||
Expires: 2035-02-09 21:40:36 +0000
|
||||
SHA256 Fingerprint:
|
||||
B0 B1 73 0E CB C7 FF 45 05 14 2C 49 F1 29 5E 6E DA 6B CA ED 7E 2C
|
||||
68 C5 BE 91 B5 A1 10 01 F0 24
|
||||
@@ -0,0 +1,5 @@
|
||||
productsign: using timestamp authority for signature
|
||||
productsign: signing product with identity "Developer ID Installer: zhong luo (B3W25FX5H5)" from keychain /Users/dayu/Library/Keychains/login.keychain-db
|
||||
productsign: adding certificate "Developer ID Certification Authority"
|
||||
productsign: adding certificate "Apple Root CA"
|
||||
productsign: Wrote signed product archive to /Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg
|
||||
@@ -0,0 +1,3 @@
|
||||
Processing: /Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg
|
||||
Processing: /Users/dayu/Documents/PaintFCP/releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg
|
||||
The staple and validate action worked!
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"package": "releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg",
|
||||
"bytes": 4889706,
|
||||
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||
"version": "1.3.2",
|
||||
"build": "17",
|
||||
"app_files_compared": 34,
|
||||
"app_byte_and_symlink_equality": true,
|
||||
"template_files": {
|
||||
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
|
||||
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
|
||||
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
|
||||
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
|
||||
},
|
||||
"locked_relative_paths": [
|
||||
"大鱼人像美化/large.png",
|
||||
"大鱼人像美化/small.png"
|
||||
],
|
||||
"script_sha256": {
|
||||
"preinstall": "b0562f7705c84a2f34e31df67a4f0d429e60083bab122dad99f56a4b266c0174",
|
||||
"postinstall": "d147ccab1c428659fd2b0ed60e77399d1eb5910d1049dcdcbdbfc88fd3824300"
|
||||
},
|
||||
"isolated_script_tests": [
|
||||
"fresh install",
|
||||
"replace old locked thumbnail",
|
||||
"partial copy failure restores old bytes and locks"
|
||||
],
|
||||
"isolation_changes": [
|
||||
"Console identity/home redirected to task fixture",
|
||||
"chown replaced with true",
|
||||
"FxPlug verification skipped; formal app signature and discovery verified separately"
|
||||
],
|
||||
"real_installer_execution": false,
|
||||
"app_and_template_installed": "APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG",
|
||||
"fonts": "No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed."
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"package": "releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg",
|
||||
"bytes": 4889706,
|
||||
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||
"version": "1.3.2",
|
||||
"build": "17",
|
||||
"app_files_compared": 34,
|
||||
"app_byte_and_symlink_equality": true,
|
||||
"template_files": {
|
||||
"大鱼人像美化.moef": "e9fa97dc14323d0daa7d3d61b06a78ba4000a70ab9f5e67ebffd750d49df1e15",
|
||||
"Drop Zone.tiff": "a7f8e3a2a431dbb3ce9e777040bb55e701cfe9ab9632e8cbb10359732bc8692e",
|
||||
"large.png": "a02ddb255b1ae255c749bb837a759e2dee1c3b8ffb9bdc1167957761bd5a1b97",
|
||||
"small.png": "1552b838dd88f60dee0795e20aaca652f9c558ecefc93500e895fbff77c2a4d5"
|
||||
},
|
||||
"locked_relative_paths": [
|
||||
"大鱼人像美化/large.png",
|
||||
"大鱼人像美化/small.png"
|
||||
],
|
||||
"script_sha256": {
|
||||
"preinstall": "b0562f7705c84a2f34e31df67a4f0d429e60083bab122dad99f56a4b266c0174",
|
||||
"postinstall": "d147ccab1c428659fd2b0ed60e77399d1eb5910d1049dcdcbdbfc88fd3824300"
|
||||
},
|
||||
"isolated_script_tests": [
|
||||
"fresh install",
|
||||
"replace old locked thumbnail",
|
||||
"partial copy failure restores old bytes and locks"
|
||||
],
|
||||
"isolation_changes": [
|
||||
"Console identity/home redirected to task fixture",
|
||||
"chown replaced with true",
|
||||
"FxPlug verification skipped; formal app signature and discovery verified separately"
|
||||
],
|
||||
"real_installer_execution": false,
|
||||
"app_and_template_installed": "APP installed through signed delivery workflow; formal template files matched the specified installed category, not changed by running this PKG",
|
||||
"fonts": "No editable third-party font dependency; promotional lettering baked into PNG. No optional font ZIP needed."
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
识别到 2 个安装内容:
|
||||
- FCP-BeautyGirl.app
|
||||
类型:FxPlug 插件
|
||||
目录:/Library/Plug-Ins/FxPlug
|
||||
状态:已签名并公证,保留隔离属性,自动验证并修复注册;失败时打开 APP 所在目录
|
||||
- 大鱼磨皮瘦脸
|
||||
类型:FCP 效果
|
||||
目录:~/Movies/Motion Templates.localized/Effects.localized
|
||||
状态:非 APP,保留隔离属性
|
||||
|
||||
识别完成,未生成安装包。
|
||||
@@ -0,0 +1,27 @@
|
||||
识别到 2 个安装内容:
|
||||
- FCP-BeautyGirl.app
|
||||
类型:FxPlug 插件
|
||||
目录:/Library/Plug-Ins/FxPlug
|
||||
状态:已签名并公证,保留隔离属性,自动验证并修复注册;失败时打开 APP 所在目录
|
||||
- 大鱼磨皮瘦脸
|
||||
类型:FCP 效果
|
||||
目录:~/Movies/Motion Templates.localized/Effects.localized
|
||||
状态:非 APP,保留隔离属性
|
||||
|
||||
完成:/Users/dayu/Documents/PaintFCP/build/package-1.3.2/base/FCP-BeautyGirl-1.3.2.pkg
|
||||
|
||||
本次唯一标识:com.dayu.fcppackage.b20261022104001942.tt2yn7vc
|
||||
安装包版本:1.3.2(继承 FCP-BeautyGirl.app)
|
||||
[正在准备内容]
|
||||
正在整理 2 个内容项
|
||||
[正在生成安装包]
|
||||
正在构建组件包
|
||||
[正在签名]
|
||||
正在使用 Developer ID Installer 签名
|
||||
[正在等待 Apple 公证]
|
||||
已提交 Apple,公证通常需要几分钟
|
||||
[正在粘附公证票据]
|
||||
公证已通过,正在粘附票据
|
||||
[正在验证结果]
|
||||
正在检查签名和安装包结构
|
||||
签名、包结构与公证票据验证通过
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"status": "verified",
|
||||
"version": "1.3.2",
|
||||
"releaseTag": "v1.3.2",
|
||||
"releaseCommit": "8a70d38b7cd17e0ea530c5226f2be8c2df4308b3",
|
||||
"githubRelease": "https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.2",
|
||||
"dayuRelease": "https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.3.2",
|
||||
"dayuReleaseAssetNameAndSizeReadback": true,
|
||||
"dayuReleaseDownloadByteReadback": false,
|
||||
"dayuReleaseGateway": "Site login/member gateway retained; not bypassed",
|
||||
"article": "https://dayu.media/15593/",
|
||||
"articleId": 15593,
|
||||
"authorCoverCategoriesTagsAndAccessRulesPreserved": true,
|
||||
"articleCodeBlocks": 1,
|
||||
"downloadChecks": [
|
||||
{
|
||||
"url": "https://github.com/dayumeida/FCP-BeautyGirl/releases/download/v1.3.2/FCP-BeautyGirl-1.3.2-source.zip",
|
||||
"name": "FCP-BeautyGirl-1.3.2-source.zip",
|
||||
"bytes": 9728489,
|
||||
"sha256": "c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834",
|
||||
"anonymousByteReadback": true
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/dayumeida/FCP-BeautyGirl/releases/download/v1.3.2/FCP-BeautyGirl-1.3.2.pkg",
|
||||
"name": "FCP-BeautyGirl-1.3.2.pkg",
|
||||
"bytes": 4889706,
|
||||
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||
"anonymousByteReadback": true
|
||||
},
|
||||
{
|
||||
"role": "package",
|
||||
"url": "https://dayu.media/wp-content/uploads/2026/10/1792666128-1202b0d4fd350d5.pkg",
|
||||
"bytes": 4889706,
|
||||
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||
"anonymousByteReadback": true
|
||||
},
|
||||
{
|
||||
"role": "source",
|
||||
"url": "https://dayu.media/wp-content/uploads/2026/10/1792666125-4e4f241a6fe317d.zip",
|
||||
"bytes": 9728489,
|
||||
"sha256": "c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834",
|
||||
"anonymousByteReadback": true
|
||||
}
|
||||
],
|
||||
"frontends": [
|
||||
{
|
||||
"url": "https://dayu.media/15593/",
|
||||
"versionAndInstallCommand": true,
|
||||
"singleCustomDescriptionAndKeywords": true,
|
||||
"seoTitle": "大鱼人像美化 1.3.2|FCP / Motion 免费开源自动美颜插件",
|
||||
"anonymousFreeAndLoginPromptVisible": true
|
||||
},
|
||||
{
|
||||
"url": "https://dayu.media/15593/?release_check=1792666175",
|
||||
"versionAndInstallCommand": true,
|
||||
"singleCustomDescriptionAndKeywords": true,
|
||||
"seoTitle": "大鱼人像美化 1.3.2|FCP / Motion 免费开源自动美颜插件",
|
||||
"anonymousFreeAndLoginPromptVisible": true
|
||||
}
|
||||
],
|
||||
"testOrderPlaced": false,
|
||||
"nativeOldProjectReopen": "pending_user"
|
||||
}
|
||||
已加载 100/176 个文件。由于本次变更涉及的文件过多,其余文件未显示。
显示更多
在新工单中引用
屏蔽一个用户