mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-24 02:24:07 +00:00
Remove number of references from --gop=lp syntax
The number of references should be part of the presets, so gop should be defined separately.
This commit is contained in:
parent
cbfa824d1a
commit
16790c9f15
193
src/cfg.c
193
src/cfg.c
|
@ -118,6 +118,9 @@ int kvz_config_init(kvz_config *cfg)
|
|||
cfg->input_format = KVZ_FORMAT_P420;
|
||||
cfg->input_bitdepth = 8;
|
||||
|
||||
cfg->gop_lp_definition.d = 0;
|
||||
cfg->gop_lp_definition.t = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -683,105 +686,32 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
struct {
|
||||
unsigned g; // length
|
||||
unsigned d; // depth
|
||||
unsigned r; // references
|
||||
unsigned t; // temporal
|
||||
} gop = { 0, 0, 0, 0 };
|
||||
} gop = { 0, 0, 0 };
|
||||
|
||||
if (sscanf(value, "lp-g%ud%ur%ut%u", &gop.g, &gop.d, &gop.r, &gop.t) != 4) {
|
||||
fprintf(stderr, "Error in GOP syntax. Example: lp-g8d4r2t2\n");
|
||||
// Parse --gop=lp-g#d#t#
|
||||
if (sscanf(value, "lp-g%ud%ut%u", &gop.g, &gop.d, &gop.t) != 3) {
|
||||
fprintf(stderr, "Error in GOP syntax. Example: lp-g8d4t2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gop.g < 1 || gop.g > 32) {
|
||||
fprintf(stderr, "gop.g must be between 1 and 32.\n");
|
||||
return 0;
|
||||
}
|
||||
if (gop.d < 1 || gop.d > 8) {
|
||||
fprintf(stderr, "gop.d must be between 1 and 8.\n");
|
||||
}
|
||||
if (gop.r < 1 || gop.r > 15) {
|
||||
fprintf(stderr, "gop.d must be between 1 and 15.\n");
|
||||
return 0;
|
||||
}
|
||||
if (gop.t < 1 || gop.t > 15) {
|
||||
fprintf(stderr, "gop.t must be between 1 and 32.\n");
|
||||
fprintf(stderr, "gop.t must be between 1 and 15.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize modulos for testing depth.
|
||||
// The picture belong to the lowest depth in which (poc % modulo) == 0.
|
||||
unsigned depth_modulos[8] = { 0 };
|
||||
for (int d = 0; d < gop.d; ++d) {
|
||||
depth_modulos[gop.d - 1 - d] = 1 << d;
|
||||
}
|
||||
depth_modulos[0] = gop.g;
|
||||
|
||||
cfg->gop_lowdelay = 1;
|
||||
cfg->gop_lowdelay = true;
|
||||
cfg->gop_len = gop.g;
|
||||
for (int g = 1; g <= gop.g; ++g) {
|
||||
kvz_gop_config *gop_pic = &cfg->gop[g - 1];
|
||||
|
||||
// Find gop depth for picture.
|
||||
int gop_layer = 0;
|
||||
while (gop_layer < gop.d && (g % depth_modulos[gop_layer])) {
|
||||
++gop_layer;
|
||||
}
|
||||
|
||||
gop_pic->poc_offset = g;
|
||||
gop_pic->layer = gop_layer + 1;
|
||||
gop_pic->qp_offset = gop_layer + 1;
|
||||
gop_pic->ref_pos_count = 0;
|
||||
gop_pic->ref_neg_count = gop.r;
|
||||
gop_pic->is_ref = 0;
|
||||
|
||||
// Set first ref to point to previous frame, and the rest to previous
|
||||
// key-frames.
|
||||
// If gop.t > 1, have (poc % gop.t) == 0 point gop.t frames away,
|
||||
// instead of the previous frame. Set the frames in between to
|
||||
// point to the nearest frame with a lower gop-depth.
|
||||
if (gop.t > 1) {
|
||||
if (gop_pic->poc_offset % gop.t == 0) {
|
||||
gop_pic->ref_neg[0] = gop.t;
|
||||
} else {
|
||||
int r = gop_pic->poc_offset - 1;
|
||||
while (r > 0) {
|
||||
if (cfg->gop[r].layer < gop_pic->layer) break;
|
||||
--r;
|
||||
}
|
||||
// Var r is now 0 or index of the pic with layer < depth.
|
||||
if (cfg->gop[r].layer < gop_pic->layer) {
|
||||
gop_pic->ref_neg[0] = gop_pic->poc_offset - cfg->gop[r].poc_offset;
|
||||
cfg->gop[r].is_ref = 1;
|
||||
} else {
|
||||
// No ref was found, just refer to the previous key-frame.
|
||||
gop_pic->ref_neg[0] = gop_pic->poc_offset % gop.g;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gop_pic->ref_neg[0] = 1;
|
||||
if (gop_pic->poc_offset >= 2) {
|
||||
cfg->gop[gop_pic->poc_offset - 2].is_ref = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int keyframe = gop_pic->poc_offset;
|
||||
for (int i = 1; i < gop_pic->ref_neg_count; ++i) {
|
||||
while (keyframe == gop_pic->ref_neg[i - 1]) {
|
||||
keyframe += gop.g;
|
||||
}
|
||||
gop_pic->ref_neg[i] = keyframe;
|
||||
}
|
||||
|
||||
gop_pic->qp_factor = 0.4624; // from HM
|
||||
}
|
||||
|
||||
for (int g = 0; g < gop.g; ++g) {
|
||||
kvz_gop_config *gop_pic = &cfg->gop[g];
|
||||
if (!gop_pic->is_ref) {
|
||||
gop_pic->qp_factor = 0.68 * 1.31; // derived from HM
|
||||
}
|
||||
}
|
||||
|
||||
// Key-frame is always a reference.
|
||||
cfg->gop[gop.g - 1].is_ref = 1;
|
||||
cfg->gop[gop.g - 1].qp_factor = 0.578; // from HM
|
||||
cfg->gop_lp_definition.d = gop.d;
|
||||
cfg->gop_lp_definition.t = gop.t;
|
||||
} else if (atoi(value) == 8) {
|
||||
cfg->gop_lowdelay = 0;
|
||||
// GOP
|
||||
|
@ -821,10 +751,6 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
fprintf(stderr, "Input error: unsupported gop length, must be 0 or 8\n");
|
||||
return 0;
|
||||
}
|
||||
if (cfg->gop_len && cfg->tmvp_enable) {
|
||||
cfg->tmvp_enable = false;
|
||||
fprintf(stderr, "Disabling TMVP because GOP is used.\n");
|
||||
}
|
||||
}
|
||||
else if OPT("bipred")
|
||||
cfg->bipred = atobool(value);
|
||||
|
@ -985,6 +911,97 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void kvz_config_process_lp_gop(kvz_config *cfg)
|
||||
{
|
||||
struct {
|
||||
unsigned g;
|
||||
unsigned d;
|
||||
unsigned t;
|
||||
} gop;
|
||||
|
||||
gop.g = cfg->gop_len;
|
||||
gop.d = cfg->gop_lp_definition.d;
|
||||
gop.t = cfg->gop_lp_definition.t;
|
||||
|
||||
// Initialize modulos for testing depth.
|
||||
// The picture belong to the lowest depth in which (poc % modulo) == 0.
|
||||
unsigned depth_modulos[8] = { 0 };
|
||||
for (int d = 0; d < gop.d; ++d) {
|
||||
depth_modulos[gop.d - 1 - d] = 1 << d;
|
||||
}
|
||||
depth_modulos[0] = gop.g;
|
||||
|
||||
cfg->gop_lowdelay = 1;
|
||||
cfg->gop_len = gop.g;
|
||||
for (int g = 1; g <= gop.g; ++g) {
|
||||
kvz_gop_config *gop_pic = &cfg->gop[g - 1];
|
||||
|
||||
// Find gop depth for picture.
|
||||
int gop_layer = 0;
|
||||
while (gop_layer < gop.d && (g % depth_modulos[gop_layer])) {
|
||||
++gop_layer;
|
||||
}
|
||||
|
||||
gop_pic->poc_offset = g;
|
||||
gop_pic->layer = gop_layer + 1;
|
||||
gop_pic->qp_offset = gop_layer + 1;
|
||||
gop_pic->ref_pos_count = 0;
|
||||
gop_pic->ref_neg_count = cfg->ref_frames;
|
||||
gop_pic->is_ref = 0;
|
||||
|
||||
// Set first ref to point to previous frame, and the rest to previous
|
||||
// key-frames.
|
||||
// If gop.t > 1, have (poc % gop.t) == 0 point gop.t frames away,
|
||||
// instead of the previous frame. Set the frames in between to
|
||||
// point to the nearest frame with a lower gop-depth.
|
||||
if (gop.t > 1) {
|
||||
if (gop_pic->poc_offset % gop.t == 0) {
|
||||
gop_pic->ref_neg[0] = gop.t;
|
||||
} else {
|
||||
int r = gop_pic->poc_offset - 1;
|
||||
while (r > 0) {
|
||||
if (cfg->gop[r].layer < gop_pic->layer) break;
|
||||
--r;
|
||||
}
|
||||
// Var r is now 0 or index of the pic with layer < depth.
|
||||
if (cfg->gop[r].layer < gop_pic->layer) {
|
||||
gop_pic->ref_neg[0] = gop_pic->poc_offset - cfg->gop[r].poc_offset;
|
||||
cfg->gop[r].is_ref = 1;
|
||||
} else {
|
||||
// No ref was found, just refer to the previous key-frame.
|
||||
gop_pic->ref_neg[0] = gop_pic->poc_offset % gop.g;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gop_pic->ref_neg[0] = 1;
|
||||
if (gop_pic->poc_offset >= 2) {
|
||||
cfg->gop[gop_pic->poc_offset - 2].is_ref = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int keyframe = gop_pic->poc_offset;
|
||||
for (int i = 1; i < gop_pic->ref_neg_count; ++i) {
|
||||
while (keyframe == gop_pic->ref_neg[i - 1]) {
|
||||
keyframe += gop.g;
|
||||
}
|
||||
gop_pic->ref_neg[i] = keyframe;
|
||||
}
|
||||
|
||||
gop_pic->qp_factor = 0.4624; // from HM
|
||||
}
|
||||
|
||||
for (int g = 0; g < gop.g; ++g) {
|
||||
kvz_gop_config *gop_pic = &cfg->gop[g];
|
||||
if (!gop_pic->is_ref) {
|
||||
gop_pic->qp_factor = 0.68 * 1.31; // derived from HM
|
||||
}
|
||||
}
|
||||
|
||||
// Key-frame is always a reference.
|
||||
cfg->gop[gop.g - 1].is_ref = 1;
|
||||
cfg->gop[gop.g - 1].qp_factor = 0.578; // from HM
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check that configuration is sensible.
|
||||
*
|
||||
|
|
|
@ -36,6 +36,7 @@ kvz_config *kvz_config_alloc(void);
|
|||
int kvz_config_init(kvz_config *cfg);
|
||||
int kvz_config_destroy(kvz_config *cfg);
|
||||
int kvz_config_parse(kvz_config *cfg, const char *name, const char *value);
|
||||
void kvz_config_process_lp_gop(kvz_config *cfg);
|
||||
int kvz_config_validate(const kvz_config *cfg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -80,7 +80,7 @@ static int select_owf_auto(const kvz_config *const cfg)
|
|||
* \param cfg encoder configuration
|
||||
* \return initialized encoder control or NULL on failure
|
||||
*/
|
||||
encoder_control_t* kvz_encoder_control_init(const kvz_config *const cfg) {
|
||||
encoder_control_t* kvz_encoder_control_init(kvz_config *const cfg) {
|
||||
encoder_control_t *encoder = NULL;
|
||||
|
||||
if (!cfg) {
|
||||
|
@ -88,6 +88,16 @@ encoder_control_t* kvz_encoder_control_init(const kvz_config *const cfg) {
|
|||
goto init_failed;
|
||||
}
|
||||
|
||||
if (cfg->gop_len > 0) {
|
||||
if (cfg->tmvp_enable) {
|
||||
cfg->tmvp_enable = false;
|
||||
fprintf(stderr, "Disabling TMVP because GOP is used.\n");
|
||||
}
|
||||
if (cfg->gop_lowdelay) {
|
||||
kvz_config_process_lp_gop(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the parameters make sense.
|
||||
if (!kvz_config_validate(cfg)) {
|
||||
goto init_failed;
|
||||
|
|
|
@ -155,7 +155,7 @@ typedef struct encoder_control_t
|
|||
|
||||
} encoder_control_t;
|
||||
|
||||
encoder_control_t* kvz_encoder_control_init(const kvz_config *cfg);
|
||||
encoder_control_t* kvz_encoder_control_init(kvz_config *cfg);
|
||||
void kvz_encoder_control_free(encoder_control_t *encoder);
|
||||
|
||||
void kvz_encoder_control_input_init(encoder_control_t *encoder, int32_t width, int32_t height);
|
||||
|
|
|
@ -75,7 +75,9 @@ static kvz_encoder * kvazaar_open(const kvz_config *cfg)
|
|||
goto kvazaar_open_failure;
|
||||
}
|
||||
|
||||
encoder->control = kvz_encoder_control_init(cfg);
|
||||
// FIXME: const qualifier disgarded. I don't want to change kvazaar_open
|
||||
// but I really need to change cfg.
|
||||
encoder->control = kvz_encoder_control_init((kvz_config*)cfg);
|
||||
if (!encoder->control) {
|
||||
goto kvazaar_open_failure;
|
||||
}
|
||||
|
|
|
@ -312,6 +312,11 @@ typedef struct kvz_config
|
|||
|
||||
enum kvz_input_format input_format; /*!< \brief Use Temporal Motion Vector Predictors. */
|
||||
int32_t input_bitdepth; /*!< \brief Use Temporal Motion Vector Predictors. */
|
||||
|
||||
struct {
|
||||
unsigned d; // depth
|
||||
unsigned t; // temporal
|
||||
} gop_lp_definition;
|
||||
} kvz_config;
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue