「 2011年04月 」一覧

oggコンテナやめてmp4

録画したデータは最近はx264+aacで、mp4コンテナに格納している状況です。

昔は、aviコンテナにx264+mp3なんてことをやっていましたが、
多くの環境で、なるべく標準で再生できるということを考えるとmp4に統一していこうかと思ったわけです。

さて、ここまで流れ着くまでにも色々と試したことがありました。
音声データにOggVorbisを使ってみたり、映像部分ではXvidやDivx使ったりとか。
また、コンテナもogm(ogg)を使ってみたりとか。

そうこうしているうちに、aviの拡張子を持つけどoggコンテナであるなんていうデータも作ってしまったようです。
こうなるといざ再生しようとして失敗し、その理由がなぜだろうと思うことがあります(ありました)。
またmp4に統一するために変換しようとして、aviを開くツールで開こうとすると失敗するなど。

そういう場合には真空波動研SuperLiteを使ってコーデック確認したりするのですが、コンテナ情報までは出してくれなかったりするので、意外と原因究明に手間取ったりしました。

こういうときにバイナリエディタを使うと一発だったりします。
ヘッダ情報を見て、あぁ通常のAVIファイルじゃないなと分かるわけです。

Oggコンテナ(ogm)から変換

Oggコンテナから映像、音声を取り出してmp4へ変換ということをやりました。
いざoggコンテナを処理しようとすると多くのツールがaviの対応のため出来なかったりします。
そうして何か方法は無いかと探していたら、oggコンテナから映像と音声等を取り出すツールを発見しました。
それは、OGMDemuxer というツールです。

これは、oggコンテナ内の各ストリーム(映像や音声)を別々のファイルに書き出してくれます。
結果、書き出されたファイルを別ツールで処理することにより目的の形式へ再変換することが出来ました。

今回の場合だと、映像がaviとして保存されたのでAVIUtlで処理をおこないました。

古いファイルはaviのコンテナ、最近のものはmp4という感じでおおよそ統一を取れそうです。


DirectX11始めました -第3回-

今回はプログラムを修正して4角形にしたうえで、テクスチャを貼ってみます。

今回のプログラムの流れ

準備段階

第2回のものに加え、以下の準備を行います。

  1. テクスチャの準備
  2. サンプラーオブジェクトの準備

また以下の修正を行います。

  1. 頂点データの修正
    1. TEXCOORDの追加
  2. シェーダーの変更
  3. 頂点入力レイアウトを変更

メッセージループ

画面クリア処理の後、以下の設定を行います。

  1. バッファのセット
    1. 頂点バッファのセット
    2. 入力頂点の情報オブジェクトをセット
  2. シェーダーのセット
  3. テクスチャのセット
  4. サンプラーオブジェクトのセット
  5. 描画命令を発行

テクスチャの準備

今回はD3DXの関数を使って楽にテクスチャを作成します。

シェーダーから使うテクスチャは ID3D11ShaderResourceViewとして表現されます。
D3DX11には便利な関数が用意されていて、D3DX11CreateShaderResourceViewFromFile というものを使うと、ファイル名を指定するとこのID3D11ShaderResourceViewを作成してくれます。

サンプラーオブジェクトの準備

D3D11_SAMPLER_DESCの構造体に値を代入し、CreateSamperStateメソッドにてサンプラーオブジェクトを作成します。

頂点バッファの修正

このような感じで、頂点データおよび頂点バッファの作成部分を修正します。

シェーダーの修正

テクスチャを使うようにシェーダーファイルを修正します。

頂点シェーダー

ピクセルシェーダー

頂点入力レイアウトの修正

TEXCOORDのセマンティクスが追加されているので、それにあうように修正します。

描画処理

シェーダーのセットしたあたりで、テクスチャとサンプラーオブジェクトをセットします。

感想

DirectX10のサンプルを書いていたときには、テクスチャの作成がもう少し手間でした。
一旦ID3D10Texture2D作って、そこからシェーダーリソースビューを作っていました。
今回は、D3DXのAPIの中に便利なものがあったのでそれを使ってみました。1行でシェーダーリソースビューが取得できてしまうので便利です。
とはいえ、DirectX9のときには、D3DXCreateTextureFromFileが使えたので、それと同じことだったりします。

HelloDX11_3 ソースコード


DirectX11始めました -第2回-

今回は画面に三角形1つを出すまでをがんばってみます。

今回のプログラムの流れ

準備段階

