Last active
February 21, 2025 20:52
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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