Fix problems with CTB 16x16 and level 5.1.
diff --git a/doc/params.txt b/doc/params.txt
index 1dfdb68..29ddc72 100644
--- a/doc/params.txt
+++ b/doc/params.txt
@@ -48,6 +48,15 @@ Output format. Set to 'byte' if the output is a raw H.265 stream.
Chroma format (0 => 4:0:0, 1 => 4:2:0, 2 => 4:2:2, 3 => 4:4:4).
+* level=X. Default to 0. Floating point value, e.g. "4.1".
+
+Set the level indicator of the stream. If left to 0, the level is set
+automatically (currently, this is "6.2"). Note that setting the level has no
+incidence on the parameters used by the encoder. A warning is printed when the
+encoder detects that the level specified is incompatible with the encoder
+parameters.
+
+
* bit-depth=W,X,Y,Z. Default to 8,8,8,8. Other values are unsupported.
Bit depth for luma/chroma/PCM luma/PCM chroma (8..14). The luma bit depth
diff --git a/f265/analyze.c b/f265/analyze.c
index 704d088..c415cbf 100644
--- a/f265/analyze.c
+++ b/f265/analyze.c
@@ -35,6 +35,7 @@
// Bit 10 enables fake luma interpolation.
// Bit 11 enables the use of thresholds for the mode analysis.
// Bit 12 forces the reconstruction of blocks in RDM.
+// Bit 13 prevents the analysis of the 32x32 CBs (forced split).
// Bit 14 early terminates the transform tree exploration.
// Description of some failed experiments.
@@ -3389,6 +3390,9 @@ static void fenc_analyze_cb_rdo_threshold(f265_enc_thread *t, f265_cb *cb)
// Analyze the 16x16 CBs in RDO.
fenc_analyze_split_cb(t, cb);
+ // Disable the analysis of the 32x32 CTB.
+ if (t->enc->gd.algo&(1<<13)) cb_unsplit_flag = 0;
+
// Test 32x32 RDM.
if (cb_unsplit_flag)
{
@@ -3497,6 +3501,10 @@ static void fenc_analyze_cb(f265_enc_thread *t, f265_cb *cb)
int cb_inter_flag = cb_unsplit_flag && t->frame_type != F265_FRAME_I;
uint8_t *init_tn = t->tt.tn;
+ // Disable the analysis of the 32x32 CTB.
+ if (cb->lg_bs == 5 && t->enc->gd.algo&(1<<13))
+ cb_inter_flag = cb_intra_hv_flag = cb_intra_un_flag = 0;
+
// Initialize the CB.
fenc_analyze_init_cb(t, cb);
diff --git a/f265/bdi.c b/f265/bdi.c
index d87c8ef..b8114a6 100644
--- a/f265/bdi.c
+++ b/f265/bdi.c
@@ -286,6 +286,13 @@ void f265_normalize_params(f265_enc_params *p)
#undef CLF
#undef CLP
+ // Set the level indicator automatically.
+ if (!p->level_idc) p->level_idc = 6.2*30;
+
+ // Warn if the level is incompatible with the specified parameters.
+ if (p->level_idc >= 5*30 && p->cb_range[1] < 5)
+ fprintf(stderr, "Warning: non-conformant stream. 32x32 CTBs must be used with level >= 5.\n");
+
// Make sure there is room for B frames in the lookahead.
p->la_decision_delay = F265_MAX(p->la_decision_delay, p->nb_b_frames);
diff --git a/f265/bs.c b/f265/bs.c
index 7e3b6b3..204e6af 100644
--- a/f265/bs.c
+++ b/f265/bs.c
@@ -176,7 +176,7 @@ void fenc_write_vps(f265_vlc_bs *vbs, f265_enc *enc)
FENC_PUT_FLAG(vbs, 0, "general_non_packed_constraint_flag");
FENC_PUT_FLAG(vbs, 0, "general_frame_only_constraint_flag");
FENC_PUT_BITS(vbs, 0, 44, "XXX_reserved_zero_44bits");
- FENC_PUT_BITS(vbs, 153, 8, "general_level_idc"); // 30* Level. 5.1*30=153.
+ FENC_PUT_BITS(vbs, gd->level_idc, 8, "general_level_idc");
FENC_PUT_FLAG(vbs, 1, "vps_sub_layer_ordering_info_present_flag");
FENC_PUT_UE_V(vbs, gd->nb_refs, "vps_max_dec_pic_buffering_minus1");
FENC_PUT_UE_V(vbs, gd->nb_reordered_frames, "vps_num_reorder_pics");
@@ -206,7 +206,7 @@ void fenc_write_sps(f265_vlc_bs *vbs, f265_enc *enc)
FENC_PUT_FLAG(vbs, 0, "general_non_packed_constraint_flag");
FENC_PUT_FLAG(vbs, 0, "general_frame_only_constraint_flag");
FENC_PUT_BITS(vbs, 0, 44, "XXX_reserved_zero_44bits");
- FENC_PUT_BITS(vbs, 153, 8, "general_level_idc");
+ FENC_PUT_BITS(vbs, gd->level_idc, 8, "general_level_idc");
FENC_PUT_UE_V(vbs, fenc_get_sps_id(enc), "sps_seq_parameter_set_id");
FENC_PUT_UE_V(vbs, gd->chroma_format, "chroma_format_idc");
FENC_PUT_UE_V(vbs, gd->pix_dim[0], "pic_width_in_luma_samples");
diff --git a/f265/enc.h b/f265/enc.h
index 12da932..3af6647 100644
--- a/f265/enc.h
+++ b/f265/enc.h
@@ -2254,7 +2254,7 @@ typedef struct f265_gen_data
int8_t profile_idc;
// Level indicator.
- int8_t level_idc;
+ uint8_t level_idc;
// Chroma QP index offset.
int8_t chroma_qp_idx_off;
diff --git a/f265/f265.h b/f265/f265.h
index 083bde9..5fade9f 100644
--- a/f265/f265.h
+++ b/f265/f265.h
@@ -140,7 +140,7 @@ typedef struct f265_enc_params
int8_t profile_idc;
// Level indicator.
- int8_t level_idc;
+ uint8_t level_idc;
// Chroma QP index offset.
int8_t chroma_qp_idx_off;
diff --git a/f265/parse.c b/f265/parse.c
index f519c5c..9642a7a 100644
--- a/f265/parse.c
+++ b/f265/parse.c
@@ -122,6 +122,11 @@ static void handle_param_chroma_format(f265_parse_ctx *ctx, f265_enc_params *p,
p->chroma_format = a->i;
}
+static void handle_param_level(f265_parse_ctx *ctx, f265_enc_params *p, f265_parse_arg *a, int32_t nb_args)
+{
+ p->level_idc = a->f*30;
+}
+
static void handle_param_bit_depth(f265_parse_ctx *ctx, f265_enc_params *p, f265_parse_arg *a, int32_t nb_args)
{
for (int i = 0; i < 4; i++) p->bit_depth[i] = a[i].i;
@@ -249,20 +254,20 @@ static void handle_param_quality(f265_parse_ctx *ctx, f265_enc_params *p, f265_p
if (quality <= 0)
{
p->cb_range[0] = 4;
- p->cb_range[1] = 4;
+ p->cb_range[1] = 5;
p->tb_range[0] = 3;
p->tb_range[1] = 4;
p->tb_depth[0] = 0;
p->tb_depth[1] = 0;
p->merge_cand = 1;
for (int i = 0; i < 3; i++) p->me_algo[i] = 0;
- p->algo = (1<<10);
+ p->algo = (1<<10)|(1<<13);
}
else if (quality <= 10)
{
p->cb_range[0] = 3;
- p->cb_range[1] = 4;
+ p->cb_range[1] = 5;
p->tb_range[0] = 2;
p->tb_range[1] = 4;
p->tb_depth[0] = 1;
@@ -270,7 +275,7 @@ static void handle_param_quality(f265_parse_ctx *ctx, f265_enc_params *p, f265_p
p->rdo_level = 1;
p->amp_flag = 0;
p->tmv_flag = 1;
- p->algo = (1<<0)|(1<<2)|(1<<4)|(1<<5)|(1<<7)|(1<<10)|(1<<11)|(1<<14);
+ p->algo = (1<<0)|(1<<2)|(1<<4)|(1<<5)|(1<<7)|(1<<10)|(1<<11)|(1<<13)|(1<<14);
}
else if (quality <= 20)
@@ -290,7 +295,7 @@ static void handle_param_quality(f265_parse_ctx *ctx, f265_enc_params *p, f265_p
else if (quality <= 25)
{
p->cb_range[0] = 3;
- p->cb_range[1] = 4;
+ p->cb_range[1] = 5;
p->tb_range[0] = 2;
p->tb_range[1] = 4;
p->tb_depth[0] = 1;
@@ -298,7 +303,7 @@ static void handle_param_quality(f265_parse_ctx *ctx, f265_enc_params *p, f265_p
p->rdo_level = 1;
p->amp_flag = 0;
p->tmv_flag = 1;
- p->algo = (1<<0)|(1<<2)|(1<<4)|(1<<5)|(1<<7)|(1<<10);
+ p->algo = (1<<0)|(1<<2)|(1<<4)|(1<<5)|(1<<7)|(1<<10)|(1<<13);
}
else if (quality <= 50)
@@ -495,6 +500,7 @@ static const f265_parse_entry f265_enc_params_table[] =
// Name, handler, argument count, argument type (0=int, 1=float, 2=string).
{ "format", handle_param_format, 1, 2 },
{ "chroma-format", handle_param_chroma_format, 1, 0 },
+ { "level", handle_param_level, 1, 1 },
{ "bit-depth", handle_param_bit_depth, 4, 0 },
{ "cb-range", handle_param_cb_range, 2, 0 },
{ "pcm-range", handle_param_pcm_range, 2, 0 },
diff --git a/test/data/regress.ini b/test/data/regress.ini
index b9795ff..77e7440 100644
--- a/test/data/regress.ini
+++ b/test/data/regress.ini
@@ -1,6 +1,6 @@
[test_intra16x16V]
encs=hm,f265
-f265_params=format=byte chroma-format=1 bit-depth=8,8,8,8 cb-range=4,4 pcm-range=3,5 tb-range=3,4 tb-depth=0,0 qg=-1 ref=0 bframes=0 deblock=0 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=0 amp=0 tmv=0 weight=0 chroma-me=0 key-frame-spacing=10000 key-frame-type=1
+f265_params=format=byte chroma-format=1 level=5.1 bit-depth=8,8,8,8 cb-range=4,4 pcm-range=3,5 tb-range=3,4 tb-depth=0,0 qg=-1 ref=0 bframes=0 deblock=0 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=0 amp=0 tmv=0 weight=0 chroma-me=0 key-frame-spacing=10000 key-frame-type=1
hm_cfg=intra16x16.cfg
f265_special=hm_gop
van_cfg_f265= VAN_DUMP_INTRA
@@ -13,7 +13,7 @@ qp=30
[test_inter16x16P]
encs=hm,f265
-f265_params=format=byte chroma-format=1 bit-depth=8,8,8,8 cb-range=4,4 pcm-range=3,5 tb-range=3,4 tb-depth=0,0 qg=-1 ref=1 bframes=0 deblock=0 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=0 amp=0 tmv=0 weight=0 chroma-me=0 key-frame-spacing=32 key-frame-type=0
+f265_params=format=byte chroma-format=1 level=5.1 bit-depth=8,8,8,8 cb-range=4,4 pcm-range=3,5 tb-range=3,4 tb-depth=0,0 qg=-1 ref=1 bframes=0 deblock=0 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=0 amp=0 tmv=0 weight=0 chroma-me=0 key-frame-spacing=32 key-frame-type=0
hm_cfg=inter16x16p.cfg
f265_special=hm_gop
van_cfg_f265= VAN_LOAD_CTB_ANALYSIS
@@ -26,7 +26,7 @@ qp=20
[test_inter_full_B]
encs=hm,f265
-f265_params=format=byte chroma-format=1 bit-depth=8,8,8,8 cb-range=3,6 pcm-range=3,5 tb-range=2,5 tb-depth=4,4 qg=-1 ref=4 bframes=7 deblock=1 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=1 amp=1 tmv=1 weight=0 chroma-me=0 key-frame-spacing=32 key-frame-type=0
+f265_params=format=byte chroma-format=1 level=5.1 bit-depth=8,8,8,8 cb-range=3,6 pcm-range=3,5 tb-range=2,5 tb-depth=4,4 qg=-1 ref=4 bframes=7 deblock=1 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=1 amp=1 tmv=1 weight=0 chroma-me=0 key-frame-spacing=32 key-frame-type=0
hm_params=--DeblockingFilterControlPresent=0
hm_cfg=inter_full_b.cfg
f265_special=hm_gop
@@ -40,7 +40,7 @@ qp=31
[test_analyze]
encs=f265
-f265_params=format=byte chroma-format=1 bit-depth=8,8,8,8 cb-range=3,4 pcm-range=3,5 tb-range=2,4 tb-depth=1,1 qg=-1 ref=1 bframes=0 deblock=1 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=0 amp=1 tmv=1 weight=0 chroma-me=0 key-frame-spacing=32 key-frame-type=0 hpel=xdia,1,sad qpel=xdia,1,satd rdo=1 hm-me=1 nullify-inter-tb=1 algo=6,7
+f265_params=format=byte chroma-format=1 level=5.1 bit-depth=8,8,8,8 cb-range=3,4 pcm-range=3,5 tb-range=2,4 tb-depth=1,1 qg=-1 ref=1 bframes=0 deblock=1 sao=0 scaling=0 transquant-bypass=0 sign-hiding=0 transform-skip=0 smooth-intra=0 amp=1 tmv=1 weight=0 chroma-me=0 key-frame-spacing=32 key-frame-type=0 hpel=xdia,1,sad qpel=xdia,1,satd rdo=1 hm-me=1 nullify-inter-tb=1 algo=6,7
mode=db
video=racehorses
frames=10