Hi!

i did not find a mailinglist for users of x265 encoder. so i am posting here in 
hopes that someone can help me.
i am trying to use x265 for streaming video and want to change encoder bitrate 
during encoding, according to network bandwidth.
it works fine with x264 but when trying to achive this with x265 it fails no 
matter what i try.
it always stays on the bitrate that i set during encoder setup.

i hope i implemented it according to docs:
https://x265.readthedocs.io/en/master/api.html
https://x265.readthedocs.io/en/master/cli.html#quality-rate-control-and-rate-distortion-options

here is my minimal example:


############################################################


/*
 *
 * gcc -O3 -g test.c -o test $(pkg-config --libs --cflags x265) 
-fsanitize=address -fno-omit-frame-pointer -static-libasan
 *
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include <x265.h>

int h265_enc_width = 1920;
int h265_enc_height = 1080;
int bit_rate = 2000;
uint64_t timestamp = 0;
int encoded_frame_bytes = 0;
int rnd_every_x_frames = 100;
int rnd_every_x_frames_cur = 0;

uint8_t *y = NULL;
uint8_t *u = NULL;
uint8_t *v = NULL;

x265_encoder *h265_encoder = NULL;
x265_picture *h265_in_pic = NULL;
x265_picture *h265_out_pic = NULL;
x265_param *param = NULL;

void init_encoder()
{
    param = x265_param_alloc();
    if (x265_param_default_preset(param, "ultrafast", "zerolatency") != 0) {
        printf("init_encoder_h265: H265 encoder:x265_param_default_preset 
error\n");
    }

    param->sourceWidth = h265_enc_width;
    param->sourceHeight = h265_enc_height;
    param->fpsNum = 20;
    param->fpsDenom = 1;
    param->internalCsp = X265_CSP_I420;
    param->bframes = 0;
    param->bRepeatHeaders = 1;
    param->bAnnexB = 1;
    param->keyframeMax = 60; // every n-th frame is an I-frame
    param->bIntraRefresh = 1;

    x265_param_parse(param, "repeat-headers", "1");
    x265_param_parse(param, "annexb", "1");
    x265_param_parse(param, "input-csp", "i420");
    x265_param_parse(param, "log-level", "debug");
    x265_param_parse(param, "frame-rc", "1");

    // 
https://x265.readthedocs.io/en/master/cli.html#quality-rate-control-and-rate-distortion-options
    // Specify the target bitrate in kbps. Default is 0 (CRF)

    param->rc.bitrate = bit_rate;
    param->rc.vbvBufferSize = bit_rate;
    param->rc.vbvMaxBitrate = bit_rate;

    param->rc.rateControlMode = X265_RC_ABR;
    param->rc.bStrictCbr = 1;

    h265_in_pic = x265_picture_alloc();
    x265_picture_init(param, h265_in_pic);

    h265_out_pic = x265_picture_alloc();
    x265_picture_init(param, h265_out_pic);

    // Allocate memory for YUV frame
    h265_in_pic->colorSpace = X265_CSP_I420;
    h265_in_pic->stride[0] = h265_enc_width;
    h265_in_pic->stride[1] = h265_enc_width / 2;
    h265_in_pic->stride[2] = h265_enc_width / 2;
    h265_in_pic->planes[0] = (uint8_t *)calloc(1, (h265_enc_width * 
h265_enc_height));
    h265_in_pic->planes[1] = (uint8_t *)calloc(1, (h265_enc_width * 
h265_enc_height) / 4);
    h265_in_pic->planes[2] = (uint8_t *)calloc(1, (h265_enc_width * 
h265_enc_height) / 4);

    h265_encoder = x265_encoder_open(param);
    printf("H265 encoder:h265_encoder=%p\n", (void *)h265_encoder);

    x265_param_free(param);
}

void kill_encoder()
{
    free(h265_in_pic->planes[0]);
    free(h265_in_pic->planes[1]);
    free(h265_in_pic->planes[2]);
    x265_picture_free(h265_in_pic);
    x265_picture_free(h265_out_pic);
    x265_encoder_close(h265_encoder);
}

void reconfigure_encoder()
{
    printf("reconfigure_encoder_h265:1:bit_rate = %d\n", (int)bit_rate);
    x265_param *param = x265_param_alloc();
    x265_encoder_parameters(h265_encoder, param);

    param->rc.bitrate = bit_rate;
    param->rc.vbvBufferSize = bit_rate;
    param->rc.vbvMaxBitrate = bit_rate;

    int res = x265_encoder_reconfig(h265_encoder, param);
    x265_param_free(param);
    setvbuf(stdout, NULL, _IOLBF, 0);
    setvbuf(stderr, NULL, _IOLBF, 0);
    printf("x265 [*R**] x265_encoder_reconfig:res=%d bitrate=%d\n", (int)res, 
bit_rate);
}

int encode_frame(uint16_t width, uint16_t height,
                           const uint8_t *y,
                           const uint8_t *u,
                           const uint8_t *v,
                           uint64_t pts)
{
    uint32_t i_nal;
    int x265_num_nals;
    uint64_t pts_out;
    int i_frame_size;
    int res;
    x265_nal* h265_nals = NULL;

    h265_in_pic->pts = (int64_t)pts;
    // printf("X265:in_ts:%lu\n", pts);

    memcpy(h265_in_pic->planes[0], y, (width * height));
    memcpy(h265_in_pic->planes[1], u, (width / 2) * (height / 2));
    memcpy(h265_in_pic->planes[2], v, (width / 2) * (height / 2));
    res = x265_encoder_encode(h265_encoder, &h265_nals, &i_nal, h265_in_pic, 
h265_out_pic);

    pts_out = (uint64_t)h265_out_pic->pts;
    // printf("X265:res:%d\n", res);
    // printf("X265:out_ts:%lu\n", pts);
    // printf("X265:out_ts:dts:%d\n", (int)h265_out_pic->dts);
    // printf("X265:out_ts:pts:%d\n", (int)h265_out_pic->pts);

    if (h265_nals == NULL) {
        printf("X265:RET 001\n");
        return -1;
    }

    if (i_nal < 1) {
        printf("X265:RET 002\n");
        return -2;
    }

    x265_num_nals = (int)i_nal;
    i_frame_size = h265_nals[0].sizeBytes;

    if (i_frame_size < 0) {
        // some error
        printf("X265:ERR 010\n");
    } else if (i_frame_size == 0) {
        // zero size output
        printf("X265:ERR 020\n");
    }

    if (h265_nals[0].payload == NULL) {
        printf("X265:ERR 099\n");
        return -3;
    }

    return i_frame_size;
}

uint32_t n_r(const uint32_t upper_bound)
{
    return rand() % upper_bound;
}

void rvbuf(uint8_t *buf, size_t size)
{
    for (int i=0; i < size; i++)
    {
        // random value 1..255
        *buf = (uint8_t)((n_r(255)) + 1);
        buf++;
    }
}

void rnd_yuv()
{
    size_t y_size = h265_enc_width * h265_enc_height;
    size_t u_size = (h265_enc_height/2) * (h265_enc_width/2);
    size_t v_size = (h265_enc_height/2) * (h265_enc_width/2);
    if (!y) {y = calloc(1, y_size);}
    if (!u) {u = calloc(1, u_size);}
    if (!v) {v = calloc(1, v_size);}
    rnd_every_x_frames_cur++;
    if (rnd_every_x_frames_cur > rnd_every_x_frames)
    {
        rnd_every_x_frames_cur = 0;
        rvbuf(y, y_size);
        rvbuf(u, u_size);
        rvbuf(v, v_size);
    }
}

int main(int argc, char *argv[])
{
    init_encoder();

    for (int i=0;i<200;i++) {
        timestamp++;
        rnd_yuv();
        encoded_frame_bytes = encode_frame(h265_enc_width, h265_enc_height, y, 
u, v, timestamp);
        printf("x265 [eee1]: bytes=%d\n", encoded_frame_bytes);
    }

    bit_rate = 800;
    reconfigure_encoder();

    for (int i=0;i<200;i++) {
        timestamp++;
        rnd_yuv();
        encoded_frame_bytes = encode_frame(h265_enc_width, h265_enc_height, y, 
u, v, timestamp);
        printf("x265 [eee2]: bytes=%d\n", encoded_frame_bytes);
    }

    bit_rate = 600;
    reconfigure_encoder();

    for (int i=0;i<200;i++) {
        timestamp++;
        rnd_yuv();
        encoded_frame_bytes = encode_frame(h265_enc_width, h265_enc_height, y, 
u, v, timestamp);
        printf("x265 [eee2]: bytes=%d\n", encoded_frame_bytes);
    }


    kill_encoder();
}



############################################################



compile with:
gcc -O3 -g test.c -o test $(pkg-config --libs --cflags x265) -fsanitize=address 
-fno-omit-frame-pointer -static-libasan
then run:
./test

what i get is:

x265 [info]: frame I:      1, Avg QP:20.63  kb/s: 112.32
x265 [info]: frame P:    599, Avg QP:41.15  kb/s: 1996.36
x265 [info]: consecutive B-frames: 100.0%

encoded 600 frames in 16.54s (36.28 fps), 1993.22 kb/s, Avg QP:41.11


the encoder bitrate stays at about 2000 kbit/s
but i change the rate with reconfigure_encoder() during encoding.

any ideas, what am i doing wrong?


cheers,
Zoff.
_______________________________________________
x265-devel mailing list
[email protected]
https://mailman.videolan.org/listinfo/x265-devel

Reply via email to