Skip to content

Commit

Permalink
Enhanced VideoToolbox options.
Browse files Browse the repository at this point in the history
  • Loading branch information
shogo4405 committed Nov 25, 2023
1 parent d612881 commit dea9b09
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 17 deletions.
16 changes: 4 additions & 12 deletions Sources/Codec/VideoCodec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ protocol VideoCodecDelegate: AnyObject {
}

private let kVideoCodec_defaultFrameInterval: Double = 0.0
private let kVideoCodec_defaultAttributes: [NSString: AnyObject]? = [
kCVPixelBufferIOSurfacePropertiesKey: NSDictionary(),
kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue
]

// MARK: -
/**
Expand All @@ -46,16 +42,12 @@ final class VideoCodec<T: VideoCodecDelegate> {
private(set) var isRunning: Atomic<Bool> = .init(false)
var needsSync: Atomic<Bool> = .init(true)
var attributes: [NSString: AnyObject]? {
guard kVideoCodec_defaultAttributes != nil else {
return nil
}
var attributes: [NSString: AnyObject] = [:]
for (key, value) in kVideoCodec_defaultAttributes ?? [:] {
attributes[key] = value
if let inputFormat {
// Specify the pixel format of the uncompressed video.
attributes[kCVPixelBufferPixelFormatTypeKey] = inputFormat._mediaSubType as CFNumber
}
attributes[kCVPixelBufferWidthKey] = NSNumber(value: settings.videoSize.width)
attributes[kCVPixelBufferHeightKey] = NSNumber(value: settings.videoSize.height)
return attributes
return attributes.isEmpty ? nil : attributes
}
var passthrough = true
var frameInterval = kVideoCodec_defaultFrameInterval
Expand Down
22 changes: 17 additions & 5 deletions Sources/Codec/VideoCodecSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ public struct VideoCodecSettings: Codable {
public var videoSize: CGSize
/// Specifies the bitrate.
public var bitRate: Int
/// Specifies the video frame interval.
public var frameInterval: Double
/// Specifies the H264 profileLevel.
public var profileLevel: String {
didSet {
Expand All @@ -106,31 +104,35 @@ public struct VideoCodecSettings: Codable {
public var maxKeyFrameIntervalDuration: Int32
/// Specifies the allowFrameRecording.
public var allowFrameReordering: Bool? // swiftlint:disable:this discouraged_optional_boolean
/// Specifies the dataRateLimits
public var dataRateLimits: [Double]?
/// Specifies the HardwareEncoder is enabled(TRUE), or not(FALSE) for macOS.
public var isHardwareEncoderEnabled: Bool
/// Specifies the video frame interval.
public var frameInterval: Double = 0.0

var format: Format = .h264

/// Creates a new VideoCodecSettings instance.
public init(
videoSize: CGSize = .init(width: 854, height: 480),
bitRate: Int = 640 * 1000,
frameInterval: Double = 0.0,
profileLevel: String = kVTProfileLevel_H264_Baseline_3_1 as String,
scalingMode: ScalingMode = .trim,
bitRateMode: BitRateMode = .average,
maxKeyFrameIntervalDuration: Int32 = 2,
allowFrameReordering: Bool? = nil, // swiftlint:disable:this discouraged_optional_boolean,
dataRateLimits: [Double]? = [0.0, 0.0],
isHardwareEncoderEnabled: Bool = true
) {
self.videoSize = videoSize
self.bitRate = bitRate
self.frameInterval = frameInterval
self.profileLevel = profileLevel
self.scalingMode = scalingMode
self.bitRateMode = bitRateMode
self.maxKeyFrameIntervalDuration = maxKeyFrameIntervalDuration
self.allowFrameReordering = allowFrameReordering
self.dataRateLimits = dataRateLimits
self.isHardwareEncoderEnabled = isHardwareEncoderEnabled
if profileLevel.contains("HEVC") {
self.format = .hevc
Expand All @@ -144,6 +146,7 @@ public struct VideoCodecSettings: Codable {
allowFrameReordering == rhs.allowFrameReordering &&
bitRateMode == rhs.bitRateMode &&
profileLevel == rhs.profileLevel &&
dataRateLimits == rhs.dataRateLimits &&
isHardwareEncoderEnabled == rhs.isHardwareEncoderEnabled
)
}
Expand All @@ -161,6 +164,7 @@ public struct VideoCodecSettings: Codable {
}
}

// https://developer.apple.com/documentation/videotoolbox/encoding_video_for_live_streaming
func options<T>(_ codec: VideoCodec<T>) -> Set<VTSessionOption> {
let isBaseline = profileLevel.contains("Baseline")
var options = Set<VTSessionOption>([
Expand All @@ -175,14 +179,22 @@ public struct VideoCodecSettings: Codable {
"ScalingMode": scalingMode.rawValue
] as NSObject)
])
if bitRateMode == .average {
if let dataRateLimits, dataRateLimits.count == 2 {
var limits: [Double] = []
limits[0] = dataRateLimits[0] == 0 ? Double(bitRate) / 8 * 1.5 : dataRateLimits[0]
limits[1] = dataRateLimits[1] == 0 ? Double(1.0) : dataRateLimits[1]
options.insert(.init(key: .dataRateLimits, value: limits as NSArray))
}
}
#if os(macOS)
if isHardwareEncoderEnabled {
options.insert(.init(key: .encoderID, value: format.encoderID))
options.insert(.init(key: .enableHardwareAcceleratedVideoEncoder, value: kCFBooleanTrue))
options.insert(.init(key: .requireHardwareAcceleratedVideoEncoder, value: kCFBooleanTrue))
}
#endif
if !isBaseline {
if !isBaseline && profileLevel.contains("H264") {
options.insert(.init(key: .H264EntropyMode, value: kVTH264EntropyMode_CABAC))
}
return options
Expand Down

0 comments on commit dea9b09

Please sign in to comment.