Skip to content

Commit 8ca784e

Browse files
kylophoneniranjankumar-ittiamMallikarjunKamblenilfm99
committed
libvmaf: introduce framesync api
Co-authored-by: Niranjan Kumar <[email protected]> Co-authored-by: Mallikarjun Kamble <[email protected]> Co-authored-by: Nil Fons Miret <[email protected]>
1 parent b6548d4 commit 8ca784e

9 files changed

+459
-1
lines changed

libvmaf/src/feature/feature_extractor.c

+2
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ int vmaf_fex_ctx_pool_aquire(VmafFeatureExtractorContextPool *pool,
386386
}
387387
err = vmaf_feature_extractor_context_create(&f, entry->fex, d);
388388
if (err) goto unlock;
389+
if (f->fex->flags & VMAF_FEATURE_FRAME_SYNC)
390+
f->fex->framesync = (fex->framesync);
389391
}
390392
if (!entry->ctx_list[i].in_use) {
391393
entry->ctx_list[i].fex_ctx = *fex_ctx = f;

libvmaf/src/feature/feature_extractor.h

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <stdlib.h>
2525

2626
#include "dict.h"
27+
#include "framesync.h"
2728
#include "feature_collector.h"
2829
#include "opt.h"
2930

@@ -36,6 +37,7 @@
3637
enum VmafFeatureExtractorFlags {
3738
VMAF_FEATURE_EXTRACTOR_TEMPORAL = 1 << 0,
3839
VMAF_FEATURE_EXTRACTOR_CUDA = 1 << 1,
40+
VMAF_FEATURE_FRAME_SYNC = 1 << 2,
3941
};
4042

4143
typedef struct VmafFeatureExtractor {
@@ -94,6 +96,8 @@ typedef struct VmafFeatureExtractor {
9496
VmafCudaState *cu_state; ///< VmafCudaState, set by framework
9597
#endif
9698

99+
VmafFrameSyncContext *framesync;
100+
97101
} VmafFeatureExtractor;
98102

99103
VmafFeatureExtractor *vmaf_get_feature_extractor_by_name(const char *name);

libvmaf/src/feature/float_adm.c

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "dict.h"
2424
#include "feature_collector.h"
25+
#include "framesync.h"
2526
#include "feature_extractor.h"
2627
#include "feature_name.h"
2728

libvmaf/src/framesync.c

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/**
2+
*
3+
* Copyright 2016-2023 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 <string.h>
21+
#include <pthread.h>
22+
#include <stdbool.h>
23+
#include <stdlib.h>
24+
#include "framesync.h"
25+
26+
enum {
27+
BUF_FREE = 0,
28+
BUF_ACQUIRED,
29+
BUF_FILLED,
30+
BUF_RETRIEVED,
31+
};
32+
33+
typedef struct VmafFrameSyncBuf {
34+
void *frame_data;
35+
int buf_status;
36+
signed long index;
37+
struct VmafFrameSyncBuf *next;
38+
} VmafFrameSyncBuf;
39+
40+
typedef struct VmafFrameSyncContext {
41+
VmafFrameSyncBuf *buf_que;
42+
pthread_mutex_t acquire_lock;
43+
pthread_mutex_t retrieve_lock;
44+
pthread_cond_t retrieve;
45+
unsigned buf_cnt;
46+
} VmafFrameSyncContext;
47+
48+
int vmaf_framesync_init(VmafFrameSyncContext **fs_ctx)
49+
{
50+
VmafFrameSyncContext *const ctx = *fs_ctx = malloc(sizeof(VmafFrameSyncContext));
51+
if (!ctx) return -ENOMEM;
52+
memset(ctx, 0, sizeof(VmafFrameSyncContext));
53+
ctx->buf_cnt = 1;
54+
55+
pthread_mutex_init(&(ctx->acquire_lock), NULL);
56+
pthread_mutex_init(&(ctx->retrieve_lock), NULL);
57+
pthread_cond_init(&(ctx->retrieve), NULL);
58+
59+
VmafFrameSyncBuf *buf_que = ctx->buf_que = malloc(sizeof(VmafFrameSyncBuf));
60+
61+
buf_que->frame_data = NULL;
62+
buf_que->buf_status = BUF_FREE;
63+
buf_que->index = -1;
64+
buf_que->next = NULL;
65+
66+
return 0;
67+
}
68+
69+
int vmaf_framesync_acquire_new_buf(VmafFrameSyncContext *fs_ctx, void **data,
70+
unsigned data_sz, unsigned index)
71+
{
72+
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
73+
*data = NULL;
74+
75+
pthread_mutex_lock(&(fs_ctx->acquire_lock));
76+
77+
// traverse until a free buffer is found
78+
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
79+
if (buf_que->buf_status == BUF_FREE) {
80+
buf_que->frame_data = *data = malloc(data_sz);
81+
if (!buf_que->frame_data)
82+
return -ENOMEM;
83+
buf_que->buf_status = BUF_ACQUIRED;
84+
buf_que->index = index;
85+
break;
86+
}
87+
// move to next node
88+
if (buf_que->next != NULL)
89+
buf_que = buf_que->next;
90+
}
91+
92+
// create a new node if all nodes are occupied in the list and append to the tail
93+
if (*data == NULL) {
94+
VmafFrameSyncBuf *new_buf_node = malloc(sizeof(VmafFrameSyncBuf));
95+
buf_que->next = new_buf_node;
96+
new_buf_node->buf_status = BUF_FREE;
97+
new_buf_node->index = -1;
98+
new_buf_node->next = NULL;
99+
fs_ctx->buf_cnt++;
100+
101+
new_buf_node->frame_data = *data = malloc(data_sz);
102+
if (!new_buf_node->frame_data)
103+
return -ENOMEM;
104+
new_buf_node->buf_status = BUF_ACQUIRED;
105+
new_buf_node->index = index;
106+
}
107+
108+
pthread_mutex_unlock(&(fs_ctx->acquire_lock));
109+
110+
return 0;
111+
}
112+
113+
int vmaf_framesync_submit_filled_data(VmafFrameSyncContext *fs_ctx, void *data,
114+
unsigned index)
115+
{
116+
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
117+
118+
pthread_mutex_lock(&(fs_ctx->retrieve_lock));
119+
120+
// loop until a matchng buffer is found
121+
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
122+
if ((buf_que->index == index) && (buf_que->buf_status == BUF_ACQUIRED)) {
123+
buf_que->buf_status = BUF_FILLED;
124+
if (data != buf_que->frame_data)
125+
return -1;
126+
break;
127+
}
128+
129+
// move to next node
130+
if (NULL != buf_que->next)
131+
buf_que = buf_que->next;
132+
}
133+
134+
pthread_cond_broadcast(&(fs_ctx->retrieve));
135+
pthread_mutex_unlock(&(fs_ctx->retrieve_lock));
136+
137+
return 0;
138+
}
139+
140+
int vmaf_framesync_retrieve_filled_data(VmafFrameSyncContext *fs_ctx,
141+
void **data, unsigned index)
142+
{
143+
*data = NULL;
144+
145+
while (*data == NULL) {
146+
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
147+
pthread_mutex_lock(&(fs_ctx->retrieve_lock));
148+
// loop until a free buffer is found
149+
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
150+
if ((buf_que->index == index) && (buf_que->buf_status == BUF_FILLED)) {
151+
buf_que->buf_status = BUF_RETRIEVED;
152+
*data = buf_que->frame_data;
153+
break;
154+
}
155+
156+
// move to next node
157+
if (NULL != buf_que->next)
158+
buf_que = buf_que->next;
159+
}
160+
161+
if (*data == NULL)
162+
pthread_cond_wait(&(fs_ctx->retrieve), &(fs_ctx->retrieve_lock));
163+
164+
pthread_mutex_unlock(&(fs_ctx->retrieve_lock));
165+
}
166+
167+
return 0;
168+
}
169+
170+
int vmaf_framesync_release_buf(VmafFrameSyncContext *fs_ctx, void *data,
171+
unsigned index)
172+
{
173+
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
174+
175+
pthread_mutex_lock(&(fs_ctx->acquire_lock));
176+
// loop until a matching buffer is found
177+
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
178+
if ((buf_que->index == index) && (buf_que->buf_status == BUF_RETRIEVED)) {
179+
if (data != buf_que->frame_data)
180+
return -1;
181+
182+
free(buf_que->frame_data);
183+
buf_que->frame_data = NULL;
184+
buf_que->buf_status = BUF_FREE;
185+
buf_que->index = -1;
186+
break;
187+
}
188+
189+
// move to next node
190+
if (NULL != buf_que->next)
191+
buf_que = buf_que->next;
192+
}
193+
194+
pthread_mutex_unlock(&(fs_ctx->acquire_lock));
195+
return 0;
196+
}
197+
198+
int vmaf_framesync_destroy(VmafFrameSyncContext *fs_ctx)
199+
{
200+
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
201+
VmafFrameSyncBuf *buf_que_tmp;
202+
203+
pthread_mutex_destroy(&(fs_ctx->acquire_lock));
204+
pthread_mutex_destroy(&(fs_ctx->retrieve_lock));
205+
pthread_cond_destroy(&(fs_ctx->retrieve));
206+
207+
//check for any data buffers which are not freed
208+
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
209+
if (NULL != buf_que->frame_data) {
210+
free(buf_que->frame_data);
211+
buf_que->frame_data = NULL;
212+
}
213+
214+
// move to next node
215+
if (NULL != buf_que->next) {
216+
buf_que_tmp = buf_que;
217+
buf_que = buf_que->next;
218+
free(buf_que_tmp);
219+
} else {
220+
free(buf_que);
221+
}
222+
}
223+
224+
free(fs_ctx);
225+
226+
return 0;
227+
}

libvmaf/src/framesync.h

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
*
3+
* Copyright 2016-2023 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+
#ifndef __VMAF_FRAME_SYNC_H__
20+
#define __VMAF_FRAME_SYNC_H__
21+
22+
#include <pthread.h>
23+
#include <stdatomic.h>
24+
#include <stdint.h>
25+
#include <stdlib.h>
26+
#include "libvmaf/libvmaf.h"
27+
28+
typedef struct VmafFrameSyncContext VmafFrameSyncContext;
29+
30+
int vmaf_framesync_init(VmafFrameSyncContext **fs_ctx);
31+
32+
int vmaf_framesync_acquire_new_buf(VmafFrameSyncContext *fs_ctx, void **data,
33+
unsigned data_sz, unsigned index);
34+
35+
int vmaf_framesync_submit_filled_data(VmafFrameSyncContext *fs_ctx, void *data,
36+
unsigned index);
37+
38+
int vmaf_framesync_retrieve_filled_data(VmafFrameSyncContext *fs_ctx, void **data,
39+
unsigned index);
40+
41+
int vmaf_framesync_release_buf(VmafFrameSyncContext *fs_ctx, void *data,
42+
unsigned index);
43+
44+
int vmaf_framesync_destroy(VmafFrameSyncContext *fs_ctx);
45+
46+
#endif /* __VMAF_FRAME_SYNC_H__ */

libvmaf/src/libvmaf.c

+18-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ typedef struct VmafContext {
5656
RegisteredFeatureExtractors registered_feature_extractors;
5757
VmafFeatureExtractorContextPool *fex_ctx_pool;
5858
VmafThreadPool *thread_pool;
59+
VmafFrameSyncContext *framesync;
5960
#ifdef HAVE_CUDA
6061
struct {
6162
struct {
@@ -99,8 +100,10 @@ int vmaf_init(VmafContext **vmaf, VmafConfiguration cfg)
99100

100101
vmaf_set_log_level(cfg.log_level);
101102

102-
err = vmaf_feature_collector_init(&(v->feature_collector));
103+
err = vmaf_framesync_init(&(v->framesync));
103104
if (err) goto free_v;
105+
err = vmaf_feature_collector_init(&(v->feature_collector));
106+
if (err) goto free_framesync;
104107
err = feature_extractor_vector_init(&(v->registered_feature_extractors));
105108
if (err) goto free_feature_collector;
106109

@@ -119,6 +122,8 @@ int vmaf_init(VmafContext **vmaf, VmafConfiguration cfg)
119122
feature_extractor_vector_destroy(&(v->registered_feature_extractors));
120123
free_feature_collector:
121124
vmaf_feature_collector_destroy(v->feature_collector);
125+
free_framesync:
126+
vmaf_framesync_destroy(v->framesync);
122127
free_v:
123128
free(v);
124129
fail:
@@ -235,11 +240,20 @@ static int set_fex_cuda_state(VmafFeatureExtractorContext *fex_ctx,
235240

236241
#endif
237242

243+
static int set_fex_framesync(VmafFeatureExtractorContext *fex_ctx,
244+
VmafContext *vmaf)
245+
{
246+
if (fex_ctx->fex->flags & VMAF_FEATURE_FRAME_SYNC)
247+
fex_ctx->fex->framesync = (vmaf->framesync);
248+
return 0;
249+
}
250+
238251
int vmaf_close(VmafContext *vmaf)
239252
{
240253
if (!vmaf) return -EINVAL;
241254

242255
vmaf_thread_pool_wait(vmaf->thread_pool);
256+
vmaf_framesync_destroy(vmaf->framesync);
243257
feature_extractor_vector_destroy(&(vmaf->registered_feature_extractors));
244258
vmaf_feature_collector_destroy(vmaf->feature_collector);
245259
vmaf_thread_pool_destroy(vmaf->thread_pool);
@@ -292,6 +306,7 @@ int vmaf_use_feature(VmafContext *vmaf, const char *feature_name,
292306
#ifdef HAVE_CUDA
293307
err |= set_fex_cuda_state(fex_ctx, vmaf);
294308
#endif
309+
err |= set_fex_framesync(fex_ctx, vmaf);
295310
if (err) return err;
296311

297312
RegisteredFeatureExtractors *rfe = &(vmaf->registered_feature_extractors);
@@ -339,6 +354,7 @@ int vmaf_use_features_from_model(VmafContext *vmaf, VmafModel *model)
339354
#ifdef HAVE_CUDA
340355
err |= set_fex_cuda_state(fex_ctx, vmaf);
341356
#endif
357+
err |= set_fex_framesync(fex_ctx, vmaf);
342358
if (err) return err;
343359
err = feature_extractor_vector_append(rfe, fex_ctx, 0);
344360
if (err) {
@@ -405,6 +421,7 @@ static int threaded_read_pictures(VmafContext *vmaf, VmafPicture *ref,
405421
continue;
406422
}
407423

424+
fex->framesync = vmaf->framesync;
408425
VmafFeatureExtractorContext *fex_ctx;
409426
err = vmaf_fex_ctx_pool_aquire(vmaf->fex_ctx_pool, fex, opts_dict,
410427
&fex_ctx);

libvmaf/src/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ libvmaf_sources = [
461461
src_dir + 'read_json_model.c',
462462
src_dir + 'pdjson.c',
463463
src_dir + 'log.c',
464+
src_dir + 'framesync.c',
464465
]
465466

466467
if is_cuda_enabled

0 commit comments

Comments
 (0)