Skip to content

Commit 790cdd5

Browse files
committed
Add support for transparent photo and videos.
1 parent f9e94ee commit 790cdd5

File tree

9 files changed

+462
-176
lines changed

9 files changed

+462
-176
lines changed

Example/Example.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@
552552
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
553553
CLANG_ENABLE_MODULES = YES;
554554
CODE_SIGN_STYLE = Automatic;
555+
CURRENT_PROJECT_VERSION = 1;
555556
DEVELOPMENT_TEAM = 5S8646274U;
556557
INFOPLIST_FILE = Source/Info.plist;
557558
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@@ -576,6 +577,7 @@
576577
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
577578
CLANG_ENABLE_MODULES = YES;
578579
CODE_SIGN_STYLE = Automatic;
580+
CURRENT_PROJECT_VERSION = 1;
579581
DEVELOPMENT_TEAM = 5S8646274U;
580582
INFOPLIST_FILE = Source/Info.plist;
581583
IPHONEOS_DEPLOYMENT_TARGET = 13.0;

Example/Pods/Pods.xcodeproj/project.pbxproj

Lines changed: 11 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SCNRecorder.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
D500F759257AB94100118C11 /* TestRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D500F758257AB94100118C11 /* TestRenderer.swift */; };
1919
D500F774257ABE1200118C11 /* TestRecordableLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D500F773257ABE1200118C11 /* TestRecordableLayer.swift */; };
2020
D55385CD254CB15900225EC0 /* PixelBufferOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55385CC254CB15900225EC0 /* PixelBufferOutput.swift */; };
21+
D56915CF263F445B00591380 /* VideoSettings.CompressionProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56915CE263F445B00591380 /* VideoSettings.CompressionProperties.swift */; };
2122
D56D805F25F16ECB00935848 /* AudioEngine.Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56D805C25F16ECB00935848 /* AudioEngine.Player.swift */; };
2223
D56D806025F16ECB00935848 /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56D805D25F16ECB00935848 /* AudioEngine.swift */; };
2324
D56D806125F16ECB00935848 /* AudioEngine.Player.State.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56D805E25F16ECB00935848 /* AudioEngine.Player.State.swift */; };
@@ -137,6 +138,7 @@
137138
D500F769257ABA0700118C11 /* SCNRecorderTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SCNRecorderTests-Bridging-Header.h"; sourceTree = "<group>"; };
138139
D500F773257ABE1200118C11 /* TestRecordableLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestRecordableLayer.swift; sourceTree = "<group>"; };
139140
D55385CC254CB15900225EC0 /* PixelBufferOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelBufferOutput.swift; sourceTree = "<group>"; };
141+
D56915CE263F445B00591380 /* VideoSettings.CompressionProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoSettings.CompressionProperties.swift; sourceTree = "<group>"; };
140142
D56D805C25F16ECB00935848 /* AudioEngine.Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioEngine.Player.swift; sourceTree = "<group>"; };
141143
D56D805D25F16ECB00935848 /* AudioEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
142144
D56D805E25F16ECB00935848 /* AudioEngine.Player.State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioEngine.Player.State.swift; sourceTree = "<group>"; };
@@ -286,6 +288,7 @@
286288
D5B923AC2510CC9B00D35585 /* VideoRecording.State.swift */,
287289
D5B923D02510CC9B00D35585 /* VideoSettings.swift */,
288290
D5B923BE2510CC9B00D35585 /* VideoSettings.Codec.swift */,
291+
D56915CE263F445B00591380 /* VideoSettings.CompressionProperties.swift */,
289292
D5B9238B2510CC9A00D35585 /* VideoSettings.FileType.swift */,
290293
D5B923C22510CC9B00D35585 /* VideoSettings.ScalingMode.swift */,
291294
D56D805B25F16ECB00935848 /* AudioEngine */,
@@ -824,6 +827,7 @@
824827
D5EE33F3257108C20056085A /* MetalPixelBufferProducer.swift in Sources */,
825828
D5B923FB2510CC9C00D35585 /* Observable.swift in Sources */,
826829
D5B923EB2510CC9C00D35585 /* VideoSettings.FileType.swift in Sources */,
830+
D56915CF263F445B00591380 /* VideoSettings.CompressionProperties.swift in Sources */,
827831
D5B923E12510CC9C00D35585 /* SCNView+MulticastDelegate.swift in Sources */,
828832
D5B923F22510CC9C00D35585 /* UnfairAtomic.swift in Sources */,
829833
);