第1回のものに加え、以下の準備を行います。

  1. 頂点バッファの準備
  2. シェーダーの準備
  3. 頂点入力レイアウトオブジェクトを作成

メッセージループ

画面クリア処理の後、以下の設定を行います。

  1. バッファのセット
    1. 頂点バッファのセット
    2. 入力頂点の情報オブジェクトをセット
  2. シェーダーのセット
  3. 描画命令を発行

頂点バッファの作成

頂点バッファを指定サイズで作成し、
ある初期値をコピーするようにして初期化まで行います。

シェーダーの準備

ピクセルシェーダーもほぼ同様なのでここでは頂点シェーダーだけの説明にします。

まずHLSLで記述したファイルから読み込みコンパイルを行います。
その後、コンパイル後のバイトデータ列からシェーダーを作成します。

なお、頂点シェーダーのバイトデータ列はこの後の処理でも使うので、
即座に解放することは出来ません。

また、DirectX SDK 2009Augustのものでは、
D3D10Blobを使うようになっていました。
DirectX SDK 2010June版では、D3DBlobを使うようです。
新しいバージョンのSDKでは、どうやらD3D[10,11]の部分の番号が取れていく傾向にありそうです。
特に機能拡張のないデータに関してはそのようになるっぽいです。
シェーダーのコンパイルのフラグもD3D10となっていますが、新しいSDKではバージョン番号が取れている物を使用することが出来るので、
DirectX11なのにDirectX10の設定を使うことに関する違和感は軽減されるかと思います。

手元が2009Augのため、DirectX11RTM版のSDKでは~という話です。
こんな変更もあるし、開発に使用するSDKのバージョンも再検討したほうが良さそうです。

自分がDirectX SDK 2009Augなのは、Windows7環境でDirectX9が正しく動作する最低バージョンだからです。

頂点入力レイアウトの作成

従来でいう頂点宣言になります。
頂点データがどのような構造で入力されていくかを示すオブジェクトになります。
この情報を作成するのに、頂点シェーダーのバイトデータ列が必要になっています。
このあたりはDirectX10と変更は特にありません。

描画処理

画面のクリア後には、今まで作成したオブジェクトをセットしていきます。

この部分も例によって、ID3D11ImmediateContextに対して設定し、描画コールを行います。
デバイスのオブジェクトではなく、コンテキストに対する描画発行となっています。
また、シェーダーのセットでも若干引数が増えました。
今回は使用していないので、ゼロが設定してあります。

シェーダーコード

現在のシェーダーコードはこんな感じです。

頂点シェーダー

ピクセルシェーダー

感想

DirectX SDK 2009Augを使用しており、これはDirectX11 SDK RTM版といえます。
そのため、シェーダー部分を筆頭に、D3D10, D3D11と入り乱れた感じで初期化になっています。
新しいSDKならこのあたりは解消されているらしいので、プログラムの見やすさは良くなると思います。

あと、算術関連がD3DXではなくxnamath.hに入るようになっていました。
この部分は大きな変更と言えそうです。
“XNA Math”だからプレフィックスは XM*** ということっぽい(XMFLOAT3 とか)。

ソースコードと画面

今回のソースコードです。 HelloDX11_2ソースコード


DirectX11始めました

はじめに

Windows7 SP1やVisualStudio2010 SP1が出ている現在において、未だにDirectX11を扱うプログラムコードを作ったことがありませんでした。2011年4月と”11″繋がりで、ちょっとDirectX11を始めてみました。

いつものことですが、画面をクリアするまでの最小限サンプルをまずは作ってみようと思います。

昨年夏にDirectX10の記事も同じように書いたので、
DirectX10とDirectX11でどんなふうに変わったかも気付く範囲で書いてみます。

プログラムの流れ

手順としては以下のように実装をしていきます。

  1. スワップチェインとD3D11デバイスのセットアップ
  2. バックバッファを描画対象とするための設定
  3. バックバッファに対するデプス・ステンシルの準備
  4. 準備したデータを描画対象に設定
  5. メッセージループ
    1. バックバッファのクリア
    2. 表示バッファの更新

D3D11デバイスの作成

まずDXGIでスワップチェインの準備を行います。
DXGIはD3D11よりも低位に位置し、グラフィックスハードウェアの情報を扱うレイヤーになります。
スワップチェインはこのレイヤーに属します。
また、画面の解像度等を取得したいとき、フルスクリーン表示にしたいときにもDXGIにお世話になります。

