簡體   English   中英

在 C 中編碼由 OpenGL 捕獲的緩沖區

[英]Encode buffer captured by OpenGL in C

我正在嘗試使用 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);

您的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 位整數,因此小端藍色首先出現。 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM