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
しただけです。gluBuild2DMipmaps
GL_RGBA
フレームは次のようになります。
もう一度編集
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);
に変更しPixelFormat
たavgpicture_get_size
のでPIX_FMT_RGB24
、に変更しました。SwsContext
に変更GluBuild2DMipmaps
するGL_RGB
と、少し良い画像が得られますが、まだ線が欠けているようで、まだ少し伸びています。
別の編集
Mackeのアドバイスに従い、実際の解像度をOpenGLに渡した後、フレームはほぼ適切になりましたが、それでも少し歪んでいて白黒で、110fpsではなく6fpsしか得られていません。
PS
フレームを画像に保存する機能がありますが、sws_scale()
色などすべてがうまく表示されているので、OGLの何かが白黒になっています。
最後の編集
働く!これで動作しました。基本的に、テクスチャを2の累乗でパディングするのではなく、ビデオの解像度を使用するだけです。
正しいglPixelStorei()で幸運な推測をして、テクスチャが適切に表示されるようになりました。
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
また、subimage()
私のような空白の問題が他にある場合は、少なくとも1回はテクスチャを塗りつぶす必要があるためglTexImage2D()
、ループで1回使用し、その後使用glTexSubImage2D()
します。
Mackeとdatenwolfにご協力いただきありがとうございます。