このDXGIの設定についてはDirectX10のDXGIの設定をほぼ変わっていないようです。

続いて、機能レベルの設定です。
DirectX11では多くの環境で動作させることが出来るように設計されているので、
プログラムがハードウェアのサポート範囲をどこまでにするかを決めるために必要です。
ここでは以下のようにして、範囲を絞ってみました。

デバイスの作成

スワップチェインの設定と、機能レベルの設定を引数に設定して、
DirectX11のデバイスを作成します。
他の項目も色々とありますが、多くの場合はこのようなコードになると思います。

DirectX11からデバイス以外にも必要になるDirectXのオブジェクトがあります。
それは、上記のコードでいう pImmediateContext です。
どちらかというと、従来の環境でのデバイスはこのpImmediateContextが担当する感じです。

また、supportLevelの値を確認することで生成されたデバイスおよびコンテキストがどの機能レベルなのかを知ることが出来ます。

バックバッファの準備 -カラーバッファ設定-

DirectX11ではDirectX9と違い、バックバッファのカラーバッファの設定を自分でおこなう必要があります。
デバイス生成状態ではバックバッファは1つ存在します。
これを描画先とするために、ビュー(RenderTargetView)を作成します。

このビューを作成するまでのコードは以下のようになります。
この部分はDirectX10のときと全く同じです。

バックバッファの準備 -デプスステンシル設定-

カラー用はスワップチェインで用意されたバックバッファでしたが、
デプスやステンシルのバッファは自分で作成する必要があります。

  1. デプス&ステンシルのテクスチャを用意
  2. そのテクスチャをバックバッファとして扱えるようにビューを作成

このような手順で行います。

ビューを作成したら、テクスチャのインターフェースは解放しておきます。

描画先設定

今まで準備したバッファを描画対象として、デバイスに設定します。
デバイスに設定するのですが、pImmediateContext、すなわち、ID3D11DeviceContextインターフェースに対して設定します。

このID3D11DeviceContextに対して設定する部分が D3D10と違いますね。

画面のクリア

クリア処理は、デバイスに対して行うという感じではなく、
コンテキストに対して、クリアするビューを設定して行う、という感じになっています。

後始末

感想

DirectX10をやっていれば、そこまで大きく変わった感じはしないですね。
今までデバイスに指示していたのがデバイスコンテキストへ指示と変えたくらいです。

今回のソースコード

HelloDX11 ダウンロード


DirectX11ちょっと調べてみた

DirectX11環境でのDX9ハードウェア

DirectX11(D3D11)では、DX9ハードウェア上でも動作します。
正確には、DX9相当の機能を使う分には動作できるという感じです。

使用するAPIを変えなくてもDX9ハードウェアからDX11ハードウェアまで
動作できるというのは魅力ですが、何もしなくても動作するというのとはちがうようです。

新しい環境でも、古い環境でもそれぞれの出来る範囲で動作するということを考えたときには、
ハードウェアが備えているレベルに応じて処理を切り替えることが必要になります。

たとえば、DX10相当のハードとDX9のハードでは、使用できる定数レジスタのサイズが全く違います。軽く試してみたところ、vs_4_0_level_9_3のプロファイルで、大きな定数バッファを使用するHLSLシェーダーファイルはコンパイルに失敗します。

まぁ、そうなるだろうと予測していましたが、納得の症状です。

よって、ハードウェアを見ながら使用するシェーダーを変更する、ということが
それぞれの環境での最良のパフォーマンスを引き出すのには必要になります。


IntelグラボとOpenGLの苦悩 その3

前回、Intelでは問題がなかった、という表現をしていましたが、
実はテクスチャ座標も正しくシェーダー側へ渡せてないことが分かりました。
うまく値が渡るのは頂点カラーのみ。これらの結果から、
GL_ARB_vertex_program の各頂点属性のインデックス値が、
仕様通りに動くのは NVIDIAのみということになります。

vertex_programを使用時においてどの環境でも動くためには、
EnableVertexAttribArray系ではなく、glEnableClientStatus系で有効にして、
頂点データ属性のセットには、glXXXXPointer系を使う必要があるということになります。

このvertex_programやfragment_programのシェーダーについて、
GLARBシェーダーとここでは表記することにします。

FBO未使用でのテクスチャレンダリング

GL_ARB_framebuffer_objectを使えない時のテクスチャレンダリングの話です。
使用しそうな場面としては、以下のような状況があるかと思います。

  • GLSL使えないとき(GLver2.0未満)の場合
  • ドライバが対応していないものを使用している場合

