42

ffmpegを使用してビデオから取得および変換されたフレームをクワッドに配置するOpenGLテクスチャにレンダリングしようとしています。私はグーグルをかなり使い果たして、答えを見つけられませんでした、まあ私は答えを見つけました、しかしそれらのどれもうまくいかなかったようです。

基本的に、私はavcodec_decode_video2()フレームをデコードし、次にsws_scale()フレームをRGBに変換し、それglTexSubImage2D()からopenGLテクスチャを作成するために使用していますが、何も機能しないようです。

SWSコンテキストの設定では、「宛先」のAVFrameに2次元のパワーがあることを確認しました。これが私のコードです:

SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width,
                pCodecCtx->height, pCodecCtx->pix_fmt, 512,
                256, PIX_FMT_RGB24, SWS_BICUBIC, NULL,
                NULL, NULL);

//While still frames to read
while(av_read_frame(pFormatCtx, &packet)>=0) {
    glClear(GL_COLOR_BUFFER_BIT);

    //If the packet is from the video stream
    if(packet.stream_index == videoStream) {
        //Decode the video
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

        //If we got a frame then convert it and put it into RGB buffer
        if(frameFinished) {
            printf("frame finished: %i\n", number);
            sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

            glBindTexture(GL_TEXTURE_2D, texture);
            //gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pCodecCtx->width, pCodecCtx->height, GL_RGB, GL_UNSIGNED_INT, pFrameRGB->data);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, 512, 256, GL_RGB, GL_UNSIGNED_BYTE, pFrameRGB->data[0]);
            SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, number);
            number++;
        }
    }

    glColor3f(1,1,1);
    glBindTexture(GL_TEXTURE_2D, texture);
    glBegin(GL_QUADS);
        glTexCoord2f(0,1);
        glVertex3f(0,0,0);

        glTexCoord2f(1,1);
        glVertex3f(pCodecCtx->width,0,0);

        glTexCoord2f(1,0);
        glVertex3f(pCodecCtx->width, pCodecCtx->height,0);

        glTexCoord2f(0,0);
        glVertex3f(0,pCodecCtx->height,0);

    glEnd();

そのコードでわかるように、フレームが実際にレンダリングされていることを確認するために、フレームを.ppmファイルに保存しています。

使用されているファイルは854x480の.wmvですが、これが問題になる可能性がありますか?私が512x256にするように言っているという事実は?

PS私はこのStackOverflowの質問を見てきましたが、役に立ちませんでした。

また、私も持っglEnable(GL_TEXTURE_2D)ており、通常のbmpをロードするだけでテストしました。

編集

画面に画像が表示されていますが、文字化けしているので、2の累乗に変更することと関係があると思います(デコード時、swscontextおよびgluBuild2DMipmapsコードに示されているように)。私は通常、上記のコードとほぼ同じですが、タイプをに変更して変更glTexSubImage2Dしただけです。gluBuild2DMipmapsGL_RGBA

フレームは次のようになります。

OpenGLテクスチャとしてのFfmpegが文字化けしている

もう一度編集

pFrameRGBの設定方法のコードを示していないことに気づきました。

//Allocate video frame for 24bit RGB that we convert to.
AVFrame *pFrameRGB;
pFrameRGB = avcodec_alloc_frame();

if(pFrameRGB == NULL) {
    return -1;
}

//Allocate memory for the raw data we get when converting.
uint8_t *buffer;
int numBytes;
numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t));

//Associate frame with our buffer
avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB24,
    pCodecCtx->width, pCodecCtx->height);

に変更しPixelFormatavgpicture_get_sizeのでPIX_FMT_RGB24、に変更しました。SwsContextに変更GluBuild2DMipmapsするGL_RGBと、少し良い画像が得られますが、まだ線が欠けているようで、まだ少し伸びています。

Ffmpeg Garbled OpenGL Texture 2

別の編集

Mackeのアドバイスに従い、実際の解像度をOpenGLに渡した後、フレームはほぼ適切になりましたが、それでも少し歪んでいて白黒で、110fpsではなく6fpsしか得られていません。

