Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions libvmaf/include/getopt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef VMAF_GETOPT_H
#define VMAF_GETOPT_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;

int getopt(int argc, char *const *argv, const char *optstring);
int getopt_long(int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int32_t *longind);
int getopt_long_only(int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int32_t *longind);

struct option {
const char *name;
int has_arg;
int *flag;
int val;
};

#define no_argument 0
#define required_argument 1
#define optional_argument 2

#ifdef __cplusplus
}
#endif

#endif /* VMAF_GETOPT_H */
2 changes: 0 additions & 2 deletions libvmaf/src/compat/msvc/stdatomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@

#include <windows.h>

#include "common/attributes.h"

typedef volatile LONG __declspec(align(32)) atomic_int;
typedef volatile ULONG __declspec(align(32)) atomic_uint;

Expand Down
5 changes: 5 additions & 0 deletions libvmaf/src/feature/ciede.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ SOFTWARE.
#include "mem.h"
#include "opt.h"

#ifndef M_PI
/* There are a lot of M_PI definitions but none generic to be included */
#define M_PI 3.14159265358979323846264338327
#endif // M_PI

typedef struct CiedeState {
VmafPicture ref;
VmafPicture dist;
Expand Down
20 changes: 20 additions & 0 deletions libvmaf/src/feature/integer_adm.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@
#include <arm_neon.h>
#endif

#ifdef _MSC_VER
#include <intrin.h>

/* Provide small fallbacks for GCC builtins used upstream. These are only
* defined for MSVC to avoid interfering with other compilers. */
static inline int __builtin_clz(unsigned x) {
if (x == 0) return 32;
unsigned long index;
_BitScanReverse(&index, x);
return 31 - (int)index;
}

static inline int __builtin_clzll(unsigned long long x) {
if (x == 0) return 64;
unsigned long index;
_BitScanReverse64(&index, x);
return 63 - (int)index;
}
#endif

typedef struct AdmState {
size_t integer_stride;
AdmBuffer buf;
Expand Down
38 changes: 21 additions & 17 deletions libvmaf/src/feature/integer_vif.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,23 +630,27 @@ static int init(VmafFeatureExtractor *fex, enum VmafPixelFormat pix_fmt,
if (!data) return -ENOMEM;
memset(data, 0, data_sz);

s->public.buf.data = data; data += pad_size;
s->public.buf.ref = data; data += frame_size + pad_size + pad_size;
s->public.buf.dis = data; data += frame_size + pad_size;
s->public.buf.mu1 = data; data += h * s->public.buf.stride_16;
s->public.buf.mu2 = data; data += h * s->public.buf.stride_16;
s->public.buf.mu1_32 = data; data += s->public.buf.stride_32;
s->public.buf.mu2_32 = data; data += s->public.buf.stride_32;
s->public.buf.ref_sq = data; data += s->public.buf.stride_32;
s->public.buf.dis_sq = data; data += s->public.buf.stride_32;
s->public.buf.ref_dis = data; data += s->public.buf.stride_32;
s->public.buf.tmp.mu1 = data; data += s->public.buf.stride_tmp;
s->public.buf.tmp.mu2 = data; data += s->public.buf.stride_tmp;
s->public.buf.tmp.ref = data; data += s->public.buf.stride_tmp;
s->public.buf.tmp.dis = data; data += s->public.buf.stride_tmp;
s->public.buf.tmp.ref_dis = data; data += s->public.buf.stride_tmp;
s->public.buf.tmp.ref_convol = data; data += s->public.buf.stride_tmp;
s->public.buf.tmp.dis_convol = data;
/* Keep original layout but perform offset arithmetic on a byte pointer.
* This avoids undefined behavior on some compilers when doing pointer
* arithmetic with non-char pointer types (MSVC is strict about this). */
s->public.buf.data = data;
unsigned char *d = (unsigned char *)data + pad_size;
s->public.buf.ref = (void *)d; d += frame_size + pad_size + pad_size;
s->public.buf.dis = (void *)d; d += frame_size + pad_size;
s->public.buf.mu1 = (void *)d; d += h * s->public.buf.stride_16;
s->public.buf.mu2 = (void *)d; d += h * s->public.buf.stride_16;
s->public.buf.mu1_32 = (void *)d; d += s->public.buf.stride_32;
s->public.buf.mu2_32 = (void *)d; d += s->public.buf.stride_32;
s->public.buf.ref_sq = (void *)d; d += s->public.buf.stride_32;
s->public.buf.dis_sq = (void *)d; d += s->public.buf.stride_32;
s->public.buf.ref_dis = (void *)d; d += s->public.buf.stride_32;
s->public.buf.tmp.mu1 = (void *)d; d += s->public.buf.stride_tmp;
s->public.buf.tmp.mu2 = (void *)d; d += s->public.buf.stride_tmp;
s->public.buf.tmp.ref = (void *)d; d += s->public.buf.stride_tmp;
s->public.buf.tmp.dis = (void *)d; d += s->public.buf.stride_tmp;
s->public.buf.tmp.ref_dis = (void *)d; d += s->public.buf.stride_tmp;
s->public.buf.tmp.ref_convol = (void *)d; d += s->public.buf.stride_tmp;
s->public.buf.tmp.dis_convol = (void *)d;

s->feature_name_dict =
vmaf_feature_name_dict_from_provided_features(fex->provided_features,
Expand Down
28 changes: 21 additions & 7 deletions libvmaf/src/feature/mkdirp.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
// MIT licensed
//

#include <unistd.h>
#ifdef _MSC_VER
# include <io.h>
# include <direct.h> /* _mkdir, _wmkdir */
# ifndef strdup
# define strdup _strdup
# endif
#else
# include <unistd.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -64,12 +72,18 @@ mkdirp(const char *path, mode_t mode) {
free(parent);

// make this one if parent has been made
#ifdef _WIN32
// http://msdn.microsoft.com/en-us/library/2fkk4dzw.aspx
int rc = mkdir(pathname);
#else
int rc = mkdir(pathname, mode);
#endif
#ifdef _MSC_VER
/* On MSVC use _mkdir which takes only a path.
* Microsoft docs: _mkdir and _wmkdir create a new directory and return 0
* on success or -1 on error, setting errno accordingly. See CRT docs:
* https://learn.microsoft.com/en-us/c-runtime-library/reference/mkdir-wmkdir
*
* The CRT documents that _mkdir/_wmkdir behave like mkdir but accept only
* a path (no mode) and set errno on failure (EEXIST, ENOENT, ...). */
int rc = _mkdir(pathname);
#else
int rc = mkdir(pathname, mode);
#endif

free(pathname);

Expand Down
5 changes: 5 additions & 0 deletions libvmaf/src/feature/mkdirp.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
#include <sys/types.h>
#include <sys/stat.h>

#ifdef _MSC_VER
/* On MSVC provide a minimal mode_t typedef */
typedef int mode_t;
#endif

/*
* Recursively `mkdir(path, mode)`
*/
Expand Down
4 changes: 3 additions & 1 deletion libvmaf/src/libvmaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,8 @@ int vmaf_score_pooled_model_collection(VmafContext *vmaf,
const char *suffix_stddev = "_stddev";
const size_t name_sz =
strlen(model_collection->name) + strlen(suffix_lo) + 1;
char name[name_sz];
char *name = malloc(name_sz);
if (!name) return -ENOMEM;
memset(name, 0, name_sz);

snprintf(name, name_sz, "%s%s", model_collection->name, suffix_bagging);
Expand All @@ -917,6 +918,7 @@ int vmaf_score_pooled_model_collection(VmafContext *vmaf,
&score->bootstrap.ci.p95.hi,
index_low, index_high);

free(name);
return err;
}

Expand Down
8 changes: 7 additions & 1 deletion libvmaf/src/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@
#include "libvmaf/libvmaf.h"

#include <stdarg.h>
#include <unistd.h>
#ifdef _WIN32
# include <io.h>
# define isatty _isatty
# define fileno _fileno
#else
# include <unistd.h>
#endif

static enum VmafLogLevel vmaf_log_level = VMAF_LOG_LEVEL_INFO;
static int istty = 0;
Expand Down
13 changes: 9 additions & 4 deletions libvmaf/src/predict.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@ static int vmaf_bootstrap_predict_score_at_index(
VmafModelCollectionScore *score)
{
int err = 0;
double scores[model_collection->cnt];
/* Use heap allocation to avoid large stack arrays on MSVC */
double *scores = malloc(sizeof(double) * model_collection->cnt);
if (!scores) return -ENOMEM;

for (unsigned i = 0; i < model_collection->cnt; i++) {
// mean, stddev, etc. are calculated on untransformed/unclipped scores
Expand All @@ -370,15 +372,15 @@ static int vmaf_bootstrap_predict_score_at_index(
feature_collector, index,
&scores[i], false,
false, flags);
if (err) return err;
if (err) { free(scores); return err; }

// do not override the model's transform/clip behavior
// write the scores to the feature collector
double score;
err = vmaf_predict_score_at_index(model_collection->model[i],
feature_collector, index,
&score, true, false, 0);
if (err) return err;
if (err) { free(scores); return err; }
}

score->type = VMAF_MODEL_COLLECTION_SCORE_BOOTSTRAP;
Expand Down Expand Up @@ -424,7 +426,8 @@ static int vmaf_bootstrap_predict_score_at_index(
const char *suffix_stddev = "_stddev";
const size_t name_sz =
strlen(model_collection->name) + strlen(suffix_lo) + 1;
char name[name_sz];
char *name = malloc(name_sz);
if (!name) { free(scores); return -ENOMEM; }
memset(name, 0, name_sz);

snprintf(name, name_sz, "%s%s", model_collection->name, suffix_bagging);
Expand All @@ -443,6 +446,8 @@ static int vmaf_bootstrap_predict_score_at_index(
err |= vmaf_feature_collector_append(feature_collector, name,
score->bootstrap.ci.p95.hi,
index);
free(name);
free(scores);
return err;
}

Expand Down
20 changes: 13 additions & 7 deletions libvmaf/src/read_json_model.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,40 +493,46 @@ static int model_collection_parse(json_stream *s, VmafModel **model,
if (!c.name) return -ENOMEM;

const size_t cfg_name_sz = strlen(name) + 5 + 1;
char cfg_name[cfg_name_sz];
char *cfg_name = malloc(cfg_name_sz);
if (!cfg_name) { free((char*)name); return -ENOMEM; }

const size_t generated_key_sz = 4 + 1;
char generated_key[generated_key_sz];
char *generated_key = malloc(generated_key_sz);
if (!generated_key) { free(cfg_name); free((char*)name); return -ENOMEM; }

unsigned i = 0;
while (json_peek(s) != JSON_OBJECT_END && !json_get_error(s)) {
if (json_next(s) != JSON_STRING)
return -EINVAL;
if (json_next(s) != JSON_STRING) {
err = -EINVAL;
goto cleanup;
}

const char *key = json_get_string(s, NULL);
snprintf(generated_key, generated_key_sz, "%d", i);

if (!strcmp(key, generated_key)) {
VmafModel *m;
err = vmaf_read_json_model(&m, &c, s);
if (err) return err;
if (err) { free(generated_key); free(cfg_name); free((char*)name); return err; }

if (i == 0) {
*model = m;
c.name = cfg_name;
} else {
err = vmaf_model_collection_append(model_collection, m);
if (err) return err;
if (err) { free(generated_key); free(cfg_name); free((char*)name); return err; }
}

sprintf((char*)c.name, "%s_%04d", name, ++i);
continue;
}

json_skip(s);
}

cleanup:
free((char*)name);
free(generated_key);
free(cfg_name);
if (!(*model_collection)) return -EINVAL;
return err;
}
Expand Down
52 changes: 52 additions & 0 deletions libvmaf/tools/compat/getopt/getopt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* Minimal getopt compatibility implementation for platforms without getopt.h */

#include "getopt.h"
#include <stdlib.h>
#include <string.h>

char *optarg = NULL;
int optind = 1;
int opterr = 1;
int optopt = '?';

int getopt(int argc, char *const *argv, const char *optstring) {
static int sp = 1;
if (optind >= argc) return -1;
char *arg = argv[optind];
if (arg[0] != '-' || arg[1] == '\0') return -1;
if (strcmp(arg, "--") == 0) { optind++; return -1; }
char c = arg[sp];
const char *oli = strchr(optstring, c);
if (!oli) {
optopt = c;
if (arg[++sp] == '\0') { optind++; sp = 1; }
return '?';
}
if (oli[1] == ':') {
if (arg[sp+1] != '\0') {
optarg = &arg[sp+1];
optind++;
} else if (optind+1 < argc) {
optarg = argv[++optind];
optind++;
} else {
optopt = c;
if (optstring[0] == ':') return ':'; else return '?';
}
sp = 1;
} else {
if (arg[++sp] == '\0') { optind++; sp = 1; }
}
return c;
}

int getopt_long(int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int32_t *longind) {
(void)longopts; (void)longind;
return getopt(argc, argv, shortopts);
}

int getopt_long_only(int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int32_t *longind) {
return getopt_long(argc, argv, shortopts, longopts, longind);
}
19 changes: 12 additions & 7 deletions libvmaf/tools/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ if cc.has_function('strsep')
compat_cflags += '-DHAVE_STRSEP'
endif

compat_getopt = []
if cc.get_id() == 'msvc'
compat_getopt = ['compat/getopt/getopt.c']
endif

vmaf = executable(
'vmaf',
['vmaf.c', 'cli_parse.c', 'y4m_input.c', 'vidinput.c', 'yuv_input.c'],
include_directories : [libvmaf_inc, vmaf_include],
dependencies: [stdatomic_dependency, cuda_dependency],
c_args : [vmaf_cflags_common, compat_cflags],
link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf,
install : true,
'vmaf',
compat_getopt + ['vmaf.c', 'cli_parse.c', 'y4m_input.c', 'vidinput.c', 'yuv_input.c'],
include_directories : [libvmaf_inc, vmaf_include],
dependencies: [stdatomic_dependency, cuda_dependency],
c_args : [vmaf_cflags_common, compat_cflags],
link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf,
install : true,
)

subdir('test')
Loading