意外と古いドライバでは FBOが使えなかったりします。
それと古い環境で、DirectX9.0とGLの対応を行う場合に、
OpenGLでテクスチャレンダリングする場合にこの方法が必要になるかと思います。

これから説明する方法はパフォーマンスがあまりよくはありません。
しかしながら、制限された環境で、両者互換を取る場合には仕方ないかなと思っています。

wglCreatePbufferARBでPBufferを使う

OpenGLのP-Bufferというものを使います。
これはオフスクリーン描画のためのバッファです。
ただし、この拡張はプラットフォーム依存が酷く、マルチ展開は厳しいです。
また、FBOに比べて使い勝手が悪いです。

P-Bufferを用いて描画の方法はサンプルもそこそこあるので、
ここでは手順だけ説明します。

  1. P-Bufferを作成
    1. メインのGLコンテキストとリソース共有出来るようにwglShareListsを呼び出しておきます。
  2. テクスチャに書き込みたいシーンをP-Bufferを現在のコンテキストに設定して描画
  3. glCopyTexSubImage2Dを呼び出して、描画したシーンをテクスチャに転送
  4. P-Bufferでのコンテキストの各値をメインにコピー
    • 必要がないなら不要。wglCopyContextでコピーできる
    • コピーしておくとテクスチャレンダリングパスでのクリア値とかを引き継げる
    • コピー有無にかかわらず、頂点属性のセット値は引き継がれない。
  5. メインのコンテキストに戻す。
    1. ビューポートやシザーの再セット

これらの手順により、描画結果をテクスチャに落とし込めます。
glReadPixels命令でも一応可能ですが、それよりはこちらの方が若干マシです。

まとめ

OpenGL 2.0対応していて、FBOが使える状況ではまず必要にならない方法でした。
最近だと2.0あたりに対応はしているはずなので、あまり役に立たないかも。

P-Bufferなんて昔の話と思っていたので、まさか実際に触ってみる日が来るとはびっくりです。
Intel GMA950あたりで動かそうと思ったが運の尽きってことで。

勉強にはなったと思いますが…。


IntelグラボとOpenGLの苦悩 その2

シェーダーを使う状況かつVertexBufferObject(VBO)を使ってということを前提条件とします。
このとき、glEnableVertexAttribArray, glVertexAttribPointer等を使って、
頂点ストリームを設定していくのが自然です。しかしながら今回、これでトラブルに見舞われました。

GL_ARB_vertex_program の仕様をOpenGL Registryで調べると、
各頂点属性のindex値は、頂点データのセマンティクスにより決まるように書いてあります。
今までは、この値を参考にしながら glEnableVertexAttribArray( index ); を設定していました。

そのようにして実装した結果、NVIDIA, Intel のグラフィックチップによる描画では
問題が起こらなかったのですが、AMD(ATI)のチップでは、位置情報以外設定されない!という動作結果が出てしまいました。

もともとはIntelの場合を想定して、この作業を行っていたのに、
意外にもAMDでまともに動作しないという状況ではちょっと不味い…。

GLSLを使える状況、すなわち、GL_ARB_vertex_shaderの拡張でシェーダーを使う分には、
従来方式で問題はおこりません。今回~programのほうなので問題があるわけです。
この~programは、いわゆるシェーダーアセンブラへOpenGLが対応したときの拡張です。

おおまかな出現順から考えると、

  1. GL_ARB_vertex_program, fragment_program
  2. GL_ARB_vertex_buffer_object
  3. GL_ARB_vertex_shader

という順序なので、VBOとの同時使用で問題が引き起こされている感もありそうです。

  • VBOを使用せずに、頂点データを直接VertexAttribPointerで設定した
    • NG. 動作せず。
  • VBO使用して、glVertexPointer等でオフセットを指定した
    • OK. AMDで動作した。

こんな結果になりました。
もう古いAPIである glVertexPonterやglColorPointer等で、VBO内のオフセットを設定してあげることにより、
シェーダーアセンブラ使用時でも、頂点属性をシェーダー側へ流し込むことが出来ました。

※ なるべくならこんな古いAPIを使いたくはなかったんですが…。


IntelグラボとOpenGLの苦悩

久しぶりにOpenGLのコードを書いて実験していました。
今回気になってと色々と試していたのは、テクスチャへのレンダリングについてです。

背景

