从OpenGL渲染帧创建视频

时间:2014-09-27 16:09:29

标签: opengl osx-mavericks qt5 ubuntu-14.04

我正在尝试使用OpenGL中的动画创建视频文件。 我一直在阅读如何做到这一点,据我所知,有两种选择:

  1. 将OpenGL中的每个渲染帧保存到图像文件,然后从那些
  2. 创建视频文件
  3. 使用glReadPixels()获取帧数据,并将其写入视频文件
  4. 第二种方法是我认为最适合我的方法,但是,我找不到有关如何实现第二部分的信息(写入视频文件)。

    有人能指出我在某些网站上学习如何做到这一点吗?我可以使用哪种库来编码(?)来自我在OpenGL中渲染的帧的视频?

    修改

    在搜索了一下这个之后,我相信ffmpeg是可行的方法。我发现this blog的代码显然适用于Windows。

    我已从网站下载了ffmpeg,以便我可以像在示例中一样执行命令。不幸的是,我的应用程序崩溃,没有创建视频。我检查文件指针是否有效,但事实并非如此,所以我认为错误来自函数popen的执行。

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

    问题是,我不想花太多时间编写视频编码,因为我还有其他项目需要处理。

2 个答案:

答案 0 :(得分:1)

由于我无法直接从我的c ++代码中使用ffmpeg,因此可能的解决方案如下。在Qt5中,您具有函数paintGL,您可以在其中更新要渲染的帧。之后,使用glReadPixels获取像素,然后使用QImage

将帧保存为png图像
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");
}

这将在您的工作目录中留下一堆图像,您可以使用控制台中的以下命令在视频中对其进行编码

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

我仍然需要检查为什么颜色被反转但是现在这很好用,因为动画是重要的而不是颜色。

答案 1 :(得分:0)

安装libpng后你可以这样做:  uint8_t pixels = new uint8_t [w h * 3];  glReadPixels(0,0,w,h,GL_RGB,GL_UNSIGNED_BYTE,(GLvoid *)像素);

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);     如果(!png)         返回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;