SCNRecorderTests/Extensions/VideoSetting.Codec+Helpers.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ extension VideoSettings.Codec {
3030

3131
var name: String {
3232
switch self {
33-
case .h264: return "h264"
3433
case .hevc: return "hevc"
34+
case .hevcWithAlpha: return "hevcWithAlpha"
35+
case .h264: return "h264"
3536
case .jpeg: return "jpeg"
3637
}
3738
}

SCNRecorderTests/SceneRecorderTests.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,17 @@ extension SceneRecorderTests {
7272
var codecs: [VideoSettings.Codec] = [.h264()]
7373

7474
let supportHEVCEncoder = AVAssetExportSession.allExportPresets().contains(AVAssetExportPresetHEVC1920x1080)
75-
if supportHEVCEncoder { codecs.append(.hevc) }
75+
if supportHEVCEncoder {
76+
codecs.append(.hevc())
77+
if #available(iOS 13.0, *) {
78+
if fileType == .mov {
79+
codecs.append(.hevcWithAlpha())
80+
}
81+
}
82+
}
7683

7784
#if !targetEnvironment(simulator)
78-
codecs.append(.jpeg)
85+
codecs.append(.jpeg())
7986
#endif
8087

8188
codecs.forEach { (codec) in

Sources/Extensions/MTLPixelFormat+Helpers.swift

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@
2525

2626
import Foundation
2727
import AVFoundation
28+
import MetalPerformanceShaders
2829

2930
extension MTLPixelFormat {
3031

31-
// Undocumented format, something like bgr10_xr_srgb, was obtained on iPhone 7 iOS 12.1.4
32-
static let rgb10a8_2p_xr10_srgb = MTLPixelFormat(rawValue: 551) ?? .bgr10_xr_srgb
32+
// Undocumented format, something like bgra10_xr_srgb, was found on iPhone 7 iOS 12.1.4
33+
static let rgb10a8_2p_xr10_srgb = MTLPixelFormat(rawValue: 551) ?? .bgra10_xr_srgb
3334

3435
#if !targetEnvironment(simulator)
3536
static let supportedPixelFormats: Set<MTLPixelFormat> = Set([
3637
.bgra8Unorm, .bgra8Unorm_srgb,
37-
.bgr10_xr, .bgr10_xr_srgb,
38+
.bgr10_xr, .bgr10_xr_srgb
3839
])
3940
#else
4041
static let supportedPixelFormats: Set<MTLPixelFormat> = Set([
@@ -44,8 +45,14 @@ extension MTLPixelFormat {
4445

4546
var colorPrimaries: String {
4647
switch self {
47-
case .bgr10_xr, .bgr10_xr_srgb: return AVVideoColorPrimaries_P3_D65
48-
default: return AVVideoColorPrimaries_ITU_R_709_2
48+
case .bgr10_xr,
49+
.bgr10_xr_srgb,
50+
.bgra10_xr,
51+
.bgra10_xr_srgb,
52+
.rgb10a8_2p_xr10_srgb:
53+
return AVVideoColorPrimaries_P3_D65
54+
default:
55+
return AVVideoColorPrimaries_ITU_R_709_2
4956
}
5057
}
5158

@@ -58,13 +65,28 @@ extension MTLPixelFormat {
5865
var supportedPixelFormat: MTLPixelFormat {
5966
if Self.supportedPixelFormats.contains(self) { return self }
6067

68+
// For some reason bgra8Unorm_srgb is not writable on simulators
69+
#if targetEnvironment(simulator)
70+
let bgra8Unorm_srgb = MTLPixelFormat.bgra8Unorm
71+
#else
72+
let bgra8Unorm_srgb = MTLPixelFormat.bgra8Unorm_srgb
73+
#endif
74+
75+
// The recorder doesn't support bgra10_xr, bgra10_xr_srgb and rgb10a8_2p_xr10_srgb to be wrote directly.
76+
// They should be converted to intermediate bgra8Unorm and bgra8Unorm_srgb formats to be recorded.
77+
// Mostly becaouse, I can find a CoreVideo pixel format to be used for them.
78+
// The drawback is loose of extended colors.
79+
// In general any of https://developer.apple.com/documentation/metalperformanceshaders/image_filters#2793234
80+
// formats can be used as intermediates, but for now, I don't see any reason to experiment.
81+
// - Vlad
6182
switch self {
62-
case .bgra10_xr: return .bgr10_xr
63-
case .bgra10_xr_srgb, .rgb10a8_2p_xr10_srgb: return .bgr10_xr_srgb
64-
default: return .bgra8Unorm_srgb
83+
case .bgra10_xr: return .bgra8Unorm
84+
case .bgra10_xr_srgb, .rgb10a8_2p_xr10_srgb: return bgra8Unorm_srgb
85+
default: return bgra8Unorm_srgb
6586
}
6687
}
6788

89+
// A CoreVideo pixel format to be used as a format for storage for the content encoded as MTLPixelFormat
6890
var pixelFormatType: OSType {
6991
switch self {
7092

@@ -78,4 +100,23 @@ extension MTLPixelFormat {
78100
return kCVPixelFormatType_32BGRA
79101
}
80102
}
103+
104+
// Assume that the alpha is premultiplied for formats with alpha channel.
105+
// This is true for SceneKit, ARKit, but might be different for pure metal projects with custom shaders
106+
var alphaType: MPSAlphaType {
107+
switch self {
108+
109+
case .bgra8Unorm, .bgra8Unorm_srgb:
110+
return .premultiplied
111+
112+
case .bgr10_xr, .bgr10_xr_srgb:
113+
return .alphaIsOne
114+
115+
case .bgra10_xr, .bgra10_xr_srgb, .rgb10a8_2p_xr10_srgb:
116+
return .premultiplied
117+
118+
default:
119+
return .premultiplied
120+
}
121+
}
81122
}

Sources/PixelBuffer/MetalPixelBufferProducer.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ final class MetalPixelBufferProducer {
120120
) throws {
121121
guard let commandBuffer = commandQueue.makeCommandBuffer() else { throw Error.noCommandBuffer }
122122

123-
let imageConversion = self.makeImageConversion()
123+
let imageConversion = self.makeImageConversion(
124+
sourceTexture: sourceTexture,
125+
destinationTexture: destinationTexture.mtlTexture
126+
)
127+
124128
imageConversion.encode(
125129
commandBuffer: commandBuffer,
126130
sourceTexture: sourceTexture,
@@ -173,11 +177,14 @@ final class MetalPixelBufferProducer {
173177
return attachements
174178
}
175179

176-
func makeImageConversion() -> MPSImageConversion {
180+
func makeImageConversion(
181+
sourceTexture: MTLTexture,
182+
destinationTexture: MTLTexture
183+
) -> MPSImageConversion {
177184
MPSImageConversion(
178185
device: device,
179-
srcAlpha: .alphaIsOne,
180-
destAlpha: .alphaIsOne,
186+
srcAlpha: sourceTexture.pixelFormat.alphaType,
187+
destAlpha: destinationTexture.pixelFormat.alphaType,
181188
backgroundColor: nil,
182189
conversionInfo: nil
183190
)

0 commit comments

Comments
 (0)