Отображение декодированного кадра FFMPEG в окне GLFW

Я реализую клиентскую программу игры, где сервер отправляет закодированные кадры игры клиенту (через UDP), а клиент их декодирует (через FFMPEG) и отображает в окно GLFW. Моя программа имеет два потока:

  1. Поток 1: визуализирует содержимое переменной uint8_t* dataToRender
  2. Тема 2: продолжает получать кадры с сервера, декодирует их и соответственно обновляет dataToRender

Поток 1 выполняет типичный рендеринг окна GLFW в цикле while. Я уже пытался отобразить некоторые данные фиктивного кадра (полностью красный кадр), и это сработало:

while (!glfwWindowShouldClose(window)) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    ...

    glBindTexture(GL_TEXTURE_2D, tex_handle);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, dataToRender);
    ...
    glfwSwapBuffers(window);
}

Тема 2, где у меня проблемы. Я не могу правильно сохранить декодированный кадр в моей переменной dataToRender. Кроме того, данные кадра изначально имеют формат YUV и должны быть преобразованы в RGB. Я использую для этого FFMPEG sws_scale, который также выдает ошибку bad dst image pointers в консоли. Вот фрагмент кода, отвечающий за эту часть:

        size_t data_size = frameBuffer.size();  // frameBuffer is a std::vector where I accumulate the frame data chunks
        uint8_t* data = frameBuffer.data();  // convert the vector to a pointer
        picture->format = AV_PIX_FMT_RGB24;
        av_frame_get_buffer(picture, 1);
        while (data_size > 0) {
            int ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
                data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
            if (ret < 0) {
                fprintf(stderr, "Error while parsing\n");
                exit(1);
            }
            data += ret;
            data_size -= ret;

            if (pkt->size) {
                swsContext = sws_getContext(
                    c->width, c->height,
                    AV_PIX_FMT_YUV420P, c->width, c->height,
                    AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL
                );
                uint8_t* rgb24[1] = { data };
                int rgb24_stride[1] = { 3 * c->width };
                sws_scale(swsContext, rgb24, rgb24_stride, 0, c->height, picture->data, picture->linesize);

                decode(c, picture, pkt, outname);
                // TODO: copy content of picture->data[0] to "dataToRender" maybe?
            }
        }

Я уже пытался сделать еще один sws_scale, чтобы скопировать содержимое в dataToRender, и я не могу избавиться от ошибки bad dst image pointers. Буду очень признателен за любой совет или решение проблемы, так как я застрял на этом несколько дней.


person Infecto    schedule 12.06.2020    source источник


Ответы (1)


Я думаю, вам следует преобразовать YUV в RGB с помощью OpenGL. Это очень высокая эффективность и простота. Фрагментный шейдер выглядит следующим образом:

precision mediump float;
varying vec2 v_texPo;
uniform sampler2D sampler_y;
uniform sampler2D sampler_u;
uniform sampler2D sampler_v;

void main() {
    float y, u, v;
    vec3 rgb;
    y = texture2D(sampler_y, v_texPo).r;
    u = texture2D(sampler_u, v_texPo).r - 0.5;
    v = texture2D(sampler_v, v_texPo).r - 0.5;
    rgb.r = y + 1.403 * v;
    rgb.g = y - 0.344 * u - 0.714 * v;
    rgb.b = y + 1.770 * u;
    gl_FragColor = vec4(rgb, 1);
}

И вы должны загрузить три текстуры в OpenGL.

person BrianChen    schedule 17.06.2020