From 7d00f6eb00663a02a5e1609466cd57f125d28014 Mon Sep 17 00:00:00 2001 From: Yigithan Yigit Date: Sun, 30 Jun 2024 02:20:58 +0300 Subject: [PATCH] Add Feature propagation to metadata --- libvmaf/include/libvmaf/libvmaf.h | 45 ++++++++++ libvmaf/src/feature/feature_collector.c | 112 ++++++++++++++++++++++++ libvmaf/src/feature/feature_collector.h | 14 +++ libvmaf/src/libvmaf.c | 14 ++- libvmaf/src/meson.build | 1 + libvmaf/src/metadata_handler.c | 79 +++++++++++++++++ libvmaf/src/metadata_handler.h | 42 +++++++++ libvmaf/src/predict.c | 13 +-- libvmaf/src/predict.h | 1 + libvmaf/test/meson.build | 17 ++-- libvmaf/test/test_feature_collector.c | 88 +++++++++++++++++++ libvmaf/test/test_predict.c | 101 ++++++++++++++++++++- libvmaf/test/test_propagate_metadata.c | 86 ++++++++++++++++++ 13 files changed, 601 insertions(+), 12 deletions(-) create mode 100644 libvmaf/src/metadata_handler.c create mode 100644 libvmaf/src/metadata_handler.h create mode 100644 libvmaf/test/test_propagate_metadata.c diff --git a/libvmaf/include/libvmaf/libvmaf.h b/libvmaf/include/libvmaf/libvmaf.h index 71d39e656..11d0d1190 100644 --- a/libvmaf/include/libvmaf/libvmaf.h +++ b/libvmaf/include/libvmaf/libvmaf.h @@ -253,6 +253,51 @@ int vmaf_score_at_index_model_collection(VmafContext *vmaf, int vmaf_feature_score_at_index(VmafContext *vmaf, const char *feature_name, double *score, unsigned index); +/** + * Metadata structure. + * + * @param feature_name Name of the feature to fetch. + * + * @param picture_index Picture index. + * + * @param score Score. + * + * @note This structure is used to pass metadata to a callback function. + */ +typedef struct VmafMetadata { + char *feature_name; + unsigned picture_index; + double score; +} VmafMetadata; + +/** + * Metadata configuration. + * + * @param feature_name Name of the feature to fetch. + * + * @param callback Callback to receive metadata. + * + * @param data User data to pass to the callback. + */ +typedef struct VmafMetadataConfiguration { + char *feature_name; + void (*callback)(void *data, VmafMetadata *metadata); + void *data; +} VmafMetadataConfiguration; + +/** + * Register a callback to receive VMAF metadata. + * + * @param vmaf The VMAF context allocated with `vmaf_init()`. + * + * @param cfg Metadata configuration. + * + * + * @return 0 on success, or < 0 (a negative errno code) on error. + */ + +int vmaf_register_metadata_handler(VmafContext *vmaf, VmafMetadataConfiguration cfg); + /** * Pooled VMAF score for a specific interval. * diff --git a/libvmaf/src/feature/feature_collector.c b/libvmaf/src/feature/feature_collector.c index 0e90b7e70..2eb2ec643 100644 --- a/libvmaf/src/feature/feature_collector.c +++ b/libvmaf/src/feature/feature_collector.c @@ -24,9 +24,12 @@ #include #include "dict.h" +#include "metadata_handler.h" #include "feature_collector.h" #include "feature_name.h" +#include "libvmaf/libvmaf.h" #include "log.h" +#include "predict.h" static int aggregate_vector_init(AggregateVector *aggregate_vector) { @@ -215,8 +218,12 @@ int vmaf_feature_collector_init(VmafFeatureCollector **const feature_collector) if (err) goto free_feature_vector; err = pthread_mutex_init(&(fc->lock), NULL); if (err) goto free_aggregate_vector; + err = vmaf_metadata_init(&(fc->metadata)); + if (err) goto free_mutex; return 0; +free_mutex: + pthread_mutex_destroy(&(fc->lock)); free_aggregate_vector: aggregate_vector_destroy(&(fc->aggregate_vector)); free_feature_vector: @@ -227,6 +234,62 @@ int vmaf_feature_collector_init(VmafFeatureCollector **const feature_collector) return -ENOMEM; } +int vmaf_feature_collector_mount_model(VmafFeatureCollector *feature_collector, + VmafModel *model) +{ + if (!feature_collector) return -EINVAL; + if (!model) return -EINVAL; + + VmafPredictModel *m = malloc(sizeof(VmafPredictModel)); + if (!m) return -ENOMEM; + m->model = model; + m->next = NULL; + + VmafPredictModel **head = &feature_collector->models; + while (*head && (*head)->next != NULL) + *head = (*head)->next; + + if (!(*head)) + *head = m; + else + (*head)->next = m; + + return 0; +} + +int vmaf_feature_collector_unmount_model(VmafFeatureCollector *feature_collector, + VmafModel *model) +{ + if (!feature_collector) return -EINVAL; + if (!model) return -EINVAL; + + VmafPredictModel **head = &feature_collector->models; + while (*head && (*head)->model != model) + head = &(*head)->next; + + if (!(*head)) return -EINVAL; + + VmafPredictModel *m = *head; + *head = m->next; + free(m); + + return 0; +} + +int vmaf_feature_collector_register_metadata(VmafFeatureCollector *feature_collector, + VmafMetadataConfiguration metadata_cfg) +{ + if (!feature_collector) return -EINVAL; + if (!metadata_cfg.feature_name) return -EINVAL; + if (!metadata_cfg.callback) return -EINVAL; + + VmafCallbackList *metadata = feature_collector->metadata; + int err = vmaf_metadata_append(metadata, metadata_cfg); + if (err) return err; + + return 0; +} + static FeatureVector *find_feature_vector(VmafFeatureCollector *fc, const char *feature_name) { @@ -280,6 +343,51 @@ int vmaf_feature_collector_append(VmafFeatureCollector *feature_collector, } err = feature_vector_append(feature_vector, picture_index, score); + if (err) goto unlock; + + int res = 0; + + VmafCallbackItem *metadata_iter = feature_collector->metadata ? + feature_collector->metadata->head : NULL; + while (metadata_iter) { + // Check current feature name is the same as the metadata feature name + if (!strcmp(metadata_iter->metadata_cfg.feature_name, feature_name)) { + + // Call the callback function with the metadata feature name + VmafMetadata data = { + .feature_name = metadata_iter->metadata_cfg.feature_name, + .picture_index = picture_index, + .score = score, + }; + metadata_iter->metadata_cfg.callback(metadata_iter->metadata_cfg.data, &data); + // Move to the next metadata + goto next_metadata; + } + + VmafPredictModel *model_iter = feature_collector->models; + + // If metadata feature name is not the same as the current feature feature_name + // Check if metadata feature name is the predicted feature + while (model_iter) { + VmafModel *model = model_iter->model; + + pthread_mutex_unlock(&(feature_collector->lock)); + res = vmaf_feature_collector_get_score(feature_collector, + model->name, &score, picture_index); + pthread_mutex_lock(&(feature_collector->lock)); + + if (res) { + pthread_mutex_unlock(&(feature_collector->lock)); + res |= vmaf_predict_score_at_index(model, feature_collector, + picture_index, &score, true, true, 0); + pthread_mutex_lock(&(feature_collector->lock)); + } + model_iter = model_iter->next; + } + + next_metadata: + metadata_iter = metadata_iter->next; + } unlock: feature_collector->timer.end = clock(); @@ -338,6 +446,10 @@ void vmaf_feature_collector_destroy(VmafFeatureCollector *feature_collector) aggregate_vector_destroy(&(feature_collector->aggregate_vector)); for (unsigned i = 0; i < feature_collector->cnt; i++) feature_vector_destroy(feature_collector->feature_vector[i]); + while (feature_collector->models) + vmaf_feature_collector_unmount_model(feature_collector, + feature_collector->models->model); + vmaf_metadata_destroy(feature_collector->metadata); free(feature_collector->feature_vector); pthread_mutex_unlock(&(feature_collector->lock)); pthread_mutex_destroy(&(feature_collector->lock)); diff --git a/libvmaf/src/feature/feature_collector.h b/libvmaf/src/feature/feature_collector.h index 1de99304d..83745bf8c 100644 --- a/libvmaf/src/feature/feature_collector.h +++ b/libvmaf/src/feature/feature_collector.h @@ -24,6 +24,8 @@ #include #include "dict.h" +#include "model.h" +#include "metadata_handler.h" typedef struct { char *name; @@ -42,9 +44,16 @@ typedef struct { unsigned cnt, capacity; } AggregateVector; +typedef struct VmafPredictModel { + VmafModel *model; + struct VmafPredictModel *next; +} VmafPredictModel; + typedef struct VmafFeatureCollector { FeatureVector **feature_vector; AggregateVector aggregate_vector; + VmafCallbackList *metadata; + VmafPredictModel *models; unsigned cnt, capacity; struct { clock_t begin, end; } timer; pthread_mutex_t lock; @@ -52,10 +61,15 @@ typedef struct VmafFeatureCollector { int vmaf_feature_collector_init(VmafFeatureCollector **const feature_collector); +int vmaf_feature_collector_mount_model(VmafFeatureCollector *feature_collector, VmafModel *model); + int vmaf_feature_collector_append(VmafFeatureCollector *feature_collector, const char *feature_name, double score, unsigned index); +int vmaf_feature_collector_register_metadata(VmafFeatureCollector *feature_collector, + VmafMetadataConfiguration metadata_cfg); + int vmaf_feature_collector_append_with_dict(VmafFeatureCollector *fc, VmafDictionary *dict, const char *feature_name, double score, unsigned index); diff --git a/libvmaf/src/libvmaf.c b/libvmaf/src/libvmaf.c index fa3fe6787..31340e22c 100644 --- a/libvmaf/src/libvmaf.c +++ b/libvmaf/src/libvmaf.c @@ -32,6 +32,7 @@ #include "cpu.h" #include "feature/feature_extractor.h" #include "feature/feature_collector.h" +#include "metadata_handler.h" #include "fex_ctx_vector.h" #include "log.h" #include "model.h" @@ -362,6 +363,10 @@ int vmaf_use_features_from_model(VmafContext *vmaf, VmafModel *model) return err; } } + + err = vmaf_feature_collector_mount_model(vmaf->feature_collector, model); + if (err) return err; + return 0; } @@ -739,6 +744,13 @@ int vmaf_read_pictures(VmafContext *vmaf, VmafPicture *ref, VmafPicture *dist, return err; } +int vmaf_register_metadata_handler(VmafContext *vmaf, VmafMetadataConfiguration cfg) +{ + if (!vmaf) return -EINVAL; + + return vmaf_feature_collector_register_metadata(vmaf->feature_collector, cfg); +} + int vmaf_feature_score_at_index(VmafContext *vmaf, const char *feature_name, double *score, unsigned index) { @@ -763,7 +775,7 @@ int vmaf_score_at_index(VmafContext *vmaf, VmafModel *model, double *score, score, index); if (err) { err = vmaf_predict_score_at_index(model, vmaf->feature_collector, index, - score, true, 0); + score, true, false, 0); } return err; diff --git a/libvmaf/src/meson.build b/libvmaf/src/meson.build index 4e4f211de..5602b6997 100644 --- a/libvmaf/src/meson.build +++ b/libvmaf/src/meson.build @@ -462,6 +462,7 @@ libvmaf_sources = [ src_dir + 'pdjson.c', src_dir + 'log.c', src_dir + 'framesync.c', + src_dir + 'metadata_handler.c', ] if is_cuda_enabled diff --git a/libvmaf/src/metadata_handler.c b/libvmaf/src/metadata_handler.c new file mode 100644 index 000000000..99f69c212 --- /dev/null +++ b/libvmaf/src/metadata_handler.c @@ -0,0 +1,79 @@ +/** + * + * Copyright 2016-2020 Netflix, Inc. + * + * Licensed under the BSD+Patent License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSDplusPatent + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include "metadata_handler.h" + +int vmaf_metadata_init(VmafCallbackList **const metadata) +{ + if (!metadata) return -EINVAL; + + VmafCallbackList *const metadata_s = *metadata = + malloc(sizeof(*metadata_s)); + if (!metadata_s) goto fail; + + metadata_s->head = NULL; + + return 0; + +fail: + return -ENOMEM; +} + +int vmaf_metadata_append(VmafCallbackList *metadata, const VmafMetadataConfiguration metadata_cfg) +{ + if (!metadata) return -EINVAL; + + VmafCallbackItem *node = malloc(sizeof(*node)); + if (!node) goto fail; + memset(node, 0, sizeof(*node)); + + node->metadata_cfg = metadata_cfg; + + if (!metadata->head) { + metadata->head = node; + } else { + VmafCallbackItem *iter = metadata->head; + while (iter->next) iter = iter->next; + iter->next = node; + } + + return 0; + +fail: + return -ENOMEM; +} + +int vmaf_metadata_destroy(VmafCallbackList *metadata) +{ + if (!metadata) return -EINVAL; + + VmafCallbackItem *iter = metadata->head; + while (iter) { + VmafCallbackItem *next = iter->next; + free(iter); + iter = next; + } + + free(metadata); + + return 0; +} diff --git a/libvmaf/src/metadata_handler.h b/libvmaf/src/metadata_handler.h new file mode 100644 index 000000000..f5f781fa4 --- /dev/null +++ b/libvmaf/src/metadata_handler.h @@ -0,0 +1,42 @@ +/** + * + * Copyright 2016-2020 Netflix, Inc. + * + * Licensed under the BSD+Patent License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSDplusPatent + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __VMAF_SRC_PROPAGATE_METADATA_H__ +#define __VMAF_SRC_PROPAGATE_METADATA_H__ + +#include "libvmaf/libvmaf.h" + +typedef struct VmafCallbackItem { + VmafMetadataConfiguration metadata_cfg; + void (*callback)(void *, VmafMetadata *); + void *data; + struct VmafCallbackItem *next; +} VmafCallbackItem; + +typedef struct VmafCallbackList{ + VmafCallbackItem *head; +} VmafCallbackList; + +int vmaf_metadata_init(VmafCallbackList **const metadata); + +int vmaf_metadata_append(VmafCallbackList *metadata, + const VmafMetadataConfiguration metadata_cfg); + +int vmaf_metadata_destroy(VmafCallbackList *metadata); + +#endif // !__VMAF_PROPAGATE_METADATA_H__ diff --git a/libvmaf/src/predict.c b/libvmaf/src/predict.c index e20097aa2..9926de15b 100644 --- a/libvmaf/src/predict.c +++ b/libvmaf/src/predict.c @@ -228,6 +228,7 @@ int vmaf_predict_score_at_index(VmafModel *model, VmafFeatureCollector *feature_collector, unsigned index, double *vmaf_score, bool write_prediction, + bool propagate_metadata, enum VmafModelFlags flags) { if (!model) return -EINVAL; @@ -287,9 +288,11 @@ int vmaf_predict_score_at_index(VmafModel *model, index); if (err) { - vmaf_log(VMAF_LOG_LEVEL_ERROR, - "vmaf_predict_score_at_index(): no feature '%s' " - "at index %d\n", feature_name, index); + if (!propagate_metadata) { + vmaf_log(VMAF_LOG_LEVEL_ERROR, + "vmaf_predict_score_at_index(): no feature '%s' " + "at index %d\n", feature_name, index); + } free(feature_name); goto free_node; } @@ -366,7 +369,7 @@ static int vmaf_bootstrap_predict_score_at_index( err = vmaf_predict_score_at_index(model_collection->model[i], feature_collector, index, &scores[i], false, - flags); + false, flags); if (err) return err; // do not override the model's transform/clip behavior @@ -374,7 +377,7 @@ static int vmaf_bootstrap_predict_score_at_index( double score; err = vmaf_predict_score_at_index(model_collection->model[i], feature_collector, index, - &score, true, 0); + &score, true, false, 0); if (err) return err; } diff --git a/libvmaf/src/predict.h b/libvmaf/src/predict.h index e4183e569..30851b6e8 100644 --- a/libvmaf/src/predict.h +++ b/libvmaf/src/predict.h @@ -26,6 +26,7 @@ int vmaf_predict_score_at_index(VmafModel *model, VmafFeatureCollector *feature_collector, unsigned index, double *vmaf_score, bool write_prediction, + bool propagate_metadata, enum VmafModelFlags flags); int vmaf_predict_score_at_index_model_collection( diff --git a/libvmaf/test/meson.build b/libvmaf/test/meson.build index 725fdfea8..e8d943e98 100644 --- a/libvmaf/test/meson.build +++ b/libvmaf/test/meson.build @@ -17,8 +17,13 @@ test_picture = executable('test_picture', dependencies:[stdatomic_dependency, thread_lib, cuda_dependency], ) +test_propagate_metadata = executable('test_propagate_metadata', + ['test.c', 'test_propagate_metadata.c', '../src/metadata_handler.c'], + include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], +) + test_feature_collector = executable('test_feature_collector', - ['test.c', 'test_feature_collector.c', '../src/log.c'], + ['test.c', 'test_feature_collector.c', '../src/log.c', '../src/predict.c', '../src/svm.cpp', '../src/metadata_handler.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/feature/'), include_directories('../src')], link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, dependencies: cuda_dependency @@ -45,10 +50,10 @@ test_model = executable('test_model', ) test_predict = executable('test_predict', - ['test.c', 'test_predict.c', '../src/dict.c', + ['test.c', 'test_predict.c', '../src/dict.c', '../src/metadata_handler.c', '../src/feature/feature_collector.c', '../src/feature/alias.c', '../src/model.c', '../src/svm.cpp', '../src/log.c', - '../src/read_json_model.c', '../src/pdjson.c', json_model_c_sources, '../src/feature/feature_name.c', '../src/feature/feature_extractor.c'], - include_directories : [libvmaf_inc, test_inc, include_directories('../src')], + '../src/read_json_model.c', '../src/pdjson.c', json_model_c_sources, '../src/feature/feature_name.c', '../src/feature/feature_extractor.c',], + include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, c_args : vmaf_cflags_common, cpp_args : vmaf_cflags_common, @@ -57,7 +62,8 @@ test_predict = executable('test_predict', test_feature_extractor = executable('test_feature_extractor', ['test.c', 'test_feature_extractor.c', '../src/mem.c', '../src/picture.c', '../src/ref.c', - '../src/dict.c', '../src/opt.c', '../src/log.c'], + '../src/dict.c', '../src/opt.c', '../src/log.c', '../src/predict.c', '../src/svm.cpp', + '../src/metadata_handler.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], dependencies : [math_lib, stdatomic_dependency, thread_lib, cuda_dependency], objects : [ @@ -168,3 +174,4 @@ test('test_luminance_tools', test_luminance_tools) test('test_cli_parse', test_cli_parse) test('test_psnr', test_psnr) test('test_framesync', test_framesync) +test('test_propagate_metadata', test_propagate_metadata) diff --git a/libvmaf/test/test_feature_collector.c b/libvmaf/test/test_feature_collector.c index 4815947b6..647d07703 100644 --- a/libvmaf/test/test_feature_collector.c +++ b/libvmaf/test/test_feature_collector.c @@ -18,6 +18,91 @@ #include "test.h" #include "feature_collector.c" +#include "libvmaf.c" +#include + +static char *test_model_mount_with_use_features() +{ + int err = 0; + + VmafConfiguration vmaf_cfg = { 0 }; + + VmafContext *vmaf; + vmaf_init(&vmaf, vmaf_cfg); + mu_assert("problem during vmaf_init", vmaf); + + VmafModelConfig model_cfg = { 0 }; + VmafModel *model; + vmaf_model_load(&model, &model_cfg, "vmaf_v0.6.1"); + mu_assert("problem during vmaf_model_load", model); + + err = vmaf_use_features_from_model(vmaf, model); + mu_assert("problem during vmaf_use_features_from_model", !err); + + mu_assert("problem during vmaf_model_mount", + vmaf->feature_collector->models); + + vmaf_model_destroy(model); + err = vmaf_close(vmaf); + mu_assert("problem During vmaf_close", !err); + + return NULL; +} + +static char* test_model_mount() +{ + int err = 0; + + VmafFeatureCollector *feature_collector; + err = vmaf_feature_collector_init(&feature_collector); + mu_assert("problem during vmaf_feature_collector_init", !err); + + VmafModelConfig model_cfg = { 0 }; + VmafModel *model; + vmaf_model_load(&model, &model_cfg, "vmaf_v0.6.1"); + mu_assert("problem during vmaf_model_load", model); + + + err = vmaf_feature_collector_mount_model(feature_collector, model); + mu_assert("problem during vmaf_model_mount", + feature_collector->models); + + err = vmaf_feature_collector_mount_model(feature_collector, model); + mu_assert("problem during vmaf_model_mount", + feature_collector->models->next); + + vmaf_model_destroy(model); + vmaf_feature_collector_destroy(feature_collector); + + return NULL; +} + +static char* test_model_unmount() +{ + int err = 0; + + VmafFeatureCollector *feature_collector; + err = vmaf_feature_collector_init(&feature_collector); + mu_assert("problem during vmaf_feature_collector_init", !err); + + VmafModelConfig model_cfg = { 0 }; + VmafModel *model; + vmaf_model_load(&model, &model_cfg, "vmaf_v0.6.1"); + mu_assert("problem during vmaf_model_load", model); + + err = vmaf_feature_collector_mount_model(feature_collector, model); + mu_assert("problem during vmaf_model_mount", + feature_collector->models); + + err = vmaf_feature_collector_unmount_model(feature_collector, model); + mu_assert("problem during vmaf_model_unmount", + !feature_collector->models); + + vmaf_model_destroy(model); + vmaf_feature_collector_destroy(feature_collector); + + return NULL; +} static char *test_aggregate_vector_init_append_and_destroy() { @@ -161,5 +246,8 @@ char *run_tests() mu_run_test(test_feature_vector_init_append_and_destroy); mu_run_test(test_feature_collector_init_append_get_and_destroy); mu_run_test(test_aggregate_vector_init_append_and_destroy); + mu_run_test(test_model_mount); + mu_run_test(test_model_unmount); + mu_run_test(test_model_mount_with_use_features); return NULL; } diff --git a/libvmaf/test/test_predict.c b/libvmaf/test/test_predict.c index 63c725114..3fe970047 100644 --- a/libvmaf/test/test_predict.c +++ b/libvmaf/test/test_predict.c @@ -18,6 +18,8 @@ #include +#include "feature/feature_collector.h" +#include "metadata_handler.h" #include "test.h" #include "predict.h" #include "predict.c" @@ -25,6 +27,12 @@ #include #include +typedef struct { + VmafDictionary **metadata; + int flags; +} MetaStruct; + + static char *test_predict_score_at_index() { int err; @@ -49,7 +57,7 @@ static char *test_predict_score_at_index() double vmaf_score = 0.; err = vmaf_predict_score_at_index(model, feature_collector, 0, &vmaf_score, - true, 0); + true, false, 0); mu_assert("problem during vmaf_predict_score_at_index", !err); vmaf_model_destroy(model); @@ -57,6 +65,96 @@ static char *test_predict_score_at_index() return NULL; } + +void set_meta(void *data, VmafMetadata *metadata) +{ + if (!data) return; + MetaStruct *meta = data; + char key[128], value[128]; + snprintf(key, sizeof(value), "%s_%d", metadata->feature_name, + metadata->picture_index); + snprintf(value, sizeof(value), "%f", metadata->score); + vmaf_dictionary_set(meta->metadata, key, value, meta->flags); +} + +static char* test_propagate_metadata() +{ + int err; + + VmafDictionary *dict = NULL; + MetaStruct meta_data = { + .metadata = &dict, + .flags = 0, + }; + + VmafMetadataConfiguration m = { + .feature_name = "vmaf", + .callback = set_meta, + .data = &meta_data, + }; + + VmafFeatureCollector *feature_collector; + err = vmaf_feature_collector_init(&feature_collector); + mu_assert("problem during vmaf_feature_collector_init", !err); + + err = vmaf_feature_collector_register_metadata(feature_collector, m); + mu_assert("problem during vmaf_feature_collector_register_metadata_0", !err); + + VmafModel *model; + VmafModelConfig cfg = { + .name = "vmaf", + .flags = VMAF_MODEL_FLAGS_DEFAULT, + }; + err = vmaf_model_load(&model, &cfg, "vmaf_v0.6.1"); + mu_assert("problem during vmaf_model_load", !err); + err = vmaf_feature_collector_mount_model(feature_collector, model); + mu_assert("problem during vmaf_mount_model", !err); + + for (unsigned i = 0; i < model->n_features; i++) { + err = vmaf_feature_collector_append(feature_collector, + model->feature[i].name, 60., 0); + mu_assert("problem during vmaf_feature_collector_append", !err); + } + + VmafDictionaryEntry *e = vmaf_dictionary_get(&dict, "vmaf_0", 0); + mu_assert("error on propagaton metadata: propagated key not found!", + e); + mu_assert("error on propagaton metadata: propagated key wrong!", + !strcmp(e->key, "vmaf_0")); + mu_assert("error on propagaton metadata: propagated data wrong!", + !strcmp(e->val, "100.000000")); + + vmaf_feature_collector_destroy(feature_collector); + + m.data = NULL; + err = vmaf_feature_collector_init(&feature_collector); + mu_assert("problem during vmaf_feature_collector_init", !err); + + err = vmaf_feature_collector_register_metadata(feature_collector, m); + mu_assert("problem during vmaf_feature_collector_register_metadata_1", !err); + + for (unsigned i = 0; i < model->n_features; i++) { + err = vmaf_feature_collector_append(feature_collector, + model->feature[i].name, 60., 0); + mu_assert("problem during vmaf_feature_collector_append", !err); + } + + vmaf_feature_collector_destroy(feature_collector); + + m.callback = NULL; + err = vmaf_feature_collector_init(&feature_collector); + mu_assert("problem during vmaf_feature_collector_init", !err); + + err = vmaf_feature_collector_register_metadata(feature_collector, m); + mu_assert("problem during vmaf_feature_collector_register_metadata_2", err); + + vmaf_feature_collector_destroy(feature_collector); + + vmaf_model_destroy(model); + return NULL; + +} + static char *test_find_linear_function_parameters() { int err; @@ -173,5 +271,6 @@ char *run_tests() mu_run_test(test_predict_score_at_index); mu_run_test(test_find_linear_function_parameters); mu_run_test(test_piecewise_linear_mapping); + mu_run_test(test_propagate_metadata); return NULL; } diff --git a/libvmaf/test/test_propagate_metadata.c b/libvmaf/test/test_propagate_metadata.c new file mode 100644 index 000000000..ee4faced3 --- /dev/null +++ b/libvmaf/test/test_propagate_metadata.c @@ -0,0 +1,86 @@ +/** + * + * Copyright 2016-2020 Netflix, Inc. + * + * Licensed under the BSD+Patent License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSDplusPatent + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "metadata_handler.h" +#include "test.h" + +void set_meta() {} + +static char *test_propagate_metadata_init() +{ + VmafCallbackList *propagate_metadata; + int err = vmaf_metadata_init(&propagate_metadata); + mu_assert("problem during vmaf_propagate_metadata_init", !err); + mu_assert("problem during vmaf_propagate_metadata_init, metadata is NULL", + propagate_metadata); + + vmaf_metadata_destroy(propagate_metadata); + mu_assert("problem during vmaf_propagate_metadata_destroy", !err); + + return NULL; +} + +static char *test_propagate_metadata_destroy() +{ + VmafCallbackList *propagate_metadata; + int err = vmaf_metadata_init(&propagate_metadata); + mu_assert("problem during vmaf_propagate_metadata_init", !err); + mu_assert("problem during vmaf_propagate_metadata_init, metadata is NULL", + propagate_metadata); + + err = vmaf_metadata_destroy(propagate_metadata); + mu_assert("problem during vmaf_propagate_metadata_destroy", !err); + + return NULL; +} + +static char *test_propagate_metadata_append() +{ + VmafCallbackList *propagate_metadata; + int err = vmaf_metadata_init(&propagate_metadata); + mu_assert("problem during vmaf_propagate_metadata_init", !err); + + VmafMetadataConfiguration metadata_config; + metadata_config.callback = set_meta; + metadata_config.data = NULL; + + err = vmaf_metadata_append(propagate_metadata, metadata_config); + mu_assert("problem during vmaf_propagate_metadata_append", !err); + mu_assert("problem during vmaf_propagate_metadata_append, metadata->head is NULL", + propagate_metadata->head); + mu_assert("problem during vmaf_propagate_metadata_append, metadata->head->next is not NULL", + !propagate_metadata->head->next); + + err = vmaf_metadata_append(propagate_metadata, metadata_config); + mu_assert("problem during vmaf_propagate_metadata_append", !err); + mu_assert("problem during vmaf_propagate_metadata_append, metadata->head->next is NULL", + propagate_metadata->head->next); + + err = vmaf_metadata_destroy(propagate_metadata); + mu_assert("problem during vmaf_propagate_metadata_destroy", !err); + + return NULL; +} + +char *run_tests() +{ + mu_run_test(test_propagate_metadata_init); + mu_run_test(test_propagate_metadata_destroy); + mu_run_test(test_propagate_metadata_append); + return NULL; +}