Add video animation support, update examples SimpleVideoAnimation SimpleVideoTransitionSwitch

This commit is contained in:
RenZhu Macro
2020-07-22 16:02:13 +08:00
parent 3929205637
commit bd7ee080bd
144 changed files with 10316 additions and 70 deletions
+11
View File
@@ -0,0 +1,11 @@
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'SimpleVideoAnimation' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for SimpleVideoAnimation
pod 'PryntTrimmerView'
end
@@ -0,0 +1,16 @@
PODS:
- PryntTrimmerView (4.0.0)
DEPENDENCIES:
- PryntTrimmerView
SPEC REPOS:
trunk:
- PryntTrimmerView
SPEC CHECKSUMS:
PryntTrimmerView: 67e67573ffd4c073f1308effa66aefd0cfa667a0
PODFILE CHECKSUM: 4473f02a1528566660f9c5ed79ea1d9d7df2096d
COCOAPODS: 1.8.4
+16
View File
@@ -0,0 +1,16 @@
PODS:
- PryntTrimmerView (4.0.0)
DEPENDENCIES:
- PryntTrimmerView
SPEC REPOS:
trunk:
- PryntTrimmerView
SPEC CHECKSUMS:
PryntTrimmerView: 67e67573ffd4c073f1308effa66aefd0cfa667a0
PODFILE CHECKSUM: 4473f02a1528566660f9c5ed79ea1d9d7df2096d
COCOAPODS: 1.8.4
@@ -0,0 +1,632 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
032F877127CB819B89EEF1CD59F35190 /* AssetVideoScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A4A1BACF84E64074643AF16313BED24 /* AssetVideoScrollView.swift */; };
084A42F97C9368ECB9C3C1BD50B83EAC /* VideoScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC439C201F68AF1EFFAC34B79FC8AABD /* VideoScrollView.swift */; };
1930B7608D16293CE006BBFFA59D2227 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */; };
3128FA0C6EF67C366889FD25B20C26B7 /* PryntTrimmerView-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = D432584627C3896D39BF7C2FE358F7B1 /* PryntTrimmerView-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
425982410476D4F38E665418296EA801 /* PryntTrimmerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F96BD1A00504790CD63CC5AAF94AAD4 /* PryntTrimmerView.swift */; };
4B1654EAC59903A3F57D722DD9D63788 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */; };
71138F4FB33001A655E478C0D395323E /* Pods-SimpleVideoAnimation-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BFB1D34029B68E2B40E8D668E3A8C /* Pods-SimpleVideoAnimation-dummy.m */; };
79AC849669741DC41B762F02D976F3B3 /* VideoCropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8625023B3E6DF67C7E31E4320747783 /* VideoCropView.swift */; };
8FE524682461A32D247F3280857E8576 /* ThumbSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3490BF84958387765BD324D9462ADE /* ThumbSelectorView.swift */; };
A1C503843AC95229CA9962770191D8CB /* AVAssetTimeSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = F60A650D855F62F330AA252B6C596BBB /* AVAssetTimeSelector.swift */; };
B47B377106D48A971F34C95FD6027D4E /* HandlerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3DD5E1779CA8E74EA322A3C642F0050 /* HandlerView.swift */; };
DD7151461459B7C1560131156E029E30 /* Pods-SimpleVideoAnimation-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA28EAFECF92C9585C9095F6F893A77 /* Pods-SimpleVideoAnimation-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
E6F4D1AA87BE2E09EFB06D3A7DB61858 /* PryntTrimmerView-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1275509E869B124B7D2117626286EE7E /* PryntTrimmerView-dummy.m */; };
EAB22516ACAA6EA3DA06A1BE26196675 /* CropMaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5574049F3812F6B26ABE1805FD9F4C18 /* CropMaskView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
86668A496B743E07BBAD7FF5F1AE251A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 492A3F539D36426FFCED62F4F58F688B;
remoteInfo = PryntTrimmerView;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0038897C32633F5F73BE1AEAC19DE309 /* Pods-SimpleVideoAnimation.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-SimpleVideoAnimation.modulemap"; sourceTree = "<group>"; };
010BFB1D34029B68E2B40E8D668E3A8C /* Pods-SimpleVideoAnimation-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-SimpleVideoAnimation-dummy.m"; sourceTree = "<group>"; };
017DD82CAC46C38F8A97838282A19238 /* Pods_SimpleVideoAnimation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_SimpleVideoAnimation.framework; path = "Pods-SimpleVideoAnimation.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
0C3506BDF9400573529648DF3D801256 /* Pods-SimpleVideoAnimation.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SimpleVideoAnimation.debug.xcconfig"; sourceTree = "<group>"; };
0F96BD1A00504790CD63CC5AAF94AAD4 /* PryntTrimmerView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PryntTrimmerView.swift; path = PryntTrimmerView/Classes/Trimmer/PryntTrimmerView.swift; sourceTree = "<group>"; };
1275509E869B124B7D2117626286EE7E /* PryntTrimmerView-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PryntTrimmerView-dummy.m"; sourceTree = "<group>"; };
2A4A1BACF84E64074643AF16313BED24 /* AssetVideoScrollView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AssetVideoScrollView.swift; path = PryntTrimmerView/Classes/Parents/AssetVideoScrollView.swift; sourceTree = "<group>"; };
3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
44D06F46436AACB33E8D2E85504271CE /* Pods-SimpleVideoAnimation-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-SimpleVideoAnimation-acknowledgements.markdown"; sourceTree = "<group>"; };
4F75A400052C49C7C0424C6199354326 /* Pods-SimpleVideoAnimation-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SimpleVideoAnimation-Info.plist"; sourceTree = "<group>"; };
5574049F3812F6B26ABE1805FD9F4C18 /* CropMaskView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CropMaskView.swift; path = PryntTrimmerView/Classes/Cropper/CropMaskView.swift; sourceTree = "<group>"; };
56395D8727605D379FEE467729B17928 /* PryntTrimmerView.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PryntTrimmerView.xcconfig; sourceTree = "<group>"; };
782DD95E3C1D9DD6570A9B32B5E8C027 /* PryntTrimmerView.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PryntTrimmerView.modulemap; sourceTree = "<group>"; };
9541F8AE153E6A07FF82F8BE4D1DF4CE /* Pods-SimpleVideoAnimation-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-SimpleVideoAnimation-frameworks.sh"; sourceTree = "<group>"; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
9E3490BF84958387765BD324D9462ADE /* ThumbSelectorView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ThumbSelectorView.swift; path = PryntTrimmerView/Classes/ThumbSelectorView.swift; sourceTree = "<group>"; };
A21A3E5DAE9D963771CB82663DB77372 /* PryntTrimmerView-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PryntTrimmerView-prefix.pch"; sourceTree = "<group>"; };
BCA28EAFECF92C9585C9095F6F893A77 /* Pods-SimpleVideoAnimation-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-SimpleVideoAnimation-umbrella.h"; sourceTree = "<group>"; };
C45D1BDF6010C3F370037BA1366D39A9 /* Pods-SimpleVideoAnimation.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SimpleVideoAnimation.release.xcconfig"; sourceTree = "<group>"; };
C63296516747E930E004498D034CBEC8 /* PryntTrimmerView-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PryntTrimmerView-Info.plist"; sourceTree = "<group>"; };
CB21E0A22EAC99D55621CBFDCE99B6FB /* Pods-SimpleVideoAnimation-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SimpleVideoAnimation-acknowledgements.plist"; sourceTree = "<group>"; };
CC439C201F68AF1EFFAC34B79FC8AABD /* VideoScrollView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VideoScrollView.swift; path = PryntTrimmerView/Classes/Cropper/VideoScrollView.swift; sourceTree = "<group>"; };
D09DB48D8145BFA029AAEA61818EC68B /* PryntTrimmerView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = PryntTrimmerView.framework; path = PryntTrimmerView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D432584627C3896D39BF7C2FE358F7B1 /* PryntTrimmerView-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PryntTrimmerView-umbrella.h"; sourceTree = "<group>"; };
E3DD5E1779CA8E74EA322A3C642F0050 /* HandlerView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HandlerView.swift; path = PryntTrimmerView/Classes/Trimmer/HandlerView.swift; sourceTree = "<group>"; };
F60A650D855F62F330AA252B6C596BBB /* AVAssetTimeSelector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AVAssetTimeSelector.swift; path = PryntTrimmerView/Classes/Parents/AVAssetTimeSelector.swift; sourceTree = "<group>"; };
F8625023B3E6DF67C7E31E4320747783 /* VideoCropView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VideoCropView.swift; path = PryntTrimmerView/Classes/Cropper/VideoCropView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
AF1BE2436FA9C0AFA75A7FA0ADD09D5B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1930B7608D16293CE006BBFFA59D2227 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C96EDBA35CA5052A71FDC4046C1C72B2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4B1654EAC59903A3F57D722DD9D63788 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
3299D943353D836EC70C7C067763BC0A /* PryntTrimmerView */ = {
isa = PBXGroup;
children = (
2A4A1BACF84E64074643AF16313BED24 /* AssetVideoScrollView.swift */,
F60A650D855F62F330AA252B6C596BBB /* AVAssetTimeSelector.swift */,
5574049F3812F6B26ABE1805FD9F4C18 /* CropMaskView.swift */,
E3DD5E1779CA8E74EA322A3C642F0050 /* HandlerView.swift */,
0F96BD1A00504790CD63CC5AAF94AAD4 /* PryntTrimmerView.swift */,
9E3490BF84958387765BD324D9462ADE /* ThumbSelectorView.swift */,
F8625023B3E6DF67C7E31E4320747783 /* VideoCropView.swift */,
CC439C201F68AF1EFFAC34B79FC8AABD /* VideoScrollView.swift */,
913459968288E6874F51EBA6C6BC4F42 /* Support Files */,
);
name = PryntTrimmerView;
path = PryntTrimmerView;
sourceTree = "<group>";
};
5F0F96C3DFA71EC2D7EDB6D805C616DF /* Products */ = {
isa = PBXGroup;
children = (
017DD82CAC46C38F8A97838282A19238 /* Pods_SimpleVideoAnimation.framework */,
D09DB48D8145BFA029AAEA61818EC68B /* PryntTrimmerView.framework */,
);
name = Products;
sourceTree = "<group>";
};
657908C41F07AE316229BADE15AE40AA /* Targets Support Files */ = {
isa = PBXGroup;
children = (
68CC947BC3E006F2F0C7914F735374B2 /* Pods-SimpleVideoAnimation */,
);
name = "Targets Support Files";
sourceTree = "<group>";
};
68CC947BC3E006F2F0C7914F735374B2 /* Pods-SimpleVideoAnimation */ = {
isa = PBXGroup;
children = (
0038897C32633F5F73BE1AEAC19DE309 /* Pods-SimpleVideoAnimation.modulemap */,
44D06F46436AACB33E8D2E85504271CE /* Pods-SimpleVideoAnimation-acknowledgements.markdown */,
CB21E0A22EAC99D55621CBFDCE99B6FB /* Pods-SimpleVideoAnimation-acknowledgements.plist */,
010BFB1D34029B68E2B40E8D668E3A8C /* Pods-SimpleVideoAnimation-dummy.m */,
9541F8AE153E6A07FF82F8BE4D1DF4CE /* Pods-SimpleVideoAnimation-frameworks.sh */,
4F75A400052C49C7C0424C6199354326 /* Pods-SimpleVideoAnimation-Info.plist */,
BCA28EAFECF92C9585C9095F6F893A77 /* Pods-SimpleVideoAnimation-umbrella.h */,
0C3506BDF9400573529648DF3D801256 /* Pods-SimpleVideoAnimation.debug.xcconfig */,
C45D1BDF6010C3F370037BA1366D39A9 /* Pods-SimpleVideoAnimation.release.xcconfig */,
);
name = "Pods-SimpleVideoAnimation";
path = "Target Support Files/Pods-SimpleVideoAnimation";
sourceTree = "<group>";
};
913459968288E6874F51EBA6C6BC4F42 /* Support Files */ = {
isa = PBXGroup;
children = (
782DD95E3C1D9DD6570A9B32B5E8C027 /* PryntTrimmerView.modulemap */,
56395D8727605D379FEE467729B17928 /* PryntTrimmerView.xcconfig */,
1275509E869B124B7D2117626286EE7E /* PryntTrimmerView-dummy.m */,
C63296516747E930E004498D034CBEC8 /* PryntTrimmerView-Info.plist */,
A21A3E5DAE9D963771CB82663DB77372 /* PryntTrimmerView-prefix.pch */,
D432584627C3896D39BF7C2FE358F7B1 /* PryntTrimmerView-umbrella.h */,
);
name = "Support Files";
path = "../Target Support Files/PryntTrimmerView";
sourceTree = "<group>";
};
9D4B4E6D53A1F0FBAE805F589D033B5A /* Pods */ = {
isa = PBXGroup;
children = (
3299D943353D836EC70C7C067763BC0A /* PryntTrimmerView */,
);
name = Pods;
sourceTree = "<group>";
};
C0834CEBB1379A84116EF29F93051C60 /* iOS */ = {
isa = PBXGroup;
children = (
3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */,
);
name = iOS;
sourceTree = "<group>";
};
CF1408CF629C7361332E53B88F7BD30C = {
isa = PBXGroup;
children = (
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */,
D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */,
9D4B4E6D53A1F0FBAE805F589D033B5A /* Pods */,
5F0F96C3DFA71EC2D7EDB6D805C616DF /* Products */,
657908C41F07AE316229BADE15AE40AA /* Targets Support Files */,
);
sourceTree = "<group>";
};
D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = {
isa = PBXGroup;
children = (
C0834CEBB1379A84116EF29F93051C60 /* iOS */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
86A339BA1B223A27BCFB984A3C47E28B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
3128FA0C6EF67C366889FD25B20C26B7 /* PryntTrimmerView-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DFB6EC49F1D54FFAAF97A8DC14107147 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
DD7151461459B7C1560131156E029E30 /* Pods-SimpleVideoAnimation-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
492A3F539D36426FFCED62F4F58F688B /* PryntTrimmerView */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5F256E2E76CAD307A29C8FD48E4430F4 /* Build configuration list for PBXNativeTarget "PryntTrimmerView" */;
buildPhases = (
86A339BA1B223A27BCFB984A3C47E28B /* Headers */,
29AFF14336C5C60CF4D7ECE4FCF71B99 /* Sources */,
AF1BE2436FA9C0AFA75A7FA0ADD09D5B /* Frameworks */,
90642AE968639B75967B5E9FBE4FB582 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = PryntTrimmerView;
productName = PryntTrimmerView;
productReference = D09DB48D8145BFA029AAEA61818EC68B /* PryntTrimmerView.framework */;
productType = "com.apple.product-type.framework";
};
A385EDF46896AAD667E7CB6AEBEEA453 /* Pods-SimpleVideoAnimation */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5510412BFB33A41088328A2944E8429E /* Build configuration list for PBXNativeTarget "Pods-SimpleVideoAnimation" */;
buildPhases = (
DFB6EC49F1D54FFAAF97A8DC14107147 /* Headers */,
47130975D92528825F7CD9F43190F66E /* Sources */,
C96EDBA35CA5052A71FDC4046C1C72B2 /* Frameworks */,
90C5D17977835042DD034C1A0D848044 /* Resources */,
);
buildRules = (
);
dependencies = (
4F0D8E61E9CE9580D4CB4657DFBBF101 /* PBXTargetDependency */,
);
name = "Pods-SimpleVideoAnimation";
productName = "Pods-SimpleVideoAnimation";
productReference = 017DD82CAC46C38F8A97838282A19238 /* Pods_SimpleVideoAnimation.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
BFDFE7DC352907FC980B868725387E98 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1100;
LastUpgradeCheck = 1100;
};
buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = CF1408CF629C7361332E53B88F7BD30C;
productRefGroup = 5F0F96C3DFA71EC2D7EDB6D805C616DF /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
A385EDF46896AAD667E7CB6AEBEEA453 /* Pods-SimpleVideoAnimation */,
492A3F539D36426FFCED62F4F58F688B /* PryntTrimmerView */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
90642AE968639B75967B5E9FBE4FB582 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
90C5D17977835042DD034C1A0D848044 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
29AFF14336C5C60CF4D7ECE4FCF71B99 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
032F877127CB819B89EEF1CD59F35190 /* AssetVideoScrollView.swift in Sources */,
A1C503843AC95229CA9962770191D8CB /* AVAssetTimeSelector.swift in Sources */,
EAB22516ACAA6EA3DA06A1BE26196675 /* CropMaskView.swift in Sources */,
B47B377106D48A971F34C95FD6027D4E /* HandlerView.swift in Sources */,
E6F4D1AA87BE2E09EFB06D3A7DB61858 /* PryntTrimmerView-dummy.m in Sources */,
425982410476D4F38E665418296EA801 /* PryntTrimmerView.swift in Sources */,
8FE524682461A32D247F3280857E8576 /* ThumbSelectorView.swift in Sources */,
79AC849669741DC41B762F02D976F3B3 /* VideoCropView.swift in Sources */,
084A42F97C9368ECB9C3C1BD50B83EAC /* VideoScrollView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
47130975D92528825F7CD9F43190F66E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
71138F4FB33001A655E478C0D395323E /* Pods-SimpleVideoAnimation-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
4F0D8E61E9CE9580D4CB4657DFBBF101 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = PryntTrimmerView;
target = 492A3F539D36426FFCED62F4F58F688B /* PryntTrimmerView */;
targetProxy = 86668A496B743E07BBAD7FF5F1AE251A /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
13967C5C8F4B10B3EE4D6C208A0A7BEB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"POD_CONFIGURATION_DEBUG=1",
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
SYMROOT = "${SRCROOT}/../build";
};
name = Debug;
};
22EFBC31083FBA35442432B8942CCB05 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C45D1BDF6010C3F370037BA1366D39A9 /* Pods-SimpleVideoAnimation.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
4812C7722161295CE314C28F40961E87 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 56395D8727605D379FEE467729B17928 /* PryntTrimmerView.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Target Support Files/PryntTrimmerView/PryntTrimmerView-prefix.pch";
INFOPLIST_FILE = "Target Support Files/PryntTrimmerView/PryntTrimmerView-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MODULEMAP_FILE = "Target Support Files/PryntTrimmerView/PryntTrimmerView.modulemap";
PRODUCT_MODULE_NAME = PryntTrimmerView;
PRODUCT_NAME = PryntTrimmerView;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
72B8A024B2332A85E8D4B741B60F6372 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0C3506BDF9400573529648DF3D801256 /* Pods-SimpleVideoAnimation.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
871B6E28ABA34DAE69824AB9D22D3B7D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"POD_CONFIGURATION_RELEASE=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
SYMROOT = "${SRCROOT}/../build";
};
name = Release;
};
F1B17B29AA8479A18A091848A6D12474 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 56395D8727605D379FEE467729B17928 /* PryntTrimmerView.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Target Support Files/PryntTrimmerView/PryntTrimmerView-prefix.pch";
INFOPLIST_FILE = "Target Support Files/PryntTrimmerView/PryntTrimmerView-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MODULEMAP_FILE = "Target Support Files/PryntTrimmerView/PryntTrimmerView.modulemap";
PRODUCT_MODULE_NAME = PryntTrimmerView;
PRODUCT_NAME = PryntTrimmerView;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13967C5C8F4B10B3EE4D6C208A0A7BEB /* Debug */,
871B6E28ABA34DAE69824AB9D22D3B7D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5510412BFB33A41088328A2944E8429E /* Build configuration list for PBXNativeTarget "Pods-SimpleVideoAnimation" */ = {
isa = XCConfigurationList;
buildConfigurations = (
72B8A024B2332A85E8D4B741B60F6372 /* Debug */,
22EFBC31083FBA35442432B8942CCB05 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5F256E2E76CAD307A29C8FD48E4430F4 /* Build configuration list for PBXNativeTarget "PryntTrimmerView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F1B17B29AA8479A18A091848A6D12474 /* Debug */,
4812C7722161295CE314C28F40961E87 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */;
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Prynt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,114 @@
//
// CropMaskView.swift
// PryntTrimmerView
//
// Created by Henry on 10/04/2017.
// Copyright © 2017 CocoaPods. All rights reserved.
//
import UIKit
class CropMaskView: UIView {
let cropBoxView = UIView()
let frameView = UIView()
let maskLayer = CAShapeLayer()
let frameLayer = CAShapeLayer()
private let lineWidth: CGFloat = 4.0
private var cropFrame: CGRect = CGRect.zero
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
private func setupSubviews() {
maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
maskLayer.fillColor = UIColor.black.cgColor
maskLayer.opacity = 1.0
frameLayer.strokeColor = UIColor.white.cgColor
frameLayer.fillColor = UIColor.clear.cgColor
frameView.layer.addSublayer(frameLayer)
cropBoxView.layer.mask = maskLayer
cropBoxView.translatesAutoresizingMaskIntoConstraints = false
cropBoxView.backgroundColor = UIColor.white.withAlphaComponent(0.7)
addSubview(cropBoxView)
addSubview(frameView)
cropBoxView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
cropBoxView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
cropBoxView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
cropBoxView.topAnchor.constraint(equalTo: topAnchor).isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
let path = UIBezierPath(rect: bounds)
let framePath = UIBezierPath(rect: cropFrame)
path.append(framePath)
path.usesEvenOddFillRule = true
maskLayer.path = path.cgPath
framePath.lineWidth = lineWidth
frameLayer.path = framePath.cgPath
}
func setCropFrame(_ frame: CGRect, animated: Bool) {
cropFrame = frame
guard animated else {
setNeedsLayout()
return
}
let (path, framePath) = getPaths(with: cropFrame)
CATransaction.begin()
let animation = getPathAnimation(with: path)
maskLayer.path = maskLayer.presentation()?.path
frameLayer.path = frameLayer.presentation()?.path
maskLayer.removeAnimation(forKey: "maskPath")
maskLayer.add(animation, forKey: "maskPath")
animation.toValue = framePath
frameLayer.removeAnimation(forKey: "framePath")
frameLayer.add(animation, forKey: "framePath")
CATransaction.commit()
}
private func getPaths(with cropFrame: CGRect) -> (path: CGPath, framePath: CGPath) {
let path = UIBezierPath(rect: bounds)
let framePath = UIBezierPath(rect: cropFrame)
framePath.lineWidth = lineWidth
path.append(framePath)
path.usesEvenOddFillRule = true
return (path.cgPath, framePath.cgPath)
}
private func getPathAnimation(with path: CGPath) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "path")
animation.toValue = path
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
animation.fillMode = CAMediaTimingFillMode.both
animation.isRemovedOnCompletion = false
return animation
}
}
@@ -0,0 +1,123 @@
//
// VideoCropView.swift
// PryntTrimmerView
//
// Created by Henry on 07/04/2017.
// Copyright © 2017 CocoaPods. All rights reserved.
//
import UIKit
import AVFoundation
private let margin: CGFloat = 16
/// A view to preview a video inside an `AVPlayer`, with a scroll view to be able to select a specific area of the video.
/// Simply set the `asset` property to load you video inside the view, and use the `getImageCropFrame` method to retrieve the
/// selected frame of the video.
public class VideoCropView: UIView {
let videoScrollView = VideoScrollView()
let cropMaskView = CropMaskView()
/// The asset being cropped. Setting the property will load the asset in the `AVPlayer` contained in the scroll view.
public var asset: AVAsset? {
didSet {
if let asset = asset {
videoScrollView.setupVideo(with: asset)
}
}
}
var cropFrame = CGRect.zero
/// The current aspect ratio of the crop view.
public private(set) var aspectRatio = CGSize(width: 1, height: 1)
/// The player used in the scroll view. Use it if you want to seek a specific time of your video.
public var player: AVPlayer? {
return videoScrollView.player
}
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
private func setupSubviews() {
videoScrollView.translatesAutoresizingMaskIntoConstraints = false
addSubview(videoScrollView)
videoScrollView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
videoScrollView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
videoScrollView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
videoScrollView.topAnchor.constraint(equalTo: topAnchor).isActive = true
cropMaskView.isUserInteractionEnabled = false
cropMaskView.translatesAutoresizingMaskIntoConstraints = false
addSubview(cropMaskView)
cropMaskView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
cropMaskView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
cropMaskView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
cropMaskView.topAnchor.constraint(equalTo: topAnchor).isActive = true
setAspectRatio(aspectRatio, animated: false)
}
/// Set the aspect ratio for the cropping box.
///
/// [Issue #3]: https://github.com/HHK1/PryntTrimmerView/issues/3
/// - Parameters:
/// - aspectRatio: The desired aspect ratio.
/// - animated: true if you want to animate the change. TODO: the animation glitches sometimes. See [Issue #3]
public func setAspectRatio(_ aspectRatio: CGSize, animated: Bool) {
self.aspectRatio = aspectRatio
let ratio = aspectRatio.width / aspectRatio.height
let cropBoxWidth = ratio > 1 ? (bounds.width - 2 * margin) : (bounds.height - 2 * margin) * ratio
let cropBoxHeight = cropBoxWidth / ratio
let origin = CGPoint(x: (bounds.width - cropBoxWidth) / 2, y: (bounds.height - cropBoxHeight) / 2)
cropFrame = CGRect(origin: origin, size: CGSize(width: cropBoxWidth, height: cropBoxHeight))
let edgeInsets = UIEdgeInsets(top: origin.y, left: origin.x, bottom: origin.y, right: origin.x)
let duration: TimeInterval = animated ? 0.15 : 0.0
cropMaskView.setCropFrame(cropFrame, animated: animated)
UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .curveEaseInOut], animations: {
self.videoScrollView.scrollView.contentInset = edgeInsets
}, completion: nil)
videoScrollView.setZoomScaleAndCenter(animated: animated)
}
/// Get the currently selected frame of the asset. You can then use it to perform the actual cropping of the video or of an
/// isolated image
public func getImageCropFrame() -> CGRect {
let imageSize = videoScrollView.assetSize
let contentSize = videoScrollView.scrollView.contentSize
let cropBoxFrame = cropFrame
let contentOffset = videoScrollView.scrollView.contentOffset
let edgeInsets = videoScrollView.scrollView.contentInset
var frame = CGRect.zero
frame.origin.x = floor((contentOffset.x + edgeInsets.left) * (imageSize.width / contentSize.width))
frame.origin.x = max(0, frame.origin.x)
frame.origin.y = floor((contentOffset.y + edgeInsets.top) * (imageSize.height / contentSize.height))
frame.origin.y = max(0, frame.origin.y)
frame.size.width = ceil(cropBoxFrame.size.width * (imageSize.width / contentSize.width))
frame.size.width = min(imageSize.width, frame.size.width)
frame.size.height = ceil(cropBoxFrame.size.height * (imageSize.height / contentSize.height))
frame.size.height = min(imageSize.height, frame.size.height)
return frame
}
}
@@ -0,0 +1,103 @@
//
// VideoScrollView.swift
// PryntTrimmerView
//
// Created by Henry on 10/04/2017.
// Copyright © 2017 CocoaPods. All rights reserved.
//
import UIKit
import AVFoundation
class VideoScrollView: UIView {
let scrollView = UIScrollView()
var contentView = UIView()
var assetSize = CGSize.zero
var playerItem: AVPlayerItem?
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
private func setupSubviews() {
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
scrollView.delegate = self
addSubview(scrollView)
scrollView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: topAnchor).isActive = true
}
func setupVideo(with asset: AVAsset) {
guard let track = asset.tracks(withMediaType: AVMediaType.video).first else { return }
let trackSize = track.naturalSize.applying(track.preferredTransform)
assetSize = CGSize(width: abs(trackSize.width), height: abs(trackSize.height))
scrollView.zoomScale = 1.0 // Reset zoom scale before changing the frame of the content view.
playerItem = AVPlayerItem(asset: asset)
let playerFrame = CGRect(x: 0, y: 0, width: assetSize.width, height: assetSize.height)
addVideoLayer(with: playerFrame)
scrollView.contentSize = assetSize
setZoomScaleAndCenter(animated: false)
}
private func addVideoLayer(with playerFrame: CGRect) {
playerLayer?.removeFromSuperlayer()
player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = playerFrame
playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
contentView.frame = playerFrame
contentView.layer.addSublayer(playerLayer!)
}
func setZoomScaleAndCenter(animated: Bool) {
guard assetSize != CGSize.zero else { return }
let scrollWidth = scrollView.bounds.width - scrollView.contentInset.left - scrollView.contentInset.right
let scrollHeight = scrollView.bounds.height - scrollView.contentInset.top - scrollView.contentInset.bottom
let scale = max(scrollWidth / assetSize.width, scrollHeight / assetSize.height)
scrollView.minimumZoomScale = scale
scrollView.maximumZoomScale = 3.0
var offset = scrollView.contentOffset
offset.x = -scrollView.contentInset.left - (scrollWidth - assetSize.width * scale) / 2
offset.y = -scrollView.contentInset.top - (scrollHeight - assetSize.height * scale) / 2
scrollView.setZoomScale(scale, animated: animated)
scrollView.setContentOffset(offset, animated: animated)
}
}
extension VideoScrollView: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return contentView
}
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
let scaledAssetSize = CGSize(width: assetSize.width * scale, height: assetSize.height * scale)
scrollView.contentSize = scaledAssetSize
}
}
@@ -0,0 +1,85 @@
//
// AVAssetTimeSelector.swift
// Pods
//
// Created by Henry on 06/04/2017.
//
//
import UIKit
import AVFoundation
/// A generic class to display an asset into a scroll view with thumbnail images, and make the equivalence between a time in
// the asset and a position in the scroll view
public class AVAssetTimeSelector: UIView, UIScrollViewDelegate {
let assetPreview = AssetVideoScrollView()
/// The asset to be displayed in the underlying scroll view. Setting a new asset will automatically refresh the thumbnails.
public var asset: AVAsset? {
didSet {
assetDidChange(newAsset: asset)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
func setupSubviews() {
setupAssetPreview()
constrainAssetPreview()
}
// MARK: - Asset Preview
func setupAssetPreview() {
assetPreview.translatesAutoresizingMaskIntoConstraints = false
assetPreview.delegate = self
addSubview(assetPreview)
}
func constrainAssetPreview() {
assetPreview.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
assetPreview.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
assetPreview.topAnchor.constraint(equalTo: topAnchor).isActive = true
assetPreview.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
func assetDidChange(newAsset: AVAsset?) {
if let asset = newAsset {
assetPreview.regenerateThumbnails(for: asset)
}
}
// MARK: - Time & Position Equivalence
var durationSize: CGFloat {
return assetPreview.contentSize.width
}
func getTime(from position: CGFloat) -> CMTime? {
guard let asset = asset else {
return nil
}
let normalizedRatio = max(min(1, position / durationSize), 0)
let positionTimeValue = Double(normalizedRatio) * Double(asset.duration.value)
return CMTime(value: Int64(positionTimeValue), timescale: asset.duration.timescale)
}
func getPosition(from time: CMTime) -> CGFloat? {
guard let asset = asset else {
return nil
}
let timeRatio = CGFloat(time.value) * CGFloat(asset.duration.timescale) /
(CGFloat(time.timescale) * CGFloat(asset.duration.value))
return timeRatio * durationSize
}
}
@@ -0,0 +1,166 @@
//
// AssetVideoScrollView.swift
// PryntTrimmerView
//
// Created by HHK on 28/03/2017.
// Copyright © 2017 Prynt. All rights reserved.
//
import AVFoundation
import UIKit
class AssetVideoScrollView: UIScrollView {
private var widthConstraint: NSLayoutConstraint?
let contentView = UIView()
var maxDuration: Double = 15
private var generator: AVAssetImageGenerator?
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
private func setupSubviews() {
backgroundColor = .clear
showsVerticalScrollIndicator = false
showsHorizontalScrollIndicator = false
clipsToBounds = true
contentView.backgroundColor = .clear
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.tag = -1
addSubview(contentView)
contentView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
widthConstraint = contentView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.0)
widthConstraint?.isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
contentSize = contentView.bounds.size
}
internal func regenerateThumbnails(for asset: AVAsset) {
guard let thumbnailSize = getThumbnailFrameSize(from: asset), thumbnailSize.width != 0 else {
print("Could not calculate the thumbnail size.")
return
}
generator?.cancelAllCGImageGeneration()
removeFormerThumbnails()
let newContentSize = setContentSize(for: asset)
let visibleThumbnailsCount = Int(ceil(frame.width / thumbnailSize.width))
let thumbnailCount = Int(ceil(newContentSize.width / thumbnailSize.width))
addThumbnailViews(thumbnailCount, size: thumbnailSize)
let timesForThumbnail = getThumbnailTimes(for: asset, numberOfThumbnails: thumbnailCount)
generateImages(for: asset, at: timesForThumbnail, with: thumbnailSize, visibleThumnails: visibleThumbnailsCount)
}
private func getThumbnailFrameSize(from asset: AVAsset) -> CGSize? {
guard let track = asset.tracks(withMediaType: AVMediaType.video).first else { return nil}
let assetSize = track.naturalSize.applying(track.preferredTransform)
let height = frame.height
let ratio = assetSize.width / assetSize.height
let width = height * ratio
return CGSize(width: abs(width), height: abs(height))
}
private func removeFormerThumbnails() {
contentView.subviews.forEach({ $0.removeFromSuperview() })
}
private func setContentSize(for asset: AVAsset) -> CGSize {
let contentWidthFactor = CGFloat(max(1, asset.duration.seconds / maxDuration))
widthConstraint?.isActive = false
widthConstraint = contentView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: contentWidthFactor)
widthConstraint?.isActive = true
layoutIfNeeded()
return contentView.bounds.size
}
private func addThumbnailViews(_ count: Int, size: CGSize) {
for index in 0..<count {
let thumbnailView = UIImageView(frame: CGRect.zero)
thumbnailView.clipsToBounds = true
let viewEndX = CGFloat(index) * size.width + size.width
if viewEndX > contentView.frame.width {
thumbnailView.frame.size = CGSize(width: size.width + (contentView.frame.width - viewEndX), height: size.height)
thumbnailView.contentMode = .scaleAspectFill
} else {
thumbnailView.frame.size = size
thumbnailView.contentMode = .scaleAspectFit
}
thumbnailView.frame.origin = CGPoint(x: CGFloat(index) * size.width, y: 0)
thumbnailView.tag = index
contentView.addSubview(thumbnailView)
}
}
private func getThumbnailTimes(for asset: AVAsset, numberOfThumbnails: Int) -> [NSValue] {
let timeIncrement = (asset.duration.seconds * 1000) / Double(numberOfThumbnails)
var timesForThumbnails = [NSValue]()
for index in 0..<numberOfThumbnails {
let cmTime = CMTime(value: Int64(timeIncrement * Float64(index)), timescale: 1000)
let nsValue = NSValue(time: cmTime)
timesForThumbnails.append(nsValue)
}
return timesForThumbnails
}
private func generateImages(for asset: AVAsset, at times: [NSValue], with maximumSize: CGSize, visibleThumnails: Int) {
generator = AVAssetImageGenerator(asset: asset)
generator?.appliesPreferredTrackTransform = true
let scaledSize = CGSize(width: maximumSize.width * UIScreen.main.scale, height: maximumSize.height * UIScreen.main.scale)
generator?.maximumSize = scaledSize
var count = 0
let handler: AVAssetImageGeneratorCompletionHandler = { [weak self] (_, cgimage, _, result, error) in
if let cgimage = cgimage, error == nil && result == AVAssetImageGenerator.Result.succeeded {
DispatchQueue.main.async(execute: { [weak self] () -> Void in
if count == 0 {
self?.displayFirstImage(cgimage, visibleThumbnails: visibleThumnails)
}
self?.displayImage(cgimage, at: count)
count += 1
})
}
}
generator?.generateCGImagesAsynchronously(forTimes: times, completionHandler: handler)
}
private func displayFirstImage(_ cgImage: CGImage, visibleThumbnails: Int) {
for i in 0...visibleThumbnails {
displayImage(cgImage, at: i)
}
}
private func displayImage(_ cgImage: CGImage, at index: Int) {
if let imageView = contentView.viewWithTag(index) as? UIImageView {
let uiimage = UIImage(cgImage: cgImage, scale: 1.0, orientation: UIImage.Orientation.up)
imageView.image = uiimage
}
}
}
@@ -0,0 +1,178 @@
//
// ThumbSelectorView.swift
// Pods
//
// Created by Henry on 06/04/2017.
//
//
import UIKit
import AVFoundation
/// A delegate to be notified of when the thumb position has changed. Useful to link an instance of the ThumbSelectorView to a
/// video preview like an `AVPlayer`.
public protocol ThumbSelectorViewDelegate: class {
func didChangeThumbPosition(_ imageTime: CMTime)
}
/// A view to select a specific time of an `AVAsset`. It is composed of an asset preview within a scroll view, and a thumb view
/// to select a precise time of the video. Set the `asset` property to load the video, and use the `selectedTime` property to
// retrieve the exact frame of the asset that was selected.
public class ThumbSelectorView: AVAssetTimeSelector {
public var thumbBorderColor: UIColor = .white {
didSet {
thumbView.layer.borderColor = thumbBorderColor.cgColor
}
}
private let thumbView = UIImageView()
private let dimmingView = UIView()
private var leftThumbConstraint: NSLayoutConstraint?
private var currentThumbConstraint: CGFloat = 0
private var generator: AVAssetImageGenerator?
public weak var delegate: ThumbSelectorViewDelegate?
// MARK: - View & constraints configurations
override func setupSubviews() {
super.setupSubviews()
setupDimmingView()
setupThumbView()
}
private func setupDimmingView() {
dimmingView.translatesAutoresizingMaskIntoConstraints = false
dimmingView.isUserInteractionEnabled = false
dimmingView.backgroundColor = UIColor.white.withAlphaComponent(0.7)
addSubview(dimmingView)
dimmingView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
dimmingView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
dimmingView.topAnchor.constraint(equalTo: topAnchor).isActive = true
dimmingView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
private func setupThumbView() {
thumbView.translatesAutoresizingMaskIntoConstraints = false
thumbView.layer.borderWidth = 2.0
thumbView.layer.borderColor = thumbBorderColor.cgColor
thumbView.isUserInteractionEnabled = true
thumbView.contentMode = .scaleAspectFill
thumbView.clipsToBounds = true
addSubview(thumbView)
leftThumbConstraint = thumbView.leftAnchor.constraint(equalTo: leftAnchor)
leftThumbConstraint?.isActive = true
thumbView.widthAnchor.constraint(equalTo: thumbView.heightAnchor).isActive = true
thumbView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
thumbView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(ThumbSelectorView.handlePanGesture(_:)))
thumbView.addGestureRecognizer(panGestureRecognizer)
}
// MARK: - Gesture handling
@objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let superView = gestureRecognizer.view?.superview else { return }
switch gestureRecognizer.state {
case .began:
currentThumbConstraint = leftThumbConstraint!.constant
updateSelectedTime()
case .changed:
let translation = gestureRecognizer.translation(in: superView)
updateThumbConstraint(with: translation)
layoutIfNeeded()
updateSelectedTime()
case .cancelled, .ended, .failed:
updateSelectedTime()
default: break
}
}
private func updateThumbConstraint(with translation: CGPoint) {
let maxConstraint = frame.width - thumbView.frame.width
let newConstraint = min(max(0, currentThumbConstraint + translation.x), maxConstraint)
leftThumbConstraint?.constant = newConstraint
}
// MARK: - Thumbnail Generation
override func assetDidChange(newAsset: AVAsset?) {
if let asset = newAsset {
setupThumbnailGenerator(with: asset)
leftThumbConstraint?.constant = 0
updateSelectedTime()
}
super.assetDidChange(newAsset: newAsset)
}
private func setupThumbnailGenerator(with asset: AVAsset) {
generator = AVAssetImageGenerator(asset: asset)
generator?.appliesPreferredTrackTransform = true
generator?.requestedTimeToleranceAfter = CMTime.zero
generator?.requestedTimeToleranceBefore = CMTime.zero
generator?.maximumSize = getThumbnailFrameSize(from: asset) ?? CGSize.zero
}
private func getThumbnailFrameSize(from asset: AVAsset) -> CGSize? {
guard let track = asset.tracks(withMediaType: AVMediaType.video).first else { return nil}
let assetSize = track.naturalSize.applying(track.preferredTransform)
let maxDimension = max(assetSize.width, assetSize.height)
let minDimension = min(assetSize.width, assetSize.height)
let ratio = maxDimension / minDimension
let side = thumbView.frame.height * ratio * UIScreen.main.scale
return CGSize(width: side, height: side)
}
private func generateThumbnailImage(for time: CMTime) {
generator?.generateCGImagesAsynchronously(forTimes: [time as NSValue],
completionHandler: { (_, image, _, _, _) in
guard let image = image else {
return
}
DispatchQueue.main.async {
self.generator?.cancelAllCGImageGeneration()
let uiimage = UIImage(cgImage: image)
self.thumbView.image = uiimage
}
})
}
// MARK: - Time & Position Equivalence
override var durationSize: CGFloat {
return assetPreview.contentSize.width - thumbView.frame.width
}
/// The currently selected time of the asset.
public var selectedTime: CMTime? {
let thumbPosition = thumbView.center.x + assetPreview.contentOffset.x - (thumbView.frame.width / 2)
return getTime(from: thumbPosition)
}
private func updateSelectedTime() {
if let selectedTime = selectedTime {
delegate?.didChangeThumbPosition(selectedTime)
generateThumbnailImage(for: selectedTime)
}
}
// MARK: - UIScrollViewDelegate
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
updateSelectedTime()
}
}
@@ -0,0 +1,22 @@
//
// HandlerView.swift
// PryntTrimmerView
//
// Created by HHK on 27/03/2017.
// Copyright © 2017 Prynt. All rights reserved.
//
import Foundation
import UIKit
class HandlerView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitFrame = bounds.insetBy(dx: -20, dy: -20)
return hitFrame.contains(point) ? self : nil
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let hitFrame = bounds.insetBy(dx: -20, dy: -20)
return hitFrame.contains(point)
}
}
@@ -0,0 +1,345 @@
//
// PryntTrimmerView.swift
// PryntTrimmerView
//
// Created by HHK on 27/03/2017.
// Copyright © 2017 Prynt. All rights reserved.
//
import AVFoundation
import UIKit
public protocol TrimmerViewDelegate: class {
func didChangePositionBar(_ playerTime: CMTime)
func positionBarStoppedMoving(_ playerTime: CMTime)
}
/// A view to select a specific time range of a video. It consists of an asset preview with thumbnails inside a scroll view, two
/// handles on the side to select the beginning and the end of the range, and a position bar to synchronize the control with a
/// video preview, typically with an `AVPlayer`.
/// Load the video by setting the `asset` property. Access the `startTime` and `endTime` of the view to get the selected time
// range
@IBDesignable public class TrimmerView: AVAssetTimeSelector {
// MARK: - Properties
// MARK: Color Customization
/// The color of the main border of the view
@IBInspectable public var mainColor: UIColor = UIColor.orange {
didSet {
updateMainColor()
}
}
/// The color of the handles on the side of the view
@IBInspectable public var handleColor: UIColor = UIColor.gray {
didSet {
updateHandleColor()
}
}
/// The color of the position indicator
@IBInspectable public var positionBarColor: UIColor = UIColor.white {
didSet {
positionBar.backgroundColor = positionBarColor
}
}
// MARK: Interface
public weak var delegate: TrimmerViewDelegate?
// MARK: Subviews
private let trimView = UIView()
private let leftHandleView = HandlerView()
private let rightHandleView = HandlerView()
private let positionBar = UIView()
private let leftHandleKnob = UIView()
private let rightHandleKnob = UIView()
private let leftMaskView = UIView()
private let rightMaskView = UIView()
// MARK: Constraints
private var currentLeftConstraint: CGFloat = 0
private var currentRightConstraint: CGFloat = 0
private var leftConstraint: NSLayoutConstraint?
private var rightConstraint: NSLayoutConstraint?
private var positionConstraint: NSLayoutConstraint?
private let handleWidth: CGFloat = 15
/// The maximum duration allowed for the trimming. Change it before setting the asset, as the asset preview
public var maxDuration: Double = 15 {
didSet {
assetPreview.maxDuration = maxDuration
}
}
/// The minimum duration allowed for the trimming. The handles won't pan further if the minimum duration is attained.
public var minDuration: Double = 3
// MARK: - View & constraints configurations
override func setupSubviews() {
super.setupSubviews()
backgroundColor = UIColor.clear
layer.zPosition = 1
setupTrimmerView()
setupHandleView()
setupMaskView()
setupPositionBar()
setupGestures()
updateMainColor()
updateHandleColor()
}
override func constrainAssetPreview() {
assetPreview.leftAnchor.constraint(equalTo: leftAnchor, constant: handleWidth).isActive = true
assetPreview.rightAnchor.constraint(equalTo: rightAnchor, constant: -handleWidth).isActive = true
assetPreview.topAnchor.constraint(equalTo: topAnchor).isActive = true
assetPreview.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
private func setupTrimmerView() {
trimView.layer.borderWidth = 2.0
trimView.layer.cornerRadius = 2.0
trimView.translatesAutoresizingMaskIntoConstraints = false
trimView.isUserInteractionEnabled = false
addSubview(trimView)
trimView.topAnchor.constraint(equalTo: topAnchor).isActive = true
trimView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
leftConstraint = trimView.leftAnchor.constraint(equalTo: leftAnchor)
rightConstraint = trimView.rightAnchor.constraint(equalTo: rightAnchor)
leftConstraint?.isActive = true
rightConstraint?.isActive = true
}
private func setupHandleView() {
leftHandleView.isUserInteractionEnabled = true
leftHandleView.layer.cornerRadius = 2.0
leftHandleView.translatesAutoresizingMaskIntoConstraints = false
addSubview(leftHandleView)
leftHandleView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
leftHandleView.widthAnchor.constraint(equalToConstant: handleWidth).isActive = true
leftHandleView.leftAnchor.constraint(equalTo: trimView.leftAnchor).isActive = true
leftHandleView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
leftHandleKnob.translatesAutoresizingMaskIntoConstraints = false
leftHandleView.addSubview(leftHandleKnob)
leftHandleKnob.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5).isActive = true
leftHandleKnob.widthAnchor.constraint(equalToConstant: 2).isActive = true
leftHandleKnob.centerYAnchor.constraint(equalTo: leftHandleView.centerYAnchor).isActive = true
leftHandleKnob.centerXAnchor.constraint(equalTo: leftHandleView.centerXAnchor).isActive = true
rightHandleView.isUserInteractionEnabled = true
rightHandleView.layer.cornerRadius = 2.0
rightHandleView.translatesAutoresizingMaskIntoConstraints = false
addSubview(rightHandleView)
rightHandleView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
rightHandleView.widthAnchor.constraint(equalToConstant: handleWidth).isActive = true
rightHandleView.rightAnchor.constraint(equalTo: trimView.rightAnchor).isActive = true
rightHandleView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
rightHandleKnob.translatesAutoresizingMaskIntoConstraints = false
rightHandleView.addSubview(rightHandleKnob)
rightHandleKnob.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5).isActive = true
rightHandleKnob.widthAnchor.constraint(equalToConstant: 2).isActive = true
rightHandleKnob.centerYAnchor.constraint(equalTo: rightHandleView.centerYAnchor).isActive = true
rightHandleKnob.centerXAnchor.constraint(equalTo: rightHandleView.centerXAnchor).isActive = true
}
private func setupMaskView() {
leftMaskView.isUserInteractionEnabled = false
leftMaskView.backgroundColor = .white
leftMaskView.alpha = 0.7
leftMaskView.translatesAutoresizingMaskIntoConstraints = false
insertSubview(leftMaskView, belowSubview: leftHandleView)
leftMaskView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
leftMaskView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
leftMaskView.topAnchor.constraint(equalTo: topAnchor).isActive = true
leftMaskView.rightAnchor.constraint(equalTo: leftHandleView.centerXAnchor).isActive = true
rightMaskView.isUserInteractionEnabled = false
rightMaskView.backgroundColor = .white
rightMaskView.alpha = 0.7
rightMaskView.translatesAutoresizingMaskIntoConstraints = false
insertSubview(rightMaskView, belowSubview: rightHandleView)
rightMaskView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
rightMaskView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
rightMaskView.topAnchor.constraint(equalTo: topAnchor).isActive = true
rightMaskView.leftAnchor.constraint(equalTo: rightHandleView.centerXAnchor).isActive = true
}
private func setupPositionBar() {
positionBar.frame = CGRect(x: 0, y: 0, width: 3, height: frame.height)
positionBar.backgroundColor = positionBarColor
positionBar.center = CGPoint(x: leftHandleView.frame.maxX, y: center.y)
positionBar.layer.cornerRadius = 1
positionBar.translatesAutoresizingMaskIntoConstraints = false
positionBar.isUserInteractionEnabled = false
addSubview(positionBar)
positionBar.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
positionBar.widthAnchor.constraint(equalToConstant: 3).isActive = true
positionBar.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
positionConstraint = positionBar.leftAnchor.constraint(equalTo: leftHandleView.rightAnchor, constant: 0)
positionConstraint?.isActive = true
}
private func setupGestures() {
let leftPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(TrimmerView.handlePanGesture))
leftHandleView.addGestureRecognizer(leftPanGestureRecognizer)
let rightPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(TrimmerView.handlePanGesture))
rightHandleView.addGestureRecognizer(rightPanGestureRecognizer)
}
private func updateMainColor() {
trimView.layer.borderColor = mainColor.cgColor
leftHandleView.backgroundColor = mainColor
rightHandleView.backgroundColor = mainColor
}
private func updateHandleColor() {
leftHandleKnob.backgroundColor = handleColor
rightHandleKnob.backgroundColor = handleColor
}
// MARK: - Trim Gestures
@objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let view = gestureRecognizer.view, let superView = gestureRecognizer.view?.superview else { return }
let isLeftGesture = view == leftHandleView
switch gestureRecognizer.state {
case .began:
if isLeftGesture {
currentLeftConstraint = leftConstraint!.constant
} else {
currentRightConstraint = rightConstraint!.constant
}
updateSelectedTime(stoppedMoving: false)
case .changed:
let translation = gestureRecognizer.translation(in: superView)
if isLeftGesture {
updateLeftConstraint(with: translation)
} else {
updateRightConstraint(with: translation)
}
layoutIfNeeded()
if let startTime = startTime, isLeftGesture {
seek(to: startTime)
} else if let endTime = endTime {
seek(to: endTime)
}
updateSelectedTime(stoppedMoving: false)
case .cancelled, .ended, .failed:
updateSelectedTime(stoppedMoving: true)
default: break
}
}
private func updateLeftConstraint(with translation: CGPoint) {
let maxConstraint = max(rightHandleView.frame.origin.x - handleWidth - minimumDistanceBetweenHandle, 0)
let newConstraint = min(max(0, currentLeftConstraint + translation.x), maxConstraint)
leftConstraint?.constant = newConstraint
}
private func updateRightConstraint(with translation: CGPoint) {
let maxConstraint = min(2 * handleWidth - frame.width + leftHandleView.frame.origin.x + minimumDistanceBetweenHandle, 0)
let newConstraint = max(min(0, currentRightConstraint + translation.x), maxConstraint)
rightConstraint?.constant = newConstraint
}
// MARK: - Asset loading
override func assetDidChange(newAsset: AVAsset?) {
super.assetDidChange(newAsset: newAsset)
resetHandleViewPosition()
}
private func resetHandleViewPosition() {
leftConstraint?.constant = 0
rightConstraint?.constant = 0
layoutIfNeeded()
}
// MARK: - Time Equivalence
/// Move the position bar to the given time.
public func seek(to time: CMTime) {
if let newPosition = getPosition(from: time) {
let offsetPosition = newPosition - assetPreview.contentOffset.x - leftHandleView.frame.origin.x
let maxPosition = rightHandleView.frame.origin.x - (leftHandleView.frame.origin.x + handleWidth)
- positionBar.frame.width
let normalizedPosition = min(max(0, offsetPosition), maxPosition)
positionConstraint?.constant = normalizedPosition
layoutIfNeeded()
}
}
/// The selected start time for the current asset.
public var startTime: CMTime? {
let startPosition = leftHandleView.frame.origin.x + assetPreview.contentOffset.x
return getTime(from: startPosition)
}
/// The selected end time for the current asset.
public var endTime: CMTime? {
let endPosition = rightHandleView.frame.origin.x + assetPreview.contentOffset.x - handleWidth
return getTime(from: endPosition)
}
private func updateSelectedTime(stoppedMoving: Bool) {
guard let playerTime = positionBarTime else {
return
}
if stoppedMoving {
delegate?.positionBarStoppedMoving(playerTime)
} else {
delegate?.didChangePositionBar(playerTime)
}
}
private var positionBarTime: CMTime? {
let barPosition = positionBar.frame.origin.x + assetPreview.contentOffset.x - handleWidth
return getTime(from: barPosition)
}
private var minimumDistanceBetweenHandle: CGFloat {
guard let asset = asset else { return 0 }
return CGFloat(minDuration) * assetPreview.contentView.frame.width / CGFloat(asset.duration.seconds)
}
// MARK: - Scroll View Delegate
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
updateSelectedTime(stoppedMoving: true)
}
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
updateSelectedTime(stoppedMoving: true)
}
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
updateSelectedTime(stoppedMoving: false)
}
}
@@ -0,0 +1,88 @@
# PryntTrimmerView
[![codebeat badge](https://codebeat.co/badges/ac008534-7f30-4b04-8434-0c6d69251e4b)](https://codebeat.co/projects/github-com-prynt-prynttrimmerview-master)
[![Platform](https://img.shields.io/cocoapods/p/PryntTrimmerView.svg?style=flat)](http://cocoapods.org/pods/PryntTrimmerView)
[![License](https://img.shields.io/cocoapods/l/PryntTrimmerView.svg?style=flat)](http://cocoapods.org/pods/PryntTrimmerView)
[![Version](https://img.shields.io/cocoapods/v/PryntTrimmerView.svg?style=flat)](http://cocoapods.org/pods/PryntTrimmerView)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
A set of tools written in swift to crop and trim videos.
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first.
### Trimming
![](https://media.giphy.com/media/GwZGkLiKxZcTm/giphy.gif)
### Cropping
![](https://media.giphy.com/media/10FsDfHS7616XC/giphy.gif)
## Requirements
PryntTrimmerView requires iOS9: It uses Layout Anchors to define the constraints.
## Installation
#### CocoaPods
PryntTrimmerView is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod "PryntTrimmerView"
```
Then, run `pod install` to download the source and add it to your workspace.
#### Carthage
PryntTrimmmerView is available through Carthage. To install
it, simply add the following line to your Cartfile:
```
github "HHK1/PryntTrimmerView"
```
Run `carthage update` to build the framework and drag the built PryntTrimmerView.framework into your Xcode project.
#### Swift Version
- Swift 3 compatibility: use version 1.0.1 or below.
- Swift 4 compatibility: use version 2.x.x.
- Swift 4.2 compatibility: use version 3.x.x
## Usage
:warning: _This library does not contain an API to crop or trim your video asset. You can find a possible implementation for this in the example pod, but the library only provides the UI._
### Trimming
Create a `TrimmerView` instance (in interface builder or through code), and add it to your view hierarchy.
```
trimmerView.asset = asset
trimmerView.delegate = self
```
Access the `startTime` and `endTime` property to know where to trim your asset. You can use the `TrimmerViewDelegate` to link the trimmer with an `AVPlayer` and provide the end user with a preview. See the `VideoTrimmerViewController` inside the project to see an example.
You can also customize the trimmer view by changing its colors:
```
trimmerView.handleColor = UIColor.white
trimmerView.mainColor = UIColor.orange
trimmerView.positionBarColor = UIColor.white
```
### Cropping
Create an instance of the `VideoCropView` and add it to your view hierarchy, then load your video into the crop view: `videoCropView.asset = asset`.
You can set the aspect ratio you want using the `setAspectRatio` method. Once you are satisfied with the portion of the asset you want to crop, call `getImageCropFrame` to retrieve the select frame. See the `VideoCropperViewController` in the example app for an actual example of how to crop the video for export.
## License
PryntTrimmerView is available under the MIT license. See the LICENSE file for more info.
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -0,0 +1,28 @@
# Acknowledgements
This application makes use of the following third party libraries:
## PryntTrimmerView
MIT License
Copyright (c) 2017 Prynt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Generated by CocoaPods - https://cocoapods.org
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>MIT License
Copyright (c) 2017 Prynt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>PryntTrimmerView</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>
@@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_SimpleVideoAnimation : NSObject
@end
@implementation PodsDummy_Pods_SimpleVideoAnimation
@end
@@ -0,0 +1,2 @@
${PODS_ROOT}/Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-frameworks.sh
${BUILT_PRODUCTS_DIR}/PryntTrimmerView/PryntTrimmerView.framework
@@ -0,0 +1 @@
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PryntTrimmerView.framework
@@ -0,0 +1,2 @@
${PODS_ROOT}/Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-frameworks.sh
${BUILT_PRODUCTS_DIR}/PryntTrimmerView/PryntTrimmerView.framework
@@ -0,0 +1 @@
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PryntTrimmerView.framework
@@ -0,0 +1,171 @@
#!/bin/sh
set -e
set -u
set -o pipefail
function on_error {
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
}
trap 'on_error $LINENO' ERR
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
# frameworks to, so exit 0 (signalling the script phase was successful).
exit 0
fi
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
# Used as a return value for each invocation of `strip_invalid_archs` function.
STRIP_BINARY_RETVAL=0
# This protects against multiple targets copying the same framework dependency at the same time. The solution
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
# Copies and strips a vendored framework
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
fi
# Use filter instead of exclude so missing patterns don't throw errors.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
elif [ -L "${binary}" ]; then
echo "Destination binary is symlinked..."
dirname="$(dirname "${binary}")"
binary="${dirname}/$(readlink "${binary}")"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
fi
}
# Copies and strips a vendored dSYM
install_dsym() {
local source="$1"
if [ -r "$source" ]; then
# Copy the dSYM into a the targets temp dir.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
local basename
basename="$(basename -s .framework.dSYM "$source")"
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
strip_invalid_archs "$binary"
fi
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
# Move the stripped file into its final destination.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
else
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
fi
fi
}
# Copies the bcsymbolmap files of a vendored framework
install_bcsymbolmap() {
local bcsymbolmap_path="$1"
local destination="${BUILT_PRODUCTS_DIR}"
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
}
# Signs a framework with the provided identity
code_sign_if_enabled() {
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
# Use the current code_sign_identity
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
code_sign_cmd="$code_sign_cmd &"
fi
echo "$code_sign_cmd"
eval "$code_sign_cmd"
fi
}
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
# Get architectures for current target binary
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
# Intersect them with the architectures we are building for
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
# If there are no archs supported by this binary then warn the user
if [[ -z "$intersected_archs" ]]; then
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
STRIP_BINARY_RETVAL=0
return
fi
stripped=""
for arch in $binary_archs; do
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary"
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
STRIP_BINARY_RETVAL=1
}
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/PryntTrimmerView/PryntTrimmerView.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/PryntTrimmerView/PryntTrimmerView.framework"
fi
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
wait
fi
@@ -0,0 +1,16 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double Pods_SimpleVideoAnimationVersionNumber;
FOUNDATION_EXPORT const unsigned char Pods_SimpleVideoAnimationVersionString[];
@@ -0,0 +1,12 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PryntTrimmerView"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PryntTrimmerView/PryntTrimmerView.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "PryntTrimmerView"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
@@ -0,0 +1,6 @@
framework module Pods_SimpleVideoAnimation {
umbrella header "Pods-SimpleVideoAnimation-umbrella.h"
export *
module * { export * }
}
@@ -0,0 +1,12 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PryntTrimmerView"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PryntTrimmerView/PryntTrimmerView.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "PryntTrimmerView"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>4.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_PryntTrimmerView : NSObject
@end
@implementation PodsDummy_PryntTrimmerView
@end
@@ -0,0 +1,12 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
@@ -0,0 +1,16 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double PryntTrimmerViewVersionNumber;
FOUNDATION_EXPORT const unsigned char PryntTrimmerViewVersionString[];
@@ -0,0 +1,6 @@
framework module PryntTrimmerView {
umbrella header "PryntTrimmerView-umbrella.h"
export *
module * { export * }
}
@@ -0,0 +1,10 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PryntTrimmerView
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/PryntTrimmerView
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
@@ -0,0 +1,477 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
0194809395268398D3F15306 /* Pods_SimpleVideoAnimation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16B763834C8C3CCC5972A2A2 /* Pods_SimpleVideoAnimation.framework */; };
6A54C20024C7DE9200EF216E /* cute.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 6A54C1FE24C7DE9200EF216E /* cute.mp4 */; };
6A874BA024C53EF700ADFD8A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A874B9F24C53EF700ADFD8A /* AppDelegate.swift */; };
6A874BA224C53EF700ADFD8A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A874BA124C53EF700ADFD8A /* SceneDelegate.swift */; };
6A874BA424C53EF700ADFD8A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A874BA324C53EF700ADFD8A /* ViewController.swift */; };
6A874BA724C53EF700ADFD8A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6A874BA524C53EF700ADFD8A /* Main.storyboard */; };
6A874BA924C53EF800ADFD8A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A874BA824C53EF800ADFD8A /* Assets.xcassets */; };
6A874BAC24C53EF800ADFD8A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6A874BAA24C53EF800ADFD8A /* LaunchScreen.storyboard */; };
6A874BB924C5462C00ADFD8A /* MetalVideoProcess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A874BB824C545CC00ADFD8A /* MetalVideoProcess.framework */; };
6A874BBA24C5462C00ADFD8A /* MetalVideoProcess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6A874BB824C545CC00ADFD8A /* MetalVideoProcess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
6A874BDA24C6FDE200ADFD8A /* 853.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 6A874BD824C6FDE200ADFD8A /* 853.mp4 */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
6A874BB724C545CC00ADFD8A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 6A874BB324C545CC00ADFD8A /* MetalVideoProcess.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 6ADB062424AD885F0010A817;
remoteInfo = MetalVideoProcess;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
6A874BBB24C5462C00ADFD8A /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
6A874BBA24C5462C00ADFD8A /* MetalVideoProcess.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
16B763834C8C3CCC5972A2A2 /* Pods_SimpleVideoAnimation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SimpleVideoAnimation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6A54C1FE24C7DE9200EF216E /* cute.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = cute.mp4; sourceTree = "<group>"; };
6A874B9C24C53EF700ADFD8A /* SimpleVideoAnimation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimpleVideoAnimation.app; sourceTree = BUILT_PRODUCTS_DIR; };
6A874B9F24C53EF700ADFD8A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
6A874BA124C53EF700ADFD8A /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
6A874BA324C53EF700ADFD8A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
6A874BA624C53EF700ADFD8A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
6A874BA824C53EF800ADFD8A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6A874BAB24C53EF800ADFD8A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
6A874BAD24C53EF800ADFD8A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6A874BB324C545CC00ADFD8A /* MetalVideoProcess.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MetalVideoProcess.xcodeproj; path = ../../MetalVideoProcess.xcodeproj; sourceTree = "<group>"; };
6A874BD824C6FDE200ADFD8A /* 853.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; name = 853.mp4; path = SimpleVIdeoAnimation/853.mp4; sourceTree = SOURCE_ROOT; };
A512CD4DD2F5AB414CF01FE6 /* Pods-SimpleVideoAnimation.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleVideoAnimation.release.xcconfig"; path = "Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation.release.xcconfig"; sourceTree = "<group>"; };
D107CF0887B69DDEA376CBEA /* Pods-SimpleVideoAnimation.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleVideoAnimation.debug.xcconfig"; path = "Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
6A874B9924C53EF700ADFD8A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
6A874BB924C5462C00ADFD8A /* MetalVideoProcess.framework in Frameworks */,
0194809395268398D3F15306 /* Pods_SimpleVideoAnimation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
09662178662A79DB0CFDDB51 /* Frameworks */ = {
isa = PBXGroup;
children = (
16B763834C8C3CCC5972A2A2 /* Pods_SimpleVideoAnimation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
6A874B9324C53EF700ADFD8A = {
isa = PBXGroup;
children = (
6A874BB324C545CC00ADFD8A /* MetalVideoProcess.xcodeproj */,
6A874B9E24C53EF700ADFD8A /* SimpleVideoAnimation */,
6A874B9D24C53EF700ADFD8A /* Products */,
99120D7228A6AD7ADD24AEFC /* Pods */,
09662178662A79DB0CFDDB51 /* Frameworks */,
);
sourceTree = "<group>";
};
6A874B9D24C53EF700ADFD8A /* Products */ = {
isa = PBXGroup;
children = (
6A874B9C24C53EF700ADFD8A /* SimpleVideoAnimation.app */,
);
name = Products;
sourceTree = "<group>";
};
6A874B9E24C53EF700ADFD8A /* SimpleVideoAnimation */ = {
isa = PBXGroup;
children = (
6A874BD824C6FDE200ADFD8A /* 853.mp4 */,
6A54C1FE24C7DE9200EF216E /* cute.mp4 */,
6A874B9F24C53EF700ADFD8A /* AppDelegate.swift */,
6A874BA124C53EF700ADFD8A /* SceneDelegate.swift */,
6A874BA324C53EF700ADFD8A /* ViewController.swift */,
6A874BA524C53EF700ADFD8A /* Main.storyboard */,
6A874BA824C53EF800ADFD8A /* Assets.xcassets */,
6A874BAA24C53EF800ADFD8A /* LaunchScreen.storyboard */,
6A874BAD24C53EF800ADFD8A /* Info.plist */,
);
path = SimpleVideoAnimation;
sourceTree = "<group>";
};
6A874BB424C545CC00ADFD8A /* Products */ = {
isa = PBXGroup;
children = (
6A874BB824C545CC00ADFD8A /* MetalVideoProcess.framework */,
);
name = Products;
sourceTree = "<group>";
};
99120D7228A6AD7ADD24AEFC /* Pods */ = {
isa = PBXGroup;
children = (
D107CF0887B69DDEA376CBEA /* Pods-SimpleVideoAnimation.debug.xcconfig */,
A512CD4DD2F5AB414CF01FE6 /* Pods-SimpleVideoAnimation.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
6A874B9B24C53EF700ADFD8A /* SimpleVideoAnimation */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6A874BB024C53EF800ADFD8A /* Build configuration list for PBXNativeTarget "SimpleVideoAnimation" */;
buildPhases = (
F6586DA6B62A1C6F6FBAC023 /* [CP] Check Pods Manifest.lock */,
6A874B9824C53EF700ADFD8A /* Sources */,
6A874B9924C53EF700ADFD8A /* Frameworks */,
6A874B9A24C53EF700ADFD8A /* Resources */,
D3C3047B9CCE5998654663D7 /* [CP] Embed Pods Frameworks */,
6A874BBB24C5462C00ADFD8A /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = SimpleVideoAnimation;
productName = SimpleVideoAnimation;
productReference = 6A874B9C24C53EF700ADFD8A /* SimpleVideoAnimation.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
6A874B9424C53EF700ADFD8A /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1160;
LastUpgradeCheck = 1160;
ORGANIZATIONNAME = "RenZhu Macro";
TargetAttributes = {
6A874B9B24C53EF700ADFD8A = {
CreatedOnToolsVersion = 11.6;
};
};
};
buildConfigurationList = 6A874B9724C53EF700ADFD8A /* Build configuration list for PBXProject "SimpleVideoAnimation" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 6A874B9324C53EF700ADFD8A;
productRefGroup = 6A874B9D24C53EF700ADFD8A /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 6A874BB424C545CC00ADFD8A /* Products */;
ProjectRef = 6A874BB324C545CC00ADFD8A /* MetalVideoProcess.xcodeproj */;
},
);
projectRoot = "";
targets = (
6A874B9B24C53EF700ADFD8A /* SimpleVideoAnimation */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
6A874BB824C545CC00ADFD8A /* MetalVideoProcess.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = MetalVideoProcess.framework;
remoteRef = 6A874BB724C545CC00ADFD8A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
6A874B9A24C53EF700ADFD8A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6A874BAC24C53EF800ADFD8A /* LaunchScreen.storyboard in Resources */,
6A874BA924C53EF800ADFD8A /* Assets.xcassets in Resources */,
6A874BDA24C6FDE200ADFD8A /* 853.mp4 in Resources */,
6A54C20024C7DE9200EF216E /* cute.mp4 in Resources */,
6A874BA724C53EF700ADFD8A /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
D3C3047B9CCE5998654663D7 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SimpleVideoAnimation/Pods-SimpleVideoAnimation-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
F6586DA6B62A1C6F6FBAC023 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-SimpleVideoAnimation-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
6A874B9824C53EF700ADFD8A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6A874BA424C53EF700ADFD8A /* ViewController.swift in Sources */,
6A874BA024C53EF700ADFD8A /* AppDelegate.swift in Sources */,
6A874BA224C53EF700ADFD8A /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
6A874BA524C53EF700ADFD8A /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
6A874BA624C53EF700ADFD8A /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
6A874BAA24C53EF800ADFD8A /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
6A874BAB24C53EF800ADFD8A /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
6A874BAE24C53EF800ADFD8A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
6A874BAF24C53EF800ADFD8A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
6A874BB124C53EF800ADFD8A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D107CF0887B69DDEA376CBEA /* Pods-SimpleVideoAnimation.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = RYRPKMVKDL;
INFOPLIST_FILE = SimpleVideoAnimation/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.wangrenzhu.SimpleVideoAnimation;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
6A874BB224C53EF800ADFD8A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A512CD4DD2F5AB414CF01FE6 /* Pods-SimpleVideoAnimation.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = RYRPKMVKDL;
INFOPLIST_FILE = SimpleVideoAnimation/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.wangrenzhu.SimpleVideoAnimation;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
6A874B9724C53EF700ADFD8A /* Build configuration list for PBXProject "SimpleVideoAnimation" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6A874BAE24C53EF800ADFD8A /* Debug */,
6A874BAF24C53EF800ADFD8A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6A874BB024C53EF800ADFD8A /* Build configuration list for PBXNativeTarget "SimpleVideoAnimation" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6A874BB124C53EF800ADFD8A /* Debug */,
6A874BB224C53EF800ADFD8A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 6A874B9424C53EF700ADFD8A /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:SimpleVideoAnimation.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1160"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6A874B9B24C53EF700ADFD8A"
BuildableName = "SimpleVideoAnimation.app"
BlueprintName = "SimpleVideoAnimation"
ReferencedContainer = "container:SimpleVideoAnimation.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUFrameCaptureMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6A874B9B24C53EF700ADFD8A"
BuildableName = "SimpleVideoAnimation.app"
BlueprintName = "SimpleVideoAnimation"
ReferencedContainer = "container:SimpleVideoAnimation.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6A874B9B24C53EF700ADFD8A"
BuildableName = "SimpleVideoAnimation.app"
BlueprintName = "SimpleVideoAnimation"
ReferencedContainer = "container:SimpleVideoAnimation.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,37 @@
//
// AppDelegate.swift
// SimpleVideoAnimation
//
// Created by RenZhu Macro on 2020/7/20.
// Copyright © 2020 RenZhu Macro. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="SimpleVideoAnimation" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FXj-LY-59h" customClass="MetalVideoProcessRenderView" customModule="MetalVideoProcess">
<rect key="frame" x="0.0" y="0.0" width="375" height="375"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="width" secondItem="FXj-LY-59h" secondAttribute="height" id="iBP-Gu-Wj9"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gLe-Zn-niL">
<rect key="frame" x="166.5" y="515" width="42" height="30"/>
<state key="normal" title="Pause"/>
<connections>
<action selector="pause:" destination="BYZ-38-t0r" eventType="touchUpInside" id="jXA-Ko-2E5"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9lP-KN-D4J">
<rect key="frame" x="172.5" y="475" width="30" height="30"/>
<state key="normal" title="Play"/>
<connections>
<action selector="play:" destination="BYZ-38-t0r" eventType="touchUpInside" id="BxN-gS-f9o"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JkB-hg-7A6" customClass="TrimmerView" customModule="PryntTrimmerView">
<rect key="frame" x="0.0" y="385" width="375" height="80"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="height" constant="80" id="9zr-ar-gfx"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="9lP-KN-D4J" firstAttribute="top" secondItem="JkB-hg-7A6" secondAttribute="bottom" constant="10" id="EVm-H0-xCG"/>
<constraint firstItem="FXj-LY-59h" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="Hbb-9e-X3i"/>
<constraint firstItem="gLe-Zn-niL" firstAttribute="top" secondItem="9lP-KN-D4J" secondAttribute="bottom" constant="10" id="RPS-Ea-blL"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="JkB-hg-7A6" secondAttribute="trailing" id="SQ5-rc-Ie3"/>
<constraint firstItem="9lP-KN-D4J" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="T7k-7C-oA5"/>
<constraint firstItem="gLe-Zn-niL" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="Z0h-3k-NiZ"/>
<constraint firstItem="JkB-hg-7A6" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="bea-xO-Fs7"/>
<constraint firstItem="FXj-LY-59h" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="cew-hA-jt7"/>
<constraint firstItem="JkB-hg-7A6" firstAttribute="top" secondItem="FXj-LY-59h" secondAttribute="bottom" constant="10" id="rCV-zQ-Eyi"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="FXj-LY-59h" secondAttribute="trailing" id="rUK-5t-TAP"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
<connections>
<outlet property="progressView" destination="JkB-hg-7A6" id="eky-zy-L0Z"/>
<outlet property="renderView" destination="FXj-LY-59h" id="8pT-q1-cV2"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="132" y="138"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -0,0 +1,53 @@
//
// SceneDelegate.swift
// SimpleVideoAnimation
//
// Created by RenZhu Macro on 2020/7/20.
// Copyright © 2020 RenZhu Macro. All rights reserved.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
@@ -0,0 +1,130 @@
//
// ViewController.swift
// SimpleVideoAnimation
//
// Created by RenZhu Macro on 2020/7/20.
// Copyright © 2020 RenZhu Macro. All rights reserved.
//
import UIKit
import AVFoundation
import MetalVideoProcess
import PryntTrimmerView
class ViewController: UIViewController {
@IBOutlet weak var renderView: MetalVideoProcessRenderView!
@IBOutlet weak var progressView: TrimmerView!
var player: MetalVideoProcessPlayer?
var editor: MetalVideoEditor?
override func viewDidLoad() {
super.viewDidLoad()
let asset1 = AVAsset(url: Bundle.main.url(forResource: "853", withExtension: "mp4")!)
let item1 = MetalVideoEditorItem(asset: asset1)
do {
let editor = try MetalVideoEditor(videoItems: [item1])
self.editor = editor
let playerItem = editor.buildPlayerItem()
let fadeIn = MetalVideoProcessFadeInMotion()
fadeIn.timingType = .quadraticEaseOut
let fadeOut = MetalVideoProcessFadeOutMotion()
fadeOut.timingType = .quarticEaseOut
let fadeInTimeRange = CMTimeRangeMake(start: CMTime(seconds: 2.0), duration: CMTime(seconds: 2.0))
fadeIn.saveUniformSettings(forTimelineRange: fadeInTimeRange, trackID: item1.trackID)
let fadeOutTimeRange = CMTimeRange(start: item1.timeRange.end - CMTime(seconds: 4.0), duration: CMTime(seconds: 1.5))
fadeOut.saveUniformSettings(forTimelineRange: fadeOutTimeRange, trackID: item1.trackID)
let player = try MetalVideoProcessPlayer(playerItem: playerItem)
player.playerDelegate = self
let background = MetalVideoProcessBackground(trackID: 0)
background.aspectRatioType = .Ratio9_16
background.canvasSizeType = .Type720p
background.setBackgroundType(type: .Blur)
let transform = MetalVideoProcessTransformFilter()
transform.saveUniformSettings(forTimelineRange: item1.timeRange, trackID: item1.trackID)
transform.roi = CGRect(x: 0.25, y: 0.25, width: 0.5, height: 0.5)
player.addTarget(background, atTargetIndex: 0, trackID: item1.trackID, targetTrackId: 0)
background --> fadeIn //source 0
player.addTarget(transform, atTargetIndex: nil, trackID: item1.trackID, targetTrackId: 0) //source 1
transform --> fadeIn //source 1
background --> fadeOut //source 0
fadeIn --> fadeOut --> renderView //source 1
self.player = player
} catch {
}
}
override func viewDidAppear(_ animated: Bool) {
guard let asset = self.editor?.playerItem?.asset else {
return
}
self.progressView.asset = asset
self.progressView.delegate = self
}
@IBAction func play(_ sender: Any) {
self.player?.play()
}
@IBAction func pause(_ sender: Any) {
self.player?.pause()
}
@IBAction func progressChanged(_ sender: Any) {
}
}
extension ViewController: TrimmerViewDelegate {
func didChangePositionBar(_ playerTime: CMTime) {
self.player?.seekTo(time: playerTime.seconds)
}
func positionBarStoppedMoving(_ playerTime: CMTime) {
}
}
extension ViewController: MetalVideoProcessPlayerDelegate {
func playbackFrameTimeChanged(frameTime time: CMTime, player: AVPlayer) {
if player.rate == 0.0 {
return
}
DispatchQueue.main.async { [weak self] in
guard let `self` = self else { return }
self.progressView.seek(to: time)
}
}
func playEnded(currentPlayer player: AVPlayer) {
}
func finishExport(error: NSError?) {
}
func exportProgressChanged(_ progress: Float) {
}
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:SimpleVideoAnimation.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>