Skip to content

Commit

Permalink
feat(*): make resolution clearer
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibaultBee committed Feb 9, 2024
1 parent c72e362 commit 282b9d9
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 93 deletions.
12 changes: 5 additions & 7 deletions Examples/ExampleUIKit/ExampleUIkit/Settings.bundle/Root.plist
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,22 @@
<key>Key</key>
<string>Resolution</string>
<key>DefaultValue</key>
<string>858x480</string>
<string>854x480</string>
<key>Values</key>
<array>
<string>352x240</string>
<string>426x240</string>
<string>480x360</string>
<string>858x480</string>
<string>854x480</string>
<string>1280x720</string>
<string>1920x1080</string>
<string>3840x2160</string>
</array>
<key>Titles</key>
<array>
<string>352x240</string>
<string>426x240</string>
<string>480x360</string>
<string>858x480</string>
<string>854x480</string>
<string>1280x720</string>
<string>1920x1080</string>
<string>3840x2160</string>
</array>
</dict>
<dict>
Expand Down
14 changes: 9 additions & 5 deletions Examples/ExampleUIKit/ExampleUIkit/SettingsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ enum SettingsManager {

private static var resolution: Resolution {
do {
return try UserDefaults.standard.string(forKey: "Resolution")?.toResolution() ?? Resolution.RESOLUTION_720
return try UserDefaults.standard.string(forKey: "Resolution")?.toResolution() ?? Resolution
.RESOLUTION_16_9_720P
} catch {
print("Can't get resolution from user defaults")
return Resolution.RESOLUTION_720
fatalError("Can't get resolution from user defaults")
}
}

Expand Down Expand Up @@ -57,13 +57,17 @@ extension String {
guard let height = Int(resolutionArray[1]) else {
throw ParameterError.Invalid("Height is invalid")
}
return try Resolution.getResolution(width: width, height: height)
let resolution = Resolution(rawValue: CGSize(width: width, height: height))
if resolution == nil {
throw ParameterError.Invalid("Resolution is invalid for \(width)x\(height)")
}
return resolution!
}
}

extension Resolution {
func toString() -> String {
"\(size.width)x\(size.height)"
"\(rawValue.width)x\(rawValue.height)"
}
}

