From 23138fd6deb2568ffee806c24358362621c432c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Wed, 30 Nov 2022 17:24:55 -0600 Subject: [PATCH 01/16] Model implementation based on avcodec_descriptor_next from libavcodec --- libvmaf/include/libvmaf/model.h | 8 ++++++++ libvmaf/src/model.c | 7 +++++++ libvmaf/src/model.h | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/libvmaf/include/libvmaf/model.h b/libvmaf/include/libvmaf/model.h index 98211466f..265fb0bfc 100644 --- a/libvmaf/include/libvmaf/model.h +++ b/libvmaf/include/libvmaf/model.h @@ -70,6 +70,14 @@ typedef struct VmafModelCollectionScore { } bootstrap; } VmafModelCollectionScore; +typedef struct VmafBuiltInModel { + const char *version; + const char *data; + const int *data_len; +} VmafBuiltInModel; + +const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev); + int vmaf_model_collection_load(VmafModel **model, VmafModelCollection **model_collection, VmafModelConfig *cfg, diff --git a/libvmaf/src/model.c b/libvmaf/src/model.c index dfffdccc3..959bce9db 100644 --- a/libvmaf/src/model.c +++ b/libvmaf/src/model.c @@ -316,3 +316,10 @@ int vmaf_model_collection_feature_overload(VmafModel *model, return err; } +const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev){ + if(!prev) + return &built_in_models[0]; + if(prev - built_in_models < BUILT_IN_MODEL_CNT) + return prev + 1; + return NULL; +} \ No newline at end of file diff --git a/libvmaf/src/model.h b/libvmaf/src/model.h index e0a41953b..ace93259d 100644 --- a/libvmaf/src/model.h +++ b/libvmaf/src/model.h @@ -83,6 +83,14 @@ typedef struct VmafModelCollection { const char *name; } VmafModelCollection; +typedef struct VmafBuiltInModel { + const char *version; + const char *data; + const int *data_len; +} VmafBuiltInModel; + +const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev); + char *vmaf_model_generate_name(VmafModelConfig *cfg); int vmaf_model_collection_append(VmafModelCollection **model_collection, From 0fd4015a5ecd99f1ce106a01bf214d4aff71a0e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Wed, 30 Nov 2022 19:26:05 -0600 Subject: [PATCH 02/16] Add inline documentation --- libvmaf/include/libvmaf/model.h | 8 ++++++++ libvmaf/src/model.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/libvmaf/include/libvmaf/model.h b/libvmaf/include/libvmaf/model.h index 265fb0bfc..3f150dc04 100644 --- a/libvmaf/include/libvmaf/model.h +++ b/libvmaf/include/libvmaf/model.h @@ -76,6 +76,14 @@ typedef struct VmafBuiltInModel { const int *data_len; } VmafBuiltInModel; +/** + * Iterate through all built in vmaf models + * + * @param prev previous model. NULL to get the first model + * + * @return next model or NULL after the last model + * +*/ const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev); int vmaf_model_collection_load(VmafModel **model, diff --git a/libvmaf/src/model.h b/libvmaf/src/model.h index ace93259d..2fa5dd982 100644 --- a/libvmaf/src/model.h +++ b/libvmaf/src/model.h @@ -89,6 +89,14 @@ typedef struct VmafBuiltInModel { const int *data_len; } VmafBuiltInModel; +/** + * Iterate through all built in vmaf models + * + * @param prev previous model. NULL to get the first model + * + * @return next model or NULL after the last model + * +*/ const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev); char *vmaf_model_generate_name(VmafModelConfig *cfg); From 6a121faa380957ebdb161394545a6655b69570b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Wed, 30 Nov 2022 19:34:03 -0600 Subject: [PATCH 03/16] Move VmafBuiltInModel Definition to libvmaf/include/model.h --- libvmaf/src/model.c | 6 ------ libvmaf/src/model.h | 6 ------ 2 files changed, 12 deletions(-) diff --git a/libvmaf/src/model.c b/libvmaf/src/model.c index 959bce9db..647b05ee0 100644 --- a/libvmaf/src/model.c +++ b/libvmaf/src/model.c @@ -13,12 +13,6 @@ #include "read_json_model.h" #include "svm.h" -typedef struct VmafBuiltInModel { - const char *version; - const char *data; - const int *data_len; -} VmafBuiltInModel; - #if VMAF_BUILT_IN_MODELS #if VMAF_FLOAT_FEATURES extern const char src_vmaf_float_v0_6_1neg_json; diff --git a/libvmaf/src/model.h b/libvmaf/src/model.h index 2fa5dd982..bf1f6be8f 100644 --- a/libvmaf/src/model.h +++ b/libvmaf/src/model.h @@ -83,12 +83,6 @@ typedef struct VmafModelCollection { const char *name; } VmafModelCollection; -typedef struct VmafBuiltInModel { - const char *version; - const char *data; - const int *data_len; -} VmafBuiltInModel; - /** * Iterate through all built in vmaf models * From c12c49fbb24cd71fb6861f7c359cfb3b58bf6cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Fri, 2 Dec 2022 19:08:42 -0600 Subject: [PATCH 04/16] Bring VmafBuiltInModel back into model.c and declare VmafModelDescriptor as type exposed in model.h --- libvmaf/src/model.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/libvmaf/src/model.c b/libvmaf/src/model.c index 647b05ee0..1a36ee683 100644 --- a/libvmaf/src/model.c +++ b/libvmaf/src/model.c @@ -34,6 +34,17 @@ extern const char src_vmaf_4k_v0_6_1_json; extern const int src_vmaf_4k_v0_6_1_json_len; #endif +/** + * For the purposes of working with vmaf_model_descriptor_next, + * the version property of VmafBuiltInModel must be the first property + * declared on this struct +*/ +typedef struct VmafBuiltInModel { + const char *version; + const char *data; + const int *data_len; +} VmafBuiltInModel; + static const VmafBuiltInModel built_in_models[] = { #if VMAF_BUILT_IN_MODELS #if VMAF_FLOAT_FEATURES @@ -310,10 +321,15 @@ int vmaf_model_collection_feature_overload(VmafModel *model, return err; } -const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev){ - if(!prev) +const VmafModelDescriptor *vmaf_model_descriptor_next(const VmafModelDescriptor *prev){ + // Cast *VmafModelDescriptor into *VmafBuilInModel + VmafBuiltInModel *builtin = (VmafBuiltInModel*)prev; + + if(!builtin) return &built_in_models[0]; - if(prev - built_in_models < BUILT_IN_MODEL_CNT) - return prev + 1; + + if(builtin - built_in_models < BUILT_IN_MODEL_CNT) + return (VmafModelDescriptor*)(builtin + 1); + return NULL; } \ No newline at end of file From e35ded76963a6a4b0d41f99eb61c006e08c83157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Fri, 2 Dec 2022 19:09:10 -0600 Subject: [PATCH 05/16] These weren't added in the previous commit for some reason --- libvmaf/include/libvmaf/model.h | 8 +++----- libvmaf/src/model.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libvmaf/include/libvmaf/model.h b/libvmaf/include/libvmaf/model.h index 3f150dc04..c5455a1a2 100644 --- a/libvmaf/include/libvmaf/model.h +++ b/libvmaf/include/libvmaf/model.h @@ -70,11 +70,9 @@ typedef struct VmafModelCollectionScore { } bootstrap; } VmafModelCollectionScore; -typedef struct VmafBuiltInModel { +typedef struct VmafModelDescriptor{ const char *version; - const char *data; - const int *data_len; -} VmafBuiltInModel; +} VmafModelDescriptor; /** * Iterate through all built in vmaf models @@ -84,7 +82,7 @@ typedef struct VmafBuiltInModel { * @return next model or NULL after the last model * */ -const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev); +const VmafModelDescriptor *vmaf_model_descriptor_next(const VmafModelDescriptor *prev); int vmaf_model_collection_load(VmafModel **model, VmafModelCollection **model_collection, diff --git a/libvmaf/src/model.h b/libvmaf/src/model.h index bf1f6be8f..160ccca47 100644 --- a/libvmaf/src/model.h +++ b/libvmaf/src/model.h @@ -91,7 +91,7 @@ typedef struct VmafModelCollection { * @return next model or NULL after the last model * */ -const VmafBuiltInModel *vmaf_built_in_model_next(const VmafBuiltInModel *prev); +const VmafModelDescriptor *vmaf_built_in_model_next(const VmafModelDescriptor *prev); char *vmaf_model_generate_name(VmafModelConfig *cfg); From 53d0fe80f10927c02793029d603e2af4eaab3106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Fri, 2 Dec 2022 19:12:01 -0600 Subject: [PATCH 06/16] Fix typo and a casting I forgot to make --- libvmaf/src/model.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libvmaf/src/model.c b/libvmaf/src/model.c index 1a36ee683..e4e9c7918 100644 --- a/libvmaf/src/model.c +++ b/libvmaf/src/model.c @@ -322,11 +322,11 @@ int vmaf_model_collection_feature_overload(VmafModel *model, } const VmafModelDescriptor *vmaf_model_descriptor_next(const VmafModelDescriptor *prev){ - // Cast *VmafModelDescriptor into *VmafBuilInModel + // Cast *VmafModelDescriptor into *VmafBuiltInModel VmafBuiltInModel *builtin = (VmafBuiltInModel*)prev; if(!builtin) - return &built_in_models[0]; + return (VmafModelDescriptor*)&built_in_models[0]; if(builtin - built_in_models < BUILT_IN_MODEL_CNT) return (VmafModelDescriptor*)(builtin + 1); From 288c11390cc6d5192f0760b87bcbcdc683319e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= <32885853+ThatNerdUKnow@users.noreply.github.com> Date: Mon, 5 Dec 2022 10:13:56 -0600 Subject: [PATCH 07/16] Fix function name --- libvmaf/src/model.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvmaf/src/model.h b/libvmaf/src/model.h index 160ccca47..fd780469a 100644 --- a/libvmaf/src/model.h +++ b/libvmaf/src/model.h @@ -91,7 +91,7 @@ typedef struct VmafModelCollection { * @return next model or NULL after the last model * */ -const VmafModelDescriptor *vmaf_built_in_model_next(const VmafModelDescriptor *prev); +const VmafModelDescriptor *vmaf_model_descriptor_next(const VmafModelDescriptor *prev); char *vmaf_model_generate_name(VmafModelConfig *cfg); From 2243109a850b930eccbd0d4e6a99db0a4f9baca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Mon, 5 Dec 2022 17:18:05 -0600 Subject: [PATCH 08/16] Add unit tests --- .vscode/c_cpp_properties.json | 16 +++++ libvmaf/test/test_model.c | 117 +++++++++++++++++++++------------- 2 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 .vscode/c_cpp_properties.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..e883a9f2d --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang-12", + "cStandard": "c17", + "cppStandard": "c++14", + "intelliSenseMode": "linux-clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index ff965cd38..720c47100 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -27,17 +27,18 @@ static int model_compare(VmafModel *model_a, VmafModel *model_b) { int err = 0; - //err += model_a->type != model_b->type; + // err += model_a->type != model_b->type; err += model_a->slope != model_b->slope; err += model_a->intercept != model_b->intercept; err += model_a->n_features != model_b->n_features; - for (unsigned i = 0; i < model_a->n_features; i++) { - //err += strcmp(model_a->feature[i].name, model_b->feature[i].name) != 0; - err += model_a->feature[i].slope != model_b->feature[i].slope; - err += model_a->feature[i].intercept != model_b->feature[i].intercept; - err += !model_a->feature[i].opts_dict != !model_b->feature[i].opts_dict; + for (unsigned i = 0; i < model_a->n_features; i++) + { + // err += strcmp(model_a->feature[i].name, model_b->feature[i].name) != 0; + err += model_a->feature[i].slope != model_b->feature[i].slope; + err += model_a->feature[i].intercept != model_b->feature[i].intercept; + err += !model_a->feature[i].opts_dict != !model_b->feature[i].opts_dict; } err += model_a->score_clip.enabled != model_b->score_clip.enabled; @@ -54,7 +55,8 @@ static int model_compare(VmafModel *model_a, VmafModel *model_b) err += model_a->score_transform.p2.enabled != model_b->score_transform.p2.enabled; err += model_a->score_transform.p2.value != model_b->score_transform.p2.value; err += model_a->score_transform.knots.enabled != model_b->score_transform.knots.enabled; - for (unsigned i = 0; i < model_a->score_transform.knots.n_knots; i++) { + for (unsigned i = 0; i < model_a->score_transform.knots.n_knots; i++) + { err += model_a->score_transform.knots.list[i].x != model_b->score_transform.knots.list[i].x; err += model_a->score_transform.knots.list[i].y != model_b->score_transform.knots.list[i].y; } @@ -69,14 +71,14 @@ static char *test_json_model() int err = 0; VmafModel *model_json; - VmafModelConfig cfg_json = { 0 }; - const char *path_json = JSON_MODEL_PATH"vmaf_v0.6.1neg.json"; + VmafModelConfig cfg_json = {0}; + const char *path_json = JSON_MODEL_PATH "vmaf_v0.6.1neg.json"; err = vmaf_read_json_model_from_path(&model_json, &cfg_json, path_json); mu_assert("problem during vmaf_read_json_model", !err); VmafModel *model; - VmafModelConfig cfg = { 0 }; + VmafModelConfig cfg = {0}; const char *version = "vmaf_v0.6.1neg"; err = vmaf_model_load(&model, &cfg, version); @@ -96,14 +98,14 @@ static char *test_built_in_model() int err = 0; VmafModel *model; - VmafModelConfig cfg = { 0 }; + VmafModelConfig cfg = {0}; const char *version = "vmaf_v0.6.1neg"; err = vmaf_model_load(&model, &cfg, version); mu_assert("problem during vmaf_model_load", !err); VmafModel *model_file; - VmafModelConfig cfg_file = { 0 }; - const char *path = JSON_MODEL_PATH"vmaf_v0.6.1neg.json"; + VmafModelConfig cfg_file = {0}; + const char *path = JSON_MODEL_PATH "vmaf_v0.6.1neg.json"; err = vmaf_model_load_from_path(&model_file, &cfg_file, path); mu_assert("problem during vmaf_model_load_from_path", !err); @@ -121,8 +123,8 @@ static char *test_model_load_and_destroy() int err; VmafModel *model; - VmafModelConfig cfg = { 0 }; - const char *path = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; + VmafModelConfig cfg = {0}; + const char *path = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model, &cfg, path); mu_assert("problem during vmaf_model_load_from_path", !err); @@ -145,7 +147,7 @@ static char *test_model_feature() int err; VmafModel *model; - VmafModelConfig cfg = { 0 }; + VmafModelConfig cfg = {0}; const char *version = "vmaf_v0.6.1"; err = vmaf_model_load(&model, &cfg, version); mu_assert("problem during vmaf_model_load", !err); @@ -173,13 +175,13 @@ static char *test_model_feature() const VmafDictionaryEntry *e = vmaf_dictionary_get(&model->feature[0].opts_dict, - "adm_enhancement_gain_limit", 0); + "adm_enhancement_gain_limit", 0); mu_assert("dict should have a new key/val pair", !strcmp(e->key, "adm_enhancement_gain_limit") && - !strcmp(e->val, "1.1")); + !strcmp(e->val, "1.1")); VmafModel *model_neg; - VmafModelConfig cfg_neg = { 0 }; + VmafModelConfig cfg_neg = {0}; const char *version_neg = "vmaf_v0.6.1neg"; err = vmaf_model_load(&model_neg, &cfg_neg, version_neg); mu_assert("problem during vmaf_model_load", !err); @@ -200,10 +202,10 @@ static char *test_model_feature() model->feature[0].opts_dict); const VmafDictionaryEntry *e2 = vmaf_dictionary_get(&model->feature[0].opts_dict, - "adm_enhancement_gain_limit", 0); + "adm_enhancement_gain_limit", 0); mu_assert("dict should have an existing key/val pair", !strcmp(e2->key, "adm_enhancement_gain_limit") && - !strcmp(e2->val, "1.1")); + !strcmp(e2->val, "1.1")); err = vmaf_model_feature_overload(model, "adm", dict_neg); @@ -215,10 +217,10 @@ static char *test_model_feature() model->feature[0].opts_dict); const VmafDictionaryEntry *e3 = vmaf_dictionary_get(&model->feature[0].opts_dict, - "adm_enhancement_gain_limit", 0); + "adm_enhancement_gain_limit", 0); mu_assert("dict should have an updated key/val pair", !strcmp(e3->key, "adm_enhancement_gain_limit") && - !strcmp(e3->val, "1.2")); + !strcmp(e3->val, "1.2")); vmaf_model_destroy(model); vmaf_model_destroy(model_neg); @@ -234,7 +236,7 @@ static char *test_model_check_default_behavior_unset_flags() VmafModelConfig cfg = { .name = "some_vmaf", }; - const char *path = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; + const char *path = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model, &cfg, path); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Model name is inconsistent.\n", !strcmp(model->name, "some_vmaf")); @@ -258,7 +260,7 @@ static char *test_model_check_default_behavior_set_flags() .name = "some_vmaf", .flags = VMAF_MODEL_FLAGS_DEFAULT, }; - const char *path = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; + const char *path = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model, &cfg, path); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Model name is inconsistent.\n", !strcmp(model->name, "some_vmaf")); @@ -281,7 +283,7 @@ static char *test_model_set_flags() VmafModelConfig cfg1 = { .flags = VMAF_MODEL_FLAG_ENABLE_TRANSFORM, }; - const char *path1 = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; + const char *path1 = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model1, &cfg1, path1); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Score transform must be enabled.\n", @@ -294,7 +296,7 @@ static char *test_model_set_flags() VmafModelConfig cfg2 = { .flags = VMAF_MODEL_FLAG_DISABLE_CLIP, }; - const char *path2 = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; + const char *path2 = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model2, &cfg2, path2); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Score transform must be disabled.\n", @@ -303,9 +305,9 @@ static char *test_model_set_flags() !model2->score_clip.enabled); vmaf_model_destroy(model2); - VmafModel *model3; - VmafModelConfig cfg3 = { 0 }; - const char *path3 = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; + VmafModel *model3; + VmafModelConfig cfg3 = {0}; + const char *path3 = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model3, &cfg3, path3); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("feature[0].opts_dict must be NULL.\n", @@ -322,9 +324,9 @@ static char *test_model_set_flags() !model3->feature[5].opts_dict); vmaf_model_destroy(model3); - VmafModel *model4; - VmafModelConfig cfg4 = { 0 }; - const char *path4 = JSON_MODEL_PATH"vmaf_float_v0.6.1neg.json"; + VmafModel *model4; + VmafModelConfig cfg4 = {0}; + const char *path4 = JSON_MODEL_PATH "vmaf_float_v0.6.1neg.json"; err = vmaf_model_load_from_path(&model4, &cfg4, path4); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("feature[0].opts_dict must not be NULL.\n", @@ -343,34 +345,62 @@ static char *test_model_set_flags() const VmafDictionaryEntry *entry = NULL; entry = vmaf_dictionary_get(&model4->feature[0].opts_dict, "adm_enhn_gain_limit", 0); mu_assert("feature[0].opts_dict must have key adm_enhn_gain_limit.\n", - strcmp(entry->key, "adm_enhn_gain_limit")==0); + strcmp(entry->key, "adm_enhn_gain_limit") == 0); mu_assert("feature[0].opts_dict[\"adm_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1")==0); + strcmp(entry->val, "1") == 0); entry = vmaf_dictionary_get(&model4->feature[2].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[2].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit")==0); + strcmp(entry->key, "vif_enhn_gain_limit") == 0); mu_assert("feature[2].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1")==0); + strcmp(entry->val, "1") == 0); entry = vmaf_dictionary_get(&model4->feature[3].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[3].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit")==0); + strcmp(entry->key, "vif_enhn_gain_limit") == 0); mu_assert("feature[3].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1")==0); + strcmp(entry->val, "1") == 0); entry = vmaf_dictionary_get(&model4->feature[4].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[4].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit")==0); + strcmp(entry->key, "vif_enhn_gain_limit") == 0); mu_assert("feature[4].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1")==0); + strcmp(entry->val, "1") == 0); entry = vmaf_dictionary_get(&model4->feature[5].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[5].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit")==0); + strcmp(entry->key, "vif_enhn_gain_limit") == 0); mu_assert("feature[5].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1")==0); + strcmp(entry->val, "1") == 0); vmaf_model_destroy(model4); return NULL; } +char *test_model_next() +{ + + + VmafModelDescriptor *first = vmaf_model_descriptor_next(NULL); + VmafBuiltInModel *builtin = first; + mu_assert("When given null, return first item",first == &built_in_models[0]); + mu_assert("Version field matches on the first VmafBuiltInModel",first->version == builtin->version); + + for(int i=1;i==BUILT_IN_MODEL_CNT;i++){ + VmafBuiltInModel *builtin = &built_in_models[i]; + VmafModelDescriptor *current = builtin; + VmafBuiltInModel *expected = &built_in_models[i+1]; + + VmafModelDescriptor *next = vmaf_model_descriptor_next(current); + + mu_assert("Given the address of a VmafBuiltInModel, returns the address of the next VmafBuiltInModel",next==expected); + mu_assert("Version field should match on both pointers",expected->version == next->version); + } + + VmafModelDescriptor *last = &built_in_models[BUILT_IN_MODEL_CNT]; + + VmafModelDescriptor *shouldBeNull = vmaf_model_descriptor_next(last); + + mu_assert("When given the last item in the array, returns null",!shouldBeNull); + return NULL; +} + char *run_tests() { mu_run_test(test_json_model); @@ -382,5 +412,6 @@ char *run_tests() mu_run_test(test_model_check_default_behavior_set_flags); mu_run_test(test_model_set_flags); mu_run_test(test_model_feature); + mu_run_test(test_model_next); return NULL; } From 47629ef171b4e15463a3b20a71f7a99917adf5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Mon, 5 Dec 2022 17:21:02 -0600 Subject: [PATCH 09/16] Add disclaimer --- libvmaf/test/test_model.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index 720c47100..61e591121 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -373,10 +373,12 @@ static char *test_model_set_flags() return NULL; } +/** + * This test may fail if VmafBuiltInModel's memory layout has changed + * (version MUST be the first defined property in the struct) +*/ char *test_model_next() { - - VmafModelDescriptor *first = vmaf_model_descriptor_next(NULL); VmafBuiltInModel *builtin = first; mu_assert("When given null, return first item",first == &built_in_models[0]); From b5dc4d77ad14cb87f60e786f6d3b1e6f87ef24c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= <32885853+ThatNerdUKnow@users.noreply.github.com> Date: Mon, 5 Dec 2022 17:24:08 -0600 Subject: [PATCH 10/16] Delete c_cpp_properties.json Vscode automatically generated this file, It's not needed --- .vscode/c_cpp_properties.json | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .vscode/c_cpp_properties.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index e883a9f2d..000000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux", - "includePath": [ - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "/usr/bin/clang-12", - "cStandard": "c17", - "cppStandard": "c++14", - "intelliSenseMode": "linux-clang-x64" - } - ], - "version": 4 -} \ No newline at end of file From bd2c79c8daee5dc5921c92315277213a2751a3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= <32885853+ThatNerdUKnow@users.noreply.github.com> Date: Tue, 6 Dec 2022 08:00:31 -0600 Subject: [PATCH 11/16] Update test_model.c Forgot to assert that *next is not null --- libvmaf/test/test_model.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index 61e591121..2265726fc 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -391,6 +391,7 @@ char *test_model_next() VmafModelDescriptor *next = vmaf_model_descriptor_next(current); + mu_assert("Pointer returned from vmaf_model_descriptor_next is not null",next); mu_assert("Given the address of a VmafBuiltInModel, returns the address of the next VmafBuiltInModel",next==expected); mu_assert("Version field should match on both pointers",expected->version == next->version); } From 95c9cd92f4b0f2996b12401bbcceaf736c172149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= <32885853+ThatNerdUKnow@users.noreply.github.com> Date: Tue, 6 Dec 2022 12:23:16 -0600 Subject: [PATCH 12/16] Update test_model.c change test function's name to better reflect which function it's actually testing --- libvmaf/test/test_model.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index 2265726fc..f66d274bb 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -377,7 +377,7 @@ static char *test_model_set_flags() * This test may fail if VmafBuiltInModel's memory layout has changed * (version MUST be the first defined property in the struct) */ -char *test_model_next() +char *test_model_descriptor_next() { VmafModelDescriptor *first = vmaf_model_descriptor_next(NULL); VmafBuiltInModel *builtin = first; @@ -415,6 +415,6 @@ char *run_tests() mu_run_test(test_model_check_default_behavior_set_flags); mu_run_test(test_model_set_flags); mu_run_test(test_model_feature); - mu_run_test(test_model_next); + mu_run_test(test_model_descriptor_next); return NULL; } From 2334d39fb06d753451e0892910ea0e5e38af0577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Tue, 6 Dec 2022 17:24:57 -0600 Subject: [PATCH 13/16] Revert "Add unit tests" This reverts commit 2243109a850b930eccbd0d4e6a99db0a4f9baca9. --- libvmaf/test/test_model.c | 88 +++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index f66d274bb..d2d639dd0 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -27,18 +27,17 @@ static int model_compare(VmafModel *model_a, VmafModel *model_b) { int err = 0; - // err += model_a->type != model_b->type; + //err += model_a->type != model_b->type; err += model_a->slope != model_b->slope; err += model_a->intercept != model_b->intercept; err += model_a->n_features != model_b->n_features; - for (unsigned i = 0; i < model_a->n_features; i++) - { - // err += strcmp(model_a->feature[i].name, model_b->feature[i].name) != 0; - err += model_a->feature[i].slope != model_b->feature[i].slope; - err += model_a->feature[i].intercept != model_b->feature[i].intercept; - err += !model_a->feature[i].opts_dict != !model_b->feature[i].opts_dict; + for (unsigned i = 0; i < model_a->n_features; i++) { + //err += strcmp(model_a->feature[i].name, model_b->feature[i].name) != 0; + err += model_a->feature[i].slope != model_b->feature[i].slope; + err += model_a->feature[i].intercept != model_b->feature[i].intercept; + err += !model_a->feature[i].opts_dict != !model_b->feature[i].opts_dict; } err += model_a->score_clip.enabled != model_b->score_clip.enabled; @@ -55,8 +54,7 @@ static int model_compare(VmafModel *model_a, VmafModel *model_b) err += model_a->score_transform.p2.enabled != model_b->score_transform.p2.enabled; err += model_a->score_transform.p2.value != model_b->score_transform.p2.value; err += model_a->score_transform.knots.enabled != model_b->score_transform.knots.enabled; - for (unsigned i = 0; i < model_a->score_transform.knots.n_knots; i++) - { + for (unsigned i = 0; i < model_a->score_transform.knots.n_knots; i++) { err += model_a->score_transform.knots.list[i].x != model_b->score_transform.knots.list[i].x; err += model_a->score_transform.knots.list[i].y != model_b->score_transform.knots.list[i].y; } @@ -71,14 +69,14 @@ static char *test_json_model() int err = 0; VmafModel *model_json; - VmafModelConfig cfg_json = {0}; - const char *path_json = JSON_MODEL_PATH "vmaf_v0.6.1neg.json"; + VmafModelConfig cfg_json = { 0 }; + const char *path_json = JSON_MODEL_PATH"vmaf_v0.6.1neg.json"; err = vmaf_read_json_model_from_path(&model_json, &cfg_json, path_json); mu_assert("problem during vmaf_read_json_model", !err); VmafModel *model; - VmafModelConfig cfg = {0}; + VmafModelConfig cfg = { 0 }; const char *version = "vmaf_v0.6.1neg"; err = vmaf_model_load(&model, &cfg, version); @@ -98,14 +96,14 @@ static char *test_built_in_model() int err = 0; VmafModel *model; - VmafModelConfig cfg = {0}; + VmafModelConfig cfg = { 0 }; const char *version = "vmaf_v0.6.1neg"; err = vmaf_model_load(&model, &cfg, version); mu_assert("problem during vmaf_model_load", !err); VmafModel *model_file; - VmafModelConfig cfg_file = {0}; - const char *path = JSON_MODEL_PATH "vmaf_v0.6.1neg.json"; + VmafModelConfig cfg_file = { 0 }; + const char *path = JSON_MODEL_PATH"vmaf_v0.6.1neg.json"; err = vmaf_model_load_from_path(&model_file, &cfg_file, path); mu_assert("problem during vmaf_model_load_from_path", !err); @@ -123,8 +121,8 @@ static char *test_model_load_and_destroy() int err; VmafModel *model; - VmafModelConfig cfg = {0}; - const char *path = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; + VmafModelConfig cfg = { 0 }; + const char *path = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model, &cfg, path); mu_assert("problem during vmaf_model_load_from_path", !err); @@ -147,7 +145,7 @@ static char *test_model_feature() int err; VmafModel *model; - VmafModelConfig cfg = {0}; + VmafModelConfig cfg = { 0 }; const char *version = "vmaf_v0.6.1"; err = vmaf_model_load(&model, &cfg, version); mu_assert("problem during vmaf_model_load", !err); @@ -175,13 +173,13 @@ static char *test_model_feature() const VmafDictionaryEntry *e = vmaf_dictionary_get(&model->feature[0].opts_dict, - "adm_enhancement_gain_limit", 0); + "adm_enhancement_gain_limit", 0); mu_assert("dict should have a new key/val pair", !strcmp(e->key, "adm_enhancement_gain_limit") && - !strcmp(e->val, "1.1")); + !strcmp(e->val, "1.1")); VmafModel *model_neg; - VmafModelConfig cfg_neg = {0}; + VmafModelConfig cfg_neg = { 0 }; const char *version_neg = "vmaf_v0.6.1neg"; err = vmaf_model_load(&model_neg, &cfg_neg, version_neg); mu_assert("problem during vmaf_model_load", !err); @@ -202,10 +200,10 @@ static char *test_model_feature() model->feature[0].opts_dict); const VmafDictionaryEntry *e2 = vmaf_dictionary_get(&model->feature[0].opts_dict, - "adm_enhancement_gain_limit", 0); + "adm_enhancement_gain_limit", 0); mu_assert("dict should have an existing key/val pair", !strcmp(e2->key, "adm_enhancement_gain_limit") && - !strcmp(e2->val, "1.1")); + !strcmp(e2->val, "1.1")); err = vmaf_model_feature_overload(model, "adm", dict_neg); @@ -217,10 +215,10 @@ static char *test_model_feature() model->feature[0].opts_dict); const VmafDictionaryEntry *e3 = vmaf_dictionary_get(&model->feature[0].opts_dict, - "adm_enhancement_gain_limit", 0); + "adm_enhancement_gain_limit", 0); mu_assert("dict should have an updated key/val pair", !strcmp(e3->key, "adm_enhancement_gain_limit") && - !strcmp(e3->val, "1.2")); + !strcmp(e3->val, "1.2")); vmaf_model_destroy(model); vmaf_model_destroy(model_neg); @@ -236,7 +234,7 @@ static char *test_model_check_default_behavior_unset_flags() VmafModelConfig cfg = { .name = "some_vmaf", }; - const char *path = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; + const char *path = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model, &cfg, path); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Model name is inconsistent.\n", !strcmp(model->name, "some_vmaf")); @@ -260,7 +258,7 @@ static char *test_model_check_default_behavior_set_flags() .name = "some_vmaf", .flags = VMAF_MODEL_FLAGS_DEFAULT, }; - const char *path = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; + const char *path = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model, &cfg, path); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Model name is inconsistent.\n", !strcmp(model->name, "some_vmaf")); @@ -283,7 +281,7 @@ static char *test_model_set_flags() VmafModelConfig cfg1 = { .flags = VMAF_MODEL_FLAG_ENABLE_TRANSFORM, }; - const char *path1 = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; + const char *path1 = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model1, &cfg1, path1); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Score transform must be enabled.\n", @@ -296,7 +294,7 @@ static char *test_model_set_flags() VmafModelConfig cfg2 = { .flags = VMAF_MODEL_FLAG_DISABLE_CLIP, }; - const char *path2 = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; + const char *path2 = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model2, &cfg2, path2); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("Score transform must be disabled.\n", @@ -305,9 +303,9 @@ static char *test_model_set_flags() !model2->score_clip.enabled); vmaf_model_destroy(model2); - VmafModel *model3; - VmafModelConfig cfg3 = {0}; - const char *path3 = JSON_MODEL_PATH "vmaf_float_v0.6.1.json"; + VmafModel *model3; + VmafModelConfig cfg3 = { 0 }; + const char *path3 = JSON_MODEL_PATH"vmaf_float_v0.6.1.json"; err = vmaf_model_load_from_path(&model3, &cfg3, path3); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("feature[0].opts_dict must be NULL.\n", @@ -324,9 +322,9 @@ static char *test_model_set_flags() !model3->feature[5].opts_dict); vmaf_model_destroy(model3); - VmafModel *model4; - VmafModelConfig cfg4 = {0}; - const char *path4 = JSON_MODEL_PATH "vmaf_float_v0.6.1neg.json"; + VmafModel *model4; + VmafModelConfig cfg4 = { 0 }; + const char *path4 = JSON_MODEL_PATH"vmaf_float_v0.6.1neg.json"; err = vmaf_model_load_from_path(&model4, &cfg4, path4); mu_assert("problem during vmaf_model_load_from_path", !err); mu_assert("feature[0].opts_dict must not be NULL.\n", @@ -345,29 +343,29 @@ static char *test_model_set_flags() const VmafDictionaryEntry *entry = NULL; entry = vmaf_dictionary_get(&model4->feature[0].opts_dict, "adm_enhn_gain_limit", 0); mu_assert("feature[0].opts_dict must have key adm_enhn_gain_limit.\n", - strcmp(entry->key, "adm_enhn_gain_limit") == 0); + strcmp(entry->key, "adm_enhn_gain_limit")==0); mu_assert("feature[0].opts_dict[\"adm_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1") == 0); + strcmp(entry->val, "1")==0); entry = vmaf_dictionary_get(&model4->feature[2].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[2].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit") == 0); + strcmp(entry->key, "vif_enhn_gain_limit")==0); mu_assert("feature[2].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1") == 0); + strcmp(entry->val, "1")==0); entry = vmaf_dictionary_get(&model4->feature[3].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[3].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit") == 0); + strcmp(entry->key, "vif_enhn_gain_limit")==0); mu_assert("feature[3].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1") == 0); + strcmp(entry->val, "1")==0); entry = vmaf_dictionary_get(&model4->feature[4].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[4].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit") == 0); + strcmp(entry->key, "vif_enhn_gain_limit")==0); mu_assert("feature[4].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1") == 0); + strcmp(entry->val, "1")==0); entry = vmaf_dictionary_get(&model4->feature[5].opts_dict, "vif_enhn_gain_limit", 0); mu_assert("feature[5].opts_dict must have key vif_enhn_gain_limit.\n", - strcmp(entry->key, "vif_enhn_gain_limit") == 0); + strcmp(entry->key, "vif_enhn_gain_limit")==0); mu_assert("feature[5].opts_dict[\"vif_enhn_gain_limit\"] must have value 1.\n", - strcmp(entry->val, "1") == 0); + strcmp(entry->val, "1")==0); vmaf_model_destroy(model4); return NULL; From bbb3615569902259f06d95b251fcd00739668cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Tue, 6 Dec 2022 22:35:56 -0600 Subject: [PATCH 14/16] Rewrite test_model_descriptor_next --- libvmaf/test/test_model.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index d2d639dd0..7891729b9 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -374,31 +374,16 @@ static char *test_model_set_flags() /** * This test may fail if VmafBuiltInModel's memory layout has changed * (version MUST be the first defined property in the struct) -*/ + */ char *test_model_descriptor_next() { - VmafModelDescriptor *first = vmaf_model_descriptor_next(NULL); - VmafBuiltInModel *builtin = first; - mu_assert("When given null, return first item",first == &built_in_models[0]); - mu_assert("Version field matches on the first VmafBuiltInModel",first->version == builtin->version); - - for(int i=1;i==BUILT_IN_MODEL_CNT;i++){ - VmafBuiltInModel *builtin = &built_in_models[i]; - VmafModelDescriptor *current = builtin; - VmafBuiltInModel *expected = &built_in_models[i+1]; - - VmafModelDescriptor *next = vmaf_model_descriptor_next(current); - - mu_assert("Pointer returned from vmaf_model_descriptor_next is not null",next); - mu_assert("Given the address of a VmafBuiltInModel, returns the address of the next VmafBuiltInModel",next==expected); - mu_assert("Version field should match on both pointers",expected->version == next->version); + VmafModelDescriptor *next = NULL; + while (vmaf_model_descriptor_next(next)) + { + next = vmaf_model_descriptor_next(next); + VmafBuiltInModel *builtin = next; + mu_assert("Version field should match on both builtin and next", next->version == builtin->version); } - - VmafModelDescriptor *last = &built_in_models[BUILT_IN_MODEL_CNT]; - - VmafModelDescriptor *shouldBeNull = vmaf_model_descriptor_next(last); - - mu_assert("When given the last item in the array, returns null",!shouldBeNull); return NULL; } From 95ebb3c4344c7a68853663bad45003e17aae442b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= <32885853+ThatNerdUKnow@users.noreply.github.com> Date: Wed, 7 Dec 2022 09:23:08 -0600 Subject: [PATCH 15/16] Update test_model.c It has come to my attention that assignments are also expressions in c --- libvmaf/test/test_model.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index 7891729b9..22b48524b 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -378,9 +378,8 @@ static char *test_model_set_flags() char *test_model_descriptor_next() { VmafModelDescriptor *next = NULL; - while (vmaf_model_descriptor_next(next)) + while (next = vmaf_model_descriptor_next(next)) { - next = vmaf_model_descriptor_next(next); VmafBuiltInModel *builtin = next; mu_assert("Version field should match on both builtin and next", next->version == builtin->version); } From ba86f6068355a9e0e62d98c8c8ae6877b27233b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brandon=20Pi=C3=B1a?= Date: Tue, 13 Dec 2022 19:57:39 -0600 Subject: [PATCH 16/16] Assert that VmafModelDescriptor can be used to load a model --- libvmaf/test/test_model.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libvmaf/test/test_model.c b/libvmaf/test/test_model.c index 7891729b9..562d4e3f9 100644 --- a/libvmaf/test/test_model.c +++ b/libvmaf/test/test_model.c @@ -378,11 +378,19 @@ static char *test_model_set_flags() char *test_model_descriptor_next() { VmafModelDescriptor *next = NULL; + VmafModelConfig config = {.name = NULL, .flags = VMAF_MODEL_FLAGS_DEFAULT}; while (vmaf_model_descriptor_next(next)) { next = vmaf_model_descriptor_next(next); VmafBuiltInModel *builtin = next; mu_assert("Version field should match on both builtin and next", next->version == builtin->version); + VmafModel *model; + printf(next->version); + printf("\n"); + int err = vmaf_model_load(&model, &config, next->version); + + mu_assert("Model load should not return an error",err==0); + vmaf_model_destroy(model); } return NULL; }