Reputation: 11084
I have seen some examples of CMTime (Three separate links), but I still don't get it. I'm using an AVCaptureSession with AVCaptureVideoDataOutput and I want to set the max and min frame rate of the the output. My problem is I just don't understand the CMTime struct.
Apparently CMTimeMake(value, timeScale) should give me value frames every 1/timeScale seconds for a total of value/timeScale seconds, or am I getting that wrong?
Why isn't this documented anywhere in order to explain what this does?
If it does truly work like that, how would I get it to have an indefinite number of frames?
If its really simple, I'm sorry, but nothing has clicked just yet.
Upvotes: 81
Views: 38292
Reputation: 657
You're right that CMTime
isn't well documented. Martin R and Doug Voss have already covered a lot of ground, but I thought it would helpful to further explain how init(seconds:preferredTimescale:)
works.
As the other answers have covered, a CMTime
represents time as a rational value. In other words, an integer divided by an integer. The numerator is the number of time units and the denominator is the timescale. The timescale indicates the number of time units per second. A CMTime
may be init with a numerator and denominator (value
and timescale
respectively) or with seconds
and preferredTimescale
. The seconds
and preferredTimescale
init is more intuitive, I think, but only just. To determine the value
(numerator) of a CMTime
init with seconds
and preferredTimescale
:
value = seconds * preferredTimescale
So, for CMTime(seconds: 0.25, preferredTimescale: 4)
:
value
= (0.25 * 4) = 1 so, the CMTime
is 1/4 or 0.25.
Remember, value
and preferredTimescale
are both integers (Int64) so not all combinations of value
and preferredTimescale
can be represented precisely. As an example of a time that can't be represented precisely, consider 1.6 seconds with a preferred timescale of 3:
value
= 1.6 * 3 = 4.8 ~ 4
This would represent 4/3 or 1.33, rather than the intended 1.6. When rounding occurs, the CMTime
will set hasBeenRounded
to true.
Upvotes: 1
Reputation: 1209
CMTime(seconds: value, timescale: scale)
means value/scale in a just one second
Upvotes: -1
Reputation: 61
My experience differs.
For let testTime = CMTime(seconds: 3.83, preferredTimescale: 100)
If you set a breakpoint and look in the debugger side window it says:
"383 100ths of a second"
Testing by seeking to a fixed offset in a video in AVPlayer has confirmed this.
So put the actual number of seconds in the seconds field, and the precision in the preferredTimescale field. So 100 means precision of hundredths of a second.
Doing
let testTime = CMTime(seconds: 3.83, preferredTimescale: 100)
Still seeks to the same place in the video, but it displays in the debugger side window as "3833 1000ths of a second"
Doing
let testTime = CMTime(seconds: 3.83, preferredTimescale: 1)
Does not seek to the same place in the video, because it's been truncated, and it displays in the debugger side window as "3 seconds". Notice that the .833 part has been lost due to the preferredTimescale.
Upvotes: 6
Reputation: 540045
A CMTime
struct represents a length of time that is stored as rational number (see CMTime Reference). CMTime
has a value
and a timescale
field, and represents the time value/timescale seconds
.
CMTimeMake
is a function that returns a CMTime
structure, for example:
CMTime t1 = CMTimeMake(1, 10); // 1/10 second = 0.1 second
CMTime t2 = CMTimeMake(2, 1); // 2 seconds
CMTime t3 = CMTimeMake(3, 4); // 3/4 second = 0.75 second
CMTime t4 = CMTimeMake(6, 8); // 6/8 second = 0.75 second
The last two time values t3
and t4
represent the same time value, therefore
CMTimeCompare(t3, t4) == 0
If you set the videoMinFrameDuration
of a AVCaptureSession
is does not make a difference if you set
connection.videoMinFrameDuration = CMTimeMake(1, 20); // or
connection.videoMinFrameDuration = CMTimeMake(2, 40);
In both cases the minimum time interval between frames is set to 1/20 = 0.05 seconds.
Upvotes: 193