ここに画像の説明を入力してください

PS

フレームを画像に保存する機能がありますが、sws_scale()色などすべてがうまく表示されているので、OGLの何かが白黒になっています。

最後の編集

働く!これで動作しました。基本的に、テクスチャを2の累乗でパディングするのではなく、ビデオの解像度を使用するだけです。

正しいglPixelStorei()で幸運な推測をして、テクスチャが適切に表示されるようになりました。

glPixelStorei(GL_UNPACK_ALIGNMENT, 2);

また、subimage()私のような空白の問題が他にある場合は、少なくとも1回はテクスチャを塗りつぶす必要があるためglTexImage2D()、ループで1回使用し、その後使用glTexSubImage2D()します。

Mackeとdatenwolfにご協力いただきありがとうございます。

4

2 に答える 2

9

を呼び出すと、テクスチャは初期化されますglTexSubImage2Dか? テクスチャ オブジェクトを初期化するには、glTexImage2D( Subではなく) 1 回呼び出す必要があります。データ ポインターに NULL を使用すると、OpenGL はデータをコピーせずにテクスチャを初期化します。 答えた

編集

ミップマッピングレベルを提供していません。ミップマッピングを無効にしましたか?

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILER, linear_interpolation ? GL_LINEAR : GL_NEAREST);

編集 2ほとんどの画像形式は左上に原点があるのに対し、OpenGL はテクスチャ画像の原点を左下に配置するため、画像が上下逆になっていることは驚くことではありません。そこに見えるバンディングは、行のストライドが間違っているように見えます。

編集3

私は約1年前に自分でこの種のことをしました。私はffmpegの小さなラッパーを書いて、aveasyと呼んでいましたhttps://github.com/datenwolf/aveasy

aveasy を使用して取得したデータを OpenGL テクスチャに配置するコードを次に示します。

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <GL/glew.h>

#include "camera.h"
#include "aveasy.h"

#define CAM_DESIRED_WIDTH 640
#define CAM_DESIRED_HEIGHT 480

AVEasyInputContext *camera_av;
char const *camera_path = "/dev/video0";
GLuint camera_texture;

int open_camera(void)
{
    glGenTextures(1, &camera_texture);

    AVEasyInputContext *ctx;

    ctx = aveasy_input_open_v4l2(
        camera_path,
        CAM_DESIRED_WIDTH,
        CAM_DESIRED_HEIGHT,
        CODEC_ID_MJPEG,
        PIX_FMT_BGR24 );
    camera_av = ctx;

    if(!ctx) {
        return 0;
    }

    /* OpenGL-2 or later is assumed; OpenGL-2 supports NPOT textures. */
    glBindTexture(GL_TEXTURE_2D, camera_texture[i]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(
        GL_TEXTURE_2D,  
        0,
        GL_RGB, 
        aveasy_input_width(ctx),
        aveasy_input_height(ctx),
        0,
        GL_BGR,
        GL_UNSIGNED_BYTE,
        NULL );

    return 1;
}

void update_camera(void)
{
    glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
    glPixelStorei( GL_UNPACK_LSB_FIRST,  GL_TRUE  );
    glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
    glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei( GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1);

    AVEasyInputContext *ctx = camera_av;
    void *buffer;

    if(!ctx)
        return;

    if( !( buffer = aveasy_input_read_frame(ctx) ) )
        return;

    glBindTexture(GL_TEXTURE_2D, camera_texture);
    glTexSubImage2D(
        GL_TEXTURE_2D,
        0,
        0,
        0,
        aveasy_input_width(ctx),
        aveasy_input_height(ctx),
        GL_BGR,
        GL_UNSIGNED_BYTE,
        buffer );
}


void close_cameras(void)
{
    aveasy_input_close(camera_av);
    camera_av=0;
}

私はこれをプロジェクトで使用していますが、そこで動作するため、このコードはテスト済みです。

于 2011-06-27T16:32:07.177 に答える