Skip to content

Commit

Permalink
libvmaf: introduce framesync api
Browse files Browse the repository at this point in the history
Co-authored-by: Niranjan Kumar <[email protected]>
Co-authored-by: Mallikarjun Kamble <[email protected]>
Co-authored-by: Nil Fons Miret <[email protected]>
  • Loading branch information
4 people committed Feb 7, 2024
1 parent 1bb98bb commit 8b2687a
Show file tree
Hide file tree
Showing 9 changed files with 459 additions and 1 deletion.
2 changes: 2 additions & 0 deletions libvmaf/src/feature/feature_extractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ int vmaf_fex_ctx_pool_aquire(VmafFeatureExtractorContextPool *pool,
}
err = vmaf_feature_extractor_context_create(&f, entry->fex, d);
if (err) goto unlock;
if (f->fex->flags & VMAF_FEATURE_FRAME_SYNC)
f->fex->framesync = (fex->framesync);
}
if (!entry->ctx_list[i].in_use) {
entry->ctx_list[i].fex_ctx = *fex_ctx = f;
Expand Down
4 changes: 4 additions & 0 deletions libvmaf/src/feature/feature_extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <stdlib.h>

#include "dict.h"
#include "framesync.h"
#include "feature_collector.h"
#include "opt.h"

Expand All @@ -36,6 +37,7 @@
enum VmafFeatureExtractorFlags {
VMAF_FEATURE_EXTRACTOR_TEMPORAL = 1 << 0,
VMAF_FEATURE_EXTRACTOR_CUDA = 1 << 1,
VMAF_FEATURE_FRAME_SYNC = 1 << 2,
};

typedef struct VmafFeatureExtractor {
Expand Down Expand Up @@ -94,6 +96,8 @@ typedef struct VmafFeatureExtractor {
VmafCudaState *cu_state; ///< VmafCudaState, set by framework
#endif

VmafFrameSyncContext *framesync;

} VmafFeatureExtractor;

VmafFeatureExtractor *vmaf_get_feature_extractor_by_name(const char *name);
Expand Down
1 change: 1 addition & 0 deletions libvmaf/src/feature/float_adm.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "dict.h"
#include "feature_collector.h"
#include "framesync.h"
#include "feature_extractor.h"
#include "feature_name.h"

Expand Down
227 changes: 227 additions & 0 deletions libvmaf/src/framesync.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/**
*
* Copyright 2016-2023 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 <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include "framesync.h"

enum {
BUF_FREE = 0,
BUF_ACQUIRED,
BUF_FILLED,
BUF_RETRIEVED,
};

typedef struct VmafFrameSyncBuf {
void *frame_data;
int buf_status;
signed long index;
struct VmafFrameSyncBuf *next;
} VmafFrameSyncBuf;

typedef struct VmafFrameSyncContext {
VmafFrameSyncBuf *buf_que;
pthread_mutex_t acquire_lock;
pthread_mutex_t retrieve_lock;
pthread_cond_t retrieve;
unsigned buf_cnt;
} VmafFrameSyncContext;

int vmaf_framesync_init(VmafFrameSyncContext **fs_ctx)
{
VmafFrameSyncContext *const ctx = *fs_ctx = malloc(sizeof(VmafFrameSyncContext));
if (!ctx) return -ENOMEM;
memset(ctx, 0, sizeof(VmafFrameSyncContext));
ctx->buf_cnt = 1;

pthread_mutex_init(&(ctx->acquire_lock), NULL);
pthread_mutex_init(&(ctx->retrieve_lock), NULL);
pthread_cond_init(&(ctx->retrieve), NULL);

VmafFrameSyncBuf *buf_que = ctx->buf_que = malloc(sizeof(VmafFrameSyncBuf));

buf_que->frame_data = NULL;
buf_que->buf_status = BUF_FREE;
buf_que->index = -1;
buf_que->next = NULL;

return 0;
}

int vmaf_framesync_acquire_new_buf(VmafFrameSyncContext *fs_ctx, void **data,
unsigned data_sz, unsigned index)
{
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
*data = NULL;

pthread_mutex_lock(&(fs_ctx->acquire_lock));

// traverse until a free buffer is found
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
if (buf_que->buf_status == BUF_FREE) {
buf_que->frame_data = *data = malloc(data_sz);
if (!buf_que->frame_data)
return -ENOMEM;
buf_que->buf_status = BUF_ACQUIRED;
buf_que->index = index;
break;
}
// move to next node
if (buf_que->next != NULL)
buf_que = buf_que->next;
}

// create a new node if all nodes are occupied in the list and append to the tail
if (*data == NULL) {
VmafFrameSyncBuf *new_buf_node = malloc(sizeof(VmafFrameSyncBuf));
buf_que->next = new_buf_node;
new_buf_node->buf_status = BUF_FREE;
new_buf_node->index = -1;
new_buf_node->next = NULL;
fs_ctx->buf_cnt++;

new_buf_node->frame_data = *data = malloc(data_sz);
if (!new_buf_node->frame_data)
return -ENOMEM;
new_buf_node->buf_status = BUF_ACQUIRED;
new_buf_node->index = index;
}

pthread_mutex_unlock(&(fs_ctx->acquire_lock));

return 0;
}

int vmaf_framesync_submit_filled_data(VmafFrameSyncContext *fs_ctx, void *data,
unsigned index)
{
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;

pthread_mutex_lock(&(fs_ctx->retrieve_lock));

// loop until a matchng buffer is found
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
if ((buf_que->index == index) && (buf_que->buf_status == BUF_ACQUIRED)) {
buf_que->buf_status = BUF_FILLED;
if (data != buf_que->frame_data)
return -1;
break;
}

// move to next node
if (NULL != buf_que->next)
buf_que = buf_que->next;
}

pthread_cond_broadcast(&(fs_ctx->retrieve));
pthread_mutex_unlock(&(fs_ctx->retrieve_lock));

return 0;
}

int vmaf_framesync_retrieve_filled_data(VmafFrameSyncContext *fs_ctx,
void **data, unsigned index)
{
*data = NULL;

while (*data == NULL) {
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
pthread_mutex_lock(&(fs_ctx->retrieve_lock));
// loop until a free buffer is found
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
if ((buf_que->index == index) && (buf_que->buf_status == BUF_FILLED)) {
buf_que->buf_status = BUF_RETRIEVED;
*data = buf_que->frame_data;
break;
}

// move to next node
if (NULL != buf_que->next)
buf_que = buf_que->next;
}

if (*data == NULL)
pthread_cond_wait(&(fs_ctx->retrieve), &(fs_ctx->retrieve_lock));

pthread_mutex_unlock(&(fs_ctx->retrieve_lock));
}

return 0;
}

int vmaf_framesync_release_buf(VmafFrameSyncContext *fs_ctx, void *data,
unsigned index)
{
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;

pthread_mutex_lock(&(fs_ctx->acquire_lock));
// loop until a matching buffer is found
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
if ((buf_que->index == index) && (buf_que->buf_status == BUF_RETRIEVED)) {
if (data != buf_que->frame_data)
return -1;

free(buf_que->frame_data);
buf_que->frame_data = NULL;
buf_que->buf_status = BUF_FREE;
buf_que->index = -1;
break;
}

// move to next node
if (NULL != buf_que->next)
buf_que = buf_que->next;
}

pthread_mutex_unlock(&(fs_ctx->acquire_lock));
return 0;
}

int vmaf_framesync_destroy(VmafFrameSyncContext *fs_ctx)
{
VmafFrameSyncBuf *buf_que = fs_ctx->buf_que;
VmafFrameSyncBuf *buf_que_tmp;

pthread_mutex_destroy(&(fs_ctx->acquire_lock));
pthread_mutex_destroy(&(fs_ctx->retrieve_lock));
pthread_cond_destroy(&(fs_ctx->retrieve));

//check for any data buffers which are not freed
for (unsigned i = 0; i < fs_ctx->buf_cnt; i++) {
if (NULL != buf_que->frame_data) {
free(buf_que->frame_data);
buf_que->frame_data = NULL;
}

// move to next node
if (NULL != buf_que->next) {
buf_que_tmp = buf_que;
buf_que = buf_que->next;
free(buf_que_tmp);
} else {
free(buf_que);
}
}

free(fs_ctx);

return 0;
}
46 changes: 46 additions & 0 deletions libvmaf/src/framesync.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
*
* Copyright 2016-2023 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_FRAME_SYNC_H__
#define __VMAF_FRAME_SYNC_H__

#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include "libvmaf/libvmaf.h"

typedef struct VmafFrameSyncContext VmafFrameSyncContext;

int vmaf_framesync_init(VmafFrameSyncContext **fs_ctx);

int vmaf_framesync_acquire_new_buf(VmafFrameSyncContext *fs_ctx, void **data,
unsigned data_sz, unsigned index);

int vmaf_framesync_submit_filled_data(VmafFrameSyncContext *fs_ctx, void *data,
unsigned index);

int vmaf_framesync_retrieve_filled_data(VmafFrameSyncContext *fs_ctx, void **data,
unsigned index);

int vmaf_framesync_release_buf(VmafFrameSyncContext *fs_ctx, void *data,
unsigned index);

int vmaf_framesync_destroy(VmafFrameSyncContext *fs_ctx);

#endif /* __VMAF_FRAME_SYNC_H__ */
19 changes: 18 additions & 1 deletion libvmaf/src/libvmaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ typedef struct VmafContext {
RegisteredFeatureExtractors registered_feature_extractors;
VmafFeatureExtractorContextPool *fex_ctx_pool;
VmafThreadPool *thread_pool;
VmafFrameSyncContext *framesync;
#ifdef HAVE_CUDA
struct {
struct {
Expand Down Expand Up @@ -99,8 +100,10 @@ int vmaf_init(VmafContext **vmaf, VmafConfiguration cfg)

vmaf_set_log_level(cfg.log_level);

err = vmaf_feature_collector_init(&(v->feature_collector));
err = vmaf_framesync_init(&(v->framesync));
if (err) goto free_v;
err = vmaf_feature_collector_init(&(v->feature_collector));
if (err) goto free_framesync;
err = feature_extractor_vector_init(&(v->registered_feature_extractors));
if (err) goto free_feature_collector;

Expand All @@ -119,6 +122,8 @@ int vmaf_init(VmafContext **vmaf, VmafConfiguration cfg)
feature_extractor_vector_destroy(&(v->registered_feature_extractors));
free_feature_collector:
vmaf_feature_collector_destroy(v->feature_collector);
free_framesync:
vmaf_framesync_destroy(v->framesync);
free_v:
free(v);
fail:
Expand Down Expand Up @@ -235,11 +240,20 @@ static int set_fex_cuda_state(VmafFeatureExtractorContext *fex_ctx,

#endif

static int set_fex_framesync(VmafFeatureExtractorContext *fex_ctx,
VmafContext *vmaf)
{
if (fex_ctx->fex->flags & VMAF_FEATURE_FRAME_SYNC)
fex_ctx->fex->framesync = (vmaf->framesync);
return 0;
}

int vmaf_close(VmafContext *vmaf)
{
if (!vmaf) return -EINVAL;

vmaf_thread_pool_wait(vmaf->thread_pool);
vmaf_framesync_destroy(vmaf->framesync);
feature_extractor_vector_destroy(&(vmaf->registered_feature_extractors));
vmaf_feature_collector_destroy(vmaf->feature_collector);
vmaf_thread_pool_destroy(vmaf->thread_pool);
Expand Down Expand Up @@ -292,6 +306,7 @@ int vmaf_use_feature(VmafContext *vmaf, const char *feature_name,
#ifdef HAVE_CUDA
err |= set_fex_cuda_state(fex_ctx, vmaf);
#endif
err |= set_fex_framesync(fex_ctx, vmaf);
if (err) return err;

RegisteredFeatureExtractors *rfe = &(vmaf->registered_feature_extractors);
Expand Down Expand Up @@ -339,6 +354,7 @@ int vmaf_use_features_from_model(VmafContext *vmaf, VmafModel *model)
#ifdef HAVE_CUDA
err |= set_fex_cuda_state(fex_ctx, vmaf);
#endif
err |= set_fex_framesync(fex_ctx, vmaf);
if (err) return err;
err = feature_extractor_vector_append(rfe, fex_ctx, 0);
if (err) {
Expand Down Expand Up @@ -405,6 +421,7 @@ static int threaded_read_pictures(VmafContext *vmaf, VmafPicture *ref,
continue;
}

fex->framesync = vmaf->framesync;
VmafFeatureExtractorContext *fex_ctx;
err = vmaf_fex_ctx_pool_aquire(vmaf->fex_ctx_pool, fex, opts_dict,
&fex_ctx);
Expand Down
1 change: 1 addition & 0 deletions libvmaf/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ libvmaf_sources = [
src_dir + 'read_json_model.c',
src_dir + 'pdjson.c',
src_dir + 'log.c',
src_dir + 'framesync.c',
]

if is_cuda_enabled
Expand Down
Loading

0 comments on commit 8b2687a

Please sign in to comment.