0

7 月から、.avi、.flv などのビデオ ファイルを編集する Android アプリケーションを開発しました。FFMPEG と OpenGL ES 2.0 を使用して、このアプリケーションを実装しています。

「ぼかし」などのフィルター効果を CPU で実行するには計算量が多すぎるため、GPU と Shader を使用してビデオのフレームにフィルター効果を適用するために OpenGl ES 2.0 を使用することにしました。

私がやろうとしているのは、「シェーダーを使用してビデオのフレームにフィルター効果を適用し、フレーム バッファーに格納されているピクセルを取得する」ことです。

そのため、FrameBuffer からピクセルを取得するために使用できる glReadPixels のみの OpenGl ES 2.0 メソッドを使用する必要があります。しかし、多くの GPU 開発ガイドによると、glReadPixels の使用は推奨されておらず、ガイド ブックは glReadPixels を使用する場合の潜在的なリスクを警告しています。また、glReadPixels のパフォーマンスは、GPU のバージョンとベンダーによって異なります。glReadPixels を使用することを具体的に決定することはできず、GPU 計算の結果であるピクセルを取得するための他の方法を見つけようとしました。

数日後、Android GraphicBuffer を使用してピクセル データを取得するハックな方法を見つけました。

ここにリンクがあります。

このリンクから、Karthik の方法を自分のコードに試してみました。

唯一の違いは次のとおりです。

//render method I made.
void renderFrame(){
    /* some codes to init */

    glBindFramebuffer(GL_FRAMEBUFFER, iFBO);

    /* Set the viewport according to the FBO's texture. */
    glViewport(0, 0, mTexWidth , mTexHeight);

    /* Clear screen on FBO. */
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Different Code compare to Karthik's.
    contents->setTexture();
    contents->draw(mPositionVarIndex, mTextrueCoIndex);
    contents->releaseData();

    /* And unbind the FrameBuffer Object so subsequent drawing calls are to the EGL window surface. */
    glBindFramebuffer(GL_FRAMEBUFFER,0);

    LOGI("Read Graphic Buffer");
    // Just in case the buffer was not created yet

    void* vaddr;
    // Lock the buffer and retrieve a pointer where we are going to write the data
    buffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr);

    if (vaddr == NULL)    {

        LOGE("lock error");
        buffer->unlock();
        return;
    }
     /* some codes that use the pixels from GraphicBuffer...*/
}


void setTexture(){
    glGenTextures(1, mTexture);
    glBindTexture(GL_TEXTURE_2D, mTexture[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, mData);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);
}


void releaseData(){
    glDeleteTextures(1, mTexture);
    glDeleteBuffers(1, mVbo);
}


void draw(int positionIndex, int textureIndex){
    mVbo[0] = create_vbo(lengthOfArray*sizeOfFloat*2, NULL, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, mVbo[0]);
    glBufferSubData(GL_ARRAY_BUFFER, 0, lengthOfArray*sizeOfFloat, this->vertexData);
    glEnableVertexAttribArray(positionIndex);
    //    checkGlError("glEnableVertexAttribArray");

    glVertexAttribPointer(positionIndex, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    //    checkGlError("glVertexAttribPointer");
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, mVbo[0]);
    glBufferSubData(GL_ARRAY_BUFFER, lengthOfArray*sizeOfFloat,     lengthOfArray*sizeOfFloat, this->mImgTextureData);
    glEnableVertexAttribArray(textureIndex);
    glVertexAttribPointer(textureIndex, 2, GL_FLOAT, GL_FALSE, 0,   BUFFER_OFFSET(lengthOfArray*sizeOfFloat));
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mTexture[0]);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
    checkGlError("glDrawArrays");
}

テクスチャとレンダー フレームを使用して Buffer を埋めます。私は 2 台のテスト用電話を持っています。1 台は Samsung Galaxy S 2 で、レンダラーは Mali-400MP です。もう 1 つは LG Optimus G Pro で、レンダラーは Adreno(TM) 320 です。Galaxy S2 は上記のコードと Karthik の方法でうまく動作します。しかし、LGスマートフォンの場合、いくつかの問題があります。

E/libgenlock(17491): perform_lock_unlock_operation: GENLOCK_IOC_DREADLOCK failed (lockType0x1,err=Connection timed out fd=47)
E/gralloc(17491): gralloc_lock: genlock_lock_buffer (lockType=0x2) failed
W/GraphicBufferMapper(17491): lock(...) failed -22 (Invalid argument)

このリンクによると、

Android 4.2 より前の Qualcomm ハードウェアでは、Genlock という名前の Qualcomm 固有のメカニズムが使用されます。

GenLock に関連するエラーが表示されたのは私だけだったので、GraphicBuffer と Qualcomm GPU の間の問題を注意深く推測しました。その後、Gralloc.cpp、GraphicBufferMapper.cpp、GraphicBuffer.cpp、*.h のコードを検索して読み、これらのエラーの原因を見つけましたが、失敗しました。

私の質問は次のとおりです。

  1. GPU計算からフィルター効果を得るのは正しいアプローチですか? そうでない場合、非常に多くの計算を必要とする「ぼかし」のようなフィルター効果を取得するにはどうすればよいですか?

  2. Karthik の方法は Qualcomm GPU では機能しませんか? これらのエラーが Qualcomm GPU、Adreno でのみ発生した理由を知りたいです。

4

1 に答える 1

0

GraphicBuffer割り当てがGRALLOC_USAGE_SW_READ_OFTEN指定されていることを確認してください。これがないと、CPU で実行されているコードからバッファをロックできない場合があります。

関連性はありませんが、より良いアプローチを示唆している可能性があります。CameraToMpegTest の例を参照してください。これは、GLES 2.0 シェーダーを使用してライブ カメラ入力を簡単に編集します。

更新: Grafikaで GPU を使用してフィルターを適用する例があります。こちらでスクリーンレコーディングされたデモを見ることができます

于 2013-10-21T20:01:37.153 に答える