CMTime
QTKit では、QTTime で時間の処理を行っていたが、AVFoundation の AVKit では CMTime を使う。
QTTime は、timeValue, timeScale, flags でできていたが、CMTime は value, timescale, flags, epoch から成る。QTTime からの変換時は、timeValue を value に timeScale を timescale(s が小文字)に代える必要がある。
CMTime (cmTime) から value, timescale を取り出したい場合は、次のようにする。
timeValue = cmTime.value
timeScale = cmTime.timescale
(timeValue = qtTime.timeValue)
(timeScale = qtTime.timeScale)
CMTime は、CMTimeMake で CMTime value もしくは、CMTimeMakeWithSeconds で秒数と timescale を指定して作ることができる(他にもあるが)。
cmTime = CMTimeMake(value,timescale)
cmTime = CMTimeMakeWithSeconds(seconds,timescale)
(qtTime = QTMakeTime(timeValue,timeScale))
QuickTime は d:hh:mm:ss.xxx という書式で時間を扱うこともあったので、QTTimeFromString という便利なのがあったのだが、CMTime にはどうもないらしい。なので、とりあえず hh:mm:ss.xxx の時間表時を CMTime にするために、次のようなスクリプトを書いてみた。もしちゃんとした方法が見つかったり、もっといい方法があったら、追記するか書き換えるつもり。
timeCodeText.match(/[(\d+?):(\d+?):(\d+?)\.(\d+)\]/)
cmTimeValue = ($1.to_i * 3600 + $2.to_i * 60 + $3.to_i) * 1000 + $4.to_i
cmTime = CMTimeMake(cmTimeValue,1000)
cmTime = CMTimeMakeWithSeconds(initTime/1000.0,playerItem.timescale)
何をしているかというと、hh:mm:ss.xxx という形式を match で後方参照で取り出して CMTime value を計算しているだけ。ここでは、テキストの時間表示の time scale が 1000 ということにしているが、QTTime でよくある 600 の場合は 1000 の所を 600 に代えればいけるはず。そして、CMTimeMake で、timescale を 1000 にして作るか、1000.0 で割ったものが秒数になるので、それと、扱っているメディアファイルから作った AVPlayerItem の timescale を使って、CMTimeMakeWithSeconds で CMTime にしている。
CMTime から情報を得るものには、次のようなものがある。
absoluteTime = CMTimeAbsoluteValue(cmTime)
seconds = CMTimeGetSeconds(cmTime)
newTime = CMTimeConvertScale(cmTime,newTimeScale,CMTimeRoundingMethod)
CMTimeShow(cmTime)
(newTime = QTMakeTimeScaled(time,timeScale))
CMTimeAbsoluteValue(cmTime) - value が正の場合は CMTime そのものが返る。負の値の場合には正の値が返る(はず)。
CMTimeGetSeconds(cmTime) - CMTime の秒数が返ってくる。つまり value/timescale の値。64-bit float で返ると書いてあるが、RubyMotion だと float かな?
CMTimeConvertScale(cmTime,newTimeScale,CMTimeRoundingMethod) - kCMTimeRoundingMethod_RoundHalfAwayFromZero (1), kCMTimeRoundingMethod_RoundTowardZero (2), kCMTimeRoundingMethod_RoundAwayFromZero (3), kCMTimeRoundingMethod_QuickTime (4), kCMTimeRoundingMethod_RoundTowardPositiveInfinity (5), kCMTimeRoundingMethod_RoundTowardNegativeInfinity (6)。
CMTimeShow(cmTime) - どのように使うのかはわからないが、中身を見るもの?という感じで、value/timescale = seconds (それぞれ実際の値)というのが返ってきた。
2 つの CMTime を比較する場合は、次の方法がある。
comparison = CMTimeCompare(cmTime1,cmTime2)
largerCMTime = CMTimeMaximum(cmTime1,cmTime2)
smallerCMTime = CMTimeMinimum(cmTime1,cmTime2)
(QTTimeCompare(qtTime1,qtTime2))
CMTimeCompare(cmTime1,cmTime2) - 1: cmTime1 > cmTime2, -1: cmTime1 < cmTime2, 0: cmTime1 = cmTime2。QTTimeCompare と同じっぽい。
CMTimeMaximum(cmTime1,cmTime2) - 2 つの CMTime のうち大きい方が返る。
CMTimeMinimum(cmTime1,cmTime2) - 2 つの CMTime のうち小さい方が返る。
newCMTime = CMTimeAdd(cmTime1,cmTime2)
newCMTime = CMTimeSubtract(cmTime1,cmTime2)
newCMTime = CMTimeMultiply(cmTime1,multiplier)
QTTimeIncrement(qtTime1,qtTime2)
QTTimeDecrement(qtTime1,qtTime2)
CMTimeAdd(cmTime1,cmTime2) - 2 つの CMTime を加算する。QTTimeIncrement と同じっぽい。
CMTimeSubtract(cmTime1,cmTime2) - cmTime1 から cmTime2 を引く。QTTimeDecrement と同じっぽい。
CMTimeMultiply(cmTime,multiplier) - cmTime を multiplier で乗算する。multiplier は 32-bit integer。つまり、32-bit で扱える範囲の integer。
QTTimeRange に対応するのが CMTimeRange。CMTimeRange は start と duration が CMTime で保持されている。
startTime = cmTimeRange.start
duration = cmTimeRange.duration
(startTime = qtTimeRange.time)
(duration = qtTimeRange.duration)
CMTimeRange を得るには、CMTimeRangeMake で、start と duration を CMTime で指定する。もしくは、CMTimeRangeFromTimeToTime で、start と end を CMTime で指定する。QTTimeRange のときも同じで、QTMakeTimeRange で start にあたる time と duration を指定した。
timeRange = CMTimeRangeMake(start,duration)
timeRange = CMTimeRangeFromTimeToTime(start,end)
(timeRange = QTMakeTimeRange(time,duration))
CMTimeRange の情報を得る方法。
endTime = CMTimeRangeGetEnd(cmRange)
crossedRange = CMTimeRangeGetIntersection(cmRange1,cmRange2)
(endTime = QTTimeRangeEnd(qtRange))
(crossedRange = QTIntersectionTimeRange(qtRange1,qtRange2))
CMTimeRangeGetEnd(cmRange) - cmRange の終わりの時間が CMTime で得られる。
CMTimeRangeGetIntersection(cmRange1,cmRange2) - cmRange1 と cmRange2 が重なる部分が CMTimeRange として返る。
CMTimeRange が同じかどうか、time もしくは range を含むかどうかのチェックができる。
true/false = CMTimeRangeEqual(cmRange1,cmRange2)
true/false = CMTimeRangeContainsTime(cmRange,cmTime)
true/false = CMTimeRangeContainsTimeRange(cmRange1,cmRange2)
(true/false = QTEqualTimeRanges(qtRange1,qtRange2))
(true/false = QTTimeInTimeRange(time,qtRange))
CMTimeRangeEqual(cmRange1,cmRange2) - cmRange1 と cmRange2 が等しいかどうかのチェック。
CMTimeRangeContainsTime(cmRange,cmTime) - cmTime が cmRange に含まれているかどうかのチェック。
CMTimeRangeContainsTimeRange(cmRange1,cmRange2) - cmRange2 が cmRange1 に含まれているかどうかのチェック。
2 つの range で長さが異なる場合に、range が変換された場合に指定した CMTime および duration が取る値を返す方法もある。
mappedTime = CMTimeMapTimeFromRangeToRange(cmTime,cmRange1,cmRange2)
mappedDuration = CMTimeMapDurationFromRangeToRange(duration,cmRange1,cmRange2)
CMTimeMapTimeFromRangeToRange(cmTime,cmRange1,cmRange2) - cmRange1 が cmRange2 に変換された場合(トラックを追加するなどして cmRange1 を cmRange2 に合わせる場合など)に、cmRange1 での cmTime の値が、cmRange2 になった場合に取る値を CMTime で返す。
CMTimeMapDurationFromRangeToRange(cmTime,cmRange1,cmRange2) - cmRange1 が cmRange2 に変換された場合(トラックを追加するなどして cmRange1 を cmRange2 に合わせる場合など)に、cmRange1 での duration (CMTime) が、cmRange2 になった場合に取る値を CMTime で返す。上とほぼ同じ?