FFmpeg
vf_libvmaf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Ronald S. Bultje <rsbultje@gmail.com>
3  * Copyright (c) 2017 Ashish Pratap Singh <ashk43712@gmail.com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * Calculate the VMAF between two input videos.
25  */
26 
27 #include "config_components.h"
28 
29 #include <libvmaf.h>
30 
31 #include "libavutil/avstring.h"
32 #include "libavutil/mem.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/pixdesc.h"
35 #include "avfilter.h"
36 #include "drawutils.h"
37 #include "formats.h"
38 #include "framesync.h"
39 #include "internal.h"
40 #include "video.h"
41 
42 #if CONFIG_LIBVMAF_CUDA_FILTER
43 #include <libvmaf_cuda.h>
44 
45 #include "libavutil/hwcontext.h"
47 #endif
48 
49 typedef struct LIBVMAFContext {
50  const AVClass *class;
52  char *log_path;
53  char *log_fmt;
54  char *pool;
55  int n_threads;
57  char *model_cfg;
58  char *feature_cfg;
59  VmafContext *vmaf;
60  VmafModel **model;
61  unsigned model_cnt;
62  unsigned frame_cnt;
63  unsigned bpc;
64 #if CONFIG_LIBVMAF_CUDA_FILTER
65  VmafCudaState *cu_state;
66 #endif
68 
69 #define OFFSET(x) offsetof(LIBVMAFContext, x)
70 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
71 
72 static const AVOption libvmaf_options[] = {
73  {"log_path", "Set the file path to be used to write log.", OFFSET(log_path), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS},
74  {"log_fmt", "Set the format of the log (csv, json, xml, or sub).", OFFSET(log_fmt), AV_OPT_TYPE_STRING, {.str="xml"}, 0, 1, FLAGS},
75  {"pool", "Set the pool method to be used for computing vmaf.", OFFSET(pool), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS},
76  {"n_threads", "Set number of threads to be used when computing vmaf.", OFFSET(n_threads), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT_MAX, FLAGS},
77  {"n_subsample", "Set interval for frame subsampling used when computing vmaf.", OFFSET(n_subsample), AV_OPT_TYPE_INT, {.i64=1}, 1, UINT_MAX, FLAGS},
78  {"model", "Set the model to be used for computing vmaf.", OFFSET(model_cfg), AV_OPT_TYPE_STRING, {.str="version=vmaf_v0.6.1"}, 0, 1, FLAGS},
79  {"feature", "Set the feature to be used for computing vmaf.", OFFSET(feature_cfg), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS},
80  { NULL }
81 };
82 
84 
85 static enum VmafPixelFormat pix_fmt_map(enum AVPixelFormat av_pix_fmt)
86 {
87  switch (av_pix_fmt) {
88  case AV_PIX_FMT_YUV420P:
92  return VMAF_PIX_FMT_YUV420P;
93  case AV_PIX_FMT_YUV422P:
97  return VMAF_PIX_FMT_YUV422P;
98  case AV_PIX_FMT_YUV444P:
102  return VMAF_PIX_FMT_YUV444P;
103  default:
104  return VMAF_PIX_FMT_UNKNOWN;
105  }
106 }
107 
108 static int copy_picture_data(AVFrame *src, VmafPicture *dst, unsigned bpc)
109 {
110  const int bytes_per_value = bpc > 8 ? 2 : 1;
111  int err = vmaf_picture_alloc(dst, pix_fmt_map(src->format), bpc,
112  src->width, src->height);
113  if (err)
114  return AVERROR(ENOMEM);
115 
116  for (unsigned i = 0; i < 3; i++) {
117  uint8_t *src_data = src->data[i];
118  uint8_t *dst_data = dst->data[i];
119  for (unsigned j = 0; j < dst->h[i]; j++) {
120  memcpy(dst_data, src_data, bytes_per_value * dst->w[i]);
121  src_data += src->linesize[i];
122  dst_data += dst->stride[i];
123  }
124  }
125 
126  return 0;
127 }
128 
129 static int do_vmaf(FFFrameSync *fs)
130 {
131  AVFilterContext *ctx = fs->parent;
132  LIBVMAFContext *s = ctx->priv;
133  VmafPicture pic_ref, pic_dist;
134  AVFrame *ref, *dist;
135  int err = 0;
136 
137  int ret = ff_framesync_dualinput_get(fs, &dist, &ref);
138  if (ret < 0)
139  return ret;
140  if (ctx->is_disabled || !ref)
141  return ff_filter_frame(ctx->outputs[0], dist);
142 
143  if (dist->color_range != ref->color_range) {
144  av_log(ctx, AV_LOG_WARNING, "distorted and reference "
145  "frames use different color ranges (%s != %s)\n",
147  av_color_range_name(ref->color_range));
148  }
149 
150  err = copy_picture_data(ref, &pic_ref, s->bpc);
151  if (err) {
152  av_log(s, AV_LOG_ERROR, "problem during vmaf_picture_alloc.\n");
153  return AVERROR(ENOMEM);
154  }
155 
156  err = copy_picture_data(dist, &pic_dist, s->bpc);
157  if (err) {
158  av_log(s, AV_LOG_ERROR, "problem during vmaf_picture_alloc.\n");
159  vmaf_picture_unref(&pic_ref);
160  return AVERROR(ENOMEM);
161  }
162 
163  err = vmaf_read_pictures(s->vmaf, &pic_ref, &pic_dist, s->frame_cnt++);
164  if (err) {
165  av_log(s, AV_LOG_ERROR, "problem during vmaf_read_pictures.\n");
166  return AVERROR(EINVAL);
167  }
168 
169  return ff_filter_frame(ctx->outputs[0], dist);
170 }
171 
172 static AVDictionary **delimited_dict_parse(char *str, unsigned *cnt)
173 {
174  AVDictionary **dict = NULL;
175  char *str_copy = NULL;
176  char *saveptr = NULL;
177  unsigned cnt2;
178  int err = 0;
179 
180  if (!str)
181  return NULL;
182 
183  cnt2 = 1;
184  for (char *p = str; *p; p++) {
185  if (*p == '|')
186  cnt2++;
187  }
188 
189  dict = av_calloc(cnt2, sizeof(*dict));
190  if (!dict)
191  goto fail;
192 
193  str_copy = av_strdup(str);
194  if (!str_copy)
195  goto fail;
196 
197  *cnt = 0;
198  for (unsigned i = 0; i < cnt2; i++) {
199  char *s = av_strtok(i == 0 ? str_copy : NULL, "|", &saveptr);
200  if (!s)
201  continue;
202  err = av_dict_parse_string(&dict[(*cnt)++], s, "=", ":", 0);
203  if (err)
204  goto fail;
205  }
206 
207  av_free(str_copy);
208  return dict;
209 
210 fail:
211  if (dict) {
212  for (unsigned i = 0; i < *cnt; i++) {
213  if (dict[i])
214  av_dict_free(&dict[i]);
215  }
216  av_free(dict);
217  }
218 
219  av_free(str_copy);
220  *cnt = 0;
221  return NULL;
222 }
223 
225 {
226  LIBVMAFContext *s = ctx->priv;
227  AVDictionary **dict = NULL;
228  unsigned dict_cnt;
229  int err = 0;
230 
231  if (!s->feature_cfg)
232  return 0;
233 
234  dict = delimited_dict_parse(s->feature_cfg, &dict_cnt);
235  if (!dict) {
237  "could not parse feature config: %s\n", s->feature_cfg);
238  return AVERROR(EINVAL);
239  }
240 
241  for (unsigned i = 0; i < dict_cnt; i++) {
242  char *feature_name = NULL;
243  VmafFeatureDictionary *feature_opts_dict = NULL;
244  const AVDictionaryEntry *e = NULL;
245 
246  while (e = av_dict_iterate(dict[i], e)) {
247  if (!strcmp(e->key, "name")) {
248  feature_name = e->value;
249  continue;
250  }
251 
252  err = vmaf_feature_dictionary_set(&feature_opts_dict, e->key,
253  e->value);
254  if (err) {
256  "could not set feature option: %s.%s=%s\n",
257  feature_name, e->key, e->value);
258  goto exit;
259  }
260  }
261 
262  err = vmaf_use_feature(s->vmaf, feature_name, feature_opts_dict);
263  if (err) {
265  "problem during vmaf_use_feature: %s\n", feature_name);
266  goto exit;
267  }
268  }
269 
270 exit:
271  for (unsigned i = 0; i < dict_cnt; i++) {
272  if (dict[i])
273  av_dict_free(&dict[i]);
274  }
275  av_free(dict);
276  return err;
277 }
278 
280 {
281  LIBVMAFContext *s = ctx->priv;
282  AVDictionary **dict;
283  unsigned dict_cnt;
284  int err = 0;
285 
286  if (!s->model_cfg) return 0;
287 
288  dict_cnt = 0;
289  dict = delimited_dict_parse(s->model_cfg, &dict_cnt);
290  if (!dict) {
292  "could not parse model config: %s\n", s->model_cfg);
293  return AVERROR(EINVAL);
294  }
295 
296  s->model_cnt = dict_cnt;
297  s->model = av_calloc(s->model_cnt, sizeof(*s->model));
298  if (!s->model)
299  return AVERROR(ENOMEM);
300 
301  for (unsigned i = 0; i < dict_cnt; i++) {
302  VmafModelConfig model_cfg = { 0 };
303  const AVDictionaryEntry *e = NULL;
304  char *version = NULL;
305  char *path = NULL;
306 
307  while (e = av_dict_iterate(dict[i], e)) {
308  if (!strcmp(e->key, "disable_clip")) {
309  model_cfg.flags |= !strcmp(e->value, "true") ?
310  VMAF_MODEL_FLAG_DISABLE_CLIP : 0;
311  continue;
312  }
313 
314  if (!strcmp(e->key, "enable_transform")) {
315  model_cfg.flags |= !strcmp(e->value, "true") ?
316  VMAF_MODEL_FLAG_ENABLE_TRANSFORM : 0;
317  continue;
318  }
319 
320  if (!strcmp(e->key, "name")) {
321  model_cfg.name = e->value;
322  continue;
323  }
324 
325  if (!strcmp(e->key, "version")) {
326  version = e->value;
327  continue;
328  }
329 
330  if (!strcmp(e->key, "path")) {
331  path = e->value;
332  continue;
333  }
334  }
335 
336  if (version) {
337  err = vmaf_model_load(&s->model[i], &model_cfg, version);
338  if (err) {
340  "could not load libvmaf model with version: %s\n",
341  version);
342  goto exit;
343  }
344  }
345 
346  if (path && !s->model[i]) {
347  err = vmaf_model_load_from_path(&s->model[i], &model_cfg, path);
348  if (err) {
350  "could not load libvmaf model with path: %s\n",
351  path);
352  goto exit;
353  }
354  }
355 
356  if (!s->model[i]) {
358  "could not load libvmaf model with config: %s\n",
359  s->model_cfg);
360  goto exit;
361  }
362 
363  while (e = av_dict_iterate(dict[i], e)) {
364  VmafFeatureDictionary *feature_opts_dict = NULL;
365  char *feature_opt = NULL;
366 
367  char *feature_name = av_strtok(e->key, ".", &feature_opt);
368  if (!feature_opt)
369  continue;
370 
371  err = vmaf_feature_dictionary_set(&feature_opts_dict,
372  feature_opt, e->value);
373  if (err) {
375  "could not set feature option: %s.%s=%s\n",
376  feature_name, feature_opt, e->value);
377  err = AVERROR(EINVAL);
378  goto exit;
379  }
380 
381  err = vmaf_model_feature_overload(s->model[i], feature_name,
382  feature_opts_dict);
383  if (err) {
385  "could not overload feature: %s\n", feature_name);
386  err = AVERROR(EINVAL);
387  goto exit;
388  }
389  }
390  }
391 
392  for (unsigned i = 0; i < s->model_cnt; i++) {
393  err = vmaf_use_features_from_model(s->vmaf, s->model[i]);
394  if (err) {
396  "problem during vmaf_use_features_from_model\n");
397  err = AVERROR(EINVAL);
398  goto exit;
399  }
400  }
401 
402 exit:
403  for (unsigned i = 0; i < dict_cnt; i++) {
404  if (dict[i])
405  av_dict_free(&dict[i]);
406  }
407  av_free(dict);
408  return err;
409 }
410 
411 static enum VmafLogLevel log_level_map(int log_level)
412 {
413  switch (log_level) {
414  case AV_LOG_QUIET:
415  return VMAF_LOG_LEVEL_NONE;
416  case AV_LOG_ERROR:
417  return VMAF_LOG_LEVEL_ERROR;
418  case AV_LOG_WARNING:
419  return VMAF_LOG_LEVEL_WARNING;
420  case AV_LOG_INFO:
421  return VMAF_LOG_LEVEL_INFO;
422  case AV_LOG_DEBUG:
423  return VMAF_LOG_LEVEL_DEBUG;
424  default:
425  return VMAF_LOG_LEVEL_INFO;
426  }
427 }
428 
430 {
431  LIBVMAFContext *s = ctx->priv;
432  int err = 0;
433 
434  VmafConfiguration cfg = {
435  .log_level = log_level_map(av_log_get_level()),
436  .n_subsample = s->n_subsample,
437  .n_threads = s->n_threads,
438  };
439 
440  err = vmaf_init(&s->vmaf, cfg);
441  if (err)
442  return AVERROR(EINVAL);
443 
444  err = parse_models(ctx);
445  if (err)
446  return err;
447 
448  err = parse_features(ctx);
449  if (err)
450  return err;
451 
452  s->fs.on_event = do_vmaf;
453  return 0;
454 }
455 
456 static const enum AVPixelFormat pix_fmts[] = {
462 };
463 
465 {
466  AVFilterContext *ctx = inlink->dst;
467  LIBVMAFContext *s = ctx->priv;
468  const AVPixFmtDescriptor *desc;
469  int err = 0;
470 
471  if (ctx->inputs[0]->w != ctx->inputs[1]->w) {
472  av_log(ctx, AV_LOG_ERROR, "input width must match.\n");
473  err |= AVERROR(EINVAL);
474  }
475 
476  if (ctx->inputs[0]->h != ctx->inputs[1]->h) {
477  av_log(ctx, AV_LOG_ERROR, "input height must match.\n");
478  err |= AVERROR(EINVAL);
479  }
480 
481  if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
482  av_log(ctx, AV_LOG_ERROR, "input pix_fmt must match.\n");
483  err |= AVERROR(EINVAL);
484  }
485 
486  if (err)
487  return err;
488 
489  desc = av_pix_fmt_desc_get(inlink->format);
490  s->bpc = desc->comp[0].depth;
491 
492  return 0;
493 }
494 
495 static int config_output(AVFilterLink *outlink)
496 {
497  AVFilterContext *ctx = outlink->src;
498  LIBVMAFContext *s = ctx->priv;
499  AVFilterLink *mainlink = ctx->inputs[0];
500  int ret;
501 
503  if (ret < 0)
504  return ret;
505  outlink->w = mainlink->w;
506  outlink->h = mainlink->h;
507  outlink->time_base = mainlink->time_base;
508  outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
509  outlink->frame_rate = mainlink->frame_rate;
510  if ((ret = ff_framesync_configure(&s->fs)) < 0)
511  return ret;
512 
513  return 0;
514 }
515 
517 {
518  LIBVMAFContext *s = ctx->priv;
519  return ff_framesync_activate(&s->fs);
520 }
521 
522 static enum VmafOutputFormat log_fmt_map(const char *log_fmt)
523 {
524  if (log_fmt) {
525  if (!strcmp(log_fmt, "xml"))
526  return VMAF_OUTPUT_FORMAT_XML;
527  if (!strcmp(log_fmt, "json"))
528  return VMAF_OUTPUT_FORMAT_JSON;
529  if (!strcmp(log_fmt, "csv"))
530  return VMAF_OUTPUT_FORMAT_CSV;
531  if (!strcmp(log_fmt, "sub"))
532  return VMAF_OUTPUT_FORMAT_SUB;
533  }
534 
535  return VMAF_OUTPUT_FORMAT_XML;
536 }
537 
538 static enum VmafPoolingMethod pool_method_map(const char *pool_method)
539 {
540  if (pool_method) {
541  if (!strcmp(pool_method, "min"))
542  return VMAF_POOL_METHOD_MIN;
543  if (!strcmp(pool_method, "mean"))
544  return VMAF_POOL_METHOD_MEAN;
545  if (!strcmp(pool_method, "harmonic_mean"))
546  return VMAF_POOL_METHOD_HARMONIC_MEAN;
547  }
548 
549  return VMAF_POOL_METHOD_MEAN;
550 }
551 
553 {
554  LIBVMAFContext *s = ctx->priv;
555  int err = 0;
556 
557  ff_framesync_uninit(&s->fs);
558 
559  if (!s->frame_cnt)
560  goto clean_up;
561 
562  err = vmaf_read_pictures(s->vmaf, NULL, NULL, 0);
563  if (err) {
565  "problem flushing libvmaf context.\n");
566  }
567 
568  for (unsigned i = 0; i < s->model_cnt; i++) {
569  double vmaf_score;
570  err = vmaf_score_pooled(s->vmaf, s->model[i], pool_method_map(s->pool),
571  &vmaf_score, 0, s->frame_cnt - 1);
572  if (err) {
574  "problem getting pooled vmaf score.\n");
575  }
576 
577  av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n", vmaf_score);
578  }
579 
580  if (s->vmaf) {
581  if (s->log_path && !err)
582  vmaf_write_output(s->vmaf, s->log_path, log_fmt_map(s->log_fmt));
583  }
584 
585 clean_up:
586  if (s->model) {
587  for (unsigned i = 0; i < s->model_cnt; i++) {
588  if (s->model[i])
589  vmaf_model_destroy(s->model[i]);
590  }
591  av_free(s->model);
592  }
593 
594  if (s->vmaf)
595  vmaf_close(s->vmaf);
596 }
597 
598 static const AVFilterPad libvmaf_inputs[] = {
599  {
600  .name = "main",
601  .type = AVMEDIA_TYPE_VIDEO,
602  },
603  {
604  .name = "reference",
605  .type = AVMEDIA_TYPE_VIDEO,
606  .config_props = config_input_ref,
607  },
608 };
609 
610 static const AVFilterPad libvmaf_outputs[] = {
611  {
612  .name = "default",
613  .type = AVMEDIA_TYPE_VIDEO,
614  .config_props = config_output,
615  },
616 };
617 
619  .name = "libvmaf",
620  .description = NULL_IF_CONFIG_SMALL("Calculate the VMAF between two video streams."),
621  .preinit = libvmaf_framesync_preinit,
622  .init = init,
623  .uninit = uninit,
624  .activate = activate,
625  .priv_size = sizeof(LIBVMAFContext),
626  .priv_class = &libvmaf_class,
630 };
631 
632 #if CONFIG_LIBVMAF_CUDA_FILTER
633 static const enum AVPixelFormat supported_formats[] = {
636 };
637 
638 static int format_is_supported(enum AVPixelFormat fmt)
639 {
640  int i;
641 
642  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
643  if (supported_formats[i] == fmt)
644  return 1;
645  return 0;
646 }
647 
648 static int config_props_cuda(AVFilterLink *outlink)
649 {
650  int err;
651  AVFilterContext *ctx = outlink->src;
652  LIBVMAFContext *s = ctx->priv;
653  AVFilterLink *inlink = ctx->inputs[0];
654  AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inlink->hw_frames_ctx->data;
655  AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
656  CUcontext cu_ctx = device_hwctx->cuda_ctx;
658 
659  VmafConfiguration cfg = {
660  .log_level = log_level_map(av_log_get_level()),
661  .n_subsample = s->n_subsample,
662  .n_threads = s->n_threads,
663  };
664 
665  VmafCudaPictureConfiguration cuda_pic_cfg = {
666  .pic_params = {
667  .bpc = desc->comp[0].depth,
668  .w = inlink->w,
669  .h = inlink->h,
670  .pix_fmt = pix_fmt_map(frames_ctx->sw_format),
671  },
672  .pic_prealloc_method = VMAF_CUDA_PICTURE_PREALLOCATION_METHOD_DEVICE,
673  };
674 
675  VmafCudaConfiguration cuda_cfg = {
676  .cu_ctx = cu_ctx,
677  };
678 
679  if (!format_is_supported(frames_ctx->sw_format)) {
681  "Unsupported input format: %s\n", desc->name);
682  return AVERROR(EINVAL);
683  }
684 
685  err = vmaf_init(&s->vmaf, cfg);
686  if (err)
687  return AVERROR(EINVAL);
688 
689  err = vmaf_cuda_state_init(&s->cu_state, cuda_cfg);
690  if (err)
691  return AVERROR(EINVAL);
692 
693  err = vmaf_cuda_import_state(s->vmaf, s->cu_state);
694  if (err)
695  return AVERROR(EINVAL);
696 
697  err = vmaf_cuda_preallocate_pictures(s->vmaf, cuda_pic_cfg);
698  if (err < 0)
699  return err;
700 
701  err = parse_models(ctx);
702  if (err)
703  return err;
704 
705  err = parse_features(ctx);
706  if (err)
707  return err;
708 
709  return config_output(outlink);
710 }
711 
712 static int copy_picture_data_cuda(VmafContext* vmaf,
713  AVCUDADeviceContext* device_hwctx,
714  AVFrame* src, VmafPicture* dst,
715  enum AVPixelFormat pix_fmt)
716 {
718  CudaFunctions *cu = device_hwctx->internal->cuda_dl;
719 
720  CUDA_MEMCPY2D m = {
721  .srcMemoryType = CU_MEMORYTYPE_DEVICE,
722  .dstMemoryType = CU_MEMORYTYPE_DEVICE,
723  };
724 
725  int err = vmaf_cuda_fetch_preallocated_picture(vmaf, dst);
726  if (err)
727  return AVERROR(ENOMEM);
728 
729  err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx);
730  if (err)
731  return AVERROR_EXTERNAL;
732 
733  for (unsigned i = 0; i < pix_desc->nb_components; i++) {
734  m.srcDevice = (CUdeviceptr) src->data[i];
735  m.srcPitch = src->linesize[i];
736  m.dstDevice = (CUdeviceptr) dst->data[i];
737  m.dstPitch = dst->stride[i];
738  m.WidthInBytes = dst->w[i] * ((dst->bpc + 7) / 8);
739  m.Height = dst->h[i];
740 
741  err = cu->cuMemcpy2D(&m);
742  if (err)
743  return AVERROR_EXTERNAL;
744  break;
745  }
746 
747  err = cu->cuCtxPopCurrent(NULL);
748  if (err)
749  return AVERROR_EXTERNAL;
750 
751  return 0;
752 }
753 
754 static int do_vmaf_cuda(FFFrameSync* fs)
755 {
756  AVFilterContext* ctx = fs->parent;
757  LIBVMAFContext* s = ctx->priv;
758  AVFilterLink *inlink = ctx->inputs[0];
759  AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inlink->hw_frames_ctx->data;
760  AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
761  VmafPicture pic_ref, pic_dist;
762  AVFrame *ref, *dist;
763 
764  int err = 0;
765 
766  err = ff_framesync_dualinput_get(fs, &dist, &ref);
767  if (err < 0)
768  return err;
769  if (ctx->is_disabled || !ref)
770  return ff_filter_frame(ctx->outputs[0], dist);
771 
772  err = copy_picture_data_cuda(s->vmaf, device_hwctx, ref, &pic_ref,
773  frames_ctx->sw_format);
774  if (err) {
775  av_log(s, AV_LOG_ERROR, "problem during copy_picture_data_cuda.\n");
776  return AVERROR(ENOMEM);
777  }
778 
779  err = copy_picture_data_cuda(s->vmaf, device_hwctx, dist, &pic_dist,
780  frames_ctx->sw_format);
781  if (err) {
782  av_log(s, AV_LOG_ERROR, "problem during copy_picture_data_cuda.\n");
783  return AVERROR(ENOMEM);
784  }
785 
786  err = vmaf_read_pictures(s->vmaf, &pic_ref, &pic_dist, s->frame_cnt++);
787  if (err) {
788  av_log(s, AV_LOG_ERROR, "problem during vmaf_read_pictures.\n");
789  return AVERROR(EINVAL);
790  }
791 
792  return ff_filter_frame(ctx->outputs[0], dist);
793 }
794 
795 static av_cold int init_cuda(AVFilterContext *ctx)
796 {
797  LIBVMAFContext *s = ctx->priv;
798  s->fs.on_event = do_vmaf_cuda;
799  return 0;
800 }
801 
802 static const AVFilterPad libvmaf_outputs_cuda[] = {
803  {
804  .name = "default",
805  .type = AVMEDIA_TYPE_VIDEO,
806  .config_props = config_props_cuda,
807  },
808 };
809 
811  .name = "libvmaf_cuda",
812  .description = NULL_IF_CONFIG_SMALL("Calculate the VMAF between two video streams."),
813  .preinit = libvmaf_framesync_preinit,
814  .init = init_cuda,
815  .uninit = uninit,
816  .activate = activate,
817  .priv_size = sizeof(LIBVMAFContext),
818  .priv_class = &libvmaf_class,
820  FILTER_OUTPUTS(libvmaf_outputs_cuda),
822  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
823 };
824 #endif
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:85
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:134
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVFrame::color_range
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition: frame.h:654
AV_PIX_FMT_CUDA
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition: pixfmt.h:260
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
hwcontext_cuda_internal.h
libvmaf_inputs
static const AVFilterPad libvmaf_inputs[]
Definition: vf_libvmaf.c:598
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:304
FF_FILTER_FLAG_HWFRAME_AWARE
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition: internal.h:351
AV_LOG_QUIET
#define AV_LOG_QUIET
Print no output.
Definition: log.h:162
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1015
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2965
FILTER_PIXFMTS_ARRAY
#define FILTER_PIXFMTS_ARRAY(array)
Definition: internal.h:162
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
LIBVMAFContext
Definition: vf_libvmaf.c:49
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:375
pixdesc.h
log_fmt_map
static enum VmafOutputFormat log_fmt_map(const char *log_fmt)
Definition: vf_libvmaf.c:522
AVOption
AVOption.
Definition: opt.h:346
AV_PIX_FMT_YUV420P16LE
@ AV_PIX_FMT_YUV420P16LE
planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
Definition: pixfmt.h:128
AVDictionary
Definition: dict.c:34
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
FFFrameSync
Frame sync structure.
Definition: framesync.h:168
video.h
AV_PIX_FMT_YUV444P16LE
@ AV_PIX_FMT_YUV444P16LE
planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
Definition: pixfmt.h:132
formats.h
AV_PIX_FMT_YUV420P12LE
@ AV_PIX_FMT_YUV420P12LE
planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
Definition: pixfmt.h:268
fail
#define fail()
Definition: checkasm.h:179
LIBVMAFContext::fs
FFFrameSync fs
Definition: vf_libvmaf.c:51
LIBVMAFContext::n_subsample
int n_subsample
Definition: vf_libvmaf.c:56
AVCUDADeviceContext::cuda_ctx
CUcontext cuda_ctx
Definition: hwcontext_cuda.h:43
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:33
AV_PIX_FMT_YUV420P10LE
@ AV_PIX_FMT_YUV420P10LE
planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
Definition: pixfmt.h:156
AV_PIX_FMT_YUV444P12LE
@ AV_PIX_FMT_YUV444P12LE
planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
Definition: pixfmt.h:276
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:491
LIBVMAFContext::model
VmafModel ** model
Definition: vf_libvmaf.c:60
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demux_decode.c:41
ff_vf_libvmaf
const AVFilter ff_vf_libvmaf
Definition: vf_libvmaf.c:618
config_input_ref
static int config_input_ref(AVFilterLink *inlink)
Definition: vf_libvmaf.c:464
AVDictionaryEntry::key
char * key
Definition: dict.h:90
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:178
copy_picture_data
static int copy_picture_data(AVFrame *src, VmafPicture *dst, unsigned bpc)
Definition: vf_libvmaf.c:108
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:49
format_is_supported
static int format_is_supported(enum AVPixelFormat fmt)
Definition: vf_bilateral_cuda.c:143
LIBVMAFContext::model_cnt
unsigned model_cnt
Definition: vf_libvmaf.c:61
LIBVMAFContext::frame_cnt
unsigned frame_cnt
Definition: vf_libvmaf.c:62
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
FRAMESYNC_DEFINE_CLASS
FRAMESYNC_DEFINE_CLASS(libvmaf, LIBVMAFContext, fs)
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
AV_PIX_FMT_YUV444P10LE
@ AV_PIX_FMT_YUV444P10LE
planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
Definition: pixfmt.h:162
LIBVMAFContext::vmaf
VmafContext * vmaf
Definition: vf_libvmaf.c:59
ff_vf_libvmaf_cuda
const AVFilter ff_vf_libvmaf_cuda
activate
static int activate(AVFilterContext *ctx)
Definition: vf_libvmaf.c:516
av_color_range_name
const char * av_color_range_name(enum AVColorRange range)
Definition: pixdesc.c:3281
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:442
AV_PIX_FMT_YUV422P16LE
@ AV_PIX_FMT_YUV422P16LE
planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
Definition: pixfmt.h:130
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:210
do_vmaf
static int do_vmaf(FFFrameSync *fs)
Definition: vf_libvmaf.c:129
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:200
AVPixFmtDescriptor::nb_components
uint8_t nb_components
The number of components each pixel has, (1-4)
Definition: pixdesc.h:71
LIBVMAFContext::log_fmt
char * log_fmt
Definition: vf_libvmaf.c:53
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_libvmaf.c:552
LIBVMAFContext::feature_cfg
char * feature_cfg
Definition: vf_libvmaf.c:58
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: vf_libvmaf.c:456
pool_method_map
static enum VmafPoolingMethod pool_method_map(const char *pool_method)
Definition: vf_libvmaf.c:538
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_libvmaf.c:495
AVCUDADeviceContext::internal
AVCUDADeviceContextInternal * internal
Definition: hwcontext_cuda.h:45
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
ff_framesync_init_dualinput
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:375
AV_PIX_FMT_YUV422P10LE
@ AV_PIX_FMT_YUV422P10LE
planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
Definition: pixfmt.h:158
LIBVMAFContext::n_threads
int n_threads
Definition: vf_libvmaf.c:55
LIBVMAFContext::log_path
char * log_path
Definition: vf_libvmaf.c:52
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:223
supported_formats
static enum AVPixelFormat supported_formats[]
Definition: vf_bilateral_cuda.c:37
LIBVMAFContext::model_cfg
char * model_cfg
Definition: vf_libvmaf.c:57
version
version
Definition: libkvazaar.c:321
LIBVMAFContext::bpc
unsigned bpc
Definition: vf_libvmaf.c:63
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
delimited_dict_parse
static AVDictionary ** delimited_dict_parse(char *str, unsigned *cnt)
Definition: vf_libvmaf.c:172
internal.h
FILTER_SINGLE_PIXFMT
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition: internal.h:172
AVCUDADeviceContextInternal::cuda_dl
CudaFunctions * cuda_dl
Definition: hwcontext_cuda_internal.h:32
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
AVFilter
Filter definition.
Definition: avfilter.h:166
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:115
AVCUDADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_cuda.h:42
ret
ret
Definition: filter_design.txt:187
AVHWFramesContext::device_ctx
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:134
libvmaf_outputs
static const AVFilterPad libvmaf_outputs[]
Definition: vf_libvmaf.c:610
pix_fmt_map
static enum VmafPixelFormat pix_fmt_map(enum AVPixelFormat av_pix_fmt)
Definition: vf_libvmaf.c:85
framesync.h
libvmaf_options
static const AVOption libvmaf_options[]
Definition: vf_libvmaf.c:72
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
avfilter.h
av_dict_parse_string
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition: dict.c:200
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:112
LIBVMAFContext::pool
char * pool
Definition: vf_libvmaf.c:54
OFFSET
#define OFFSET(x)
Definition: vf_libvmaf.c:69
FLAGS
#define FLAGS
Definition: vf_libvmaf.c:70
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:78
AVFilterContext
An instance of a filter.
Definition: avfilter.h:407
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
desc
const char * desc
Definition: libsvtav1.c:75
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:77
mem.h
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_libvmaf.c:429
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVDictionaryEntry
Definition: dict.h:89
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
log_level_map
static enum VmafLogLevel log_level_map(int log_level)
Definition: vf_libvmaf.c:411
hwcontext.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
parse_models
static int parse_models(AVFilterContext *ctx)
Definition: vf_libvmaf.c:279
AVDictionaryEntry::value
char * value
Definition: dict.h:91
ff_framesync_activate
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:355
avstring.h
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:393
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
drawutils.h
parse_features
static int parse_features(AVFilterContext *ctx)
Definition: vf_libvmaf.c:224
AV_PIX_FMT_YUV422P12LE
@ AV_PIX_FMT_YUV422P12LE
planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
Definition: pixfmt.h:272
av_dict_iterate
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition: dict.c:44