Выходное видео x264 пустое, когда включена потоковая передача - PullRequest
1 голос
/ 14 июля 2020

Я использую libx264, собранную из исходников. Он был настроен для получения как .dll, так и .lib с помощью этой команды

./configure --disable-cli --enable-shared --extra-ldflags=-Wl,--output-def=libx264.def`

Я использую libx264 API в своей программе совместного использования экрана с предустановкой - «очень быстро», настройте - «нулевой», профиль - «высокий», а также следующие настройки.

        param.i_csp = X264_CSP_BGRA;
        param.i_threads = 1;
        param.i_width = width;
        param.i_height = height;
        param.i_fps_num = fps;
        param.i_fps_den = 1;
        param.rc.i_bitrate = bitrate;
        param.rc.i_rc_method = X264_RC_ABR;
        param.rc.b_filler = true;
        param.rc.f_rf_constant = (float)0;
        param.rc.i_vbv_max_bitrate = param.rc.i_bitrate;
        param.rc.i_vbv_buffer_size = param.rc.i_bitrate;
        param.b_repeat_headers = 0;
        param.b_annexb = 1;

Для этих настроек программа работает нормально. Я указал его как однопоточное, установив param.i_threads = 1. Если это удалить, x264 по умолчанию использует несколько потоков и автоматически устанавливает param.i_threads как 1,5-кратное количество ядер в ЦП. Это даст более высокую производительность, чем работа в одном потоке.

Но когда я удаляю param.i_threads = 1, чтобы сделать его многопоточным, сгенерированный вывод становится полностью серым. Я не вижу никаких выходных данных, когда просматриваю прямой эфир с помощью VL C, или иногда я могу просматривать странные выходные данные.

Я использую это растровое изображение в качестве примера (https://imgur.com/a/l8LCd1l). Только одно и то же изображение кодируется несколько раз. Когда он сохранен в видео .h264, он хорошо виден. Но когда закодированная полезная нагрузка отправляется через rtmp, прямой поток дает очень плохой и странный вывод (или иногда вообще не выводится). Это странный вывод, который я вижу большую часть времени для этого изображения: https://imgur.com/a/VdyX1Zm

Это полный пример кода, в котором я одновременно транслирую и записываю видеофайл одного и того же картина. Это использует библиотеку srs librtmp. Ошибки нет, но поток имеет странный вывод.

В этом коде, если вы установите add param.i_threads = 1;, тогда будет доступен только поток вывода. Проблема в том, что он должен быть доступен для просмотра как в однопоточной, так и в многопоточной кодировке.

#include <iostream>
#include <stdio.h>
#include <sstream>
#include <x264.h>
#include "srs_librtmp.h"

#pragma comment(lib, "C:/Softwares/x264/libx264.lib")

using namespace std;

int check_ret(int ret);

int main()
{
    int dts = 0;

    x264_param_t param;
    x264_t* h;
    x264_nal_t* nals;
    int i_nal;
    int pts = 0;
    int i_frame_size;
    x264_picture_t picIn;
    x264_picture_t picOut;

    x264_param_default_preset(&param, "veryfast", "zerolatency");

    //x264 settings
    param.i_csp = X264_CSP_BGRA;
    param.i_width = 1920;
    param.i_height = 1080;
    param.i_fps_num = 30;
    param.i_fps_den = 1;
    param.rc.i_bitrate = 2500;
    param.rc.i_rc_method = X264_RC_ABR;
    param.rc.b_filler = true;
    param.rc.f_rf_constant = (float)0;
    param.rc.i_vbv_max_bitrate = param.rc.i_bitrate;
    param.rc.i_vbv_buffer_size = param.rc.i_bitrate;
    param.b_repeat_headers = 0;
    param.b_annexb = 1;

    x264_param_apply_profile(&param, "high");
    h = x264_encoder_open(&param);

    //allocate picture
    x264_picture_alloc(&picIn, param.i_csp, param.i_width, param.i_height);

    //picture settings
    picIn.img.i_plane = 1;
    picIn.img.i_stride[0] = 4 * param.i_width;
    picIn.i_type = X264_TYPE_AUTO;

    int header_size = x264_encoder_headers(h, &nals, &i_nal);
    FILE* fptr;
    fopen_s(&fptr, "example1.h264", "wb");
    // write sps and pps in the video file
    fwrite(nals->p_payload, header_size, 1, fptr);

    int size = 1920 * 1080 * 4;
    char* bmp = new char[size];
    FILE* bitptr;
    errno_t err = fopen_s(&bitptr, "flower.bmp", "rb");
    fseek(bitptr, 54, SEEK_SET);
    fread(bmp, size, 1, bitptr);
    fclose(bitptr);

    srs_rtmp_t rtmp = srs_rtmp_create("127.0.0.1:1935/live/test");

    if (srs_rtmp_handshake(rtmp) != 0)
    {
        std::cout << "Simple handshake failed.";
        return -1;
    }

    std::cout << "Handshake completed successfully.\n";

    if (srs_rtmp_connect_app(rtmp) != 0) {
        std::cout << "Connecting to host failed.";
        return -1;
    }

    std::cout << "Connected to host successfully.\n";

    if (srs_rtmp_publish_stream(rtmp) != 0) {
        std::cout << "Publish signal failed.";
    }

    std::cout << "Publish signal success\n";

    // write sps and pps in the live stream
    int ret = srs_h264_write_raw_frames(rtmp, reinterpret_cast<char*>(nals->p_payload), header_size, 0, 0);
    ret = check_ret(ret);
    if (!ret)
        return -1;
    std::cout << "SPS and PPS sent.\n";

    // main loop
    std::cout << "Now streaming and encoding\n";
    int i = 1800;
    while (i--)
    {

        picIn.img.plane[0] = reinterpret_cast<uint8_t*>(bmp);
        picIn.i_pts = pts++;
        i_frame_size = x264_encoder_encode(h, &nals, &i_nal, &picIn, &picOut);
        if (i_frame_size)
        {
            for (int j = 0; j < i_nal; j++)
            {

                x264_nal_t* nal = nals + j;
                // write data in the video file
                fwrite(nal->p_payload, nal->i_payload, 1, fptr);
                // write data in the live stream
                ret = srs_h264_write_raw_frames(rtmp, reinterpret_cast<char*>(nal->p_payload), nal->i_payload, dts, dts);
                ret = check_ret(ret);
                if (!ret)
                {
                    return -1;
                }
            }
        }
        else
        {
            std::cout << "i_frame_size = 0 (encoder failed)\n";
        }
        dts += 33;
    }

    while (x264_encoder_delayed_frames(h))
    {
        i_frame_size = x264_encoder_encode(h, &nals, &i_nal, NULL, &picOut);
        if (i_frame_size)
        {
            fwrite(nals->p_payload, i_frame_size, 1, fptr);
        }
    }

    std::cout << "\nAll done\n";
    std::cout << "Output video is example1.h264 and it is viewable in VLC";

    return 0;
}

int check_ret(int ret)
{
    if (ret != 0) {
        if (srs_h264_is_dvbsp_error(ret)) {
            srs_human_trace("ignoring drop video error, code=%d", ret);
        }
        else if (srs_h264_is_duplicated_sps_error(ret)) {
            srs_human_trace("ignoring duplicated sps, code=%d", ret);
        }
        else if (srs_h264_is_duplicated_pps_error(ret)) {
            srs_human_trace("ignoring duplicated pps, code=%d", ret);
        }
        else {
            srs_human_trace("sending h264 raw data failed. ret=%d", ret);
            return 0;
        }
    }
    return 1;
}

Если вы хотите загрузить исходный файл flower.bmp, вот ссылка: https://gofile.io/d/w2kX56 Эта ошибка также может быть воспроизведена в любом другом файле BMP.

Пожалуйста, скажите мне, что вызывает эту проблему, когда включена многопоточность. Я устанавливаю неправильные значения? Код, в котором я транслирую закодированные данные, неправильный?

...