What kinds of CMTime are invalid?
There are five possible states:
- +Infinity: This is similar to Float.Infinity. This is a valid value, just greater than any finite number. How might you use it? For example, imagine an API that gives you information about a time range within a video, identified by two CMTimes. You might invoke it with (-Infinity, +Infinity) to ask for information about the entire video.
- -Infinity: This is again similar to -Float.Infinity.
- Indefinite: This is similar to Float.NaN, as I understand. Use this when you don't know what value to use, like the duration of a live stream, as Apple suggests. It wouldn't be right to use infinity, for example, since a live stream doesn't go on for forever. It has a finite duration; we just don't know it yet.
- Invalid: This is a CMTime structure that doesn't obey the rules of CMTime. I assume that means things like a zero or negative denominator. Since CMTime is a C struct, it's not encapsulated, so someone can create one with invalid values like this. C structs can't have initialisers that throw an exception or return nil.
- Numeric: This is the normal case of a finite value. Use CMTIME_IS_NUMERIC to check for this. It returns false for all the weird cases above.
Check if CMTime is in CMTimeRange
CMTimeRange
has a
func containsTime(_ time: CMTime) -> Bool
method, so you can simply check
if range.containsTime(time) {
// ...
}
Remark: The documentation seems to be outdated, the global
function CMTimeRangeContainsTime()
is imported as a member function
to Swift.
Check CMTime Equals
I found the following way to check by converting it to seconds
if(CMTimeGetSeconds(myTime) == CMTimeGetSeconds(kCMTimeZero))
{
// do something...
}
swift and CMTimeMake
CMTime
and CMTimeMake
are defined in the "CoreMedia" module, therefore you have to
import CoreMedia
Then this compiles without problems:
let seconds : Int64 = 10
let preferredTimeScale : Int32 = 1
let aMovieFileOutput = AVCaptureMovieFileOutput()
let maxDuration : CMTime = CMTimeMake(seconds, preferredTimeScale)
aMovieFileOutput.maxRecordedDuration = maxDuration
Update for Swift 3:
let maxDuration = CMTime(seconds: Double(seconds), preferredTimescale: 1)
Modern way of CMTime and CMTimeRange in plist using Swift
Use PropertyListEncoder
/PropertyListDecoder
with a Codable
model type. CMTime
and CMTimeRange
are not Codable
conformant by default, so you need to add the conformance yourself.
extension CMTime: Codable {
enum CodingKeys: String, CodingKey {
case value
case timescale
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let value = try container.decode(CMTimeValue.self, forKey: .value)
let timescale = try container.decode(CMTimeScale.self, forKey: .timescale)
self.init(value: value, timescale: timescale)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(value, forKey: .value)
try container.encode(timescale, forKey: .timescale)
}
}
extension CMTimeRange: Codable {
enum CodingKeys: String, CodingKey {
case start
case duration
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let start = try container.decode(CMTime.self, forKey: .start)
let duration = try container.decode(CMTime.self, forKey: .duration)
self.init(start: start, duration: duration)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(start, forKey: .start)
try container.encode(duration, forKey: .duration)
}
}
struct Model: Codable {
let time: CMTime
let timeRange: CMTimeRange
}
let model = Model(time: CMTime.invalid, timeRange: CMTimeRange(start: CMTime(), end: CMTime()))
do {
let encodedData = try PropertyListEncoder().encode(model)
let decodedData = try PropertyListDecoder().decode(Model.self, from: encodedData)
print(decodedData)
} catch {
print(error)
}
I do not know how to properly use CMTimeRange and CMTime in Swift or Objc
I have solved the above problem with the code below.
let musicAsset = AVAsset(url: (item?.assetURL)!)
self.scwaveScrollView.waveformView.asset = musicAsset
self.scwaveScrollView.waveformView.precision = 1
var duration = CMTimeMakeWithSeconds( 1.0 * CMTimeGetSeconds(self.scwaveScrollView.waveformView.asset.duration), 100000)
self.scwaveScrollView.waveformView.timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0, 10000), duration);
let start = self.scwaveScrollView.waveformView.timeRange.start
duration = CMTime(seconds: 15, preferredTimescale: 1)
self.scwaveScrollView.waveformView.timeRange = CMTimeRangeMake(start, duration)
CMTIME_COMPARE_INLINE in Swift 3?
CMTime
is imported as a Comparable
type in Swift 3, so, you have no need to use CMTIME_COMPARE_INLINE
.
Assuming _previousSecondTimestamps
is of type [CMTime]
(*1), you can write something like this in Swift 3:
let oneSecond = CMTime(seconds: 1.0, preferredTimescale: 1)
let oneSecondAgo = timestamp - oneSecond
while !_previousSecondTimestamps.isEmpty && _previousSecondTimestamps[0] < oneSecondAgo {
_previousSecondTimestamps.remove(at: 0)
}
*1 In Swift, you can declare an Array of CMTime
directly, you have no need to use NSMutableArray
containing NSValue
.
Related Topics
App Crashes from IPA File But Runs Fine from Xcode
How to Get the Kvc-String from Swift 4 Keypath
Pop View Controller Using Screen Edge Pan Gesture Recogniser Not Following the Thumb
How to Suppress a Specific Warning in Swift
More Concise Way to Nest Enums for Access by Switch Statements in Swift
How to Have Arview and Arscnview Coexist
Need Help Converting (Cfpropertylistref *)Nsdictionary to Swift
How to Generate an Auth Token Using Jwt for Google Firebase
How to Declare Protocol Property as Private
Convert JSON Anyobject to Int64
Swift 3:Appdelegate Does Not Conform to Protocol Gidsignindelegate
How to Check If Cmtime Is Valid in Swift
How to Set Realtime Thread in Swift
Require Associatedtype to Be Representable in a @Convention(C) Block
How to Create a Multiline Textfield in Swiftui? Like the Notes App