2012-01-07 12 views
3

AVAssetWriterの助けを借りて、OpenGLでレンダリングしたイメージをムービーファイルに記録したいとします。問題は、OpenGLフレームバッファからピクセルにアクセスする唯一の方法は、iOSでRGBAピクセル形式のみをサポートするglReadPixelsを使用することです。しかし、AVAssetWriterはこの形式をサポートしていません。ここでは、ARGBまたはBGRAを使用できます。アルファ値を無視することができるように、私はARGBにRGBAを変換するための最速の方法は、glReadPixelsに1バイトずつシフトバッファを与えることだろうと、結論に達しました:RGBAをARGBに変換する(glReadPixels - > AVAssetWriter)

UInt8 *buffer = malloc(width*height*4+1); 
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer+1); 

問題は、そのglReadPixelsですコールはEXC_BAD_ACCESSクラッシュにつながります。バッファを1バイトシフトさせなければ、ビデオファイルに間違った色が付いていても問題はありません。ここで何が問題なの?

+1

があなたの代わりにサイズ+ 4を割り当てることができません、呼び出し、その後、AVAssetWriterに+ 3をバッファglReadPixelsにバッファ+ 4を送りますか?そうすれば、iOS上で必要なGLコールを整列させることができます。 –

答えて

5

私はARGBにRGBAを変換するための最速の方法は、glReadPixelsにこれは、しかし、同様に1つのピクセルで、あなたのアルファ値をシフトする

1バイトずつシフトバッファを与えることだろうと、結論に達しました。

画像をテクスチャにレンダリングする(そのテクスチャをカラーアタッチメントとして使用する)。次のスウィズリングフラグメントシェーダで、別のフレームバッファにそのテクスチャをレンダリング:

#version ... 
uniform sampler2D image; 
uniform vec2 image_dim; 
void main() 
{ 
    // we want to address texel centers by absolute fragment coordinates, this 
    // requires a bit of work (OpenGL-ES SL doesn't provide texelFetch function). 
    gl_FragColor.rgba = 
     texture2D(image, vec2((2*gl_FragCoord.x + 1)/(2*image_dim.y), 
           (2*gl_FragCoord.y + 1)/(2*image_dim.y)) 
     ).argb; // this swizzles RGBA into ARGB order if read into a RGBA buffer 
} 
+1

私が言及したように、私はアルファ情報は必要ありません(私はh264ビデオを制作しています)が、OpenGLシェーダでうねっているのは素晴らしいアイデアです:) –

+2

Btw。私はちょうど非常に興味深いものを見つけました:ARGBの代わりにBGRAを指定すると、AVAssetWriterはビデオを多く(!)速くエンコードします。 RGBA→ARBの代わりにRGBA→BGRAを変換することは本当に問題であり、RGBA→BGRAを変換できない1バイトシフト技法が提案されているので、このピクセルスウィズル技術は絶対に必須です。 –

+0

@DominikSeibold実装のサンプルコードを投稿してください – anuj

0

memcpyまたは他のコピー操作を実行することによって、バイトをシフトする必要があります。ポインタを変更すると、それらは整列していないままになります。これは、基盤となるハードウェアの能力(DMAバス幅、タイルの粒度など)にある場合とない場合があります。

+0

私は、glReadPixelsが整列していないポインタに書き込むことができないような理由は見当たりません。それは最適に効率的ではないかもしれませんが、実際にはクラッシュしてはいけません... – StilesCrisis

1

末尾に余分な128バイトの余裕あなたのバッファの? OpenGLがパフォーマンスのために一度に4/8/16/etcバイトを埋めるようにしようとしている可能性があり、バッファが整列していないか、何か不具合があります。 OpenGLのパフォーマンス最適化では、最初のケースで問題が発生することは初めてです:)

+0

私はさらにバッファサイズを倍増させようとしましたが、それでもクラッシュします。 4バイトまたは1行(4 *幅)だけシフトすると動作しますが、もちろん初期の問題では役に立ちません。 –

+1

あなたのmallocの後に、NSLog(@ "Buffer at 0x%08X"、buffer)を追加してみてください。 。次に、EXC_BAD_ACCESSが発生するアドレスを調べます。悪いアクセスがあなたのバッファの始まりにある場合、OpenGLはおそらくARM上のアラインされていないアクセスで爆発的にメモリを書き込んでいます。私は、ARMが、整列していないときに何が失敗するかを知るために十分なことは分かっていません(私は、Mac OSのもっと多くの人です)。もちろん、それが他の場所で発生した場合でも、それはまだ興味深いデータポイントです。 – StilesCrisis

+0

EXC_BAD_ACCESSが発生するアドレスを取得するにはどうすればよいですか? –

-1

buffer+1を使用すると、データはmallocのメモリの先頭に書き込まれず、それはあなたのmalloc'dメモリの終わりに上書きし、クラッシュを引き起こします。

もしiOSのglReadPixelsがGL_RGBAだけを受け入れるならば、あなたはそれを通過して自分自身を再配置する必要があります。

私はあなたのmallocで+1を見逃しましたが、StilesCrisisはおそらくクラッシュの原因です。

+0

彼は割り当てられたバッファに余分なバイトを追加しますが、 – StilesCrisis

1

はglReadPixels前

glPixelStorei(GL_PACK_ALIGNMENT,1) 

を呼び出してみてください。 docsから

GL_PACK_ALIGNMENT

は、メモリ内の各画素行の開始のためのアラインメント要件を指定します。 1(バイト整列)、 2(偶数バイトに整列された行)、 4(ワード整列)、および 8(行はダブルワード境界で開始します)です。

デフォルト値は4です(glGet参照)。これは、さまざまな "OpenGL pitfalls"タイプのlistsのトラブルメーカーとしてよく言われますが、これは一般に、バッファの配置よりも行のパディング効果が関係します。

別のアプローチとして、4つの余分なバイトをmallocした場合、glReadPixelsをバッファ+ 4から4バイトの位置に整列してから、AVAssetWriterバッファ+ 3を渡してください(AVAssetWriterがアラインメントの問題にもっと寛容です)?

+0

glPixelStoreiは助けになりません。2番目の解決策は機能しますが、追加のmemcpy-ステップに必要なものはパフォーマンスには良いものではありません –

関連する問題