Skip to content

Commit d95b69e

Browse files
yigithanyigitkylophone
authored andcommitted
Add Feature propagation to metadata
1 parent 014ea9d commit d95b69e

File tree

13 files changed

+601
-12
lines changed

13 files changed

+601
-12
lines changed

libvmaf/include/libvmaf/libvmaf.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,51 @@ int vmaf_score_at_index_model_collection(VmafContext *vmaf,
253253
int vmaf_feature_score_at_index(VmafContext *vmaf, const char *feature_name,
254254
double *score, unsigned index);
255255

256+
/**
257+
* Metadata structure.
258+
*
259+
* @param feature_name Name of the feature to fetch.
260+
*
261+
* @param picture_index Picture index.
262+
*
263+
* @param score Score.
264+
*
265+
* @note This structure is used to pass metadata to a callback function.
266+
*/
267+
typedef struct VmafMetadata {
268+
char *feature_name;
269+
unsigned picture_index;
270+
double score;
271+
} VmafMetadata;
272+
273+
/**
274+
* Metadata configuration.
275+
*
276+
* @param feature_name Name of the feature to fetch.
277+
*
278+
* @param callback Callback to receive metadata.
279+
*
280+
* @param data User data to pass to the callback.
281+
*/
282+
typedef struct VmafMetadataConfiguration {
283+
char *feature_name;
284+
void (*callback)(void *data, VmafMetadata *metadata);
285+
void *data;
286+
} VmafMetadataConfiguration;
287+
288+
/**
289+
* Register a callback to receive VMAF metadata.
290+
*
291+
* @param vmaf The VMAF context allocated with `vmaf_init()`.
292+
*
293+
* @param cfg Metadata configuration.
294+
*
295+
*
296+
* @return 0 on success, or < 0 (a negative errno code) on error.
297+
*/
298+
299+
int vmaf_register_metadata_handler(VmafContext *vmaf, VmafMetadataConfiguration cfg);
300+
256301
/**
257302
* Pooled VMAF score for a specific interval.
258303
*

libvmaf/src/feature/feature_collector.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424
#include <string.h>
2525

2626
#include "dict.h"
27+
#include "metadata_handler.h"
2728
#include "feature_collector.h"
2829
#include "feature_name.h"
30+
#include "libvmaf/libvmaf.h"
2931
#include "log.h"
32+
#include "predict.h"
3033

3134
static int aggregate_vector_init(AggregateVector *aggregate_vector)
3235
{
@@ -215,8 +218,12 @@ int vmaf_feature_collector_init(VmafFeatureCollector **const feature_collector)
215218
if (err) goto free_feature_vector;
216219
err = pthread_mutex_init(&(fc->lock), NULL);
217220
if (err) goto free_aggregate_vector;
221+
err = vmaf_metadata_init(&(fc->metadata));
222+
if (err) goto free_mutex;
218223
return 0;
219224

225+
free_mutex:
226+
pthread_mutex_destroy(&(fc->lock));
220227
free_aggregate_vector:
221228
aggregate_vector_destroy(&(fc->aggregate_vector));
222229
free_feature_vector:
@@ -227,6 +234,62 @@ int vmaf_feature_collector_init(VmafFeatureCollector **const feature_collector)
227234
return -ENOMEM;
228235
}
229236

237+
int vmaf_feature_collector_mount_model(VmafFeatureCollector *feature_collector,
238+
VmafModel *model)
239+
{
240+
if (!feature_collector) return -EINVAL;
241+
if (!model) return -EINVAL;
242+
243+
VmafPredictModel *m = malloc(sizeof(VmafPredictModel));
244+
if (!m) return -ENOMEM;
245+
m->model = model;
246+
m->next = NULL;
247+
248+
VmafPredictModel **head = &feature_collector->models;
249+
while (*head && (*head)->next != NULL)
250+
*head = (*head)->next;
251+
252+
if (!(*head))
253+
*head = m;
254+
else
255+
(*head)->next = m;
256+
257+
return 0;
258+
}
259+
260+
int vmaf_feature_collector_unmount_model(VmafFeatureCollector *feature_collector,
261+
VmafModel *model)
262+
{
263+
if (!feature_collector) return -EINVAL;
264+
if (!model) return -EINVAL;
265+
266+
VmafPredictModel **head = &feature_collector->models;
267+
while (*head && (*head)->model != model)
268+
head = &(*head)->next;
269+
270+
if (!(*head)) return -EINVAL;
271+
272+
VmafPredictModel *m = *head;
273+
*head = m->next;
274+
free(m);
275+
276+
return 0;
277+
}
278+
279+
int vmaf_feature_collector_register_metadata(VmafFeatureCollector *feature_collector,
280+
VmafMetadataConfiguration metadata_cfg)
281+
{
282+
if (!feature_collector) return -EINVAL;
283+
if (!metadata_cfg.feature_name) return -EINVAL;
284+
if (!metadata_cfg.callback) return -EINVAL;
285+
286+
VmafCallbackList *metadata = feature_collector->metadata;
287+
int err = vmaf_metadata_append(metadata, metadata_cfg);
288+
if (err) return err;
289+
290+
return 0;
291+
}
292+
230293
static FeatureVector *find_feature_vector(VmafFeatureCollector *fc,
231294
const char *feature_name)
232295
{
@@ -280,6 +343,51 @@ int vmaf_feature_collector_append(VmafFeatureCollector *feature_collector,
280343
}
281344

282345
err = feature_vector_append(feature_vector, picture_index, score);
346+
if (err) goto unlock;
347+
348+
int res = 0;
349+
350+
VmafCallbackItem *metadata_iter = feature_collector->metadata ?
351+
feature_collector->metadata->head : NULL;
352+
while (metadata_iter) {
353+
// Check current feature name is the same as the metadata feature name
354+
if (!strcmp(metadata_iter->metadata_cfg.feature_name, feature_name)) {
355+
356+
// Call the callback function with the metadata feature name
357+
VmafMetadata data = {
358+
.feature_name = metadata_iter->metadata_cfg.feature_name,
359+
.picture_index = picture_index,
360+
.score = score,
361+
};
362+
metadata_iter->metadata_cfg.callback(metadata_iter->metadata_cfg.data, &data);
363+
// Move to the next metadata
364+
goto next_metadata;
365+
}
366+
367+
VmafPredictModel *model_iter = feature_collector->models;
368+
369+
// If metadata feature name is not the same as the current feature feature_name
370+
// Check if metadata feature name is the predicted feature
371+
while (model_iter) {
372+
VmafModel *model = model_iter->model;
373+
374+
pthread_mutex_unlock(&(feature_collector->lock));
375+
res = vmaf_feature_collector_get_score(feature_collector,
376+
model->name, &score, picture_index);
377+
pthread_mutex_lock(&(feature_collector->lock));
378+
379+
if (res) {
380+
pthread_mutex_unlock(&(feature_collector->lock));
381+
res |= vmaf_predict_score_at_index(model, feature_collector,
382+
picture_index, &score, true, true, 0);
383+
pthread_mutex_lock(&(feature_collector->lock));
384+
}
385+
model_iter = model_iter->next;
386+
}
387+
388+
next_metadata:
389+
metadata_iter = metadata_iter->next;
390+
}
283391

284392
unlock:
285393
feature_collector->timer.end = clock();
@@ -338,6 +446,10 @@ void vmaf_feature_collector_destroy(VmafFeatureCollector *feature_collector)
338446
aggregate_vector_destroy(&(feature_collector->aggregate_vector));
339447
for (unsigned i = 0; i < feature_collector->cnt; i++)
340448
feature_vector_destroy(feature_collector->feature_vector[i]);
449+
while (feature_collector->models)
450+
vmaf_feature_collector_unmount_model(feature_collector,
451+
feature_collector->models->model);
452+
vmaf_metadata_destroy(feature_collector->metadata);
341453
free(feature_collector->feature_vector);
342454
pthread_mutex_unlock(&(feature_collector->lock));
343455
pthread_mutex_destroy(&(feature_collector->lock));

libvmaf/src/feature/feature_collector.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <time.h>
2525

2626
#include "dict.h"
27+
#include "model.h"
28+
#include "metadata_handler.h"
2729

2830
typedef struct {
2931
char *name;
@@ -42,20 +44,32 @@ typedef struct {
4244
unsigned cnt, capacity;
4345
} AggregateVector;
4446

47+
typedef struct VmafPredictModel {
48+
VmafModel *model;
49+
struct VmafPredictModel *next;
50+
} VmafPredictModel;
51+
4552
typedef struct VmafFeatureCollector {
4653
FeatureVector **feature_vector;
4754
AggregateVector aggregate_vector;
55+
VmafCallbackList *metadata;
56+
VmafPredictModel *models;
4857
unsigned cnt, capacity;
4958
struct { clock_t begin, end; } timer;
5059
pthread_mutex_t lock;
5160
} VmafFeatureCollector;
5261

5362
int vmaf_feature_collector_init(VmafFeatureCollector **const feature_collector);
5463

64+
int vmaf_feature_collector_mount_model(VmafFeatureCollector *feature_collector, VmafModel *model);
65+
5566
int vmaf_feature_collector_append(VmafFeatureCollector *feature_collector,
5667
const char *feature_name, double score,
5768
unsigned index);
5869

70+
int vmaf_feature_collector_register_metadata(VmafFeatureCollector *feature_collector,
71+
VmafMetadataConfiguration metadata_cfg);
72+
5973
int vmaf_feature_collector_append_with_dict(VmafFeatureCollector *fc,
6074
VmafDictionary *dict, const char *feature_name, double score,
6175
unsigned index);

libvmaf/src/libvmaf.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "cpu.h"
3333
#include "feature/feature_extractor.h"
3434
#include "feature/feature_collector.h"
35+
#include "metadata_handler.h"
3536
#include "fex_ctx_vector.h"
3637
#include "log.h"
3738
#include "model.h"
@@ -362,6 +363,10 @@ int vmaf_use_features_from_model(VmafContext *vmaf, VmafModel *model)
362363
return err;
363364
}
364365
}
366+
367+
err = vmaf_feature_collector_mount_model(vmaf->feature_collector, model);
368+
if (err) return err;
369+
365370
return 0;
366371
}
367372

@@ -739,6 +744,13 @@ int vmaf_read_pictures(VmafContext *vmaf, VmafPicture *ref, VmafPicture *dist,
739744
return err;
740745
}
741746

747+
int vmaf_register_metadata_handler(VmafContext *vmaf, VmafMetadataConfiguration cfg)
748+
{
749+
if (!vmaf) return -EINVAL;
750+
751+
return vmaf_feature_collector_register_metadata(vmaf->feature_collector, cfg);
752+
}
753+
742754
int vmaf_feature_score_at_index(VmafContext *vmaf, const char *feature_name,
743755
double *score, unsigned index)
744756
{
@@ -763,7 +775,7 @@ int vmaf_score_at_index(VmafContext *vmaf, VmafModel *model, double *score,
763775
score, index);
764776
if (err) {
765777
err = vmaf_predict_score_at_index(model, vmaf->feature_collector, index,
766-
score, true, 0);
778+
score, true, false, 0);
767779
}
768780

769781
return err;

libvmaf/src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ libvmaf_sources = [
462462
src_dir + 'pdjson.c',
463463
src_dir + 'log.c',
464464
src_dir + 'framesync.c',
465+
src_dir + 'metadata_handler.c',
465466
]
466467

467468
if is_cuda_enabled

libvmaf/src/metadata_handler.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
*
3+
* Copyright 2016-2020 Netflix, Inc.
4+
*
5+
* Licensed under the BSD+Patent License (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://opensource.org/licenses/BSDplusPatent
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
#include <errno.h>
20+
#include <stdlib.h>
21+
#include <string.h>
22+
23+
#include "metadata_handler.h"
24+
25+
int vmaf_metadata_init(VmafCallbackList **const metadata)
26+
{
27+
if (!metadata) return -EINVAL;
28+
29+
VmafCallbackList *const metadata_s = *metadata =
30+
malloc(sizeof(*metadata_s));
31+
if (!metadata_s) goto fail;
32+
33+
metadata_s->head = NULL;
34+
35+
return 0;
36+
37+
fail:
38+
return -ENOMEM;
39+
}
40+
41+
int vmaf_metadata_append(VmafCallbackList *metadata, const VmafMetadataConfiguration metadata_cfg)
42+
{
43+
if (!metadata) return -EINVAL;
44+
45+
VmafCallbackItem *node = malloc(sizeof(*node));
46+
if (!node) goto fail;
47+
memset(node, 0, sizeof(*node));
48+
49+
node->metadata_cfg = metadata_cfg;
50+
51+
if (!metadata->head) {
52+
metadata->head = node;
53+
} else {
54+
VmafCallbackItem *iter = metadata->head;
55+
while (iter->next) iter = iter->next;
56+
iter->next = node;
57+
}
58+
59+
return 0;
60+
61+
fail:
62+
return -ENOMEM;
63+
}
64+
65+
int vmaf_metadata_destroy(VmafCallbackList *metadata)
66+
{
67+
if (!metadata) return -EINVAL;
68+
69+
VmafCallbackItem *iter = metadata->head;
70+
while (iter) {
71+
VmafCallbackItem *next = iter->next;
72+
free(iter);
73+
iter = next;
74+
}
75+
76+
free(metadata);
77+
78+
return 0;
79+
}

0 commit comments

Comments
 (0)