比較的新しい環境で、NVIDIA/AMDなどのグラフィックチップを使っている物については、FBO(FramebufferObject)の使用で簡単に対応可能です。
しかしたまにFBOを使えない環境という状況についてどうしようということがあります。

FBOはOpenGLの3系で初めてコアに取り込まれていたので、
OpenGL 2.1対応のビデオボードというだけでは、使えない可能性もあります。
(拡張でつかえることも当然ある。ドライバの完成度次第です)

今までは、「そんな環境は知らない。」としていたのですが、

  • 意外にも旧Intel Coreシリーズの内蔵グラフィックチップがOpenGL 2.1止まりである
  • Intelのグラフィックチップではかなりの世代がOpenGL対応バージョンが低いままである

という点から、このまま放置はダメだと思い、ちょっと調べてみることにしました。

調査

出典は英語のほうのWikiPediaより。

チップ OpenGL対応具合 備考
GMA 900 1.4
GMA 950 1.4
GMA 3100 1.5
GMA 3150 1.5
GMA X3500 2.0 G35のもの
GMA X4500 2.1 G4xあたり
HD Graphics 2.1 旧Intel Core iシリーズ.
HD Graphics 2000 3.0 新Core iシリーズ
HD Graphics 3000 3.0 新Core iシリーズ

ざっと、このような状況でした。
まだまだGMA3000番代を使っている環境も多いと思うので、
ここの対応を切ってしまうのはやはり不味そうです。

手元にGMA950のノートPCがあるので、これを実験対象として用いてみたいと思います。

実験中

今の世代を考慮して、シェーダーの使用は前提とします。
その場合に必要となる関数として以下のものを読み込んだのですが、エラーに。

  • glVertexAttribPointer
  • glEnableVertexAttribArray
  • glDisableVertexAttribArray

色々と調べてみると、末尾に”ARB”が付いているものを使用しなくてはならないようです。
この末尾になにもないタイプは、OpenGL 2.0でのコア関数に位置づけされるものっぽいです。

これらのことを考えると、2.0未満の場合では末尾にARBが付いている物を使い、
それ以外の場合には、何も付いていないものを使用するべきのように思います。

さて、そのようにして作業を進めていくと驚くべき事実が発覚。
GMA950のOpenGL 1.4の環境では、GLSLが使用不可能でした…
あれ?と思って調べてみると、GLSLではなくARBのシェーダーが使えるようです。
DirectXでもHLSLの前はシェーダーアセンブラでしたし、これと同じ状況です。

結果、この環境でシェーダーが動くためには、GLSLではなくアセンブラ形式のシェーダーを使う必要があるということでした。

シェーダー使用の前提を保ちつつ、レンダーテクスチャ(のようなもの)をサポートするには、
かなり厳しい道のりがありそうです。

とりあえず、HLSLで書いたコードをNVIDIAが提供しているCg Toolkitを用いて、
OpenGL ARB用のシェーダーアセンブラを出力することが可能です。
ここではこの助けを借りて、もうちょっとがんばってみようと思います。


仮想マシンでTV録画

KTV-FSUSB2を仮想マシンに接続するようにして、
録画環境を作ってみました。今回も例によって ESXi の中の仮想マシンに、
USBデバイスのパススルー機能を使って、チューナーを接続させました。

KTV-FSUSB2をamazonでも購入してしまったので、
この製品を2つ、同一の仮想マシンへ接続です。
そもそも、BonDriverのほうがFSUSB2デバイスの同時2つに対応しているか、
不安ではありましたが、チャンネル設定等いじっていたらうまくいきました。
最初から2つ取り付けて、tvrockのセットアップをやれば、
問題なく動くのでしょう。
今回は、1つずつ順番にやってしまったためのトラブルだと思われます。

TIPS

  • 仮想マシン CPUのシェアを高、予約を1GHz程度は与えておくこと。

意外とこれ重要です。
怠るとDROPが結構発生します。設定後は軽減されました!

感想

PX-W3PEよりは安定した録画品質を維持できました。
W3PEのほうでは割と頻繁にDROPがでたり、
1チューナーで何とか使える(小DROP)という稼働状況でした。

しかし今回の構成だと DROPが出ることもありますが、
W3PEよりは少なめでした。
また、W録画が使用に耐えられることもメリットです。
(たまにW録画でDROPが多めに出る、うちでは50ドロップ以下に収まるが・・・)
シングル録画ではDROPが出ても数個でした。

仮想マシンのなかでの動作という点で、
色々と難しいのですが、安定して使えそうな環境が出来てきたことは嬉しく思います。