Refactor VideoCodec.
This commit is contained in:
parent
527b1909dc
commit
65b8aca8ee
|
@ -1,6 +1,6 @@
|
|||
struct Preference {
|
||||
static var defaultInstance = Preference()
|
||||
|
||||
var uri: String? = "rtmp://192.168.1.9/live"
|
||||
var uri: String? = "rtmp://192.168.1.7/live"
|
||||
var streamName: String? = "live"
|
||||
}
|
||||
|
|
|
@ -315,9 +315,6 @@
|
|||
29F6F4851DFB83E200920A3A /* RTMPHandshake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F6F4841DFB83E200920A3A /* RTMPHandshake.swift */; };
|
||||
29F6F4861DFB862400920A3A /* RTMPHandshake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F6F4841DFB83E200920A3A /* RTMPHandshake.swift */; };
|
||||
29F97F242336A4FA00A4C317 /* SettingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F97F232336A4FA00A4C317 /* SettingTests.swift */; };
|
||||
29FD1B5022FF13190095A0BE /* VTSessionPropertyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FD1B4F22FF13190095A0BE /* VTSessionPropertyKey.swift */; };
|
||||
29FD1B5122FF13190095A0BE /* VTSessionPropertyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FD1B4F22FF13190095A0BE /* VTSessionPropertyKey.swift */; };
|
||||
29FD1B5222FF13190095A0BE /* VTSessionPropertyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FD1B4F22FF13190095A0BE /* VTSessionPropertyKey.swift */; };
|
||||
2EC97B6927880E9900D8BE32 /* VisualEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296897461CDB01D20074D5F0 /* VisualEffect.swift */; };
|
||||
2EC97B6A27880E9C00D8BE32 /* Preference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291468161E581C7D00E619BA /* Preference.swift */; };
|
||||
2EC97B6B27880EA200D8BE32 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 291F4E361CF206E200F59C51 /* Icon.png */; };
|
||||
|
@ -341,6 +338,21 @@
|
|||
BC44A1A923D31E92002D4297 /* AudioCodecBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC44A1A823D31E92002D4297 /* AudioCodecBuffer.swift */; };
|
||||
BC44A1AA23D31E92002D4297 /* AudioCodecBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC44A1A823D31E92002D4297 /* AudioCodecBuffer.swift */; };
|
||||
BC44A1AB23D31E92002D4297 /* AudioCodecBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC44A1A823D31E92002D4297 /* AudioCodecBuffer.swift */; };
|
||||
BC4914A228DDD33D009E2DF6 /* VTSessionConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A128DDD33D009E2DF6 /* VTSessionConvertible.swift */; };
|
||||
BC4914A328DDD33D009E2DF6 /* VTSessionConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A128DDD33D009E2DF6 /* VTSessionConvertible.swift */; };
|
||||
BC4914A428DDD33D009E2DF6 /* VTSessionConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A128DDD33D009E2DF6 /* VTSessionConvertible.swift */; };
|
||||
BC4914A628DDD367009E2DF6 /* VTSessionOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A528DDD367009E2DF6 /* VTSessionOption.swift */; };
|
||||
BC4914A728DDD367009E2DF6 /* VTSessionOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A528DDD367009E2DF6 /* VTSessionOption.swift */; };
|
||||
BC4914A828DDD367009E2DF6 /* VTSessionOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A528DDD367009E2DF6 /* VTSessionOption.swift */; };
|
||||
BC4914AA28DDD966009E2DF6 /* VTSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A928DDD966009E2DF6 /* VTSessionHolder.swift */; };
|
||||
BC4914AB28DDD966009E2DF6 /* VTSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A928DDD966009E2DF6 /* VTSessionHolder.swift */; };
|
||||
BC4914AC28DDD966009E2DF6 /* VTSessionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914A928DDD966009E2DF6 /* VTSessionHolder.swift */; };
|
||||
BC4914AE28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914AD28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift */; };
|
||||
BC4914AF28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914AD28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift */; };
|
||||
BC4914B028DDF445009E2DF6 /* VTDecompressionSession+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914AD28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift */; };
|
||||
BC4914B228DDFE31009E2DF6 /* VTSessionOptionKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914B128DDFE31009E2DF6 /* VTSessionOptionKey.swift */; };
|
||||
BC4914B328DDFE31009E2DF6 /* VTSessionOptionKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914B128DDFE31009E2DF6 /* VTSessionOptionKey.swift */; };
|
||||
BC4914B428DDFE31009E2DF6 /* VTSessionOptionKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4914B128DDFE31009E2DF6 /* VTSessionOptionKey.swift */; };
|
||||
BC4C9EAC23F00F3A004A14F2 /* Preference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291468161E581C7D00E619BA /* Preference.swift */; };
|
||||
BC4C9EAF23F2E736004A14F2 /* AudioStreamBasicDescription+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4C9EAE23F2E736004A14F2 /* AudioStreamBasicDescription+Extension.swift */; };
|
||||
BC4C9EB023F2E736004A14F2 /* AudioStreamBasicDescription+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4C9EAE23F2E736004A14F2 /* AudioStreamBasicDescription+Extension.swift */; };
|
||||
|
@ -822,7 +834,6 @@
|
|||
29F39BE72335F8010055F9BB /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
|
||||
29F6F4841DFB83E200920A3A /* RTMPHandshake.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTMPHandshake.swift; sourceTree = "<group>"; };
|
||||
29F97F232336A4FA00A4C317 /* SettingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingTests.swift; sourceTree = "<group>"; };
|
||||
29FD1B4F22FF13190095A0BE /* VTSessionPropertyKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VTSessionPropertyKey.swift; sourceTree = "<group>"; };
|
||||
2EC97B6D27880FF400D8BE32 /* ViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = "<group>"; };
|
||||
2EC97B6E27880FF400D8BE32 /* OnTapGestureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnTapGestureView.swift; sourceTree = "<group>"; };
|
||||
2EC97B6F27880FF400D8BE32 /* Views.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Views.swift; sourceTree = "<group>"; };
|
||||
|
@ -831,6 +842,11 @@
|
|||
BC34DFD125EBB12C005F975A /* Logboard.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Logboard.xcframework; path = Carthage/Build/Logboard.xcframework; sourceTree = "<group>"; };
|
||||
BC34FA0A286CB90A00EFAF27 /* PiPHkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPHkView.swift; sourceTree = "<group>"; };
|
||||
BC44A1A823D31E92002D4297 /* AudioCodecBuffer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCodecBuffer.swift; sourceTree = "<group>"; wrapsLines = 1; };
|
||||
BC4914A128DDD33D009E2DF6 /* VTSessionConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VTSessionConvertible.swift; sourceTree = "<group>"; };
|
||||
BC4914A528DDD367009E2DF6 /* VTSessionOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VTSessionOption.swift; sourceTree = "<group>"; };
|
||||
BC4914A928DDD966009E2DF6 /* VTSessionHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VTSessionHolder.swift; sourceTree = "<group>"; };
|
||||
BC4914AD28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VTDecompressionSession+Extension.swift"; sourceTree = "<group>"; };
|
||||
BC4914B128DDFE31009E2DF6 /* VTSessionOptionKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VTSessionOptionKey.swift; sourceTree = "<group>"; };
|
||||
BC4C9EAE23F2E736004A14F2 /* AudioStreamBasicDescription+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioStreamBasicDescription+Extension.swift"; sourceTree = "<group>"; };
|
||||
BC558267240BB40E00011AC0 /* RTMPStreamInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RTMPStreamInfo.swift; sourceTree = "<group>"; };
|
||||
BC566F6D25D2ECC500573C4C /* HLSService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HLSService.swift; sourceTree = "<group>"; };
|
||||
|
@ -1005,7 +1021,10 @@
|
|||
297E69112324E38800D418AB /* AudioCodecFormat.swift */,
|
||||
29B876581CD70A7900FC07DA /* H264Decoder.swift */,
|
||||
29B876591CD70A7900FC07DA /* VideoCodec.swift */,
|
||||
29FD1B4F22FF13190095A0BE /* VTSessionPropertyKey.swift */,
|
||||
BC4914A128DDD33D009E2DF6 /* VTSessionConvertible.swift */,
|
||||
BC4914A928DDD966009E2DF6 /* VTSessionHolder.swift */,
|
||||
BC4914A528DDD367009E2DF6 /* VTSessionOption.swift */,
|
||||
BC4914B128DDFE31009E2DF6 /* VTSessionOptionKey.swift */,
|
||||
);
|
||||
path = Codec;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1422,6 +1441,7 @@
|
|||
29EA87D41E799F670043A5F8 /* Mirror+Extension.swift */,
|
||||
29EA87D71E79A0090043A5F8 /* URL+Extension.swift */,
|
||||
BC83A4722403D83B006BDE06 /* VTCompressionSession+Extension.swift */,
|
||||
BC4914AD28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift */,
|
||||
);
|
||||
path = Extension;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2017,6 +2037,7 @@
|
|||
295891161EEB8DFC00CE51E1 /* FLVTagType.swift in Sources */,
|
||||
BCA97C0A263D80F40027213C /* MP4SampleEntry.swift in Sources */,
|
||||
BCC1A6D726446B2D00661156 /* MP4SoundMediaHeaderBox.swift in Sources */,
|
||||
BC4914AE28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift in Sources */,
|
||||
29B876B11CD70B2800FC07DA /* RTMPMessage.swift in Sources */,
|
||||
2941746B22D069B300A2944F /* AudioEffect.swift in Sources */,
|
||||
BCB9773F2621812800C9A649 /* AVCFormatStream.swift in Sources */,
|
||||
|
@ -2025,6 +2046,7 @@
|
|||
BC83A4732403D83B006BDE06 /* VTCompressionSession+Extension.swift in Sources */,
|
||||
2943ED53232FCA7C00ED6301 /* Setting.swift in Sources */,
|
||||
BC3FA38C2413AEDA009C83D3 /* AVFoundation+Extension.swift in Sources */,
|
||||
BC4914A228DDD33D009E2DF6 /* VTSessionConvertible.swift in Sources */,
|
||||
BCAD0C00263E968400ADFB80 /* MP4FileReader.swift in Sources */,
|
||||
BCA97B8A263AC1830027213C /* MP4Box.swift in Sources */,
|
||||
2915EC4D1D85BB8C00621092 /* RTMPTSocket.swift in Sources */,
|
||||
|
@ -2058,6 +2080,7 @@
|
|||
296242621D8DB86500C451A3 /* TSWriter.swift in Sources */,
|
||||
BC9CFA9323BDE8B700917EEF /* NetStreamDrawable.swift in Sources */,
|
||||
29B8769B1CD70B1100FC07DA /* MIME.swift in Sources */,
|
||||
BC4914AA28DDD966009E2DF6 /* VTSessionHolder.swift in Sources */,
|
||||
BCC1A727264FA1C100661156 /* ProfileLevelIndicationIndexDescriptor.swift in Sources */,
|
||||
29B8769C1CD70B1100FC07DA /* NetClient.swift in Sources */,
|
||||
BC94E530264146540094C169 /* MP4ReaderConvertible.swift in Sources */,
|
||||
|
@ -2097,6 +2120,8 @@
|
|||
BCC1A7132647F28F00661156 /* SLConfigDescriptor.swift in Sources */,
|
||||
29DF20622312A3DD004057C3 /* RTMPNWSocket.swift in Sources */,
|
||||
29B876BD1CD70B3900FC07DA /* CRC32.swift in Sources */,
|
||||
BC4914A628DDD367009E2DF6 /* VTSessionOption.swift in Sources */,
|
||||
BC4914B228DDFE31009E2DF6 /* VTSessionOptionKey.swift in Sources */,
|
||||
29EA87E61E79A2780043A5F8 /* CMAudioFormatDescription+Extension.swift in Sources */,
|
||||
BC94E506263FEA7F0094C169 /* MP4TrackFragmentBaseMediaDecodeTimeBox.swift in Sources */,
|
||||
29B876B51CD70B2800FC07DA /* RTMPSocket.swift in Sources */,
|
||||
|
@ -2153,7 +2178,6 @@
|
|||
29EA87D31E799F360043A5F8 /* ExpressibleByIntegerLiteral+Extension.swift in Sources */,
|
||||
BCC1A70F2647F25A00661156 /* DecoderConfigDescriptor.swift in Sources */,
|
||||
29B8767A1CD70ACE00FC07DA /* M3U.swift in Sources */,
|
||||
29FD1B5022FF13190095A0BE /* VTSessionPropertyKey.swift in Sources */,
|
||||
29B876901CD70AFE00FC07DA /* AVAudioIOUnit.swift in Sources */,
|
||||
BC94E50A263FEBB60094C169 /* MP4TrackRunBox.swift in Sources */,
|
||||
BCB976D126107B1200C9A649 /* TSAdaptationExtensionField.swift in Sources */,
|
||||
|
@ -2224,7 +2248,6 @@
|
|||
2916196D1E7F0777009FB344 /* CMFormatDescription+Extension.swift in Sources */,
|
||||
29DF20632312A3DD004057C3 /* RTMPNWSocket.swift in Sources */,
|
||||
29EA87E71E79A2780043A5F8 /* CMAudioFormatDescription+Extension.swift in Sources */,
|
||||
29FD1B5122FF13190095A0BE /* VTSessionPropertyKey.swift in Sources */,
|
||||
29B876F61CD70D5900FC07DA /* HTTPRequest.swift in Sources */,
|
||||
BCC1A70C2647F23200661156 /* ESDescriptor.swift in Sources */,
|
||||
29B876F71CD70D5900FC07DA /* HTTPResponse.swift in Sources */,
|
||||
|
@ -2296,6 +2319,7 @@
|
|||
29B8770C1CD70D5A00FC07DA /* NetService.swift in Sources */,
|
||||
2958911B1EEB8E3F00CE51E1 /* FLVAudioCodec.swift in Sources */,
|
||||
BCA97BF8263C4B8F0027213C /* MP4ChunkOffsetBox.swift in Sources */,
|
||||
BC4914A328DDD33D009E2DF6 /* VTSessionConvertible.swift in Sources */,
|
||||
BCA97BFE263C54560027213C /* MP4SampleToChunkBox.swift in Sources */,
|
||||
293B42EA2340B4840086F973 /* RTMPObjectEncoding.swift in Sources */,
|
||||
29DC17B421D0CC0600E26CED /* Atomic.swift in Sources */,
|
||||
|
@ -2317,6 +2341,7 @@
|
|||
BCC1A7082647E89300661156 /* BaseDescriptor.swift in Sources */,
|
||||
BC34FA0E286CBD6D00EFAF27 /* PiPHkView.swift in Sources */,
|
||||
29B877121CD70D5A00FC07DA /* RTMPChunk.swift in Sources */,
|
||||
BC4914A728DDD367009E2DF6 /* VTSessionOption.swift in Sources */,
|
||||
29AF3FD01D7C745200E41212 /* NetStream.swift in Sources */,
|
||||
29F6F4861DFB862400920A3A /* RTMPHandshake.swift in Sources */,
|
||||
BCA97BE9263C27080027213C /* MP4SampleSizeBox.swift in Sources */,
|
||||
|
@ -2343,11 +2368,14 @@
|
|||
29EA87DA1E79A00E0043A5F8 /* ExpressibleByIntegerLiteral+Extension.swift in Sources */,
|
||||
29D0E3681DD4CE3700863B3B /* AnyUtil.swift in Sources */,
|
||||
29B8771C1CD70D5A00FC07DA /* CRC32.swift in Sources */,
|
||||
BC4914AB28DDD966009E2DF6 /* VTSessionHolder.swift in Sources */,
|
||||
2958912B1EEB8F1D00CE51E1 /* FLVSoundSize.swift in Sources */,
|
||||
BC94E50B263FEBB60094C169 /* MP4TrackRunBox.swift in Sources */,
|
||||
BC4914B328DDFE31009E2DF6 /* VTSessionOptionKey.swift in Sources */,
|
||||
BCB976D226107B1200C9A649 /* TSAdaptationExtensionField.swift in Sources */,
|
||||
BCA97C04263C61940027213C /* MP4MediaHeaderBox.swift in Sources */,
|
||||
29B8771D1CD70D5A00FC07DA /* EventDispatcher.swift in Sources */,
|
||||
BC4914AF28DDF445009E2DF6 /* VTDecompressionSession+Extension.swift in Sources */,
|
||||
2901A4EF1D437662002BBD23 /* MediaLink.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -2448,11 +2476,15 @@
|
|||
BCA97BF6263C390E0027213C /* CustomXmlStringConvertible.swift in Sources */,
|
||||
BCC1A6BB2643F41600661156 /* MP4File.Builder.swift in Sources */,
|
||||
BC94E52E264146530094C169 /* MP4ReaderConvertible.swift in Sources */,
|
||||
BC4914AC28DDD966009E2DF6 /* VTSessionHolder.swift in Sources */,
|
||||
BCC1A72D264FAC1800661156 /* ElementaryStreamSpecificData.swift in Sources */,
|
||||
BCB976E126107B5600C9A649 /* TSAdaptationField.swift in Sources */,
|
||||
BC4914B028DDF445009E2DF6 /* VTDecompressionSession+Extension.swift in Sources */,
|
||||
BCC1A6D5264461FE00661156 /* MP4HandlerBox.swift in Sources */,
|
||||
BCC1A7112647F25A00661156 /* DecoderConfigDescriptor.swift in Sources */,
|
||||
BCC1A6D126445AF500661156 /* MP4TrackExtendsBox.swift in Sources */,
|
||||
BC4914A828DDD367009E2DF6 /* VTSessionOption.swift in Sources */,
|
||||
BC4914A428DDD33D009E2DF6 /* VTSessionConvertible.swift in Sources */,
|
||||
BCAD0C02263E968400ADFB80 /* MP4FileReader.swift in Sources */,
|
||||
BCA97C00263C599C0027213C /* MP4SyncSampleBox.swift in Sources */,
|
||||
2941746D22D069B300A2944F /* AudioEffect.swift in Sources */,
|
||||
|
@ -2474,6 +2506,7 @@
|
|||
BCA97C03263C61930027213C /* MP4MediaHeaderBox.swift in Sources */,
|
||||
29EB3E0C1ED05874001CAE8B /* TSWriter.swift in Sources */,
|
||||
295891181EEB8DFC00CE51E1 /* FLVTagType.swift in Sources */,
|
||||
BC4914B428DDFE31009E2DF6 /* VTSessionOptionKey.swift in Sources */,
|
||||
BCA97BFA263C4F980027213C /* MP4EditListBox.swift in Sources */,
|
||||
29EB3DF91ED0579C001CAE8B /* ExpressibleByIntegerLiteral+Extension.swift in Sources */,
|
||||
29EB3E201ED059F9001CAE8B /* RTMPConnection.swift in Sources */,
|
||||
|
@ -2513,7 +2546,6 @@
|
|||
29EB3E361ED05A35001CAE8B /* EventDispatcher.swift in Sources */,
|
||||
29EB3E341ED05A30001CAE8B /* CRC32.swift in Sources */,
|
||||
BC566F7025D2ECC500573C4C /* HLSService.swift in Sources */,
|
||||
29FD1B5222FF13190095A0BE /* VTSessionPropertyKey.swift in Sources */,
|
||||
BCAD0C1D263EE1D000ADFB80 /* MP4Util.swift in Sources */,
|
||||
29EB3E181ED05896001CAE8B /* NetService.swift in Sources */,
|
||||
295891281EEB8EF300CE51E1 /* FLVAACPacket.swift in Sources */,
|
||||
|
|
|
@ -37,8 +37,8 @@ extension AVVideoIOUnit {
|
|||
input = nil
|
||||
output = nil
|
||||
if useScreenSize {
|
||||
encoder.width = screen.attributes["Width"] as! Int32
|
||||
encoder.height = screen.attributes["Height"] as! Int32
|
||||
codec.width = screen.attributes["Width"] as! Int32
|
||||
codec.height = screen.attributes["Height"] as! Int32
|
||||
}
|
||||
self.screen = screen
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ extension AVVideoIOUnit: CaptureSessionDelegate {
|
|||
// MARK: CaptureSessionDelegate
|
||||
func session(_ session: CaptureSessionConvertible, didSet size: CGSize) {
|
||||
lockQueue.async {
|
||||
self.encoder.width = Int32(size.width)
|
||||
self.encoder.height = Int32(size.height)
|
||||
self.codec.width = Int32(size.width)
|
||||
self.codec.height = Int32(size.height)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ extension AVVideoIOUnit: CaptureSessionDelegate {
|
|||
}
|
||||
context?.render(effect(pixelBuffer, info: nil), to: pixelBuffer)
|
||||
}
|
||||
encoder.encodeImageBuffer(
|
||||
codec.inputBuffer(
|
||||
pixelBuffer,
|
||||
presentationTimeStamp: presentationTime,
|
||||
duration: CMTime.invalid
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import AVFoundation
|
||||
import Foundation
|
||||
import VideoToolbox
|
||||
|
||||
protocol VTSessionConvertible {
|
||||
func setOption(_ option: VTSessionOption) -> OSStatus
|
||||
func setOptions(_ options: Set<VTSessionOption>) -> OSStatus
|
||||
func copySupportedPropertyDictionary() -> [AnyHashable: Any]
|
||||
func inputBuffer(_ imageBuffer: CVImageBuffer, presentationTimeStamp: CMTime, duration: CMTime, outputHandler: @escaping VTCompressionOutputHandler)
|
||||
func invalidate()
|
||||
}
|
||||
|
||||
extension VTSessionConvertible where Self: VTSession {
|
||||
func setOption(_ option: VTSessionOption) -> OSStatus {
|
||||
return VTSessionSetProperty(self, key: option.key.CFString, value: option.value)
|
||||
}
|
||||
|
||||
func setOptions(_ options: Set<VTSessionOption>) -> OSStatus {
|
||||
var properties: [AnyHashable: AnyObject] = [:]
|
||||
for option in options {
|
||||
properties[option.key.CFString] = option.value
|
||||
}
|
||||
return VTSessionSetProperties(self, propertyDictionary: properties as CFDictionary)
|
||||
}
|
||||
|
||||
func copySupportedPropertyDictionary() -> [AnyHashable: Any] {
|
||||
var support: CFDictionary?
|
||||
guard VTSessionCopySupportedPropertyDictionary(self, supportedPropertyDictionaryOut: &support) == noErr else {
|
||||
return [:]
|
||||
}
|
||||
guard let result = support as? [AnyHashable: Any] else {
|
||||
return [:]
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import Foundation
|
||||
import VideoToolbox
|
||||
|
||||
struct VTSessionHolder {
|
||||
private(set) var isInvalidateSession = false
|
||||
private(set) var session: VTSessionConvertible?
|
||||
|
||||
mutating func makeSession(_ videoCodec: VideoCodec) -> OSStatus {
|
||||
session?.invalidate()
|
||||
session = nil
|
||||
var session: VTCompressionSession?
|
||||
var status = VTCompressionSessionCreate(
|
||||
allocator: kCFAllocatorDefault,
|
||||
width: videoCodec.width,
|
||||
height: videoCodec.height,
|
||||
codecType: kCMVideoCodecType_H264,
|
||||
encoderSpecification: nil,
|
||||
imageBufferAttributes: nil,
|
||||
compressedDataAllocator: nil,
|
||||
outputCallback: nil,
|
||||
refcon: nil,
|
||||
compressionSessionOut: &session
|
||||
)
|
||||
guard status == noErr, let session else {
|
||||
videoCodec.delegate?.videoCodec(videoCodec, errorOccurred: .failedToCreate(status: status))
|
||||
return status
|
||||
}
|
||||
status = session.setOptions(videoCodec.options())
|
||||
status = session.prepareToEncodeFrame()
|
||||
guard status == noErr else {
|
||||
videoCodec.delegate?.videoCodec(videoCodec, errorOccurred: .failedToPrepare(status: status))
|
||||
return status
|
||||
}
|
||||
self.session = session
|
||||
isInvalidateSession = false
|
||||
return noErr
|
||||
}
|
||||
|
||||
mutating func invalidateSession() {
|
||||
isInvalidateSession = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import Foundation
|
||||
|
||||
public struct VTSessionOption: Hashable {
|
||||
public static func == (lhs: VTSessionOption, rhs: VTSessionOption) -> Bool {
|
||||
return lhs.key.CFString == rhs.key.CFString
|
||||
}
|
||||
|
||||
let key: VTSessionOptionKey
|
||||
let value: AnyObject
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
return hasher.combine(key.CFString)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import Foundation
|
||||
import VideoToolbox
|
||||
|
||||
struct VTSessionOptionKey {
|
||||
static let depth = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_Depth)
|
||||
static let profileLevel = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_ProfileLevel)
|
||||
static let H264EntropyMode = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_H264EntropyMode)
|
||||
static let numberOfPendingFrames = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_NumberOfPendingFrames)
|
||||
static let pixelBufferPoolIsShared = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_PixelBufferPoolIsShared)
|
||||
static let videoEncoderPixelBufferAttributes = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_VideoEncoderPixelBufferAttributes)
|
||||
static let aspectRatio16x9 = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_AspectRatio16x9)
|
||||
static let cleanAperture = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_CleanAperture)
|
||||
static let fieldCount = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_FieldCount)
|
||||
static let fieldDetail = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_FieldDetail)
|
||||
static let pixelAspectRatio = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_PixelAspectRatio)
|
||||
static let progressiveScan = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_ProgressiveScan)
|
||||
static let colorPrimaries = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_ColorPrimaries)
|
||||
static let transferFunction = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_TransferFunction)
|
||||
static let YCbCrMatrix = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_YCbCrMatrix)
|
||||
static let ICCProfile = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_ICCProfile)
|
||||
static let expectedDuration = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_ExpectedDuration)
|
||||
static let expectedFrameRate = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_ExpectedFrameRate)
|
||||
static let sourceFrameCount = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_SourceFrameCount)
|
||||
static let allowFrameReordering = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_AllowFrameReordering)
|
||||
static let allowTemporalCompression = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_AllowTemporalCompression)
|
||||
static let maxKeyFrameInterval = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MaxKeyFrameInterval)
|
||||
static let maxKeyFrameIntervalDuration = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration)
|
||||
#if os(macOS)
|
||||
static let usingHardwareAcceleratedVideoEncoder = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder)
|
||||
static let requireHardwareAcceleratedVideoEncoder = VTSessionOptionKey(CFString: kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder)
|
||||
static let enableHardwareAcceleratedVideoEncoder = VTSessionOptionKey(CFString: kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder)
|
||||
#endif
|
||||
static let multiPassStorage = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MultiPassStorage)
|
||||
static let forceKeyFrame = VTSessionOptionKey(CFString: kVTEncodeFrameOptionKey_ForceKeyFrame)
|
||||
static let fpixelTransferProperties = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_PixelTransferProperties)
|
||||
static let averageBitRate = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_AverageBitRate)
|
||||
static let dataRateLimits = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_DataRateLimits)
|
||||
static let moreFramesAfterEnd = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MoreFramesAfterEnd)
|
||||
static let moreFramesBeforeStart = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MoreFramesBeforeStart)
|
||||
static let quality = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_Quality)
|
||||
static let realTime = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_RealTime)
|
||||
static let maxH264SliceBytes = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MaxH264SliceBytes)
|
||||
static let maxFrameDelayCount = VTSessionOptionKey(CFString: kVTCompressionPropertyKey_MaxFrameDelayCount)
|
||||
static let encoderUsage = VTSessionOptionKey(CFString: "EncoderUsage" as CFString)
|
||||
|
||||
let CFString: CFString
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import Foundation
|
||||
import VideoToolbox
|
||||
|
||||
protocol VTSessionPropertyKey {
|
||||
var CFString: CFString { get }
|
||||
}
|
|
@ -33,6 +33,8 @@ public class VideoCodec {
|
|||
case failedToPrepare(status: OSStatus)
|
||||
/// The VideoCodec failed to encode or decode a flame.
|
||||
case failedToFlame(status: OSStatus)
|
||||
/// The VideoCodec failed to set an option.
|
||||
case failedToSetOption(status: OSStatus, option: VTSessionOption)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,7 +116,7 @@ public class VideoCodec {
|
|||
guard scalingMode != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +125,7 @@ public class VideoCodec {
|
|||
guard width != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
var height: Int32 = VideoCodec.defaultHeight {
|
||||
|
@ -131,7 +133,7 @@ public class VideoCodec {
|
|||
guard height != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
#if os(macOS)
|
||||
|
@ -140,7 +142,7 @@ public class VideoCodec {
|
|||
guard enabledHardwareEncoder != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -149,7 +151,10 @@ public class VideoCodec {
|
|||
guard bitrate != oldValue else {
|
||||
return
|
||||
}
|
||||
setProperty(kVTCompressionPropertyKey_AverageBitRate, Int(bitrate) as CFTypeRef)
|
||||
let option = VTSessionOption(key: .averageBitRate, value: NSNumber(value: bitrate))
|
||||
if let status = sessionHolder.session?.setOption(option), status != noErr {
|
||||
delegate?.videoCodec(self, errorOccurred: .failedToSetOption(status: status, option: option))
|
||||
}
|
||||
}
|
||||
}
|
||||
var profileLevel: String = kVTProfileLevel_H264_Baseline_3_1 as String {
|
||||
|
@ -157,7 +162,7 @@ public class VideoCodec {
|
|||
guard profileLevel != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
var maxKeyFrameIntervalDuration: Double = 2.0 {
|
||||
|
@ -165,7 +170,7 @@ public class VideoCodec {
|
|||
guard maxKeyFrameIntervalDuration != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
// swiftlint:disable discouraged_optional_boolean
|
||||
|
@ -174,7 +179,7 @@ public class VideoCodec {
|
|||
guard allowFrameReordering != oldValue else {
|
||||
return
|
||||
}
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
}
|
||||
var locked: UInt32 = 0
|
||||
|
@ -184,7 +189,11 @@ public class VideoCodec {
|
|||
guard expectedFPS != oldValue else {
|
||||
return
|
||||
}
|
||||
setProperty(kVTCompressionPropertyKey_ExpectedFrameRate, NSNumber(value: expectedFPS))
|
||||
let option = VTSessionOption(key: .expectedFrameRate, value: NSNumber(value: expectedFPS))
|
||||
if let status = sessionHolder.session?.setOption(option), status != noErr {
|
||||
print(status)
|
||||
delegate?.videoCodec(self, errorOccurred: .failedToSetOption(status: status, option: option))
|
||||
}
|
||||
}
|
||||
}
|
||||
var formatDescription: CMFormatDescription? {
|
||||
|
@ -196,7 +205,6 @@ public class VideoCodec {
|
|||
}
|
||||
}
|
||||
weak var delegate: VideoCodecDelegate?
|
||||
|
||||
private var attributes: [NSString: AnyObject]? {
|
||||
guard VideoCodec.defaultAttributes != nil else {
|
||||
return nil
|
||||
|
@ -209,142 +217,68 @@ public class VideoCodec {
|
|||
attributes[kCVPixelBufferHeightKey] = NSNumber(value: height)
|
||||
return attributes
|
||||
}
|
||||
private var invalidateSession = true
|
||||
private var lastImageBuffer: CVImageBuffer?
|
||||
|
||||
/// - seealso: https://developer.apple.com/library/mac/releasenotes/General/APIDiffsMacOSX10_8/VideoToolbox.html
|
||||
private var properties: [NSString: NSObject] {
|
||||
let isBaseline: Bool = profileLevel.contains("Baseline")
|
||||
var properties: [NSString: NSObject] = [
|
||||
kVTCompressionPropertyKey_RealTime: kCFBooleanTrue,
|
||||
kVTCompressionPropertyKey_ProfileLevel: profileLevel as NSObject,
|
||||
kVTCompressionPropertyKey_AverageBitRate: Int(bitrate) as NSObject,
|
||||
kVTCompressionPropertyKey_ExpectedFrameRate: NSNumber(value: expectedFPS),
|
||||
kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration: NSNumber(value: maxKeyFrameIntervalDuration),
|
||||
kVTCompressionPropertyKey_AllowFrameReordering: (allowFrameReordering ?? !isBaseline) as NSObject,
|
||||
kVTCompressionPropertyKey_PixelTransferProperties: [
|
||||
"ScalingMode": scalingMode.rawValue
|
||||
] as NSObject
|
||||
]
|
||||
#if os(OSX)
|
||||
if enabledHardwareEncoder {
|
||||
#if arch(arm64)
|
||||
properties[kVTVideoEncoderSpecification_EncoderID] = "com.apple.videotoolbox.videoencoder.ave.avc" as NSObject
|
||||
#else
|
||||
properties[kVTVideoEncoderSpecification_EncoderID] = "com.apple.videotoolbox.videoencoder.h264.gva" as NSObject
|
||||
#endif
|
||||
properties["EnableHardwareAcceleratedVideoEncoder"] = kCFBooleanTrue
|
||||
properties["RequireHardwareAcceleratedVideoEncoder"] = kCFBooleanTrue
|
||||
}
|
||||
#endif
|
||||
if !isBaseline {
|
||||
properties[kVTCompressionPropertyKey_H264EntropyMode] = kVTH264EntropyMode_CABAC
|
||||
}
|
||||
return properties
|
||||
}
|
||||
|
||||
private var callback: VTCompressionOutputCallback = {(outputCallbackRefCon: UnsafeMutableRawPointer?, _: UnsafeMutableRawPointer?, status: OSStatus, _: VTEncodeInfoFlags, sampleBuffer: CMSampleBuffer?) in
|
||||
guard let refcon = outputCallbackRefCon else {
|
||||
return
|
||||
}
|
||||
let codec = Unmanaged<VideoCodec>.fromOpaque(refcon).takeUnretainedValue()
|
||||
guard
|
||||
let sampleBuffer: CMSampleBuffer = sampleBuffer, status == noErr else {
|
||||
if status == kVTParameterErr {
|
||||
// on iphone 11 with size=1792x827 this occurs
|
||||
logger.error("encoding failed with kVTParameterErr. Perhaps the width x height is too big for the encoder setup?")
|
||||
codec.delegate?.videoCodec(codec, errorOccurred: .failedToFlame(status: status))
|
||||
}
|
||||
return
|
||||
}
|
||||
codec.formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer)
|
||||
codec.delegate?.videoCodec(codec, didOutput: sampleBuffer)
|
||||
}
|
||||
|
||||
private var _session: VTCompressionSession?
|
||||
private var session: VTCompressionSession? {
|
||||
get {
|
||||
if _session == nil {
|
||||
var status: OSStatus = VTCompressionSessionCreate(
|
||||
allocator: kCFAllocatorDefault,
|
||||
width: width,
|
||||
height: height,
|
||||
codecType: kCMVideoCodecType_H264,
|
||||
encoderSpecification: nil,
|
||||
imageBufferAttributes: attributes as CFDictionary?,
|
||||
compressedDataAllocator: nil,
|
||||
outputCallback: callback,
|
||||
refcon: Unmanaged.passUnretained(self).toOpaque(),
|
||||
compressionSessionOut: &_session
|
||||
)
|
||||
guard status == noErr, let session = _session else {
|
||||
logger.warn("create a VTCompressionSessionCreate")
|
||||
delegate?.videoCodec(self, errorOccurred: .failedToCreate(status: status))
|
||||
return nil
|
||||
}
|
||||
invalidateSession = false
|
||||
status = session.setProperties(properties)
|
||||
status = session.prepareToEncodeFrame()
|
||||
guard status == noErr else {
|
||||
logger.error("setup failed VTCompressionSessionPrepareToEncodeFrames. Size = \(width)x\(height)")
|
||||
delegate?.videoCodec(self, errorOccurred: .failedToPrepare(status: status))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return _session
|
||||
}
|
||||
set {
|
||||
_session?.invalidate()
|
||||
_session = newValue
|
||||
}
|
||||
}
|
||||
private var sessionHolder = VTSessionHolder()
|
||||
|
||||
init() {
|
||||
settings.observer = self
|
||||
}
|
||||
|
||||
func encodeImageBuffer(_ imageBuffer: CVImageBuffer, presentationTimeStamp: CMTime, duration: CMTime) {
|
||||
func inputBuffer(_ imageBuffer: CVImageBuffer, presentationTimeStamp: CMTime, duration: CMTime) {
|
||||
guard isRunning.value && locked == 0 else {
|
||||
return
|
||||
}
|
||||
if invalidateSession {
|
||||
session = nil
|
||||
if sessionHolder.isInvalidateSession {
|
||||
_ = sessionHolder.makeSession(self)
|
||||
}
|
||||
guard let session: VTCompressionSession = session else {
|
||||
return
|
||||
}
|
||||
var flags: VTEncodeInfoFlags = []
|
||||
VTCompressionSessionEncodeFrame(
|
||||
session,
|
||||
imageBuffer: muted ? lastImageBuffer ?? imageBuffer : imageBuffer,
|
||||
sessionHolder.session?.inputBuffer(
|
||||
muted ? lastImageBuffer ?? imageBuffer : imageBuffer,
|
||||
presentationTimeStamp: presentationTimeStamp,
|
||||
duration: duration,
|
||||
frameProperties: nil,
|
||||
sourceFrameRefcon: nil,
|
||||
infoFlagsOut: &flags
|
||||
)
|
||||
if !muted || lastImageBuffer == nil {
|
||||
lastImageBuffer = imageBuffer
|
||||
duration: duration
|
||||
) { [unowned self] status, _, sampleBuffer in
|
||||
guard let sampleBuffer, status == noErr else {
|
||||
self.delegate?.videoCodec(self, errorOccurred: .failedToFlame(status: status))
|
||||
return
|
||||
}
|
||||
self.formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer)
|
||||
self.delegate?.videoCodec(self, didOutput: sampleBuffer)
|
||||
if !self.muted || self.lastImageBuffer == nil {
|
||||
self.lastImageBuffer = imageBuffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func setProperty(_ key: CFString, _ value: CFTypeRef?) {
|
||||
lockQueue.async {
|
||||
guard let session: VTCompressionSession = self._session else {
|
||||
return
|
||||
}
|
||||
VTSessionSetProperty(
|
||||
session,
|
||||
key: key,
|
||||
value: value
|
||||
)
|
||||
func options() -> Set<VTSessionOption> {
|
||||
let isBaseline = profileLevel.contains("Baseline")
|
||||
var options = Set<VTSessionOption>([
|
||||
.init(key: .realTime, value: kCFBooleanTrue),
|
||||
.init(key: .profileLevel, value: profileLevel as NSObject),
|
||||
.init(key: .averageBitRate, value: NSNumber(value: bitrate)),
|
||||
.init(key: .expectedFrameRate, value: NSNumber(value: expectedFPS)),
|
||||
.init(key: .maxKeyFrameIntervalDuration, value: NSNumber(value: maxKeyFrameIntervalDuration)),
|
||||
.init(key: .allowFrameReordering, value: (allowFrameReordering ?? !isBaseline) as NSObject)
|
||||
])
|
||||
#if os(OSX)
|
||||
if enabledHardwareEncoder {
|
||||
#if arch(arm64)
|
||||
options.insert(.init(key: .init(CFString: kVTVideoEncoderSpecification_EncoderID), value: "com.apple.videotoolbox.videoencoder.ave.avc" as NSObject))
|
||||
#else
|
||||
options.insert(.init(key: .init(CFString: kVTVideoEncoderSpecification_EncoderID), value: "com.apple.videotoolbox.videoencoder.h264.gva" as NSObject))
|
||||
#endif
|
||||
options.insert(.init(key: .init(CFString: "EnableHardwareAcceleratedVideoEncoder" as CFString), value: kCFBooleanTrue))
|
||||
options.insert(.init(key: .init(CFString: "RequireHardwareAcceleratedVideoEncoder" as CFString), value: kCFBooleanTrue))
|
||||
}
|
||||
#endif
|
||||
if !isBaseline {
|
||||
options.insert(.init(key: .H264EntropyMode, value: kVTH264EntropyMode_CABAC))
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
@objc
|
||||
private func applicationWillEnterForeground(_ notification: Notification) {
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -357,7 +291,7 @@ public class VideoCodec {
|
|||
}
|
||||
switch type {
|
||||
case .ended:
|
||||
invalidateSession = true
|
||||
sessionHolder.invalidateSession()
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -390,7 +324,7 @@ extension VideoCodec: Running {
|
|||
|
||||
public func stopRunning() {
|
||||
lockQueue.async {
|
||||
self.session = nil
|
||||
self.sessionHolder.invalidateSession()
|
||||
self.lastImageBuffer = nil
|
||||
self.formatDescription = nil
|
||||
#if os(iOS)
|
||||
|
|
|
@ -1,182 +1,27 @@
|
|||
import Foundation
|
||||
import VideoToolbox
|
||||
|
||||
enum VTCompressionSessionPropertyKey: VTSessionPropertyKey {
|
||||
// Bitstream Configuration
|
||||
case depth
|
||||
case profileLevel
|
||||
case H264EntropyMode
|
||||
|
||||
// Buffers
|
||||
case numberOfPendingFrames
|
||||
case pixelBufferPoolIsShared
|
||||
case videoEncoderPixelBufferAttributes
|
||||
|
||||
// Clean Aperture and Pixel Aspect Ratio
|
||||
case aspectRatio16x9
|
||||
case cleanAperture
|
||||
case fieldCount
|
||||
case fieldDetail
|
||||
case pixelAspectRatio
|
||||
case progressiveScan
|
||||
|
||||
// Color
|
||||
case colorPrimaries
|
||||
case transferFunction
|
||||
case YCbCrMatrix
|
||||
case ICCProfile
|
||||
|
||||
// Expected Values
|
||||
case expectedDuration
|
||||
case expectedFrameRate
|
||||
case sourceFrameCount
|
||||
|
||||
// Frame Dependency
|
||||
case allowFrameReordering
|
||||
case allowTemporalCompression
|
||||
case maxKeyFrameInterval
|
||||
case maxKeyFrameIntervalDuration
|
||||
|
||||
#if os(macOS)
|
||||
// Hardware Acceleration
|
||||
case usingHardwareAcceleratedVideoEncoder
|
||||
case requireHardwareAcceleratedVideoEncoder
|
||||
case enableHardwareAcceleratedVideoEncoder
|
||||
#endif
|
||||
|
||||
// Multipass Storage
|
||||
case multiPassStorage
|
||||
|
||||
// Per-Frame Configuration
|
||||
case forceKeyFrame
|
||||
|
||||
// Precompression Processing
|
||||
case pixelTransferProperties
|
||||
|
||||
// Rate Control
|
||||
case averageBitRate
|
||||
case dataRateLimits
|
||||
case moreFramesAfterEnd
|
||||
case moreFramesBeforeStart
|
||||
case quality
|
||||
|
||||
// Runtime Restriction
|
||||
case realTime
|
||||
case maxH264SliceBytes
|
||||
case maxFrameDelayCount
|
||||
|
||||
// Others
|
||||
case encoderUsage
|
||||
|
||||
var CFString: CFString {
|
||||
switch self {
|
||||
case .depth:
|
||||
return kVTCompressionPropertyKey_Depth
|
||||
case .profileLevel:
|
||||
return kVTCompressionPropertyKey_ProfileLevel
|
||||
case .H264EntropyMode:
|
||||
return kVTCompressionPropertyKey_H264EntropyMode
|
||||
case .numberOfPendingFrames:
|
||||
return kVTCompressionPropertyKey_NumberOfPendingFrames
|
||||
case .pixelBufferPoolIsShared:
|
||||
return kVTCompressionPropertyKey_PixelBufferPoolIsShared
|
||||
case .videoEncoderPixelBufferAttributes:
|
||||
return kVTCompressionPropertyKey_VideoEncoderPixelBufferAttributes
|
||||
case .aspectRatio16x9:
|
||||
return kVTCompressionPropertyKey_AspectRatio16x9
|
||||
case .cleanAperture:
|
||||
return kVTCompressionPropertyKey_CleanAperture
|
||||
case .fieldCount:
|
||||
return kVTCompressionPropertyKey_FieldCount
|
||||
case .fieldDetail:
|
||||
return kVTCompressionPropertyKey_FieldDetail
|
||||
case .pixelAspectRatio:
|
||||
return kVTCompressionPropertyKey_PixelAspectRatio
|
||||
case .progressiveScan:
|
||||
return kVTCompressionPropertyKey_ProgressiveScan
|
||||
case .colorPrimaries:
|
||||
return kVTCompressionPropertyKey_ColorPrimaries
|
||||
case .transferFunction:
|
||||
return kVTCompressionPropertyKey_TransferFunction
|
||||
case .YCbCrMatrix:
|
||||
return kVTCompressionPropertyKey_YCbCrMatrix
|
||||
case .ICCProfile:
|
||||
return kVTCompressionPropertyKey_ICCProfile
|
||||
case .expectedDuration:
|
||||
return kVTCompressionPropertyKey_ExpectedDuration
|
||||
case .expectedFrameRate:
|
||||
return kVTCompressionPropertyKey_ExpectedFrameRate
|
||||
case .sourceFrameCount:
|
||||
return kVTCompressionPropertyKey_SourceFrameCount
|
||||
case .allowFrameReordering:
|
||||
return kVTCompressionPropertyKey_AllowFrameReordering
|
||||
case .allowTemporalCompression:
|
||||
return kVTCompressionPropertyKey_AllowTemporalCompression
|
||||
case .maxKeyFrameInterval:
|
||||
return kVTCompressionPropertyKey_MaxKeyFrameInterval
|
||||
case .maxKeyFrameIntervalDuration:
|
||||
return kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration
|
||||
#if os(macOS)
|
||||
case .usingHardwareAcceleratedVideoEncoder:
|
||||
return kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder
|
||||
case .requireHardwareAcceleratedVideoEncoder:
|
||||
return kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder
|
||||
case .enableHardwareAcceleratedVideoEncoder:
|
||||
return kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder
|
||||
#endif
|
||||
case .multiPassStorage:
|
||||
return kVTCompressionPropertyKey_MultiPassStorage
|
||||
case .forceKeyFrame:
|
||||
return kVTEncodeFrameOptionKey_ForceKeyFrame
|
||||
case .pixelTransferProperties:
|
||||
return kVTCompressionPropertyKey_PixelTransferProperties
|
||||
case .averageBitRate:
|
||||
return kVTCompressionPropertyKey_AverageBitRate
|
||||
case .dataRateLimits:
|
||||
return kVTCompressionPropertyKey_DataRateLimits
|
||||
case .moreFramesAfterEnd:
|
||||
return kVTCompressionPropertyKey_MoreFramesAfterEnd
|
||||
case .moreFramesBeforeStart:
|
||||
return kVTCompressionPropertyKey_MoreFramesBeforeStart
|
||||
case .quality:
|
||||
return kVTCompressionPropertyKey_Quality
|
||||
case .realTime:
|
||||
return kVTCompressionPropertyKey_RealTime
|
||||
case .maxH264SliceBytes:
|
||||
return kVTCompressionPropertyKey_MaxH264SliceBytes
|
||||
case .maxFrameDelayCount:
|
||||
return kVTCompressionPropertyKey_MaxFrameDelayCount
|
||||
case .encoderUsage:
|
||||
return "EncoderUsage" as CFString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension VTCompressionSession {
|
||||
func setProperty(_ key: VTCompressionSessionPropertyKey, value: CFTypeRef?) -> OSStatus {
|
||||
VTSessionSetProperty(self, key: key.CFString, value: value)
|
||||
}
|
||||
|
||||
func setProperties(_ propertyDictionary: [NSString: NSObject]) -> OSStatus {
|
||||
VTSessionSetProperties(self, propertyDictionary: propertyDictionary as CFDictionary)
|
||||
}
|
||||
|
||||
func prepareToEncodeFrame() -> OSStatus {
|
||||
VTCompressionSessionPrepareToEncodeFrames(self)
|
||||
extension VTCompressionSession: VTSessionConvertible {
|
||||
func inputBuffer(_ imageBuffer: CVImageBuffer, presentationTimeStamp: CMTime, duration: CMTime, outputHandler: @escaping VTCompressionOutputHandler) {
|
||||
var flags: VTEncodeInfoFlags = []
|
||||
VTCompressionSessionEncodeFrame(
|
||||
self,
|
||||
imageBuffer: imageBuffer,
|
||||
presentationTimeStamp: presentationTimeStamp,
|
||||
duration: duration,
|
||||
frameProperties: nil,
|
||||
infoFlagsOut: &flags,
|
||||
outputHandler: outputHandler
|
||||
)
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
VTCompressionSessionInvalidate(self)
|
||||
}
|
||||
}
|
||||
|
||||
func copySupportedPropertyDictionary() -> [AnyHashable: Any] {
|
||||
var support: CFDictionary?
|
||||
guard VTSessionCopySupportedPropertyDictionary(self, supportedPropertyDictionaryOut: &support) == noErr else {
|
||||
return [:]
|
||||
}
|
||||
guard let result = support as? [AnyHashable: Any] else {
|
||||
return [:]
|
||||
}
|
||||
return result
|
||||
extension VTCompressionSession {
|
||||
func prepareToEncodeFrame() -> OSStatus {
|
||||
VTCompressionSessionPrepareToEncodeFrames(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import Foundation
|
||||
import VideoToolbox
|
||||
|
||||
extension VTDecompressionSession: VTSessionConvertible {
|
||||
func inputBuffer(_ imageBuffer: CVImageBuffer, presentationTimeStamp: CMTime, duration: CMTime, outputHandler: @escaping VTCompressionOutputHandler) {
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
VTDecompressionSessionInvalidate(self)
|
||||
}
|
||||
}
|
|
@ -231,8 +231,8 @@ extension AVMixer {
|
|||
#if os(iOS)
|
||||
videoIO.screen?.startRunning()
|
||||
#endif
|
||||
videoIO.encoder.delegate = delegate as? VideoCodecDelegate
|
||||
videoIO.encoder.startRunning()
|
||||
videoIO.codec.delegate = delegate as? VideoCodecDelegate
|
||||
videoIO.codec.startRunning()
|
||||
audioIO.codec.delegate = delegate as? AudioCodecDelegate
|
||||
audioIO.codec.startRunning()
|
||||
}
|
||||
|
@ -244,8 +244,8 @@ extension AVMixer {
|
|||
#endif
|
||||
videoTimeStamp = CMTime.zero
|
||||
audioTimeStamp = CMTime.zero
|
||||
videoIO.encoder.delegate = nil
|
||||
videoIO.encoder.stopRunning()
|
||||
videoIO.codec.delegate = nil
|
||||
videoIO.codec.stopRunning()
|
||||
audioIO.codec.delegate = nil
|
||||
audioIO.codec.stopRunning()
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ final class AVVideoIOUnit: NSObject, AVIOUnit {
|
|||
decoder.formatDescription = formatDescription
|
||||
}
|
||||
}
|
||||
lazy var encoder: VideoCodec = {
|
||||
var encoder = VideoCodec()
|
||||
encoder.lockQueue = lockQueue
|
||||
return encoder
|
||||
lazy var codec: VideoCodec = {
|
||||
var codec = VideoCodec()
|
||||
codec.lockQueue = lockQueue
|
||||
return codec
|
||||
}()
|
||||
lazy var decoder: H264Decoder = {
|
||||
var decoder = H264Decoder()
|
||||
|
@ -87,7 +87,7 @@ final class AVVideoIOUnit: NSObject, AVIOUnit {
|
|||
}
|
||||
|
||||
fps = data.fps
|
||||
encoder.expectedFPS = data.fps
|
||||
codec.expectedFPS = data.fps
|
||||
logger.info("\(data)")
|
||||
|
||||
do {
|
||||
|
@ -422,7 +422,7 @@ extension AVVideoIOUnit {
|
|||
drawable?.enqueue(sampleBuffer)
|
||||
}
|
||||
|
||||
encoder.encodeImageBuffer(
|
||||
codec.inputBuffer(
|
||||
imageBuffer ?? buffer,
|
||||
presentationTimeStamp: sampleBuffer.presentationTimeStamp,
|
||||
duration: sampleBuffer.duration
|
||||
|
|
|
@ -70,10 +70,10 @@ open class NetStream: NSObject {
|
|||
/// Specify the video compression properties.
|
||||
public var videoSettings: Setting<VideoCodec, VideoCodec.Option> {
|
||||
get {
|
||||
mixer.videoIO.encoder.settings
|
||||
mixer.videoIO.codec.settings
|
||||
}
|
||||
set {
|
||||
mixer.videoIO.encoder.settings = newValue
|
||||
mixer.videoIO.codec.settings = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ open class RTMPStream: NetStream {
|
|||
switch self.readyState {
|
||||
case .publish, .publishing:
|
||||
self.mixer.audioIO.codec.muted = self.paused
|
||||
self.mixer.videoIO.encoder.muted = self.paused
|
||||
self.mixer.videoIO.codec.muted = self.paused
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -431,11 +431,11 @@ open class RTMPStream: NetStream {
|
|||
metadata.removeAll()
|
||||
#if os(iOS) || os(macOS)
|
||||
if let _: AVCaptureInput = mixer.videoIO.input {
|
||||
metadata["width"] = mixer.videoIO.encoder.width
|
||||
metadata["height"] = mixer.videoIO.encoder.height
|
||||
metadata["width"] = mixer.videoIO.codec.width
|
||||
metadata["height"] = mixer.videoIO.codec.height
|
||||
metadata["framerate"] = mixer.videoIO.fps
|
||||
metadata["videocodecid"] = FLVVideoCodec.avc.rawValue
|
||||
metadata["videodatarate"] = mixer.videoIO.encoder.bitrate / 1000
|
||||
metadata["videodatarate"] = mixer.videoIO.codec.bitrate / 1000
|
||||
}
|
||||
if let _: AVCaptureInput = mixer.audioIO.input {
|
||||
metadata["audiocodecid"] = FLVAudioCodec.aac.rawValue
|
||||
|
@ -608,12 +608,12 @@ extension RTMPStream: RTMPMuxerDelegate {
|
|||
return
|
||||
}
|
||||
let type: FLVTagType = .video
|
||||
OSAtomicOr32Barrier(1, &mixer.videoIO.encoder.locked)
|
||||
OSAtomicOr32Barrier(1, &mixer.videoIO.codec.locked)
|
||||
let length: Int = rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
||||
type: videoWasSent ? .one : .zero,
|
||||
streamId: type.streamId,
|
||||
message: RTMPVideoMessage(streamId: id, timestamp: UInt32(videoTimestamp), payload: buffer)
|
||||
), locked: &mixer.videoIO.encoder.locked)
|
||||
), locked: &mixer.videoIO.codec.locked)
|
||||
if !videoWasSent {
|
||||
logger.debug("first video frame was sent")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue