我目前正在尝试将openGL
中制作的动画保存到视频文件。我试过使用openCV
的videowriter
,但没有任何优势。我已经成功地生成了一个快照,并使用SDL
库将其保存为bmp
。如果我保存所有快照,然后使用ffmpeg
生成视频,这就像收集了4GB的图像。不实用。如何在渲染期间直接写入视频帧?下面是我在需要时用来拍摄快照的代码:
void snapshot(){
SDL_Surface* snap = SDL_CreateRGBSurface(SDL_SWSURFACE,WIDTH,HEIGHT,24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
char * pixels = new char [3 *WIDTH * HEIGHT];
glReadPixels(0, 0,WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
for (int i = 0 ; i <HEIGHT ; i++)
std::memcpy( ((char *) snap->pixels) + snap->pitch * i, pixels + 3 * WIDTH * (HEIGHT-i - 1), WIDTH*3 );
delete [] pixels;
SDL_SaveBMP(snap, "snapshot.bmp");
SDL_FreeSurface(snap);
}
我需要视频输出。我发现ffmpeg
可以用来从C++代码创建视频,但还没有弄清楚这个过程。救命啊!
编辑:我试过使用openCV
CvVideoWriter
类,但程序在声明的那一刻就崩溃了(“segmentation fault
”),编译当然没有错误。对此有什么建议吗?
Python用户解决方案(需要Python2.7
、python-imaging
、python-opengl
、python-opencv
,需要写入格式的编解码器,我在Ubuntu 14.04 64-bit
):
def snap():
pixels=[]
screenshot = glReadPixels(0,0,W,H,GL_RGBA,GL_UNSIGNED_BYTE)
snapshot = Image.frombuffer("RGBA",W,H),screenshot,"raw","RGBA",0,0)
snapshot.save(os.path.dirname(videoPath) + "/temp.jpg")
load = cv2.cv.LoadImage(os.path.dirname(videoPath) + "/temp.jpg")
cv2.cv.WriteFrame(videoWriter,load)
这里W
和H
是窗口尺寸(宽度,高度)。我正在使用PIL将从glReadPixels
命令读取的原始像素转换为JPEG
图像。我正在将该JPEG加载到openCV
图像中并写入视频作家。我有一些问题,直接使用PIL图像到videowriter(这将保存数百万个时钟周期的I/O
),但现在我没有工作。Image
是PIL
模块cv2
是python-opencv
模块。
5条答案
按热度按时间2g32fytz1#
这听起来像是在使用命令行实用程序:
ffmpeg
。您应该使用libavcodec
和libavformat
,而不是使用命令行从静态图像集合中编码视频。这些是ffmpeg
实际构建的库,允许您对视频进行编码并将其存储为标准流/交换格式(例如RIFF/AVI)而不使用单独的程序。您可能找不到很多关于实现它的教程,因为传统上人们希望使用
ffmpeg
来实现另一种方式;即,解码各种视频格式以在OpenGL中显示。我认为随着PS4和Xbox One游戏机引入游戏视频编码,这种情况很快就会改变,对这种功能的需求将突然飙升。然而,一般过程是这样的:
一个好的方面是你实际上不需要写一个文件。由于您定期对来自静态帧缓冲区的数据包进行编码,因此如果需要,您可以通过网络流式传输已编码的视频-这就是编解码器和容器(交换)格式分开的原因。
另一个好处是你不必同步CPU和GPU,你可以设置一个像素缓冲区对象,让OpenGL将数据复制到GPU后面几帧的CPU内存中。这使得视频的实时编码要求低得多,如果视频延迟要求不是不合理的,您只需要定期编码并将视频刷新到磁盘或通过网络。这在实时渲染中非常有效,因为您有足够大的数据池,可以让CPU线程始终忙碌编码。
编码帧甚至可以在GPU上实时完成,为大型帧缓冲区提供足够的存储空间(因为最终编码数据必须从GPU复制到CPU,并且您希望尽可能少地执行此操作)。显然,这不是使用
ffmpeg
完成的,有专门的库使用CUDA / OpenCL /计算着色器来实现此目的。我从未使用过它们,但它们确实存在。为了便于移植,你应该坚持使用libavcodec和Pixel Buffer Objects来实现GPU->CPU的异步复制。现在的CPU有足够的核心,如果你缓冲足够的帧并在多个同时线程中编码(这会增加同步开销并增加输出编码视频时的延迟),或者只是丢弃帧/降低分辨率(穷人的解决方案),你可能不需要GPU辅助编码。
这里涉及的许多概念远远超出了SDL的范围,但您确实询问了如何以比当前解决方案更好的性能实现这一点。简而言之,使用OpenGL Pixel Buffer Objects传输数据,使用libavcodec进行编码。可以在ffmpeg libavcodec examples页面上找到编码视频的example application。
ryhaxcpt2#
对于一些快速测试,比如下面的代码work(tested),可调整大小的窗口是未处理的。
j0pj023g3#
FFmpeg 2.7可运行mpg示例
解释和一个超集例子:如何使用GLUT/OpenGL渲染到文件?
考虑使用https://github.com/FFmpeg/FFmpeg/blob/n3.0/doc/examples/muxing.c生成包含格式。
mzaanser4#
我通过以下方式解决了从Python OpenGL在Python中编写视频文件的问题:在main部分中,设置要写入的视频文件:
在DisplayFunction中:
这将写入“videoout.mp4”。请注意,它最终需要“out.release()”来获得正确的mp4文件。
t5fffqht5#
我成功地用Python从OpenGL中编写了一个视频,方法如下:
1.初始化
cv2.VideoWriter()
1.在一个循环中,从OpenGL小部件(let
w = gl.GLViewWidget()
)逐帧获取,将其从4通道转换为3通道,并写入cv2.VideoWriter()
1.循环后释放
cv2.VideoWriter()