使用x264将OpenGL输出转换为H264

4
我想将OpenGL程序的输出转换为h264并流式传输输出。我在某个地方收集了大部分代码,得到了一个输出文件,但我不知道该怎么做,或者它是否有效。目前,输出仅保存在file.h264文件中。
编辑:“全局”变量。
    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;

我的初始化函数:

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获取了GRB2YUV函数。
输出结果如下:
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返回数据。

它能在 VLC 媒体播放器中播放吗?如果可以,那么你的编码是正确的。如果不能,那么你的视频编码不正确。 - KrisSodroski
无法播放,VLC或AVPlay都不行。 - user2660369
你在哪里声明pic_in? - KrisSodroski
全局变量声明请仅返回已翻译文本:全局变量声明 - user2660369
x264的设置将根据您希望写入的容器(或协议)而有所不同。流是否要发送到像twitch.tv这样的流媒体服务? - szatmary
我想要像rtsp一样进行流媒体传输,这样任何访问rtsp://xxx.xxx.xxx.xxx/stream的人都能够查看该流。 - user2660369
2个回答

6
您的文件格式有问题,无法被任何程序读取。.264格式采用附加到IDR帧前面的头部,并使用AnnexB格式。

请更改这些参数:

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

请注意,这是针对 .264 文件的。如果您要流式传输到 RTMP,则需要从 x264_encoder_headers() 创建一个序列头,并切换回 b_annexb = 0; - szatmary
对于文件,这很好用。我该如何流式传输到RTMP,应该使用哪个库(适用于Linux和Windows)? - user2660369
请查看 https://github.com/szatmary/RtmpBroadcaster 中的 rtmp.cpp,flvtag.cpp 和 encode.cpp 文件。你在直播视频游戏吗? - szatmary
谢谢,我会看一下的。它不是一个视频游戏,只是一个使用OpenGL的模拟程序。 - user2660369

0
 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. 

我想避免使用libffmpeg来进行YUV420P转换。那么你认为RGB2YUV函数有问题吗? - user2660369
不是出了问题,只是可能和你想象的不一样。你从哪个库获取的?你确定它正在将RGB转换为YUV420P吗?它可能正在进行YUV444到RGB888的转换,这可能不起作用。 - KrisSodroski
我从http://svn.gnumonks.org/trunk/21c3-video/cutting_tagging/tools/mpeg4ip-1.2/server/util/rgb2yuv/rgb2yuv.c获取了GRB2YUV函数。 - user2660369
那么我该如何将RGB数据输入到sws_scale中呢? - user2660369
srcstride来自哪里?data是RGB数据开头的指针,h为768(在我的情况下),pic_in是sws_scale的输出吗?pic_in.img.stride未定义,您是否意味着pic_in.img.i_stride? - user2660369
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接