【发布时间】:2011-09-23 15:26:15
【问题描述】:
我正在尝试渲染从使用 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?
附:我看过这个Stack Overflow question,但没有帮助。
另外,我也有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);
现在我已经将avgpicture_get_size 中的PixelFormat 更改为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 提供的所有帮助。
【问题讨论】:
-
投票结束。 IMO,这个问题已经失控了。您需要比 SO 在这里支持的更多的手持设备。有很多问题需要覆盖,并且不断地重新编辑问题并不是很好。我建议尝试邮件列表或论坛,或 SO OpenGL 聊天室。
-
好的,感谢 glPixelStorei,问题现在已经解决了。我已经删除了 cmets 等,这些对其他有同样问题的人解决这个问题没有帮助。
-
另外,由于问题是关于将 ffmpeg 框架获取到 opengl 纹理,我不明白这个问题是如何失控的,因为所有问题和答案都是关于将 ffmpeg 框架上传到一个opengl纹理,无论它是关于性能(gluBuild2DMipmaps(),glTexSubImage2D()),像素存储(glPixelStorei()等)ffmpeg的执行(sws_scale,SwsContext)还是与问题有关的任何其他事情。编辑问题对于遇到相同问题的其他人很有用,因为他们可以轻松查看为解决问题所采取的步骤。
-
@InfinitiFizz:嘿,我正在尝试通过创建一个浏览器插件来实现同样的目标,但是,我得到的只是一个黑屏,你能指导我吗?
标签: opengl ffmpeg textures video-processing render-to-texture