├── MyTransparentVideoExample ├── playdoh-bat.mp4 ├── AVAsset+VideoSize.swift ├── AlphaFrameFilter.metal ├── CIKernel+DefaultMetalLibrary.swift ├── CIImage+VerticalSplit.swift ├── Info.plist ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── AppDelegate.swift ├── AVPlayerView.swift ├── ViewController.swift └── AlphaFrameFilter.swift ├── MyTransparentVideoExample.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ └── MyTransparentVideoExample.xcscheme └── project.pbxproj └── .gitignore /MyTransparentVideoExample/playdoh-bat.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinfasquel/MyTransparentVideoExample/HEAD/MyTransparentVideoExample/playdoh-bat.mp4 -------------------------------------------------------------------------------- /MyTransparentVideoExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MyTransparentVideoExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/AVAsset+VideoSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVAsset+VideoSize.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin Fasquel on 22/03/2020. 6 | // Copyright © 2020 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | 11 | extension AVAsset { 12 | var videoSize: CGSize { tracks(withMediaType: .video).first?.naturalSize ?? .zero } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/AlphaFrameFilter.metal: -------------------------------------------------------------------------------- 1 | // 2 | // AlphaFrameFilter.metal 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin Fasquel on 22/03/2020. 6 | // Copyright © 2020 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | #include 10 | #include // includes CIKernelMetalLib.h 11 | 12 | extern "C" { 13 | namespace coreimage { 14 | float4 alphaFrame(sampler source, sampler mask) { 15 | float4 color = source.sample(source.coord()); 16 | float opacity = mask.sample(mask.coord()).r; 17 | return float4(color.rgb, opacity); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/CIKernel+DefaultMetalLibrary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIKernelExtension.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin Fasquel on 22/03/2020. 6 | // Copyright © 2020 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import CoreImage 10 | import Metal 11 | 12 | private func defaultMetalLibrary() throws -> Data { 13 | let url = Bundle.main.url(forResource: "default", withExtension: "metallib")! 14 | return try Data(contentsOf: url) 15 | } 16 | 17 | extension CIKernel { 18 | /// Init CI kernel with just a `functionName` directly from default metal library 19 | convenience init(functionName: String) throws { 20 | let metalLibrary = try defaultMetalLibrary() 21 | try self.init(functionName: functionName, fromMetalLibraryData: metalLibrary) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/CIImage+VerticalSplit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIImage+Split.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin Fasquel on 27/03/2020. 6 | // Copyright © 2020 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import CoreImage 10 | 11 | extension CIImage { 12 | 13 | typealias VerticalSplit = (topImage: CIImage, bottomImage: CIImage) 14 | 15 | func verticalSplit() -> VerticalSplit { 16 | let outputExtent = self.extent.applying(CGAffineTransform(scaleX: 1.0, y: 0.5)) 17 | 18 | // Get the top region according to Core Image coordinate system, (0,0) being bottom left 19 | let translate = CGAffineTransform(translationX: 0, y: outputExtent.height) 20 | let topRegion = outputExtent.applying(translate) 21 | var topImage = self.cropped(to: topRegion) 22 | // Translate topImage back to origin 23 | topImage = topImage.transformed(by: translate.inverted()) 24 | 25 | let bottomRegion = outputExtent 26 | let bottomImage = self.cropped(to: bottomRegion) 27 | 28 | return (topImage, bottomImage) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /MyTransparentVideoExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin on 27/10/2017. 6 | // Copyright © 2017 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | func applicationWillResignActive(_ application: UIApplication) { 22 | // 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. 23 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 24 | } 25 | 26 | func applicationDidEnterBackground(_ application: UIApplication) { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | func applicationWillEnterForeground(_ application: UIApplication) { 32 | // 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. 33 | } 34 | 35 | func applicationDidBecomeActive(_ application: UIApplication) { 36 | // 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. 37 | } 38 | 39 | func applicationWillTerminate(_ application: UIApplication) { 40 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 41 | } 42 | 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /MyTransparentVideoExample.xcodeproj/xcshareddata/xcschemes/MyTransparentVideoExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/AVPlayerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVPlayerView.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin on 27/10/2017. 6 | // Copyright © 2017 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | import UIKit 11 | 12 | public class AVPlayerView: UIView { 13 | 14 | deinit { 15 | playerItem = nil 16 | } 17 | 18 | public override class var layerClass: AnyClass { 19 | return AVPlayerLayer.self 20 | } 21 | 22 | public var playerLayer: AVPlayerLayer { 23 | return layer as! AVPlayerLayer 24 | } 25 | 26 | public private(set) var player: AVPlayer? { 27 | set { playerLayer.player = newValue } 28 | get { return playerLayer.player } 29 | } 30 | 31 | private var playerItemStatusObserver: NSKeyValueObservation? 32 | 33 | private(set) var playerItem: AVPlayerItem? = nil { 34 | didSet { 35 | // If `isLoopingEnabled` is called before the AVPlayer was set 36 | setupLooping() 37 | } 38 | } 39 | 40 | public func loadPlayerItem(_ playerItem: AVPlayerItem, onReady: ((Result) -> Void)? = nil) { 41 | let player = AVPlayer(playerItem: playerItem) 42 | 43 | self.player = player 44 | self.playerItem = playerItem 45 | 46 | guard let completion = onReady else { 47 | playerItemStatusObserver = nil 48 | return 49 | } 50 | 51 | playerItemStatusObserver = playerItem.observe(\.status) { [weak self] item, _ in 52 | switch item.status { 53 | case .failed: 54 | completion(.failure(item.error!)) 55 | case .readyToPlay: 56 | completion(.success(player)) 57 | // Stop observing 58 | self?.playerItemStatusObserver = nil 59 | case .unknown: 60 | break 61 | @unknown default: 62 | fatalError() 63 | } 64 | } 65 | } 66 | 67 | // MARK: - Looping Handler 68 | 69 | /// When set to `true`, the player view automatically adds an observer on its AVPlayer, 70 | /// and it will play again from start every time playback ends. 71 | /// * Warning: This will not result in a smooth video loop. 72 | public var isLoopingEnabled: Bool = false { 73 | didSet { setupLooping() } 74 | } 75 | 76 | private var didPlayToEndTimeObsever: NSObjectProtocol? = nil { 77 | willSet(newObserver) { 78 | // When updating didPlayToEndTimeObserver, 79 | // automatically remove its previous value from the Notification Center 80 | if let observer = didPlayToEndTimeObsever, didPlayToEndTimeObsever !== newObserver { 81 | NotificationCenter.default.removeObserver(observer) 82 | } 83 | } 84 | } 85 | 86 | private func setupLooping() { 87 | guard let playerItem = self.playerItem, let player = self.player else { 88 | return 89 | } 90 | 91 | guard isLoopingEnabled else { 92 | didPlayToEndTimeObsever = nil 93 | return 94 | } 95 | 96 | didPlayToEndTimeObsever = NotificationCenter.default.addObserver( 97 | forName: .AVPlayerItemDidPlayToEndTime, object: playerItem, queue: nil, using: { _ in 98 | player.seek(to: CMTime.zero) { _ in 99 | player.play() 100 | } 101 | }) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin on 27/10/2017. 6 | // Copyright © 2017 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | import UIKit 11 | import os.log 12 | 13 | class ViewController: UIViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | let videoSize = CGSize(width: 300, height: 187) 19 | let playerView = AVPlayerView(frame: CGRect(origin: .zero, size: videoSize)) 20 | view.addSubview(playerView) 21 | 22 | // Use Auto Layout anchors to center our playerView 23 | playerView.translatesAutoresizingMaskIntoConstraints = false 24 | playerView.widthAnchor.constraint(equalToConstant: videoSize.width).isActive = true 25 | playerView.heightAnchor.constraint(equalToConstant: videoSize.height).isActive = true 26 | playerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 27 | playerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true 28 | 29 | // Setup our playerLayer to hold a pixel buffer format with "alpha" 30 | let playerLayer: AVPlayerLayer = playerView.playerLayer 31 | playerLayer.pixelBufferAttributes = [ 32 | (kCVPixelBufferPixelFormatTypeKey as String): kCVPixelFormatType_32BGRA] 33 | 34 | // Our AVPlayerLayer has a default backgroundColor to nil 35 | // Set a backgroundColor the viewController's view 36 | view.backgroundColor = .gray 37 | 38 | // Setup looping on our video 39 | playerView.isLoopingEnabled = true 40 | 41 | // Load our player item 42 | let itemUrl: URL = Bundle.main.url(forResource: "playdoh-bat", withExtension: "mp4")! 43 | let playerItem = createTransparentItem(url: itemUrl) 44 | 45 | playerView.loadPlayerItem(playerItem) { [weak self] result in 46 | switch result { 47 | case .failure(let error): 48 | return print("Something went wrong when loading our video", error) 49 | 50 | case .success(let player): 51 | // Finally, we can start playing 52 | player.play() 53 | // Animate background 54 | self?.animateBackgroundColor() 55 | } 56 | 57 | } 58 | } 59 | 60 | override func didReceiveMemoryWarning() { 61 | super.didReceiveMemoryWarning() 62 | // Dispose of any resources that can be recreated. 63 | } 64 | 65 | // MARK: - Player Item Configuration 66 | 67 | func createTransparentItem(url: URL) -> AVPlayerItem { 68 | let asset = AVAsset(url: url) 69 | let playerItem = AVPlayerItem(asset: asset) 70 | // Set the video so that seeking also renders with transparency 71 | playerItem.seekingWaitsForVideoCompositionRendering = true 72 | // Apply a video composition (which applies our custom filter) 73 | playerItem.videoComposition = createVideoComposition(for: asset) 74 | return playerItem 75 | } 76 | 77 | func createVideoComposition(for asset: AVAsset) -> AVVideoComposition { 78 | let filter = AlphaFrameFilter(renderingMode: .builtInFilter) 79 | let composition = AVMutableVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in 80 | do { 81 | let (inputImage, maskImage) = request.sourceImage.verticalSplit() 82 | let outputImage = try filter.process(inputImage, mask: maskImage) 83 | return request.finish(with: outputImage, context: nil) 84 | } catch { 85 | os_log("Video composition error: %s", String(describing: error)) 86 | return request.finish(with: error) 87 | } 88 | }) 89 | 90 | composition.renderSize = asset.videoSize.applying(CGAffineTransform(scaleX: 1.0, y: 0.5)) 91 | return composition 92 | } 93 | 94 | // MARK: - Background Color 95 | 96 | func animateBackgroundColor() { 97 | let backgroundColors: [UIColor] = [.purple, .blue, .cyan, .green, .yellow, .orange, .red] 98 | 99 | let animator = UIViewPropertyAnimator(duration: 2.0, curve: .linear) { 100 | let colorIndex = backgroundColors.firstIndex(of: self.view.backgroundColor!) ?? 0 101 | let countColors = backgroundColors.count 102 | self.view.backgroundColor = backgroundColors[(colorIndex + 1) % countColors] 103 | } 104 | 105 | animator.addCompletion { _ in 106 | // Infinite animation 107 | self.animateBackgroundColor() 108 | } 109 | 110 | animator.startAnimation() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /MyTransparentVideoExample/AlphaFrameFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChromaKeyFilter.swift 3 | // MyTransparentVideoExample 4 | // 5 | // Created by Quentin on 27/10/2017. 6 | // Copyright © 2017 Quentin Fasquel. All rights reserved. 7 | // 8 | 9 | import CoreImage 10 | 11 | typealias AlphaFrameFilterError = AlphaFrameFilter.Error 12 | 13 | final class AlphaFrameFilter: CIFilter { 14 | 15 | enum Error: Swift.Error { 16 | /// This error is thrown when using renderingMode `builtInFilter` and the filter named *CIBlendWithMask* was not found 17 | case buildInFilterNotFound 18 | /// This error is thrown when `inputImage` and `maskImage` have different **extents** 19 | case incompatibleExtents 20 | /// This error is thrown when a kernel couldn't be initialized, 21 | /// which may happen when using renderingMode `colorKernel` or `metalKernel` 22 | case invalidKernel 23 | /// This error is thrown when `inputImage` or `maskImage` is missing 24 | case invalidParameters 25 | /// This error would be thrown when output image is `nil` in any other case, it typically should not happen 26 | case unknown 27 | } 28 | 29 | private(set) var inputImage: CIImage? 30 | private(set) var maskImage: CIImage? 31 | private(set) var outputError: Swift.Error? 32 | 33 | private let renderingMode: RenderingMode 34 | 35 | required init(renderingMode: RenderingMode) { 36 | self.renderingMode = renderingMode 37 | super.init() 38 | } 39 | 40 | required init?(coder: NSCoder) { 41 | fatalError("init(coder:) has not been implemented") 42 | } 43 | 44 | override var outputImage: CIImage? { 45 | // Output is nil if an input image and a mask image aren't provided 46 | guard let inputImage = inputImage, let maskImage = maskImage else { 47 | outputError = Error.invalidParameters 48 | return nil 49 | } 50 | 51 | // Input image & mask image should have the same extent 52 | guard inputImage.extent == maskImage.extent else { 53 | outputError = Error.incompatibleExtents 54 | return nil 55 | } 56 | 57 | outputError = nil 58 | 59 | return render(using: renderingMode, inputImage: inputImage, maskImage: maskImage) 60 | } 61 | 62 | func process(_ inputImage: CIImage, mask maskImage: CIImage) throws -> CIImage { 63 | self.inputImage = inputImage 64 | self.maskImage = maskImage 65 | 66 | guard let outputImage = self.outputImage else { 67 | throw outputError ?? Error.unknown 68 | } 69 | 70 | return outputImage 71 | } 72 | 73 | // MARK: - Rendering 74 | 75 | enum RenderingMode { 76 | case builtInFilter 77 | case colorKernel 78 | case metalKernel 79 | } 80 | 81 | private static var colorKernel: CIColorKernel? = { 82 | // `init(source:)` was deprecated in iOS 12.0: Core Image Kernel Language API deprecated. 83 | // This warning is silent because of preprocessor macro `CI_SILENCE_GL_DEPRECATION` 84 | return CIColorKernel(source: """ 85 | kernel vec4 alphaFrame(__sample s, __sample m) { 86 | return vec4( s.rgb, m.r ); 87 | } 88 | """) 89 | }() 90 | 91 | private static var metalKernelError: Swift.Error? 92 | private static var metalKernel: CIKernel? = { 93 | do { return try CIKernel(functionName: "alphaFrame") } 94 | catch { metalKernelError = error; return nil } 95 | }() 96 | 97 | private func render(using renderingMode: RenderingMode, inputImage: CIImage, maskImage: CIImage) -> CIImage? { 98 | switch renderingMode { 99 | 100 | case .builtInFilter: 101 | guard let filter = CIFilter(name: "CIBlendWithMask") else { 102 | outputError = Error.buildInFilterNotFound 103 | return nil 104 | } 105 | 106 | let outputExtent = inputImage.extent 107 | let backgroundImage = CIImage(color: .clear).cropped(to: outputExtent) 108 | filter.setValue(backgroundImage, forKey: kCIInputBackgroundImageKey) 109 | filter.setValue(inputImage, forKey: kCIInputImageKey) 110 | filter.setValue(maskImage, forKey: kCIInputMaskImageKey) 111 | return filter.outputImage 112 | 113 | case .colorKernel: 114 | // Force a fatal error if our kernel source isn't correct 115 | guard let colorKernel = Self.colorKernel else { 116 | outputError = Error.invalidKernel 117 | return nil 118 | } 119 | 120 | // Apply our color kernel with the proper parameters 121 | let outputExtent = inputImage.extent 122 | let arguments = [inputImage, maskImage] 123 | return colorKernel.apply(extent: outputExtent, arguments: arguments) 124 | 125 | case .metalKernel: 126 | guard let metalKernel = Self.metalKernel else { 127 | outputError = Self.metalKernelError ?? Error.invalidKernel 128 | return nil 129 | } 130 | 131 | let outputExtent = inputImage.extent 132 | let roiCallback: CIKernelROICallback = { _, rect in rect } 133 | let arguments = [inputImage, maskImage] 134 | return metalKernel.apply(extent: outputExtent, roiCallback: roiCallback, arguments: arguments) 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /MyTransparentVideoExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 667F4C7E1FA3068900F9A900 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667F4C7D1FA3068900F9A900 /* AppDelegate.swift */; }; 11 | 667F4C801FA3068900F9A900 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667F4C7F1FA3068900F9A900 /* ViewController.swift */; }; 12 | 667F4C831FA3068900F9A900 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 667F4C811FA3068900F9A900 /* Main.storyboard */; }; 13 | 667F4C851FA3068900F9A900 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 667F4C841FA3068900F9A900 /* Assets.xcassets */; }; 14 | 667F4C881FA3068900F9A900 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 667F4C861FA3068900F9A900 /* LaunchScreen.storyboard */; }; 15 | 667F4C901FA3071A00F9A900 /* AVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667F4C8F1FA3071A00F9A900 /* AVPlayerView.swift */; }; 16 | 667F4C921FA3126A00F9A900 /* AlphaFrameFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667F4C911FA3126A00F9A900 /* AlphaFrameFilter.swift */; }; 17 | 6690684B1FA3656B00598D4C /* playdoh-bat.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 6690684A1FA3656B00598D4C /* playdoh-bat.mp4 */; }; 18 | 669678FB242E7BF00085D444 /* AVAsset+VideoSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 669678FA242E7BF00085D444 /* AVAsset+VideoSize.swift */; }; 19 | 669678FD242E7CFB0085D444 /* CIImage+VerticalSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 669678FC242E7CFB0085D444 /* CIImage+VerticalSplit.swift */; }; 20 | 66E0467A242E85320096DEE5 /* CIKernel+DefaultMetalLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66E04678242E85320096DEE5 /* CIKernel+DefaultMetalLibrary.swift */; }; 21 | 66E0467B242E85320096DEE5 /* AlphaFrameFilter.metal in Sources */ = {isa = PBXBuildFile; fileRef = 66E04679242E85320096DEE5 /* AlphaFrameFilter.metal */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 667F4C7A1FA3068900F9A900 /* MyTransparentVideoExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MyTransparentVideoExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 667F4C7D1FA3068900F9A900 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | 667F4C7F1FA3068900F9A900 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 28 | 667F4C821FA3068900F9A900 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 667F4C841FA3068900F9A900 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 667F4C871FA3068900F9A900 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 667F4C891FA3068900F9A900 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 667F4C8F1FA3071A00F9A900 /* AVPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AVPlayerView.swift; sourceTree = ""; }; 33 | 667F4C911FA3126A00F9A900 /* AlphaFrameFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlphaFrameFilter.swift; sourceTree = ""; }; 34 | 6690684A1FA3656B00598D4C /* playdoh-bat.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "playdoh-bat.mp4"; sourceTree = ""; }; 35 | 669678FA242E7BF00085D444 /* AVAsset+VideoSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVAsset+VideoSize.swift"; sourceTree = ""; }; 36 | 669678FC242E7CFB0085D444 /* CIImage+VerticalSplit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CIImage+VerticalSplit.swift"; sourceTree = ""; }; 37 | 66E04678242E85320096DEE5 /* CIKernel+DefaultMetalLibrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CIKernel+DefaultMetalLibrary.swift"; sourceTree = ""; }; 38 | 66E04679242E85320096DEE5 /* AlphaFrameFilter.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = AlphaFrameFilter.metal; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 667F4C771FA3068800F9A900 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 667F4C711FA3068800F9A900 = { 53 | isa = PBXGroup; 54 | children = ( 55 | 667F4C7C1FA3068900F9A900 /* MyTransparentVideoExample */, 56 | 667F4C7B1FA3068900F9A900 /* Products */, 57 | ); 58 | sourceTree = ""; 59 | }; 60 | 667F4C7B1FA3068900F9A900 /* Products */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 667F4C7A1FA3068900F9A900 /* MyTransparentVideoExample.app */, 64 | ); 65 | name = Products; 66 | sourceTree = ""; 67 | }; 68 | 667F4C7C1FA3068900F9A900 /* MyTransparentVideoExample */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 6690684A1FA3656B00598D4C /* playdoh-bat.mp4 */, 72 | 66E04679242E85320096DEE5 /* AlphaFrameFilter.metal */, 73 | 667F4C911FA3126A00F9A900 /* AlphaFrameFilter.swift */, 74 | 669678FA242E7BF00085D444 /* AVAsset+VideoSize.swift */, 75 | 667F4C8F1FA3071A00F9A900 /* AVPlayerView.swift */, 76 | 667F4C7D1FA3068900F9A900 /* AppDelegate.swift */, 77 | 669678FC242E7CFB0085D444 /* CIImage+VerticalSplit.swift */, 78 | 66E04678242E85320096DEE5 /* CIKernel+DefaultMetalLibrary.swift */, 79 | 667F4C7F1FA3068900F9A900 /* ViewController.swift */, 80 | 667F4C811FA3068900F9A900 /* Main.storyboard */, 81 | 667F4C841FA3068900F9A900 /* Assets.xcassets */, 82 | 667F4C861FA3068900F9A900 /* LaunchScreen.storyboard */, 83 | 667F4C891FA3068900F9A900 /* Info.plist */, 84 | ); 85 | path = MyTransparentVideoExample; 86 | sourceTree = ""; 87 | }; 88 | /* End PBXGroup section */ 89 | 90 | /* Begin PBXNativeTarget section */ 91 | 667F4C791FA3068800F9A900 /* MyTransparentVideoExample */ = { 92 | isa = PBXNativeTarget; 93 | buildConfigurationList = 667F4C8C1FA3068900F9A900 /* Build configuration list for PBXNativeTarget "MyTransparentVideoExample" */; 94 | buildPhases = ( 95 | 667F4C761FA3068800F9A900 /* Sources */, 96 | 667F4C771FA3068800F9A900 /* Frameworks */, 97 | 667F4C781FA3068800F9A900 /* Resources */, 98 | ); 99 | buildRules = ( 100 | ); 101 | dependencies = ( 102 | ); 103 | name = MyTransparentVideoExample; 104 | productName = MyTransparentVideoExample; 105 | productReference = 667F4C7A1FA3068900F9A900 /* MyTransparentVideoExample.app */; 106 | productType = "com.apple.product-type.application"; 107 | }; 108 | /* End PBXNativeTarget section */ 109 | 110 | /* Begin PBXProject section */ 111 | 667F4C721FA3068800F9A900 /* Project object */ = { 112 | isa = PBXProject; 113 | attributes = { 114 | LastSwiftUpdateCheck = 0910; 115 | LastUpgradeCheck = 1020; 116 | ORGANIZATIONNAME = "Quentin Fasquel"; 117 | TargetAttributes = { 118 | 667F4C791FA3068800F9A900 = { 119 | CreatedOnToolsVersion = 9.1; 120 | LastSwiftMigration = 1020; 121 | ProvisioningStyle = Automatic; 122 | }; 123 | }; 124 | }; 125 | buildConfigurationList = 667F4C751FA3068800F9A900 /* Build configuration list for PBXProject "MyTransparentVideoExample" */; 126 | compatibilityVersion = "Xcode 8.0"; 127 | developmentRegion = en; 128 | hasScannedForEncodings = 0; 129 | knownRegions = ( 130 | en, 131 | Base, 132 | ); 133 | mainGroup = 667F4C711FA3068800F9A900; 134 | productRefGroup = 667F4C7B1FA3068900F9A900 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | 667F4C791FA3068800F9A900 /* MyTransparentVideoExample */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | 667F4C781FA3068800F9A900 /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | 667F4C881FA3068900F9A900 /* LaunchScreen.storyboard in Resources */, 149 | 6690684B1FA3656B00598D4C /* playdoh-bat.mp4 in Resources */, 150 | 667F4C851FA3068900F9A900 /* Assets.xcassets in Resources */, 151 | 667F4C831FA3068900F9A900 /* Main.storyboard in Resources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXResourcesBuildPhase section */ 156 | 157 | /* Begin PBXSourcesBuildPhase section */ 158 | 667F4C761FA3068800F9A900 /* Sources */ = { 159 | isa = PBXSourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 669678FB242E7BF00085D444 /* AVAsset+VideoSize.swift in Sources */, 163 | 667F4C901FA3071A00F9A900 /* AVPlayerView.swift in Sources */, 164 | 667F4C921FA3126A00F9A900 /* AlphaFrameFilter.swift in Sources */, 165 | 66E0467A242E85320096DEE5 /* CIKernel+DefaultMetalLibrary.swift in Sources */, 166 | 667F4C801FA3068900F9A900 /* ViewController.swift in Sources */, 167 | 669678FD242E7CFB0085D444 /* CIImage+VerticalSplit.swift in Sources */, 168 | 66E0467B242E85320096DEE5 /* AlphaFrameFilter.metal in Sources */, 169 | 667F4C7E1FA3068900F9A900 /* AppDelegate.swift in Sources */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXSourcesBuildPhase section */ 174 | 175 | /* Begin PBXVariantGroup section */ 176 | 667F4C811FA3068900F9A900 /* Main.storyboard */ = { 177 | isa = PBXVariantGroup; 178 | children = ( 179 | 667F4C821FA3068900F9A900 /* Base */, 180 | ); 181 | name = Main.storyboard; 182 | sourceTree = ""; 183 | }; 184 | 667F4C861FA3068900F9A900 /* LaunchScreen.storyboard */ = { 185 | isa = PBXVariantGroup; 186 | children = ( 187 | 667F4C871FA3068900F9A900 /* Base */, 188 | ); 189 | name = LaunchScreen.storyboard; 190 | sourceTree = ""; 191 | }; 192 | /* End PBXVariantGroup section */ 193 | 194 | /* Begin XCBuildConfiguration section */ 195 | 667F4C8A1FA3068900F9A900 /* Debug */ = { 196 | isa = XCBuildConfiguration; 197 | buildSettings = { 198 | ALWAYS_SEARCH_USER_PATHS = NO; 199 | CLANG_ANALYZER_NONNULL = YES; 200 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 201 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 202 | CLANG_CXX_LIBRARY = "libc++"; 203 | CLANG_ENABLE_MODULES = YES; 204 | CLANG_ENABLE_OBJC_ARC = YES; 205 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 206 | CLANG_WARN_BOOL_CONVERSION = YES; 207 | CLANG_WARN_COMMA = YES; 208 | CLANG_WARN_CONSTANT_CONVERSION = YES; 209 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INFINITE_RECURSION = YES; 215 | CLANG_WARN_INT_CONVERSION = YES; 216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 221 | CLANG_WARN_STRICT_PROTOTYPES = YES; 222 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 223 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 224 | CLANG_WARN_UNREACHABLE_CODE = YES; 225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 226 | CODE_SIGN_IDENTITY = "iPhone Developer"; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = dwarf; 229 | ENABLE_STRICT_OBJC_MSGSEND = YES; 230 | ENABLE_TESTABILITY = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu11; 232 | GCC_DYNAMIC_NO_PIC = NO; 233 | GCC_NO_COMMON_BLOCKS = YES; 234 | GCC_OPTIMIZATION_LEVEL = 0; 235 | GCC_PREPROCESSOR_DEFINITIONS = ( 236 | "DEBUG=1", 237 | "$(inherited)", 238 | ); 239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNUSED_FUNCTION = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 246 | MTL_ENABLE_DEBUG_INFO = YES; 247 | ONLY_ACTIVE_ARCH = YES; 248 | SDKROOT = iphoneos; 249 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 250 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 251 | }; 252 | name = Debug; 253 | }; 254 | 667F4C8B1FA3068900F9A900 /* Release */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | ALWAYS_SEARCH_USER_PATHS = NO; 258 | CLANG_ANALYZER_NONNULL = YES; 259 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 261 | CLANG_CXX_LIBRARY = "libc++"; 262 | CLANG_ENABLE_MODULES = YES; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_COMMA = YES; 267 | CLANG_WARN_CONSTANT_CONVERSION = YES; 268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 270 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 271 | CLANG_WARN_EMPTY_BODY = YES; 272 | CLANG_WARN_ENUM_CONVERSION = YES; 273 | CLANG_WARN_INFINITE_RECURSION = YES; 274 | CLANG_WARN_INT_CONVERSION = YES; 275 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 276 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 277 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 278 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 279 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 280 | CLANG_WARN_STRICT_PROTOTYPES = YES; 281 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 282 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 283 | CLANG_WARN_UNREACHABLE_CODE = YES; 284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 285 | CODE_SIGN_IDENTITY = "iPhone Developer"; 286 | COPY_PHASE_STRIP = NO; 287 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 288 | ENABLE_NS_ASSERTIONS = NO; 289 | ENABLE_STRICT_OBJC_MSGSEND = YES; 290 | GCC_C_LANGUAGE_STANDARD = gnu11; 291 | GCC_NO_COMMON_BLOCKS = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 299 | MTL_ENABLE_DEBUG_INFO = NO; 300 | SDKROOT = iphoneos; 301 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 302 | VALIDATE_PRODUCT = YES; 303 | }; 304 | name = Release; 305 | }; 306 | 667F4C8D1FA3068900F9A900 /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 310 | CODE_SIGN_STYLE = Automatic; 311 | DEVELOPMENT_TEAM = H9EZHJZX4M; 312 | GCC_PREPROCESSOR_DEFINITIONS = ( 313 | "$(inherited)", 314 | CI_SILENCE_GL_DEPRECATION, 315 | ); 316 | INFOPLIST_FILE = MyTransparentVideoExample/Info.plist; 317 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 318 | MTLLINKER_FLAGS = "-cikernel"; 319 | MTL_COMPILER_FLAGS = "-fcikernel"; 320 | PRODUCT_BUNDLE_IDENTIFIER = com.quentinfasquel.MyTransparentVideoExample; 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG CI_SILENCE_GL_DEPRECATION"; 323 | SWIFT_VERSION = 5.0; 324 | TARGETED_DEVICE_FAMILY = "1,2"; 325 | }; 326 | name = Debug; 327 | }; 328 | 667F4C8E1FA3068900F9A900 /* Release */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 332 | CODE_SIGN_STYLE = Automatic; 333 | DEVELOPMENT_TEAM = H9EZHJZX4M; 334 | GCC_PREPROCESSOR_DEFINITIONS = ( 335 | "$(inherited)", 336 | CI_SILENCE_GL_DEPRECATION, 337 | ); 338 | INFOPLIST_FILE = MyTransparentVideoExample/Info.plist; 339 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 340 | MTLLINKER_FLAGS = "-cikernel"; 341 | MTL_COMPILER_FLAGS = "-fcikernel"; 342 | PRODUCT_BUNDLE_IDENTIFIER = com.quentinfasquel.MyTransparentVideoExample; 343 | PRODUCT_NAME = "$(TARGET_NAME)"; 344 | SWIFT_VERSION = 5.0; 345 | TARGETED_DEVICE_FAMILY = "1,2"; 346 | }; 347 | name = Release; 348 | }; 349 | /* End XCBuildConfiguration section */ 350 | 351 | /* Begin XCConfigurationList section */ 352 | 667F4C751FA3068800F9A900 /* Build configuration list for PBXProject "MyTransparentVideoExample" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | 667F4C8A1FA3068900F9A900 /* Debug */, 356 | 667F4C8B1FA3068900F9A900 /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | 667F4C8C1FA3068900F9A900 /* Build configuration list for PBXNativeTarget "MyTransparentVideoExample" */ = { 362 | isa = XCConfigurationList; 363 | buildConfigurations = ( 364 | 667F4C8D1FA3068900F9A900 /* Debug */, 365 | 667F4C8E1FA3068900F9A900 /* Release */, 366 | ); 367 | defaultConfigurationIsVisible = 0; 368 | defaultConfigurationName = Release; 369 | }; 370 | /* End XCConfigurationList section */ 371 | }; 372 | rootObject = 667F4C721FA3068800F9A900 /* Project object */; 373 | } 374 | --------------------------------------------------------------------------------