Refactor VideoCodec.

This commit is contained in:
shogo4405 2022-09-23 20:57:31 +09:00
parent 527b1909dc
commit 65b8aca8ee
15 changed files with 292 additions and 337 deletions

View File

@ -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"
}

View File

@ -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 */,

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -1,6 +0,0 @@
import Foundation
import VideoToolbox
protocol VTSessionPropertyKey {
var CFString: CFString { get }
}

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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")
}