Преобразование вывода OpenGL в H264 с помощью x264

Я хочу преобразовать вывод программы OpenGL в h264 и передать вывод. Я где-то собрал большую часть кода, и я получаю выходной файл, но я понятия не имею, что с ним делать, или если он действителен. В настоящее время вывод просто сохраняется в файле .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 );

    }

Я получил функцию GRB2YUV от http://svn.gnumonks.org/trunk/21c3-video/cutting_tagging/tools/mpeg4ip-1.2/server/util/rgb2yuv/rgb2yuv.c

Вывод выглядит так

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 возвращает данные.


person user2660369    schedule 07.08.2013    source источник
comment
в vlc медиаплеере играет? Если это так, то вы правильно кодируете. Если нет, то вы неправильно кодируете видео.   -  person Magn3s1um    schedule 07.08.2013
comment
ни vlc, ни avplay не могут его воспроизвести.   -  person user2660369    schedule 07.08.2013
comment
Где вы объявляете pic_in?   -  person Magn3s1um    schedule 07.08.2013
comment
Изменить: добавлены объявления глобальных переменных.   -  person user2660369    schedule 07.08.2013
comment
Настройки x264 будут отличаться в зависимости от контейнера (или протокола), в который вы хотите писать. Поток предназначен для службы потоковой передачи, такой как twitch.tv?   -  person szatmary    schedule 07.08.2013
comment
Я хочу транслировать как rtsp, чтобы любой, кто обращается к rtsp://xxx.xxx.xxx.xxx/stream, мог просматривать поток.   -  person user2660369    schedule 11.08.2013


Ответы (2)


У вас неправильный формат файла. Ничто не сможет это прочитать. A.264 использует приложение B с заголовками, предшествующими кадрам IDR.

изменить эти параметры,

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
person szatmary    schedule 07.08.2013
comment
к вашему сведению. Это если для файлов .264. Если вы выполняете потоковую передачу в RTMP, вам нужно будет создать заголовок последовательности из x264_encoder_headers() и переключиться обратно на b_annexb = 0; - person szatmary; 07.08.2013
comment
Для файлов это прекрасно работает. Как я могу транслировать по RTMP, какую библиотеку (для Linux и Windows) мне использовать? - person user2660369; 08.08.2013
comment
github.com/szatmary/RtmpBroadcaster. Посмотрите на rtmp.cpp, flvtag.cpp и encode.cpp. Вы транслируете видеоигру? - person szatmary; 08.08.2013
comment
спасибо, я посмотрю на это. Это не видеоигра, а просто программа-симулятор, использующая OpenGL. - person user2660369; 08.08.2013

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

Скорее всего, поэтому у вас нет полезного видео. Вы можете узнать больше о том, что делать здесь: Как кодировать серию изображений в H264 с помощью x264 C API?

Масштабировать:

 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. 
person Magn3s1um    schedule 07.08.2013
comment
Я хотел обойти использование libffmpeg только для преобразования YUV420P. Итак, вы думаете, что функция RGB2YUV не работает? - person user2660369; 07.08.2013
comment
Не сломан, но, возможно, отличается от того, что вы думаете, что он делает. Из какой библиотеки вы это берете? Вы уверены, что он берет RGB и переходит на YUV420P? Это может быть преобразование YUV444 в RGB888, что может не сработать. - person Magn3s1um; 07.08.2013
comment
Я получил функцию GRB2YUV от svn.gnumonks.org/trunk/21c3-video/cutting_tagged/tools/ - person user2660369; 07.08.2013
comment
Я думаю, вам нужно масштабировать его, чтобы заставить его работать. Кажется, есть некоторые спецификации о том, как изображение должно быть масштабировано перед кодированием изображения. Используйте способ, указанный в моей ссылке, и я уверен, что он сработает. - person Magn3s1um; 07.08.2013
comment
Итак, как передать данные RGB в sws_scale? - person user2660369; 07.08.2013
comment
откуда взялся srcstride? data — указатель на начало данных RGB, h — 768 (в моем случае), pic_in — вывод sws_scale? pic_in.img.stride не определено, вы имели в виду pic_in.img.i_stride? - person user2660369; 07.08.2013
comment
Возможно, они изменили имя параметра, так что да, какое бы свойство ни представляло шаг (который вычисляется автоматически). - person Magn3s1um; 07.08.2013