【问题标题】:Encode buffer captured by OpenGL in C在 C 中由 OpenGL 捕获的编码缓冲区
【发布时间】:2020-04-22 12:10:55
【问题描述】:

我正在尝试使用 OpenGL 来捕获计算机屏幕的后台缓冲区,然后使用 FFMPEG 的 libavcodec 库对缓冲区进行 H.264 编码。我遇到的问题是我想在AV_PIX_FMT_420P 中编码视频,但是OpenGL 提供的后台缓冲区捕获功能glReadPixels() 只支持GL_RGB 之类的格式。正如您在下面看到的,我尝试使用 FFMPEG 的 swscale() 函数将 RGB 转换为 YUV,但以下代码在 swscale() 行崩溃。关于如何编码 OpenGL 后台缓冲区的任何想法?

// CAPTURE BACK BUFFER USING OPENGL
    int width = 1280, height = 720;
    BYTE* pixels = (BYTE *) malloc(sizeof(BYTE));
    glReadPixels(0, 720, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

//CREATE FFMPEG VARIABLES
    avcodec_register_all();

    AVCodec *codec;
    AVCodecContext *context;
    struct SwsContext *sws;
    AVPacket packet;
    AVFrame *frame;

    codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    context = avcodec_alloc_context3(encoder->codec);
    context->dct_algo = FF_DCT_FASTINT;
    context->bit_rate = 400000;
    context->width = width;
    context->height = height;
    context->time_base.num = 1;
    context->time_base.den = 30;
    context->gop_size = 1;
    context->max_b_frames = 1;
    context->pix_fmt = AV_PIX_FMT_YUV420P;

    avcodec_open2(context, codec, NULL);

// CONVERT TO YUV AND ENCODE
    int frame_size = avpicture_get_size(AV_PIX_FMT_YUV420P, out_width, out_height);
    encoder->frame_buffer = malloc(frame_size);
    avpicture_fill((AVPicture *) encoder->frame, (uint8_t *) encoder->frame_buffer, AV_PIX_FMT_YUV420P, out_width, out_height);
    sws = sws_getContext(in_width, in_height, AV_PIX_FMT_RGB32, out_width, out_height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, 0, 0, 0);

    uint8_t *in_data[1] = {(uint8_t *) pixels};
    int in_linesize[1] = {width * 4};


// PROGRAM CRASHES HERE


    sws_scale(encoder->sws, in_data, in_linesize, 0, encoder->in_height, encoder->frame->data, encoder->frame->linesize);

    av_free_packet(&packet);
    av_init_packet(&packet);
    int success;

    avcodec_encode_video2(context, &packet, frame, &success);

【问题讨论】:

    标签: c opengl ffmpeg h.264 libavcodec


    【解决方案1】:

    您的pixels 缓冲区太小;你 malloc 只有 一个 BYTE 而不是 width*height*4 字节:

    BYTE* pixels = (BYTE *) malloc(width*height*4);
    

    您的glReadPixels 呼叫也不正确:

    • 传递y=720 会导致它在窗口外读取。请记住,OpenGL 坐标系的 y 轴指向上方。
    • AV_PIX_FMT_RGB32 需要每个像素四个字节,而GL_RGB 每个像素写入三个字节,因此您需要GL_RGBAGL_BGRA
    • 在这两者中,我很确定它应该是GL_BGRAAV_PIX_FMT_RGB32 将像素视为 32 位整数,因此首先使用 little-endian blue。 OpenGL 将每个通道视为一个字节,因此它应该是GL_BGRA 才能匹配。

    总结一下:

    glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
    

    此外,由于 OpenGL y 轴指向上方但 ffmpeg y 轴指向下方,您可能需要翻转图像。可以通过以下技巧来完成:

    uint8_t *in_data[1] = {(uint8_t *) pixels + (height-1)*width*4}; // address of the last line
    int in_linesize[1] = {- width * 4}; // negative stride
    

    【讨论】:

      猜你喜欢
      • 2020-10-02
      • 2015-07-13
      • 1970-01-01
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多