libvmaf/src/feature/float_adm.c (184 lines of code) (raw):

/** * * 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 <errno.h> #include <string.h> #include <stddef.h> #include "dict.h" #include "feature_collector.h" #include "framesync.h" #include "feature_extractor.h" #include "feature_name.h" #include "adm.h" #include "adm_options.h" #include "mem.h" #include "picture_copy.h" typedef struct AdmState { size_t float_stride; float *ref; float *dist; bool debug; double adm_enhn_gain_limit; double adm_norm_view_dist; int adm_ref_display_height; int adm_csf_mode; VmafDictionary *feature_name_dict; } AdmState; static const VmafOption options[] = { { .name = "debug", .help = "debug mode: enable additional output", .offset = offsetof(AdmState, debug), .type = VMAF_OPT_TYPE_BOOL, .default_val.b = false, }, { .name = "adm_enhn_gain_limit", .alias = "egl", .help = "enhancement gain imposed on adm, must be >= 1.0, " "where 1.0 means the gain is completely disabled", .offset = offsetof(AdmState, adm_enhn_gain_limit), .type = VMAF_OPT_TYPE_DOUBLE, .default_val.d = DEFAULT_ADM_ENHN_GAIN_LIMIT, .min = 1.0, .max = DEFAULT_ADM_ENHN_GAIN_LIMIT, .flags = VMAF_OPT_FLAG_FEATURE_PARAM, }, { .name = "adm_norm_view_dist", .alias = "nvd", .help = "normalized viewing distance = viewing distance / ref display's physical height", .offset = offsetof(AdmState, adm_norm_view_dist), .type = VMAF_OPT_TYPE_DOUBLE, .default_val.d = DEFAULT_ADM_NORM_VIEW_DIST, .min = 0.75, .max = 24.0, .flags = VMAF_OPT_FLAG_FEATURE_PARAM, }, { .name = "adm_ref_display_height", .alias = "rdf", .help = "reference display height in pixels", .offset = offsetof(AdmState, adm_ref_display_height), .type = VMAF_OPT_TYPE_INT, .default_val.i = DEFAULT_ADM_REF_DISPLAY_HEIGHT, .min = 1, .max = 4320, .flags = VMAF_OPT_FLAG_FEATURE_PARAM, }, { .name = "adm_csf_mode", .alias = "csf", .help = "contrast sensitivity function", .offset = offsetof(AdmState, adm_csf_mode), .type = VMAF_OPT_TYPE_INT, .default_val.i = DEFAULT_ADM_CSF_MODE, .min = 0, .max = 9, .flags = VMAF_OPT_FLAG_FEATURE_PARAM, }, { 0 } }; static int init(VmafFeatureExtractor *fex, enum VmafPixelFormat pix_fmt, unsigned bpc, unsigned w, unsigned h) { (void)pix_fmt; (void)bpc; AdmState *s = fex->priv; s->float_stride = ALIGN_CEIL(w * sizeof(float)); s->ref = aligned_malloc(s->float_stride * h, 32); if (!s->ref) goto fail; s->dist = aligned_malloc(s->float_stride * h, 32); if (!s->dist) goto fail; s->feature_name_dict = vmaf_feature_name_dict_from_provided_features(fex->provided_features, fex->options, s); if (!s->feature_name_dict) goto fail; return 0; fail: if (s->ref) aligned_free(s->ref); if (s->dist) aligned_free(s->dist); vmaf_dictionary_free(&s->feature_name_dict); return -ENOMEM; } static int extract(VmafFeatureExtractor *fex, VmafPicture *ref_pic, VmafPicture *ref_pic_90, VmafPicture *dist_pic, VmafPicture *dist_pic_90, unsigned index, VmafFeatureCollector *feature_collector) { AdmState *s = fex->priv; int err = 0; (void) ref_pic_90; (void) dist_pic_90; picture_copy(s->ref, s->float_stride, ref_pic, -128, ref_pic->bpc); picture_copy(s->dist, s->float_stride, dist_pic, -128, dist_pic->bpc); double score, score_num, score_den; double scores[8]; err = compute_adm(s->ref, s->dist, ref_pic->w[0], ref_pic->h[0], s->float_stride, s->float_stride, &score, &score_num, &score_den, scores, ADM_BORDER_FACTOR, s->adm_enhn_gain_limit, s->adm_norm_view_dist, s->adm_ref_display_height, s->adm_csf_mode); if (err) return err; err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "VMAF_feature_adm2_score", score, index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "VMAF_feature_adm_scale0_score", scores[0] / scores[1], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "VMAF_feature_adm_scale1_score", scores[2] / scores[3], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "VMAF_feature_adm_scale2_score", scores[4] / scores[5], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "VMAF_feature_adm_scale3_score", scores[6] / scores[7], index); if (!s->debug) return err; err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm", score, index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_num", score_num, index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_den", score_den, index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_num_scale0", scores[0], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_den_scale0", scores[1], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_num_scale1", scores[2], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_den_scale1", scores[3], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_num_scale2", scores[4], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_den_scale2", scores[5], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_num_scale3", scores[6], index); err |= vmaf_feature_collector_append_with_dict(feature_collector, s->feature_name_dict, "adm_den_scale3", scores[7], index); return err; } static int close(VmafFeatureExtractor *fex) { AdmState *s = fex->priv; if (s->ref) aligned_free(s->ref); if (s->dist) aligned_free(s->dist); vmaf_dictionary_free(&s->feature_name_dict); return 0; } static const char *provided_features[] = { "VMAF_feature_adm2_score", "VMAF_feature_adm_scale0_score", "VMAF_feature_adm_scale1_score", "VMAF_feature_adm_scale2_score", "VMAF_feature_adm_scale3_score", "adm_num", "adm_den", "adm_scale0", "adm_num_scale0", "adm_den_scale0", "adm_num_scale1", "adm_den_scale1", "adm_num_scale2", "adm_den_scale2", "adm_num_scale3", "adm_den_scale3", NULL }; VmafFeatureExtractor vmaf_fex_float_adm = { .name = "float_adm", .init = init, .extract = extract, .options = options, .close = close, .priv_size = sizeof(AdmState), .provided_features = provided_features, };