FFmpeg
ffplay_renderer.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #define VK_NO_PROTOTYPES
20 #define VK_ENABLE_BETA_EXTENSIONS
21 
22 #include "config.h"
23 #include "ffplay_renderer.h"
24 
25 #if (SDL_VERSION_ATLEAST(2, 0, 6) && CONFIG_LIBPLACEBO)
26 /* Get PL_API_VER */
27 #include <libplacebo/config.h>
28 #define HAVE_VULKAN_RENDERER (PL_API_VER >= 278)
29 #else
30 #define HAVE_VULKAN_RENDERER 0
31 #endif
32 
33 #if HAVE_VULKAN_RENDERER
34 
35 #if defined(_WIN32) && !defined(VK_USE_PLATFORM_WIN32_KHR)
36 #define VK_USE_PLATFORM_WIN32_KHR
37 #endif
38 
39 #include <libplacebo/vulkan.h>
40 #include <libplacebo/utils/frame_queue.h>
41 #include <libplacebo/utils/libav.h>
42 #include <SDL_vulkan.h>
43 
44 #include "libavutil/bprint.h"
45 #include "libavutil/mem.h"
46 #include "libavutil/internal.h"
47 
48 #endif
49 
50 struct VkRenderer {
51  const AVClass *class;
52 
53  int (*create)(VkRenderer *renderer, SDL_Window *window, AVDictionary *dict);
54 
56 
58 
59  int (*resize)(VkRenderer *renderer, int width, int height);
60 
62 };
63 
64 #if HAVE_VULKAN_RENDERER
65 
66 typedef struct RendererContext {
67  VkRenderer api;
68 
69  // Can be NULL when vulkan instance is created by avutil
70  pl_vk_inst placebo_instance;
71  pl_vulkan placebo_vulkan;
72  pl_swapchain swapchain;
73  VkSurfaceKHR vk_surface;
74  pl_renderer renderer;
75  pl_tex tex[4];
76 
77  pl_log vk_log;
78 
79  AVBufferRef *hw_device_ref;
80  AVBufferRef *hw_frame_ref;
81  enum AVPixelFormat *transfer_formats;
82  AVHWFramesConstraints *constraints;
83 
84  PFN_vkGetInstanceProcAddr get_proc_addr;
85  // This field is a copy from pl_vk_inst->instance or hw_device_ref instance.
86  VkInstance inst;
87 
88  AVFrame *vk_frame;
89 } RendererContext;
90 
91 static void vk_log_cb(void *log_priv, enum pl_log_level level,
92  const char *msg)
93 {
94  static const int level_map[] = {
100  AV_LOG_DEBUG,
101  AV_LOG_TRACE,
102  };
103 
104  if (level > 0 && level < FF_ARRAY_ELEMS(level_map))
105  av_log(log_priv, level_map[level], "%s\n", msg);
106 }
107 
108 static inline int enable_debug(const AVDictionary *opt)
109 {
110  AVDictionaryEntry *entry = av_dict_get(opt, "debug", NULL, 0);
111  int debug = entry && strtol(entry->value, NULL, 10);
112  return debug;
113 }
114 
115 static void hwctx_lock_queue(void *priv, uint32_t qf, uint32_t qidx)
116 {
117  AVHWDeviceContext *avhwctx = priv;
118  const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
119 #if FF_API_VULKAN_SYNC_QUEUES
121  hwctx->lock_queue(avhwctx, qf, qidx);
123 #endif
124 }
125 
126 static void hwctx_unlock_queue(void *priv, uint32_t qf, uint32_t qidx)
127 {
128  AVHWDeviceContext *avhwctx = priv;
129  const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
130 #if FF_API_VULKAN_SYNC_QUEUES
132  hwctx->unlock_queue(avhwctx, qf, qidx);
134 #endif
135 }
136 
137 static int add_instance_extension(const char **ext, unsigned num_ext,
138  const AVDictionary *opt,
139  AVDictionary **dict)
140 {
141  const char *inst_ext_key = "instance_extensions";
143  AVBPrint buf;
144  char *ext_list = NULL;
145  int ret;
146 
148  for (int i = 0; i < num_ext; i++) {
149  if (i)
150  av_bprintf(&buf, "+%s", ext[i]);
151  else
152  av_bprintf(&buf, "%s", ext[i]);
153  }
154 
155  entry = av_dict_get(opt, inst_ext_key, NULL, 0);
156  if (entry && entry->value && entry->value[0]) {
157  if (num_ext)
158  av_bprintf(&buf, "+");
159  av_bprintf(&buf, "%s", entry->value);
160  }
161 
162  ret = av_bprint_finalize(&buf, &ext_list);
163  if (ret < 0)
164  return ret;
165  return av_dict_set(dict, inst_ext_key, ext_list, AV_DICT_DONT_STRDUP_VAL);
166 }
167 
168 static int add_device_extension(const AVDictionary *opt,
169  AVDictionary **dict)
170 {
171  const char *dev_ext_key = "device_extensions";
173  AVBPrint buf;
174  char *ext_list = NULL;
175  int ret;
176 
178  av_bprintf(&buf, "%s", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
179  for (int i = 0; i < pl_vulkan_num_recommended_extensions; i++)
180  av_bprintf(&buf, "+%s", pl_vulkan_recommended_extensions[i]);
181 
182  entry = av_dict_get(opt, dev_ext_key, NULL, 0);
183  if (entry && entry->value && entry->value[0])
184  av_bprintf(&buf, "+%s", entry->value);
185 
186  ret = av_bprint_finalize(&buf, &ext_list);
187  if (ret < 0)
188  return ret;
189  return av_dict_set(dict, dev_ext_key, ext_list, AV_DICT_DONT_STRDUP_VAL);
190 }
191 
192 static const char *select_device(const AVDictionary *opt)
193 {
194  const AVDictionaryEntry *entry;
195 
196  entry = av_dict_get(opt, "device", NULL, 0);
197  if (entry)
198  return entry->value;
199  return NULL;
200 }
201 
202 static int create_vk_by_hwcontext(VkRenderer *renderer,
203  const char **ext, unsigned num_ext,
204  const AVDictionary *opt)
205 {
206  RendererContext *ctx = (RendererContext *) renderer;
207  AVHWDeviceContext *dev;
208  AVVulkanDeviceContext *hwctx;
209  AVDictionary *dict = NULL;
210  int ret;
211 
212  ret = add_instance_extension(ext, num_ext, opt, &dict);
213  if (ret < 0)
214  return ret;
215  ret = add_device_extension(opt, &dict);
216  if (ret) {
217  av_dict_free(&dict);
218  return ret;
219  }
220 
222  select_device(opt), dict, 0);
223  av_dict_free(&dict);
224  if (ret < 0)
225  return ret;
226 
227  dev = (AVHWDeviceContext *) ctx->hw_device_ref->data;
228  hwctx = dev->hwctx;
229 
230  // There is no way to pass SDL GetInstanceProcAddr to hwdevice.
231  // Check the result and return error if they don't match.
232  if (hwctx->get_proc_addr != SDL_Vulkan_GetVkGetInstanceProcAddr()) {
234  "hwdevice and SDL use different get_proc_addr. "
235  "Try -vulkan_params create_by_placebo=1\n");
236  return AVERROR_PATCHWELCOME;
237  }
238 
239  ctx->get_proc_addr = hwctx->get_proc_addr;
240  ctx->inst = hwctx->inst;
241 
242  struct pl_vulkan_import_params import_params = {
243  .instance = hwctx->inst,
244  .get_proc_addr = hwctx->get_proc_addr,
245  .phys_device = hwctx->phys_dev,
246  .device = hwctx->act_dev,
247  .extensions = hwctx->enabled_dev_extensions,
248  .num_extensions = hwctx->nb_enabled_dev_extensions,
249  .features = &hwctx->device_features,
250  .lock_queue = hwctx_lock_queue,
251  .unlock_queue = hwctx_unlock_queue,
252  .queue_ctx = dev,
253  .queue_graphics = {
254  .index = VK_QUEUE_FAMILY_IGNORED,
255  .count = 0,
256  },
257  .queue_compute = {
258  .index = VK_QUEUE_FAMILY_IGNORED,
259  .count = 0,
260  },
261  .queue_transfer = {
262  .index = VK_QUEUE_FAMILY_IGNORED,
263  .count = 0,
264  },
265  };
266  for (int i = 0; i < hwctx->nb_qf; i++) {
267  const AVVulkanDeviceQueueFamily *qf = &hwctx->qf[i];
268 
269  if (qf->flags & VK_QUEUE_GRAPHICS_BIT) {
270  import_params.queue_graphics.index = qf->idx;
271  import_params.queue_graphics.count = qf->num;
272  }
273  if (qf->flags & VK_QUEUE_COMPUTE_BIT) {
274  import_params.queue_compute.index = qf->idx;
275  import_params.queue_compute.count = qf->num;
276  }
277  if (qf->flags & VK_QUEUE_TRANSFER_BIT) {
278  import_params.queue_transfer.index = qf->idx;
279  import_params.queue_transfer.count = qf->num;
280  }
281  }
282 
283  ctx->placebo_vulkan = pl_vulkan_import(ctx->vk_log, &import_params);
284  if (!ctx->placebo_vulkan)
285  return AVERROR_EXTERNAL;
286 
287  return 0;
288 }
289 
290 static void placebo_lock_queue(struct AVHWDeviceContext *dev_ctx,
291  uint32_t queue_family, uint32_t index)
292 {
293  RendererContext *ctx = dev_ctx->user_opaque;
294  pl_vulkan vk = ctx->placebo_vulkan;
295 #if FF_API_VULKAN_SYNC_QUEUES
297  vk->lock_queue(vk, queue_family, index);
299 #endif
300 }
301 
302 static void placebo_unlock_queue(struct AVHWDeviceContext *dev_ctx,
303  uint32_t queue_family,
304  uint32_t index)
305 {
306  RendererContext *ctx = dev_ctx->user_opaque;
307  pl_vulkan vk = ctx->placebo_vulkan;
308 #if FF_API_VULKAN_SYNC_QUEUES
310  vk->unlock_queue(vk, queue_family, index);
312 #endif
313 }
314 
315 static int get_decode_queue(VkRenderer *renderer, int *index, int *count)
316 {
317  RendererContext *ctx = (RendererContext *) renderer;
318  VkQueueFamilyProperties *queue_family_prop = NULL;
319  uint32_t num_queue_family_prop = 0;
320  PFN_vkGetPhysicalDeviceQueueFamilyProperties get_queue_family_prop;
321  PFN_vkGetInstanceProcAddr get_proc_addr = ctx->get_proc_addr;
322 
323  *index = -1;
324  *count = 0;
325  get_queue_family_prop = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)
326  get_proc_addr(ctx->placebo_instance->instance,
327  "vkGetPhysicalDeviceQueueFamilyProperties");
328  get_queue_family_prop(ctx->placebo_vulkan->phys_device,
329  &num_queue_family_prop, NULL);
330  if (!num_queue_family_prop)
331  return AVERROR_EXTERNAL;
332 
333  queue_family_prop = av_calloc(num_queue_family_prop,
334  sizeof(*queue_family_prop));
335  if (!queue_family_prop)
336  return AVERROR(ENOMEM);
337 
338  get_queue_family_prop(ctx->placebo_vulkan->phys_device,
339  &num_queue_family_prop,
340  queue_family_prop);
341 
342  for (int i = 0; i < num_queue_family_prop; i++) {
343  if (queue_family_prop[i].queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
344  *index = i;
345  *count = queue_family_prop[i].queueCount;
346  break;
347  }
348  }
349  av_free(queue_family_prop);
350 
351  return 0;
352 }
353 
354 static int create_vk_by_placebo(VkRenderer *renderer,
355  const char **ext, unsigned num_ext,
356  const AVDictionary *opt)
357 {
358  RendererContext *ctx = (RendererContext *) renderer;
359  AVHWDeviceContext *device_ctx;
360  AVVulkanDeviceContext *vk_dev_ctx;
361  int decode_index;
362  int decode_count;
363  int ret;
364  const char **dev_exts;
365  int num_dev_exts;
366 
367  ctx->get_proc_addr = SDL_Vulkan_GetVkGetInstanceProcAddr();
368 
369  ctx->placebo_instance = pl_vk_inst_create(ctx->vk_log, pl_vk_inst_params(
370  .get_proc_addr = ctx->get_proc_addr,
371  .debug = enable_debug(opt),
372  .extensions = ext,
373  .num_extensions = num_ext
374  ));
375  if (!ctx->placebo_instance) {
376  return AVERROR_EXTERNAL;
377  }
378  ctx->inst = ctx->placebo_instance->instance;
379 
380  dev_exts = av_vk_get_optional_device_extensions(&num_dev_exts);
381  if (!dev_exts)
382  return AVERROR(ENOMEM);
383 
384  ctx->placebo_vulkan = pl_vulkan_create(ctx->vk_log, pl_vulkan_params(
385  .instance = ctx->placebo_instance->instance,
386  .get_proc_addr = ctx->placebo_instance->get_proc_addr,
387  .surface = ctx->vk_surface,
388  .allow_software = false,
389  .opt_extensions = dev_exts,
390  .num_opt_extensions = num_dev_exts,
391  .extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
392  .device_name = select_device(opt),
393  ));
394  av_free(dev_exts);
395  if (!ctx->placebo_vulkan)
396  return AVERROR_EXTERNAL;
398  if (!ctx->hw_device_ref) {
399  return AVERROR(ENOMEM);
400  }
401 
402  device_ctx = (AVHWDeviceContext *) ctx->hw_device_ref->data;
403  device_ctx->user_opaque = ctx;
404 
405  vk_dev_ctx = device_ctx->hwctx;
408  vk_dev_ctx->lock_queue = placebo_lock_queue;
409  vk_dev_ctx->unlock_queue = placebo_unlock_queue;
411 #endif
412 
413  vk_dev_ctx->get_proc_addr = ctx->placebo_instance->get_proc_addr;
414 
415  vk_dev_ctx->inst = ctx->placebo_instance->instance;
416  vk_dev_ctx->phys_dev = ctx->placebo_vulkan->phys_device;
417  vk_dev_ctx->act_dev = ctx->placebo_vulkan->device;
418 
419  vk_dev_ctx->device_features = *ctx->placebo_vulkan->features;
420 
421  vk_dev_ctx->enabled_inst_extensions = ctx->placebo_instance->extensions;
422  vk_dev_ctx->nb_enabled_inst_extensions = ctx->placebo_instance->num_extensions;
423 
424  vk_dev_ctx->enabled_dev_extensions = ctx->placebo_vulkan->extensions;
425  vk_dev_ctx->nb_enabled_dev_extensions = ctx->placebo_vulkan->num_extensions;
426 
427  int nb_qf = 0;
428  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
429  .idx = ctx->placebo_vulkan->queue_graphics.index,
430  .num = ctx->placebo_vulkan->queue_graphics.count,
431  .flags = VK_QUEUE_GRAPHICS_BIT,
432  };
433  nb_qf++;
434  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
435  .idx = ctx->placebo_vulkan->queue_transfer.index,
436  .num = ctx->placebo_vulkan->queue_transfer.count,
437  .flags = VK_QUEUE_TRANSFER_BIT,
438  };
439  nb_qf++;
440  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
441  .idx = ctx->placebo_vulkan->queue_compute.index,
442  .num = ctx->placebo_vulkan->queue_compute.count,
443  .flags = VK_QUEUE_COMPUTE_BIT,
444  };
445  nb_qf++;
446 
447  ret = get_decode_queue(renderer, &decode_index, &decode_count);
448  if (ret < 0)
449  return ret;
450 
451  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
452  .idx = decode_index,
453  .num = decode_count,
454  .flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
455  };
456  nb_qf++;
457 
458  vk_dev_ctx->nb_qf = nb_qf;
459 
460  ret = av_hwdevice_ctx_init(ctx->hw_device_ref);
461  if (ret < 0)
462  return ret;
463 
464  return 0;
465 }
466 
467 static int create(VkRenderer *renderer, SDL_Window *window, AVDictionary *opt)
468 {
469  int ret = 0;
470  unsigned num_ext = 0;
471  const char **ext = NULL;
472  int w, h;
473  struct pl_log_params vk_log_params = {
474  .log_cb = vk_log_cb,
475  .log_level = PL_LOG_DEBUG,
476  .log_priv = renderer,
477  };
478  RendererContext *ctx = (RendererContext *) renderer;
480 
481  ctx->vk_log = pl_log_create(PL_API_VER, &vk_log_params);
482 
483  if (!SDL_Vulkan_GetInstanceExtensions(window, &num_ext, NULL)) {
484  av_log(NULL, AV_LOG_FATAL, "Failed to get vulkan extensions: %s\n",
485  SDL_GetError());
486  return AVERROR_EXTERNAL;
487  }
488 
489  ext = av_calloc(num_ext, sizeof(*ext));
490  if (!ext) {
491  ret = AVERROR(ENOMEM);
492  goto out;
493  }
494 
495  SDL_Vulkan_GetInstanceExtensions(window, &num_ext, ext);
496 
497  entry = av_dict_get(opt, "create_by_placebo", NULL, 0);
498  if (entry && strtol(entry->value, NULL, 10))
499  ret = create_vk_by_placebo(renderer, ext, num_ext, opt);
500  else
501  ret = create_vk_by_hwcontext(renderer, ext, num_ext, opt);
502  if (ret < 0)
503  goto out;
504 
505  if (!SDL_Vulkan_CreateSurface(window, ctx->inst, &ctx->vk_surface)) {
507  goto out;
508  }
509 
510  ctx->swapchain = pl_vulkan_create_swapchain(
511  ctx->placebo_vulkan,
512  pl_vulkan_swapchain_params(
513  .surface = ctx->vk_surface,
514  .present_mode = VK_PRESENT_MODE_FIFO_KHR));
515  if (!ctx->swapchain) {
517  goto out;
518  }
519 
520  SDL_Vulkan_GetDrawableSize(window, &w, &h);
521  pl_swapchain_resize(ctx->swapchain, &w, &h);
522 
523  ctx->renderer = pl_renderer_create(ctx->vk_log, ctx->placebo_vulkan->gpu);
524  if (!ctx->renderer) {
526  goto out;
527  }
528 
529  ctx->vk_frame = av_frame_alloc();
530  if (!ctx->vk_frame) {
531  ret = AVERROR(ENOMEM);
532  goto out;
533  }
534 
535  ret = 0;
536 
537 out:
538  av_free(ext);
539  return ret;
540 }
541 
542 static int get_hw_dev(VkRenderer *renderer, AVBufferRef **dev)
543 {
544  RendererContext *ctx = (RendererContext *) renderer;
545 
546  *dev = ctx->hw_device_ref;
547  return 0;
548 }
549 
550 static int create_hw_frame(VkRenderer *renderer, AVFrame *frame)
551 {
552  RendererContext *ctx = (RendererContext *) renderer;
553  AVHWFramesContext *src_hw_frame = (AVHWFramesContext *)
554  frame->hw_frames_ctx->data;
555  AVHWFramesContext *hw_frame;
556  AVVulkanFramesContext *vk_frame_ctx;
557  int ret;
558 
559  if (ctx->hw_frame_ref) {
560  hw_frame = (AVHWFramesContext *) ctx->hw_frame_ref->data;
561 
562  if (hw_frame->width == frame->width &&
563  hw_frame->height == frame->height &&
564  hw_frame->sw_format == src_hw_frame->sw_format)
565  return 0;
566 
567  av_buffer_unref(&ctx->hw_frame_ref);
568  }
569 
570  if (!ctx->constraints) {
572  ctx->hw_device_ref, NULL);
573  if (!ctx->constraints)
574  return AVERROR(ENOMEM);
575  }
576 
577  // Check constraints and skip create hwframe. Don't take it as error since
578  // we can fallback to memory copy from GPU to CPU.
579  if ((ctx->constraints->max_width &&
580  ctx->constraints->max_width < frame->width) ||
581  (ctx->constraints->max_height &&
582  ctx->constraints->max_height < frame->height) ||
583  (ctx->constraints->min_width &&
584  ctx->constraints->min_width > frame->width) ||
585  (ctx->constraints->min_height &&
586  ctx->constraints->min_height > frame->height))
587  return 0;
588 
589  if (ctx->constraints->valid_sw_formats) {
590  enum AVPixelFormat *sw_formats = ctx->constraints->valid_sw_formats;
591  while (*sw_formats != AV_PIX_FMT_NONE) {
592  if (*sw_formats == src_hw_frame->sw_format)
593  break;
594  sw_formats++;
595  }
596  if (*sw_formats == AV_PIX_FMT_NONE)
597  return 0;
598  }
599 
600  ctx->hw_frame_ref = av_hwframe_ctx_alloc(ctx->hw_device_ref);
601  if (!ctx->hw_frame_ref)
602  return AVERROR(ENOMEM);
603 
604  hw_frame = (AVHWFramesContext *) ctx->hw_frame_ref->data;
605  hw_frame->format = AV_PIX_FMT_VULKAN;
606  hw_frame->sw_format = src_hw_frame->sw_format;
607  hw_frame->width = frame->width;
608  hw_frame->height = frame->height;
609 
610  if (frame->format == AV_PIX_FMT_CUDA) {
611  vk_frame_ctx = hw_frame->hwctx;
612  vk_frame_ctx->flags = AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE;
613  }
614 
615  ret = av_hwframe_ctx_init(ctx->hw_frame_ref);
616  if (ret < 0) {
617  av_log(renderer, AV_LOG_ERROR, "Create hwframe context failed, %s\n",
618  av_err2str(ret));
619  return ret;
620  }
621 
622  av_hwframe_transfer_get_formats(ctx->hw_frame_ref,
624  &ctx->transfer_formats, 0);
625 
626  return 0;
627 }
628 
629 static inline int check_hw_transfer(RendererContext *ctx, AVFrame *frame)
630 {
631  if (!ctx->hw_frame_ref || !ctx->transfer_formats)
632  return 0;
633 
634  for (int i = 0; ctx->transfer_formats[i] != AV_PIX_FMT_NONE; i++)
635  if (ctx->transfer_formats[i] == frame->format)
636  return 1;
637 
638  return 0;
639 }
640 
641 static inline int move_to_output_frame(RendererContext *ctx, AVFrame *frame)
642 {
643  int ret = av_frame_copy_props(ctx->vk_frame, frame);
644  if (ret < 0)
645  return ret;
647  av_frame_move_ref(frame, ctx->vk_frame);
648  return 0;
649 }
650 
651 static int map_frame(VkRenderer *renderer, AVFrame *frame, int use_hw_frame)
652 {
653  RendererContext *ctx = (RendererContext *) renderer;
654  int ret;
655 
656  if (use_hw_frame && !ctx->hw_frame_ref)
657  return AVERROR(ENOSYS);
658 
659  // Try map data first
660  av_frame_unref(ctx->vk_frame);
661  if (use_hw_frame) {
662  ctx->vk_frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frame_ref);
663  ctx->vk_frame->format = AV_PIX_FMT_VULKAN;
664  }
665  ret = av_hwframe_map(ctx->vk_frame, frame, 0);
666  if (!ret)
667  return move_to_output_frame(ctx, frame);
668 
669  if (ret != AVERROR(ENOSYS))
670  av_log(NULL, AV_LOG_FATAL, "Map frame failed: %s\n", av_err2str(ret));
671  return ret;
672 }
673 
674 static int transfer_frame(VkRenderer *renderer, AVFrame *frame, int use_hw_frame)
675 {
676  RendererContext *ctx = (RendererContext *) renderer;
677  int ret;
678 
679  if (use_hw_frame && !check_hw_transfer(ctx, frame))
680  return AVERROR(ENOSYS);
681 
682  av_frame_unref(ctx->vk_frame);
683  if (use_hw_frame)
684  av_hwframe_get_buffer(ctx->hw_frame_ref, ctx->vk_frame, 0);
685  ret = av_hwframe_transfer_data(ctx->vk_frame, frame, 1);
686  if (!ret)
687  return move_to_output_frame(ctx, frame);
688 
689  if (ret != AVERROR(ENOSYS))
690  av_log(NULL, AV_LOG_FATAL, "Transfer frame failed: %s\n",
691  av_err2str(ret));
692  return ret;
693 }
694 
696 {
697  int ret;
698 
699  if (!frame->hw_frames_ctx)
700  return 0;
701 
702  if (frame->format == AV_PIX_FMT_VULKAN)
703  return 0;
704 
705  ret = create_hw_frame(renderer, frame);
706  if (ret < 0)
707  return ret;
708 
709  for (int use_hw = 1; use_hw >=0; use_hw--) {
710  ret = map_frame(renderer, frame, use_hw);
711  if (!ret)
712  return 0;
713  if (ret != AVERROR(ENOSYS))
714  return ret;
715 
716  ret = transfer_frame(renderer, frame, use_hw);
717  if (!ret)
718  return 0;
719  if (ret != AVERROR(ENOSYS))
720  return ret;
721  }
722 
723  return ret;
724 }
725 
726 static int display(VkRenderer *renderer, AVFrame *frame, RenderParams *params)
727 {
728  SDL_Rect *rect = &params->target_rect;
729  struct pl_swapchain_frame swap_frame = {0};
730  struct pl_frame pl_frame = {0};
731  struct pl_frame target = {0};
732  struct pl_render_params pl_params = pl_render_default_params;
733  RendererContext *ctx = (RendererContext *) renderer;
734  int ret = 0;
735  struct pl_color_space hint = {0};
736 
738  if (ret < 0)
739  return ret;
740 
741  if (!pl_map_avframe_ex(ctx->placebo_vulkan->gpu, &pl_frame, pl_avframe_params(
742  .frame = frame,
743  .tex = ctx->tex))) {
744  av_log(NULL, AV_LOG_ERROR, "pl_map_avframe_ex failed\n");
745  return AVERROR_EXTERNAL;
746  }
747 
748  pl_color_space_from_avframe(&hint, frame);
749  pl_swapchain_colorspace_hint(ctx->swapchain, &hint);
750  if (!pl_swapchain_start_frame(ctx->swapchain, &swap_frame)) {
751  av_log(NULL, AV_LOG_ERROR, "start frame failed\n");
753  goto out;
754  }
755 
756  pl_frame_from_swapchain(&target, &swap_frame);
757 
758  target.crop = (pl_rect2df){.x0 = rect->x, .x1 = rect->x + rect->w,
759  .y0 = rect->y, .y1 = rect->y + rect->h};
760  switch (params->video_background_type) {
762  pl_params.background = PL_CLEAR_TILES;
763  pl_params.tile_size = VIDEO_BACKGROUND_TILE_SIZE * 2;
764  break;
766  pl_params.background = PL_CLEAR_COLOR;
767  for (int i = 0; i < 3; i++)
768  pl_params.background_color[i] = params->video_background_color[i] / 255.0;
769  pl_params.background_transparency = (255 - params->video_background_color[3]) / 255.0;
770  break;
772  pl_frame.repr.alpha = PL_ALPHA_NONE;
773  break;
774  }
775 
776  if (!pl_render_image(ctx->renderer, &pl_frame, &target, &pl_params)) {
777  av_log(NULL, AV_LOG_ERROR, "pl_render_image failed\n");
779  goto out;
780  }
781 
782  if (!pl_swapchain_submit_frame(ctx->swapchain)) {
783  av_log(NULL, AV_LOG_ERROR, "pl_swapchain_submit_frame failed\n");
785  goto out;
786  }
787  pl_swapchain_swap_buffers(ctx->swapchain);
788 
789 out:
790  pl_unmap_avframe(ctx->placebo_vulkan->gpu, &pl_frame);
791  return ret;
792 }
793 
794 static int resize(VkRenderer *renderer, int width, int height)
795 {
796  RendererContext *ctx = (RendererContext *) renderer;
797 
798  if (!pl_swapchain_resize(ctx->swapchain, &width, &height))
799  return AVERROR_EXTERNAL;
800  return 0;
801 }
802 
803 static void destroy(VkRenderer *renderer)
804 {
805  RendererContext *ctx = (RendererContext *) renderer;
806  PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
807 
808  av_frame_free(&ctx->vk_frame);
809  av_freep(&ctx->transfer_formats);
810  av_hwframe_constraints_free(&ctx->constraints);
811  av_buffer_unref(&ctx->hw_frame_ref);
812 
813  if (ctx->placebo_vulkan) {
814  for (int i = 0; i < FF_ARRAY_ELEMS(ctx->tex); i++)
815  pl_tex_destroy(ctx->placebo_vulkan->gpu, &ctx->tex[i]);
816  pl_renderer_destroy(&ctx->renderer);
817  pl_swapchain_destroy(&ctx->swapchain);
818  pl_vulkan_destroy(&ctx->placebo_vulkan);
819  }
820 
821  if (ctx->vk_surface) {
822  vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)
823  ctx->get_proc_addr(ctx->inst, "vkDestroySurfaceKHR");
824  vkDestroySurfaceKHR(ctx->inst, ctx->vk_surface, NULL);
825  ctx->vk_surface = VK_NULL_HANDLE;
826  }
827 
828  av_buffer_unref(&ctx->hw_device_ref);
829  pl_vk_inst_destroy(&ctx->placebo_instance);
830 
831  pl_log_destroy(&ctx->vk_log);
832 }
833 
834 static const AVClass vulkan_renderer_class = {
835  .class_name = "Vulkan Renderer",
836  .item_name = av_default_item_name,
837  .version = LIBAVUTIL_VERSION_INT,
838 };
839 
841 {
842  RendererContext *ctx = av_mallocz(sizeof(*ctx));
844 
845  if (!ctx)
846  return NULL;
847 
848  renderer = &ctx->api;
849  renderer->class = &vulkan_renderer_class;
850  renderer->get_hw_dev = get_hw_dev;
851  renderer->create = create;
852  renderer->display = display;
853  renderer->resize = resize;
854  renderer->destroy = destroy;
855 
856  return renderer;
857 }
858 
859 #else
860 
862 {
863  return NULL;
864 }
865 
866 #endif
867 
869  AVDictionary *opt)
870 {
871  return renderer->create(renderer, window, opt);
872 }
873 
875 {
876  return renderer->get_hw_dev(renderer, dev);
877 }
878 
880 {
881  return renderer->display(renderer, frame, render_params);
882 }
883 
885 {
886  return renderer->resize(renderer, width, height);
887 }
888 
890 {
891  renderer->destroy(renderer);
892 }
rect::w
int w
Definition: f_ebur128.c:78
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:88
VIDEO_BACKGROUND_TILE_SIZE
#define VIDEO_BACKGROUND_TILE_SIZE
Definition: ffplay_renderer.h:28
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
VkRenderer::create
int(* create)(VkRenderer *renderer, SDL_Window *window, AVDictionary *dict)
Definition: ffplay_renderer.c:53
AVVulkanDeviceContext::phys_dev
VkPhysicalDevice phys_dev
Physical device.
Definition: hwcontext_vulkan.h:79
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AV_PIX_FMT_CUDA
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition: pixfmt.h:260
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
convert_frame
static int convert_frame(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Convert a frame from linear RGB to logspace LAB, and accumulate channel totals for each row Convert f...
Definition: vf_grayworld.c:122
entry
#define entry
Definition: aom_film_grain_template.c:66
level
uint8_t level
Definition: svq3.c:208
VIDEO_BACKGROUND_TILES
@ VIDEO_BACKGROUND_TILES
Definition: ffplay_renderer.h:31
AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE
@ AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE
Definition: hwcontext_vulkan.h:214
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
out
static FILE * out
Definition: movenc.c:55
destroy
static void destroy(struct ResampleContext **c)
Definition: soxr_resample.c:64
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
AV_LOG_QUIET
#define AV_LOG_QUIET
Print no output.
Definition: log.h:192
ffplay_renderer.h
rect
Definition: f_ebur128.c:78
rect::y
int y
Definition: f_ebur128.c:78
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:337
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
AVVulkanDeviceContext::get_proc_addr
PFN_vkGetInstanceProcAddr get_proc_addr
Pointer to a vkGetInstanceProcAddr loading function.
Definition: hwcontext_vulkan.h:69
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:263
AVHWDeviceContext::user_opaque
void * user_opaque
Arbitrary user data, to be used e.g.
Definition: hwcontext.h:105
av_hwframe_map
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:793
vk_renderer_create
int vk_renderer_create(VkRenderer *renderer, SDL_Window *window, AVDictionary *opt)
Definition: ffplay_renderer.c:868
AVVulkanDeviceContext::inst
VkInstance inst
Vulkan instance.
Definition: hwcontext_vulkan.h:74
VIDEO_BACKGROUND_COLOR
@ VIDEO_BACKGROUND_COLOR
Definition: ffplay_renderer.h:32
AVDictionary
Definition: dict.c:32
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
map_frame
static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src, struct pl_frame *out)
Definition: vf_libplacebo.c:1163
vk_renderer_destroy
void vk_renderer_destroy(VkRenderer *renderer)
Definition: ffplay_renderer.c:889
av_hwdevice_get_hwframe_constraints
AVHWFramesConstraints * av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, const void *hwconfig)
Get the constraints on HW frames given a device and the HW-specific configuration to be used with tha...
Definition: hwcontext.c:581
av_hwdevice_ctx_init
int av_hwdevice_ctx_init(AVBufferRef *ref)
Finalize the device context before use.
Definition: hwcontext.c:223
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:379
av_vk_get_optional_device_extensions
const char ** av_vk_get_optional_device_extensions(int *count)
Returns an array of optional Vulkan device extensions that FFmpeg may use if enabled.
Definition: hwcontext_vulkan.c:753
AVVulkanDeviceContext::unlock_queue
attribute_deprecated void(* unlock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
Similar to lock_queue(), unlocks a queue.
Definition: hwcontext_vulkan.h:189
AV_HWDEVICE_TYPE_VULKAN
@ AV_HWDEVICE_TYPE_VULKAN
Definition: hwcontext.h:39
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:444
window
static SDL_Window * window
Definition: ffplay.c:364
AVVulkanDeviceContext::lock_queue
attribute_deprecated void(* lock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index)
Locks a queue, preventing other threads from submitting any command buffers to this queue.
Definition: hwcontext_vulkan.h:181
AVVulkanFramesContext
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
Definition: hwcontext_vulkan.h:220
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
AV_DICT_DONT_STRDUP_VAL
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition: dict.h:79
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:63
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:52
AVVulkanDeviceQueueFamily::num
int num
Definition: hwcontext_vulkan.h:37
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
vk_get_renderer
VkRenderer * vk_get_renderer(void)
Definition: ffplay_renderer.c:861
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
RenderParams::video_background_type
enum VideoBackgroundType video_background_type
Definition: ffplay_renderer.h:39
av_hwdevice_ctx_alloc
AVBufferRef * av_hwdevice_ctx_alloc(enum AVHWDeviceType type)
Allocate an AVHWDeviceContext for a given hardware type.
Definition: hwcontext.c:176
av_dict_get
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:60
av_hwframe_constraints_free
void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
Free an AVHWFrameConstraints structure.
Definition: hwcontext.c:606
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1414
decode_index
static int decode_index(SGAVideoContext *s, AVFrame *frame)
Definition: sga.c:181
RenderParams
Definition: ffplay_renderer.h:36
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
vk_renderer_get_hw_dev
int vk_renderer_get_hw_dev(VkRenderer *renderer, AVBufferRef **dev)
Definition: ffplay_renderer.c:874
renderer
static SDL_Renderer * renderer
Definition: ffplay.c:365
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
if
if(ret)
Definition: filter_design.txt:179
AVVulkanDeviceContext
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_vulkan.h:59
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
VkRenderer
Definition: ffplay_renderer.c:50
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
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:213
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:599
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
AVVulkanDeviceContext::nb_enabled_dev_extensions
int nb_enabled_dev_extensions
Definition: hwcontext_vulkan.h:117
create
static struct ResampleContext * create(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby, int exact_rational)
Definition: soxr_resample.c:32
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
AVVulkanDeviceContext::nb_qf
int nb_qf
Definition: hwcontext_vulkan.h:201
AVVulkanDeviceContext::enabled_inst_extensions
const char *const * enabled_inst_extensions
Enabled instance extensions.
Definition: hwcontext_vulkan.h:103
AVVulkanDeviceContext::qf
AVVulkanDeviceQueueFamily qf[64]
Queue families used.
Definition: hwcontext_vulkan.h:200
index
int index
Definition: gxfenc.c:90
RenderParams::target_rect
SDL_Rect target_rect
Definition: ffplay_renderer.h:37
height
#define height
Definition: dsp.h:89
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
rect::h
int h
Definition: f_ebur128.c:78
VkRenderer::get_hw_dev
int(* get_hw_dev)(VkRenderer *renderer, AVBufferRef **dev)
Definition: ffplay_renderer.c:55
AVVulkanDeviceQueueFamily::idx
int idx
Definition: hwcontext_vulkan.h:35
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:233
rect::x
int x
Definition: f_ebur128.c:78
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
bprint.h
internal.h
av_frame_move_ref
void av_frame_move_ref(AVFrame *dst, AVFrame *src)
Move everything contained in src to dst and reset src.
Definition: frame.c:523
vk_renderer_resize
int vk_renderer_resize(VkRenderer *renderer, int width, int height)
Definition: ffplay_renderer.c:884
av_frame_unref
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:496
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
ret
ret
Definition: filter_design.txt:187
AV_LOG_FATAL
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:204
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:81
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
VkRenderer::destroy
void(* destroy)(VkRenderer *renderer)
Definition: ffplay_renderer.c:61
av_hwdevice_ctx_create
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)
Open a device of the specified type and create an AVHWDeviceContext for it.
Definition: hwcontext.c:615
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
av_hwframe_transfer_data
int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
Copy data to or from a hw surface.
Definition: hwcontext.c:448
AVFormatContext::debug
int debug
Flags to enable debugging.
Definition: avformat.h:1538
vk_renderer_display
int vk_renderer_display(VkRenderer *renderer, AVFrame *frame, RenderParams *render_params)
Definition: ffplay_renderer.c:879
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
VIDEO_BACKGROUND_NONE
@ VIDEO_BACKGROUND_NONE
Definition: ffplay_renderer.h:33
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
av_hwframe_transfer_get_formats
int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats, int flags)
Get a list of possible source or target formats usable in av_hwframe_transfer_data().
Definition: hwcontext.c:386
AVVulkanDeviceContext::enabled_dev_extensions
const char *const * enabled_dev_extensions
Enabled device extensions.
Definition: hwcontext_vulkan.h:116
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
AVVulkanDeviceContext::act_dev
VkDevice act_dev
Active device.
Definition: hwcontext_vulkan.h:84
w
uint8_t w
Definition: llvidencdsp.c:39
AVVulkanDeviceContext::nb_enabled_inst_extensions
int nb_enabled_inst_extensions
Definition: hwcontext_vulkan.h:104
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:90
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
VkRenderer::display
int(* display)(VkRenderer *renderer, AVFrame *frame, RenderParams *params)
Definition: ffplay_renderer.c:57
FF_API_VULKAN_SYNC_QUEUES
#define FF_API_VULKAN_SYNC_QUEUES
Definition: version.h:116
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVVulkanDeviceQueueFamily
Definition: hwcontext_vulkan.h:33
RenderParams::video_background_color
uint8_t video_background_color[4]
Definition: ffplay_renderer.h:38
h
h
Definition: vp9dsp_template.c:2070
AVVulkanDeviceContext::device_features
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation.
Definition: hwcontext_vulkan.h:92
width
#define width
Definition: dsp.h:89
av_hwframe_get_buffer
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
Allocate a new frame attached to the given AVHWFramesContext.
Definition: hwcontext.c:506
AVVulkanDeviceQueueFamily::flags
VkQueueFlagBits flags
Definition: hwcontext_vulkan.h:41
VkRenderer::resize
int(* resize)(VkRenderer *renderer, int width, int height)
Definition: ffplay_renderer.c:59
AV_HWFRAME_TRANSFER_DIRECTION_TO
@ AV_HWFRAME_TRANSFER_DIRECTION_TO
Transfer the data to the queried hw frame.
Definition: hwcontext.h:415