CMTimeの使用について

画像 こんにちは、Habr! CMTimeの理解と応用に関するWarren Mooreの記事の翻訳を読むことをお勧めします。 ビデオの操作に関連する以前の投稿で、これらのすばらしい非常に重要な構造について詳細に話すことを約束しました。 主な焦点は、時間を見てCMTimeの構造を説明することの重要性になりますが、最も単純な例がないと意味がありません。



時間推定の重要性と精度


ほとんどの人は時間の正確さについて考える必要はありません。 極端な場合を考えてみましょう。あなたは、100メートルのレースでのスピードと世界記録の差をミリ秒単位で気にするオリンピックランナーかもしれません。 これらの結果はほぼ同じです。 それでも、タイムリーな情報に関しては、非常に短い間隔(数十マイクロ秒)が重要ですが、これらのセグメントは数日または数週間である場合があります。

ムービーの正確なフレームを、たとえば35:06に設定するとします。 時間を倍精度浮動小数点数として表すのは単純です。たとえば、次のようになります。

NSTimeInterval t = 2106.0;
      
      





多くの場合、このような表現は問題の状態に非常に適していますが、小さなコンポーネントに押しつぶされる非常に長い間隔になると適用されません。 浮動小数点数の詳細に入らない場合、doubleは8バイトで16桁(10進数)の有効数字を含むことができます。

 sizeof(NSTimeInterval) == sizeof(Float64) == sizeof(double) == 8
      
      





浮動小数点数は1つの問題によって結合されます。繰り返し操作(加算、乗算など)は不正確さの増加につながり、長期間後に顕著な不一致につながる可能性があります。 そして、これにより、情報の複数のストリームの同期でエラーが発生する可能性があります。



最も簡単な例
0.000001に等しい100万個の要素を合計すると、10000000000079181になります。 このエラーは、1e-6を浮動小数点形式(この例で使用)で正確に表すことができず、代わりに下位ビットが異なるバイナリ近似を使用しているために発生します。 このエラーはそれほど重大ではありませんが、HTTP Streaming Serverの使用に関しては、エラーは無期限に1秒あたり数千回増加します。




これが、浮動小数点数の使用とこの不正確さで終わる時間をより正確に表現する方法を見つけるきっかけとなりました(粗い丸め動作は言うまでもありません)。



有理数としての時間


MAC OSとiOSの両方の時間を表すためにAppleによって作成された多くのデータ構造があります。 MAC OS X 10.7とiOS 4の出現により、さらに2つが追加されました。

 CMTime CMTimeRange
      
      





最初のものを理解すると、2番目のものを簡単に理解できるので、この記事では読者がCMTimeに焦点を当てます。



実際、CMTimeは4メンバー構造にすぎず、次のようになります。

 typedef struct { CMTimeValue value; CMTimeScale timescale; CMTimeFlags flags; CMTimeEpoch epoch; } CMTime;
      
      







次に、 valuetimescaleを詳しく調べますが、 フラグについては言及する価値があります。 フラグのさまざまな値は、タイムスタンプ( 以降、時間間隔 )が無限のプラスまたはマイナスに等しくなる可能性があること、またはいくつかの計算の結果として丸められる可能性があることを示しています。 したがって、構造はNSTimeIntervalよりも表現力があり、多くの利点があります。 実際にCMTimeで表現されるものは何ですか?



タイムスケールはそれぞれ64ビットと32ビットの整数として保存されることを理解することは非常に重要です。 これは、上記のテキストから明らかなはずです。なぜなら、 は、例で与えられたものと同一のエラーを避けるような方法で提示されるからです。 さらに、合計64ビットを分母に割り当てることにより、可能なタイムスケール値ごとに最大19桁の10進数を使用できます。



タイムスケールとは何ですか? これは、各秒が分割される「スライス」の数を表します。 オブジェクト全体のCMTimeの精度はこの値に制限されるため、これは重要です。



別の例
タイムスケール値が1の場合、オブジェクトで表される時間間隔は1秒以上になり、ステップも1秒になります。 同様に、 timescale = 1000の場合、各秒は1000個に分割され、 valueには指定するミリ秒数が含まれます。





