从OpenGL渲染帧创建视频

问题描述:

我想从OpenGL中的动画创建视频文件。 我一直在阅读关于如何做到这一点,我的理解有两种选择:从OpenGL渲染帧创建视频

  1. 保存每一个在OpenGL渲染帧图像文件,然后创建从这些
  2. 视频文件获取的帧数据使用glReadPixels()和动态写那些为视频文件

第二种方法是什么,我相信会的工作最适合我,但是,我无法找到如何实现第二部分信息(写入到视频文件)。

任何人都可以指出我对一些网站,我学习如何做到这一点?我可以使用什么类型的库来编码(?)我在OpenGL中渲染的帧中的视频?

编辑

搜索更加一下这个之后,我相信ffmpeg的是要走的路。我发现this blog有一个显然可以在Windows上工作的代码。

我已经从网站上下载了ffmpeg,这样我就可以执行命令,就像在这个例子中一样。不幸的是,我的应用程序崩溃,没有视频正在创建。我检查了文件指针是否有效,但不是,所以我认为错误来自函数popen的执行。

我传递了与命令完全相同的参数,但仍然没有有效的文件指针,关于可能发生什么的任何想法?

事情是,我不想花很多时间编码视频编码,因为我有其他项目可以工作。

+0

我在编码/解码视频文件方面并不是很有经验,但我认为你最好的选择是寻找一个能为你做到这一点的图书馆,而且你只需将数据传递给它。如果它的任何部分与我想象的音频(哪个)相同,它不会变得微不足道。不幸的是,我不知道任何图书馆。 – Daniel 2014-09-27 17:22:51

+0

问题是,你并没有要求特定的帮助。有很多库能够将一系列RGB图像编码成视频流(ffmpeg,gstreamer,我非常确定OSX有本地的东西)。除非您要求提供有关这些库的具体内容,否则此问题无意义。 – peppe 2014-09-28 20:18:07

由于我无法直接从我的C++代码使用ffmpeg,所以可能的解决方案如下。在Qt5中,您可以使用功能paintGL更新要渲染的帧。这之后,得到的像素与glReadPixels,然后只用QImage

void OpenGLViewer::paintGL() 
{ 
    // Clear screen 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    // Update array attached to OpenGL 

    glDrawArrays(GL_POINTS, 0, _points); 

    update(); 

    glReadPixels(0, 0, this->width(), this->height(), GL_RGBA, GL_UNSIGNED_BYTE, _buffer); 

    std::stringstream name; 
    name << "Frame" << _frame++ << ".png"; 
    QString filename(name.str().c_str()); 
    QImage imagen(_buffer, this->width(), this->height(), QImage::Format_ARGB32); 
    imagen.save(filename, "PNG"); 
} 

的图像保存为PNG图像这将使用从下面的命令留在你的工作目录中的一些图片,你可以在视频编码控制台

ffmpeg -framerate 30 -start_number 0 -i Frame%d.png -vcodec mpeg4 -vf vflip test.avi

我还是要查,为什么颜色反转,但现在由于动画是最重要的事情,而不是颜色能正常工作。

您可以在安装libpng后以这种方式完成: uint8_t pixels = new uint8_t [w h * 3]; glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,(GLvoid *)pixels);

for (int j = 0; j * 2 < h; ++j) { 
int x = j * w * 3; 
int y = (h - 1 - j) * w * 3; 
for (int i = w * 3; i > 0; --i) { 
    uint8_t tmp = pixels[x]; 
    pixels[x] = pixels[y]; 
    pixels[y] = tmp; 
    ++x; 
    ++y; 
    } 
} 

png_structp PNG = png_create_write_struct(PNG_LIBPNG_VER_STRING,nullptr,nullptr,nullptr); if(!png) return false;

png_infop info = png_create_info_struct(png); 
if (!info) { 
    png_destroy_write_struct(&png, &info); 
    return false; 
} 
std::string s = "IMAGE/"+string(filename); 
FILE *fp = fopen(s.c_str(), "wb"); 
if (!fp) { 
    png_destroy_write_struct(&png, &info); 
    return false; 
} 

png_init_io(png, fp); 
png_set_IHDR(png, info, w, h, 8 , PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, 
    PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 
png_colorp palette = (png_colorp)png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); 
if (!palette) { 
    fclose(fp); 
    png_destroy_write_struct(&png, &info); 
    return false; 
} 
png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH); 
png_write_info(png, info); 
png_set_packing(png); 

png_bytepp rows = (png_bytepp)png_malloc(png, h * sizeof(png_bytep)); 
for (int i = 0; i < h; ++i) 
    rows[i] = (png_bytep)(pixels + (h - i - 1) * w * 3); 

png_write_image(png, rows); 
png_write_end(png, info); 
png_free(png, palette); 
png_destroy_write_struct(&png, &info); 

fclose(fp); 
delete[] rows; 
+0

ffmpeg -framerate 30 -start_number 0 -i Frame%d.png -vcodec mpeg4 -vf vflip test.avi – user3059007 2015-04-23 00:50:04