407 lines
20 KiB
C
407 lines
20 KiB
C
//
|
|
// ProResTime.h
|
|
// Copyright © 2017 Apple. All rights reserved.
|
|
//
|
|
|
|
#ifndef PRORESTIME_H
|
|
#define PRORESTIME_H 1
|
|
|
|
/*!
|
|
@header
|
|
@abstract API for creating and manipulating PRTime structs.
|
|
@discussion PRTime structs are non-opaque mutable structs representing times (either timestamps or durations).
|
|
|
|
A PRTime is represented as a rational number, with a numerator (int64_t value), and a denominator (int32_t timescale).
|
|
A flags field allows various non-numeric values to be stored (+infinity, -infinity, indefinite, invalid). There is also
|
|
a flag to mark whether or not the time is completely precise, or had to be rounded at some point in its past.
|
|
|
|
PRTimes contain an epoch number, which is usually set to 0, but can be used to distinguish unrelated
|
|
timelines: for example, it could be incremented each time through a presentation loop,
|
|
to differentiate between time N in loop 0 from time N in loop 1.
|
|
*/
|
|
|
|
#include "ProResTypes.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#pragma pack(push, 4)
|
|
|
|
/*!
|
|
@typedef PRTimeValue
|
|
@abstract Numerator of rational PRTime.
|
|
*/
|
|
typedef int64_t PRTimeValue;
|
|
|
|
/*!
|
|
@typedef PRTimeScale
|
|
@abstract Denominator of rational PRTime.
|
|
@discussion Timescales must be positive.
|
|
Note: kCMTimeMaxTimescale is NOT a good choice of timescale for movie files.
|
|
(Recommended timescales for movie files range from 600 to 90000.)
|
|
*/
|
|
typedef int32_t PRTimeScale;
|
|
#define kPRTimeMaxTimescale 0x7fffffffL
|
|
|
|
/*!
|
|
@typedef PRTimeEpoch
|
|
@abstract Epoch (eg, loop number) to which a PRTime refers.
|
|
*/
|
|
typedef int64_t PRTimeEpoch;
|
|
|
|
/*!
|
|
@enum PRTimeFlags
|
|
@abstract Flag bits for a PRTime.
|
|
@constant kPRTimeFlags_Valid Must be set, or the PRTime is considered invalid.
|
|
Allows simple clearing (eg. with calloc or memset) for initialization
|
|
of arrays of PRTime structs to "invalid". This flag must be set, even
|
|
if other flags are set as well.
|
|
@constant kPRTimeFlags_HasBeenRounded Set whenever a PRTime value is rounded, or is derived from another rounded PRTime.
|
|
@constant kPRTimeFlags_PositiveInfinity Set if the PRTime is +inf. "Implied value" flag (other struct fields are ignored).
|
|
@constant kPRTimeFlags_NegativeInfinity Set if the PRTime is -inf. "Implied value" flag (other struct fields are ignored).
|
|
@constant kPRTimeFlags_Indefinite Set if the PRTime is indefinite/unknown. Example of usage: duration of a live broadcast.
|
|
"Implied value" flag (other struct fields are ignored).
|
|
*/
|
|
enum {
|
|
kPRTimeFlags_Valid = 1UL<<0,
|
|
kPRTimeFlags_HasBeenRounded = 1UL<<1,
|
|
kPRTimeFlags_PositiveInfinity = 1UL<<2,
|
|
kPRTimeFlags_NegativeInfinity = 1UL<<3,
|
|
kPRTimeFlags_Indefinite = 1UL<<4,
|
|
kPRTimeFlags_ImpliedValueFlagsMask = kPRTimeFlags_PositiveInfinity | kPRTimeFlags_NegativeInfinity | kPRTimeFlags_Indefinite
|
|
};
|
|
typedef uint32_t PRTimeFlags;
|
|
|
|
/*!
|
|
@typedef PRTime
|
|
@abstract Rational time value represented as int64/int32.
|
|
*/
|
|
typedef struct {
|
|
PRTimeValue value; /*! @field value The value of the PRTime. value/timescale = seconds. */
|
|
PRTimeScale timescale; /*! @field timescale The timescale of the PRTime. value/timescale = seconds. */
|
|
PRTimeFlags flags; /*! @field flags The flags, eg. kPRTimeFlags_Valid, kPRTimeFlags_PositiveInfinity, etc. */
|
|
PRTimeEpoch epoch; /*! @field epoch Differentiates between equal timestamps that are actually different because
|
|
of looping, multi-item sequencing, etc.
|
|
Will be used during comparison: greater epochs happen after lesser ones.
|
|
Additions/subtraction is only possible within a single epoch,
|
|
however, since epoch length may be unknown/variable. */
|
|
} PRTime;
|
|
|
|
/*!
|
|
@function PRTIME_IS_VALID
|
|
@abstract Returns whether a PRTime is valid.
|
|
@discussion This is a macro that evaluates a Boolean result.
|
|
@result Returns true if the PRTime is valid, false if it is invalid.
|
|
*/
|
|
#define PRTIME_IS_VALID(time) ((bool)(((time).flags & kPRTimeFlags_Valid) != 0))
|
|
|
|
/*!
|
|
@function PRTIME_IS_INVALID
|
|
@abstract Returns whether a PRTime is invalid.
|
|
@discussion This is a macro that evaluates a Boolean result.
|
|
@result Returns true if the PRTime is invalid, false if it is valid.
|
|
*/
|
|
#define PRTIME_IS_INVALID(time) (!PRTIME_IS_VALID(time))
|
|
|
|
/*!
|
|
@function PRTIME_IS_POSITIVEINFINITY
|
|
@abstract Returns whether a PRTime is positive infinity. Use this instead of (myTime == kPRTimePositiveInfinity),
|
|
since there are many PRTime structs that represent positive infinity. This is because the non-flags fields are ignored,
|
|
so they can contain anything.
|
|
@discussion This is a macro that evaluates a Boolean result.
|
|
@result Returns true if the PRTime is positive infinity, false if it is not.
|
|
*/
|
|
#define PRTIME_IS_POSITIVE_INFINITY(time) ((bool)(PRTIME_IS_VALID(time) && (((time).flags & kPRTimeFlags_PositiveInfinity) != 0)))
|
|
|
|
/*!
|
|
@function PRTIME_IS_NEGATIVEINFINITY
|
|
@abstract Returns whether a PRTime is negative infinity.
|
|
@discussion This is a macro that evaluates a Boolean result.
|
|
@result Returns true if the PRTime is negative infinity, false if it is not.
|
|
*/
|
|
#define PRTIME_IS_NEGATIVE_INFINITY(time) ((bool)(PRTIME_IS_VALID(time) && (((time).flags & kPRTimeFlags_NegativeInfinity) != 0)))
|
|
|
|
/*!
|
|
@function PRTIME_IS_INDEFINITE
|
|
@abstract Returns whether a PRTime is indefinite.
|
|
@discussion This is a macro that evaluates to a Boolean result.
|
|
@result Returns true if the PRTime is indefinite, false if it is not.
|
|
*/
|
|
#define PRTIME_IS_INDEFINITE(time) ((Boolean)(PRTIME_IS_VALID(time) && (((time).flags & kPRTimeFlags_Indefinite) != 0)))
|
|
|
|
/*!
|
|
@function PRTIME_IS_NUMERIC
|
|
@abstract Returns whether a PRTime is numeric (ie. contains a usable value/timescale/epoch).
|
|
@discussion This is a macro that evaluates to a Boolean result.
|
|
@result Returns false if the PRTime is invalid, indefinite or +/- infinity.
|
|
Returns true otherwise.
|
|
*/
|
|
#define PRTIME_IS_NUMERIC(time) ((bool)(((time).flags & (kPRTimeFlags_Valid | kPRTimeFlags_ImpliedValueFlagsMask)) == kPRTimeFlags_Valid))
|
|
|
|
/*!
|
|
@function PRTIME_HAS_BEEN_ROUNDED
|
|
@abstract Returns whether a PRTime has been rounded.
|
|
@discussion This is a macro that evaluates a Boolean result.
|
|
@result Returns true if the PRTime has been rounded, false if it is completely accurate.
|
|
*/
|
|
#define PRTIME_HAS_BEEN_ROUNDED(time) ((bool)(PRTIME_IS_NUMERIC(time) && (((time).flags & kPRTimeFlags_HasBeenRounded) != 0)))
|
|
|
|
PR_EXPORT const PRTime kPRTimeInvalid; /*! @constant kPRTimeInvalid
|
|
Use this constant to initialize an invalid PRTime.
|
|
All fields are 0, so you can calloc or fill with 0's to make lots of them.
|
|
Do not test against this using (time == kPRTimeInvalid), there are many
|
|
PRTimes other than this that are also invalid.
|
|
Use !PRTIME_IS_VALID(time) instead. */
|
|
PR_EXPORT const PRTime kPRTimeIndefinite; /*! @constant kPRTimeIndefinite
|
|
Use this constant to initialize an indefinite PRTime (eg. duration of a live
|
|
broadcast). Do not test against this using (time == kPRTimeIndefinite),
|
|
there are many PRTimes other than this that are also indefinite.
|
|
Use PRTIME_IS_INDEFINITE(time) instead. */
|
|
PR_EXPORT const PRTime kPRTimePositiveInfinity; /*! @constant kPRTimePositiveInfinity
|
|
Use this constant to initialize a PRTime to +infinity.
|
|
Do not test against this using (time == kPRTimePositiveInfinity),
|
|
there are many PRTimes other than this that are also +infinity.
|
|
Use PRTIME_IS_POSITIVEINFINITY(time) instead. */
|
|
PR_EXPORT const PRTime kPRTimeNegativeInfinity; /*! @constant kPRTimeNegativeInfinity
|
|
Use this constant to initialize a PRTime to -infinity.
|
|
Do not test against this using (time == kPRTimeNegativeInfinity),
|
|
there are many PRTimes other than this that are also -infinity.
|
|
Use PRTIME_IS_NEGATIVEINFINITY(time) instead. */
|
|
PR_EXPORT const PRTime kPRTimeZero; /*! @constant kPRTimeZero
|
|
Use this constant to initialize a PRTime to 0.
|
|
Do not test against this using (time == kPRTimeZero),
|
|
there are many PRTimes other than this that are also 0.
|
|
Use PRTimeCompare(time, kPRTimeZero) instead. */
|
|
|
|
/*!
|
|
@function PRTimeMake
|
|
@abstract Make a valid PRTime with value and timescale.
|
|
@result The resulting PRTime.
|
|
*/
|
|
PR_EXPORT
|
|
PRTime PRTimeMake(
|
|
int64_t value, /*! @param value Initializes the value field of the resulting CMTime. */
|
|
int32_t timescale); /*! @param timescale Initializes the timescale field of the resulting CMTime. */
|
|
|
|
/*!
|
|
@enum PRTimeRoundingMethod
|
|
@abstract Rounding method to use when computing time.value during timescale conversions.
|
|
@constant kPRTimeRoundingMethod_Round Round towards zero if abs(fraction) is less than 0.5, away from 0 if abs(fraction) is >= 0.5.
|
|
@constant kPRTimeRoundingMethod_Default Synonym for kPRTimeRoundingMethod_Round.
|
|
@constant kPRTimeRoundingMethod_Truncate Round towards zero if fraction is != 0.
|
|
@constant kPRTimeRoundingMethod_RoundUp Round away from zero if abs(fraction) is > 0.
|
|
@constant kPRTimeRoundingMethod_QuickTime Use kPRTimeRoundingMethod_Truncate if converting from larger to smaller scale
|
|
(ie. from more precision to less precision), but use kPRTimeRoundingMethod_RoundUp
|
|
if converting from smaller to larger scale (ie. from less precision to more precision).
|
|
Also, never round a negative number down to 0; always return the smallest magnitude
|
|
negative PRTime in this case (-1/newTimescale).
|
|
*/
|
|
enum {
|
|
kPRTimeRoundingMethod_RoundHalfAwayFromZero = 1,
|
|
kPRTimeRoundingMethod_RoundTowardZero = 2,
|
|
kPRTimeRoundingMethod_RoundAwayFromZero = 3,
|
|
kPRTimeRoundingMethod_QuickTime = 4,
|
|
kPRTimeRoundingMethod_RoundTowardPositiveInfinity = 5,
|
|
kPRTimeRoundingMethod_RoundTowardNegativeInfinity = 6,
|
|
|
|
kPRTimeRoundingMethod_Default = kPRTimeRoundingMethod_RoundHalfAwayFromZero
|
|
};
|
|
typedef uint32_t PRTimeRoundingMethod;
|
|
|
|
/*!
|
|
@function PRTimeConvertScale
|
|
@abstract Returns a new PRTime containing the source PRTime converted to a new timescale (rounding as requested).
|
|
@discussion If the value needs to be rounded, the kPRTimeFlags_HasBeenRounded flag will be set.
|
|
See definition of PRTimeRoundingMethod for a discussion of the various rounding methods available. If
|
|
the source time is non-numeric (ie. infinite, indefinite, invalid), the result will be similarly non-numeric.
|
|
@result The converted result PRTime.
|
|
*/
|
|
PR_EXPORT
|
|
PRTime PRTimeConvertScale(
|
|
PRTime time, /*! @param time Source PRTime. */
|
|
int32_t newTimescale, /*! @param newTimescale The requested timescale for the converted result PRTime. */
|
|
PRTimeRoundingMethod method); /*! @param method The requested rounding method. */
|
|
|
|
/*!
|
|
@function PRTimeAdd
|
|
@abstract Returns the sum of two PRTimes.
|
|
@discussion If the operands both have the same timescale, the timescale of the result will be the same as
|
|
the operands' timescale. If the operands have different timescales, the timescale of the result
|
|
will be the least common multiple of the operands' timescales. If that LCM timescale is
|
|
greater than kPRTimeMaxTimescale, the result timescale will be kPRTimeMaxTimescale,
|
|
and default rounding will be applied when converting the result to this timescale.
|
|
|
|
If the result value overflows, the result timescale will be repeatedly halved until the result
|
|
value no longer overflows. Again, default rounding will be applied when converting the
|
|
result to this timescale. If the result value still overflows when timescale == 1, then the
|
|
result will be either positive or negative infinity, depending on the direction of the
|
|
overflow.
|
|
|
|
If any rounding occurs for any reason, the result's kPRTimeFlags_HasBeenRounded flag will be
|
|
set. This flag will also be set if either of the operands has kPRTimeFlags_HasBeenRounded set.
|
|
|
|
If either of the operands is invalid, the result will be invalid.
|
|
|
|
If the operands are valid, but just one operand is infinite, the result will be similarly
|
|
infinite. If the operands are valid, and both are infinite, the results will be as follows:
|
|
<ul> +infinity + +infinity == +infinity
|
|
<br> -infinity + -infinity == -infinity
|
|
<br> +infinity + -infinity == invalid
|
|
<br> -infinity + +infinity == invalid
|
|
</ul>
|
|
If the operands are valid, not infinite, and either or both is indefinite, the result
|
|
will be indefinite.
|
|
|
|
If the two operands are numeric (ie. valid, not infinite, not indefinite), but have
|
|
different epochs, the result will be invalid. Times in different epochs cannot be
|
|
added or subtracted, because epoch length is unknown. Times in different epochs can
|
|
be compared, however, because numerically greater epochs always occur after numerically
|
|
lesser epochs.
|
|
@result The sum of the two PRTimes (addend1 + addend2).
|
|
*/
|
|
PR_EXPORT
|
|
PRTime PRTimeAdd(
|
|
PRTime addend1, /*! @param addend1 A PRTime to be added. */
|
|
PRTime addend2 /*! @param addend2 Another PRTime to be added. */
|
|
);
|
|
/*!
|
|
@function PRTimeSubtract
|
|
@abstract Returns the difference of two PRTimes.
|
|
@discussion If the operands both have the same timescale, the timescale of the result will be the same as
|
|
the operands' timescale. If the operands have different timescales, the timescale of the result
|
|
will be the least common multiple of the operands' timescales. If that LCM timescale is
|
|
greater than kPRTimeMaxTimescale, the result timescale will be kPRTimeMaxTimescale,
|
|
and default rounding will be applied when converting the result to this timescale.
|
|
|
|
If the result value overflows, the result timescale will be repeatedly halved until the result
|
|
value no longer overflows. Again, default rounding will be applied when converting the
|
|
result to this timescale. If the result value still overflows when timescale == 1, then the
|
|
result will be either positive or negative infinity, depending on the direction of the
|
|
overflow.
|
|
|
|
If any rounding occurs for any reason, the result's kPRTimeFlags_HasBeenRounded flag will be
|
|
set. This flag will also be set if either of the operands has kPRTimeFlags_HasBeenRounded set.
|
|
|
|
If either of the operands is invalid, the result will be invalid.
|
|
|
|
If the operands are valid, but just one operand is infinite, the result will be similarly
|
|
infinite. If the operands are valid, and both are infinite, the results will be as follows:
|
|
<ul> +infinity - +infinity == invalid
|
|
<li> -infinity - -infinity == invalid
|
|
<li> +infinity - -infinity == +infinity
|
|
<li> -infinity - +infinity == -infinity
|
|
</ul>
|
|
If the operands are valid, not infinite, and either or both is indefinite, the result
|
|
will be indefinite.
|
|
|
|
If the two operands are numeric (ie. valid, not infinite, not indefinite), but have
|
|
different nonzero epochs, the result will be invalid. If they have the same nonzero
|
|
epoch, the result will have epoch zero (a duration). Times in different epochs
|
|
cannot be added or subtracted, because epoch length is unknown. Times in epoch zero
|
|
are considered to be durations and can be subtracted from times in other epochs.
|
|
Times in different epochs can be compared, however, because numerically greater
|
|
epochs always occur after numerically lesser epochs.
|
|
@result The difference of the two PRTimes (minuend - subtrahend).
|
|
*/
|
|
PR_EXPORT
|
|
PRTime PRTimeSubtract(
|
|
PRTime minuend,
|
|
PRTime subtrahend);
|
|
|
|
/*!
|
|
@function PRTimeCompare
|
|
@abstract Returns the numerical relationship (-1 = less than, 1 = greater than, 0 = equal) of two PRTimes.
|
|
@discussion If the two PRTimes are numeric (ie. not invalid, infinite, or indefinite), and have
|
|
different epochs, it is considered that times in numerically larger epochs are always
|
|
greater than times in numerically smaller epochs.
|
|
|
|
Since this routine will be used to sort lists by time, it needs to give all values
|
|
(even invalid and indefinite ones) a strict ordering to guarantee that sort algorithms
|
|
terminate safely. The order chosen is somewhat arbitrary:
|
|
|
|
-infinity < all finite values < indefinite < +infinity < invalid
|
|
|
|
Invalid PRTimes are considered to be equal to other invalid PRTimes, and larger than
|
|
any other PRTime. Positive infinity is considered to be smaller than any invalid PRTime,
|
|
equal to itself, and larger than any other PRTime. An indefinite PRTime is considered
|
|
to be smaller than any invalid PRTime, smaller than positive infinity, equal to itself,
|
|
and larger than any other PRTime. Negative infinity is considered to be equal to itself,
|
|
and smaller than any other PRTime.
|
|
|
|
-1 is returned if time1 is less than time2. 0 is returned if they
|
|
are equal. 1 is returned if time1 is greater than time2.
|
|
@result The numerical relationship of the two PRTimes (-1 = less than, 1 = greater than, 0 = equal).
|
|
*/
|
|
PR_EXPORT
|
|
int32_t PRTimeCompare(
|
|
PRTime time1, /*! @param time1 First PRTime in comparison. */
|
|
PRTime time2); /*! @param time2 Second PRTime in comparison. */
|
|
|
|
/*!
|
|
@function PRTIME_COMPARE_INLINE
|
|
@abstract Returns whether the specified comparison of two PRTimes is true.
|
|
@discussion This is a macro that evaluates a Boolean result.
|
|
Example of usage:
|
|
PRTIME_COMPARE_INLINE(time1, <=, time2) will return true if time1 <= time2.
|
|
@param time1 First time to compare
|
|
@param comparator Comparison operation to perform (eg. <=).
|
|
@param time2 Second time to compare
|
|
@result Returns the result of the specified PRTime comparison.
|
|
*/
|
|
#define PRTIME_COMPARE_INLINE(time1, comparator, time2) ((bool)(PRTimeCompare(time1, time2) comparator 0))
|
|
|
|
/*!
|
|
@function PRTimeGetSeconds
|
|
@abstract Converts a PRTime to seconds.
|
|
@discussion If the PRTime is invalid or indefinite, NAN is returned. If the PRTime is infinite, +/- __inf()
|
|
is returned. If the PRTime is numeric, epoch is ignored, and time.value / time.timescale is
|
|
returned. The division is done in double, so the fraction is not lost in the returned result.
|
|
@result The resulting double number of seconds.
|
|
*/
|
|
PR_EXPORT
|
|
double PRTimeGetSeconds(
|
|
PRTime time);
|
|
|
|
/*!
|
|
@typedef PRTimeRange
|
|
@discussion PRTimeRange structs are non-opaque mutable structs that represent time ranges.
|
|
|
|
A PRTimeRange is represented as two PRTime structs, one that specifies the start time of the
|
|
range and another that specifies the duration of the range. A time range does not include the time
|
|
that is the start time plus the duration.
|
|
*/
|
|
typedef struct
|
|
{
|
|
PRTime start; /*! @field start The start time of the time range. */
|
|
PRTime duration; /*! @field duration The duration of the time range. */
|
|
} PRTimeRange;
|
|
|
|
/*!
|
|
@typedef PRTimeMapping
|
|
@abstract A PRTimeMapping specifies the mapping of a segment of one time line (called "source") into another time line (called "target").
|
|
@discussion
|
|
When used for movie edit lists, the source time line is the media and the target time line is the track/movie.
|
|
@field source
|
|
The time range on the source time line.
|
|
For an empty edit, source.start is an invalid PRTime, in which case source.duration shall be ignored.
|
|
Otherwise, source.start is the starting time within the source, and source.duration is the duration
|
|
of the source timeline to be mapped to the target time range.
|
|
@field target
|
|
The time range on the target time line.
|
|
If target.duration and source.duration are different, then the source segment should
|
|
be played at rate source.duration/target.duration to fit.
|
|
*/
|
|
typedef struct {
|
|
PRTimeRange source;
|
|
PRTimeRange target;
|
|
} PRTimeMapping;
|
|
|
|
#pragma pack(pop)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // PRORESTIME_H
|