トリミングされたピースを取得しないように適切なタイムスケールを選択する方法は? Appleはビデオに600を推奨しています(24、25、および30フレーム/秒のほとんどのビデオでは600が一般的であると説明しています)。 オーディオファイルの正確なインデックス作成が必要な場合は、値を60,000に設定できます。 この64ビット の優れた点は、このパスに沿って1/60000秒単位で580万年を想像できることです



タイムスパンの秒数はt.value / t.timescaleにすぎません。 CMTimeGetSecondsを使用して、最大精度を保証するような方法でCMTimeを簡単にfloat64に変換できます。



それほど便利ではない方法


CMTimeGetSecondsは友好的で便利な方法ですが、その邪悪な双子の兄弟であるCMTimeMakeWithSecondsは 、私たちの兄弟にとってそれほど友好的でありません

 CMTime CMTimeMakeWithSeconds ( Float64 seconds, int32_t preferredTimeScale );
      
      







この関数を使用する最初の数回は、私が望んでいたことを実行することができませんでした( 約Translator 、いまいましい)。 CMTimeの内部をすべて確認したので 、私の間違いを理解してください。 0.5秒でビューを実行して、 AVPlayerオブジェクトから定期的なコールバックを受信しようとしました(MP3ストリーミング)。

私は次のことをしようとしました:

 CMTime interval = CMTimeMakeWithSeconds(0.5, 1);
      
      





この時点まで読んだ場合、間隔は実際には0.5ではなくゼロになることがわかります。 整数のシーケンスの半分のユニットを照会するのは意味がありませんが、これはまさに私がやろうとしたことです。 ここではタイムスケールが十分に正確でないため、 値は切り捨てられました。



Core Media APIには、 CMTimeに関連する算術演算を構築、比較、および実行するための関数の完全なセットが含まれています 。 これらの関数を使用してCMTimeで算術演算を実行することは簡単ではありませんが、精度と整合性を維持する場合は、それらを使用することが重要です。 これらの各関数は、特別なオーバーフローチェックと丸めチェックを実行し、そのような必要が生じたときにCMTimeオブジェクトに対応するフラグを設定します。



2つのCMTimesを追加するには、 CMTimeAdd関数を使用します。 比較するには、 CMTimeCompareを使用します (この関数の戻り値は、標準Cライブラリで使用され、 qsortという名前でよく知られている関数コンパレーターの合意に従います )。 CMTimeからさらに学習するには、 CMTimeMaximumを使用します 。 残りの方法についてはドキュメントをご覧ください。通常、この機能セットで十分です。



不確実性と無限大:「奇妙な」フラグを設定する


CMTime関連の記事の最後の部分は、無限フラグ、未定義の値、および丸めの表示です。 不確実な時間とは、値が不明な時間です。 初期化される前に経過時間を要求すると、オブジェクトのこのような時間間隔を取得できます。 例外ごとにフラグ値を確認できます。

 kCMTimeFlags_PositiveInfinity kCMTimeFlags_NegativeInfinity kCMTimeFlags_Indefinite
      
      





ビット単位のOR(オリジナルではOR'ing)は誰もが使用するわけではないため、これらのフラグの存在を確認する便利なマクロがあります。

 CMTIME_IS_POSITIVE_INFINITY CMTIME_IS_NEGATIVE_INFINITY CMTIME_IS_INDEFINITE
      
      





ところで、それらは期間の有効性を検証するためにも使用できます。 タイムスタンプが有効ない場合、このような操作の結果はNOになります。



さらに、さまざまな時間カテゴリの比較がどのように機能するかの長いリストを以下に示します。











わかった。



注:

もちろん、検討中のトピックはかなり狭いですが、それでも一部の人にとっては興味深いように思えるかもしれません。 さらに、RuNetの情報はゼロよりわずかに小さくなっています。 著者の承認を得るために、またいくつかの点を明確にするために、私は彼に郵便で連絡しなければなりませんでした。 コメントやコメントにエラーを記述しないでください。内部メールに送信してください、ありがとう。



All Articles