使用x264将OpenGL输出转换为H264

Convert OpenGL output to H264 with x264

本文关键字:转换 H264 输出 OpenGL x264 使用      更新时间:2023-10-16

我想将OpenGL程序的输出转换为h264并流式传输输出。我在某个地方收集了大部分代码,并得到了一个输出文件,但我不知道该怎么处理它,也不知道它是否有效。目前,输出仅保存在文件.264中。

编辑:"全局"变量

    x264_param_t param;
    x264_t* encoder;
    x264_picture_t pic_in;
    x264_picture_t pic_out;
    x264_nal_t *headers;
    int i_nal;
    FILE* pFile;

我的init函数:

initX264() {
    pFile = fopen("file.h264", "wb");
    x264_param_t param;
    x264_param_default_preset(&param, "veryfast", "zerolatency");
    param.i_threads = 1;
    param.i_width = 1024;
    param.i_height = 768;
    param.i_fps_num = 30;
    param.i_fps_den = 1;
    param.i_keyint_max = 30;
    param.b_intra_refresh = 1;
    param.rc.i_rc_method = X264_RC_CRF;
    param.rc.f_rf_constant = 25;
    param.rc.f_rf_constant_max = 35;
    param.b_annexb = 0;
    param.b_repeat_headers = 0;
    param.i_log_level = X264_LOG_DEBUG;
    x264_param_apply_profile(&param, "baseline");
    encoder = x264_encoder_open(&param);
    x264_picture_alloc(&pic_in, X264_CSP_I420, 1024, 768);
    x264_encoder_parameters( encoder, &param );
    x264_encoder_headers( encoder, &headers, &i_nal );
    int size = headers[0].i_payload + headers[1].i_payload + headers[2].i_payload;
    fwrite( headers[0].p_payload, 1, size, pFile);
}

这在Render函数中进行,每秒执行约30次:

    GLubyte *data = new GLubyte[3 * 1024 * 768];
    GLubyte *PixelYUV = new GLubyte[3 * 1024 * 768];
    glReadPixels(0, 0, 1024, 768, GL_RGB, GL_UNSIGNED_BYTE, data);
    RGB2YUV(1024, 768, data, PixelYUV, PixelYUV + 1024 * 768, PixelYUV + 1024 * 768 + (1024 * 768) / 4, true);
    pic_in.img.plane[0] = PixelYUV;
    pic_in.img.plane[1] = PixelYUV + 1024 * 768;
    pic_in.img.plane[2] = PixelYUV + 1024 * 768 + (1024 * 768) / 4;
    x264_nal_t* nals;
    int i_nals;
    int frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);
    if( frame_size )
    {
        fwrite( (char*)nals[0].p_payload, frame_size, 1, pFile );
    }

我从http://svn.gnumonks.org/trunk/21c3-video/cutting_tagging/tools/mpeg4ip-1.2/server/util/rgb2yuv/rgb2yuv.c

输出看起来像

x264 [debug]: frame=   0 QP=11.14 NAL=3 Slice:I Poc:0   I:3072 P:0    SKIP:0    size=21133 bytes
x264 [debug]: frame=   1 QP=20.08 NAL=2 Slice:P Poc:2   I:0    P:14   SKIP:3058 size=72 bytes
x264 [debug]: frame=   2 QP=18.66 NAL=2 Slice:P Poc:4   I:0    P:48   SKIP:3024 size=161 bytes
x264 [debug]: frame=   3 QP=18.23 NAL=2 Slice:P Poc:6   I:0    P:84   SKIP:2988 size=293 bytes

在Linux上,file.h264返回数据。

您的文件格式不正确。没有人能读出来。A.264使用了附录B,其标题是为IDR帧准备的。

更改这些参数,

param.b_annexb = 1;
param.b_repeat_headers = 1;

并删除

x264_encoder_headers( encoder, &headers, &i_nal );
int size = headers[0].i_payload + headers[1].i_payload + headers[2].i_payload;
fwrite( headers[0].p_payload, 1, size, pFile);

最后,您应该能够获取输出并将其转换为mp4。

ffmpeg -i file.264 -vcodec copy -an file.mp4
 X264 expects YUV420P data (I guess some others also, but that's the common one). You can use libswscale (from ffmpeg) to convert images to the right format. Initializing this is like this (i assume RGB data with 24bpp).

这很可能就是你没有得到任何可用视频的原因。你可以在这里找到更多关于该做什么的信息:如何使用x264 C API将一系列图像编码到H264中?

按比例:

 sws_scale(convertCtx, &data, &srcstride, 0, h, pic_in.img.plane, pic_in.img.stride);
 //pic_in is your RGB data getting fed to scale.