Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56ed236c31 | |||
| d7875a1b5b | |||
| d636abbe7e | |||
| 7124b79549 | |||
| eddae7758c | |||
| 08ad254271 | |||
| 720c1af699 | |||
| e134ab9792 | |||
| e9c7cfaaca | |||
| 2f40c3d9f0 | |||
| de62d34b9e | |||
| fe093e65d6 | |||
| b05e744dc6 | |||
| c51fc0db85 | |||
| 61415aa9aa | |||
| b89bd27d59 | |||
| 6037aa9619 | |||
| 3379dbaba4 | |||
| 8e7eafb797 | |||
| 62f90d09ef | |||
| f0c0c393a0 | |||
| c798581992 | |||
| aa625e8a56 | |||
| 0b09ad4483 | |||
| 15124d26cc | |||
| 525c802ca4 | |||
| 1b786d4c3d | |||
| 5d20554db4 | |||
| f79760470e | |||
| 469d1fcc70 | |||
| a7bf5a0894 | |||
| d27f999341 | |||
| de69cfaaf6 | |||
| e6eddcce30 | |||
| eae0dcacd5 | |||
| 81f5045f7c | |||
| 3c3326129e | |||
| 8299d7c0f8 | |||
| d624343a30 | |||
| edcadab554 | |||
| 42613ed528 | |||
| 6a9e2393c6 | |||
| 5786fffaf7 | |||
| 87101908c8 | |||
| 31ef66b903 | |||
| 67fc993dc4 | |||
| 1e9968c1a3 | |||
| 2cac116d16 | |||
| cc7019f687 | |||
| 359e3dcbda | |||
| 7ff20805b0 | |||
| d94ae2125a | |||
| 49ea34ac8b | |||
| dba2398267 | |||
| 71094b27e2 | |||
| 6505e7346d | |||
| 9894d2a9f8 | |||
| ed3468f487 | |||
| f7f98881c3 | |||
| 232dab4f57 | |||
| 6bb55a923b | |||
| 054d23ca50 | |||
| 7fb760dab0 | |||
| 6693e32ecf | |||
| b79af89eb6 | |||
| b0b7f41904 | |||
| 105e8360e4 | |||
| 71f2f27d11 | |||
| 6d1624c730 | |||
| 6aa443b3d9 | |||
| 30087d53d3 | |||
| c7ad4295a1 | |||
| f9cabf3ea4 | |||
| 85f1f00a91 | |||
| a14ef8d6cc | |||
| 0c4bae5fb6 | |||
| f5c87b097c | |||
| 4af1d53984 | |||
| a28f673153 | |||
| d9f34cfeb0 | |||
| 0b4659adee | |||
| 407d934fa5 | |||
| 2a87e4a423 | |||
| 21377e4d90 | |||
| 7daf13658a | |||
| eea3ab7818 | |||
| 6e552a93e3 | |||
| b8c8e2d71f | |||
| 850198ed7d | |||
| aebc1e303d | |||
| 33ddee03ed | |||
| 9b6edaacd7 | |||
| 2c93b1585d | |||
| a3cca1ba5b | |||
| afee84b1bb | |||
| 1e6217fcac | |||
| 01dd05ed25 | |||
| bb3732f32a | |||
| 57381fd1f6 | |||
| 5a1fbe1b9a | |||
| a4c8c8b0cc | |||
| d618b3a570 | |||
| c3fef201d8 | |||
| a75a1e0895 | |||
| 1544362fda | |||
| 382192ce36 | |||
| 0d493645df | |||
| 8b1148ca81 | |||
| bb5c31bf7b | |||
| daa7bcd7b4 | |||
| c976195885 | |||
| 3645199f11 | |||
| c13a4c8e98 |
@@ -1 +0,0 @@
|
||||
echo "4.0" > .swift-version
|
||||
Binary file not shown.
@@ -1,220 +0,0 @@
|
||||
// Generated by Apple Swift version 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
|
||||
#if !defined(__has_include)
|
||||
# define __has_include(x) 0
|
||||
#endif
|
||||
#if !defined(__has_attribute)
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
#if !defined(__has_feature)
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
#if !defined(__has_warning)
|
||||
# define __has_warning(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# define SWIFT_STRINGIFY(str) #str
|
||||
# define SWIFT_MODULE_NAMESPACE_PUSH(module_name) _Pragma(SWIFT_STRINGIFY(clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in=module_name, generated_declaration))), apply_to=any(function, enum, objc_interface, objc_category, objc_protocol))))
|
||||
# define SWIFT_MODULE_NAMESPACE_POP _Pragma("clang attribute pop")
|
||||
#else
|
||||
# define SWIFT_MODULE_NAMESPACE_PUSH(module_name)
|
||||
# define SWIFT_MODULE_NAMESPACE_POP
|
||||
#endif
|
||||
|
||||
#if __has_include(<swift/objc-prologue.h>)
|
||||
# include <swift/objc-prologue.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wauto-import"
|
||||
#include <objc/NSObject.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(SWIFT_TYPEDEFS)
|
||||
# define SWIFT_TYPEDEFS 1
|
||||
# if __has_include(<uchar.h>)
|
||||
# include <uchar.h>
|
||||
# elif !defined(__cplusplus) || __cplusplus < 201103L
|
||||
typedef uint_least16_t char16_t;
|
||||
typedef uint_least32_t char32_t;
|
||||
# endif
|
||||
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PASTE)
|
||||
# define SWIFT_PASTE_HELPER(x, y) x##y
|
||||
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
|
||||
#endif
|
||||
#if !defined(SWIFT_METATYPE)
|
||||
# define SWIFT_METATYPE(X) Class
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_PROPERTY)
|
||||
# if __has_feature(objc_class_property)
|
||||
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
|
||||
# else
|
||||
# define SWIFT_CLASS_PROPERTY(...)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __has_attribute(objc_runtime_name)
|
||||
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
|
||||
#else
|
||||
# define SWIFT_RUNTIME_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(swift_name)
|
||||
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
|
||||
#else
|
||||
# define SWIFT_COMPILE_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(objc_method_family)
|
||||
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
|
||||
#else
|
||||
# define SWIFT_METHOD_FAMILY(X)
|
||||
#endif
|
||||
#if __has_attribute(noescape)
|
||||
# define SWIFT_NOESCAPE __attribute__((noescape))
|
||||
#else
|
||||
# define SWIFT_NOESCAPE
|
||||
#endif
|
||||
#if __has_attribute(warn_unused_result)
|
||||
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define SWIFT_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
#if __has_attribute(noreturn)
|
||||
# define SWIFT_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
# define SWIFT_NORETURN
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_EXTRA)
|
||||
# define SWIFT_CLASS_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_PROTOCOL_EXTRA)
|
||||
# define SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_EXTRA)
|
||||
# define SWIFT_ENUM_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS)
|
||||
# if __has_attribute(objc_subclassing_restricted)
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# else
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PROTOCOL)
|
||||
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_EXTENSION)
|
||||
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
|
||||
#endif
|
||||
|
||||
#if !defined(OBJC_DESIGNATED_INITIALIZER)
|
||||
# if __has_attribute(objc_designated_initializer)
|
||||
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
# else
|
||||
# define OBJC_DESIGNATED_INITIALIZER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_ATTR)
|
||||
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
|
||||
# define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open)))
|
||||
# else
|
||||
# define SWIFT_ENUM_ATTR
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM)
|
||||
# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# if __has_feature(generalized_swift_name)
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# else
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE)
|
||||
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE_MSG)
|
||||
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
|
||||
#endif
|
||||
#if !defined(SWIFT_AVAILABILITY)
|
||||
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED)
|
||||
# define SWIFT_DEPRECATED __attribute__((deprecated))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED_MSG)
|
||||
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
|
||||
#endif
|
||||
#if __has_feature(attribute_diagnose_if_objc)
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
|
||||
#else
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
|
||||
#endif
|
||||
#if __has_feature(modules)
|
||||
@import Photos;
|
||||
@import UIKit;
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
|
||||
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
|
||||
#if __has_warning("-Wpragma-clang-attribute")
|
||||
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wnullability"
|
||||
|
||||
SWIFT_MODULE_NAMESPACE_PUSH("ARVideoKit")
|
||||
@class NSCoder;
|
||||
|
||||
/// A <code>PHLivePhotoPlus</code> object is a <code>PHLivePhoto</code> sub-class that contains objects to allow manual exporting of a live photo.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_CLASS("_TtC10ARVideoKit15PHLivePhotoPlus")
|
||||
@interface PHLivePhotoPlus : PHLivePhoto
|
||||
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
|
||||
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SWIFT_MODULE_NAMESPACE_POP
|
||||
#pragma clang diagnostic pop
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+18
-14
@@ -1,21 +1,25 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "ARVideoKit"
|
||||
s.version = "1.5.12"
|
||||
s.summary = "Capture & record ARKit videos 📹, photos 🌄, Live Photos 🎇, and GIFs 🎆."
|
||||
s.description = "Enabling developers to capture videos 📹, photos 🌄, Live Photos 🎇, and GIFs 🎆 with augmented reality components."
|
||||
s.homepage = "https://github.com/AFathi/ARVideoKit"
|
||||
s.screenshots = "http://www.ahmedbekhit.com/SK_PREV.gif", "http://www.ahmedbekhit.com/SCN_PREVIEW.gif"
|
||||
|
||||
s.name = "ARVideoKit"
|
||||
s.version = "1.0"
|
||||
s.summary = "Enabling developers to capture media with ARKit content."
|
||||
|
||||
s.description = "An iOS Framework that enables developers to capture videos 📹, photos 🌄, Live Photos 🎇, and GIFs 🎆 with ARKit content."
|
||||
|
||||
s.homepage = "https://github.com/AFathi/ARVideoKit"
|
||||
|
||||
s.screenshots = "http://www.ahmedbekhit.com/SK_PREV.gif"
|
||||
|
||||
s.author = { "Ahmed Bekhit" => "me@ahmedbekhit.com" }
|
||||
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }
|
||||
|
||||
s.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
|
||||
|
||||
s.author = { "Ahmed Fathi Bekhit" => "me@ahmedbekhit.com" }
|
||||
s.social_media_url = "http://ahmedbekhit.com"
|
||||
|
||||
s.platform = :ios, "11.0"
|
||||
|
||||
s.source = { :http => "http://ahmedbekhit.com/ARVideoKit.zip" }
|
||||
s.module_map = "ARVideoKit.framework/Modules/module.modulemap"
|
||||
s.vendored_frameworks = "ARVideoKit.framework"
|
||||
# ARVideoKit for Swift 4.0
|
||||
s.source = { :git => "https://github.com/AFathi/ARVideoKit.git", :tag => "1.5.12" }
|
||||
s.source_files = "ARVideoKit", "ARVideoKit/**/*.{h,m,swift}"
|
||||
s.resources = "ARVideoKit/Assets/*.scnassets"
|
||||
|
||||
s.swift_version = '4.0'
|
||||
end
|
||||
|
||||
@@ -0,0 +1,507 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 48;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
FB2E36891FAE29C00035B8D6 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = FB2E36881FAE29BF0035B8D6 /* LICENSE */; };
|
||||
FB404FFE20D72A190056EA1D /* JPEG.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB404FFD20D72A190056EA1D /* JPEG.swift */; };
|
||||
FBD604DF1FA969DD00EC9804 /* ARVideoKit.h in Headers */ = {isa = PBXBuildFile; fileRef = FBD604DD1FA969DD00EC9804 /* ARVideoKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
FBD604EB1FA96B1C00EC9804 /* video.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = FBD604EA1FA96B1C00EC9804 /* video.scnassets */; };
|
||||
FBD604EE1FA96B2700EC9804 /* ARVideoOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604EC1FA96B2700EC9804 /* ARVideoOptions.swift */; };
|
||||
FBD604EF1FA96B2700EC9804 /* ARInputViewOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604ED1FA96B2700EC9804 /* ARInputViewOptions.swift */; };
|
||||
FBD604F51FA96B3300EC9804 /* UIImage+VideoBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604F01FA96B3300EC9804 /* UIImage+VideoBuffer.swift */; };
|
||||
FBD604F61FA96B3300EC9804 /* CGImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604F11FA96B3300EC9804 /* CGImage+Resize.swift */; };
|
||||
FBD604F71FA96B3300EC9804 /* RecordAR+PhotoRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604F21FA96B3300EC9804 /* RecordAR+PhotoRender.swift */; };
|
||||
FBD604F81FA96B3300EC9804 /* UIView+isType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604F31FA96B3300EC9804 /* UIView+isType.swift */; };
|
||||
FBD604F91FA96B3300EC9804 /* UIViewController+hasType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604F41FA96B3300EC9804 /* UIViewController+hasType.swift */; };
|
||||
FBD604FC1FA96B3E00EC9804 /* RecordARDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604FA1FA96B3E00EC9804 /* RecordARDelegate.swift */; };
|
||||
FBD604FD1FA96B3E00EC9804 /* RenderARDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604FB1FA96B3E00EC9804 /* RenderARDelegate.swift */; };
|
||||
FBD605001FA96B5500EC9804 /* Generate+GIF.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD604FF1FA96B5500EC9804 /* Generate+GIF.swift */; };
|
||||
FBD605071FA96B6B00EC9804 /* LoveLiver_LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = FBD605021FA96B6B00EC9804 /* LoveLiver_LICENSE */; };
|
||||
FBD605081FA96B6B00EC9804 /* Generate+LivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD605031FA96B6B00EC9804 /* Generate+LivePhoto.swift */; };
|
||||
FBD6050A1FA96B6B00EC9804 /* QuickTimeMov.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD605051FA96B6B00EC9804 /* QuickTimeMov.swift */; };
|
||||
FBD6050B1FA96B6B00EC9804 /* PHLivePhotoPlus.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD605061FA96B6B00EC9804 /* PHLivePhotoPlus.swift */; };
|
||||
FBD605111FA96BA100EC9804 /* ARView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD6050D1FA96BA100EC9804 /* ARView.swift */; };
|
||||
FBD605121FA96BA100EC9804 /* RecordAR.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD6050E1FA96BA100EC9804 /* RecordAR.swift */; };
|
||||
FBD605131FA96BA100EC9804 /* WritAR.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD6050F1FA96BA100EC9804 /* WritAR.swift */; };
|
||||
FBD605141FA96BA100EC9804 /* ViewAR.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD605101FA96BA100EC9804 /* ViewAR.swift */; };
|
||||
FBE5A5A62002BFCF0025C89F /* RenderAR.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE5A5A52002BFCF0025C89F /* RenderAR.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
FB2E36881FAE29BF0035B8D6 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
FB404FFD20D72A190056EA1D /* JPEG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JPEG.swift; sourceTree = "<group>"; };
|
||||
FBD604DA1FA969DD00EC9804 /* ARVideoKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ARVideoKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FBD604DD1FA969DD00EC9804 /* ARVideoKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARVideoKit.h; sourceTree = "<group>"; };
|
||||
FBD604DE1FA969DD00EC9804 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FBD604EA1FA96B1C00EC9804 /* video.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = video.scnassets; sourceTree = "<group>"; };
|
||||
FBD604EC1FA96B2700EC9804 /* ARVideoOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARVideoOptions.swift; sourceTree = "<group>"; };
|
||||
FBD604ED1FA96B2700EC9804 /* ARInputViewOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARInputViewOptions.swift; sourceTree = "<group>"; };
|
||||
FBD604F01FA96B3300EC9804 /* UIImage+VideoBuffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+VideoBuffer.swift"; sourceTree = "<group>"; };
|
||||
FBD604F11FA96B3300EC9804 /* CGImage+Resize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGImage+Resize.swift"; sourceTree = "<group>"; };
|
||||
FBD604F21FA96B3300EC9804 /* RecordAR+PhotoRender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RecordAR+PhotoRender.swift"; sourceTree = "<group>"; };
|
||||
FBD604F31FA96B3300EC9804 /* UIView+isType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+isType.swift"; sourceTree = "<group>"; };
|
||||
FBD604F41FA96B3300EC9804 /* UIViewController+hasType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+hasType.swift"; sourceTree = "<group>"; };
|
||||
FBD604FA1FA96B3E00EC9804 /* RecordARDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecordARDelegate.swift; sourceTree = "<group>"; };
|
||||
FBD604FB1FA96B3E00EC9804 /* RenderARDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RenderARDelegate.swift; sourceTree = "<group>"; };
|
||||
FBD604FF1FA96B5500EC9804 /* Generate+GIF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Generate+GIF.swift"; sourceTree = "<group>"; };
|
||||
FBD605021FA96B6B00EC9804 /* LoveLiver_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LoveLiver_LICENSE; sourceTree = "<group>"; };
|
||||
FBD605031FA96B6B00EC9804 /* Generate+LivePhoto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Generate+LivePhoto.swift"; sourceTree = "<group>"; };
|
||||
FBD605051FA96B6B00EC9804 /* QuickTimeMov.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickTimeMov.swift; sourceTree = "<group>"; };
|
||||
FBD605061FA96B6B00EC9804 /* PHLivePhotoPlus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PHLivePhotoPlus.swift; sourceTree = "<group>"; };
|
||||
FBD6050D1FA96BA100EC9804 /* ARView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARView.swift; sourceTree = "<group>"; };
|
||||
FBD6050E1FA96BA100EC9804 /* RecordAR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecordAR.swift; sourceTree = "<group>"; };
|
||||
FBD6050F1FA96BA100EC9804 /* WritAR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WritAR.swift; sourceTree = "<group>"; };
|
||||
FBD605101FA96BA100EC9804 /* ViewAR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewAR.swift; sourceTree = "<group>"; };
|
||||
FBE5A5A52002BFCF0025C89F /* RenderAR.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenderAR.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
FBD604D61FA969DD00EC9804 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
FBA0AA0A1FAD9D9D006C481B /* Writer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD6050F1FA96BA100EC9804 /* WritAR.swift */,
|
||||
);
|
||||
path = Writer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604D01FA969DD00EC9804 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB2E36881FAE29BF0035B8D6 /* LICENSE */,
|
||||
FBD604DC1FA969DD00EC9804 /* ARVideoKit */,
|
||||
FBD604DB1FA969DD00EC9804 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604DB1FA969DD00EC9804 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604DA1FA969DD00EC9804 /* ARVideoKit.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604DC1FA969DD00EC9804 /* ARVideoKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604E51FA96ACD00EC9804 /* Assets */,
|
||||
FBD604E61FA96AD400EC9804 /* Enumerations */,
|
||||
FBD604E71FA96AE500EC9804 /* Extensions */,
|
||||
FBD604E81FA96AEC00EC9804 /* Protocols */,
|
||||
FBD604E91FA96AF400EC9804 /* Rendering */,
|
||||
FBD6050C1FA96B8F00EC9804 /* Sources */,
|
||||
FBD604DD1FA969DD00EC9804 /* ARVideoKit.h */,
|
||||
FBD604DE1FA969DD00EC9804 /* Info.plist */,
|
||||
);
|
||||
path = ARVideoKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604E51FA96ACD00EC9804 /* Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604EA1FA96B1C00EC9804 /* video.scnassets */,
|
||||
);
|
||||
path = Assets;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604E61FA96AD400EC9804 /* Enumerations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604ED1FA96B2700EC9804 /* ARInputViewOptions.swift */,
|
||||
FBD604EC1FA96B2700EC9804 /* ARVideoOptions.swift */,
|
||||
);
|
||||
path = Enumerations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604E71FA96AE500EC9804 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604F11FA96B3300EC9804 /* CGImage+Resize.swift */,
|
||||
FBD604F21FA96B3300EC9804 /* RecordAR+PhotoRender.swift */,
|
||||
FBD604F01FA96B3300EC9804 /* UIImage+VideoBuffer.swift */,
|
||||
FBD604F31FA96B3300EC9804 /* UIView+isType.swift */,
|
||||
FBD604F41FA96B3300EC9804 /* UIViewController+hasType.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604E81FA96AEC00EC9804 /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604FA1FA96B3E00EC9804 /* RecordARDelegate.swift */,
|
||||
FBD604FB1FA96B3E00EC9804 /* RenderARDelegate.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604E91FA96AF400EC9804 /* Rendering */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBE5A5A52002BFCF0025C89F /* RenderAR.swift */,
|
||||
FBA0AA0A1FAD9D9D006C481B /* Writer */,
|
||||
FBD604FE1FA96B4800EC9804 /* GIF */,
|
||||
FBD605011FA96B5900EC9804 /* Live Photo */,
|
||||
);
|
||||
path = Rendering;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD604FE1FA96B4800EC9804 /* GIF */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD604FF1FA96B5500EC9804 /* Generate+GIF.swift */,
|
||||
);
|
||||
path = GIF;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD605011FA96B5900EC9804 /* Live Photo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBDBF6BA20F3E009004E757D /* LoveLiver */,
|
||||
FBD605031FA96B6B00EC9804 /* Generate+LivePhoto.swift */,
|
||||
FBD605061FA96B6B00EC9804 /* PHLivePhotoPlus.swift */,
|
||||
);
|
||||
path = "Live Photo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD6050C1FA96B8F00EC9804 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD6050D1FA96BA100EC9804 /* ARView.swift */,
|
||||
FBD6050E1FA96BA100EC9804 /* RecordAR.swift */,
|
||||
FBD605101FA96BA100EC9804 /* ViewAR.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBDBF6BA20F3E009004E757D /* LoveLiver */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD605021FA96B6B00EC9804 /* LoveLiver_LICENSE */,
|
||||
FB404FFD20D72A190056EA1D /* JPEG.swift */,
|
||||
FBD605051FA96B6B00EC9804 /* QuickTimeMov.swift */,
|
||||
);
|
||||
path = LoveLiver;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
FBD604D71FA969DD00EC9804 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBD604DF1FA969DD00EC9804 /* ARVideoKit.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
FBD604D91FA969DD00EC9804 /* ARVideoKit */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = FBD604E21FA969DD00EC9804 /* Build configuration list for PBXNativeTarget "ARVideoKit" */;
|
||||
buildPhases = (
|
||||
FBD604D51FA969DD00EC9804 /* Sources */,
|
||||
FBD604D61FA969DD00EC9804 /* Frameworks */,
|
||||
FBD604D71FA969DD00EC9804 /* Headers */,
|
||||
FBD604D81FA969DD00EC9804 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = ARVideoKit;
|
||||
productName = ARVideoKit;
|
||||
productReference = FBD604DA1FA969DD00EC9804 /* ARVideoKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
FBD604D11FA969DD00EC9804 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0940;
|
||||
ORGANIZATIONNAME = "Ahmed Fathit Bekhit";
|
||||
TargetAttributes = {
|
||||
FBD604D91FA969DD00EC9804 = {
|
||||
CreatedOnToolsVersion = 9.1;
|
||||
LastSwiftMigration = 0910;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = FBD604D41FA969DD00EC9804 /* Build configuration list for PBXProject "ARVideoKit" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = FBD604D01FA969DD00EC9804;
|
||||
productRefGroup = FBD604DB1FA969DD00EC9804 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
FBD604D91FA969DD00EC9804 /* ARVideoKit */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
FBD604D81FA969DD00EC9804 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FB2E36891FAE29C00035B8D6 /* LICENSE in Resources */,
|
||||
FBD604EB1FA96B1C00EC9804 /* video.scnassets in Resources */,
|
||||
FBD605071FA96B6B00EC9804 /* LoveLiver_LICENSE in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
FBD604D51FA969DD00EC9804 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBD604F81FA96B3300EC9804 /* UIView+isType.swift in Sources */,
|
||||
FBD604F71FA96B3300EC9804 /* RecordAR+PhotoRender.swift in Sources */,
|
||||
FBD6050A1FA96B6B00EC9804 /* QuickTimeMov.swift in Sources */,
|
||||
FB404FFE20D72A190056EA1D /* JPEG.swift in Sources */,
|
||||
FBD604FD1FA96B3E00EC9804 /* RenderARDelegate.swift in Sources */,
|
||||
FBD605131FA96BA100EC9804 /* WritAR.swift in Sources */,
|
||||
FBD604F51FA96B3300EC9804 /* UIImage+VideoBuffer.swift in Sources */,
|
||||
FBD605111FA96BA100EC9804 /* ARView.swift in Sources */,
|
||||
FBD604F61FA96B3300EC9804 /* CGImage+Resize.swift in Sources */,
|
||||
FBD604F91FA96B3300EC9804 /* UIViewController+hasType.swift in Sources */,
|
||||
FBD605141FA96BA100EC9804 /* ViewAR.swift in Sources */,
|
||||
FBD604EE1FA96B2700EC9804 /* ARVideoOptions.swift in Sources */,
|
||||
FBD605001FA96B5500EC9804 /* Generate+GIF.swift in Sources */,
|
||||
FBD605081FA96B6B00EC9804 /* Generate+LivePhoto.swift in Sources */,
|
||||
FBD605121FA96BA100EC9804 /* RecordAR.swift in Sources */,
|
||||
FBE5A5A62002BFCF0025C89F /* RenderAR.swift in Sources */,
|
||||
FBD604FC1FA96B3E00EC9804 /* RecordARDelegate.swift in Sources */,
|
||||
FBD604EF1FA96B2700EC9804 /* ARInputViewOptions.swift in Sources */,
|
||||
FBD6050B1FA96B6B00EC9804 /* PHLivePhotoPlus.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
FBD604E01FA969DD00EC9804 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BITCODE_GENERATION_MODE = marker;
|
||||
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_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;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
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 = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "-fembed-bitcode-marker";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FBD604E11FA969DD00EC9804 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
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_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;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
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 = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_CFLAGS = "-fembed-bitcode";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
FBD604E31FA969DD00EC9804 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=*]" = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = YES;
|
||||
INFOPLIST_FILE = ARVideoKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ahmedbekhit.ARVideoKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FBD604E41FA969DD00EC9804 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = YES;
|
||||
INFOPLIST_FILE = ARVideoKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ahmedbekhit.ARVideoKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
FBD604D41FA969DD00EC9804 /* Build configuration list for PBXProject "ARVideoKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FBD604E01FA969DD00EC9804 /* Debug */,
|
||||
FBD604E11FA969DD00EC9804 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
FBD604E21FA969DD00EC9804 /* Build configuration list for PBXNativeTarget "ARVideoKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FBD604E31FA969DD00EC9804 /* Debug */,
|
||||
FBD604E41FA969DD00EC9804 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = FBD604D11FA969DD00EC9804 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:ARVideoKit.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,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>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0940"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FBD604D91FA969DD00EC9804"
|
||||
BuildableName = "ARVideoKit.framework"
|
||||
BlueprintName = "ARVideoKit"
|
||||
ReferencedContainer = "container:ARVideoKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FBD604D91FA969DD00EC9804"
|
||||
BuildableName = "ARVideoKit.framework"
|
||||
BlueprintName = "ARVideoKit"
|
||||
ReferencedContainer = "container:ARVideoKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FBD604D91FA969DD00EC9804"
|
||||
BuildableName = "ARVideoKit.framework"
|
||||
BlueprintName = "ARVideoKit"
|
||||
ReferencedContainer = "container:ARVideoKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0940"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FBD604D91FA969DD00EC9804"
|
||||
BuildableName = "ARVideoKit.framework"
|
||||
BlueprintName = "ARVideoKit"
|
||||
ReferencedContainer = "container:ARVideoKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FBD604D91FA969DD00EC9804"
|
||||
BuildableName = "ARVideoKit.framework"
|
||||
BlueprintName = "ARVideoKit"
|
||||
ReferencedContainer = "container:ARVideoKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "FBD604D91FA969DD00EC9804"
|
||||
BuildableName = "ARVideoKit.framework"
|
||||
BlueprintName = "ARVideoKit"
|
||||
ReferencedContainer = "container:ARVideoKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -2,12 +2,11 @@
|
||||
// ARVideoKit.h
|
||||
// ARVideoKit
|
||||
//
|
||||
// Created by Ahmed Bekhit on 11/5/17.
|
||||
// Created by Ahmed Bekhit on 10/31/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for ARVideoKit.
|
||||
FOUNDATION_EXPORT double ARVideoKitVersionNumber;
|
||||
|
||||
|
||||
Regular → Executable
BIN
Binary file not shown.
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// ARInputViewOptions.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Allows specifying the accepted orientaions in a `UIViewController` with AR scenes.
|
||||
@objc public enum ARInputViewOrientation: Int {
|
||||
/// Enables the portrait input views orientation.
|
||||
case portrait = 1
|
||||
/// Enables the landscape left input views orientation.
|
||||
case landscapeLeft = 3
|
||||
/// Enables the landscape right input views orientation.
|
||||
case landscapeRight = 4
|
||||
}
|
||||
|
||||
/// Allows specifying which subviews will rotate in a `UIViewController` with AR scenes.
|
||||
public enum ARInputViewOrientationMode {
|
||||
/// The framework automatically detects and rotates key objects in a `UIViewController`.
|
||||
case auto
|
||||
/// Rotates all objects in a `UIViewController`.
|
||||
case all
|
||||
/// Rotates manually specified `UIView` subviews in a `UIViewController`.
|
||||
case manual(subviews:[UIView])
|
||||
/// Disables rotating any objects in a `UIViewController`.
|
||||
case disabled
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// ARVideoOptions.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
/// Allows specifying the final video orientation.
|
||||
@objc public enum ARFrameMode: Int {
|
||||
case auto
|
||||
case aspectFit
|
||||
/// Recommended for iPhone X
|
||||
case aspectFill
|
||||
}
|
||||
|
||||
/// Allows specifying the video rendering frame per second `FPS` rate.
|
||||
@objc public enum ARVideoFrameRate: Int {
|
||||
/// The framework automatically sets the most appropriate `FPS` based on the device support.
|
||||
case auto = 0
|
||||
/// Sets the `FPS` to 30 frames per second.
|
||||
case fps30 = 30
|
||||
/// Sets the `FPS` to 60 frames per second.
|
||||
case fps60 = 60
|
||||
}
|
||||
|
||||
/// Allows specifying the final video orientation.
|
||||
@objc public enum ARVideoOrientation: Int {
|
||||
/// The framework automatically sets the video orientation based on the active `ARInputViewOrientation` orientations.
|
||||
case auto
|
||||
/// Sets the video orientation to always portrait.
|
||||
case alwaysPortrait
|
||||
/// Sets the video orientation to always landscape.
|
||||
case alwaysLandscape
|
||||
}
|
||||
|
||||
/// Allows specifying when to request Microphone access.
|
||||
@objc public enum RecordARMicrophonePermission: Int {
|
||||
/// The framework automatically requests Microphone access when needed.
|
||||
case auto
|
||||
/// Allows manual permission request.
|
||||
case manual
|
||||
}
|
||||
|
||||
/// An object that returns the AR recorder current status.
|
||||
@objc public enum RecordARStatus: Int {
|
||||
/// The current status of the recorder is unknown.
|
||||
case unknown
|
||||
/// The current recorder is ready to record.
|
||||
case readyToRecord
|
||||
/// The current recorder is recording.
|
||||
case recording
|
||||
/// The current recorder is paused.
|
||||
case paused
|
||||
}
|
||||
|
||||
/// An object that returns the current Microphone status.
|
||||
@objc public enum RecordARMicrophoneStatus: Int {
|
||||
// The current status of the Microphone access is unknown.
|
||||
case unknown
|
||||
// The current status of the Microphone access is enabled.
|
||||
case enabled
|
||||
// The current status of the Microphone access is disabled.
|
||||
case disabled
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// CGImage+Resize.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/27/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreGraphics
|
||||
|
||||
extension CGImage {
|
||||
func resize(with ratio: Float) -> CGImage? {
|
||||
let imageWidth: Int = Int(Float(self.width) * ratio)
|
||||
let imageHeight: Int = Int(Float(self.height) * ratio)
|
||||
|
||||
guard let colorSpace = self.colorSpace else { return nil }
|
||||
guard let context = CGContext(data: nil, width: imageWidth, height: imageHeight, bitsPerComponent: self.bitsPerComponent, bytesPerRow: self.bytesPerRow, space: colorSpace, bitmapInfo: self.alphaInfo.rawValue) else { return nil }
|
||||
|
||||
context.interpolationQuality = .low
|
||||
context.draw(self, in: CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight))
|
||||
|
||||
return context.makeImage()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// RecordAR+PhotoRender.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/27/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import Photos
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
extension RecordAR {
|
||||
|
||||
func adjustTime(current: CMTime, resume: CMTime, pause: CMTime) -> CMTime {
|
||||
return CMTimeSubtract(current, CMTimeSubtract(resume, pause))
|
||||
}
|
||||
|
||||
func imageFromBuffer(buffer: CVPixelBuffer) -> UIImage {
|
||||
let coreImg = CIImage(cvPixelBuffer: buffer)
|
||||
let context = CIContext()
|
||||
let cgImg = context.createCGImage(coreImg, from: coreImg.extent)
|
||||
|
||||
var angleEnabled: Bool {
|
||||
for v in inputViewOrientations {
|
||||
if UIDevice.current.orientation.rawValue == v.rawValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var recentAngle: CGFloat = 0
|
||||
var rotationAngle: CGFloat = 0
|
||||
switch UIDevice.current.orientation {
|
||||
case .landscapeLeft:
|
||||
rotationAngle = -90
|
||||
recentAngle = -90
|
||||
case .landscapeRight:
|
||||
rotationAngle = 90
|
||||
recentAngle = 90
|
||||
case .faceUp, .faceDown, .portraitUpsideDown:
|
||||
rotationAngle = recentAngle
|
||||
default:
|
||||
rotationAngle = 0
|
||||
recentAngle = 0
|
||||
}
|
||||
|
||||
if !angleEnabled {
|
||||
rotationAngle = 0
|
||||
}
|
||||
|
||||
switch videoOrientation {
|
||||
case .alwaysPortrait:
|
||||
rotationAngle = 0
|
||||
case .alwaysLandscape:
|
||||
if rotationAngle != 90 || rotationAngle != -90 {
|
||||
rotationAngle = -90
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return UIImage(cgImage: cgImg!).rotate(by: rotationAngle, flip: false)
|
||||
}
|
||||
|
||||
@objc func appWillEnterBackground() {
|
||||
delegate?.recorder(willEnterBackground: status)
|
||||
}
|
||||
}
|
||||
|
||||
extension FloatingPoint {
|
||||
var degreesToRadians: Self { return self * .pi / 180 }
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// UIImage+VideoBuffer.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreVideo
|
||||
import UIKit
|
||||
|
||||
extension UIImage
|
||||
{
|
||||
func rotate(by degrees: CGFloat, flip: Bool? = nil) -> UIImage
|
||||
{
|
||||
let radians = CGFloat(degrees * (CGFloat.pi / 180.0))
|
||||
|
||||
let bufferView = UIView(frame: CGRect(origin: CGPoint.zero, size: self.size))
|
||||
let t: CGAffineTransform = CGAffineTransform(rotationAngle: radians)
|
||||
bufferView.transform = t
|
||||
let bufferSize = bufferView.frame.size
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(bufferSize, false, self.scale)
|
||||
let bitmap = UIGraphicsGetCurrentContext()
|
||||
bitmap?.translateBy(x: bufferSize.width / 2, y: bufferSize.height / 2)
|
||||
bitmap?.rotate(by: radians)
|
||||
if let isFlipped = flip {
|
||||
if !isFlipped {
|
||||
bitmap?.scaleBy(x: 1.0, y: -1.0)
|
||||
} else {
|
||||
bitmap?.scaleBy(x: -1.0, y: -1.0)
|
||||
}
|
||||
} else {
|
||||
bitmap?.scaleBy(x: -1.0, y: -1.0)
|
||||
}
|
||||
bitmap?.draw(self.cgImage!, in: CGRect(origin: CGPoint(x: -self.size.width / 2, y: -self.size.height / 2), size: self.size))
|
||||
|
||||
let finalBuffer = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
return finalBuffer!
|
||||
}
|
||||
|
||||
var buffer: CVPixelBuffer? {
|
||||
let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
|
||||
var pixelBuffer: CVPixelBuffer?
|
||||
let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(self.size.width), Int(self.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
|
||||
guard (status == kCVReturnSuccess) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!)
|
||||
|
||||
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let context = CGContext(data: pixelData, width: Int(self.size.width), height: Int(self.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
|
||||
|
||||
context?.translateBy(x: 0, y: self.size.height)
|
||||
context?.scaleBy(x: 1.0, y: -1.0)
|
||||
|
||||
UIGraphicsPushContext(context!)
|
||||
self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
|
||||
UIGraphicsPopContext()
|
||||
CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
|
||||
return pixelBuffer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// UIView+isType.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ARKit
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
extension UIScreen {
|
||||
/**
|
||||
`isiPhone10` is a boolean that returns if the device is iPhone X or not.
|
||||
*/
|
||||
var isiPhone10: Bool {
|
||||
return self.nativeBounds.size == CGSize(width: 1125, height: 2436) || self.nativeBounds.size == CGSize(width: 2436, height: 1125)
|
||||
}
|
||||
}
|
||||
@available(iOS 11.0, *)
|
||||
extension UIView {
|
||||
var parent: UIViewController? {
|
||||
var responder: UIResponder? = self
|
||||
while responder != nil {
|
||||
responder = responder!.next
|
||||
if let viewController = responder as? UIViewController {
|
||||
return viewController
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var isButton: Bool {
|
||||
return (self is UIButton)
|
||||
}
|
||||
|
||||
var isARView: Bool {
|
||||
return (self is ARSCNView) || (self is ARSKView)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIViewController+hasType.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ARKit
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
extension UIViewController {
|
||||
var hasARView: Bool {
|
||||
let views = self.view.subviews
|
||||
for v in views {
|
||||
if v is ARSCNView || v is ARSKView {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>ARVideoKit</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -15,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>1.31</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// RecordARDelegate.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreVideo
|
||||
import CoreMedia
|
||||
import ARKit
|
||||
|
||||
/**
|
||||
The recorder protocol.
|
||||
|
||||
- Author: Ahmed Fathi Bekhit
|
||||
* [Github](http://github.com/AFathi)
|
||||
* [Website](http://ahmedbekhit.com)
|
||||
* [Twitter](http://twitter.com/iAFapps)
|
||||
* [Email](mailto:me@ahmedbekhit.com)
|
||||
*/
|
||||
@available(iOS 11.0, *)
|
||||
@objc public protocol RecordARDelegate {
|
||||
/**
|
||||
A protocol method that is triggered when a recorder ends recording.
|
||||
- parameter path: A `URL` object that returns the video file path.
|
||||
- parameter noError: A boolean that returns true when the recorder ends without errors. Otherwise, it returns false.
|
||||
*/
|
||||
func recorder(didEndRecording path: URL, with noError: Bool)
|
||||
/**
|
||||
A protocol method that is triggered when a recorder fails recording.
|
||||
- parameter error: An `Error` object that returns the error value.
|
||||
- parameter status: A string that returns the reason of the recorder failure in a string literal format.
|
||||
*/
|
||||
func recorder(didFailRecording error: Error?, and status: String)
|
||||
|
||||
/**
|
||||
A protocol method that is triggered when the application will resign active.
|
||||
- parameter status: A `RecordARStatus` object that returns the AR recorder current status.
|
||||
|
||||
|
||||
- NOTE: Check [applicationWillResignActive(_:)](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive) for more information.
|
||||
*/
|
||||
@objc func recorder(willEnterBackground status: RecordARStatus)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// RenderARDelegate.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/21/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreVideo
|
||||
import CoreMedia
|
||||
import ARKit
|
||||
|
||||
/**
|
||||
The renderer protocol.
|
||||
|
||||
- Author: Ahmed Fathi Bekhit
|
||||
* [Github](http://github.com/AFathi)
|
||||
* [Website](http://ahmedbekhit.com)
|
||||
* [Twitter](http://twitter.com/iAFapps)
|
||||
* [Email](mailto:me@ahmedbekhit.com)
|
||||
*/
|
||||
@available(iOS 11.0, *)
|
||||
@objc public protocol RenderARDelegate {
|
||||
/**
|
||||
A protocol method that is triggered when a frame renders the `ARSCNView` or `ARSKView` content with the device's camera stream.
|
||||
- parameter buffer: A `CVPixelBuffer` object that returns the rendered buffer.
|
||||
- parameter time: A `CMTime` object that returns the time a buffer was rendered with.
|
||||
- parameter rawBuffer: A `CVPixelBuffer` object that returns the raw buffer.
|
||||
*/
|
||||
func frame(didRender buffer: CVPixelBuffer, with time: CMTime, using rawBuffer: CVPixelBuffer)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Generate+GIF.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/27/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
import ImageIO
|
||||
import MobileCoreServices
|
||||
|
||||
class GIFGenerator {
|
||||
let gifQueue = DispatchQueue(label:"com.ahmedbekhit.GIFQueue", attributes: .concurrent)
|
||||
private var currentGIFPath: URL?
|
||||
private var newGIFPath: URL {
|
||||
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
|
||||
let documentsDirectory = paths[0]
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .full
|
||||
formatter.timeStyle = .full
|
||||
formatter.dateFormat = "yyyy-MM-dd'@'HH-mm-ssZZZZ"
|
||||
|
||||
let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970)
|
||||
|
||||
let gifPath = "\(documentsDirectory)/\(formatter.string(from: date))AR.gif"
|
||||
return URL(fileURLWithPath: gifPath, isDirectory: false)
|
||||
}
|
||||
|
||||
func generate(gif images:[UIImage], with delay: Float, loop count: Int = 0, adjust: Bool, _ finished: ((_ status: Bool, _ path: URL?) -> Void)? = nil) {
|
||||
currentGIFPath = newGIFPath
|
||||
gifQueue.async {
|
||||
let gifSettings = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: count]]
|
||||
let imageSettings = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: delay]]
|
||||
|
||||
guard let path = self.currentGIFPath else { return }
|
||||
guard let destination = CGImageDestinationCreateWithURL(path as CFURL, kUTTypeGIF, images.count, nil) else {
|
||||
finished?(false, nil)
|
||||
return
|
||||
}
|
||||
logAR.message("\(destination)")
|
||||
CGImageDestinationSetProperties(destination, gifSettings as CFDictionary)
|
||||
for image in images {
|
||||
if let imageRef = image.cgImage {
|
||||
var ratio: Float = 0.0
|
||||
if adjust { ratio = 0.5 } else { ratio = 1.0 }
|
||||
CGImageDestinationAddImage(destination, imageRef.resize(with: ratio)!, imageSettings as CFDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
if !CGImageDestinationFinalize(destination){
|
||||
finished?(false, nil)
|
||||
return
|
||||
} else {
|
||||
finished?(true, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// Generate+LivePhoto.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/28/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import Photos
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
class LivePhotoGenerator {
|
||||
private var keyPhotoPath: URL?
|
||||
|
||||
private var finalKeyPhotoPath: URL?
|
||||
private var finalPairedVideoPath: URL?
|
||||
|
||||
let livePhotoQueue = DispatchQueue(label:"com.ahmedbekhit.livePhotoQueue", attributes: .concurrent)
|
||||
|
||||
func generate(livePhoto video: URL?, _ finished: ((_ status: Bool, _ photo: PHLivePhotoPlus?, _ pairedVideoPath: URL?, _ keyFramePath: URL?) -> Void)? = nil) {
|
||||
livePhotoQueue.async {
|
||||
guard let liveFrames = video else { finished?(false, nil, nil, nil); return }
|
||||
let asset = AVURLAsset(url: video!)
|
||||
let generator = AVAssetImageGenerator(asset: asset)
|
||||
generator.appliesPreferredTrackTransform = true
|
||||
|
||||
//retrieves the key photo frame from the middle of the video asset
|
||||
let time = NSValue(time: CMTimeMultiplyByFloat64(asset.duration, 0.5))
|
||||
|
||||
//generates the key photo CGImage asynchronously
|
||||
generator.generateCGImagesAsynchronously(forTimes: [time], completionHandler: { _, image, _, _, _ in
|
||||
if let cgImg = image, let imgData = UIImagePNGRepresentation(UIImage(cgImage: cgImg)) {
|
||||
do {
|
||||
self.keyPhotoPath = self.newPath(for: true, and: false)
|
||||
try imgData.write(to: self.keyPhotoPath!, options: [.atomic])
|
||||
} catch let error {
|
||||
self.keyPhotoPath = nil
|
||||
logAR.message("An error occurred while capturing a live photo: \(error)")
|
||||
finished?(false, nil, nil, nil)
|
||||
return
|
||||
}
|
||||
self.finalKeyPhotoPath = self.newPath(for: true, and: true)
|
||||
self.finalPairedVideoPath = self.newPath(for: false, and: true)
|
||||
|
||||
guard let keyFrame = self.keyPhotoPath else { finished?(false, nil, nil, nil); return }
|
||||
guard let keyLiveFrame = self.finalKeyPhotoPath else { finished?(false, nil, nil, nil); return }
|
||||
guard let keyLiveFrames = self.finalPairedVideoPath else { finished?(false, nil, nil, nil); return }
|
||||
|
||||
let assetIdentifier = UUID().uuidString
|
||||
|
||||
JPEG(path: keyFrame.path).write(keyLiveFrame.path, assetIdentifier: assetIdentifier)
|
||||
QuickTimeMov(path: liveFrames.path).write(keyLiveFrames.path, assetIdentifier: assetIdentifier)
|
||||
|
||||
|
||||
PHLivePhoto.request(withResourceFileURLs: [keyLiveFrames, keyLiveFrame], placeholderImage: UIImage(cgImage: cgImg), targetSize: .zero, contentMode: .aspectFit) { photo, settings in
|
||||
logAR.remove(from: keyFrame)
|
||||
logAR.remove(from: liveFrames)
|
||||
if let livePhoto = photo {
|
||||
let finalPhoto = PHLivePhotoPlus(photo: livePhoto)
|
||||
finalPhoto.keyPhotoPath = keyLiveFrame
|
||||
finalPhoto.pairedVideoPath = keyLiveFrames
|
||||
finished?(true, finalPhoto, finalPhoto.pairedVideoPath, finalPhoto.keyPhotoPath)
|
||||
return
|
||||
} else {
|
||||
let finalPhoto = PHLivePhotoPlus(photo: photo!)
|
||||
finalPhoto.keyPhotoPath = keyLiveFrame
|
||||
finalPhoto.pairedVideoPath = keyLiveFrames
|
||||
finished?(false, finalPhoto, finalPhoto.pairedVideoPath, finalPhoto.keyPhotoPath)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newPath(for JPEG: Bool, and live: Bool) -> URL {
|
||||
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
|
||||
let documentsDirectory = paths[0]
|
||||
|
||||
let livePhotosFolder = "\(documentsDirectory)/livePhotos"
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .full
|
||||
formatter.timeStyle = .full
|
||||
formatter.dateFormat = "yyyy-MM-dd'@'HH-mm-ssZZZZ"
|
||||
|
||||
let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970)
|
||||
|
||||
do {
|
||||
try FileManager.default.createDirectory(atPath: livePhotosFolder, withIntermediateDirectories: true, attributes: nil)
|
||||
}catch let error {
|
||||
logAR.message("An error occurred while rendering the live photo: \(error)")
|
||||
return URL(fileURLWithPath: "\(documentsDirectory)/\(formatter.string(from: date))AR.jpg", isDirectory: false)
|
||||
}
|
||||
|
||||
if JPEG && live {
|
||||
return URL(fileURLWithPath: "\(livePhotosFolder)/\(formatter.string(from: date))AR.jpg", isDirectory: false)
|
||||
} else if JPEG && !live {
|
||||
return URL(fileURLWithPath: "\(documentsDirectory)/\(formatter.string(from: date))AR.jpg", isDirectory: false)
|
||||
} else {
|
||||
return URL(fileURLWithPath: "\(livePhotosFolder)/\(formatter.string(from: date))AR.mov", isDirectory: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// JPEG.swift
|
||||
// LoveLiver
|
||||
//
|
||||
// Created by mzp on 10/10/15.
|
||||
// Copyright © 2015 mzp. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MobileCoreServices
|
||||
import ImageIO
|
||||
|
||||
class JPEG {
|
||||
private let kFigAppleMakerNote_AssetIdentifier = "17"
|
||||
private let path: String
|
||||
|
||||
init(path: String) {
|
||||
self.path = path
|
||||
}
|
||||
|
||||
func read() -> String? {
|
||||
guard let makerNote = metadata()?.object(forKey: kCGImagePropertyMakerAppleDictionary) as? NSDictionary? else {
|
||||
return nil
|
||||
}
|
||||
return makerNote?.object(forKey: kFigAppleMakerNote_AssetIdentifier) as? String
|
||||
}
|
||||
|
||||
func write(_ dest: String, assetIdentifier: String) {
|
||||
guard let dest = CGImageDestinationCreateWithURL(URL(fileURLWithPath: dest) as CFURL, kUTTypeJPEG, 1, nil)
|
||||
else { return }
|
||||
defer { CGImageDestinationFinalize(dest) }
|
||||
guard let imageSource = self.imageSource() else { return }
|
||||
guard let metadata = self.metadata()?.mutableCopy() as? NSMutableDictionary else { return }
|
||||
|
||||
let makerNote = NSMutableDictionary()
|
||||
makerNote.setObject(assetIdentifier, forKey: kFigAppleMakerNote_AssetIdentifier as NSCopying)
|
||||
metadata.setObject(makerNote, forKey: kCGImagePropertyMakerAppleDictionary as String as String as NSCopying)
|
||||
CGImageDestinationAddImageFromSource(dest, imageSource, 0, metadata)
|
||||
}
|
||||
|
||||
private func metadata() -> NSDictionary? {
|
||||
return self.imageSource().flatMap {
|
||||
CGImageSourceCopyPropertiesAtIndex($0, 0, nil) as NSDictionary?
|
||||
}
|
||||
}
|
||||
|
||||
private func imageSource() -> CGImageSource? {
|
||||
return self.data().flatMap {
|
||||
CGImageSourceCreateWithData($0 as CFData, nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func data() -> Data? {
|
||||
return (try? Data(contentsOf: URL(fileURLWithPath: path)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
|
||||
//
|
||||
// QuickTimeMov.swift
|
||||
// LoveLiver
|
||||
//
|
||||
// Created by mzp on 10/10/15.
|
||||
// Copyright © 2015 mzp. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
class QuickTimeMov {
|
||||
private let kKeyContentIdentifier = "com.apple.quicktime.content.identifier"
|
||||
private let kKeyStillImageTime = "com.apple.quicktime.still-image-time"
|
||||
private let kKeySpaceQuickTimeMetadata = "mdta"
|
||||
private let path: String
|
||||
private let dummyTimeRange = CMTimeRangeMake(CMTimeMake(0, 1000), CMTimeMake(200, 3000))
|
||||
|
||||
private lazy var asset: AVURLAsset = {
|
||||
let url = URL(fileURLWithPath: self.path)
|
||||
return AVURLAsset(url: url)
|
||||
}()
|
||||
|
||||
init(path: String) {
|
||||
self.path = path
|
||||
}
|
||||
|
||||
func readAssetIdentifier() -> String? {
|
||||
for item in metadata() {
|
||||
if item.key as? String == kKeyContentIdentifier &&
|
||||
item.keySpace!.rawValue == kKeySpaceQuickTimeMetadata {
|
||||
return item.value as? String
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readStillImageTime() -> NSNumber? {
|
||||
if let track = track(AVMediaType.metadata) {
|
||||
let (reader, output) = try! self.reader(track, settings: nil)
|
||||
reader.startReading()
|
||||
|
||||
while true {
|
||||
guard let buffer = output.copyNextSampleBuffer() else { return nil }
|
||||
if CMSampleBufferGetNumSamples(buffer) > 0 {
|
||||
let group = AVTimedMetadataGroup(sampleBuffer: buffer)
|
||||
for item in group?.items ?? [] {
|
||||
if item.key as? String == kKeyStillImageTime &&
|
||||
item.keySpace!.rawValue == kKeySpaceQuickTimeMetadata {
|
||||
return item.numberValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func write(_ dest: String, assetIdentifier: String) {
|
||||
|
||||
var audioReader: AVAssetReader? = nil
|
||||
var audioWriterInput: AVAssetWriterInput? = nil
|
||||
var audioReaderOutput: AVAssetReaderOutput? = nil
|
||||
do {
|
||||
// --------------------------------------------------
|
||||
// reader for source video
|
||||
// --------------------------------------------------
|
||||
guard let track = self.track(AVMediaType.video) else {
|
||||
logAR.message("not found video track")
|
||||
return
|
||||
}
|
||||
let readerSettings: [String: AnyObject] = [
|
||||
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA as AnyObject
|
||||
]
|
||||
let (reader, output) = try self.reader(track,
|
||||
settings: readerSettings)
|
||||
// --------------------------------------------------
|
||||
// writer for mov
|
||||
// --------------------------------------------------
|
||||
let writer = try AVAssetWriter(outputURL: URL(fileURLWithPath: dest), fileType: AVFileType.mov)
|
||||
writer.metadata = [metadataFor(assetIdentifier)]
|
||||
|
||||
// video track
|
||||
let input = AVAssetWriterInput(mediaType: AVMediaType.video,
|
||||
outputSettings: videoSettings(track.naturalSize))
|
||||
input.expectsMediaDataInRealTime = true
|
||||
input.transform = track.preferredTransform
|
||||
writer.add(input)
|
||||
|
||||
|
||||
let url = URL(fileURLWithPath: self.path)
|
||||
let aAudioAsset: AVAsset = AVAsset(url: url)
|
||||
|
||||
if aAudioAsset.tracks.count > 1 {
|
||||
logAR.message("Has Audio")
|
||||
//setup audio writer
|
||||
audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
|
||||
|
||||
audioWriterInput?.expectsMediaDataInRealTime = false
|
||||
if writer.canAdd(audioWriterInput!){
|
||||
writer.add(audioWriterInput!)
|
||||
}
|
||||
//setup audio reader
|
||||
let audioTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaType.audio).first!
|
||||
audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
|
||||
|
||||
do{
|
||||
audioReader = try AVAssetReader(asset: aAudioAsset)
|
||||
} catch {
|
||||
fatalError("Unable to read Asset: \(error): ")
|
||||
}
|
||||
//let audioReader: AVAssetReader = AVAssetReader(asset: aAudioAsset, error: &error)
|
||||
if (audioReader?.canAdd(audioReaderOutput!))! {
|
||||
audioReader?.add(audioReaderOutput!)
|
||||
} else {
|
||||
logAR.message("cant add audio reader")
|
||||
}
|
||||
}
|
||||
|
||||
// metadata track
|
||||
let adapter = metadataAdapter()
|
||||
writer.add(adapter.assetWriterInput)
|
||||
|
||||
// --------------------------------------------------
|
||||
// creating video
|
||||
// --------------------------------------------------
|
||||
writer.startWriting()
|
||||
reader.startReading()
|
||||
writer.startSession(atSourceTime: kCMTimeZero)
|
||||
|
||||
// write metadata track
|
||||
adapter.append(AVTimedMetadataGroup(items: [metadataForStillImageTime()],
|
||||
timeRange: dummyTimeRange))
|
||||
|
||||
// write video track
|
||||
input.requestMediaDataWhenReady(on: DispatchQueue(label: "assetVideoWriterQueue", attributes: [])) {
|
||||
while(input.isReadyForMoreMediaData) {
|
||||
if reader.status == .reading {
|
||||
if let buffer = output.copyNextSampleBuffer() {
|
||||
if !input.append(buffer) {
|
||||
logAR.message("cannot write: \(String(describing: writer.error))")
|
||||
reader.cancelReading()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
input.markAsFinished()
|
||||
if reader.status == .completed && aAudioAsset.tracks.count > 1 {
|
||||
audioReader?.startReading()
|
||||
writer.startSession(atSourceTime: kCMTimeZero)
|
||||
let media_queue = DispatchQueue(label: "assetAudioWriterQueue", attributes: [])
|
||||
audioWriterInput?.requestMediaDataWhenReady(on: media_queue) {
|
||||
while (audioWriterInput?.isReadyForMoreMediaData)! {
|
||||
let sampleBuffer2:CMSampleBuffer? = audioReaderOutput?.copyNextSampleBuffer()
|
||||
if audioReader?.status == .reading && sampleBuffer2 != nil {
|
||||
if !(audioWriterInput?.append(sampleBuffer2!))! {
|
||||
audioReader?.cancelReading()
|
||||
}
|
||||
} else {
|
||||
audioWriterInput?.markAsFinished()
|
||||
logAR.message("Audio writer finish")
|
||||
writer.finishWriting() {
|
||||
if let e = writer.error {
|
||||
logAR.message("cannot write: \(e)")
|
||||
} else {
|
||||
logAR.message("finish writing.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
logAR.message("Video Reader not completed")
|
||||
writer.finishWriting() {
|
||||
if let e = writer.error {
|
||||
logAR.message("cannot write: \(e)")
|
||||
} else {
|
||||
logAR.message("finish writing.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while writer.status == .writing {
|
||||
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.5))
|
||||
}
|
||||
if let e = writer.error {
|
||||
logAR.message("cannot write: \(e)")
|
||||
}
|
||||
} catch {
|
||||
logAR.message("error")
|
||||
}
|
||||
}
|
||||
|
||||
private func metadata() -> [AVMetadataItem] {
|
||||
return asset.metadata(forFormat: AVMetadataFormat.quickTimeMetadata)
|
||||
}
|
||||
|
||||
private func track(_ mediaType: AVMediaType) -> AVAssetTrack? {
|
||||
return asset.tracks(withMediaType: mediaType).first
|
||||
}
|
||||
|
||||
private func reader(_ track: AVAssetTrack, settings: [String: AnyObject]?) throws -> (AVAssetReader, AVAssetReaderOutput) {
|
||||
let output = AVAssetReaderTrackOutput(track: track, outputSettings: settings)
|
||||
let reader = try AVAssetReader(asset: asset)
|
||||
reader.add(output)
|
||||
return (reader, output)
|
||||
}
|
||||
|
||||
private func metadataAdapter() -> AVAssetWriterInputMetadataAdaptor {
|
||||
let spec: NSDictionary = [
|
||||
kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as NSString:
|
||||
"\(kKeySpaceQuickTimeMetadata)/\(kKeyStillImageTime)",
|
||||
kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as NSString:
|
||||
"com.apple.metadata.datatype.int8" ]
|
||||
|
||||
var desc: CMFormatDescription? = nil
|
||||
CMMetadataFormatDescriptionCreateWithMetadataSpecifications(kCFAllocatorDefault, kCMMetadataFormatType_Boxed, [spec] as CFArray, &desc)
|
||||
let input = AVAssetWriterInput(mediaType: AVMediaType.metadata,
|
||||
outputSettings: nil, sourceFormatHint: desc)
|
||||
return AVAssetWriterInputMetadataAdaptor(assetWriterInput: input)
|
||||
}
|
||||
|
||||
private func videoSettings(_ size: CGSize) -> [String: AnyObject] {
|
||||
return [
|
||||
AVVideoCodecKey: AVVideoCodecType.h264 as AnyObject,
|
||||
AVVideoWidthKey: size.width as AnyObject,
|
||||
AVVideoHeightKey: size.height as AnyObject
|
||||
]
|
||||
}
|
||||
|
||||
private func metadataFor(_ assetIdentifier: String) -> AVMetadataItem {
|
||||
let item = AVMutableMetadataItem()
|
||||
item.key = kKeyContentIdentifier as (NSCopying & NSObjectProtocol)?
|
||||
item.keySpace = AVMetadataKeySpace(rawValue: kKeySpaceQuickTimeMetadata)
|
||||
item.value = assetIdentifier as (NSCopying & NSObjectProtocol)?
|
||||
item.dataType = "com.apple.metadata.datatype.UTF-8"
|
||||
return item
|
||||
}
|
||||
|
||||
private func metadataForStillImageTime() -> AVMetadataItem {
|
||||
let item = AVMutableMetadataItem()
|
||||
item.key = kKeyStillImageTime as (NSCopying & NSObjectProtocol)?
|
||||
item.keySpace = AVMetadataKeySpace(rawValue: kKeySpaceQuickTimeMetadata)
|
||||
item.value = 0 as (NSCopying & NSObjectProtocol)?
|
||||
item.dataType = "com.apple.metadata.datatype.int8"
|
||||
return item
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// PHLivePhotoPlus.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/30/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import Photos
|
||||
|
||||
/**
|
||||
A `PHLivePhotoPlus` object is a `PHLivePhoto` sub-class that contains objects to allow manual exporting of a live photo.
|
||||
|
||||
- Author: Ahmed Fathi Bekhit
|
||||
* [Github](http://github.com/AFathi)
|
||||
* [Website](http://ahmedbekhit.com)
|
||||
* [Twitter](http://twitter.com/iAFapps)
|
||||
* [Email](mailto:me@ahmedbekhit.com)
|
||||
*/
|
||||
@available(iOS 9.1, *)
|
||||
@objc public class PHLivePhotoPlus: NSObject {
|
||||
var pairedVideoPath: URL?
|
||||
var keyPhotoPath: URL?
|
||||
|
||||
/// A `PHLivePhoto` object that returns the Live Photo content from `PHLivePhotoPlus`.
|
||||
@objc public var livePhoto: PHLivePhoto?
|
||||
|
||||
@objc public override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
@objc public init(photo: PHLivePhoto) {
|
||||
super.init()
|
||||
livePhoto = photo
|
||||
}
|
||||
|
||||
@objc required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// RenderAR.swift
|
||||
// ARVideoKit
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/7/18.
|
||||
// Copyright © 2018 Ahmed Fathit Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ARKit
|
||||
|
||||
private var view: Any?
|
||||
private var renderEngine: SCNRenderer!
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
struct RenderAR {
|
||||
var ARcontentMode: ARFrameMode!
|
||||
|
||||
init(_ ARview: Any?, renderer: SCNRenderer, contentMode: ARFrameMode) {
|
||||
view = ARview
|
||||
renderEngine = renderer
|
||||
ARcontentMode = contentMode
|
||||
}
|
||||
|
||||
let pixelsQueue = DispatchQueue(label: "com.ahmedbekhit.PixelsQueue", attributes: .concurrent)
|
||||
var time: CFTimeInterval { return CACurrentMediaTime()}
|
||||
var rawBuffer: CVPixelBuffer? {
|
||||
if let view = view as? ARSCNView {
|
||||
guard let rawBuffer = view.session.currentFrame?.capturedImage else { return nil }
|
||||
return rawBuffer
|
||||
} else if let view = view as? ARSKView {
|
||||
guard let rawBuffer = view.session.currentFrame?.capturedImage else { return nil }
|
||||
return rawBuffer
|
||||
} else if view is SCNView {
|
||||
return buffer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var bufferSize: CGSize? {
|
||||
guard let raw = rawBuffer else { return nil }
|
||||
var width = CVPixelBufferGetWidth(raw)
|
||||
var height = CVPixelBufferGetHeight(raw)
|
||||
|
||||
if let contentMode = ARcontentMode {
|
||||
switch contentMode {
|
||||
case .auto:
|
||||
if UIScreen.main.isiPhone10 {
|
||||
width = Int(UIScreen.main.nativeBounds.width)
|
||||
height = Int(UIScreen.main.nativeBounds.height)
|
||||
}
|
||||
case .aspectFit:
|
||||
width = CVPixelBufferGetWidth(raw)
|
||||
height = CVPixelBufferGetHeight(raw)
|
||||
case .aspectFill:
|
||||
width = Int(UIScreen.main.nativeBounds.width)
|
||||
height = Int(UIScreen.main.nativeBounds.height)
|
||||
default:
|
||||
if UIScreen.main.isiPhone10 {
|
||||
width = Int(UIScreen.main.nativeBounds.width)
|
||||
height = Int(UIScreen.main.nativeBounds.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if width > height {
|
||||
return CGSize(width: height, height: width)
|
||||
} else {
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
}
|
||||
|
||||
var bufferSizeFill: CGSize? {
|
||||
guard let raw = rawBuffer else { return nil }
|
||||
let width = CVPixelBufferGetWidth(raw)
|
||||
let height = CVPixelBufferGetHeight(raw)
|
||||
if width > height {
|
||||
return CGSize(width: height, height: width)
|
||||
} else {
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
}
|
||||
|
||||
var buffer: CVPixelBuffer? {
|
||||
if view is ARSCNView {
|
||||
guard let size = bufferSize else { return nil }
|
||||
//UIScreen.main.bounds.size
|
||||
var renderedFrame: UIImage?
|
||||
pixelsQueue.sync {
|
||||
renderedFrame = renderEngine.snapshot(atTime: self.time, with: size, antialiasingMode: .none)
|
||||
}
|
||||
if let _ = renderedFrame {
|
||||
} else {
|
||||
renderedFrame = renderEngine.snapshot(atTime: time, with: size, antialiasingMode: .none)
|
||||
}
|
||||
|
||||
guard let buffer = renderedFrame!.buffer else { return nil }
|
||||
|
||||
return buffer
|
||||
} else if view is ARSKView {
|
||||
guard let size = bufferSize else { return nil }
|
||||
var renderedFrame: UIImage?
|
||||
pixelsQueue.sync {
|
||||
renderedFrame = renderEngine.snapshot(atTime: self.time, with: size, antialiasingMode: .none).rotate(by: 180)
|
||||
}
|
||||
if renderedFrame == nil {
|
||||
renderedFrame = renderEngine.snapshot(atTime: time, with: size, antialiasingMode: .none).rotate(by: 180)
|
||||
}
|
||||
guard let buffer = renderedFrame!.buffer else { return nil }
|
||||
return buffer;
|
||||
} else if view is SCNView {
|
||||
let size = UIScreen.main.bounds.size
|
||||
var renderedFrame: UIImage?
|
||||
pixelsQueue.sync {
|
||||
renderedFrame = renderEngine.snapshot(atTime: self.time, with: size, antialiasingMode: .none)
|
||||
}
|
||||
if let _ = renderedFrame {
|
||||
} else {
|
||||
renderedFrame = renderEngine.snapshot(atTime: time, with: size, antialiasingMode: .none)
|
||||
}
|
||||
guard let buffer = renderedFrame!.buffer else { return nil }
|
||||
return buffer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
//
|
||||
// WritAR.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/19/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import CoreImage
|
||||
import UIKit
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
class WritAR: NSObject, AVCaptureAudioDataOutputSampleBufferDelegate {
|
||||
private var assetWriter: AVAssetWriter!
|
||||
private var videoInput: AVAssetWriterInput!
|
||||
private var audioInput: AVAssetWriterInput!
|
||||
private var session: AVCaptureSession!
|
||||
|
||||
private var pixelBufferInput: AVAssetWriterInputPixelBufferAdaptor!
|
||||
private var videoOutputSettings: Dictionary<String, AnyObject>!
|
||||
private var audioSettings: [String: Any]?
|
||||
|
||||
let audioBufferQueue = DispatchQueue(label: "com.ahmedbekhit.AudioBufferQueue")
|
||||
|
||||
private var isRecording: Bool = false
|
||||
|
||||
var delegate: RecordARDelegate?
|
||||
var videoInputOrientation: ARVideoOrientation = .auto
|
||||
|
||||
init(output: URL, width: Int, height: Int, adjustForSharing: Bool, audioEnabled: Bool, orientaions:[ARInputViewOrientation], queue: DispatchQueue, allowMix: Bool) {
|
||||
super.init()
|
||||
do {
|
||||
assetWriter = try AVAssetWriter(outputURL: output, fileType: AVFileType.mp4)
|
||||
} catch {
|
||||
fatalError("An error occurred while intializing an AVAssetWriter")
|
||||
}
|
||||
|
||||
if audioEnabled {
|
||||
if allowMix {
|
||||
let audioOptions: AVAudioSessionCategoryOptions = [.mixWithOthers , .allowBluetooth, .defaultToSpeaker, .interruptSpokenAudioAndMixWithOthers]
|
||||
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: audioOptions)
|
||||
try? AVAudioSession.sharedInstance().setActive(true)
|
||||
}
|
||||
AVAudioSession.sharedInstance().requestRecordPermission({ permitted in
|
||||
if permitted {
|
||||
self.prepareAudioDevice(with: queue)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//HEVC file format only supports A10 Fusion Chip or higher.
|
||||
//to support HEVC, make sure to check if the device is iPhone 7 or higher
|
||||
videoOutputSettings = [
|
||||
AVVideoCodecKey: AVVideoCodecType.h264 as AnyObject,
|
||||
AVVideoWidthKey: width as AnyObject,
|
||||
AVVideoHeightKey: height as AnyObject
|
||||
]
|
||||
|
||||
// let attributes: [String: Bool] = [
|
||||
// kCVPixelBufferCGImageCompatibilityKey as String: true,
|
||||
// kCVPixelBufferCGBitmapContextCompatibilityKey as String: true
|
||||
// ]
|
||||
videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoOutputSettings)
|
||||
|
||||
videoInput.expectsMediaDataInRealTime = true
|
||||
pixelBufferInput = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoInput, sourcePixelBufferAttributes: nil)
|
||||
|
||||
var angleEnabled: Bool {
|
||||
for v in orientaions {
|
||||
if UIDevice.current.orientation.rawValue == v.rawValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var recentAngle: CGFloat = 0
|
||||
var rotationAngle: CGFloat = 0
|
||||
switch UIDevice.current.orientation {
|
||||
case .landscapeLeft:
|
||||
rotationAngle = -90
|
||||
recentAngle = -90
|
||||
case .landscapeRight:
|
||||
rotationAngle = 90
|
||||
recentAngle = 90
|
||||
case .faceUp, .faceDown, .portraitUpsideDown:
|
||||
rotationAngle = recentAngle
|
||||
default:
|
||||
rotationAngle = 0
|
||||
recentAngle = 0
|
||||
}
|
||||
|
||||
if !angleEnabled {
|
||||
rotationAngle = 0
|
||||
}
|
||||
|
||||
var t = CGAffineTransform.identity
|
||||
|
||||
switch videoInputOrientation {
|
||||
case .auto:
|
||||
t = t.rotated(by: ((rotationAngle*CGFloat.pi) / 180))
|
||||
case .alwaysPortrait:
|
||||
t = t.rotated(by: 0)
|
||||
case .alwaysLandscape:
|
||||
if rotationAngle == 90 || rotationAngle == -90 {
|
||||
t = t.rotated(by: ((rotationAngle * CGFloat.pi) / 180))
|
||||
} else {
|
||||
t = t.rotated(by: ((-90 * CGFloat.pi) / 180))
|
||||
}
|
||||
}
|
||||
|
||||
videoInput.transform = t
|
||||
|
||||
if assetWriter.canAdd(videoInput) {
|
||||
assetWriter.add(videoInput)
|
||||
} else {
|
||||
delegate?.recorder(didFailRecording: assetWriter.error, and: "An error occurred while adding video input.")
|
||||
isWritingWithoutError = false
|
||||
}
|
||||
assetWriter.shouldOptimizeForNetworkUse = adjustForSharing
|
||||
}
|
||||
|
||||
func prepareAudioDevice(with queue: DispatchQueue) {
|
||||
let device: AVCaptureDevice = AVCaptureDevice.default(for: .audio)!
|
||||
var audioDeviceInput: AVCaptureDeviceInput?
|
||||
do {
|
||||
audioDeviceInput = try AVCaptureDeviceInput(device: device)
|
||||
} catch {
|
||||
audioDeviceInput = nil
|
||||
}
|
||||
|
||||
let audioDataOutput = AVCaptureAudioDataOutput()
|
||||
audioDataOutput.setSampleBufferDelegate(self, queue: queue)
|
||||
|
||||
session = AVCaptureSession()
|
||||
session.sessionPreset = .medium
|
||||
session.usesApplicationAudioSession = true
|
||||
session.automaticallyConfiguresApplicationAudioSession = false
|
||||
|
||||
if session.canAddInput(audioDeviceInput!) {
|
||||
session.addInput(audioDeviceInput!)
|
||||
}
|
||||
|
||||
if session.canAddOutput(audioDataOutput) {
|
||||
session.addOutput(audioDataOutput)
|
||||
}
|
||||
|
||||
|
||||
audioSettings = audioDataOutput.recommendedAudioSettingsForAssetWriter(writingTo: .m4v) as? [String: Any]
|
||||
|
||||
audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioSettings)
|
||||
audioInput.expectsMediaDataInRealTime = true
|
||||
|
||||
audioBufferQueue.async {
|
||||
self.session.startRunning()
|
||||
}
|
||||
|
||||
if assetWriter.canAdd(audioInput) {
|
||||
assetWriter.add(audioInput)
|
||||
}
|
||||
}
|
||||
|
||||
var startingVideoTime: CMTime?
|
||||
var isWritingWithoutError: Bool?
|
||||
|
||||
func insert(pixel buffer: CVPixelBuffer, with intervals: CFTimeInterval) {
|
||||
let time: CMTime = CMTimeMakeWithSeconds(intervals, 1000000)
|
||||
if assetWriter.status == .unknown {
|
||||
guard startingVideoTime == nil else {
|
||||
isWritingWithoutError = false
|
||||
return
|
||||
}
|
||||
startingVideoTime = time
|
||||
if assetWriter.startWriting() {
|
||||
assetWriter.startSession(atSourceTime: startingVideoTime!)
|
||||
session.startRunning()
|
||||
isRecording = true
|
||||
isWritingWithoutError = true
|
||||
} else {
|
||||
delegate?.recorder(didFailRecording: assetWriter.error, and: "An error occurred while starting the video session.")
|
||||
isWritingWithoutError = false
|
||||
}
|
||||
} else if assetWriter.status == .failed {
|
||||
delegate?.recorder(didFailRecording: assetWriter.error, and: "Video session failed while recording.")
|
||||
logAR.message("An error occurred while recording the video, status: \(assetWriter.status.rawValue), error: \(assetWriter.error!.localizedDescription)")
|
||||
isWritingWithoutError = false
|
||||
return
|
||||
}
|
||||
if videoInput.isReadyForMoreMediaData {
|
||||
append(pixel: buffer, with: time)
|
||||
isWritingWithoutError = true
|
||||
}
|
||||
}
|
||||
|
||||
func insert(pixel buffer: CVPixelBuffer, with time: CMTime) {
|
||||
if assetWriter.status == .unknown {
|
||||
guard startingVideoTime == nil else {
|
||||
isWritingWithoutError = false
|
||||
return
|
||||
}
|
||||
startingVideoTime = time
|
||||
if assetWriter.startWriting() {
|
||||
assetWriter.startSession(atSourceTime: startingVideoTime!)
|
||||
isRecording = true
|
||||
isWritingWithoutError = true
|
||||
} else {
|
||||
delegate?.recorder(didFailRecording: assetWriter.error, and: "An error occurred while starting the video session.")
|
||||
isRecording = false
|
||||
isWritingWithoutError = false
|
||||
}
|
||||
} else if assetWriter.status == .failed {
|
||||
delegate?.recorder(didFailRecording: assetWriter.error, and: "Video session failed while recording.")
|
||||
logAR.message("An error occurred while recording the video, status: \(assetWriter.status.rawValue), error: \(assetWriter.error!.localizedDescription)")
|
||||
isRecording = false
|
||||
isWritingWithoutError = false
|
||||
return
|
||||
}
|
||||
|
||||
if videoInput.isReadyForMoreMediaData {
|
||||
append(pixel: buffer, with: time)
|
||||
isRecording = true
|
||||
isWritingWithoutError = true
|
||||
}
|
||||
}
|
||||
|
||||
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
||||
if let input = audioInput {
|
||||
audioBufferQueue.async { [weak self] in
|
||||
if input.isReadyForMoreMediaData && (self?.isRecording)! {
|
||||
input.append(sampleBuffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pause() {
|
||||
isRecording = false
|
||||
}
|
||||
|
||||
func end(writing finished: @escaping () -> Void){
|
||||
if let session = session {
|
||||
if session.isRunning {
|
||||
session.stopRunning()
|
||||
}
|
||||
}
|
||||
assetWriter.finishWriting(completionHandler: finished)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
private extension WritAR {
|
||||
func append(pixel buffer: CVPixelBuffer, with time: CMTime) {
|
||||
pixelBufferInput.append(buffer, withPresentationTime: time)
|
||||
}
|
||||
}
|
||||
|
||||
//Simple Logging to show logs only while debugging.
|
||||
class logAR {
|
||||
class func message(_ message: String) {
|
||||
#if DEBUG
|
||||
print("ARVideoKit @ \(Date().timeIntervalSince1970):- \(message)")
|
||||
#endif
|
||||
}
|
||||
|
||||
class func remove(from path: URL?) {
|
||||
if let file = path?.path {
|
||||
let manager = FileManager.default
|
||||
if manager.fileExists(atPath: file) {
|
||||
do{
|
||||
try manager.removeItem(atPath: file)
|
||||
self.message("Successfuly deleted media file from cached after exporting to Camera Roll.")
|
||||
} catch let error {
|
||||
self.message("An error occurred while deleting cached media: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// ARView.swift
|
||||
// ARVideoKit
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/14/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ARKit
|
||||
|
||||
/**
|
||||
A class that configures the Augmented Reality View orientations.
|
||||
|
||||
- Author: Ahmed Fathi Bekhit
|
||||
* [Github](http://github.com/AFathi)
|
||||
* [Website](http://ahmedbekhit.com)
|
||||
* [Twitter](http://twitter.com/iAFapps)
|
||||
* [Email](mailto:me@ahmedbekhit.com)
|
||||
*/
|
||||
@available(iOS 11.0, *)
|
||||
@objc public class ARView: NSObject {
|
||||
private var parentVC: UIViewController?
|
||||
private var recentAngle = 0
|
||||
private var inputViewOrientation:[ARInputViewOrientation] = []
|
||||
|
||||
/// An array of `ARInputViewOrientation` objects that allow customizing the accepted orientations in a `UIViewController` that contains Augmented Reality scenes.
|
||||
public var inputViewOrientations: [ARInputViewOrientation] {
|
||||
get{
|
||||
return inputViewOrientation
|
||||
}
|
||||
set{
|
||||
if newValue.count == 0 {
|
||||
inputViewOrientation = [.portrait]
|
||||
} else {
|
||||
inputViewOrientation = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var ivom: ARInputViewOrientationMode = .auto
|
||||
/// An object that allow customizing which subviews will rotate in a `UIViewController` that contains Augmented Reality scenes.
|
||||
public var inputViewOrientationMode: ARInputViewOrientationMode {
|
||||
get{
|
||||
return ivom
|
||||
}
|
||||
set{
|
||||
ivom = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc init?(ARSceneKit: ARSCNView) {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
|
||||
|
||||
let value = UIInterfaceOrientation.portrait.rawValue
|
||||
UIDevice.current.setValue(value, forKey: "orientation")
|
||||
|
||||
ViewAR.orientation = .portrait
|
||||
|
||||
guard let vc = ARSceneKit.parent else {
|
||||
return
|
||||
}
|
||||
|
||||
parentVC = vc
|
||||
}
|
||||
|
||||
@objc init?(ARSpriteKit: ARSKView) {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
|
||||
|
||||
let value = UIInterfaceOrientation.portrait.rawValue
|
||||
UIDevice.current.setValue(value, forKey: "orientation")
|
||||
|
||||
ViewAR.orientation = .portrait
|
||||
guard let vc = ARSpriteKit.parent else {
|
||||
return
|
||||
}
|
||||
parentVC = vc
|
||||
}
|
||||
|
||||
@objc init?(SceneKit: SCNView) {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
|
||||
|
||||
let value = UIInterfaceOrientation.portrait.rawValue
|
||||
UIDevice.current.setValue(value, forKey: "orientation")
|
||||
|
||||
ViewAR.orientation = .portrait
|
||||
|
||||
guard let vc = SceneKit.parent else {
|
||||
return
|
||||
}
|
||||
|
||||
parentVC = vc
|
||||
}
|
||||
|
||||
@objc private func deviceDidRotate() {
|
||||
guard var views = parentVC?.view.subviews else {
|
||||
return
|
||||
}
|
||||
|
||||
var rotationAngle = 0
|
||||
|
||||
switch inputViewOrientationMode {
|
||||
case .auto:
|
||||
views = views.filter { !$0.isARView && $0.isButton }
|
||||
case .all:
|
||||
views = views.filter { !$0.isARView }
|
||||
case .manual(let subviews):
|
||||
views = subviews.filter { !$0.isARView }
|
||||
case .disabled:
|
||||
views = []
|
||||
}
|
||||
var angleEnabled: Bool {
|
||||
for v in inputViewOrientations {
|
||||
if UIDevice.current.orientation.rawValue == v.rawValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
switch UIDevice.current.orientation {
|
||||
case .landscapeLeft:
|
||||
rotationAngle = 90
|
||||
recentAngle = 90
|
||||
case .landscapeRight:
|
||||
rotationAngle = -90
|
||||
recentAngle = -90
|
||||
case .faceUp, .faceDown, .portraitUpsideDown:
|
||||
rotationAngle = recentAngle
|
||||
default:
|
||||
rotationAngle = 0
|
||||
recentAngle = 0
|
||||
}
|
||||
|
||||
if !angleEnabled {
|
||||
rotationAngle = 0
|
||||
}
|
||||
|
||||
for view in views {
|
||||
UIView.animate(withDuration: 0.2, animations: {
|
||||
view.transform = CGAffineTransform(rotationAngle: CGFloat(rotationAngle).degreesToRadians)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,790 @@
|
||||
//
|
||||
// RecordAR.swift
|
||||
// ARVideoKit
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/18/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Metal
|
||||
import ARKit
|
||||
import Photos
|
||||
import PhotosUI
|
||||
|
||||
private var view: Any?
|
||||
private var renderEngine: SCNRenderer!
|
||||
private var gpuLoop: CADisplayLink!
|
||||
private var isResting = false
|
||||
private var ARcontentMode: ARFrameMode!
|
||||
@available(iOS 11.0, *)
|
||||
private var renderer: RenderAR!
|
||||
/**
|
||||
This class renders the `ARSCNView` or `ARSKView` content with the device's camera stream to generate a video 📹, photo 🌄, live photo 🎇 or GIF 🎆.
|
||||
|
||||
- Author: 🤓 Ahmed Fathi Bekhit © 2017
|
||||
* [Github](http://github.com/AFathi)
|
||||
* [Website](http://ahmedbekhit.com)
|
||||
* [Twitter](http://twitter.com/iAFapps)
|
||||
* [Email](mailto:me@ahmedbekhit.com)
|
||||
*/
|
||||
@available(iOS 11.0, *)
|
||||
@objc public class RecordAR: ARView {
|
||||
//MARK: - Public objects to configure RecordAR
|
||||
/**
|
||||
An object that passes the AR recorder errors and status in the protocol methods.
|
||||
*/
|
||||
@objc public weak var delegate: RecordARDelegate?
|
||||
/**
|
||||
An object that passes the AR rendered content in the protocol method.
|
||||
*/
|
||||
@objc public weak var renderAR: RenderARDelegate?
|
||||
/**
|
||||
An object that returns the AR recorder current status.
|
||||
*/
|
||||
@objc public internal(set)var status: RecordARStatus = .unknown
|
||||
/**
|
||||
An object that returns the current Microphone status.
|
||||
*/
|
||||
@objc public internal(set)var micStatus: RecordARMicrophoneStatus = .unknown
|
||||
/**
|
||||
An object that allow customizing when to ask for Microphone permission, if needed. Default is `.manual`.
|
||||
*/
|
||||
@objc public var requestMicPermission: RecordARMicrophonePermission = .manual {
|
||||
didSet {
|
||||
switch self.requestMicPermission {
|
||||
case .auto:
|
||||
if self.enableAudio {
|
||||
self.requestMicrophonePermission()
|
||||
}
|
||||
case .manual:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
An object that allow customizing the video frame per second rate. Default is `.auto`.
|
||||
*/
|
||||
@objc public var fps: ARVideoFrameRate = .auto
|
||||
/**
|
||||
An object that allow customizing the video orientation. Default is `.auto`.
|
||||
*/
|
||||
@objc public var videoOrientation: ARVideoOrientation = .auto
|
||||
/**
|
||||
An object that allow customizing the AR content mode. Default is `.auto`.
|
||||
*/
|
||||
@objc public var contentMode: ARFrameMode = .auto
|
||||
/**
|
||||
A boolean that enables or disables AR content rendering before recording for image & video processing. Default is `true`.
|
||||
*/
|
||||
@objc public var onlyRenderWhileRecording: Bool = true {
|
||||
didSet {
|
||||
self.onlyRenderWhileRec = self.onlyRenderWhileRecording
|
||||
}
|
||||
}
|
||||
/**
|
||||
A boolean that enables or disables audio recording. Default is `true`.
|
||||
*/
|
||||
@objc public var enableAudio: Bool = true {
|
||||
didSet {
|
||||
self.requestMicPermission = (self.requestMicPermission == .manual) ? .manual: .auto
|
||||
}
|
||||
}
|
||||
/**
|
||||
A boolean that enables or disables audio `mixWithOthers` if audio recording is enabled. This allows playing music and recording audio at the same time. Default is `true`.
|
||||
*/
|
||||
@objc public var enableMixWithOthers: Bool = true
|
||||
/**
|
||||
A boolean that enables or disables adjusting captured media for sharing online. Default is `true`.
|
||||
*/
|
||||
@objc public var adjustVideoForSharing: Bool = true
|
||||
/**
|
||||
A boolean that enables or disables adjusting captured GIFs for sharing online. Default is `true`.
|
||||
*/
|
||||
@objc public var adjustGIFForSharing: Bool = true
|
||||
/**
|
||||
A boolean that enables or disables clearing cached media after exporting to Camera Roll. Default is `true`.
|
||||
*/
|
||||
@objc public var deleteCacheWhenExported: Bool = true
|
||||
/**
|
||||
A boolean that enables or disables using envronment light rendering. Default is `false`.
|
||||
*/
|
||||
@objc public var enableAdjustEnvironmentLighting: Bool = false {
|
||||
didSet{
|
||||
if (renderEngine != nil) {
|
||||
renderEngine.autoenablesDefaultLighting = enableAdjustEnvironmentLighting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Public initialization methods
|
||||
/**
|
||||
Initialize 🌞🍳 `RecordAR` with an `ARSCNView` 🚀.
|
||||
*/
|
||||
@objc override public init?(ARSceneKit: ARSCNView) {
|
||||
super.init(ARSceneKit: ARSceneKit)
|
||||
view = ARSceneKit
|
||||
setup()
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize 🌞🍳 `RecordAR` with an `ARSKView` 👾.
|
||||
*/
|
||||
@objc override public init?(ARSpriteKit: ARSKView) {
|
||||
super.init(ARSpriteKit: ARSpriteKit)
|
||||
view = ARSpriteKit
|
||||
scnView = SCNView(frame: UIScreen.main.bounds)
|
||||
|
||||
let bundle = Bundle(for: RecordAR.self)
|
||||
let url = bundle.url(forResource: "video.scnassets/vid", withExtension: "scn")
|
||||
|
||||
do {
|
||||
let scene = try SCNScene(url: url!, options: nil)
|
||||
scnView.scene = scene
|
||||
setup()
|
||||
}catch let error {
|
||||
logAR.message("Error occurred while loading SK Video Assets : \(error). Please download \"video.scnassets\" from\nwww.ahmedbekhit.com/ARVideoKitAssets")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize 🌞🍳 `RecordAR` with an `SCNView` 🚀.
|
||||
*/
|
||||
@objc override public init?(SceneKit: SCNView) {
|
||||
super.init(SceneKit: SceneKit)
|
||||
view = SceneKit
|
||||
setup()
|
||||
}
|
||||
|
||||
//MARK: - threads
|
||||
let writerQueue = DispatchQueue(label:"com.ahmedbekhit.WriterQueue")
|
||||
let gifWriterQueue = DispatchQueue(label: "com.ahmedbekhit.GIFWriterQueue", attributes: .concurrent)
|
||||
let audioSessionQueue = DispatchQueue(label: "com.ahmedbekhit.AudioSessionQueue", attributes: .concurrent)
|
||||
|
||||
//MARK: - Objects
|
||||
private var scnView: SCNView!
|
||||
private var fileCount = 0
|
||||
|
||||
var parent: UIViewController? {
|
||||
if let view = view as? ARSCNView {
|
||||
return view.parent!
|
||||
} else if let view = view as? ARSKView {
|
||||
return view.parent!
|
||||
} else if let view = view as? SCNView {
|
||||
return view.parent!
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//Used for gif capturing
|
||||
var gifImages:[UIImage] = []
|
||||
//Used for checking current recorder status
|
||||
var isCapturingPhoto = false
|
||||
var isRecordingGIF = false
|
||||
var isRecording = false
|
||||
var adjustPausedTime = false
|
||||
var backFromPause = false
|
||||
var recordingWithLimit = false
|
||||
var onlyRenderWhileRec = true
|
||||
//Used to modify video time when paused
|
||||
var pausedFrameTime: CMTime?
|
||||
var resumeFrameTime: CMTime?
|
||||
//Used to locate the path of the video recording
|
||||
var currentVideoPath: URL?
|
||||
//Used to locate the path of the audio recording
|
||||
var currentAudioPath: URL?
|
||||
//Used to initialize the video writer
|
||||
var writer: WritAR?
|
||||
//Used to generate a new video path
|
||||
var newVideoPath: URL {
|
||||
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
|
||||
let documentsDirectory = paths[0]
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .full
|
||||
formatter.timeStyle = .full
|
||||
formatter.dateFormat = "yyyy-MM-dd'@'HH-mm-ssZZZZ"
|
||||
|
||||
let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970)
|
||||
|
||||
let vidPath = "\(documentsDirectory)/\(formatter.string(from: date))ARVideo.mp4"
|
||||
return URL(fileURLWithPath: vidPath, isDirectory: false)
|
||||
}
|
||||
|
||||
//MARK: - Video Setup
|
||||
func setup() {
|
||||
if let view = view as? ARSCNView {
|
||||
guard let mtlDevice = MTLCreateSystemDefaultDevice() else {
|
||||
logAR.message("ERROR:- This device does not support Metal")
|
||||
return
|
||||
}
|
||||
renderEngine = SCNRenderer(device: mtlDevice, options: nil)
|
||||
renderEngine.scene = view.scene
|
||||
|
||||
gpuLoop = CADisplayLink(target: self, selector: #selector(renderFrame))
|
||||
gpuLoop.preferredFramesPerSecond = fps.rawValue
|
||||
gpuLoop.add(to: .main, forMode: .commonModes)
|
||||
|
||||
status = .readyToRecord
|
||||
} else if let view = view as? ARSKView {
|
||||
guard let mtlDevice = MTLCreateSystemDefaultDevice() else {
|
||||
logAR.message("ERROR:- This device does not support Metal")
|
||||
return
|
||||
}
|
||||
let material = SCNMaterial()
|
||||
material.diffuse.contents = view.scene
|
||||
|
||||
let plane = SCNPlane(width: view.bounds.width, height: view.bounds.height)
|
||||
let node = SCNNode(geometry: plane)
|
||||
node.geometry?.firstMaterial = material
|
||||
node.position = SCNVector3Make(0, 0, 0)
|
||||
|
||||
scnView.scene?.rootNode.addChildNode(node)
|
||||
|
||||
renderEngine = SCNRenderer(device: mtlDevice, options: nil)
|
||||
renderEngine.scene = scnView.scene
|
||||
|
||||
gpuLoop = CADisplayLink(target: self, selector: #selector(renderFrame))
|
||||
gpuLoop.preferredFramesPerSecond = fps.rawValue
|
||||
gpuLoop.add(to: .main, forMode: .commonModes)
|
||||
|
||||
status = .readyToRecord
|
||||
} else if let view = view as? SCNView {
|
||||
guard let mtlDevice = MTLCreateSystemDefaultDevice() else {
|
||||
logAR.message("ERROR:- This device does not support Metal")
|
||||
return
|
||||
}
|
||||
renderEngine = SCNRenderer(device: mtlDevice, options: nil)
|
||||
renderEngine.scene = view.scene
|
||||
|
||||
gpuLoop = CADisplayLink(target: self, selector: #selector(renderFrame))
|
||||
gpuLoop.preferredFramesPerSecond = fps.rawValue
|
||||
gpuLoop.add(to: .main, forMode: .commonModes)
|
||||
|
||||
status = .readyToRecord
|
||||
}
|
||||
|
||||
onlyRenderWhileRec = onlyRenderWhileRecording
|
||||
|
||||
renderer = RenderAR(view, renderer: renderEngine, contentMode: contentMode)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//MARK: - Public methods for capturing videos, photos, Live Photos, and GIFs
|
||||
|
||||
/// A method that renders a photo 🌄 and returns it as `UIImage`.
|
||||
@objc public func photo() -> UIImage {
|
||||
if let buffer = renderer.buffer {
|
||||
return imageFromBuffer(buffer: buffer)
|
||||
}
|
||||
return UIImage()
|
||||
}
|
||||
/**
|
||||
A method that renders a `PHLivePhoto` 🎇 and returns `PHLivePhotoPlus` in the completion handler.
|
||||
|
||||
In order to manually export the `PHLivePhotoPlus`, use `export(live photo: PHLivePhotoPlus)` method.
|
||||
- parameter export: A boolean that enables or disables automatically exporting the `PHLivePhotoPlus` when ready.
|
||||
- parameter finished: A block that will be called when Live Photo rendering is complete.
|
||||
|
||||
The block returns the following parameters:
|
||||
|
||||
`status`
|
||||
A boolean that returns `true` when a `PHLivePhotoPlus` is successfully rendered. Otherwise, it returns `false`.
|
||||
|
||||
`livePhoto`
|
||||
A `PHLivePhotoPlus` object that contains a `PHLivePhoto` and other objects to allow manual exporting of a live photo.
|
||||
|
||||
`permissionStatus`
|
||||
A `PHAuthorizationStatus` object that returns the current application's status for exporting media to the Photo Library. It returns `nil` if the `export` parameter is `false`.
|
||||
|
||||
`exported`
|
||||
A boolean that returns `true` when a `PHLivePhotoPlus` is successfully exported to the Photo Library. Otherwise, it returns `false`.
|
||||
*/
|
||||
@objc public func livePhoto(export: Bool, _ finished: ((_ status: Bool, _ livePhoto: PHLivePhotoPlus, _ permissionStatus: PHAuthorizationStatus, _ exported: Bool) -> Swift.Void)? = nil) {
|
||||
self.record(forDuration: 3.0) { path in
|
||||
let generator: LivePhotoGenerator? = LivePhotoGenerator()
|
||||
generator?.generate(livePhoto: path) { success, photo, frames, keyFrame in
|
||||
if success && export {
|
||||
if self.fileCount == 0 {
|
||||
self.fileCount += 1
|
||||
self.export(live: photo!) { done, status in
|
||||
finished?(true, photo!, status, done)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
finished?(success, photo!, PHAuthorizationStatus.notDetermined, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that generates a GIF 🎆 image and returns its local path (`URL`) in the completion handler.
|
||||
|
||||
In order to manually export the GIF image `URL`, use `func export(image path: URL)` method.
|
||||
- parameter duration: A `TimeInterval` object that can be set to the duration specified in seconds.
|
||||
- parameter export: A boolean that enables or disables automatically exporting the GIF image `URL` when ready.
|
||||
- parameter finished: A block that will be called when GIF image rendering is complete.
|
||||
|
||||
The block returns the following parameters:
|
||||
|
||||
`status`
|
||||
A boolean that returns `true` when a GIF image `URL` is successfully rendered. Otherwise, it returns `false`.
|
||||
|
||||
`gifPath`
|
||||
A `URL` object that contains the local file path of the GIF image to allow manual exporting of a GIF.
|
||||
|
||||
`permissionStatus`
|
||||
A `PHAuthorizationStatus` object that returns the current application's status for exporting media to the Photo Library. It returns `nil` if the `export` parameter is `false`.
|
||||
|
||||
`exported`
|
||||
A boolean that returns `true` when a GIF image `URL` is successfully exported to the Photo Library. Otherwise, it returns `false`.
|
||||
*/
|
||||
@objc public func gif(forDuration duration: TimeInterval, export: Bool, _ finished: ((_ status: Bool, _ gifPath: URL, _ permissionStatus: PHAuthorizationStatus, _ exported: Bool) -> Swift.Void)? = nil) {
|
||||
writerQueue.sync {
|
||||
self.isRecordingGIF = true
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
|
||||
self.isRecordingGIF = false
|
||||
let generator: GIFGenerator? = GIFGenerator()
|
||||
generator?.generate(gif: self.gifImages, with: 0.1, loop: 0, adjust: self.adjustGIFForSharing) { ready, path in
|
||||
// FIXME: `path` may be nil
|
||||
if ready {
|
||||
self.gifImages.removeAll()
|
||||
if export {
|
||||
self.export(image: path!) { done, status in
|
||||
finished?(ready, path!, status, done)
|
||||
}
|
||||
} else {
|
||||
finished?(ready, path!, .notDetermined, false)
|
||||
}
|
||||
} else {
|
||||
self.gifImages.removeAll()
|
||||
finished?(ready, path!, .notDetermined, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
///A method that starts or resumes ⏯ recording a video 📹.
|
||||
@objc public func record() {
|
||||
writerQueue.sync {
|
||||
if self.enableAudio && micStatus == .unknown {
|
||||
self.requestMicrophonePermission { _ in
|
||||
self.isRecording = true
|
||||
self.status = .recording
|
||||
}
|
||||
} else {
|
||||
self.isRecording = true
|
||||
self.status = .recording
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that starts recording a video 📹 with a specified duration ⏳ in seconds.
|
||||
|
||||
In order to stop the recording before the specified duration, simply call `stop()` or `stopAndExport()` methods.
|
||||
|
||||
- WARNING: You CAN NOT `pause()` video recording when a duration is specified.
|
||||
- parameter duration: A `TimeInterval` object that can be set to the duration specified in seconds.
|
||||
- parameter finished: A block that will be called when the specified `duration` has ended.
|
||||
|
||||
The block returns the following parameter:
|
||||
|
||||
`videoPath`
|
||||
A `URL` object that contains the local file path of the video to allow manual exporting or preview of the video.
|
||||
*/
|
||||
@objc public func record(forDuration duration: TimeInterval, _ finished: ((_ videoPath: URL) -> Swift.Void)? = nil) {
|
||||
writerQueue.sync {
|
||||
if self.enableAudio && micStatus == .unknown {
|
||||
self.requestMicrophonePermission { _ in
|
||||
self.recordingWithLimit = true
|
||||
self.isRecording = true
|
||||
self.status = .recording
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
|
||||
self.stop { path in
|
||||
finished?(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.recordingWithLimit = true
|
||||
self.isRecording = true
|
||||
self.status = .recording
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
|
||||
self.stop { path in
|
||||
finished?(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that pauses recording a video ⏸📹.
|
||||
|
||||
In order to resume recording, simply call the `record()` method.
|
||||
*/
|
||||
@objc public func pause() {
|
||||
if !recordingWithLimit {
|
||||
onlyRenderWhileRec = false
|
||||
isRecording = false
|
||||
adjustPausedTime = true
|
||||
} else {
|
||||
logAR.message("NOT PERMITTED: The [ pause() ] method CAN NOT be used while using [ record(forDuration duration: TimeInterval) ]")
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that stops ⏹ recording a video 📹 and exports it to the Photo Library 📲💾.
|
||||
|
||||
- parameter finished: A block that will be called when the export process is complete.
|
||||
|
||||
The block returns the following parameters:
|
||||
|
||||
`videoPath`
|
||||
A `URL` object that contains the local file path of the video to allow manual exporting or preview of the video.
|
||||
|
||||
`permissionStatus`
|
||||
A `PHAuthorizationStatus` object that returns the current application's status for exporting media to the Photo Library.
|
||||
|
||||
`exported`
|
||||
A boolean that returns `true` when a video is successfully exported to the Photo Library. Otherwise, it returns `false`.
|
||||
*/
|
||||
@objc public func stopAndExport(_ finished: ((_ videoPath: URL, _ permissionStatus: PHAuthorizationStatus, _ exported: Bool) -> Swift.Void)? = nil) {
|
||||
writerQueue.sync {
|
||||
self.isRecording = false
|
||||
self.adjustPausedTime = false
|
||||
self.backFromPause = false
|
||||
self.recordingWithLimit = false
|
||||
|
||||
self.pausedFrameTime = nil
|
||||
self.resumeFrameTime = nil
|
||||
|
||||
self.writer?.end {
|
||||
if let path = self.currentVideoPath {
|
||||
self.export(video: path) { exported, status in
|
||||
finished?(path, status, exported)
|
||||
}
|
||||
self.delegate?.recorder(didEndRecording: path, with: true)
|
||||
self.status = .readyToRecord
|
||||
} else {
|
||||
finished?(self.currentVideoPath!, .notDetermined, false)
|
||||
self.status = .readyToRecord
|
||||
self.delegate?.recorder(didFailRecording: errSecDecode as? Error, and: "An error occured while stopping your video.")
|
||||
}
|
||||
self.writer = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that stops ⏹ recording a video 📹 and returns the video path in the completion handler.
|
||||
|
||||
- parameter finished: A block that will be called when the specified `duration` has ended.
|
||||
|
||||
The block returns the following parameter:
|
||||
|
||||
`videoPath`
|
||||
A `URL` object that contains the local file path of the video to allow manual exporting or preview of the video.
|
||||
*/
|
||||
@objc public func stop(_ finished:((_ videoPath: URL) -> Swift.Void)? = nil) {
|
||||
writerQueue.sync {
|
||||
isRecording = false
|
||||
adjustPausedTime = false
|
||||
backFromPause = false
|
||||
recordingWithLimit = false
|
||||
|
||||
pausedFrameTime = nil
|
||||
resumeFrameTime = nil
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.writer?.end {
|
||||
if let path = self.currentVideoPath {
|
||||
finished?(path)
|
||||
self.delegate?.recorder(didEndRecording: path, with: true)
|
||||
self.status = .readyToRecord
|
||||
} else {
|
||||
self.status = .readyToRecord
|
||||
self.delegate?.recorder(didFailRecording: errSecDecode as? Error, and: "An error occured while stopping your video.")
|
||||
}
|
||||
self.writer = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that exports a video 📹 file path to the Photo Library 📲💾.
|
||||
|
||||
- parameter path: A `URL` object that can be set to a local video file path to export to the Photo Library.
|
||||
|
||||
- parameter finished: A block that will be called when the export process is complete.
|
||||
|
||||
The block returns the following parameters:
|
||||
|
||||
`exported`
|
||||
A boolean that returns `true` when a video is successfully exported to the Photo Library. Otherwise, it returns `false`.
|
||||
|
||||
`permissionStatus`
|
||||
A `PHAuthorizationStatus` object that returns the current application's status for exporting media to the Photo Library.
|
||||
*/
|
||||
@objc public func export(video path: URL, _ finished: ((_ exported: Bool, _ permissionStatus: PHAuthorizationStatus) -> Void)? = nil) {
|
||||
audioSessionQueue.async {
|
||||
let status = PHPhotoLibrary.authorizationStatus()
|
||||
if status == .notDetermined {
|
||||
PHPhotoLibrary.requestAuthorization() { status in
|
||||
// Recursive call after authorization request
|
||||
self.export(video: path, finished)
|
||||
}
|
||||
} else if status == .authorized {
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: path)
|
||||
}) { saved, error in
|
||||
if saved && self.deleteCacheWhenExported {
|
||||
logAR.remove(from: path)
|
||||
}
|
||||
finished?(saved, status)
|
||||
}
|
||||
} else if status == .denied || status == .restricted {
|
||||
finished?(false, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that exports any image 🌄/🎆 (including gif, jpeg, and png) to the Photo Library 📲💾.
|
||||
|
||||
- parameter path: A `URL` object that can be set to a local image file path to export to the Photo Library.
|
||||
- parameter UIImage: A `UIImage` object.
|
||||
- parameter finished: A block that will be called when the export process is complete.
|
||||
|
||||
The block returns the following parameters:
|
||||
|
||||
`exported`
|
||||
A boolean that returns `true` when an image is successfully exported to the Photo Library. Otherwise, it returns `false`.
|
||||
|
||||
`permissionStatus`
|
||||
A `PHAuthorizationStatus` object that returns the current application's status for exporting media to the Photo Library.
|
||||
*/
|
||||
@objc public func export(image path: URL? = nil, UIImage: UIImage? = nil, _ finished: ((_ exported: Bool, _ permissionStatus: PHAuthorizationStatus) -> Void)? = nil) {
|
||||
let status = PHPhotoLibrary.authorizationStatus()
|
||||
if status == .notDetermined {
|
||||
PHPhotoLibrary.requestAuthorization() { status in
|
||||
// Recursive call after authorization request
|
||||
self.export(image: path, UIImage: UIImage, finished)
|
||||
}
|
||||
} else if status == .authorized {
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
if let path = path {
|
||||
PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: path)
|
||||
} else if let image = UIImage {
|
||||
PHAssetChangeRequest.creationRequestForAsset(from: image)
|
||||
}
|
||||
}) { saved, error in
|
||||
if saved && self.deleteCacheWhenExported {
|
||||
if let path = path {
|
||||
logAR.remove(from: path)
|
||||
}
|
||||
}
|
||||
finished?(saved, status)
|
||||
}
|
||||
} else if status == .denied || status == .restricted {
|
||||
finished?(false, status)
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that exports a `PHLivePhotoPlus` 🎇 object to the Photo Library 📲💾.
|
||||
|
||||
- parameter photo: A `PHLivePhotoPlus` object that can be set to the returned `PHLivePhotoPlus` object in the `livePhoto(export: Bool, _ finished:{})` method.
|
||||
|
||||
- parameter finished: A block that will be called when the export process is complete.
|
||||
|
||||
The block returns the following parameters:
|
||||
|
||||
`exported`
|
||||
A boolean that returns `true` when the Live Photo is successfully exported to the Photo Library. Otherwise, it returns `false`.
|
||||
|
||||
`permissionStatus`
|
||||
A `PHAuthorizationStatus` object that returns the current application's status for exporting media to the Photo Library.
|
||||
*/
|
||||
@objc public func export(live photo: PHLivePhotoPlus, _ finished: ((_ exported: Bool, _ permissionStatus: PHAuthorizationStatus) -> Void)? = nil) {
|
||||
guard let keyPhotoPath = photo.keyPhotoPath else {
|
||||
logAR.message("An error occurred while exporting a live photo")
|
||||
return
|
||||
}
|
||||
guard let videoPath = photo.pairedVideoPath else {
|
||||
logAR.message("An error occurred while exporting a live photo")
|
||||
return
|
||||
}
|
||||
|
||||
let status = PHPhotoLibrary.authorizationStatus()
|
||||
if status == .notDetermined {
|
||||
PHPhotoLibrary.requestAuthorization() { status in
|
||||
// Recursive call after authorization request
|
||||
self.export(live: photo, finished)
|
||||
}
|
||||
} else if status == .authorized {
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
let request = PHAssetCreationRequest.forAsset()
|
||||
let options = PHAssetResourceCreationOptions()
|
||||
request.addResource(with: .photo, fileURL: keyPhotoPath, options: options)
|
||||
request.addResource(with: .pairedVideo, fileURL: videoPath, options: options)
|
||||
}) { saved, error in
|
||||
if saved {
|
||||
if self.deleteCacheWhenExported {
|
||||
logAR.remove(from: keyPhotoPath)
|
||||
logAR.remove(from: videoPath)
|
||||
}
|
||||
self.fileCount = 0
|
||||
} else {
|
||||
logAR.message("An error occurred while exporting a live photo: \(error!)")
|
||||
}
|
||||
finished?(saved, status)
|
||||
}
|
||||
} else if status == .denied || status == .restricted {
|
||||
finished?(false, status)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A method that requsts microphone 🎙 permission manually, if micPermission is set to `manual`.
|
||||
- parameter finished: A block that will be called when the audio permission is requested.
|
||||
|
||||
The block returns the following parameter:
|
||||
|
||||
`status`
|
||||
A boolean that returns `true` when a the Microphone access is permitted. Otherwise, it returns `false`.
|
||||
*/
|
||||
@objc public func requestMicrophonePermission(_ finished: ((_ status: Bool) -> Swift.Void)? = nil) {
|
||||
AVAudioSession.sharedInstance().requestRecordPermission({ permitted in
|
||||
finished?(permitted)
|
||||
if permitted {
|
||||
self.micStatus = .enabled
|
||||
} else {
|
||||
self.micStatus = .disabled
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Public methods for setting up UIViewController orientations
|
||||
@available(iOS 11.0, *)
|
||||
@objc public extension RecordAR {
|
||||
/**
|
||||
A method that prepares the video recorder with `ARConfiguration` 📝.
|
||||
|
||||
Recommended to use in the `UIViewController`'s method `func viewWillAppear(_ animated: Bool)`
|
||||
- parameter configuration: An object that defines motion and scene tracking behaviors for the session.
|
||||
*/
|
||||
@objc public func prepare(_ configuration: ARConfiguration? = nil) {
|
||||
ARcontentMode = contentMode
|
||||
onlyRenderWhileRec = onlyRenderWhileRecording
|
||||
if let view = view as? ARSCNView {
|
||||
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
|
||||
ViewAR.orientation = .portrait
|
||||
|
||||
//try resetting anchors for the initial landscape orientation issue.
|
||||
guard let config = configuration else { return }
|
||||
view.session.run(config)
|
||||
} else if let view = view as? ARSKView {
|
||||
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
|
||||
ViewAR.orientation = .portrait
|
||||
guard let config = configuration else { return }
|
||||
view.session.run(config)
|
||||
} else if let _ = view as? SCNView {
|
||||
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
|
||||
ViewAR.orientation = .portrait
|
||||
}
|
||||
}
|
||||
/**
|
||||
A method that switches off the orientation lock used in a `UIViewController` with AR scenes 📐😴.
|
||||
|
||||
Recommended to use in the `UIViewController`'s method `func viewWillDisappear(_ animated: Bool)`.
|
||||
*/
|
||||
@objc public func rest() {
|
||||
ViewAR.orientation = UIInterfaceOrientationMask(ViewAR.orientations)
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - AR Video Frames Rendering
|
||||
@available(iOS 11.0, *)
|
||||
extension RecordAR {
|
||||
@objc func renderFrame() {
|
||||
//frame rendering
|
||||
if self.onlyRenderWhileRec && !isRecording && !isRecordingGIF { return }
|
||||
|
||||
guard let buffer = renderer.buffer else { return }
|
||||
guard let rawBuffer = renderer.rawBuffer else {
|
||||
logAR.message("ERROR:- An error occurred while rendering the camera's main buffers.")
|
||||
return
|
||||
}
|
||||
guard let size = renderer.bufferSize else {
|
||||
logAR.message("ERROR:- An error occurred while rendering the camera buffer.")
|
||||
return
|
||||
}
|
||||
renderer.ARcontentMode = contentMode
|
||||
|
||||
self.writerQueue.sync {
|
||||
var time: CMTime { return CMTimeMakeWithSeconds(renderer.time, 1000000) }
|
||||
|
||||
self.renderAR?.frame(didRender: buffer, with: time, using: rawBuffer)
|
||||
|
||||
//gif images writing
|
||||
if self.isRecordingGIF {
|
||||
self.gifWriterQueue.sync {
|
||||
self.gifImages.append(self.imageFromBuffer(buffer: buffer))
|
||||
}
|
||||
}
|
||||
|
||||
//frame writing
|
||||
if self.isRecording {
|
||||
if let frameWriter = self.writer {
|
||||
var finalFrameTime: CMTime?
|
||||
if self.backFromPause {
|
||||
if self.resumeFrameTime == nil {
|
||||
self.resumeFrameTime = time
|
||||
}
|
||||
//Formula: (currentTime - (timeWhenResume - timeWhenPaused))
|
||||
guard let resumeTime = self.resumeFrameTime,
|
||||
let pausedTime = self.pausedFrameTime else { return }
|
||||
finalFrameTime = self.adjustTime(current: time, resume: resumeTime, pause: pausedTime)
|
||||
} else {
|
||||
finalFrameTime = time
|
||||
}
|
||||
|
||||
frameWriter.insert(pixel: buffer, with: finalFrameTime!)
|
||||
|
||||
guard let isWriting = frameWriter.isWritingWithoutError else { return }
|
||||
if !isWriting {
|
||||
self.isRecording = false
|
||||
|
||||
self.status = .readyToRecord
|
||||
self.delegate?.recorder(didFailRecording: errSecDecode as? Error, and: "An error occured while recording your video.")
|
||||
self.delegate?.recorder(didEndRecording: self.currentVideoPath!, with: false)
|
||||
}
|
||||
} else {
|
||||
self.currentVideoPath = self.newVideoPath
|
||||
|
||||
self.writer = WritAR(output: self.currentVideoPath!, width: Int(size.width), height: Int(size.height), adjustForSharing: self.adjustVideoForSharing, audioEnabled: self.enableAudio, orientaions: self.inputViewOrientations, queue: self.writerQueue, allowMix: self.enableMixWithOthers)
|
||||
self.writer?.videoInputOrientation = self.videoOrientation
|
||||
self.writer?.delegate = self.delegate
|
||||
}
|
||||
} else if !self.isRecording && self.adjustPausedTime {
|
||||
writer?.pause()
|
||||
|
||||
self.adjustPausedTime = false
|
||||
|
||||
if self.pausedFrameTime != nil {
|
||||
self.pausedFrameTime = self.adjustTime(current: time, resume: self.resumeFrameTime!, pause: self.pausedFrameTime!)
|
||||
} else {
|
||||
self.pausedFrameTime = time
|
||||
}
|
||||
|
||||
self.backFromPause = true
|
||||
self.resumeFrameTime = nil
|
||||
|
||||
self.status = .paused
|
||||
self.onlyRenderWhileRec = onlyRenderWhileRecording
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// prepare.swift
|
||||
// AR Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 10/16/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import ARKit
|
||||
/**
|
||||
A struct that identifies the application `UIViewController`s and their orientations.
|
||||
|
||||
- Author: Ahmed Fathi Bekhit
|
||||
* [Github](http://github.com/AFathi)
|
||||
* [Website](http://ahmedbekhit.com)
|
||||
* [Twitter](http://twitter.com/iAFapps)
|
||||
* [Email](mailto:me@ahmedbekhit.com)
|
||||
*/
|
||||
@available(iOS 11.0, *)
|
||||
@objc public class ViewAR: NSObject {
|
||||
/**
|
||||
A `UIInterfaceOrientationMask` object that returns the recommended orientations for a `UIViewController` with AR scenes.
|
||||
|
||||
Recommended to return in the application delegate method `func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask`.
|
||||
*/
|
||||
@objc internal(set) public static var orientation: UIInterfaceOrientationMask {
|
||||
get { return mask }
|
||||
set { mask = newValue }
|
||||
}
|
||||
|
||||
static var orientations: [UIInterfaceOrientationMask] {
|
||||
var all:[UIInterfaceOrientationMask] = []
|
||||
if let info = Bundle.main.infoDictionary {
|
||||
if let supportedOrientaions = info["UISupportedInterfaceOrientations"] as? NSArray {
|
||||
for orientation in supportedOrientaions {
|
||||
if let o = orientation as? String {
|
||||
if o == "UIInterfaceOrientationPortrait" {
|
||||
all.append(.portrait)
|
||||
} else if o == "UIInterfaceOrientationPortraitUpsideDown" {
|
||||
all.append(.portraitUpsideDown)
|
||||
} else if o == "UIInterfaceOrientationLandscapeLeft" {
|
||||
all.append(.landscapeLeft)
|
||||
} else if o == "UIInterfaceOrientationLandscapeRight" {
|
||||
all.append(.landscapeRight)
|
||||
}
|
||||
}
|
||||
}
|
||||
return all
|
||||
}
|
||||
}
|
||||
return all
|
||||
}
|
||||
//returns the application's delegate to check if the current UIViewController contains an ARView
|
||||
private static var delegate = UIApplication.shared.delegate
|
||||
//variable for the setter in `mask`
|
||||
private static var m: UIInterfaceOrientationMask = .portrait
|
||||
//returns the most appropriate orientation based on the content of the UIViewController.
|
||||
private static var mask: UIInterfaceOrientationMask {
|
||||
get {
|
||||
if let vc = delegate?.window??.inputViewController {
|
||||
if vc.hasARView {
|
||||
return .portrait
|
||||
} else {
|
||||
return UIInterfaceOrientationMask(orientations)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
set { m = newValue }
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// ARVideoKitLib.h
|
||||
// ARVideoKitLib
|
||||
//
|
||||
// Created by Ahmed Bekhit on 11/5/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for ARVideoKitLib.
|
||||
FOUNDATION_EXPORT double ARVideoKitLibVersionNumber;
|
||||
|
||||
//! Project version string for ARVideoKitLib.
|
||||
FOUNDATION_EXPORT const unsigned char ARVideoKitLibVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <ARVideoKitLib/PublicHeader.h>
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?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>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,489 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 48;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
FB36BD412008166700002808 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FB36BD402008166700002808 /* AppDelegate.m */; };
|
||||
FB36BD432008166700002808 /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = FB36BD422008166700002808 /* art.scnassets */; };
|
||||
FB36BD462008166700002808 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB36BD452008166700002808 /* MainViewController.m */; };
|
||||
FB36BD492008166700002808 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FB36BD472008166700002808 /* Main.storyboard */; };
|
||||
FB36BD4B2008166700002808 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FB36BD4A2008166700002808 /* Assets.xcassets */; };
|
||||
FB36BD4E2008166700002808 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FB36BD4C2008166700002808 /* LaunchScreen.storyboard */; };
|
||||
FB36BD512008166700002808 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FB36BD502008166700002808 /* main.m */; };
|
||||
FB36BD66200849AA00002808 /* SCNViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB36BD65200849A900002808 /* SCNViewController.m */; };
|
||||
FB36BD69200856A800002808 /* SKViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB36BD68200856A800002808 /* SKViewController.m */; };
|
||||
FB36BD9420085C7B00002808 /* Scene.m in Sources */ = {isa = PBXBuildFile; fileRef = FB36BD9120085C7B00002808 /* Scene.m */; };
|
||||
FB36BD9520085C7B00002808 /* Scene.sks in Resources */ = {isa = PBXBuildFile; fileRef = FB36BD9320085C7B00002808 /* Scene.sks */; };
|
||||
FB36BD98200869D200002808 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = FB36BD97200869D200002808 /* LICENSE */; };
|
||||
FBE12A5320093EF800B0BB61 /* ARVideoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB36BD9E20086A0B00002808 /* ARVideoKit.framework */; };
|
||||
FBE12A5420093EF800B0BB61 /* ARVideoKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FB36BD9E20086A0B00002808 /* ARVideoKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
FB36BD9D20086A0B00002808 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = FB36BD9920086A0A00002808 /* ARVideoKit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = FBD604DA1FA969DD00EC9804;
|
||||
remoteInfo = ARVideoKit;
|
||||
};
|
||||
FBE12A5520093EF800B0BB61 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = FB36BD9920086A0A00002808 /* ARVideoKit.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = FBD604D91FA969DD00EC9804;
|
||||
remoteInfo = ARVideoKit;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
FBE12A5720093EF800B0BB61 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
FBE12A5420093EF800B0BB61 /* ARVideoKit.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
FB36BD3C2008166700002808 /* ARKit-Video.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ARKit-Video.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FB36BD3F2008166700002808 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
FB36BD402008166700002808 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
FB36BD422008166700002808 /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = "<group>"; };
|
||||
FB36BD442008166700002808 /* MainViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
|
||||
FB36BD452008166700002808 /* MainViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
|
||||
FB36BD482008166700002808 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
FB36BD4A2008166700002808 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
FB36BD4D2008166700002808 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
FB36BD4F2008166700002808 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FB36BD502008166700002808 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
FB36BD64200849A900002808 /* SCNViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCNViewController.h; sourceTree = "<group>"; };
|
||||
FB36BD65200849A900002808 /* SCNViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCNViewController.m; sourceTree = "<group>"; };
|
||||
FB36BD67200856A800002808 /* SKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SKViewController.h; sourceTree = "<group>"; };
|
||||
FB36BD68200856A800002808 /* SKViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SKViewController.m; sourceTree = "<group>"; };
|
||||
FB36BD9120085C7B00002808 /* Scene.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Scene.m; sourceTree = "<group>"; };
|
||||
FB36BD9220085C7B00002808 /* Scene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Scene.h; sourceTree = "<group>"; };
|
||||
FB36BD9320085C7B00002808 /* Scene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Scene.sks; sourceTree = "<group>"; };
|
||||
FB36BD97200869D200002808 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
FB36BD9920086A0A00002808 /* ARVideoKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ARVideoKit.xcodeproj; path = ../../ARVideoKit.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
FB36BD392008166700002808 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBE12A5320093EF800B0BB61 /* ARVideoKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
FB36BD332008166700002808 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD97200869D200002808 /* LICENSE */,
|
||||
FB36BD9920086A0A00002808 /* ARVideoKit.xcodeproj */,
|
||||
FB36BD3E2008166700002808 /* ARKit-Video */,
|
||||
FB36BD3D2008166700002808 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BD3D2008166700002808 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD3C2008166700002808 /* ARKit-Video.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BD3E2008166700002808 /* ARKit-Video */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD3F2008166700002808 /* AppDelegate.h */,
|
||||
FB36BD402008166700002808 /* AppDelegate.m */,
|
||||
FB36BDA320086A8C00002808 /* View Controllers */,
|
||||
FB36BDA520086ACB00002808 /* Storyboards */,
|
||||
FB36BDA620086AF100002808 /* Assets */,
|
||||
FB36BD4F2008166700002808 /* Info.plist */,
|
||||
FB36BD502008166700002808 /* main.m */,
|
||||
);
|
||||
path = "ARKit-Video";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BD9A20086A0A00002808 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD9E20086A0B00002808 /* ARVideoKit.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA320086A8C00002808 /* View Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BDA420086AA300002808 /* Headers */,
|
||||
FB36BD452008166700002808 /* MainViewController.m */,
|
||||
FB36BD68200856A800002808 /* SKViewController.m */,
|
||||
FB36BD65200849A900002808 /* SCNViewController.m */,
|
||||
);
|
||||
path = "View Controllers";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA420086AA300002808 /* Headers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD442008166700002808 /* MainViewController.h */,
|
||||
FB36BD67200856A800002808 /* SKViewController.h */,
|
||||
FB36BD64200849A900002808 /* SCNViewController.h */,
|
||||
);
|
||||
path = Headers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA520086ACB00002808 /* Storyboards */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD472008166700002808 /* Main.storyboard */,
|
||||
FB36BD4C2008166700002808 /* LaunchScreen.storyboard */,
|
||||
);
|
||||
path = Storyboards;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA620086AF100002808 /* Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BDA720086B0600002808 /* AR Assets */,
|
||||
FB36BD4A2008166700002808 /* Assets.xcassets */,
|
||||
);
|
||||
path = Assets;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA720086B0600002808 /* AR Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BDA820086B1300002808 /* SCN */,
|
||||
FB36BDA920086B1800002808 /* SK */,
|
||||
);
|
||||
path = "AR Assets";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA820086B1300002808 /* SCN */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD422008166700002808 /* art.scnassets */,
|
||||
);
|
||||
path = SCN;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BDA920086B1800002808 /* SK */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB36BD9220085C7B00002808 /* Scene.h */,
|
||||
FB36BD9120085C7B00002808 /* Scene.m */,
|
||||
FB36BD9320085C7B00002808 /* Scene.sks */,
|
||||
);
|
||||
path = SK;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
FB36BD3B2008166700002808 /* ARKit-Video */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = FB36BD542008166700002808 /* Build configuration list for PBXNativeTarget "ARKit-Video" */;
|
||||
buildPhases = (
|
||||
FB36BD382008166700002808 /* Sources */,
|
||||
FB36BD392008166700002808 /* Frameworks */,
|
||||
FB36BD3A2008166700002808 /* Resources */,
|
||||
FBE12A5720093EF800B0BB61 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
FBE12A5620093EF800B0BB61 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "ARKit-Video";
|
||||
productName = "ARKit-Video";
|
||||
productReference = FB36BD3C2008166700002808 /* ARKit-Video.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
FB36BD342008166700002808 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0920;
|
||||
ORGANIZATIONNAME = "Ahmed Fathi Bekhit";
|
||||
TargetAttributes = {
|
||||
FB36BD3B2008166700002808 = {
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = FB36BD372008166700002808 /* Build configuration list for PBXProject "ARKit-Video" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = FB36BD332008166700002808;
|
||||
productRefGroup = FB36BD3D2008166700002808 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = FB36BD9A20086A0A00002808 /* Products */;
|
||||
ProjectRef = FB36BD9920086A0A00002808 /* ARVideoKit.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
FB36BD3B2008166700002808 /* ARKit-Video */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
FB36BD9E20086A0B00002808 /* ARVideoKit.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = ARVideoKit.framework;
|
||||
remoteRef = FB36BD9D20086A0B00002808 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
FB36BD3A2008166700002808 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FB36BD98200869D200002808 /* LICENSE in Resources */,
|
||||
FB36BD432008166700002808 /* art.scnassets in Resources */,
|
||||
FB36BD4E2008166700002808 /* LaunchScreen.storyboard in Resources */,
|
||||
FB36BD4B2008166700002808 /* Assets.xcassets in Resources */,
|
||||
FB36BD492008166700002808 /* Main.storyboard in Resources */,
|
||||
FB36BD9520085C7B00002808 /* Scene.sks in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
FB36BD382008166700002808 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FB36BD9420085C7B00002808 /* Scene.m in Sources */,
|
||||
FB36BD462008166700002808 /* MainViewController.m in Sources */,
|
||||
FB36BD66200849AA00002808 /* SCNViewController.m in Sources */,
|
||||
FB36BD512008166700002808 /* main.m in Sources */,
|
||||
FB36BD69200856A800002808 /* SKViewController.m in Sources */,
|
||||
FB36BD412008166700002808 /* AppDelegate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
FBE12A5620093EF800B0BB61 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = ARVideoKit;
|
||||
targetProxy = FBE12A5520093EF800B0BB61 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
FB36BD472008166700002808 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
FB36BD482008166700002808 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB36BD4C2008166700002808 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
FB36BD4D2008166700002808 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
FB36BD522008166700002808 /* 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_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = 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_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;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
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 = 11.2;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FB36BD532008166700002808 /* 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_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = 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_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;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
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 = 11.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
FB36BD552008166700002808 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = P5DZ3XQ9FJ;
|
||||
INFOPLIST_FILE = "ARKit-Video/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ahmedbekhit.ARKit-Video";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FB36BD562008166700002808 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = P5DZ3XQ9FJ;
|
||||
INFOPLIST_FILE = "ARKit-Video/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ahmedbekhit.ARKit-Video";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
FB36BD372008166700002808 /* Build configuration list for PBXProject "ARKit-Video" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FB36BD522008166700002808 /* Debug */,
|
||||
FB36BD532008166700002808 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
FB36BD542008166700002808 /* Build configuration list for PBXNativeTarget "ARKit-Video" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FB36BD552008166700002808 /* Debug */,
|
||||
FB36BD562008166700002808 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = FB36BD342008166700002808 /* Project object */;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:ARKit-Video.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
+8
@@ -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,17 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// AppDelegate.m
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
@import ARVideoKit;
|
||||
@interface AppDelegate ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
return ViewAR.orientation;
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
// Override point for customization after application launch.
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
Binary file not shown.
Executable → Regular
|
Before Width: | Height: | Size: 342 KiB After Width: | Height: | Size: 342 KiB |
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Scene.h
|
||||
// sktstobjc
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SpriteKit/SpriteKit.h>
|
||||
#import <ARKit/ARKit.h>
|
||||
|
||||
@interface Scene : SKScene
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Scene.m
|
||||
// sktstobjc
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Scene.h"
|
||||
|
||||
@implementation Scene
|
||||
|
||||
- (void)didMoveToView:(SKView *)view {
|
||||
// Setup your scene here
|
||||
}
|
||||
|
||||
- (void)update:(CFTimeInterval)currentTime {
|
||||
// Called before each frame is rendered
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||
if (![self.view isKindOfClass:[ARSKView class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
ARSKView *sceneView = (ARSKView *)self.view;
|
||||
ARFrame *currentFrame = [sceneView.session currentFrame];
|
||||
|
||||
// Create anchor using the camera's current position
|
||||
if (currentFrame) {
|
||||
|
||||
// Create a transform with a translation of 0.2 meters in front of the camera
|
||||
matrix_float4x4 translation = matrix_identity_float4x4;
|
||||
translation.columns[3].z = -0.2;
|
||||
matrix_float4x4 transform = matrix_multiply(currentFrame.camera.transform, translation);
|
||||
|
||||
// Add a new anchor to the session
|
||||
ARAnchor *anchor = [[ARAnchor alloc] initWithTransform:transform];
|
||||
[sceneView.session addAnchor:anchor];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>AR Camera</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Export AR Media</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Export AR Media</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Audiovisual Recording</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
<string>arkit</string>
|
||||
</array>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<true/>
|
||||
<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,415 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="5Tw-hU-cLK">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
<array key="Avenir.ttc">
|
||||
<string>Avenir-Black</string>
|
||||
<string>Avenir-Medium</string>
|
||||
</array>
|
||||
</customFonts>
|
||||
<scenes>
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="G4X-NB-LNh">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="mainView" useStoryboardIdentifierAsRestorationIdentifier="YES" id="5Tw-hU-cLK" customClass="MainViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="dfd-4C-4Y3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Try" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="a4A-eO-KWv">
|
||||
<rect key="frame" x="8" y="63" width="359" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Black" family="Avenir" pointSize="40"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Framework features on" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oSj-6S-wOA">
|
||||
<rect key="frame" x="8" y="183" width="359" height="42"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="27"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="ARVideoKit" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="opq-Bf-ato">
|
||||
<rect key="frame" x="8" y="131" width="359" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="41"/>
|
||||
<color key="textColor" red="0.97052964239999995" green="0.37927614589999997" blue="0.45678941579999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rcy-rQ-hUD">
|
||||
<rect key="frame" x="8" y="268" width="359" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="18"/>
|
||||
<state key="normal" title=" AR SpriteKit App"/>
|
||||
<connections>
|
||||
<segue destination="MFx-3w-iPW" kind="show" id="DEE-BI-uju"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zcH-hB-KQ7">
|
||||
<rect key="frame" x="8" y="359" width="359" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="18"/>
|
||||
<state key="normal" title=" AR SceneKit App"/>
|
||||
<connections>
|
||||
<segue destination="Cih-XA-BXk" kind="show" id="mQt-lB-xe9"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="QnE-Y2-7D0"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="scnBtn" destination="zcH-hB-KQ7" id="Nvi-gx-DDI"/>
|
||||
<outlet property="skBtn" destination="rcy-rQ-hUD" id="h9G-C9-tCg"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="w72-wG-4VZ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-673" y="110"/>
|
||||
</scene>
|
||||
<!--SCNViewController-->
|
||||
<scene sceneID="Qf0-zk-2sy">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="scnView" title="SCNViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="Cih-XA-BXk" customClass="SCNViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="jV6-Ll-cW5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<arscnView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="V18-46-TOC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
</arscnView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AR w/ SceneKit" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NKa-6R-Myi">
|
||||
<rect key="frame" x="97" y="20" width="181" height="65"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="181" id="1mH-WK-SGf"/>
|
||||
<constraint firstAttribute="height" constant="65" id="Yad-A6-32g"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ok6-HW-RqF">
|
||||
<rect key="frame" x="155" y="582" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="Txu-Gp-54O"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="zGf-sX-RYZ"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Record">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="record:" destination="Cih-XA-BXk" eventType="touchUpInside" id="4eI-ny-INl"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="2" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="L38-Hd-e0N">
|
||||
<rect key="frame" x="294" y="582" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="KK6-r1-gTN"/>
|
||||
<constraint firstAttribute="height" constant="65" id="laE-hT-5ue"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Pause">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="record:" destination="Cih-XA-BXk" eventType="touchUpInside" id="r0N-lV-OyL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2dl-iC-P4r">
|
||||
<rect key="frame" x="155" y="509" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="mUh-Wz-Co0"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="wBp-28-57g"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Photo">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="capture:" destination="Cih-XA-BXk" eventType="touchUpInside" id="VG7-6M-7u1"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9W3-y2-hhu">
|
||||
<rect key="frame" x="16" y="509" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="Ahh-1w-2WR"/>
|
||||
<constraint firstAttribute="height" constant="65" id="KLs-IV-8FO"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Live Photo">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="capture:" destination="Cih-XA-BXk" eventType="touchUpInside" id="Rhn-PO-UXL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="S5S-Se-skL">
|
||||
<rect key="frame" x="16" y="582" width="62" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="TvX-dX-N0M"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="w/Duration">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="record:" destination="Cih-XA-BXk" eventType="touchUpInside" id="2tK-O3-umk"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="K7X-hw-mpg">
|
||||
<rect key="frame" x="294" y="509" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="S4N-Hx-8Eh"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="beo-rR-P6M"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="GIF">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="capture:" destination="Cih-XA-BXk" eventType="touchUpInside" id="hMh-a1-1VO"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Wlg-YJ-9yp">
|
||||
<rect key="frame" x="7" y="20" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="M1n-Ec-Oop"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="Pns-fp-6tL"/>
|
||||
</constraints>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Go Back">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="goBack:" destination="Cih-XA-BXk" eventType="touchUpInside" id="UyT-nS-ObP"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kBm-n4-1Kf" firstAttribute="trailing" secondItem="K7X-hw-mpg" secondAttribute="trailing" constant="16" id="2JW-lh-Ymz"/>
|
||||
<constraint firstItem="kBm-n4-1Kf" firstAttribute="bottom" secondItem="L38-Hd-e0N" secondAttribute="bottom" constant="20" id="3mq-aE-4al"/>
|
||||
<constraint firstItem="Wlg-YJ-9yp" firstAttribute="top" secondItem="kBm-n4-1Kf" secondAttribute="top" id="7Ne-Fp-qj4"/>
|
||||
<constraint firstItem="ok6-HW-RqF" firstAttribute="centerX" secondItem="kBm-n4-1Kf" secondAttribute="centerX" id="9hW-68-APq"/>
|
||||
<constraint firstItem="V18-46-TOC" firstAttribute="centerX" secondItem="kBm-n4-1Kf" secondAttribute="centerX" id="A1P-33-gnM"/>
|
||||
<constraint firstItem="NKa-6R-Myi" firstAttribute="centerX" secondItem="kBm-n4-1Kf" secondAttribute="centerX" id="EMR-99-xbS"/>
|
||||
<constraint firstItem="kBm-n4-1Kf" firstAttribute="bottom" secondItem="S5S-Se-skL" secondAttribute="bottom" constant="20" id="Jdf-p4-gFh"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Wlg-YJ-9yp" secondAttribute="trailing" constant="20" symbolic="YES" id="NTs-hY-duw"/>
|
||||
<constraint firstItem="S5S-Se-skL" firstAttribute="leading" secondItem="kBm-n4-1Kf" secondAttribute="leading" constant="16" id="QvM-wT-2aI"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="S5S-Se-skL" secondAttribute="trailing" constant="20" symbolic="YES" id="RAn-Yc-23k"/>
|
||||
<constraint firstItem="S5S-Se-skL" firstAttribute="bottom" secondItem="9W3-y2-hhu" secondAttribute="bottom" constant="73" id="ScK-7E-gse"/>
|
||||
<constraint firstItem="L38-Hd-e0N" firstAttribute="top" secondItem="K7X-hw-mpg" secondAttribute="bottom" constant="8" id="Voz-ZN-560"/>
|
||||
<constraint firstItem="kBm-n4-1Kf" firstAttribute="bottom" secondItem="ok6-HW-RqF" secondAttribute="bottom" constant="20" id="Y0Z-Eg-jth"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9W3-y2-hhu" secondAttribute="trailing" constant="294" id="YLa-tL-5Sx"/>
|
||||
<constraint firstItem="V18-46-TOC" firstAttribute="centerY" secondItem="kBm-n4-1Kf" secondAttribute="centerY" constant="-10" id="eeK-NZ-8Im"/>
|
||||
<constraint firstItem="Wlg-YJ-9yp" firstAttribute="leading" secondItem="kBm-n4-1Kf" secondAttribute="leading" constant="7" id="fCN-r5-3wG"/>
|
||||
<constraint firstItem="K7X-hw-mpg" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="jV6-Ll-cW5" secondAttribute="leading" constant="20" symbolic="YES" id="fSb-iu-7Hw"/>
|
||||
<constraint firstItem="L38-Hd-e0N" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="jV6-Ll-cW5" secondAttribute="leading" constant="20" symbolic="YES" id="gF4-gV-r6P"/>
|
||||
<constraint firstItem="kBm-n4-1Kf" firstAttribute="trailing" secondItem="L38-Hd-e0N" secondAttribute="trailing" constant="16" id="i0W-xE-Wih"/>
|
||||
<constraint firstItem="V18-46-TOC" firstAttribute="height" secondItem="jV6-Ll-cW5" secondAttribute="height" id="jIv-9h-cOR"/>
|
||||
<constraint firstItem="ok6-HW-RqF" firstAttribute="top" secondItem="2dl-iC-P4r" secondAttribute="bottom" constant="8" id="nL7-cA-MCL"/>
|
||||
<constraint firstItem="2dl-iC-P4r" firstAttribute="centerX" secondItem="kBm-n4-1Kf" secondAttribute="centerX" id="qRZ-4O-bER"/>
|
||||
<constraint firstItem="NKa-6R-Myi" firstAttribute="top" secondItem="kBm-n4-1Kf" secondAttribute="top" id="rf2-ZT-1rQ"/>
|
||||
<constraint firstItem="V18-46-TOC" firstAttribute="width" secondItem="jV6-Ll-cW5" secondAttribute="width" id="zgt-Up-jYk"/>
|
||||
<constraint firstItem="9W3-y2-hhu" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="kBm-n4-1Kf" secondAttribute="leading" id="zsO-7E-eLm"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="kBm-n4-1Kf"/>
|
||||
</view>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="pauseBtn" destination="L38-Hd-e0N" id="g7X-jO-OA3"/>
|
||||
<outlet property="recordBtn" destination="ok6-HW-RqF" id="kHc-Ob-t1Y"/>
|
||||
<outlet property="sceneView" destination="V18-46-TOC" id="gdM-qw-yKt"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="oN2-K2-5Pc" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="239" y="475"/>
|
||||
</scene>
|
||||
<!--SKViewController-->
|
||||
<scene sceneID="wjP-uZ-EDG">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="skView" title="SKViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="MFx-3w-iPW" customClass="SKViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="9BO-rB-mQd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<arskView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="REd-N3-EKf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
</arskView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AR w/ SpriteKit" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fC9-ym-jNF">
|
||||
<rect key="frame" x="97" y="20" width="181" height="65"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="181" id="UQn-Cj-Kgi"/>
|
||||
<constraint firstAttribute="height" constant="65" id="lfy-VF-HAn"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6cl-LN-KA5">
|
||||
<rect key="frame" x="155" y="582" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="VtZ-uQ-JgT"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="rSq-zK-9h0"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Record">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="record:" destination="MFx-3w-iPW" eventType="touchUpInside" id="7LA-az-7gK"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="2" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="42G-QZ-aKy">
|
||||
<rect key="frame" x="294" y="582" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="5xd-4J-QqI"/>
|
||||
<constraint firstAttribute="height" constant="65" id="cX7-N3-CEx"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Pause">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="record:" destination="MFx-3w-iPW" eventType="touchUpInside" id="Ajb-CJ-BMF"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Y1d-do-DoB">
|
||||
<rect key="frame" x="155" y="509" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="IuC-Q5-gfg"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="Tbz-1b-zrt"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Photo">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="capture:" destination="MFx-3w-iPW" eventType="touchUpInside" id="TZs-eb-by6"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZDF-6V-l6t">
|
||||
<rect key="frame" x="16" y="509" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="Bns-dt-SQr"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="jTj-3c-f6G"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Live Photo">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="capture:" destination="MFx-3w-iPW" eventType="touchUpInside" id="qiP-M0-Sn4"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="J5S-AD-x53">
|
||||
<rect key="frame" x="16" y="582" width="62" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="62" id="SLo-0k-nRI"/>
|
||||
<constraint firstAttribute="height" constant="65" id="pRA-NP-sHp"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="w/Duration">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="record:" destination="MFx-3w-iPW" eventType="touchUpInside" id="Y1m-a1-GIl"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wup-WD-B8R">
|
||||
<rect key="frame" x="294" y="509" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="63f-Hj-ihZ"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="Mh5-5M-88i"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="GIF">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="capture:" destination="MFx-3w-iPW" eventType="touchUpInside" id="m77-Pm-OLU"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="16F-pv-Bzd">
|
||||
<rect key="frame" x="16" y="20" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="8bV-TJ-klG"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="xdg-hu-waO"/>
|
||||
</constraints>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Go Back">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="goBack:" destination="MFx-3w-iPW" eventType="touchUpInside" id="jq8-ZR-Wfq"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="16F-pv-Bzd" firstAttribute="leading" secondItem="NJB-VU-MXs" secondAttribute="leading" constant="16" id="1hD-g9-eVI"/>
|
||||
<constraint firstItem="42G-QZ-aKy" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="9BO-rB-mQd" secondAttribute="leading" constant="20" symbolic="YES" id="2lB-V6-P4S"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="16F-pv-Bzd" secondAttribute="trailing" constant="20" symbolic="YES" id="2xl-N5-97A"/>
|
||||
<constraint firstItem="16F-pv-Bzd" firstAttribute="top" secondItem="NJB-VU-MXs" secondAttribute="top" id="545-NG-8SR"/>
|
||||
<constraint firstItem="6cl-LN-KA5" firstAttribute="centerX" secondItem="NJB-VU-MXs" secondAttribute="centerX" id="Cha-js-1Ov"/>
|
||||
<constraint firstItem="Y1d-do-DoB" firstAttribute="centerX" secondItem="NJB-VU-MXs" secondAttribute="centerX" id="Edx-OC-cNa"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="J5S-AD-x53" secondAttribute="trailing" constant="20" symbolic="YES" id="FZ4-QA-Zix"/>
|
||||
<constraint firstItem="fC9-ym-jNF" firstAttribute="top" secondItem="NJB-VU-MXs" secondAttribute="top" id="Jkj-LD-plm"/>
|
||||
<constraint firstItem="J5S-AD-x53" firstAttribute="top" secondItem="ZDF-6V-l6t" secondAttribute="bottom" constant="8" id="Jmt-qx-1FD"/>
|
||||
<constraint firstItem="NJB-VU-MXs" firstAttribute="trailing" secondItem="42G-QZ-aKy" secondAttribute="trailing" constant="16" id="KZz-FM-WfY"/>
|
||||
<constraint firstItem="wup-WD-B8R" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="9BO-rB-mQd" secondAttribute="leading" constant="20" symbolic="YES" id="TgR-LM-BLA"/>
|
||||
<constraint firstItem="6cl-LN-KA5" firstAttribute="top" secondItem="Y1d-do-DoB" secondAttribute="bottom" constant="8" id="Wlg-5O-j7P"/>
|
||||
<constraint firstItem="ZDF-6V-l6t" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="NJB-VU-MXs" secondAttribute="leading" id="Zuj-yy-cpS"/>
|
||||
<constraint firstItem="42G-QZ-aKy" firstAttribute="top" secondItem="wup-WD-B8R" secondAttribute="bottom" constant="8" id="bWZ-E5-KS1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ZDF-6V-l6t" secondAttribute="trailing" constant="294" id="cXz-M5-0bw"/>
|
||||
<constraint firstItem="NJB-VU-MXs" firstAttribute="bottom" secondItem="J5S-AD-x53" secondAttribute="bottom" constant="20" id="icN-gq-Q39"/>
|
||||
<constraint firstItem="fC9-ym-jNF" firstAttribute="centerX" secondItem="NJB-VU-MXs" secondAttribute="centerX" id="j2I-zq-coE"/>
|
||||
<constraint firstItem="REd-N3-EKf" firstAttribute="centerX" secondItem="NJB-VU-MXs" secondAttribute="centerX" id="oAe-UH-PDj"/>
|
||||
<constraint firstItem="NJB-VU-MXs" firstAttribute="bottom" secondItem="42G-QZ-aKy" secondAttribute="bottom" constant="20" id="peT-5F-FCD"/>
|
||||
<constraint firstItem="NJB-VU-MXs" firstAttribute="trailing" secondItem="wup-WD-B8R" secondAttribute="trailing" constant="16" id="pnV-vM-xdF"/>
|
||||
<constraint firstItem="REd-N3-EKf" firstAttribute="width" secondItem="9BO-rB-mQd" secondAttribute="width" id="q5Q-fz-ohQ"/>
|
||||
<constraint firstItem="J5S-AD-x53" firstAttribute="leading" secondItem="NJB-VU-MXs" secondAttribute="leading" constant="16" id="rtE-K6-xE7"/>
|
||||
<constraint firstItem="REd-N3-EKf" firstAttribute="height" secondItem="9BO-rB-mQd" secondAttribute="height" id="vug-SR-86C"/>
|
||||
<constraint firstItem="NJB-VU-MXs" firstAttribute="bottom" secondItem="6cl-LN-KA5" secondAttribute="bottom" constant="20" id="xbg-7F-Ke0"/>
|
||||
<constraint firstItem="REd-N3-EKf" firstAttribute="centerY" secondItem="NJB-VU-MXs" secondAttribute="centerY" constant="-10" id="z39-GZ-OmP"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="NJB-VU-MXs"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="SKSceneView" destination="REd-N3-EKf" id="wDF-av-IZs"/>
|
||||
<outlet property="pauseBtn" destination="42G-QZ-aKy" id="zJz-1A-Gkk"/>
|
||||
<outlet property="recordBtn" destination="6cl-LN-KA5" id="MFy-L9-60P"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dsU-YI-aCa" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="239" y="-258"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ViewController.h
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface MainViewController : UIViewController
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// SCNViewController.h
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <SceneKit/SceneKit.h>
|
||||
#import <ARKit/ARKit.h>
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
#import <Photos/Photos.h>
|
||||
@import ARVideoKit;
|
||||
|
||||
@interface SCNViewController : UIViewController
|
||||
@property (weak, nonatomic) IBOutlet UIButton *recordBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *pauseBtn;
|
||||
@property (nonatomic, strong) IBOutlet ARSCNView *sceneView;
|
||||
- (IBAction)capture:(UIButton *)sender;
|
||||
- (IBAction)record:(UIButton *)sender;
|
||||
- (IBAction)goBack:(UIButton *)sender;
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// SKViewController.h
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <SpriteKit/SpriteKit.h>
|
||||
#import <ARKit/ARKit.h>
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
#import <Photos/Photos.h>
|
||||
@import ARVideoKit;
|
||||
|
||||
@interface SKViewController : UIViewController
|
||||
@property (weak, nonatomic) IBOutlet UIButton *recordBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *pauseBtn;
|
||||
@property (nonatomic, strong) IBOutlet ARSKView *SKSceneView;
|
||||
- (IBAction)capture:(UIButton *)sender;
|
||||
- (IBAction)record:(UIButton *)sender;
|
||||
- (IBAction)goBack:(UIButton *)sender;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ViewController.m
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MainViewController.h"
|
||||
|
||||
@interface MainViewController ()
|
||||
@property (weak, nonatomic) IBOutlet UIButton *skBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *scnBtn;
|
||||
@end
|
||||
|
||||
|
||||
@implementation MainViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.skBtn.layer.cornerRadius = self.skBtn.bounds.size.height/2;
|
||||
self.scnBtn.layer.cornerRadius = self.scnBtn.bounds.size.height/2;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// SCNViewController.m
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SCNViewController.h"
|
||||
|
||||
@interface SCNViewController () <ARSCNViewDelegate, RecordARDelegate, RenderARDelegate>
|
||||
{
|
||||
RecordAR *recorder;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SCNViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Set the view's delegate
|
||||
self.sceneView.delegate = self;
|
||||
|
||||
// Show statistics such as fps and timing information
|
||||
self.sceneView.showsStatistics = YES;
|
||||
|
||||
// Create a new scene
|
||||
SCNScene *scene = [SCNScene sceneNamed:@"art.scnassets/ship.scn"];
|
||||
|
||||
// Set the scene to the view
|
||||
self.sceneView.scene = scene;
|
||||
|
||||
// Initialize ARVideoKit recorder
|
||||
recorder = [[RecordAR alloc] initWithARSceneKit:self.sceneView];
|
||||
|
||||
/*----👇---- ARVideoKit Configuration ----👇----*/
|
||||
|
||||
// Set the recorder's delegate
|
||||
recorder.delegate = self;
|
||||
|
||||
// Set the renderer's delegate
|
||||
recorder.renderAR = self;
|
||||
|
||||
// Configure the renderer to perform additional image & video processing 👁
|
||||
recorder.onlyRenderWhileRecording = YES;
|
||||
|
||||
// Configure ARKit content mode. Default is .auto -- aspectFill is recommended for iPhone10-only apps
|
||||
recorder.contentMode = ARFrameModeAuto;
|
||||
|
||||
// Configure RecordAR to store media files in local app directory
|
||||
recorder.deleteCacheWhenExported = NO;
|
||||
|
||||
// Configure the envronment light rendering.
|
||||
recorder.enableAdjustEnvironmentLighting = YES;
|
||||
}
|
||||
|
||||
-(void)viewWillAppear:(BOOL)animated {
|
||||
// Create a session configuration
|
||||
ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
|
||||
|
||||
// Run the view's session
|
||||
[self.sceneView.session runWithConfiguration:configuration];
|
||||
|
||||
// Prepare the recorder with sessions configuration
|
||||
[recorder prepare:configuration];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// Pause the view's session
|
||||
[self.sceneView.session pause];
|
||||
|
||||
if(recorder.status == RecordARStatusRecording) {
|
||||
[recorder stopAndExport:^(NSURL*_Nonnull filePath, PHAuthorizationStatus status, BOOL ready) {
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
NSLog(@"Video Exported Successfully!");
|
||||
}
|
||||
}];
|
||||
}
|
||||
recorder.onlyRenderWhileRecording = YES;
|
||||
|
||||
// Switch off the orientation lock for UIViewControllers with AR Scenes
|
||||
[recorder rest];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
// MARK:- Capture and Record methods
|
||||
- (IBAction)capture:(UIButton *)sender {
|
||||
if (sender.tag == 0) {
|
||||
//Photo
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
UIImage *image = [recorder photo];
|
||||
[recorder exportWithImage:NULL UIImage:image :NULL];
|
||||
}
|
||||
}else if (sender.tag == 1) {
|
||||
//Live Photo
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[recorder livePhotoWithExport:YES :NULL];
|
||||
}
|
||||
}else if (sender.tag == 2) {
|
||||
//GIF
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[recorder gifForDuration:3.0 export:YES :NULL];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)record:(UIButton *)sender {
|
||||
if (sender.tag == 0) {
|
||||
//Record
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[sender setTitle:@"Stop" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = YES;
|
||||
[recorder record];
|
||||
}else if (recorder.status == RecordARStatusRecording) {
|
||||
[sender setTitle:@"Record" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = NO;
|
||||
[recorder stopAndExport:^(NSURL*_Nonnull filePath, PHAuthorizationStatus status, BOOL ready) {
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
NSLog(@"Video Exported Successfully!");
|
||||
}
|
||||
}];
|
||||
}
|
||||
}else if (sender.tag == 1) {
|
||||
//Record with duration
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[sender setTitle:@"Stop" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = NO;
|
||||
self.recordBtn.enabled = NO;
|
||||
[recorder recordForDuration:10 :NULL];
|
||||
}else if (recorder.status == RecordARStatusRecording) {
|
||||
[sender setTitle:@"w/Duration" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = NO;
|
||||
self.recordBtn.enabled = YES;
|
||||
[recorder stopAndExport:^(NSURL*_Nonnull filePath, PHAuthorizationStatus status, BOOL ready) {
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
NSLog(@"Video Exported Successfully!");
|
||||
}
|
||||
}];
|
||||
}
|
||||
}else if (sender.tag == 2) {
|
||||
//Pause
|
||||
if (recorder.status == RecordARStatusPaused) {
|
||||
[sender setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
[recorder record];
|
||||
}else if (recorder.status == RecordARStatusRecording) {
|
||||
[sender setTitle:@"Resume" forState: UIControlStateNormal];
|
||||
[recorder pause];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)goBack:(UIButton *)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:NULL];
|
||||
}
|
||||
|
||||
// MARK:- ARKit protocol methods
|
||||
- (void)session:(ARSession *)session didFailWithError:(NSError *)error {
|
||||
// Present an error message to the user
|
||||
|
||||
}
|
||||
|
||||
- (void)sessionWasInterrupted:(ARSession *)session {
|
||||
// Inform the user that the session has been interrupted, for example, by presenting an overlay
|
||||
|
||||
}
|
||||
|
||||
- (void)sessionInterruptionEnded:(ARSession *)session {
|
||||
// Reset tracking and/or remove existing anchors if consistent tracking is required
|
||||
|
||||
}
|
||||
|
||||
// MARK:- ARVideoKit protocol methods
|
||||
- (void)recorderWithDidEndRecording:(NSURL * _Nonnull)path with:(BOOL)noError {
|
||||
|
||||
}
|
||||
|
||||
- (void)recorderWithDidFailRecording:(NSError * _Nullable)error and:(NSString * _Nonnull)status {
|
||||
|
||||
}
|
||||
|
||||
- (void)recorderWithWillEnterBackground:(enum RecordARStatus)status {
|
||||
|
||||
}
|
||||
|
||||
- (void)frameWithDidRender:(CVPixelBufferRef _Nonnull)buffer with:(CMTime)time using:(CVPixelBufferRef _Nonnull)rawBuffer {
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// SKViewController.m
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SKViewController.h"
|
||||
#import "Scene.h"
|
||||
|
||||
@interface SKViewController () <ARSKViewDelegate, RecordARDelegate, RenderARDelegate>
|
||||
{
|
||||
RecordAR *recorder;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SKViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Set the view's delegate
|
||||
self.SKSceneView.delegate = self;
|
||||
|
||||
// Show statistics such as fps and node count
|
||||
self.SKSceneView.showsFPS = YES;
|
||||
self.SKSceneView.showsNodeCount = YES;
|
||||
|
||||
// Load the SKScene from 'Scene.sks'
|
||||
Scene *scene = (Scene *)[SKScene nodeWithFileNamed:@"Scene"];
|
||||
|
||||
// Present the scene
|
||||
[self.SKSceneView presentScene:scene];
|
||||
|
||||
// Initialize ARVideoKit recorder
|
||||
recorder = [[RecordAR alloc] initWithARSpriteKit:self.SKSceneView];
|
||||
|
||||
/*----👇---- ARVideoKit Configuration ----👇----*/
|
||||
|
||||
// Set the recorder's delegate
|
||||
recorder.delegate = self;
|
||||
|
||||
// Set the renderer's delegate
|
||||
recorder.renderAR = self;
|
||||
|
||||
// Configure the renderer to perform additional image & video processing 👁
|
||||
recorder.onlyRenderWhileRecording = YES;
|
||||
|
||||
// Configure ARKit content mode. Default is .auto -- aspectFill is recommended for iPhone10-only apps
|
||||
recorder.contentMode = ARFrameModeAuto;
|
||||
|
||||
// Configure RecordAR to store media files in local app directory
|
||||
recorder.deleteCacheWhenExported = NO;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Create a session configuration
|
||||
ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
|
||||
|
||||
// Run the view's session
|
||||
[self.SKSceneView.session runWithConfiguration:configuration];
|
||||
|
||||
// Prepare the recorder with sessions configuration
|
||||
[recorder prepare:configuration];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// Pause the view's session
|
||||
[self.SKSceneView.session pause];
|
||||
|
||||
if(recorder.status == RecordARStatusRecording) {
|
||||
[recorder stopAndExport:NULL];
|
||||
}
|
||||
recorder.onlyRenderWhileRecording = YES;
|
||||
|
||||
// Switch off the orientation lock for UIViewControllers with AR Scenes
|
||||
[recorder rest];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
// MARK:- Capture and Record methods
|
||||
- (IBAction)capture:(UIButton *)sender {
|
||||
if (sender.tag == 0) {
|
||||
//Photo
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
UIImage *image = [recorder photo];
|
||||
[recorder exportWithImage:NULL UIImage:image :NULL];
|
||||
}
|
||||
}else if (sender.tag == 1) {
|
||||
//Live Photo
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[recorder livePhotoWithExport:YES :NULL];
|
||||
}
|
||||
}else if (sender.tag == 2) {
|
||||
//GIF
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[recorder gifForDuration:3.0 export:YES :NULL];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)record:(UIButton *)sender {
|
||||
if (sender.tag == 0) {
|
||||
//Record
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[sender setTitle:@"Stop" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = YES;
|
||||
[recorder record];
|
||||
}else if (recorder.status == RecordARStatusRecording) {
|
||||
[sender setTitle:@"Record" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = NO;
|
||||
//URL, PHAuthorizationStatus, Bool
|
||||
[recorder stopAndExport:^(NSURL*_Nonnull filePath, PHAuthorizationStatus status, BOOL ready) {
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
NSLog(@"Video Exported Successfully!");
|
||||
}
|
||||
}];
|
||||
}
|
||||
}else if (sender.tag == 1) {
|
||||
//Record with duration
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[sender setTitle:@"Stop" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = NO;
|
||||
self.recordBtn.enabled = NO;
|
||||
[recorder recordForDuration:10 :NULL];
|
||||
}else if (recorder.status == RecordARStatusRecording) {
|
||||
[sender setTitle:@"w/Duration" forState: UIControlStateNormal];
|
||||
[self.pauseBtn setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
self.pauseBtn.enabled = NO;
|
||||
self.recordBtn.enabled = YES;
|
||||
[recorder stopAndExport:NULL];
|
||||
}
|
||||
}else if (sender.tag == 2) {
|
||||
//Pause
|
||||
if (recorder.status == RecordARStatusPaused) {
|
||||
[sender setTitle:@"Pause" forState: UIControlStateNormal];
|
||||
[recorder record];
|
||||
}else if (recorder.status == RecordARStatusRecording) {
|
||||
[sender setTitle:@"Resume" forState: UIControlStateNormal];
|
||||
[recorder pause];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)goBack:(UIButton *)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:NULL];
|
||||
}
|
||||
|
||||
// MARK:- ARKit protocol methods
|
||||
- (SKNode *)view:(ARSKView *)view nodeForAnchor:(ARAnchor *)anchor {
|
||||
// Create and configure a node for the anchor added to the view's session.
|
||||
SKLabelNode *labelNode = [SKLabelNode labelNodeWithText:[self randoMoji]];
|
||||
labelNode.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
|
||||
labelNode.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
|
||||
return labelNode;
|
||||
}
|
||||
|
||||
-(NSString*)randoMoji {
|
||||
NSArray *emojis = @[@"👾", @"🤓", @"🔥", @"😜", @"😇", @"🤣", @"🤗"];
|
||||
return emojis[arc4random_uniform((int)emojis.count)];
|
||||
}
|
||||
- (void)session:(ARSession *)session didFailWithError:(NSError *)error {
|
||||
// Present an error message to the user
|
||||
|
||||
}
|
||||
|
||||
- (void)sessionWasInterrupted:(ARSession *)session {
|
||||
// Inform the user that the session has been interrupted, for example, by presenting an overlay
|
||||
|
||||
}
|
||||
|
||||
- (void)sessionInterruptionEnded:(ARSession *)session {
|
||||
// Reset tracking and/or remove existing anchors if consistent tracking is required
|
||||
|
||||
}
|
||||
|
||||
// MARK:- ARVideoKit protocol methods
|
||||
- (void)recorderWithDidEndRecording:(NSURL * _Nonnull)path with:(BOOL)noError {
|
||||
|
||||
}
|
||||
|
||||
- (void)recorderWithDidFailRecording:(NSError * _Nullable)error and:(NSString * _Nonnull)status {
|
||||
|
||||
}
|
||||
|
||||
- (void)recorderWithWillEnterBackground:(enum RecordARStatus)status {
|
||||
|
||||
}
|
||||
|
||||
- (void)frameWithDidRender:(CVPixelBufferRef _Nonnull)buffer with:(CMTime)time using:(CVPixelBufferRef _Nonnull)rawBuffer {
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// main.m
|
||||
// ARKit-Video
|
||||
//
|
||||
// Created by Ahmed Bekhit on 1/11/18.
|
||||
// Copyright © 2018 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Ahmed Fathi Bekhit - me@ahmedbekhit.com
|
||||
Copyright 2017 Ahmed Fathi Bekhit, www.ahmedbekhit.com, me@ahmedbekhit.com
|
||||
|
||||
ARVideoKit is licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Objective-C Example
|
||||
This folder provides you an example project written in Objective-C that demonstrates the use of [**ARVideoKit**](https://github.com/AFathi/ARVideoKit) framework.
|
||||
|
||||
## Implementation
|
||||
1. Import the `ARVideoKit` into the application delegate implementation file `AppDelegate.m` and a `UIViewController` class with an `ARKit` scene.
|
||||
```
|
||||
@import ARVideoKit;
|
||||
```
|
||||
|
||||
2. In the application delegate implementation file `AppDelegate.m`, add this 👇 in order to allow the framework access and identify the supported device orientations. **Recommended** if the application supports landscape orientations.
|
||||
```
|
||||
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
return ViewAR.orientation;
|
||||
}
|
||||
```
|
||||
|
||||
3. In the selected `UIViewController` class, create a [`RecordAR`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR) global variable by adding the following in the interface section of the implementation file (e.g `ViewController.m`).
|
||||
```
|
||||
@interface ViewController ()
|
||||
{
|
||||
RecordAR *recorder;
|
||||
}
|
||||
```
|
||||
|
||||
4. Initialize [`RecordAR`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR) with [`ARSCNView`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#init-arscenekitarscnview) or [`ARSKView`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#init-arspritekitarskview). **Recommended** to initialize in `(void)viewDidLoad`.
|
||||
|
||||
Initializing RecordAR with `ARSCNView`
|
||||
```
|
||||
recorder = [[RecordAR alloc] initWithARSceneKit:self.sceneView];
|
||||
```
|
||||
Initializing RecordAR with `ARSKView`
|
||||
```
|
||||
recorder = [[RecordAR alloc] initWithARSpriteKit:self.SKSceneView];
|
||||
```
|
||||
|
||||
5. Call the [`prepare()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-prepare_-configurationarconfiguration) method in `(void)viewWillAppear:(BOOL)animated`
|
||||
```
|
||||
ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
|
||||
[recorder prepare:configuration];
|
||||
```
|
||||
|
||||
6. Call the [`rest()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-rest) method in `(void)viewWillDisappear:(BOOL)animated`
|
||||
```
|
||||
[recorder rest];
|
||||
```
|
||||
|
||||
7. Call the [`record()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-record) method in the proper method to start recording.
|
||||
```
|
||||
- (IBAction)startRecording:(UIButton *)sender {
|
||||
if (recorder.status == RecordARStatusReadyToRecord) {
|
||||
[recorder record];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
8. Call the [`stopAndExport()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-stopandexport_-finished-_-videopath-url-_-permissionstatusphauthorizationstatus-_-exportedbool---swiftvoid--nil) method in the proper method to stop recording.
|
||||
```
|
||||
- (IBAction)stopRecording:(UIButton *)sender {
|
||||
if (recorder.status == RecordARStatusRecording) {
|
||||
[recorder stopAndExport:NULL];
|
||||
}
|
||||
}
|
||||
```
|
||||
+52
-180
@@ -8,31 +8,34 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
FB2E368C1FAE2A510035B8D6 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = FB2E368B1FAE2A510035B8D6 /* LICENSE */; };
|
||||
FB36BDB020086BBB00002808 /* ARVideoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB36BDAF20086BB000002808 /* ARVideoKit.framework */; };
|
||||
FB36BDB120086BBB00002808 /* ARVideoKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FB36BDAF20086BB000002808 /* ARVideoKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
FB9B5D2E1FC49E3E005DDD60 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB9B5D2D1FC49E3E005DDD60 /* MainViewController.swift */; };
|
||||
FBDCC5E71FABDFC600E3184D /* Scene.sks in Resources */ = {isa = PBXBuildFile; fileRef = FBDCC5E51FABDFC500E3184D /* Scene.sks */; };
|
||||
FBDCC5E81FABDFC600E3184D /* Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBDCC5E61FABDFC500E3184D /* Scene.swift */; };
|
||||
FBDCC60D1FABFE6A00E3184D /* SKViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBDCC60C1FABFE6A00E3184D /* SKViewController.swift */; };
|
||||
FBDCC6401FAC2CD900E3184D /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = FBDCC63F1FAC2CD900E3184D /* art.scnassets */; };
|
||||
FBE134BA1FAAD3DD00BEC469 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE134B91FAAD3DD00BEC469 /* AppDelegate.swift */; };
|
||||
FBE134BC1FAAD3DD00BEC469 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE134BB1FAAD3DD00BEC469 /* ViewController.swift */; };
|
||||
FBE134BC1FAAD3DD00BEC469 /* SCNViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE134BB1FAAD3DD00BEC469 /* SCNViewController.swift */; };
|
||||
FBE134BF1FAAD3DD00BEC469 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBE134BD1FAAD3DD00BEC469 /* Main.storyboard */; };
|
||||
FBE134C11FAAD3DD00BEC469 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FBE134C01FAAD3DD00BEC469 /* Assets.xcassets */; };
|
||||
FBE134C41FAAD3DD00BEC469 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBE134C21FAAD3DD00BEC469 /* LaunchScreen.storyboard */; };
|
||||
FBED18BC1FAFF4AB00D810BF /* ARVideoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBED18BA1FAFF4A500D810BF /* ARVideoKit.framework */; };
|
||||
FBED18BD1FAFF4AB00D810BF /* ARVideoKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FBED18BA1FAFF4A500D810BF /* ARVideoKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
FBED18C71FAFF52200D810BF /* ARVideoKitLib.h in Headers */ = {isa = PBXBuildFile; fileRef = FBED18C51FAFF52200D810BF /* ARVideoKitLib.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
FBED18CA1FAFF52200D810BF /* ARVideoKitLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBED18C31FAFF52200D810BF /* ARVideoKitLib.framework */; };
|
||||
FBED18CB1FAFF52200D810BF /* ARVideoKitLib.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FBED18C31FAFF52200D810BF /* ARVideoKitLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
FBED18D11FAFF54300D810BF /* ARVideoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBED18CF1FAFF53100D810BF /* ARVideoKit.framework */; };
|
||||
FBED18F91FAFF72000D810BF /* ARVideoKit.framework in Sources */ = {isa = PBXBuildFile; fileRef = FBED18CF1FAFF53100D810BF /* ARVideoKit.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
FBED18C81FAFF52200D810BF /* PBXContainerItemProxy */ = {
|
||||
FB36BDAE20086BB000002808 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = FBE134AE1FAAD3DD00BEC469 /* Project object */;
|
||||
containerPortal = FB36BDAA20086BB000002808 /* ARVideoKit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = FBD604DA1FA969DD00EC9804;
|
||||
remoteInfo = ARVideoKit;
|
||||
};
|
||||
FB36BDB220086BBB00002808 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = FB36BDAA20086BB000002808 /* ARVideoKit.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = FBED18C21FAFF52200D810BF;
|
||||
remoteInfo = ARVideoKitLib;
|
||||
remoteGlobalIDString = FBD604D91FA969DD00EC9804;
|
||||
remoteInfo = ARVideoKit;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
@@ -43,8 +46,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
FBED18CB1FAFF52200D810BF /* ARVideoKitLib.framework in Embed Frameworks */,
|
||||
FBED18BD1FAFF4AB00D810BF /* ARVideoKit.framework in Embed Frameworks */,
|
||||
FB36BDB120086BBB00002808 /* ARVideoKit.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -53,24 +55,19 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
FB2E368B1FAE2A510035B8D6 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
FB2E38081FAFF3CB0035B8D6 /* ARVideoKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARVideoKit.h; sourceTree = "<group>"; };
|
||||
FB2E38091FAFF3CB0035B8D6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FB36BDAA20086BB000002808 /* ARVideoKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ARVideoKit.xcodeproj; path = ../../ARVideoKit.xcodeproj; sourceTree = "<group>"; };
|
||||
FB9B5D2D1FC49E3E005DDD60 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
FBDCC5E51FABDFC500E3184D /* Scene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Scene.sks; sourceTree = "<group>"; };
|
||||
FBDCC5E61FABDFC500E3184D /* Scene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scene.swift; sourceTree = "<group>"; };
|
||||
FBDCC60C1FABFE6A00E3184D /* SKViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SKViewController.swift; sourceTree = "<group>"; };
|
||||
FBDCC63F1FAC2CD900E3184D /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = "<group>"; };
|
||||
FBE134B61FAAD3DD00BEC469 /* ARVideoKit-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ARVideoKit-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FBE134B91FAAD3DD00BEC469 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
FBE134BB1FAAD3DD00BEC469 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
FBE134BB1FAAD3DD00BEC469 /* SCNViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SCNViewController.swift; sourceTree = "<group>"; };
|
||||
FBE134BE1FAAD3DD00BEC469 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
FBE134C01FAAD3DD00BEC469 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
FBE134C31FAAD3DD00BEC469 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
FBE134C51FAAD3DD00BEC469 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FBED18BA1FAFF4A500D810BF /* ARVideoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ARVideoKit.framework; path = Framework/ARVideoKit.framework; sourceTree = "<group>"; };
|
||||
FBED18C31FAFF52200D810BF /* ARVideoKitLib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ARVideoKitLib.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FBED18C51FAFF52200D810BF /* ARVideoKitLib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARVideoKitLib.h; sourceTree = "<group>"; };
|
||||
FBED18C61FAFF52200D810BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
FBED18CF1FAFF53100D810BF /* ARVideoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ARVideoKit.framework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -78,38 +75,19 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBED18CA1FAFF52200D810BF /* ARVideoKitLib.framework in Frameworks */,
|
||||
FBED18BC1FAFF4AB00D810BF /* ARVideoKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FBED18BF1FAFF52200D810BF /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBED18D11FAFF54300D810BF /* ARVideoKit.framework in Frameworks */,
|
||||
FB36BDB020086BBB00002808 /* ARVideoKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
FB2E37781FAFD5C20035B8D6 /* Frameworks */ = {
|
||||
FB36BDAB20086BB000002808 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBED18CF1FAFF53100D810BF /* ARVideoKit.framework */,
|
||||
FBED18BA1FAFF4A500D810BF /* ARVideoKit.framework */,
|
||||
FB36BDAF20086BB000002808 /* ARVideoKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB2E38071FAFF3CB0035B8D6 /* ARVideoKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB2E38081FAFF3CB0035B8D6 /* ARVideoKit.h */,
|
||||
FB2E38091FAFF3CB0035B8D6 /* Info.plist */,
|
||||
);
|
||||
path = ARVideoKit;
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBA0AA0B1FAD9E13006C481B /* Assets */ = {
|
||||
@@ -133,7 +111,8 @@
|
||||
FBA0AA0D1FAD9E4B006C481B /* View Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBE134BB1FAAD3DD00BEC469 /* ViewController.swift */,
|
||||
FB9B5D2D1FC49E3E005DDD60 /* MainViewController.swift */,
|
||||
FBE134BB1FAAD3DD00BEC469 /* SCNViewController.swift */,
|
||||
FBDCC60C1FABFE6A00E3184D /* SKViewController.swift */,
|
||||
);
|
||||
path = "View Controllers";
|
||||
@@ -169,11 +148,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB2E368B1FAE2A510035B8D6 /* LICENSE */,
|
||||
FB36BDAA20086BB000002808 /* ARVideoKit.xcodeproj */,
|
||||
FBE134B81FAAD3DD00BEC469 /* ARVideoKit-Example */,
|
||||
FB2E38071FAFF3CB0035B8D6 /* ARVideoKit */,
|
||||
FBED18C41FAFF52200D810BF /* ARVideoKitLib */,
|
||||
FBE134B71FAAD3DD00BEC469 /* Products */,
|
||||
FB2E37781FAFD5C20035B8D6 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -181,7 +158,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBE134B61FAAD3DD00BEC469 /* ARVideoKit-Example.app */,
|
||||
FBED18C31FAFF52200D810BF /* ARVideoKitLib.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -198,28 +174,8 @@
|
||||
path = "ARVideoKit-Example";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBED18C41FAFF52200D810BF /* ARVideoKitLib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBED18C51FAFF52200D810BF /* ARVideoKitLib.h */,
|
||||
FBED18C61FAFF52200D810BF /* Info.plist */,
|
||||
);
|
||||
path = ARVideoKitLib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
FBED18C01FAFF52200D810BF /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBED18C71FAFF52200D810BF /* ARVideoKitLib.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
FBE134B51FAAD3DD00BEC469 /* ARVideoKit-Example */ = {
|
||||
isa = PBXNativeTarget;
|
||||
@@ -233,31 +189,13 @@
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
FBED18C91FAFF52200D810BF /* PBXTargetDependency */,
|
||||
FB36BDB320086BBB00002808 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "ARVideoKit-Example";
|
||||
productName = "ARVideoKit-Example";
|
||||
productReference = FBE134B61FAAD3DD00BEC469 /* ARVideoKit-Example.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
FBED18C21FAFF52200D810BF /* ARVideoKitLib */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = FBED18CC1FAFF52200D810BF /* Build configuration list for PBXNativeTarget "ARVideoKitLib" */;
|
||||
buildPhases = (
|
||||
FBED18BE1FAFF52200D810BF /* Sources */,
|
||||
FBED18BF1FAFF52200D810BF /* Frameworks */,
|
||||
FBED18C01FAFF52200D810BF /* Headers */,
|
||||
FBED18C11FAFF52200D810BF /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = ARVideoKitLib;
|
||||
productName = ARVideoKitLib;
|
||||
productReference = FBED18C31FAFF52200D810BF /* ARVideoKitLib.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -272,10 +210,6 @@
|
||||
CreatedOnToolsVersion = 9.1;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
FBED18C21FAFF52200D810BF = {
|
||||
CreatedOnToolsVersion = 9.1;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = FBE134B11FAAD3DD00BEC469 /* Build configuration list for PBXProject "ARVideoKit-Example" */;
|
||||
@@ -289,14 +223,29 @@
|
||||
mainGroup = FBE134AD1FAAD3DD00BEC469;
|
||||
productRefGroup = FBE134B71FAAD3DD00BEC469 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = FB36BDAB20086BB000002808 /* Products */;
|
||||
ProjectRef = FB36BDAA20086BB000002808 /* ARVideoKit.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
FBE134B51FAAD3DD00BEC469 /* ARVideoKit-Example */,
|
||||
FBED18C21FAFF52200D810BF /* ARVideoKitLib */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
FB36BDAF20086BB000002808 /* ARVideoKit.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = ARVideoKit.framework;
|
||||
remoteRef = FB36BDAE20086BB000002808 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
FBE134B41FAAD3DD00BEC469 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
@@ -311,13 +260,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FBED18C11FAFF52200D810BF /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -325,28 +267,21 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBE134BC1FAAD3DD00BEC469 /* ViewController.swift in Sources */,
|
||||
FBE134BC1FAAD3DD00BEC469 /* SCNViewController.swift in Sources */,
|
||||
FBE134BA1FAAD3DD00BEC469 /* AppDelegate.swift in Sources */,
|
||||
FBDCC60D1FABFE6A00E3184D /* SKViewController.swift in Sources */,
|
||||
FBDCC5E81FABDFC600E3184D /* Scene.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FBED18BE1FAFF52200D810BF /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FBED18F91FAFF72000D810BF /* ARVideoKit.framework in Sources */,
|
||||
FB9B5D2E1FC49E3E005DDD60 /* MainViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
FBED18C91FAFF52200D810BF /* PBXTargetDependency */ = {
|
||||
FB36BDB320086BBB00002808 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = FBED18C21FAFF52200D810BF /* ARVideoKitLib */;
|
||||
targetProxy = FBED18C81FAFF52200D810BF /* PBXContainerItemProxy */;
|
||||
name = ARVideoKit;
|
||||
targetProxy = FB36BDB220086BBB00002808 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
@@ -480,9 +415,10 @@
|
||||
FBE134C91FAAD3DD00BEC469 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = TB37P94YA8;
|
||||
DEVELOPMENT_TEAM = LXD85S9DW4;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
@@ -501,9 +437,10 @@
|
||||
FBE134CA1FAAD3DD00BEC469 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = TB37P94YA8;
|
||||
DEVELOPMENT_TEAM = LXD85S9DW4;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
@@ -519,62 +456,6 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
FBED18CD1FAFF52200D810BF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = TB37P94YA8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = ARVideoKitLib/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ahmedbekhit.ARVideoKitLib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
FBED18CE1FAFF52200D810BF /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = TB37P94YA8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = ARVideoKitLib/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ahmedbekhit.ARVideoKitLib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@@ -596,15 +477,6 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
FBED18CC1FAFF52200D810BF /* Build configuration list for PBXNativeTarget "ARVideoKitLib" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
FBED18CD1FAFF52200D810BF /* Debug */,
|
||||
FBED18CE1FAFF52200D810BF /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = FBE134AE1FAAD3DD00BEC469 /* Project object */;
|
||||
+8
@@ -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>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 342 KiB |
Binary file not shown.
+98
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -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" systemVersion="17A277" 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" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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>
|
||||
+78
-16
@@ -1,18 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="N8h-YD-r0X">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<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-->
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="wdx-bS-4nS">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="mainView" useStoryboardIdentifierAsRestorationIdentifier="YES" id="N8h-YD-r0X" customClass="MainViewController" customModule="ARVideoKit_Example" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="lKA-5t-IIG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Try" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="khu-YU-VZr">
|
||||
<rect key="frame" x="8" y="63" width="359" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Black" family="Avenir" pointSize="40"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Framework features on" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eEa-da-nmU">
|
||||
<rect key="frame" x="8" y="183" width="359" height="42"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="27"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="ARVideoKit" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HUS-U8-CBt">
|
||||
<rect key="frame" x="8" y="131" width="359" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="41"/>
|
||||
<color key="textColor" red="0.97052964239999995" green="0.37927614589999997" blue="0.45678941579999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tQf-dN-lB4">
|
||||
<rect key="frame" x="8" y="268" width="359" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="18"/>
|
||||
<state key="normal" title=" AR SpriteKit App"/>
|
||||
<connections>
|
||||
<segue destination="7Ze-pj-Xqd" kind="show" id="93E-6x-10b"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="21A-pg-4R6">
|
||||
<rect key="frame" x="8" y="359" width="359" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="18"/>
|
||||
<state key="normal" title=" AR SceneKit App"/>
|
||||
<connections>
|
||||
<segue destination="BYZ-38-t0r" kind="show" id="aHU-mz-b0b"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="2zo-8C-5Jz"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="scnBtn" destination="21A-pg-4R6" id="TOp-ks-rLN"/>
|
||||
<outlet property="skBtn" destination="tQf-dN-lB4" id="Zfs-NO-PMo"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="bSs-NK-rzw" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-724" y="454"/>
|
||||
</scene>
|
||||
<!--SCNViewController-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="scnView" useStoryboardIdentifierAsRestorationIdentifier="YES" id="BYZ-38-t0r" customClass="ViewController" customModule="ARVideoKit_Example" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="scnView" title="SCNViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="BYZ-38-t0r" customClass="SCNViewController" customModule="ARVideoKit_Example" 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"/>
|
||||
@@ -121,23 +183,23 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="69u-dy-9On">
|
||||
<rect key="frame" x="294" y="20" width="65" height="65"/>
|
||||
<rect key="frame" x="7" y="20" width="65" height="65"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="3Xy-JT-6ZT"/>
|
||||
<constraint firstAttribute="height" constant="65" id="Q5O-CD-1T4"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="65" id="IPA-eO-hiu"/>
|
||||
<constraint firstAttribute="height" constant="65" id="jVv-es-uhg"/>
|
||||
</constraints>
|
||||
<size key="titleShadowOffset" width="0.0" height="1"/>
|
||||
<state key="normal" title="Go to SK">
|
||||
<state key="normal" title="Go Back">
|
||||
<color key="titleShadowColor" white="0.0" alpha="0.65000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<segue destination="7Ze-pj-Xqd" kind="show" id="x6e-M6-jfv"/>
|
||||
<action selector="goBack:" destination="BYZ-38-t0r" eventType="touchUpInside" id="93X-Zy-W33"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="69u-dy-9On" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="28v-Xd-AVo"/>
|
||||
<constraint firstItem="69u-dy-9On" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="7" id="0m6-4F-0Fh"/>
|
||||
<constraint firstItem="IMN-9B-haO" firstAttribute="height" secondItem="8bC-Xf-vdC" secondAttribute="height" id="4lt-V9-t2E"/>
|
||||
<constraint firstItem="VIM-JP-UzO" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="55A-z8-Ex1"/>
|
||||
<constraint firstItem="DJd-jZ-eqw" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="8OL-Px-2eA"/>
|
||||
@@ -154,14 +216,14 @@
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="Sdu-XX-UpW" secondAttribute="trailing" constant="16" id="a7G-NE-FuY"/>
|
||||
<constraint firstItem="1R6-Xa-VsB" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="aDC-0U-rEb"/>
|
||||
<constraint firstItem="IMN-9B-haO" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" id="awb-Ub-ogs"/>
|
||||
<constraint firstItem="69u-dy-9On" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="bIZ-at-yZb"/>
|
||||
<constraint firstItem="p4z-aP-wTO" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="eIW-wL-nut"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="69u-dy-9On" secondAttribute="trailing" constant="16" id="fGZ-LP-ClO"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="1R6-Xa-VsB" secondAttribute="bottom" constant="20" id="g6C-dt-mSp"/>
|
||||
<constraint firstItem="1R6-Xa-VsB" firstAttribute="top" secondItem="p4z-aP-wTO" secondAttribute="bottom" constant="8" id="gd7-UD-shK"/>
|
||||
<constraint firstItem="DJd-jZ-eqw" firstAttribute="bottom" secondItem="VIM-JP-UzO" secondAttribute="bottom" constant="73" id="oes-gl-dgB"/>
|
||||
<constraint firstItem="69u-dy-9On" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="20" symbolic="YES" id="puT-8M-YHI"/>
|
||||
<constraint firstAttribute="trailing" secondItem="VIM-JP-UzO" secondAttribute="trailing" constant="294" id="shb-pG-gjl"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="pCi-Bx-pwj" secondAttribute="trailing" constant="16" id="shk-Bc-iV7"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="69u-dy-9On" secondAttribute="trailing" constant="20" symbolic="YES" id="veA-fi-fX6"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
@@ -174,12 +236,12 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53.600000000000001" y="133.5832083958021"/>
|
||||
<point key="canvasLocation" x="53.600000000000001" y="865.81709145427294"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<!--SKViewController-->
|
||||
<scene sceneID="emy-Ex-RPU">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="skView" useStoryboardIdentifierAsRestorationIdentifier="YES" id="7Ze-pj-Xqd" customClass="SKViewController" customModule="ARVideoKit_Example" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="skView" title="SKViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="7Ze-pj-Xqd" customClass="SKViewController" customModule="ARVideoKit_Example" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="ChF-2c-u6U">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
@@ -341,7 +403,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="9if-am-XF6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="836" y="134"/>
|
||||
<point key="canvasLocation" x="53.600000000000001" y="133.5832083958021"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// MainViewController.swift
|
||||
// ARVideoKit-Example
|
||||
//
|
||||
// Created by Ahmed Bekhit on 11/21/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class MainViewController: UIViewController {
|
||||
|
||||
@IBOutlet var skBtn: UIButton!
|
||||
@IBOutlet var scnBtn: UIButton!
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
skBtn.layer.cornerRadius = skBtn.bounds.height/2
|
||||
scnBtn.layer.cornerRadius = scnBtn.bounds.height/2
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
}
|
||||
+60
-28
@@ -11,12 +11,15 @@ import ARKit
|
||||
import ARVideoKit
|
||||
import Photos
|
||||
|
||||
class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, RecordARDelegate {
|
||||
class SCNViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, RecordARDelegate {
|
||||
|
||||
@IBOutlet var sceneView: ARSCNView!
|
||||
@IBOutlet var recordBtn: UIButton!
|
||||
@IBOutlet var pauseBtn: UIButton!
|
||||
|
||||
let recordingQueue = DispatchQueue(label: "recordingThread", attributes: .concurrent)
|
||||
let caprturingQueue = DispatchQueue(label: "capturingThread", attributes: .concurrent)
|
||||
|
||||
var recorder:RecordAR?
|
||||
|
||||
override func viewDidLoad() {
|
||||
@@ -33,21 +36,34 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec
|
||||
// Set the scene to the view
|
||||
sceneView.scene = scene
|
||||
sceneView.scene.rootNode.scale = SCNVector3(0.2, 0.2, 0.2)
|
||||
//
|
||||
sceneView.automaticallyUpdatesLighting = true
|
||||
sceneView.autoenablesDefaultLighting = true
|
||||
|
||||
// Initialize ARVideoKit recorder
|
||||
|
||||
|
||||
recorder = RecordAR(ARSceneKit: sceneView)
|
||||
|
||||
/*----👇---- ARVideoKit Configuration ----👇----*/
|
||||
|
||||
// Set the recorder's delegate
|
||||
recorder?.delegate = self
|
||||
|
||||
|
||||
// Set the renderer's delegate
|
||||
recorder?.renderAR = self
|
||||
|
||||
// Configure the renderer to perform additional image & video processing 👁
|
||||
recorder?.onlyRenderWhileRecording = false
|
||||
|
||||
// Configure ARKit content mode. Default is .auto
|
||||
recorder?.contentMode = .aspectFill
|
||||
|
||||
//record or photo add environment light rendering, Default is false
|
||||
recorder?.enableAdjustEnvironmentLighting = true
|
||||
|
||||
// Set the UIViewController orientations
|
||||
recorder?.inputViewOrientations = [.landscapeLeft, .landscapeRight, .portrait]
|
||||
|
||||
// Configure RecordAR to store media files in local app directory
|
||||
recorder?.deleteCacheWhenExported = false
|
||||
}
|
||||
@@ -69,6 +85,12 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec
|
||||
// Pause the view's session
|
||||
sceneView.session.pause()
|
||||
|
||||
if recorder?.status == .recording {
|
||||
recorder?.stopAndExport()
|
||||
}
|
||||
recorder?.onlyRenderWhileRecording = true
|
||||
recorder?.prepare(ARWorldTrackingConfiguration())
|
||||
|
||||
// Switch off the orientation lock for UIViewControllers with AR Scenes
|
||||
recorder?.rest()
|
||||
}
|
||||
@@ -83,7 +105,7 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec
|
||||
override var prefersStatusBarHidden: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Exported UIAlert present method
|
||||
func exportMessage(success: Bool, status:PHAuthorizationStatus) {
|
||||
if success {
|
||||
@@ -119,13 +141,17 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec
|
||||
}
|
||||
|
||||
//MARK: - Button Action Methods
|
||||
extension ViewController {
|
||||
extension SCNViewController {
|
||||
@IBAction func goBack(_ sender: UIButton) {
|
||||
self.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@IBAction func capture(_ sender: UIButton) {
|
||||
if sender.tag == 0 {
|
||||
//Photo
|
||||
if recorder?.status == .readyToRecord {
|
||||
let image = recorder?.photo()
|
||||
recorder?.export(UIImage: image) { saved, status in
|
||||
let image = self.recorder?.photo()
|
||||
self.recorder?.export(UIImage: image) { saved, status in
|
||||
if saved {
|
||||
// Inform user photo has exported successfully
|
||||
self.exportMessage(success: saved, status: status)
|
||||
@@ -135,16 +161,18 @@ extension ViewController {
|
||||
}else if sender.tag == 1 {
|
||||
//Live Photo
|
||||
if recorder?.status == .readyToRecord {
|
||||
recorder?.livePhoto(export: true) { ready, photo, status, saved in
|
||||
/*
|
||||
if ready {
|
||||
// Do something with the `photo` (PHLivePhotoPlus)
|
||||
}
|
||||
*/
|
||||
|
||||
if saved {
|
||||
// Inform user Live Photo has exported successfully
|
||||
self.exportMessage(success: saved, status: status!)
|
||||
caprturingQueue.async {
|
||||
self.recorder?.livePhoto(export: true) { ready, photo, status, saved in
|
||||
/*
|
||||
if ready {
|
||||
// Do something with the `photo` (PHLivePhotoPlus)
|
||||
}
|
||||
*/
|
||||
|
||||
if saved {
|
||||
// Inform user Live Photo has exported successfully
|
||||
self.exportMessage(success: saved, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +188,7 @@ extension ViewController {
|
||||
|
||||
if saved {
|
||||
// Inform user GIF image has exported successfully
|
||||
self.exportMessage(success: saved, status: status!)
|
||||
self.exportMessage(success: saved, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +202,9 @@ extension ViewController {
|
||||
sender.setTitle("Stop", for: .normal)
|
||||
pauseBtn.setTitle("Pause", for: .normal)
|
||||
pauseBtn.isEnabled = true
|
||||
recorder?.record()
|
||||
recordingQueue.async {
|
||||
self.recorder?.record()
|
||||
}
|
||||
}else if recorder?.status == .recording {
|
||||
sender.setTitle("Record", for: .normal)
|
||||
pauseBtn.setTitle("Pause", for: .normal)
|
||||
@@ -194,14 +224,16 @@ extension ViewController {
|
||||
pauseBtn.setTitle("Pause", for: .normal)
|
||||
pauseBtn.isEnabled = false
|
||||
recordBtn.isEnabled = false
|
||||
recorder?.record(forDuration: 10) { path in
|
||||
self.recorder?.export(video: path) { saved, status in
|
||||
DispatchQueue.main.sync {
|
||||
sender.setTitle("w/Duration", for: .normal)
|
||||
self.pauseBtn.setTitle("Pause", for: .normal)
|
||||
self.pauseBtn.isEnabled = false
|
||||
self.recordBtn.isEnabled = true
|
||||
self.exportMessage(success: saved, status: status)
|
||||
recordingQueue.async {
|
||||
self.recorder?.record(forDuration: 10) { path in
|
||||
self.recorder?.export(video: path) { saved, status in
|
||||
DispatchQueue.main.sync {
|
||||
sender.setTitle("w/Duration", for: .normal)
|
||||
self.pauseBtn.setTitle("Pause", for: .normal)
|
||||
self.pauseBtn.isEnabled = false
|
||||
self.recordBtn.isEnabled = true
|
||||
self.exportMessage(success: saved, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +264,7 @@ extension ViewController {
|
||||
}
|
||||
|
||||
//MARK: - ARVideoKit Delegate Methods
|
||||
extension ViewController {
|
||||
extension SCNViewController {
|
||||
func frame(didRender buffer: CVPixelBuffer, with time: CMTime, using rawBuffer: CVPixelBuffer) {
|
||||
// Do some image/video processing.
|
||||
}
|
||||
+40
-22
@@ -17,6 +17,9 @@ class SKViewController: UIViewController, ARSKViewDelegate, RenderARDelegate, Re
|
||||
@IBOutlet var recordBtn: UIButton!
|
||||
@IBOutlet var pauseBtn: UIButton!
|
||||
|
||||
let recordingQueue = DispatchQueue(label: "recordingThread")
|
||||
let caprturingQueue = DispatchQueue(label: "capturingThread", attributes: .concurrent)
|
||||
|
||||
var recorder:RecordAR?
|
||||
|
||||
override func viewDidLoad() {
|
||||
@@ -45,6 +48,9 @@ class SKViewController: UIViewController, ARSKViewDelegate, RenderARDelegate, Re
|
||||
// Set the renderer's delegate
|
||||
recorder?.renderAR = self
|
||||
|
||||
// Configure the renderer to perform additional image & video processing 👁
|
||||
recorder?.onlyRenderWhileRecording = false
|
||||
|
||||
// Set the UIViewController orientations
|
||||
recorder?.inputViewOrientations = [.landscapeLeft, .landscapeRight, .portrait]
|
||||
|
||||
@@ -71,6 +77,12 @@ class SKViewController: UIViewController, ARSKViewDelegate, RenderARDelegate, Re
|
||||
// Pause the view's session
|
||||
SKSceneView.session.pause()
|
||||
|
||||
if recorder?.status == .recording {
|
||||
recorder?.stopAndExport()
|
||||
}
|
||||
recorder?.onlyRenderWhileRecording = true
|
||||
recorder?.prepare(ARWorldTrackingConfiguration())
|
||||
|
||||
// Switch off the orientation lock for UIViewControllers with AR Scenes
|
||||
recorder?.rest()
|
||||
}
|
||||
@@ -129,8 +141,8 @@ extension SKViewController {
|
||||
if sender.tag == 0 {
|
||||
//Photo
|
||||
if recorder?.status == .readyToRecord {
|
||||
let image = recorder?.photo()
|
||||
recorder?.export(UIImage: image) { saved, status in
|
||||
let image = self.recorder?.photo()
|
||||
self.recorder?.export(UIImage: image) { saved, status in
|
||||
if saved {
|
||||
// Inform user photo has exported successfully
|
||||
self.exportMessage(success: saved, status: status)
|
||||
@@ -140,16 +152,18 @@ extension SKViewController {
|
||||
}else if sender.tag == 1 {
|
||||
//Live Photo
|
||||
if recorder?.status == .readyToRecord {
|
||||
recorder?.livePhoto(export: true) { ready, photo, status, saved in
|
||||
/*
|
||||
if ready {
|
||||
// Do something with the `photo` (PHLivePhotoPlus)
|
||||
}
|
||||
*/
|
||||
|
||||
if saved {
|
||||
// Inform user Live Photo has exported successfully
|
||||
self.exportMessage(success: saved, status: status!)
|
||||
caprturingQueue.async {
|
||||
self.recorder?.livePhoto(export: true) { ready, photo, status, saved in
|
||||
/*
|
||||
if ready {
|
||||
// Do something with the `photo` (PHLivePhotoPlus)
|
||||
}
|
||||
*/
|
||||
|
||||
if saved {
|
||||
// Inform user Live Photo has exported successfully
|
||||
self.exportMessage(success: saved, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,7 +179,7 @@ extension SKViewController {
|
||||
|
||||
if saved {
|
||||
// Inform user GIF image has exported successfully
|
||||
self.exportMessage(success: saved, status: status!)
|
||||
self.exportMessage(success: saved, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +193,9 @@ extension SKViewController {
|
||||
sender.setTitle("Stop", for: .normal)
|
||||
pauseBtn.setTitle("Pause", for: .normal)
|
||||
pauseBtn.isEnabled = true
|
||||
recorder?.record()
|
||||
recordingQueue.async {
|
||||
self.recorder?.record()
|
||||
}
|
||||
}else if recorder?.status == .recording {
|
||||
sender.setTitle("Record", for: .normal)
|
||||
pauseBtn.setTitle("Pause", for: .normal)
|
||||
@@ -199,14 +215,16 @@ extension SKViewController {
|
||||
pauseBtn.setTitle("Pause", for: .normal)
|
||||
pauseBtn.isEnabled = false
|
||||
recordBtn.isEnabled = false
|
||||
recorder?.record(forDuration: 10) { path in
|
||||
self.recorder?.export(video: path) { saved, status in
|
||||
DispatchQueue.main.sync {
|
||||
sender.setTitle("w/Duration", for: .normal)
|
||||
self.pauseBtn.setTitle("Pause", for: .normal)
|
||||
self.pauseBtn.isEnabled = false
|
||||
self.recordBtn.isEnabled = true
|
||||
self.exportMessage(success: saved, status: status)
|
||||
recordingQueue.async {
|
||||
self.recorder?.record(forDuration: 10) { path in
|
||||
self.recorder?.export(video: path) { saved, status in
|
||||
DispatchQueue.main.sync {
|
||||
sender.setTitle("w/Duration", for: .normal)
|
||||
self.pauseBtn.setTitle("Pause", for: .normal)
|
||||
self.pauseBtn.isEnabled = false
|
||||
self.recordBtn.isEnabled = true
|
||||
self.exportMessage(success: saved, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Ahmed Fathi Bekhit - me@ahmedbekhit.com
|
||||
Copyright 2017 Ahmed Fathi Bekhit, www.ahmedbekhit.com, me@ahmedbekhit.com
|
||||
|
||||
ARVideoKit is licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Swift Example
|
||||
This folder provides you an example project written in Swift that demonstrates the use of [**ARVideoKit**](https://github.com/AFathi/ARVideoKit) framework.
|
||||
|
||||
## Implementation
|
||||
1. `import ARVideoKit` in the application delegate `AppDelegate.swift` and a `UIViewController` with an `ARKit` scene.
|
||||
|
||||
2. In the application delegate `AppDelegate.swift`, add this 👇 in order to allow the framework access and identify the supported device orientations. **Recommended** if the application supports landscape orientations.
|
||||
```
|
||||
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
return ViewAR.orientation
|
||||
}
|
||||
```
|
||||
|
||||
3. In the selected `UIViewController` class, create an optional type [`RecordAR`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR) global variable.
|
||||
```
|
||||
var recorder:RecordAR?
|
||||
```
|
||||
|
||||
4. Initialize [`RecordAR`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR) with [`ARSCNView`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#init-arscenekitarscnview) or [`ARSKView`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#init-arspritekitarskview). **Recommended** to initialize in `viewDidLoad()`.
|
||||
|
||||
Initializing RecordAR with `ARSCNView`
|
||||
```
|
||||
recorder = RecordAR(ARSceneKit: sceneView)
|
||||
```
|
||||
Initializing RecordAR with `ARSKView`
|
||||
```
|
||||
recorder = RecordAR(ARSpriteKit: SKSceneView)
|
||||
```
|
||||
|
||||
5. Call the [`prepare()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-prepare_-configurationarconfiguration) method in `viewWillAppear(_ animated: Bool)`
|
||||
```
|
||||
let configuration = ARWorldTrackingConfiguration()
|
||||
recorder?.prepare(configuration)
|
||||
```
|
||||
|
||||
6. Call the [`rest()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-rest) method in `viewWillDisappear(_ animated: Bool)`
|
||||
```
|
||||
recorder?.rest()
|
||||
```
|
||||
|
||||
7. Call the [`record()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-record) method in the proper method to start recording.
|
||||
```
|
||||
@IBAction func startRecording(_ sender: UIButton) {
|
||||
recorder?.record()
|
||||
}
|
||||
```
|
||||
|
||||
8. Call the [`stopAndExport()`](https://github.com/AFathi/ARVideoKit/wiki/RecordAR#func-stopandexport_-finished-_-videopath-url-_-permissionstatusphauthorizationstatus-_-exportedbool---swiftvoid--nil) method in the proper method to stop recording.
|
||||
```
|
||||
@IBAction func stopRecording(_ sender: UIButton) {
|
||||
recorder?.stopAndExport()
|
||||
}
|
||||
```
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,612 @@
|
||||
// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
|
||||
#if !defined(__has_include)
|
||||
# define __has_include(x) 0
|
||||
#endif
|
||||
#if !defined(__has_attribute)
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
#if !defined(__has_feature)
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
#if !defined(__has_warning)
|
||||
# define __has_warning(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_include(<swift/objc-prologue.h>)
|
||||
# include <swift/objc-prologue.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wauto-import"
|
||||
#include <objc/NSObject.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(SWIFT_TYPEDEFS)
|
||||
# define SWIFT_TYPEDEFS 1
|
||||
# if __has_include(<uchar.h>)
|
||||
# include <uchar.h>
|
||||
# elif !defined(__cplusplus)
|
||||
typedef uint_least16_t char16_t;
|
||||
typedef uint_least32_t char32_t;
|
||||
# endif
|
||||
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PASTE)
|
||||
# define SWIFT_PASTE_HELPER(x, y) x##y
|
||||
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
|
||||
#endif
|
||||
#if !defined(SWIFT_METATYPE)
|
||||
# define SWIFT_METATYPE(X) Class
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_PROPERTY)
|
||||
# if __has_feature(objc_class_property)
|
||||
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
|
||||
# else
|
||||
# define SWIFT_CLASS_PROPERTY(...)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __has_attribute(objc_runtime_name)
|
||||
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
|
||||
#else
|
||||
# define SWIFT_RUNTIME_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(swift_name)
|
||||
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
|
||||
#else
|
||||
# define SWIFT_COMPILE_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(objc_method_family)
|
||||
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
|
||||
#else
|
||||
# define SWIFT_METHOD_FAMILY(X)
|
||||
#endif
|
||||
#if __has_attribute(noescape)
|
||||
# define SWIFT_NOESCAPE __attribute__((noescape))
|
||||
#else
|
||||
# define SWIFT_NOESCAPE
|
||||
#endif
|
||||
#if __has_attribute(warn_unused_result)
|
||||
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define SWIFT_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
#if __has_attribute(noreturn)
|
||||
# define SWIFT_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
# define SWIFT_NORETURN
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_EXTRA)
|
||||
# define SWIFT_CLASS_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_PROTOCOL_EXTRA)
|
||||
# define SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_EXTRA)
|
||||
# define SWIFT_ENUM_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS)
|
||||
# if __has_attribute(objc_subclassing_restricted)
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# else
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PROTOCOL)
|
||||
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_EXTENSION)
|
||||
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
|
||||
#endif
|
||||
|
||||
#if !defined(OBJC_DESIGNATED_INITIALIZER)
|
||||
# if __has_attribute(objc_designated_initializer)
|
||||
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
# else
|
||||
# define OBJC_DESIGNATED_INITIALIZER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_ATTR)
|
||||
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
|
||||
# define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open)))
|
||||
# else
|
||||
# define SWIFT_ENUM_ATTR
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM)
|
||||
# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# if __has_feature(generalized_swift_name)
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# else
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE)
|
||||
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE_MSG)
|
||||
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
|
||||
#endif
|
||||
#if !defined(SWIFT_AVAILABILITY)
|
||||
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED)
|
||||
# define SWIFT_DEPRECATED __attribute__((deprecated))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED_MSG)
|
||||
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
|
||||
#endif
|
||||
#if __has_feature(attribute_diagnose_if_objc)
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
|
||||
#else
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
|
||||
#endif
|
||||
#if __has_feature(modules)
|
||||
@import ObjectiveC;
|
||||
@import Photos;
|
||||
@import Foundation;
|
||||
@import CoreVideo;
|
||||
@import CoreMedia;
|
||||
@import UIKit;
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
|
||||
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
|
||||
#if __has_warning("-Wpragma-clang-attribute")
|
||||
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wnullability"
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# pragma push_macro("any")
|
||||
# undef any
|
||||
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="ARVideoKit",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
|
||||
# pragma pop_macro("any")
|
||||
#endif
|
||||
|
||||
/// Allows specifying the final video orientation.
|
||||
typedef SWIFT_ENUM(NSInteger, ARFrameMode) {
|
||||
ARFrameModeAuto = 0,
|
||||
ARFrameModeAspectFit = 1,
|
||||
/// Recommended for iPhone X
|
||||
ARFrameModeAspectFill = 2,
|
||||
};
|
||||
|
||||
/// Allows specifying the accepted orientaions in a <code>UIViewController</code> with AR scenes.
|
||||
typedef SWIFT_ENUM(NSInteger, ARInputViewOrientation) {
|
||||
/// Enables the portrait input views orientation.
|
||||
ARInputViewOrientationPortrait = 1,
|
||||
/// Enables the landscape left input views orientation.
|
||||
ARInputViewOrientationLandscapeLeft = 3,
|
||||
/// Enables the landscape right input views orientation.
|
||||
ARInputViewOrientationLandscapeRight = 4,
|
||||
};
|
||||
|
||||
/// Allows specifying the video rendering frame per second <code>FPS</code> rate.
|
||||
typedef SWIFT_ENUM(NSInteger, ARVideoFrameRate) {
|
||||
/// The framework automatically sets the most appropriate <code>FPS</code> based on the device support.
|
||||
ARVideoFrameRateAuto = 0,
|
||||
/// Sets the <code>FPS</code> to 30 frames per second.
|
||||
ARVideoFrameRateFps30 = 30,
|
||||
/// Sets the <code>FPS</code> to 60 frames per second.
|
||||
ARVideoFrameRateFps60 = 60,
|
||||
};
|
||||
|
||||
/// Allows specifying the final video orientation.
|
||||
typedef SWIFT_ENUM(NSInteger, ARVideoOrientation) {
|
||||
/// The framework automatically sets the video orientation based on the active <code>ARInputViewOrientation</code> orientations.
|
||||
ARVideoOrientationAuto = 0,
|
||||
/// Sets the video orientation to always portrait.
|
||||
ARVideoOrientationAlwaysPortrait = 1,
|
||||
/// Sets the video orientation to always landscape.
|
||||
ARVideoOrientationAlwaysLandscape = 2,
|
||||
};
|
||||
|
||||
|
||||
/// A class that configures the Augmented Reality View orientations.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_CLASS("_TtC10ARVideoKit6ARView") SWIFT_AVAILABILITY(ios,introduced=11.0)
|
||||
@interface ARView : NSObject
|
||||
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
|
||||
+ (nonnull instancetype)new SWIFT_DEPRECATED_MSG("-init is unavailable");
|
||||
@end
|
||||
|
||||
@class NSCoder;
|
||||
|
||||
/// A <code>PHLivePhotoPlus</code> object is a <code>PHLivePhoto</code> sub-class that contains objects to allow manual exporting of a live photo.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_CLASS("_TtC10ARVideoKit15PHLivePhotoPlus") SWIFT_AVAILABILITY(ios,introduced=9.1)
|
||||
@interface PHLivePhotoPlus : PHLivePhoto
|
||||
/// A <code>PHLivePhoto</code> object that returns the Live Photo content from <code>PHLivePhotoPlus</code>.
|
||||
@property (nonatomic, strong) PHLivePhoto * _Nullable livePhoto;
|
||||
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
|
||||
- (nonnull instancetype)initWithPhoto:(PHLivePhoto * _Nonnull)photo OBJC_DESIGNATED_INITIALIZER;
|
||||
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@protocol RecordARDelegate;
|
||||
@protocol RenderARDelegate;
|
||||
enum RecordARStatus : NSInteger;
|
||||
enum RecordARMicrophoneStatus : NSInteger;
|
||||
enum RecordARMicrophonePermission : NSInteger;
|
||||
@class ARSCNView;
|
||||
@class ARSKView;
|
||||
@class SCNView;
|
||||
@class UIImage;
|
||||
|
||||
/// This class renders the <code>ARSCNView</code> or <code>ARSKView</code> content with the device’s camera stream to generate a video 📹, photo 🌄, live photo 🎇 or GIF 🎆.
|
||||
/// author:
|
||||
/// 🤓 Ahmed Fathi Bekhit © 2017
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_CLASS("_TtC10ARVideoKit8RecordAR") SWIFT_AVAILABILITY(ios,introduced=11.0)
|
||||
@interface RecordAR : ARView
|
||||
/// An object that passes the AR recorder errors and status in the protocol methods.
|
||||
@property (nonatomic, strong) id <RecordARDelegate> _Nullable delegate;
|
||||
/// An object that passes the AR rendered content in the protocol method.
|
||||
@property (nonatomic, strong) id <RenderARDelegate> _Nullable renderAR;
|
||||
/// An object that returns the AR recorder current status.
|
||||
@property (nonatomic, readonly) enum RecordARStatus status;
|
||||
/// An object that returns the current Microphone status.
|
||||
@property (nonatomic, readonly) enum RecordARMicrophoneStatus micStatus;
|
||||
/// An object that allow customizing when to ask for Microphone permission, if needed. Default is <code>.auto</code>.
|
||||
@property (nonatomic) enum RecordARMicrophonePermission requestMicPermission;
|
||||
/// An object that allow customizing the video frame per second rate. Default is <code>.auto</code>.
|
||||
@property (nonatomic) enum ARVideoFrameRate fps;
|
||||
/// An object that allow customizing the video orientation. Default is <code>.auto</code>.
|
||||
@property (nonatomic) enum ARVideoOrientation videoOrientation;
|
||||
/// An object that allow customizing the AR content mode. Default is <code>.auto</code>.
|
||||
@property (nonatomic) enum ARFrameMode contentMode;
|
||||
/// A boolean that enables or disables AR content rendering before recording for image & video processing. Default is <code>true</code>.
|
||||
@property (nonatomic) BOOL onlyRenderWhileRecording;
|
||||
/// A boolean that enables or disables audio recording. Default is <code>true</code>.
|
||||
@property (nonatomic) BOOL enableAudio;
|
||||
/// A boolean that enables or disables audio <code>mixWithOthers</code> if audio recording is enabled. This allows playing music and recording audio at the same time. Default is <code>true</code>.
|
||||
@property (nonatomic) BOOL enableMixWithOthers;
|
||||
/// A boolean that enables or disables adjusting captured media for sharing online. Default is <code>true</code>.
|
||||
@property (nonatomic) BOOL adjustVideoForSharing;
|
||||
/// A boolean that enables or disables adjusting captured GIFs for sharing online. Default is <code>true</code>.
|
||||
@property (nonatomic) BOOL adjustGIFForSharing;
|
||||
/// A boolean that enables or disables clearing cached media after exporting to Camera Roll. Default is <code>true</code>.
|
||||
@property (nonatomic) BOOL deleteCacheWhenExported;
|
||||
/// A boolean that enables or disables using envronment light rendering. Default is <code>false</code>.
|
||||
@property (nonatomic) BOOL enableAdjsutEnvironmentLighting;
|
||||
/// Initialize 🌞🍳 <code>RecordAR</code> with an <code>ARSCNView</code> 🚀.
|
||||
- (nullable instancetype)initWithARSceneKit:(ARSCNView * _Nonnull)ARSceneKit OBJC_DESIGNATED_INITIALIZER;
|
||||
/// Initialize 🌞🍳 <code>RecordAR</code> with an <code>ARSKView</code> 👾.
|
||||
- (nullable instancetype)initWithARSpriteKit:(ARSKView * _Nonnull)ARSpriteKit OBJC_DESIGNATED_INITIALIZER;
|
||||
/// Initialize 🌞🍳 <code>RecordAR</code> with an <code>SCNView</code> 🚀.
|
||||
- (nullable instancetype)initWithSceneKit:(SCNView * _Nonnull)SceneKit OBJC_DESIGNATED_INITIALIZER;
|
||||
/// A method that renders a photo 🌄 and returns it as <code>UIImage</code>.
|
||||
- (UIImage * _Nonnull)photo SWIFT_WARN_UNUSED_RESULT;
|
||||
/// A method that renders a <code>PHLivePhoto</code> 🎇 and returns <code>PHLivePhotoPlus</code> in the completion handler.
|
||||
/// In order to manually export the <code>PHLivePhotoPlus</code>, use <code>export(live photo:PHLivePhotoPlus)</code> method.
|
||||
/// \param export A boolean that enables or disables automatically exporting the <code>PHLivePhotoPlus</code> when ready.
|
||||
///
|
||||
/// \param finished A block that will be called when Live Photo rendering is complete.
|
||||
/// The block returns the following parameters:
|
||||
/// <code>status</code>
|
||||
/// A boolean that returns <code>true</code> when a <code>PHLivePhotoPlus</code> is successfully rendered. Otherwise, it returns <code>false</code>.
|
||||
/// <code>livePhoto</code>
|
||||
/// A <code>PHLivePhotoPlus</code> object that contains a <code>PHLivePhoto</code> and other objects to allow manual exporting of a live photo.
|
||||
/// <code>permissionStatus</code>
|
||||
/// A <code>PHAuthorizationStatus</code> object that returns the current application’s status for exporting media to the Photo Library. It returns <code>nil</code> if the <code>export</code> parameter is <code>false</code>.
|
||||
/// <code>exported</code>
|
||||
/// A boolean that returns <code>true</code> when a <code>PHLivePhotoPlus</code> is successfully exported to the Photo Library. Otherwise, it returns <code>false</code>.
|
||||
///
|
||||
- (void)livePhotoWithExport:(BOOL)export_ :(void (^ _Nullable)(BOOL, PHLivePhotoPlus * _Nonnull, PHAuthorizationStatus, BOOL))finished;
|
||||
/// A method that generates a GIF 🎆 image and returns its local path (<code>URL</code>) in the completion handler.
|
||||
/// In order to manually export the GIF image <code>URL</code>, use <code>func export(image path:URL)</code> method.
|
||||
/// \param duration A <code>TimeInterval</code> object that can be set to the duration specified in seconds.
|
||||
///
|
||||
/// \param export A boolean that enables or disables automatically exporting the GIF image <code>URL</code> when ready.
|
||||
///
|
||||
/// \param finished A block that will be called when GIF image rendering is complete.
|
||||
/// The block returns the following parameters:
|
||||
/// <code>status</code>
|
||||
/// A boolean that returns <code>true</code> when a GIF image <code>URL</code> is successfully rendered. Otherwise, it returns <code>false</code>.
|
||||
/// <code>gifPath</code>
|
||||
/// A <code>URL</code> object that contains the local file path of the GIF image to allow manual exporting of a GIF.
|
||||
/// <code>permissionStatus</code>
|
||||
/// A <code>PHAuthorizationStatus</code> object that returns the current application’s status for exporting media to the Photo Library. It returns <code>nil</code> if the <code>export</code> parameter is <code>false</code>.
|
||||
/// <code>exported</code>
|
||||
/// A boolean that returns <code>true</code> when a GIF image <code>URL</code> is successfully exported to the Photo Library. Otherwise, it returns <code>false</code>.
|
||||
///
|
||||
- (void)gifForDuration:(NSTimeInterval)duration export:(BOOL)export_ :(void (^ _Nullable)(BOOL, NSURL * _Nonnull, PHAuthorizationStatus, BOOL))finished;
|
||||
/// A method that starts or resumes ⏯ recording a video 📹.
|
||||
- (void)record;
|
||||
/// A method that starts recording a video 📹 with a specified duration ⏳ in seconds.
|
||||
/// In order to stop the recording before the specified duration, simply call <code>stop()</code> or <code>stopAndExport()</code> methods.
|
||||
/// warning:
|
||||
/// You CAN NOT <code>pause()</code> video recording when a duration is specified.
|
||||
/// \param duration A <code>TimeInterval</code> object that can be set to the duration specified in seconds.
|
||||
///
|
||||
/// \param finished A block that will be called when the specified <code>duration</code> has ended.
|
||||
/// The block returns the following parameter:
|
||||
/// <code>videoPath</code>
|
||||
/// A <code>URL</code> object that contains the local file path of the video to allow manual exporting or preview of the video.
|
||||
///
|
||||
- (void)recordForDuration:(NSTimeInterval)duration :(void (^ _Nullable)(NSURL * _Nonnull))finished;
|
||||
/// A method that pauses recording a video ⏸📹.
|
||||
/// In order to resume recording, simply call the <code>record()</code> method.
|
||||
- (void)pause;
|
||||
/// A method that stops ⏹ recording a video 📹 and exports it to the Photo Library 📲💾.
|
||||
/// \param finished A block that will be called when the export process is complete.
|
||||
/// The block returns the following parameters:
|
||||
/// <code>videoPath</code>
|
||||
/// A <code>URL</code> object that contains the local file path of the video to allow manual exporting or preview of the video.
|
||||
/// <code>permissionStatus</code>
|
||||
/// A <code>PHAuthorizationStatus</code> object that returns the current application’s status for exporting media to the Photo Library.
|
||||
/// <code>exported</code>
|
||||
/// A boolean that returns <code>true</code> when a video is successfully exported to the Photo Library. Otherwise, it returns <code>false</code>.
|
||||
///
|
||||
- (void)stopAndExport:(void (^ _Nullable)(NSURL * _Nonnull, PHAuthorizationStatus, BOOL))finished;
|
||||
/// A method that stops ⏹ recording a video 📹 and returns the video path in the completion handler.
|
||||
/// \param finished A block that will be called when the specified <code>duration</code> has ended.
|
||||
/// The block returns the following parameter:
|
||||
/// <code>videoPath</code>
|
||||
/// A <code>URL</code> object that contains the local file path of the video to allow manual exporting or preview of the video.
|
||||
///
|
||||
- (void)stop:(void (^ _Nullable)(NSURL * _Nonnull))finished;
|
||||
/// A method that exports a video 📹 file path to the Photo Library 📲💾.
|
||||
/// \param path A <code>URL</code> object that can be set to a local video file path to export to the Photo Library.
|
||||
///
|
||||
/// \param finished A block that will be called when the export process is complete.
|
||||
/// The block returns the following parameters:
|
||||
/// <code>exported</code>
|
||||
/// A boolean that returns <code>true</code> when a video is successfully exported to the Photo Library. Otherwise, it returns <code>false</code>.
|
||||
/// <code>permissionStatus</code>
|
||||
/// A <code>PHAuthorizationStatus</code> object that returns the current application’s status for exporting media to the Photo Library.
|
||||
///
|
||||
- (void)exportWithVideo:(NSURL * _Nonnull)path :(void (^ _Nullable)(BOOL, PHAuthorizationStatus))finished;
|
||||
/// A method that exports any image 🌄/🎆 (including gif, jpeg, and png) to the Photo Library 📲💾.
|
||||
/// \param path A <code>URL</code> object that can be set to a local image file path to export to the Photo Library.
|
||||
///
|
||||
/// \param UIImage A <code>UIImage</code> object.
|
||||
///
|
||||
/// \param finished A block that will be called when the export process is complete.
|
||||
/// The block returns the following parameters:
|
||||
/// <code>exported</code>
|
||||
/// A boolean that returns <code>true</code> when an image is successfully exported to the Photo Library. Otherwise, it returns <code>false</code>.
|
||||
/// <code>permissionStatus</code>
|
||||
/// A <code>PHAuthorizationStatus</code> object that returns the current application’s status for exporting media to the Photo Library.
|
||||
///
|
||||
- (void)exportWithImage:(NSURL * _Nullable)path UIImage:(UIImage * _Nullable)UIImage :(void (^ _Nullable)(BOOL, PHAuthorizationStatus))finished;
|
||||
/// A method that exports a <code>PHLivePhotoPlus</code> 🎇 object to the Photo Library 📲💾.
|
||||
/// The block returns the following parameters:
|
||||
/// <code>exported</code>
|
||||
/// A boolean that returns <code>true</code> when the Live Photo is successfully exported to the Photo Library. Otherwise, it returns <code>false</code>.
|
||||
/// <code>permissionStatus</code>
|
||||
/// A <code>PHAuthorizationStatus</code> object that returns the current application’s status for exporting media to the Photo Library.
|
||||
/// \param photo A <code>PHLivePhotoPlus</code> object that can be set to the returned <code>PHLivePhotoPlus</code> object in the <code>livePhoto(export:Bool, _ finished:{})</code> method.
|
||||
///
|
||||
/// \param finished A block that will be called when the export process is complete.
|
||||
///
|
||||
- (void)exportWithLive:(PHLivePhotoPlus * _Nonnull)photo :(void (^ _Nullable)(BOOL, PHAuthorizationStatus))finished;
|
||||
/// A method that requsts microphone 🎙 permission manually, if micPermission is set to <code>manual</code>.
|
||||
/// The block returns the following parameter:
|
||||
/// <code>status</code>
|
||||
/// A boolean that returns <code>true</code> when a the Microphone access is permitted. Otherwise, it returns <code>false</code>.
|
||||
/// \param finished A block that will be called when the audio permission is requested.
|
||||
///
|
||||
- (void)requestMicrophonePermission:(void (^ _Nullable)(BOOL))finished;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@class ARConfiguration;
|
||||
|
||||
SWIFT_AVAILABILITY(ios,introduced=11.0)
|
||||
@interface RecordAR (SWIFT_EXTENSION(ARVideoKit))
|
||||
/// A method that prepares the video recorder with <code>ARConfiguration</code> 📝.
|
||||
/// Recommended to use in the <code>UIViewController</code>’s method <code>func viewWillAppear(_ animated: Bool)</code>
|
||||
/// \param configuration An object that defines motion and scene tracking behaviors for the session.
|
||||
///
|
||||
- (void)prepare:(ARConfiguration * _Nullable)configuration;
|
||||
/// A method that switches off the orientation lock used in a <code>UIViewController</code> with AR scenes 📐😴.
|
||||
/// Recommended to use in the <code>UIViewController</code>’s method <code>func viewWillDisappear(_ animated: Bool)</code>.
|
||||
- (void)rest;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
/// The recorder protocol.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_PROTOCOL("_TtP10ARVideoKit16RecordARDelegate_") SWIFT_AVAILABILITY(ios,introduced=11.0)
|
||||
@protocol RecordARDelegate
|
||||
/// A protocol method that is triggered when a recorder ends recording.
|
||||
/// \param path A <code>URL</code> object that returns the video file path.
|
||||
///
|
||||
/// \param noError A boolean that returns true when the recorder ends without errors. Otherwise, it returns false.
|
||||
///
|
||||
- (void)recorderWithDidEndRecording:(NSURL * _Nonnull)path with:(BOOL)noError;
|
||||
/// A protocol method that is triggered when a recorder fails recording.
|
||||
/// \param error An <code>Error</code> object that returns the error value.
|
||||
///
|
||||
/// \param status A string that returns the reason of the recorder failure in a string literal format.
|
||||
///
|
||||
- (void)recorderWithDidFailRecording:(NSError * _Nullable)error and:(NSString * _Nonnull)status;
|
||||
/// A protocol method that is triggered when the application will resign active.
|
||||
/// note:
|
||||
/// Check <a href="https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622950-applicationwillresignactive">applicationWillResignActive(_:)</a> for more information.
|
||||
/// \param status A <code>RecordARStatus</code> object that returns the AR recorder current status.
|
||||
///
|
||||
- (void)recorderWithWillEnterBackground:(enum RecordARStatus)status;
|
||||
@end
|
||||
|
||||
/// Allows specifying when to request Microphone access.
|
||||
typedef SWIFT_ENUM(NSInteger, RecordARMicrophonePermission) {
|
||||
/// The framework automatically requests Microphone access when needed.
|
||||
RecordARMicrophonePermissionAuto = 0,
|
||||
/// Allows manual permission request.
|
||||
RecordARMicrophonePermissionManual = 1,
|
||||
};
|
||||
|
||||
/// An object that returns the current Microphone status.
|
||||
typedef SWIFT_ENUM(NSInteger, RecordARMicrophoneStatus) {
|
||||
RecordARMicrophoneStatusUnknown = 0,
|
||||
RecordARMicrophoneStatusEnabled = 1,
|
||||
RecordARMicrophoneStatusDisabled = 2,
|
||||
};
|
||||
|
||||
/// An object that returns the AR recorder current status.
|
||||
typedef SWIFT_ENUM(NSInteger, RecordARStatus) {
|
||||
/// The current status of the recorder is unknown.
|
||||
RecordARStatusUnknown = 0,
|
||||
/// The current recorder is ready to record.
|
||||
RecordARStatusReadyToRecord = 1,
|
||||
/// The current recorder is recording.
|
||||
RecordARStatusRecording = 2,
|
||||
/// The current recorder is paused.
|
||||
RecordARStatusPaused = 3,
|
||||
};
|
||||
|
||||
|
||||
/// The renderer protocol.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_PROTOCOL("_TtP10ARVideoKit16RenderARDelegate_") SWIFT_AVAILABILITY(ios,introduced=11.0)
|
||||
@protocol RenderARDelegate
|
||||
/// A protocol method that is triggered when a frame renders the <code>ARSCNView</code> or <code>ARSKView</code> content with the device’s camera stream.
|
||||
/// \param buffer A <code>CVPixelBuffer</code> object that returns the rendered buffer.
|
||||
///
|
||||
/// \param time A <code>CMTime</code> object that returns the time a buffer was rendered with.
|
||||
///
|
||||
/// \param rawBuffer A <code>CVPixelBuffer</code> object that returns the raw buffer.
|
||||
///
|
||||
- (void)frameWithDidRender:(CVPixelBufferRef _Nonnull)buffer with:(CMTime)time using:(CVPixelBufferRef _Nonnull)rawBuffer;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// A struct that identifies the application <code>UIViewController</code>s and their orientations.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_CLASS("_TtC10ARVideoKit6ViewAR") SWIFT_AVAILABILITY(ios,introduced=11.0)
|
||||
@interface ViewAR : NSObject
|
||||
/// A <code>UIInterfaceOrientationMask</code> object that returns the recommended orientations for a <code>UIViewController</code> with AR scenes.
|
||||
/// Recommended to return in the application delegate method <code>func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask</code>.
|
||||
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly) UIInterfaceOrientationMask orientation;)
|
||||
+ (UIInterfaceOrientationMask)orientation SWIFT_WARN_UNUSED_RESULT;
|
||||
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# pragma clang attribute pop
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
+1
-2
@@ -2,12 +2,11 @@
|
||||
// ARVideoKit.h
|
||||
// ARVideoKit
|
||||
//
|
||||
// Created by Ahmed Bekhit on 11/5/17.
|
||||
// Created by Ahmed Bekhit on 10/31/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for ARVideoKit.
|
||||
FOUNDATION_EXPORT double ARVideoKitVersionNumber;
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Ahmed Fathi Bekhit, www.ahmedbekhit.com, me@ahmedbekhit.com
|
||||
|
||||
ARVideoKit is licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -1,220 +0,0 @@
|
||||
// Generated by Apple Swift version 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
|
||||
#if !defined(__has_include)
|
||||
# define __has_include(x) 0
|
||||
#endif
|
||||
#if !defined(__has_attribute)
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
#if !defined(__has_feature)
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
#if !defined(__has_warning)
|
||||
# define __has_warning(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# define SWIFT_STRINGIFY(str) #str
|
||||
# define SWIFT_MODULE_NAMESPACE_PUSH(module_name) _Pragma(SWIFT_STRINGIFY(clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in=module_name, generated_declaration))), apply_to=any(function, enum, objc_interface, objc_category, objc_protocol))))
|
||||
# define SWIFT_MODULE_NAMESPACE_POP _Pragma("clang attribute pop")
|
||||
#else
|
||||
# define SWIFT_MODULE_NAMESPACE_PUSH(module_name)
|
||||
# define SWIFT_MODULE_NAMESPACE_POP
|
||||
#endif
|
||||
|
||||
#if __has_include(<swift/objc-prologue.h>)
|
||||
# include <swift/objc-prologue.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wauto-import"
|
||||
#include <objc/NSObject.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(SWIFT_TYPEDEFS)
|
||||
# define SWIFT_TYPEDEFS 1
|
||||
# if __has_include(<uchar.h>)
|
||||
# include <uchar.h>
|
||||
# elif !defined(__cplusplus) || __cplusplus < 201103L
|
||||
typedef uint_least16_t char16_t;
|
||||
typedef uint_least32_t char32_t;
|
||||
# endif
|
||||
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PASTE)
|
||||
# define SWIFT_PASTE_HELPER(x, y) x##y
|
||||
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
|
||||
#endif
|
||||
#if !defined(SWIFT_METATYPE)
|
||||
# define SWIFT_METATYPE(X) Class
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_PROPERTY)
|
||||
# if __has_feature(objc_class_property)
|
||||
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
|
||||
# else
|
||||
# define SWIFT_CLASS_PROPERTY(...)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __has_attribute(objc_runtime_name)
|
||||
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
|
||||
#else
|
||||
# define SWIFT_RUNTIME_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(swift_name)
|
||||
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
|
||||
#else
|
||||
# define SWIFT_COMPILE_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(objc_method_family)
|
||||
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
|
||||
#else
|
||||
# define SWIFT_METHOD_FAMILY(X)
|
||||
#endif
|
||||
#if __has_attribute(noescape)
|
||||
# define SWIFT_NOESCAPE __attribute__((noescape))
|
||||
#else
|
||||
# define SWIFT_NOESCAPE
|
||||
#endif
|
||||
#if __has_attribute(warn_unused_result)
|
||||
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define SWIFT_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
#if __has_attribute(noreturn)
|
||||
# define SWIFT_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
# define SWIFT_NORETURN
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_EXTRA)
|
||||
# define SWIFT_CLASS_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_PROTOCOL_EXTRA)
|
||||
# define SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_EXTRA)
|
||||
# define SWIFT_ENUM_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS)
|
||||
# if __has_attribute(objc_subclassing_restricted)
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# else
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PROTOCOL)
|
||||
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_EXTENSION)
|
||||
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
|
||||
#endif
|
||||
|
||||
#if !defined(OBJC_DESIGNATED_INITIALIZER)
|
||||
# if __has_attribute(objc_designated_initializer)
|
||||
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
# else
|
||||
# define OBJC_DESIGNATED_INITIALIZER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_ATTR)
|
||||
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
|
||||
# define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open)))
|
||||
# else
|
||||
# define SWIFT_ENUM_ATTR
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM)
|
||||
# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# if __has_feature(generalized_swift_name)
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# else
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE)
|
||||
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE_MSG)
|
||||
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
|
||||
#endif
|
||||
#if !defined(SWIFT_AVAILABILITY)
|
||||
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED)
|
||||
# define SWIFT_DEPRECATED __attribute__((deprecated))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED_MSG)
|
||||
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
|
||||
#endif
|
||||
#if __has_feature(attribute_diagnose_if_objc)
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
|
||||
#else
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
|
||||
#endif
|
||||
#if __has_feature(modules)
|
||||
@import Photos;
|
||||
@import UIKit;
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
|
||||
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
|
||||
#if __has_warning("-Wpragma-clang-attribute")
|
||||
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wnullability"
|
||||
|
||||
SWIFT_MODULE_NAMESPACE_PUSH("ARVideoKit")
|
||||
@class NSCoder;
|
||||
|
||||
/// A <code>PHLivePhotoPlus</code> object is a <code>PHLivePhoto</code> sub-class that contains objects to allow manual exporting of a live photo.
|
||||
/// author:
|
||||
/// Ahmed Fathi Bekhit
|
||||
/// <ul>
|
||||
/// <li>
|
||||
/// <a href="http://github.com/AFathi">Github</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://ahmedbekhit.com">Website</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="http://twitter.com/iAFapps">Twitter</a>
|
||||
/// </li>
|
||||
/// <li>
|
||||
/// <a href="mailto:me@ahmedbekhit.com">Email</a>
|
||||
/// </li>
|
||||
/// </ul>
|
||||
SWIFT_CLASS("_TtC10ARVideoKit15PHLivePhotoPlus")
|
||||
@interface PHLivePhotoPlus : PHLivePhoto
|
||||
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
|
||||
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SWIFT_MODULE_NAMESPACE_POP
|
||||
#pragma clang diagnostic pop
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// ARVideoKit.h
|
||||
// ARVideoKit
|
||||
//
|
||||
// Created by Ahmed Bekhit on 11/5/17.
|
||||
// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for ARVideoKit.
|
||||
FOUNDATION_EXPORT double ARVideoKitVersionNumber;
|
||||
|
||||
//! Project version string for ARVideoKit.
|
||||
FOUNDATION_EXPORT const unsigned char ARVideoKitVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <ARVideoKit/PublicHeader.h>
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user