我正在尝试将使用ffmpeg从视频中抓取和转换的帧渲染为要放在四边形上的OpenGL纹理。我已经用尽谷歌并没有找到答案,我找到了答案,但似乎没有一个有效。
基本上,我avcodec_decode_video2()
用来解码帧,然后sws_scale()
将帧转换为 RGB,然后glTexSubImage2D()
从中创建一个 openGL 纹理,但似乎无法正常工作。
我已确保“目标”AVFrame 在 SWS 上下文设置中具有二维的能力。这是我的代码:
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 我看过这个Stack Overflow 问题,但没有帮助。
另外,我也有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
in更改avgpicture_get_size
为,我也已将其更改为 ,并更改为,我得到了一个稍微好一点的图像,但看起来我仍然缺少线条并且它仍然有点拉伸:PIX_FMT_RGB24
SwsContext
GluBuild2DMipmaps
GL_RGB
另一个编辑
在遵循 Macke 的建议并将实际分辨率传递给 OpenGL 之后,我得到了几乎正确的帧,但仍然有点偏斜并且是黑白的,现在它也只有 6fps 而不是 110fps:
附言
我有一个功能可以将帧保存到图像之后sws_scale()
,它们作为颜色和一切都很好,所以 OGL 中的某些东西正在使它成为黑白。
最后编辑
在职的!好的,我现在可以正常工作了,基本上我不会将纹理填充到 2 的幂,而只是使用视频的分辨率。
我通过正确的 glPixelStorei() 幸运猜测正确显示了纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
另外,如果其他subimage()
人像我一样有显示空白的问题,你必须至少填充一次纹理,glTexImage2D()
所以我在循环中使用它一次,然后再使用glTexSubImage2D()
。
感谢 Macke 和 datenwolf 提供的所有帮助。