The Media Kit Table of Contents | The Media Kit Index |
Media Kitは(audioとvideoを含むがそれらに限定されない)メディアの全ての形式に対する強力なサポートを提供し、それは広い範囲のメディアと機器の再生及び録音を含みます。
Media Kitのプログラミングには二つのレベルがあります。高レベルの方は、アプリケーションが音声とビデオを再生及び録音するためにMedia Kitにアクセスし、低レベルの方は、メディアデータを操作するノードを実際に作り出す事を含みます。
このセクションでは、メディアキットの鍵となる概念を概観します。
あなたがBeOSでメディアを扱うプログラマとして最初に理解する必要があるのは、nodeの概念です。おおまかに言って、nodeはメディア機構に於てメディアデータのバッファを処理するために特化されたオブジェクトです。全てのnodeは間接的にBMediaNodeクラスから導かれます。(しかしBMediaNodeから直接ではなく、特化されたnode型のクラスからです。)
nodeはadd-onモジュールから読み込まれるか、アプリケーション自身のなかで作り出されます。詳細はBMediaAddOnクラスをご覧下さい。
node kind (node_kind typeで定義されている) はnodeの基本的な能力を記述しています。4ページの"Types of Nodes"をご覧下さい。
media_nodeはアプリケーションがmedia nodeを使って作業する際に使用する構造体です。Media Rosterとの共同作業は、BMediaNodeから実際に導かれるオブジェクトの代りとしてほぼ常にこの構造体を使用します。なぜなら、アプリケーションがしばしばnodeを共有する必要があり、またメモリを保護しなければならないため、実際にはアプリケーション間のBMediaNodeのポインタの受け渡しは実行不可能なのです。
|
Media Kitの構造に関して詳細な情報が必要であれば (特にnodeが他のnodeとどう関連するかについて)、BMediaNodeクラスをご覧下さい。
いくつか基本的なnodeの種類があります。それぞれ、もとはBMediaNodeクラスから渡されるものです。あなたがインプリメントした任意のnodeは、順番にこれらのnode型の一つまたは複数から導かれます。node kindはnodeがインプリメントされたこれらの型を表します。
producer (BBufferProducerクラスから導かれるnode) はメディアのバッファを出力し、その後consumerに受け取られます。producerは、それ自身に於てnodeを作り出します(例えば、tone generatorは音声を生成するために数式を使用し、また音声ファイルのプレイヤーはディスクからデータを読み込み、その音声データを含むバッファを送出します)。その他のproducerは (ビデオカメラのような) メディア機器からデータを要求するという責任を果たし、中心であるconsumerにメディアバッファを渡します。
(BBufferConsumerから導かれたnodeである) consumerは、producerからのバッファを受け取り、それらをある方法で処理します。例えば、サウンドカードのソフトウェアは音声バッファから受け取ったconsumerのnodeを提供し、カードのハードウェアを通して音を鳴らします。
"nodeと対話する"の章では、sound play nodeがconsumerの例です。
(BBufferConsumerとBBufferProducerの両方から導かれるnodeである) consumer/producerはまた、filterと呼ばれます。filterは (consumerの様に) バッファを受領し、それらをある方法で処理し、その後それらを (producerの様に) 再び送り返します。これは音声やビデオのデータを変更するのに使われます。
例えば、audio filterは、残響の効果を音声バッファに付加し、またvideo filterはビデオストリームにキャプションを付加します。
"nodeとの対話"の章では、equalizer nodeがfilter nodeの例です。
もしnodeがその機能を形作るためにユーザオプションを提供しようとした場合、nodeはBControllableから派生されます。これは制御可能なパラメータのネットワークを作り出すための特徴を提供し、この情報を (Media preferenceアプリケーションを含む) Media Kitを理解するアプリケーションに対して発行します。
time source nodeは、他のnodeによって使用されるタイミング情報を広めます。全てのnodeはtime sourceに従属し、time sourceはそれに従属する全てのnodeの同期を提供します。典型的には、アプリケーションはこのことに関して留意する必要はありません。なぜなら任意のnodeはBMediaRosterクラスから生成され、自動的にシステム(デフォルト) のtime sourceに従属するからです。
|
node_kind型はnodeがインプリメントされたインターフェイスがなんであるか判別するために使用されます。これはあなたのnodeがサポートするAPIをMedia Kitに知らせます。これらのフラグはB_BUFFER_PRODUCER, B_BUFFER_CONSUMER, B_TIME_SOURCE, 及び B_FILE_INTERFACEを含みます。
node kindには、他にも使用できるフラグがあります。これらはそのnodeによってサポートされる特別なnodeの機能を表します。nodeが物理的な入力機器であることを示すB_PHYSICAL_INPUT、nodeが物理的な出力機器であることを示すB_PHYSICAL_OUTPUT、そしてそのnodeがシステムのミキサーであることをしめすB_SYSTEM_MIXERがあります。
これらのフラグの第一の目的は、これらのnodeに対するインターフェイスをどうやって描画するか、ユーザインターフェイスが決定するのを補助することです。例えば、それらはmedia preferenceアプリケーション上で特別なアイコンを得ます。
例えば、もしあなたがステレオスピーカーから音声を演奏するサウンドカードのnodeを生成しようとすると、あなたは (オーディオバッファを受け取るために) BBufferConsumerから導かれなければなりません。また、もしサウンドカードが他のものにタイミング情報を提供する能力があるなら、BTimeSourceから派生することもできます。また、もしユーザが音量、バランスやそれ以上のことを制御できるようにしたければ、BControllableから派生することもできます。
もしあなたのサウンドカードがデジタル入力も提供するなら、あなたはその特徴をサポートするために、2番目のnodeを作成します。それはBBufferProducer (他のnodeが使うための音声バッファを生成することができる) から受け継がれています。それはまた、BTimeSourceとBContollableからも派生しています。
しかし、全てのnodeが物理的なハードウェア機器を現す必要はありません。もしfilter、例えばノイズ除去のfilterを作成するなら、あなたはそれを行うためのnodeを作成することもできます。(バッファを受け取ることのできる) BBufferConsumerと、(部分的に変更されたバッファを送り返すことのできる) BBufferProducerから単純に派生します。
Media Kitのプログラミングを始めるにあたって、おそらくmedia_source、media_output、media_destination、media_inputの違いを理解することが困難だと思います。
media_sourceとmedia_destination構造体は、(ネットワークに於けるものと同様) ひと揃えの「socket」を記述します。これらは、ステレオの様々なコンポーネントに接続するためのケーブルを差し込むためのジャックによく似た、接続の両端です。(訳註 : オーディオの接続端子のことです) それらは、nodeをリアルタイムに操作するために必要な情報のみを含む、比較的小さく軽量な記述子です。バッファはsourceからdestinationへ旅します。基本的な演算子 (=, == 及び !=) をこれらのオブジェクトで使用することができます。
media_source::nullとmedia_destination::nullは、初期化されていない終端を表現します。
media_outputとmedia_input構造体は、media_sourceとmedia_destinationとの間の実際の接続を記述し、それはsourceとdestination、接続の名称、その接続が扱う予定のデータフォーマットを含んでいます。これらはより大きく、node間の接続を記述するユーザインターフェイスを示す際に必要となる付加情報を含んでいます。
media_input構造体は接続の受領(上流)端を記述します。media_outputは、送信者(下流端)を記述します。
media_outputとmedia_inputは、media_source及びmedia_destinationの全ての情報を含んでいますが、終わりの方の構造体はメディアデータのリアルタイム操作をしているときのために存在しており、その必要がなければ大きなデータブロックを受け渡したくありません。そして、そうすべきではないのです。
media_format構造体は、接続を通過するメディアの型を記述します。それの動作するアプリケーションとnodeは、呼び出しと呼び戻しのシーケンスを通じてフォーマットを取り決めます。
この構造体は、基本的なメディア型 (B_MEDIA_RAW_AUDIO, B_MEDIA_ENCODED_VIDEOの様な)や、基本的な型に依存する付加情報を含む複合(データ)を含んでいます。
B_MEDIA_RAW_AUDIOメディアによって記述されるmedia_format構造体は、下記の情報を含んでいます。
B_MEDIA_RAW_VIDEOメディアによって記述されるmedia_format構造体は、下記の情報を含んでいます。
format wildcardは、あるフォーマットの非特異的な部分を示します。これはnodeやアプリケーションが交渉中に「私はこのフォーマットの特定の部分には関心がないよ。(あるいは)私は柔軟なの。」と言うために使用されます。例えば、もしあなたのアプリケーションがvideo nodeと交渉し、任意のvideoのビット深度を扱えるなら、あなたはそのフォーマットのカラースペースフィールドに於てwildcardを明記します。
それぞれのフォーマット型はひとつのwildcard objectを持ちます。
例えば、もしあなたがaudio nodeと交渉する準備をしているとしたら、そしてframe rateに留意しないとしたら、下記のコードは交渉のためにmedia_format構造体を用意します。
media_format format; media_raw_audio_format wc; wc = media_raw_audio_format::wildcard; format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio.frame_rate = wc.frame_rate;
サンプルは、与えられた一瞬の間の音声波形の増幅を定義する単一の値です。この値は複数の方法で表現されます。1バイトの整数、2バイトの整数、浮動小数点の値またはその他の方法によって、です。BeOSネイティブな音声のサンプルフォーマットは浮動小数点であり、0.0は増幅のない値です。プラスの値はゼロポイントより上に増幅され、マイナスの値はゼロポイントより下に示されます。
フレームは、与えられた一瞬の間の音声を記述するサンプルのセットです。もし音声が複数のチャンネルを含んでいれば、フレームはそれぞれのチャンネルに対する複数のサンプルを含みます。モノラルのオーディオストリームはフレームあたり一つのサンプルを含み、ステレオのオーディオストリームはフレームあたり二つのサンプルを含みます。サラウンドサウンドのフォーマットは、さらに多くのサンプルを含みます。
バッファは、一つのnodeから他のnodeに音声を送るのに、さらに効率のよい方法です。独立した数千のフレームに目を向ける代りに、フレームはバッファにグループ化された後、nodeの鎖に沿ってまとめて移されます。これはスループットを改善し、オーバーヘッドをなくします。
347ページの"media_raw_audio_format"をご覧下さい。
ビデオは、non-interlacedまたはinterlaced (飛び越し走査) データとして表現されます。NTSC video (アメリカに於けるテレビ映像の標準フォーマット) と PAL video (他の国における標準) は、いずれもinerlacedです。
典型的には、ビデオストリームはフレームあたり一つまたは二つのフィールドを持ちます。もしビデオがinterlacedでなければ、ただ一つだけのフィールドになり、それはビデオストリームの全ての走査線を含みます。もしビデオがinterlacedであれば、大抵フレームあたり二つのフィールドがあります (さらに多い場合もありますが、二つがもっとも一般的です)。一つのフレームは偶数のラインを含み、もう一方は奇数のラインを含みます。
BeOSのMedia Kitに於けるビデオバッファは、常に完全なフレームまたは完全なフィールドを含みます。バッファは部分的なフレームやフィールドを決して含みません。
348ページの"media_raw_video_format"をご覧下さい。
この章は、複雑なオーディオやビデオのフォーマットを指導するためのものではありません。これらのテーマに関しては、よい参考書がたくさんあります。ここに、我々の技術者が推薦する書籍のリストをあげておきます。
BBufferは、nodeの間を通ることのできるメディアデータのパケット(塊)です。それは、データ及び実際に伝達されているデータを記述するためのヘッダを含んでいます。
バッファのヘッダはデータが何であるかを伝えるための情報を含んでいます :
オプションとして、メディアシステムはバッファのデータを共有メモリ空間に保存します。異ったアプリケーションとnodeがメモリ周囲にコピーを取ることなく同じバッファにアクセスできるように、です。バッファは、それぞれのnodeに、メモリの同じエリアを参照するBBufferを与えることにより、一つのnodeから次のものへと受け渡されます。
BMediaRosterクラスは、全ての使用可能なnode(それがアプリケーションによって作られたか、それともadd-onによってかにかかわらず)に対するインターフェイスを提供します。アプリケーションはnodeのインスタンスを作成した後、要求された仕事を成し遂げるはずのnodeの間に接続を発行します。
例えば、もしアプリケーションがグラフィックイコライザー経由で音声ファイルを鳴らしたければ、まず音声データをディスクのファイルから読み込んでオーディオバッファに出力するnodeのインスタンスを作成し、その後オーディオバッファをフィルタリングするnodeのインスタンスを作成します。そして最後に、スピーカーからオーディオバッファを鳴らすnodeを作成します。
一旦これら3つのnodeが作成されたら、アプリケーションはこれらの間にリンクを作成します。音声ファイルを読むnodeの出力はイコライザーnodeの入力に接続され、イコライザーnodeの出力はサウンドプレーヤの入力に接続されます :
一旦3つの接続が発行されると、アプリケーションは音声ファイルを演奏する最初のnodeに指示を出し、その後稼働中の全てのnodeを開始することでサウンドファイルを演奏し始めることができます。音声ファイルの読み込み部分はオーディオデータを含んだバッファを作成し、これらをデータを改変するためのイコライザーノードに向けて渡します。その後バッファを演奏し、それらを再利用するための音声演奏のnodeに渡されます。メディアデータを再生するためにnodeを利用するさらに詳しい例は、BMediaRosterクラスで提供されます。
メディアnodeはそれぞれ、control portを維持します。Media Kitはnodeのcontrol portにメッセージを送ることでnodeと相互に影響しあっています。
メディアデータを取り扱う上でもっとも重要な問題のひとつは、適切にトラッキングし、時間に正確にイベントを同期させることです。時間にはいくつかの種類があります。(あなたはそれを理解するためにステファン・ホーキングになる必要はまったくありません):
Media Timeは、特定のメディアファイルについての相対的な時間であり、ファイルの先頭からマイクロ秒の単位で表現されます。Seek動作は、media timeを用いて実行されます。
Real Timeは、システム時計によって報告される時間であり、コンピュータが起動した後のマイクロ秒単位で表現されます。これはsnooze(), read_port_etc()等といったシステムコールとの連携に使用されます。
performance timeはtime source nodeによって報告されます。time source nodeはreal timeとperformance timeとの関連づけを確立します。
通常、node chainの全てのnodeに対するマスタークロックとなるtime sourceはひとつだけです。
Performance Timeと Real Timeを区別するのには、二つの理由があります。もしマスタークロックがsystem timeでなければ、時間の整合性がなくなってしまうでしょう。nodeからnodeへデータを受け渡すのに使われる時間から生じる待ち時間(latency)もまた、同様にどこかに行ってしまう可能性があります。
Latency(待ち時間)は、何かをするのに必要な時間の量です。latencyには二つの鍵となるタイプがあります。
3つのnodeが接続されているケースを考えてみましょう。最初のnodeは3マイクロ秒のprocessing latencyを持ち、2番目は2マイクロ秒のprocessing latencyを持っています。そして最後のものは1ミリ秒のprocessing latencyを持っているとします。
|
加えて、2マイクロ秒があるnodeから次に受け渡されるのに要求されるとします。このnodeの鎖の待ち時間(latency)の合計は、3 + 2 + 2 + 2 + 1 = 10マイクロ秒となります。
バッファは50マイクロ秒のperformance timeで演奏される予定になっています。正しい時間で遅れずに最後のnodeにこのバッファを得るためには、40マイクロ秒のときに処理を始める必要があります。下のダイアグラムにその様子を示しています。
Node 2は、バッファを処理し、それをNode 3に渡します。これには合計4マイクロ秒必要です(2マイクロ秒のprocessing timeにNode3に送るのに必要な2マイクロ秒を加えます)。ここでperformance timeは49マイクロ秒となります。
最後に、Node 3はバッファを処理します。これは1マイクロ秒の処理時間を必要とします。この時点で、performance timeは50マイクロ秒に達し、バッファは予定通り演奏されました。
もしあなたがメディアデータ(サウンドやビデオファイル)をなんらかの形で録音または再生するアプリケーションを書くなら、あなたのメディアが必要とするものは全てBMediaRosterクラスによって供給されます。このクラスは種々のnodeへのアクセスを提供し、あなたが成し遂げたい作業を実行するのに必要なnodeの関連づけを確立させてくれます。
|
Media Kitのエラーコード定数は、MediaDfs.hにみることができます。
Media Rosterは、アプリケーションとメディアシステムの通信を管理します。
この章では、簡単に言えば、Media Rosterによって供給される機能のいくつかを要約しています。さらに詳しい情報が必要であれば、BMediaRosterクラスをご覧下さい。
Media preferenceアプリケーション及びシステムミキサーでユーザが作成する標準的なnodeがいくつかあります。BMediaRosterクラスは、これらのnodeをすばやく参照する、GetAudioMixer()やGetVideoOutput()といった便利なルーチンを提供します。詳細はBMediaRosterをご覧下さい。
もし他のnodeが必要であれば、用途にもっとも適したnodeを探すために、利用可能なnodeをブラウズすることもできます。nodeはdormant node(潜在するnode)から作り出され、Media add-on内に住んでいます。dormant nodeはそれぞれnode flavor(dormant nodeが作り出せるnodeを記述する構造体)に参照されます。
一度もっとも目的に一致したnodeを発見したら、あなたはそのnodeと交渉し、接続を発行します。これはBMediaRosterで概説されています。
もしあなたのnodeが生成され、お互いに接続されたら、あなたはそれらをBMediaRosterの機能であるPreroll(), Seek(), Start(), そしてStop()を使って制御できます。これらはあなたをメディアファイルの特定の位置に移動させ、再生や録音の開始や停止を行わせます。
あなたはまた、nodeのtime sourceや、run modeや、play rateを設定できます。
BControllableのnodeは、ユーザが設定でき、その外観を表現するユーザインターフェイスを示すことができます。これらの設定可能な外観を、それぞれparameterと呼びます。BMediaRoster::StartControlPanel()には、それを行うもっとも簡単な方法を紹介しています。
メディアデータを含むファイルにアクセスするのに許可されているのは、BMediaFile及びBMediaTrackを経由する方法です。もしあなたがnodeをベースとした再生または録音のシステムを使用しているなら、そしてメディアファイルに容易にアクセスしたいなら、あなたはBMediaFileクラスをBMediaRoster::SniffRef()を使って呼び出すことができます。
"Reading and Writing Media Files"に正しい方法でメディアファイルにアクセスする方法の例があります。
audio mixerは、後にAudio preferenceアプリケーションでユーザが選択したオーディオ出力機器にミキシングされ出力されるオーディオデータの入力部にアクセスします。あなたのアプリケーションは、BMediaRoster::GetAudioMixer()機能を使用したaudio mixerに参照されるmedia_nodeを得ることができます。あなたはaudio mixerから出力されるオーディオを遮断することはできません。それらは直接、出力機器まで行きます。
任意のraw audio formatを含むバッファはaudio mixerに送信されることが可能です。mixerはそのデータを再生するのに適当なフォーマットに変換するでしょう。
audio mixerは常に稼働しており、もっとも適当なtime sourceに隷属しています。あなたはそのtime sourceを決して変えてはならず、audio mixerを開始したり停止したりしてもいけません(言葉を変えれば、BMediaRosterのcallやSetTimeSourceFor(), Start(), またはStop()を呼び出してはいけません)。
audio inputはオーディオバッファをマイクロホンやline inポートなどの外部のソースから作成します。音声が入力される物理的なハードウェア機器はaudio preferenceアプリケーションを用いてユーザが設定します。
現在のMedia Kitの実装では、audio inputのサンプリングレートは変更できません。将来、これは変更されるでしょう。あなたのアプリケーションが将来にわたって動作し続けるには、現在のサンプリングレートが有効であり続けると仮定しないで下さい。代りに、あなたがaudio inputの接続に使うmedia_outputのmedia_format構造体をみてください。
if (input->format.media_raw_audio_format.frame_rate != MY_FRAME_RATE) { /* it's the wrong frame rate */ }
audio inputは排他的です。同時には、ただ一つの接続のみが許されます。もしあなたが2つのconsumerから入力されたバッファを受け取りたければ、オーディオバッファを受け取る特別なnodeを生成し、その複製をそれに取り付けられた全てのconsumerに送る必要があります。
もし(AIFFやWAVEファイルなどの)raw audioを再生したいだけなら、Media Kitは単にその処理を行うためのBSoundPlayerクラスを提供します。BSoundPlayerはMedia Kitの内部動作を隠し、あなたの人生を簡単にします。詳細は、これら2つのクラスをご覧下さい。BSoundPlayerクラスの概観に、音声ファイルを再生するための例があります。
あなたもBSimpleGameSoundとBFileGameSoundといった様々な音声の再生用クラスが、Game Kitで提供されていることについて考えたいでしょう。
もしちょっと満腹気味だというなら、play_sound()というglobal C関数を音声ファイルの再生に使うことができます。stop_sound()関数はplay_sound()を使って再生された音声を停止させるために使えますし、wait_for_sound()は音声の再生が終わるまで動作をブロックしてくれます。
あなたは異ったタイプのメディア処理を行うために、自分自身でnodeを生成することができます。nodeはMedia Kitがdormant nodeを読み込めるadd-onか、あるいはアプリケーション自身から供給されます。この詳細は、BMediaNode、BBufferConsumer及びBBufferProducerで論議されています。
|
一般的な規則では、あなたはメディアイベントの低レベルのスケジュールとクエリを扱うために、BMediaEventLooperクラスを使用すべきです。新しいmedia nodeを生成する事のキーポイントの説明も含めて、どうやってそれがなされるかは"A BMediaEventLooper Example"をご覧下さい。
これはBMediaAddOnの概観で詳細に論議されています。
もしあなたのアプリケーションに特殊なニーズがあれば、アプリケーション内にあなた自身のnodeのサブクラスを生成することができます。普通は(BBufferConsumerといった)適切な基底クラスから派生したものです。しかしながら、あなたのアプリケーションは決して直接そのサブクラスの関数を呼び出してはいけないということに留意して下さい。代りに、media rosterと一緒にnodeを登録し、まるで他のnodeの様に、あなたのnodeを記述したmedia_nodeを使い、BMediaRosterの呼び出しを経由して制御します。
一度あなたのnodeクラスに対してコードを書いたら、あなたはそれをBMediaRoster::RegisterNode()を呼び出してMedia Serverに登録できます。nodeを使い終わったら、それをBMediaRoster::UnregisterNode()を呼び出して登録解除する必要があります。これを行うもっとも簡単な方法は、それが削除(delete)されたとき、それ自身を登録解除させるようにすることです。
データ処理を共同で行うたくさんのnodeを扱う際、重要なタイミングの懸念が常にあります。この章では、適切なタイミングを維持するために様々な型のnodeがどう振る舞えばよいかを網羅しています。
バッファが実行されるのに必要な発表時間を計算するには、いくつのframeが実行されているかを把握し、1000000LL/sample_rateの値で掛けます。(そして、もしあなたの計算が浮動小数点で計算されたなら、あなたは結果をfloor()しなければいけません)。それからあなたは、あなたのSeek()したいどんなoffsetも適用できます。
buf->Header()->size_used = your_buf_frames * your_frame_size; buf->Header->start_time = your_total_frames*1000000LL/your_format.frame_rate; your_total_frames += your_buf_frames;
開始時間を、一つ前のバッファの長さとその開始時間を足すことで演算してはいけません。つまり、あなたがそれをすれば、丸めによる誤差の蓄積が1秒に3回のサンプルの脱落を生じることになります。
出力を意図するバッファを提供するproducerは、startTimeによって作り出したそれぞれのバッファにスタンプする必要があり、それはバッファが処理されるperformance timeを示します。もしproducerがファイルからメディアを再生するか、または音声を同期させると、これはメディアがアナログになる時間なのです。
このstartTimeを正しく演算するには、BBufferProducer::FindLatencyFor()によって報告された時間量をもとに、producerがバッファをあらかじめ用意しておかなければなりません。producerはまた、少なくとも送出したバッファに置いたタイムスタンプを更新する際には、BBufferProducer::LateNoticeReceived()のフック関数を用意する必要があります。そして、それらはdownstream nodeで演奏され、正確な時間に演奏されていることをチェックされるでしょう(そしてそれらが遅れていれば、バッファを脱落させるでしょう)。もしそうされなければ、物事はどんどん後ろにずれていく傾向になるでしょう。
|
producerは物理的な入力(マイクロホンジャックなど)から作り出されたバッファを生成すると、いくぶん異った扱いをします。producerは、バッファがキャプチャされたperformance time(バッファが最初のサンプルを得た時間であるはず)をもって作り出されたバッファにスタンプします。これは、バッファが下流に伝達されるとき、それらが到着したnodeの目からは常に「遅れている」ということです。
これはまた、あなたが簡単には物理的な入力から物理的な出力までの間に割り込めないということを意味します。なぜなら、バッファが常にタイムスタンプされた値よりも遅れて出力にたどり着くことになるからです。あなたはタイムスタンプを調整するためにもう一つのnodeを二つのnodeの間に挿入する必要があります。そうすることで、それらはもはや決して「遅れ」なくなるでしょう。
加えて、B_RECORDINGの動作モードにある(ファイルに書き込みを行うnodeのような)データを記録するnodeは、遅れて到着するバッファに関して注意を払うべきではありません。これは、データをこの問題を考慮することなく記録されるようにするからです。
もしconsumerがメディアを認知する(受け取ったバッファに含まれたオーディオやビデオを再生するような)デバイスであれば、バッファがアナログ世界に届くまでにかかる時間をproducerに正確な遅延時間(それがオーディオかビデオかにかかわらず、バッファ中のデータをユーザに与えるまでの時間量)として報告する必要があります。受け取られたバッファは、バッファが届いたときにスタンプされたstartTimeまで演奏されるべきではありません。もしバッファが遅れて到着すれば、consumerはproducerに遅延通知を送付すべきです。そうすることで、必要な調整が可能となり、バッファをまったく通過できなくします。再使用できるように、必ずバッファをRecycle()して下さい。
consumer/producer (filter) は、下流の遅延時間を加え、バッファが受け取られる時間から再伝達される時間までのフィルタ通過時間を正しい遅延時間として報告しなければなりません。フィルターの目的を明示されることなく、タイムスタンプを変更すべきではありません。フィルタはまた、producerより下流で、consumerより上流に記述された遅れたパケットを扱うべきです。
nodeと、そのnodeが従属するtime sourceを開始するアプリケーションは、それらに正しい開始時間を供給する必要があります。例えば、いくつかのnodeが接続されていて、それらは全て適切なtime sourceに従属しており、あなたがそれらを全て開始しようと望んだとすると、あなたは下記の段階を踏む必要があります :
bigtime_t latency; Roster->GetLatencyFor(node1, &latency); Roster->PrerollNode(node1); Roster->PrerollNode(node2); Roster->PrerollNode(node3); Roster->StartNode(node1, 0); Roster->StartNode(node2, 0); Roster->StartNode(node3, 0); bigtime_t now = system_time(); Roster->SeekNode(timesourceNode, -latency, now + 10000); Roster->StartNode(timesourceNode, now + 10000);
timesourceNodeを開始する準備をしている間にコードが先に進みすぎてしまわないように、10,000マイクロ秒を余分に付け足します。これは、我々が本来の時間より早くコードを開始しないように、ちょっとしたごまかしの要素を与えてくれます。
offline modeで動作するnodeは、時間系では特異なケースです。
B_OFFLINEモードでは、現在時刻は、入力のバッファの到着から現在までの時間に由来しています。現在のperformance timeはアクティブな入力から受け取られる全ての時間のうち最小のものです。アクティブな入力は、接続され、バッファが来ていないことを示すProducerDataStatus()呼び出しを受け取っていない入力です。あなたはバッファのstart_time時刻またはB_PRODUCER_STOPPEDとともにProducerDataStatus()呼び出しを受け取ります。
offline modeでは、consumer達は入力のうちの一つでバッファを受け取って処理したら、更にバッファを得るためにRequestAdditionalBuffer()を一度呼び出すべきです。
(producerは)B_OFFLINEモードでは順番にバッファを送信します。推奨される振る舞いは最初のバッファに送信し、次のバッファを送る前にAdditionalBufferRequested()呼び出しを待ちます。もしこの要求が(1秒かそこら、またはアプリケーションから見込まれていた)妥当な時間以内に到着しなければ、nodeはそれがあまり頭の良くないconsumerと作業していると認め、便宜上バッファの送信を開始します。
|
もしproducerがまだAdditionalBufferRequested()呼び出しを受け取っているなら、consumerはそれが何をしているか知っており、要求に応じてただバッファを送るべきであると想定すべきです。
Media nodeのadd-onは、/boot/home/config/add-ons/mediaのディレクトリにインストールされなければなりません。
media driverは/boot/home/config/add-ons/kernel/drivers/binにインストールされなければなりません。そしてそのdriverのsymlinkを/boot/home/config/add-ons/kernel/drivers/dev/(type)に作成します。(type)はインストールするdriverのタイプ(audio, videoなど)です。
media node add-onをインストールした後、それを使用可能にするためにmedia serverを再起動しなければなりません。
Media Kitは、メンバとしてenumを持つクラス(もっとも有名なのはBMediaNode)をいくつか持っています。例えば、BMediaNodeでは、下記のものを見つけることができます :
class BMediaNode { ... enum run_mode { B_OFFLINE = 1, B_DECREASE_PRECISION, B_INCREASE_LATENCY, B_DROP_DATA, B_RECORDING }; ... };
このケースでは、B_OFFLINEとBMediaNodeから派生したオブジェクトの内部から外側を自由に使用することができますが、もしこれらの値を他のクラス(またはクラスの外部)から使用したいのであれば、これらの定数を使うためにBMediaNode::B_OFFLINEの表記を使用しなければなりません。これはクラス内で定義されたenumについて真です。つまり、これはこの章のどの定数の記述についても厳密に、声高に叫ばれるでしょう。
仮想的な継承は、C++の一般的な継承とは少々異っています。仮想基底クラスのコンストラクタは、仮想の継承を実際に定義する直接の派生クラスに呼び出されるより、明示的に(あるいは暗黙のうちに)インスタンスを作成される**(もっとも頻繁に派生される)クラスに呼び出されます。
簡単に言えば、仮想継承を使用するクラスから新しいクラスを派生させたときはいつでも、そのクラスのコンストラクタが暗黙のうちに親クラスのコンストラクタを呼び出すはずだということです。
The Media Kit Table of Contents | The Media Kit Index |
Copyright © 2000 Be, Inc. All rights reserved..