Expand Down
42 changes: 16 additions & 26 deletions Sources/ApiVideoLiveStream/ApiVideoLiveStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public class ApiVideoLiveStream {
/// The delegate of the ApiVideoLiveStream
public weak var delegate: ApiVideoLiveStreamDelegate?

// swiftlint:disable force_cast
/// Getter and Setter for an AudioConfig
public var audioConfig: AudioConfig {
get {
Expand All @@ -34,13 +33,12 @@ public class ApiVideoLiveStream {
}
}

// swiftlint:disable force_cast force_try
/// Getter and Setter for a VideoConfig
public var videoConfig: VideoConfig {
get {
try! VideoConfig(
VideoConfig(
bitrate: Int(self.rtmpStream.videoSettings.bitRate),
resolution: Resolution.getResolution(
resolution: CGSize(
width: Int(self.rtmpStream.videoSettings.videoSize.width),
height: Int(self.rtmpStream.videoSettings.videoSize.height)
),
Expand All @@ -53,7 +51,6 @@ public class ApiVideoLiveStream {
}
}

// swiftlint:disable force_cast
/// Getter and Setter for the Bitrate number for the video
public var videoBitrate: Int {
get {
Expand Down Expand Up @@ -100,7 +97,6 @@ public class ApiVideoLiveStream {
}

#if os(iOS)
// swiftlint:disable implicit_return
/// Zoom on the video capture
public var zoomRatio: CGFloat {
get {
Expand Down Expand Up @@ -322,10 +318,10 @@ public class ApiVideoLiveStream {
self.rtmpStream.frameRate = videoConfig.fps
self.rtmpStream.sessionPreset = AVCaptureSession.Preset.high

let width = self.rtmpStream.videoOrientation.isLandscape ? videoConfig.resolution.size.width : videoConfig
.resolution.size.height
let height = self.rtmpStream.videoOrientation.isLandscape ? videoConfig.resolution.size.height : videoConfig
.resolution.size.width
let width = self.rtmpStream.videoOrientation.isLandscape ? videoConfig.resolution.width : videoConfig
.resolution.height
let height = self.rtmpStream.videoOrientation.isLandscape ? videoConfig.resolution.height : videoConfig
.resolution.width

self.rtmpStream.videoSettings = VideoCodecSettings(
videoSize: CGSize(width: width, height: height),
Expand Down Expand Up @@ -444,22 +440,16 @@ public class ApiVideoLiveStream {

self.rtmpStream.lockQueue.async {
self.rtmpStream.videoOrientation = orientation
do {
let resolution = try Resolution.getResolution(
width: Int(self.rtmpStream.videoSettings.videoSize.width),
height: Int(self.rtmpStream.videoSettings.videoSize.height)
)
self.rtmpStream.videoSettings.videoSize = CGSize(
width:
self.rtmpStream.videoOrientation.isLandscape ?
resolution.size.width : resolution.size.height,
height:
self.rtmpStream.videoOrientation.isLandscape ?
resolution.size.height : resolution.size.width
)
} catch {
print("Failed to set resolution to orientation \(orientation)")
}

let videoSize = self.rtmpStream.videoSettings.videoSize
self.rtmpStream.videoSettings.videoSize = CGSize(
width:
self.rtmpStream.videoOrientation.isLandscape ?
videoSize.width : videoSize.height,
height:
self.rtmpStream.videoOrientation.isLandscape ?
videoSize.height : videoSize.width
)
}
}
#endif
Expand Down
62 changes: 46 additions & 16 deletions Sources/ApiVideoLiveStream/models/Configuration.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CoreGraphics
import Foundation
import Network

Expand All @@ -14,51 +15,80 @@ public struct AudioConfig {

public struct VideoConfig {
public let bitrate: Int
public let resolution: Resolution
public let resolution: CGSize
public let fps: Float64
public let gopDuration: TimeInterval

/// Creates a video configuration object with default video bitrate
/// Creates a video configuration object with explicit video bitrate and CGSize resolution
/// - Parameters:
/// - bitrate: The video bitrate in bits per second
/// - resolution: The video resolution
/// - fps: The video framerate
/// - gopDuration: The time interval between two key frames
public init(
resolution: Resolution = Resolution.RESOLUTION_720,
bitrate: Int,
resolution: CGSize = CGSize(width: 1_280, height: 720),
fps: Float64 = 30,
gopDuration: TimeInterval = 1.0
) {
self.bitrate = VideoConfig.getDefaultBitrate(resolution: resolution)
self.bitrate = bitrate
self.resolution = resolution
self.fps = fps
self.gopDuration = gopDuration
}

/// Creates a video configuration object with explicit video bitrate
/// Creates a video configuration object with default video bitrate and CGSize resolution
/// - Parameters:
/// - bitrate: The video bitrate in bits per second
/// - resolution: The video resolution
/// - fps: The video framerate
/// - gopDuration: The time interval between two key frames
public init(
bitrate: Int,
resolution: Resolution = Resolution.RESOLUTION_720,
resolution: CGSize = CGSize(width: 1_280, height: 720),
fps: Float64 = 30,
gopDuration: TimeInterval = 1.0
) {
self.bitrate = bitrate
self.bitrate = VideoConfig.getDefaultBitrate(resolution)
self.resolution = resolution
self.fps = fps
self.gopDuration = gopDuration
}

static func getDefaultBitrate(resolution: Resolution) -> Int {
switch resolution {
case Resolution.RESOLUTION_240: return 800_000
case Resolution.RESOLUTION_360: return 1_000_000
case Resolution.RESOLUTION_480: return 1_300_000
case Resolution.RESOLUTION_720: return 2_000_000
case Resolution.RESOLUTION_1080: return 3_500_000
/// Creates a video configuration object with default video bitrate
/// - Parameters:
/// - resolution: The video resolution
/// - fps: The video framerate
/// - gopDuration: The time interval between two key frames
public init(
resolution: Resolution,
fps: Float64 = 30,
gopDuration: TimeInterval = 1.0
) {
self.init(resolution: resolution.rawValue, fps: fps, gopDuration: gopDuration)
}

/// Creates a video configuration object with explicit video bitrate
/// - Parameters:
/// - bitrate: The video bitrate in bits per second
/// - resolution: The video resolution
/// - fps: The video framerate
/// - gopDuration: The time interval between two key frames
public init(
bitrate: Int,
resolution: Resolution,
fps: Float64 = 30,
gopDuration: TimeInterval = 1.0
) {
self.init(bitrate: bitrate, resolution: resolution.rawValue, fps: fps, gopDuration: gopDuration)
}

static func getDefaultBitrate(_ size: CGSize) -> Int {
let numOfPixels = size.width * size.height
switch numOfPixels {
case 0 ... 102_240: return 800_000 // for 4/3 and 16/9 240p
case 102_241 ... 230_400: return 1_000_000 // for 16/9 360p
case 230_401 ... 409_920: return 1_300_000 // for 4/3 and 16/9 480p
case 409_921 ... 921_600: return 2_000_000 // for 4/3 600p, 4/3 768p and 16/9 720p
default: return 3_000_000 // for 16/9 1080p
}
}
}
Expand Down
Loading

0 comments on commit 282b9d9

Please sign in to comment.