diff --git a/README.md b/README.md index 4a775a21..5c839386 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ Video structure: - 8: B-frame pyramid of length 8 - lp-: Low-delay P-frame GOP (e.g. lp-g8d4t2, see README) + --(no-)open-gop : Use open GOP configuration. [enabled] --cqmfile : Read custom quantization matrices from a file. --bitrate : Target bitrate [0] - 0: Disable rate control. diff --git a/doc/kvazaar.1 b/doc/kvazaar.1 index ccfd148d..fbfb1662 100644 --- a/doc/kvazaar.1 +++ b/doc/kvazaar.1 @@ -1,4 +1,4 @@ -.TH KVAZAAR "1" "August 2018" "kvazaar v1.2.0" "User Commands" +.TH KVAZAAR "1" "October 2018" "kvazaar v1.2.0" "User Commands" .SH NAME kvazaar \- open source HEVC encoder .SH SYNOPSIS @@ -121,6 +121,9 @@ GOP structure [8] \- lp\-: Low\-delay P\-frame GOP (e.g. lp\-g8d4t2, see README) .TP +\fB\-\-(no\-)open\-gop +Use open GOP configuration. [enabled] +.TP \fB\-\-cqmfile Read custom quantization matrices from a file. .TP diff --git a/src/cfg.c b/src/cfg.c index a8b3f32e..234e4a31 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -117,6 +117,7 @@ int kvz_config_init(kvz_config *cfg) cfg->gop_lp_definition.d = 3; cfg->gop_lp_definition.t = 1; + cfg->open_gop = true; cfg->roi.width = 0; cfg->roi.height = 0; @@ -939,6 +940,9 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value) return 0; } } + else if OPT("open-gop") { + cfg->open_gop = (bool)atobool(value); + } else if OPT("bipred") cfg->bipred = atobool(value); else if OPT("bitrate") diff --git a/src/cli.c b/src/cli.c index 07a918ae..32618aa6 100644 --- a/src/cli.c +++ b/src/cli.c @@ -131,6 +131,8 @@ static const struct option long_options[] = { { "me-steps", required_argument, NULL, 0 }, { "fast-residual-cost", required_argument, NULL, 0 }, { "set-qp-in-cu", no_argument, NULL, 0 }, + { "open-gop", no_argument, NULL, 0 }, + { "no-open-gop", no_argument, NULL, 0 }, {0, 0, 0, 0} }; @@ -395,6 +397,7 @@ void print_help(void) " - 8: B-frame pyramid of length 8\n" " - lp-: Low-delay P-frame GOP\n" " (e.g. lp-g8d4t2, see README)\n" + " --(no-)open-gop : Use open GOP configuration. [enabled]\n" " --cqmfile : Read custom quantization matrices from a file.\n" " --bitrate : Target bitrate [0]\n" " - 0: Disable rate control.\n" diff --git a/src/encoderstate.c b/src/encoderstate.c index 25acb88a..77abf595 100644 --- a/src/encoderstate.c +++ b/src/encoderstate.c @@ -1185,10 +1185,29 @@ static void encoder_state_init_new_frame(encoder_state_t * const state, kvz_pict if (state->frame->num == 0) { state->frame->poc = 0; } else if (cfg->gop_len && !cfg->gop_lowdelay) { - // Calculate POC according to the global frame counter and GOP structure - int32_t poc = state->frame->num - 1; - int32_t poc_offset = cfg->gop[state->frame->gop_offset].poc_offset; - state->frame->poc = poc - poc % cfg->gop_len + poc_offset; + + int32_t framenum = state->frame->num - 1; + // Handle closed GOP + // Closed GOP structure has an extra IDR between the GOPs + if (cfg->intra_period > 0 && !cfg->open_gop) { + if (((state->frame->num - 1) % (cfg->intra_period + 1)) == cfg->intra_period) { + // Insert IDR before each new GOP after intra period in closed GOP configuration + state->frame->poc = 0; + } else { + // Calculate gop_offset again here with the new frame number + framenum = framenum % (cfg->intra_period + 1); + state->frame->gop_offset = (framenum + cfg->gop_len) % cfg->gop_len; + int32_t poc_offset = cfg->gop[state->frame->gop_offset].poc_offset; + state->frame->poc = framenum - framenum % cfg->gop_len + poc_offset; + // This should not be an irap picture in closed GOP + state->frame->is_irap = false; + } + } else { // Open GOP + // Calculate POC according to the global frame counter and GOP structure + int32_t poc_offset = cfg->gop[state->frame->gop_offset].poc_offset; + state->frame->poc = framenum - framenum % cfg->gop_len + poc_offset; + } + kvz_videoframe_set_poc(state->tile->frame, state->frame->poc); } else if (cfg->intra_period > 0) { state->frame->poc = state->frame->num % cfg->intra_period; @@ -1197,9 +1216,9 @@ static void encoder_state_init_new_frame(encoder_state_t * const state, kvz_pict } // Check whether the frame is a keyframe or not. - if (state->frame->num == 0) { + if (state->frame->num == 0 || state->frame->poc == 0) { state->frame->is_irap = true; - } else { + } else if(cfg->open_gop) { // In closed-GOP IDR frames are poc==0 so skip this check state->frame->is_irap = cfg->intra_period > 0 && (state->frame->poc % cfg->intra_period) == 0; @@ -1213,7 +1232,8 @@ static void encoder_state_init_new_frame(encoder_state_t * const state, kvz_pict if (state->frame->num == 0 || cfg->intra_period == 1 || cfg->gop_len == 0 || - cfg->gop_lowdelay) + cfg->gop_lowdelay || + !cfg->open_gop) // Closed GOP uses IDR pictures { state->frame->pictype = KVZ_NAL_IDR_W_RADL; } else { diff --git a/src/kvazaar.h b/src/kvazaar.h index 262be213..02dedd6b 100644 --- a/src/kvazaar.h +++ b/src/kvazaar.h @@ -372,6 +372,9 @@ typedef struct kvz_config /** \brief Set QP at CU level keeping pic_init_qp_minus26 in PPS zero */ int8_t set_qp_in_cu; + /** \brief Flag to enable/disable open GOP configuration */ + int8_t open_gop; + } kvz_config; /** diff --git a/tests/test_gop.sh b/tests/test_gop.sh index b5c6059a..3f757ad5 100755 --- a/tests/test_gop.sh +++ b/tests/test_gop.sh @@ -11,3 +11,10 @@ valgrind_test 264x130 10 $common_args --gop=8 -p0 --owf=4 valgrind_test 264x130 20 $common_args --gop=8 -p16 --owf=0 valgrind_test 264x130 10 $common_args --gop=8 -p1 --owf=4 valgrind_test 264x130 10 $common_args --gop=lp-g4d3t1 -p5 --owf=4 +valgrind_test 264x130 10 $common_args --gop=8 -p8 --owf=4 --no-open-gop +# Do more extensive tests in a private gitlab CI runner +[ ! -z "$GITLAB_CI" ] && valgrind_test 264x130 20 $common_args --gop=8 -p8 --owf=0 --no-open-gop +[ ! -z "$GITLAB_CI" ] && valgrind_test 264x130 40 $common_args --gop=8 -p32 --owf=4 --no-open-gop +[ ! -z "$GITLAB_CI" ] && valgrind_test 264x130 70 $common_args --gop=8 -p64 --owf=4 --no-open-gop +[ ! -z "$GITLAB_CI" ] && valgrind_test 264x130 50 $common_args --gop=8 -p40 --owf=4 --no-open-gop +[ ! -z "$GITLAB_CI" ] && valgrind_test 264x130 10 $common_args --gop=8 -p8 --owf=0 --no-open-gop --bipred