Skip to content

Instantly share code, notes, and snippets.

@cyanreg
Last active February 21, 2025 20:52
/* How to use any randomly retrieved VkImages in ffmpeg-related code. */
/* If you don't have a device initialized, but you have a VkDevice,
* you have to import it. */
{
AVBufferRef *ctx_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VULKAN);
AVHWDeviceContext *ctx = (AVHWDeviceContext *)ctx_ref->data;
AVVulkanDeviceContext *hwctx = ctx->hwctx;
/* Mandatory. */
hwctx->get_proc_addr = $PROC_ADDR_FN or vkGetInstanceProcAddr */
hwctx->act_dev = $VK_DEVICE;
hwctx->phys_dev = $VK_PHYSICAL_DEVICE;
hwctx->inst = $VK_INSTANCE;
hwctx->device_features = $STRUCT_WITH_ALL_FEATURES_ENABLED_AT_CREATION;
hwctx->qf[] = $ALL_ENABLED_QUEUES;
hwctx->nb_qf = $NUMBER_OF_ENABLED_QUEUES;
/* Optional. */
hwctx->lock_queue = $LOCK_QUEUE_FN;
hwctx->unlock_queue = $UNLOCK_QUEUE_FN;
av_hwdevice_ctx_init(ctx_ref);
}
/* Each hardware AVFrame requires a frame context.
* You should create one context once, and use it for
* each frame, rather than making a new context for each frame. */
{
AVBufferRef *frames_ref = av_hwframe_ctx_alloc($VULKAN_DEVICE_CONTEXT);
AVHWFramesContext *hwfc = (AVHWFramesContext *)frames_ref->data;
hwfc->format = AV_PIX_FMT_VULKAN;
hwfc->sw_format = AV_PIX_FMT_$FORMAT;
hwfc->width = $WIDTH;
hwfc->height = $HEIGHT:
AVVulkanFramesContext *vkfc = (AVVulkanFramesContext *)hwfc->hwctx;
vkfc->tiling = $VKIMAGE_TILING;
vkfc->nb_layers = 1;
vkfc->format[0] = $VKFORMAT_FOR_IMAGE;
/* If you have one VkImage per plane, set vkfc->format[1,2] to each format. */
/* The following two values are important. They determine what can be
* done with a frame. At minimum, to consume an image,
* TRANSFER_SRC and SAMPLE should be set. For multiplane images,
* img_flags should have EXTENDED_USAGE, and usage should contain the
* usage flags that all of the individual planes will have. */
vkfc->img_flags = $VKIMAGE_FLAGS;
vkfc->usage = $VKIMAGE_USAGE;
/* These should be called every time you need to look at
* vkf->access[], vkf->sem[], vkf->sem_value[], or any other field.
* Optional, if you don't set them, default ones will be used. */
vkfc->lock_frame = $LOCK_FRAME_FN;
vkfc->unlock_frame = $UNLOCK_FRAME_FN;
/* In general, if you don't know a field, you can try leaving it blank.
* lavu will try to maximize the use of a frame if a field is not set,
* and validation layers will complain, but it might work. */
av_hwframe_ctx_init(frames_ref);
}
/* Code ran for each frame: */
/* First, allocate an AVFrame */
AVFrame *f = av_frame_alloc();
f->pts = $PTS;
f->time_base = $TIME_BASE;
f->width = $WIDTH;
f->height = $HEIGHT;
f->format = AV_PIX_FMT_VULKAN;
/* Then, allocate an AVVkFrame for the Vulkan-specific data */
AVVkFrame *vkf = av_vk_frame_alloc();
f->data[0] = (uint8_t *)vkf;
/* Create a reference for the data */
AVBufferRef *vkf_ref = av_buffer_create((uint8_t *)vkf,
sizeof(vkf), /* Unimportant */
frame_free,
frame_free_context,
0);
/* You should set frame_free to a callback for when the frame is
* longer needed. */
f->buf[0] = vkf_ref;
{
/* AVFrame is now fully setup, now for AVVkFrame */
vkf->img[0] = $VKIMAGE;
/* If you don't know where it came from, you can make an educated guess.
* Validation layers will complain, but most GPUs and drivers ignore
* these for our purposes. */
vkf->access[0] = $CURRENT_VKIMAGE_ACCESS_MODE;
vkf->layout[0] = $CURRENT_VKIMAGE_LAYOUT_MODE;
vkf->queue_family[0] = $CURRENT_QUEUE_FAMILY;
/* If the image comes from a place without any semaphores,
* you need to create one via vkCreateSemaphore. */
vkf->sem[0] = $VKIMAGE_SEMAPHORE;
/* If the image comes with a semaphore, but you have no idea of its
* current value, make sure it isn't used anywhere else, then call
* vkQueueWaitIdle($CURRENT_QUEUE_FAMILY), then call
* vkGetSemaphoreCounterValue($VKIMAGE_SEMAPHORE). */
vkf->sem_value[0] = $VKIMAGE_SEMAPHORE_VALUE;
/* vkf->mem[] and vkf->size[] are ignored if you're the one allocating
* the VkImage. vkf->tiling is ignored and should be removed, as well
* as vkf->offset[] */
}
/* If you have one VkImage per plane, rather than one multiplane image
* per frame, repeat the above code, replacing [0] with 1, 2, etc. */
/* Finally, set the hw_frames_ctx for the frame. */
f->hw_frames_ctx = av_buffer_ref(frames_ref);
/* Done. */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment