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 #define HAVE_VULKAN_RENDERER 1
27 #else
28 #define HAVE_VULKAN_RENDERER 0
29 #endif
30 
31 #if HAVE_VULKAN_RENDERER
32 
33 #if defined(_WIN32) && !defined(VK_USE_PLATFORM_WIN32_KHR)
34 #define VK_USE_PLATFORM_WIN32_KHR
35 #endif
36 
37 #include <libplacebo/vulkan.h>
38 #include <libplacebo/utils/frame_queue.h>
39 #include <libplacebo/utils/libav.h>
40 #include <SDL_vulkan.h>
41 
42 #include "libavutil/bprint.h"
43 #include "libavutil/mem.h"
44 #include "libavutil/internal.h"
45 
46 #endif
47 
48 struct VkRenderer {
49  const AVClass *class;
50 
51  int (*create)(VkRenderer *renderer, SDL_Window *window, AVDictionary *dict);
52 
54 
56 
57  int (*resize)(VkRenderer *renderer, int width, int height);
58 
60 };
61 
62 #if HAVE_VULKAN_RENDERER
63 
64 typedef struct RendererContext {
65  VkRenderer api;
66 
67  // Can be NULL when vulkan instance is created by avutil
68  pl_vk_inst placebo_instance;
69  pl_vulkan placebo_vulkan;
70  pl_swapchain swapchain;
71  VkSurfaceKHR vk_surface;
72  pl_renderer renderer;
73  pl_tex tex[4];
74 
75  pl_log vk_log;
76 
77  AVBufferRef *hw_device_ref;
78  AVBufferRef *hw_frame_ref;
79  enum AVPixelFormat *transfer_formats;
80  AVHWFramesConstraints *constraints;
81 
82  PFN_vkGetInstanceProcAddr get_proc_addr;
83  // This field is a copy from pl_vk_inst->instance or hw_device_ref instance.
84  VkInstance inst;
85 
86  AVFrame *vk_frame;
87 } RendererContext;
88 
89 static void vk_log_cb(void *log_priv, enum pl_log_level level,
90  const char *msg)
91 {
92  static const int level_map[] = {
100  };
101 
102  if (level > 0 && level < FF_ARRAY_ELEMS(level_map))
103  av_log(log_priv, level_map[level], "%s\n", msg);
104 }
105 
106 static inline int enable_debug(const AVDictionary *opt)
107 {
108  AVDictionaryEntry *entry = av_dict_get(opt, "debug", NULL, 0);
109  int debug = entry && strtol(entry->value, NULL, 10);
110  return debug;
111 }
112 
113 static void hwctx_lock_queue(void *priv, uint32_t qf, uint32_t qidx)
114 {
115  AVHWDeviceContext *avhwctx = priv;
116  const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
117 #if FF_API_VULKAN_SYNC_QUEUES
119  hwctx->lock_queue(avhwctx, qf, qidx);
121 #endif
122 }
123 
124 static void hwctx_unlock_queue(void *priv, uint32_t qf, uint32_t qidx)
125 {
126  AVHWDeviceContext *avhwctx = priv;
127  const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
128 #if FF_API_VULKAN_SYNC_QUEUES
130  hwctx->unlock_queue(avhwctx, qf, qidx);
132 #endif
133 }
134 
135 static int add_instance_extension(const char **ext, unsigned num_ext,
136  const AVDictionary *opt,
137  AVDictionary **dict)
138 {
139  const char *inst_ext_key = "instance_extensions";
141  AVBPrint buf;
142  char *ext_list = NULL;
143  int ret;
144 
146  for (int i = 0; i < num_ext; i++) {
147  if (i)
148  av_bprintf(&buf, "+%s", ext[i]);
149  else
150  av_bprintf(&buf, "%s", ext[i]);
151  }
152 
153  entry = av_dict_get(opt, inst_ext_key, NULL, 0);
154  if (entry && entry->value && entry->value[0]) {
155  if (num_ext)
156  av_bprintf(&buf, "+");
157  av_bprintf(&buf, "%s", entry->value);
158  }
159 
160  ret = av_bprint_finalize(&buf, &ext_list);
161  if (ret < 0)
162  return ret;
163  return av_dict_set(dict, inst_ext_key, ext_list, AV_DICT_DONT_STRDUP_VAL);
164 }
165 
166 static int add_device_extension(const AVDictionary *opt,
167  AVDictionary **dict)
168 {
169  const char *dev_ext_key = "device_extensions";
171  AVBPrint buf;
172  char *ext_list = NULL;
173  int ret;
174 
176  av_bprintf(&buf, "%s", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
177  for (int i = 0; i < pl_vulkan_num_recommended_extensions; i++)
178  av_bprintf(&buf, "+%s", pl_vulkan_recommended_extensions[i]);
179 
180  entry = av_dict_get(opt, dev_ext_key, NULL, 0);
181  if (entry && entry->value && entry->value[0])
182  av_bprintf(&buf, "+%s", entry->value);
183 
184  ret = av_bprint_finalize(&buf, &ext_list);
185  if (ret < 0)
186  return ret;
187  return av_dict_set(dict, dev_ext_key, ext_list, AV_DICT_DONT_STRDUP_VAL);
188 }
189 
190 static const char *select_device(const AVDictionary *opt)
191 {
192  const AVDictionaryEntry *entry;
193 
194  entry = av_dict_get(opt, "device", NULL, 0);
195  if (entry)
196  return entry->value;
197  return NULL;
198 }
199 
200 static int create_vk_by_hwcontext(VkRenderer *renderer,
201  const char **ext, unsigned num_ext,
202  const AVDictionary *opt)
203 {
204  RendererContext *ctx = (RendererContext *) renderer;
205  AVHWDeviceContext *dev;
206  AVVulkanDeviceContext *hwctx;
207  AVDictionary *dict = NULL;
208  int ret;
209 
210  ret = add_instance_extension(ext, num_ext, opt, &dict);
211  if (ret < 0)
212  return ret;
213  ret = add_device_extension(opt, &dict);
214  if (ret) {
215  av_dict_free(&dict);
216  return ret;
217  }
218 
220  select_device(opt), dict, 0);
221  av_dict_free(&dict);
222  if (ret < 0)
223  return ret;
224 
225  dev = (AVHWDeviceContext *) ctx->hw_device_ref->data;
226  hwctx = dev->hwctx;
227 
228  // There is no way to pass SDL GetInstanceProcAddr to hwdevice.
229  // Check the result and return error if they don't match.
230  if (hwctx->get_proc_addr != SDL_Vulkan_GetVkGetInstanceProcAddr()) {
232  "hwdevice and SDL use different get_proc_addr. "
233  "Try -vulkan_params create_by_placebo=1\n");
234  return AVERROR_PATCHWELCOME;
235  }
236 
237  ctx->get_proc_addr = hwctx->get_proc_addr;
238  ctx->inst = hwctx->inst;
239 
240  struct pl_vulkan_import_params import_params = {
241  .instance = hwctx->inst,
242  .get_proc_addr = hwctx->get_proc_addr,
243  .phys_device = hwctx->phys_dev,
244  .device = hwctx->act_dev,
245  .extensions = hwctx->enabled_dev_extensions,
246  .num_extensions = hwctx->nb_enabled_dev_extensions,
247  .features = &hwctx->device_features,
248  .lock_queue = hwctx_lock_queue,
249  .unlock_queue = hwctx_unlock_queue,
250  .queue_ctx = dev,
251  .queue_graphics = {
252  .index = VK_QUEUE_FAMILY_IGNORED,
253  .count = 0,
254  },
255  .queue_compute = {
256  .index = VK_QUEUE_FAMILY_IGNORED,
257  .count = 0,
258  },
259  .queue_transfer = {
260  .index = VK_QUEUE_FAMILY_IGNORED,
261  .count = 0,
262  },
263  };
264  for (int i = 0; i < hwctx->nb_qf; i++) {
265  const AVVulkanDeviceQueueFamily *qf = &hwctx->qf[i];
266 
267  if (qf->flags & VK_QUEUE_GRAPHICS_BIT) {
268  import_params.queue_graphics.index = qf->idx;
269  import_params.queue_graphics.count = qf->num;
270  }
271  if (qf->flags & VK_QUEUE_COMPUTE_BIT) {
272  import_params.queue_compute.index = qf->idx;
273  import_params.queue_compute.count = qf->num;
274  }
275  if (qf->flags & VK_QUEUE_TRANSFER_BIT) {
276  import_params.queue_transfer.index = qf->idx;
277  import_params.queue_transfer.count = qf->num;
278  }
279  }
280 
281  ctx->placebo_vulkan = pl_vulkan_import(ctx->vk_log, &import_params);
282  if (!ctx->placebo_vulkan)
283  return AVERROR_EXTERNAL;
284 
285  return 0;
286 }
287 
288 static void placebo_lock_queue(struct AVHWDeviceContext *dev_ctx,
289  uint32_t queue_family, uint32_t index)
290 {
291  RendererContext *ctx = dev_ctx->user_opaque;
292  pl_vulkan vk = ctx->placebo_vulkan;
293 #if FF_API_VULKAN_SYNC_QUEUES
295  vk->lock_queue(vk, queue_family, index);
297 #endif
298 }
299 
300 static void placebo_unlock_queue(struct AVHWDeviceContext *dev_ctx,
301  uint32_t queue_family,
302  uint32_t index)
303 {
304  RendererContext *ctx = dev_ctx->user_opaque;
305  pl_vulkan vk = ctx->placebo_vulkan;
306 #if FF_API_VULKAN_SYNC_QUEUES
308  vk->unlock_queue(vk, queue_family, index);
310 #endif
311 }
312 
313 static int get_decode_queue(VkRenderer *renderer, int *index, int *count)
314 {
315  RendererContext *ctx = (RendererContext *) renderer;
316  VkQueueFamilyProperties *queue_family_prop = NULL;
317  uint32_t num_queue_family_prop = 0;
318  PFN_vkGetPhysicalDeviceQueueFamilyProperties get_queue_family_prop;
319  PFN_vkGetInstanceProcAddr get_proc_addr = ctx->get_proc_addr;
320 
321  *index = -1;
322  *count = 0;
323  get_queue_family_prop = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)
324  get_proc_addr(ctx->placebo_instance->instance,
325  "vkGetPhysicalDeviceQueueFamilyProperties");
326  get_queue_family_prop(ctx->placebo_vulkan->phys_device,
327  &num_queue_family_prop, NULL);
328  if (!num_queue_family_prop)
329  return AVERROR_EXTERNAL;
330 
331  queue_family_prop = av_calloc(num_queue_family_prop,
332  sizeof(*queue_family_prop));
333  if (!queue_family_prop)
334  return AVERROR(ENOMEM);
335 
336  get_queue_family_prop(ctx->placebo_vulkan->phys_device,
337  &num_queue_family_prop,
338  queue_family_prop);
339 
340  for (int i = 0; i < num_queue_family_prop; i++) {
341  if (queue_family_prop[i].queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
342  *index = i;
343  *count = queue_family_prop[i].queueCount;
344  break;
345  }
346  }
347  av_free(queue_family_prop);
348 
349  return 0;
350 }
351 
352 static int create_vk_by_placebo(VkRenderer *renderer,
353  const char **ext, unsigned num_ext,
354  const AVDictionary *opt)
355 {
356  RendererContext *ctx = (RendererContext *) renderer;
357  AVHWDeviceContext *device_ctx;
358  AVVulkanDeviceContext *vk_dev_ctx;
359  int decode_index;
360  int decode_count;
361  int ret;
362  const char **dev_exts;
363  int num_dev_exts;
364 
365  ctx->get_proc_addr = SDL_Vulkan_GetVkGetInstanceProcAddr();
366 
367  ctx->placebo_instance = pl_vk_inst_create(ctx->vk_log, pl_vk_inst_params(
368  .get_proc_addr = ctx->get_proc_addr,
369  .debug = enable_debug(opt),
370  .extensions = ext,
371  .num_extensions = num_ext
372  ));
373  if (!ctx->placebo_instance) {
374  return AVERROR_EXTERNAL;
375  }
376  ctx->inst = ctx->placebo_instance->instance;
377 
378  dev_exts = av_vk_get_optional_device_extensions(&num_dev_exts);
379  if (!dev_exts)
380  return AVERROR(ENOMEM);
381 
382  ctx->placebo_vulkan = pl_vulkan_create(ctx->vk_log, pl_vulkan_params(
383  .instance = ctx->placebo_instance->instance,
384  .get_proc_addr = ctx->placebo_instance->get_proc_addr,
385  .surface = ctx->vk_surface,
386  .allow_software = false,
387  .opt_extensions = dev_exts,
388  .num_opt_extensions = num_dev_exts,
389  .extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
390  .device_name = select_device(opt),
391  ));
392  av_free(dev_exts);
393  if (!ctx->placebo_vulkan)
394  return AVERROR_EXTERNAL;
396  if (!ctx->hw_device_ref) {
397  return AVERROR(ENOMEM);
398  }
399 
400  device_ctx = (AVHWDeviceContext *) ctx->hw_device_ref->data;
401  device_ctx->user_opaque = ctx;
402 
403  vk_dev_ctx = device_ctx->hwctx;
406  vk_dev_ctx->lock_queue = placebo_lock_queue;
407  vk_dev_ctx->unlock_queue = placebo_unlock_queue;
409 #endif
410 
411  vk_dev_ctx->get_proc_addr = ctx->placebo_instance->get_proc_addr;
412 
413  vk_dev_ctx->inst = ctx->placebo_instance->instance;
414  vk_dev_ctx->phys_dev = ctx->placebo_vulkan->phys_device;
415  vk_dev_ctx->act_dev = ctx->placebo_vulkan->device;
416 
417  vk_dev_ctx->device_features = *ctx->placebo_vulkan->features;
418 
419  vk_dev_ctx->enabled_inst_extensions = ctx->placebo_instance->extensions;
420  vk_dev_ctx->nb_enabled_inst_extensions = ctx->placebo_instance->num_extensions;
421 
422  vk_dev_ctx->enabled_dev_extensions = ctx->placebo_vulkan->extensions;
423  vk_dev_ctx->nb_enabled_dev_extensions = ctx->placebo_vulkan->num_extensions;
424 
425  int nb_qf = 0;
426  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
427  .idx = ctx->placebo_vulkan->queue_graphics.index,
428  .num = ctx->placebo_vulkan->queue_graphics.count,
429  .flags = VK_QUEUE_GRAPHICS_BIT,
430  };
431  nb_qf++;
432  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
433  .idx = ctx->placebo_vulkan->queue_transfer.index,
434  .num = ctx->placebo_vulkan->queue_transfer.count,
435  .flags = VK_QUEUE_TRANSFER_BIT,
436  };
437  nb_qf++;
438  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
439  .idx = ctx->placebo_vulkan->queue_compute.index,
440  .num = ctx->placebo_vulkan->queue_compute.count,
441  .flags = VK_QUEUE_COMPUTE_BIT,
442  };
443  nb_qf++;
444 
445  ret = get_decode_queue(renderer, &decode_index, &decode_count);
446  if (ret < 0)
447  return ret;
448 
449  vk_dev_ctx->qf[nb_qf] = (AVVulkanDeviceQueueFamily) {
450  .idx = decode_index,
451  .num = decode_count,
452  .flags = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
453  };
454  nb_qf++;
455 
456  vk_dev_ctx->nb_qf = nb_qf;
457 
458  ret = av_hwdevice_ctx_init(ctx->hw_device_ref);
459  if (ret < 0)
460  return ret;
461 
462  return 0;
463 }
464 
465 static int create(VkRenderer *renderer, SDL_Window *window, AVDictionary *opt)
466 {
467  int ret = 0;
468  unsigned num_ext = 0;
469  const char **ext = NULL;
470  int w, h;
471  struct pl_log_params vk_log_params = {
472  .log_cb = vk_log_cb,
473  .log_level = PL_LOG_DEBUG,
474  .log_priv = renderer,
475  };
476  RendererContext *ctx = (RendererContext *) renderer;
478 
479  ctx->vk_log = pl_log_create(PL_API_VER, &vk_log_params);
480 
481  if (!SDL_Vulkan_GetInstanceExtensions(window, &num_ext, NULL)) {
482  av_log(NULL, AV_LOG_FATAL, "Failed to get vulkan extensions: %s\n",
483  SDL_GetError());
484  return AVERROR_EXTERNAL;
485  }
486 
487  ext = av_calloc(num_ext, sizeof(*ext));
488  if (!ext) {
489  ret = AVERROR(ENOMEM);
490  goto out;
491  }
492 
493  SDL_Vulkan_GetInstanceExtensions(window, &num_ext, ext);
494 
495  entry = av_dict_get(opt, "create_by_placebo", NULL, 0);
496  if (entry && strtol(entry->value, NULL, 10))
497  ret = create_vk_by_placebo(renderer, ext, num_ext, opt);
498  else
499  ret = create_vk_by_hwcontext(renderer, ext, num_ext, opt);
500  if (ret < 0)
501  goto out;
502 
503  if (!SDL_Vulkan_CreateSurface(window, ctx->inst, &ctx->vk_surface)) {
505  goto out;
506  }
507 
508  ctx->swapchain = pl_vulkan_create_swapchain(
509  ctx->placebo_vulkan,
510  pl_vulkan_swapchain_params(
511  .surface = ctx->vk_surface,
512  .present_mode = VK_PRESENT_MODE_FIFO_KHR));
513  if (!ctx->swapchain) {
515  goto out;
516  }
517 
518  SDL_Vulkan_GetDrawableSize(window, &w, &h);
519  pl_swapchain_resize(ctx->swapchain, &w, &h);
520 
521  ctx->renderer = pl_renderer_create(ctx->vk_log, ctx->placebo_vulkan->gpu);
522  if (!ctx->renderer) {
524  goto out;
525  }
526 
527  ctx->vk_frame = av_frame_alloc();
528  if (!ctx->vk_frame) {
529  ret = AVERROR(ENOMEM);
530  goto out;
531  }
532 
533  ret = 0;
534 
535 out:
536  av_free(ext);
537  return ret;
538 }
539 
540 static int get_hw_dev(VkRenderer *renderer, AVBufferRef **dev)
541 {
542  RendererContext *ctx = (RendererContext *) renderer;
543 
544  *dev = ctx->hw_device_ref;
545  return 0;
546 }
547 
548 static int create_hw_frame(VkRenderer *renderer, AVFrame *frame)
549 {
550  RendererContext *ctx = (RendererContext *) renderer;
551  AVHWFramesContext *src_hw_frame = (AVHWFramesContext *)
552  frame->hw_frames_ctx->data;
553  AVHWFramesContext *hw_frame;
554  AVVulkanFramesContext *vk_frame_ctx;
555  int ret;
556 
557  if (ctx->hw_frame_ref) {
558  hw_frame = (AVHWFramesContext *) ctx->hw_frame_ref->data;
559 
560  if (hw_frame->width == frame->width &&
561  hw_frame->height == frame->height &&
562  hw_frame->sw_format == src_hw_frame->sw_format)
563  return 0;
564 
565  av_buffer_unref(&ctx->hw_frame_ref);
566  }
567 
568  if (!ctx->constraints) {
570  ctx->hw_device_ref, NULL);
571  if (!ctx->constraints)
572  return AVERROR(ENOMEM);
573  }
574 
575  // Check constraints and skip create hwframe. Don't take it as error since
576  // we can fallback to memory copy from GPU to CPU.
577  if ((ctx->constraints->max_width &&
578  ctx->constraints->max_width < frame->width) ||
579  (ctx->constraints->max_height &&
580  ctx->constraints->max_height < frame->height) ||
581  (ctx->constraints->min_width &&
582  ctx->constraints->min_width > frame->width) ||
583  (ctx->constraints->min_height &&
584  ctx->constraints->min_height > frame->height))
585  return 0;
586 
587  if (ctx->constraints->valid_sw_formats) {
588  enum AVPixelFormat *sw_formats = ctx->constraints->valid_sw_formats;
589  while (*sw_formats != AV_PIX_FMT_NONE) {
590  if (*sw_formats == src_hw_frame->sw_format)
591  break;
592  sw_formats++;
593  }
594  if (*sw_formats == AV_PIX_FMT_NONE)
595  return 0;
596  }
597 
598  ctx->hw_frame_ref = av_hwframe_ctx_alloc(ctx->hw_device_ref);
599  if (!ctx->hw_frame_ref)
600  return AVERROR(ENOMEM);
601 
602  hw_frame = (AVHWFramesContext *) ctx->hw_frame_ref->data;
603  hw_frame->format = AV_PIX_FMT_VULKAN;
604  hw_frame->sw_format = src_hw_frame->sw_format;
605  hw_frame->width = frame->width;
606  hw_frame->height = frame->height;
607 
608  if (frame->format == AV_PIX_FMT_CUDA) {
609  vk_frame_ctx = hw_frame->hwctx;
610  vk_frame_ctx->flags = AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE;
611  }
612 
613  ret = av_hwframe_ctx_init(ctx->hw_frame_ref);
614  if (ret < 0) {
615  av_log(renderer, AV_LOG_ERROR, "Create hwframe context failed, %s\n",
616  av_err2str(ret));
617  return ret;
618  }
619 
620  av_hwframe_transfer_get_formats(ctx->hw_frame_ref,
622  &ctx->transfer_formats, 0);
623 
624  return 0;
625 }
626 
627 static inline int check_hw_transfer(RendererContext *ctx, AVFrame *frame)
628 {
629  if (!ctx->hw_frame_ref || !ctx->transfer_formats)
630  return 0;
631 
632  for (int i = 0; ctx->transfer_formats[i] != AV_PIX_FMT_NONE; i++)
633  if (ctx->transfer_formats[i] == frame->format)
634  return 1;
635 
636  return 0;
637 }
638 
639 static inline int move_to_output_frame(RendererContext *ctx, AVFrame *frame)
640 {
641  int ret = av_frame_copy_props(ctx->vk_frame, frame);
642  if (ret < 0)
643  return ret;
645  av_frame_move_ref(frame, ctx->vk_frame);
646  return 0;
647 }
648 
649 static int map_frame(VkRenderer *renderer, AVFrame *frame, int use_hw_frame)
650 {
651  RendererContext *ctx = (RendererContext *) renderer;
652  int ret;
653 
654  if (use_hw_frame && !ctx->hw_frame_ref)
655  return AVERROR(ENOSYS);
656 
657  // Try map data first
658  av_frame_unref(ctx->vk_frame);
659  if (use_hw_frame) {
660  ctx->vk_frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frame_ref);
661  ctx->vk_frame->format = AV_PIX_FMT_VULKAN;
662  }
663  ret = av_hwframe_map(ctx->vk_frame, frame, 0);
664  if (!ret)
665  return move_to_output_frame(ctx, frame);
666 
667  if (ret != AVERROR(ENOSYS))
668  av_log(NULL, AV_LOG_FATAL, "Map frame failed: %s\n", av_err2str(ret));
669  return ret;
670 }
671 
672 static int transfer_frame(VkRenderer *renderer, AVFrame *frame, int use_hw_frame)
673 {
674  RendererContext *ctx = (RendererContext *) renderer;
675  int ret;
676 
677  if (use_hw_frame && !check_hw_transfer(ctx, frame))
678  return AVERROR(ENOSYS);
679 
680  av_frame_unref(ctx->vk_frame);
681  if (use_hw_frame)
682  av_hwframe_get_buffer(ctx->hw_frame_ref, ctx->vk_frame, 0);
683  ret = av_hwframe_transfer_data(ctx->vk_frame, frame, 1);
684  if (!ret)
685  return move_to_output_frame(ctx, frame);
686 
687  if (ret != AVERROR(ENOSYS))
688  av_log(NULL, AV_LOG_FATAL, "Transfer frame failed: %s\n",
689  av_err2str(ret));
690  return ret;
691 }
692 
694 {
695  int ret;
696 
697  if (!frame->hw_frames_ctx)
698  return 0;
699 
700  if (frame->format == AV_PIX_FMT_VULKAN)
701  return 0;
702 
703  ret = create_hw_frame(renderer, frame);
704  if (ret < 0)
705  return ret;
706 
707  for (int use_hw = 1; use_hw >=0; use_hw--) {
708  ret = map_frame(renderer, frame, use_hw);
709  if (!ret)
710  return 0;
711  if (ret != AVERROR(ENOSYS))
712  return ret;
713 
714  ret = transfer_frame(renderer, frame, use_hw);
715  if (!ret)
716  return 0;
717  if (ret != AVERROR(ENOSYS))
718  return ret;
719  }
720 
721  return ret;
722 }
723 
724 static int display(VkRenderer *renderer, AVFrame *frame, RenderParams *params)
725 {
726  SDL_Rect *rect = &params->target_rect;
727  struct pl_swapchain_frame swap_frame = {0};
728  struct pl_frame pl_frame = {0};
729  struct pl_frame target = {0};
730  struct pl_render_params pl_params = pl_render_default_params;
731  RendererContext *ctx = (RendererContext *) renderer;
732  int ret = 0;
733  struct pl_color_space hint = {0};
734 
736  if (ret < 0)
737  return ret;
738 
739  if (!pl_map_avframe_ex(ctx->placebo_vulkan->gpu, &pl_frame, pl_avframe_params(
740  .frame = frame,
741  .tex = ctx->tex))) {
742  av_log(NULL, AV_LOG_ERROR, "pl_map_avframe_ex failed\n");
743  return AVERROR_EXTERNAL;
744  }
745 
746  pl_color_space_from_avframe(&hint, frame);
747  pl_swapchain_colorspace_hint(ctx->swapchain, &hint);
748  if (!pl_swapchain_start_frame(ctx->swapchain, &swap_frame)) {
749  av_log(NULL, AV_LOG_ERROR, "start frame failed\n");
751  goto out;
752  }
753 
754  pl_frame_from_swapchain(&target, &swap_frame);
755 
756  target.crop = (pl_rect2df){.x0 = rect->x, .x1 = rect->x + rect->w,
757  .y0 = rect->y, .y1 = rect->y + rect->h};
758  switch (params->video_background_type) {
760  pl_params.background = PL_CLEAR_TILES;
761  pl_params.tile_size = VIDEO_BACKGROUND_TILE_SIZE * 2;
762  break;
764  pl_params.background = PL_CLEAR_COLOR;
765  for (int i = 0; i < 3; i++)
766  pl_params.background_color[i] = params->video_background_color[i] / 255.0;
767  pl_params.background_transparency = (255 - params->video_background_color[3]) / 255.0;
768  break;
770  pl_frame.repr.alpha = PL_ALPHA_NONE;
771  break;
772  }
773 
774  if (!pl_render_image(ctx->renderer, &pl_frame, &target, &pl_params)) {
775  av_log(NULL, AV_LOG_ERROR, "pl_render_image failed\n");
777  goto out;
778  }
779 
780  if (!pl_swapchain_submit_frame(ctx->swapchain)) {
781  av_log(NULL, AV_LOG_ERROR, "pl_swapchain_submit_frame failed\n");
783  goto out;
784  }
785  pl_swapchain_swap_buffers(ctx->swapchain);
786 
787 out:
788  pl_unmap_avframe(ctx->placebo_vulkan->gpu, &pl_frame);
789  return ret;
790 }
791 
792 static int resize(VkRenderer *renderer, int width, int height)
793 {
794  RendererContext *ctx = (RendererContext *) renderer;
795 
796  if (!pl_swapchain_resize(ctx->swapchain, &width, &height))
797  return AVERROR_EXTERNAL;
798  return 0;
799 }
800 
801 static void destroy(VkRenderer *renderer)
802 {
803  RendererContext *ctx = (RendererContext *) renderer;
804  PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
805 
806  av_frame_free(&ctx->vk_frame);
807  av_freep(&ctx->transfer_formats);
808  av_hwframe_constraints_free(&ctx->constraints);
809  av_buffer_unref(&ctx->hw_frame_ref);
810 
811  if (ctx->placebo_vulkan) {
812  for (int i = 0; i < FF_ARRAY_ELEMS(ctx->tex); i++)
813  pl_tex_destroy(ctx->placebo_vulkan->gpu, &ctx->tex[i]);
814  pl_renderer_destroy(&ctx->renderer);
815  pl_swapchain_destroy(&ctx->swapchain);
816  pl_vulkan_destroy(&ctx->placebo_vulkan);
817  }
818 
819  if (ctx->vk_surface) {
820  vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)
821  ctx->get_proc_addr(ctx->inst, "vkDestroySurfaceKHR");
822  vkDestroySurfaceKHR(ctx->inst, ctx->vk_surface, NULL);
823  ctx->vk_surface = VK_NULL_HANDLE;
824  }
825 
826  av_buffer_unref(&ctx->hw_device_ref);
827  pl_vk_inst_destroy(&ctx->placebo_instance);
828 
829  pl_log_destroy(&ctx->vk_log);
830 }
831 
832 static const AVClass vulkan_renderer_class = {
833  .class_name = "Vulkan Renderer",
834  .item_name = av_default_item_name,
835  .version = LIBAVUTIL_VERSION_INT,
836 };
837 
839 {
840  RendererContext *ctx = av_mallocz(sizeof(*ctx));
842 
843  if (!ctx)
844  return NULL;
845 
846  renderer = &ctx->api;
847  renderer->class = &vulkan_renderer_class;
848  renderer->get_hw_dev = get_hw_dev;
849  renderer->create = create;
850  renderer->display = display;
851  renderer->resize = resize;
852  renderer->destroy = destroy;
853 
854  return renderer;
855 }
856 
857 #else
858 
860 {
861  return NULL;
862 }
863 
864 #endif
865 
867  AVDictionary *opt)
868 {
869  return renderer->create(renderer, window, opt);
870 }
871 
873 {
874  return renderer->get_hw_dev(renderer, dev);
875 }
876 
878 {
879  return renderer->display(renderer, frame, render_params);
880 }
881 
883 {
884  return renderer->resize(renderer, width, height);
885 }
886 
888 {
889  renderer->destroy(renderer);
890 }
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:67
VkRenderer::create
int(* create)(VkRenderer *renderer, SDL_Window *window, AVDictionary *dict)
Definition: ffplay_renderer.c:51
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:165
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:466
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:866
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:1089
vk_renderer_destroy
void vk_renderer_destroy(VkRenderer *renderer)
Definition: ffplay_renderer.c:887
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:776
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:137
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:129
AVVulkanFramesContext
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
Definition: hwcontext_vulkan.h:171
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:859
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:1465
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:872
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:48
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:149
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:148
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:53
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:882
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:59
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:1589
vk_renderer_display
int vk_renderer_display(VkRenderer *renderer, AVFrame *frame, RenderParams *render_params)
Definition: ffplay_renderer.c:877
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:66
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:55
FF_API_VULKAN_SYNC_QUEUES
#define FF_API_VULKAN_SYNC_QUEUES
Definition: version.h:111
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
level_map
static const uint8_t level_map[LCEVC_LogLevelCount]
Definition: lcevcdec.c:280
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:57
AV_HWFRAME_TRANSFER_DIRECTION_TO
@ AV_HWFRAME_TRANSFER_DIRECTION_TO
Transfer the data to the queried hw frame.
Definition: hwcontext.h:415