FFmpeg
vf_scale_vulkan.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 #include "libavutil/random_seed.h"
20 #include "libavutil/opt.h"
21 #include "vulkan.h"
22 #include "scale_eval.h"
23 #include "internal.h"
24 #include "colorspace.h"
25 
26 #define CGROUPS (int [3]){ 32, 32, 1 }
27 
28 enum ScalerFunc {
31 
33 };
34 
35 typedef struct ScaleVulkanContext {
37 
42 
43  /* Shader updators, must be in the main filter struct */
44  VkDescriptorImageInfo input_images[3];
45  VkDescriptorImageInfo output_images[3];
46  VkDescriptorBufferInfo params_desc;
47 
51  char *w_expr;
52  char *h_expr;
54 
55 static const char scale_bilinear[] = {
56  C(0, vec4 scale_bilinear(int idx, ivec2 pos, vec2 crop_range, vec2 crop_off))
57  C(0, { )
58  C(1, vec2 npos = (vec2(pos) + 0.5f) / imageSize(output_img[idx]); )
59  C(1, npos *= crop_range; /* Reduce the range */ )
60  C(1, npos += crop_off; /* Offset the start */ )
61  C(1, return texture(input_img[idx], npos); )
62  C(0, } )
63 };
64 
65 static const char rgb2yuv[] = {
66  C(0, vec4 rgb2yuv(vec4 src, int fullrange) )
67  C(0, { )
68  C(1, src *= yuv_matrix; )
69  C(1, if (fullrange == 1) { )
70  C(2, src += vec4(0.0, 0.5, 0.5, 0.0); )
71  C(1, } else { )
72  C(2, src *= vec4(219.0 / 255.0, 224.0 / 255.0, 224.0 / 255.0, 1.0); )
73  C(2, src += vec4(16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0, 0.0); )
74  C(1, } )
75  C(1, return src; )
76  C(0, } )
77 };
78 
79 static const char write_nv12[] = {
80  C(0, void write_nv12(vec4 src, ivec2 pos) )
81  C(0, { )
82  C(1, imageStore(output_img[0], pos, vec4(src.r, 0.0, 0.0, 0.0)); )
83  C(1, pos /= ivec2(2); )
84  C(1, imageStore(output_img[1], pos, vec4(src.g, src.b, 0.0, 0.0)); )
85  C(0, } )
86 };
87 
88 static const char write_420[] = {
89  C(0, void write_420(vec4 src, ivec2 pos) )
90  C(0, { )
91  C(1, imageStore(output_img[0], pos, vec4(src.r, 0.0, 0.0, 0.0)); )
92  C(1, pos /= ivec2(2); )
93  C(1, imageStore(output_img[1], pos, vec4(src.g, 0.0, 0.0, 0.0)); )
94  C(1, imageStore(output_img[2], pos, vec4(src.b, 0.0, 0.0, 0.0)); )
95  C(0, } )
96 };
97 
98 static const char write_444[] = {
99  C(0, void write_444(vec4 src, ivec2 pos) )
100  C(0, { )
101  C(1, imageStore(output_img[0], pos, vec4(src.r, 0.0, 0.0, 0.0)); )
102  C(1, imageStore(output_img[1], pos, vec4(src.g, 0.0, 0.0, 0.0)); )
103  C(1, imageStore(output_img[2], pos, vec4(src.b, 0.0, 0.0, 0.0)); )
104  C(0, } )
105 };
106 
108 {
109  int err;
110  VkSampler *sampler;
111  VkFilter sampler_mode;
112  ScaleVulkanContext *s = ctx->priv;
113 
114  int crop_x = in->crop_left;
115  int crop_y = in->crop_top;
116  int crop_w = in->width - (in->crop_left + in->crop_right);
117  int crop_h = in->height - (in->crop_top + in->crop_bottom);
118 
120  s->vkctx.queue_count = GET_QUEUE_COUNT(s->vkctx.hwctx, 0, 1, 0);
122 
123  switch (s->scaler) {
124  case F_NEAREST:
125  sampler_mode = VK_FILTER_NEAREST;
126  break;
127  case F_BILINEAR:
128  sampler_mode = VK_FILTER_LINEAR;
129  break;
130  };
131 
132  /* Create a sampler */
133  sampler = ff_vk_init_sampler(ctx, 0, sampler_mode);
134  if (!sampler)
135  return AVERROR_EXTERNAL;
136 
137  s->pl = ff_vk_create_pipeline(ctx);
138  if (!s->pl)
139  return AVERROR(ENOMEM);
140 
141  { /* Create the shader */
142  VulkanDescriptorSetBinding desc_i[2] = {
143  {
144  .name = "input_img",
145  .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
146  .dimensions = 2,
148  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
149  .updater = s->input_images,
150  .samplers = DUP_SAMPLER_ARRAY4(*sampler),
151  },
152  {
153  .name = "output_img",
154  .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
155  .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
156  .mem_quali = "writeonly",
157  .dimensions = 2,
159  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
160  .updater = s->output_images,
161  },
162  };
163 
164  VulkanDescriptorSetBinding desc_b = {
165  .name = "params",
166  .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
167  .mem_quali = "readonly",
168  .mem_layout = "std430",
169  .stages = VK_SHADER_STAGE_COMPUTE_BIT,
170  .updater = &s->params_desc,
171  .buf_content = "mat4 yuv_matrix;",
172  };
173 
174  SPIRVShader *shd = ff_vk_init_shader(ctx, s->pl, "scale_compute",
175  VK_SHADER_STAGE_COMPUTE_BIT);
176  if (!shd)
177  return AVERROR(ENOMEM);
178 
180 
181  RET(ff_vk_add_descriptor_set(ctx, s->pl, shd, desc_i, 2, 0)); /* set 0 */
182  RET(ff_vk_add_descriptor_set(ctx, s->pl, shd, &desc_b, 1, 0)); /* set 0 */
183 
185 
186  if (s->vkctx.output_format != s->vkctx.input_format) {
187  GLSLD( rgb2yuv );
188  }
189 
190  switch (s->vkctx.output_format) {
191  case AV_PIX_FMT_NV12: GLSLD(write_nv12); break;
192  case AV_PIX_FMT_YUV420P: GLSLD( write_420); break;
193  case AV_PIX_FMT_YUV444P: GLSLD( write_444); break;
194  default: break;
195  }
196 
197  GLSLC(0, void main() );
198  GLSLC(0, { );
199  GLSLC(1, ivec2 size; );
200  GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
201  GLSLF(1, vec2 in_d = vec2(%i, %i); ,in->width, in->height);
202  GLSLF(1, vec2 c_r = vec2(%i, %i) / in_d; ,crop_w, crop_h);
203  GLSLF(1, vec2 c_o = vec2(%i, %i) / in_d; ,crop_x,crop_y);
204  GLSLC(0, );
205 
206  if (s->vkctx.output_format == s->vkctx.input_format) {
207  for (int i = 0; i < desc_i[1].elems; i++) {
208  GLSLF(1, size = imageSize(output_img[%i]); ,i);
209  GLSLC(1, if (IS_WITHIN(pos, size)) { );
210  switch (s->scaler) {
211  case F_NEAREST:
212  case F_BILINEAR:
213  GLSLF(2, vec4 res = scale_bilinear(%i, pos, c_r, c_o); ,i);
214  GLSLF(2, imageStore(output_img[%i], pos, res); ,i);
215  break;
216  };
217  GLSLC(1, } );
218  }
219  } else {
220  GLSLC(1, vec4 res = scale_bilinear(0, pos, c_r, c_o); );
221  GLSLF(1, res = rgb2yuv(res, %i); ,s->out_range == AVCOL_RANGE_JPEG);
222  switch (s->vkctx.output_format) {
223  case AV_PIX_FMT_NV12: GLSLC(1, write_nv12(res, pos); ); break;
224  case AV_PIX_FMT_YUV420P: GLSLC(1, write_420(res, pos); ); break;
225  case AV_PIX_FMT_YUV444P: GLSLC(1, write_444(res, pos); ); break;
226  default: return AVERROR(EINVAL);
227  }
228  }
229 
230  GLSLC(0, } );
231 
232  RET(ff_vk_compile_shader(ctx, shd, "main"));
233  }
234 
237 
238  if (s->vkctx.output_format != s->vkctx.input_format) {
239  const struct LumaCoefficients *lcoeffs;
240  double tmp_mat[3][3];
241 
242  struct {
243  float yuv_matrix[4][4];
244  } *par;
245 
246  lcoeffs = ff_get_luma_coefficients(in->colorspace);
247  if (!lcoeffs) {
248  av_log(ctx, AV_LOG_ERROR, "Unsupported colorspace\n");
249  return AVERROR(EINVAL);
250  }
251 
252  err = ff_vk_create_buf(ctx, &s->params_buf,
253  sizeof(*par),
254  VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
255  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
256  if (err)
257  return err;
258 
259  err = ff_vk_map_buffers(ctx, &s->params_buf, (uint8_t **)&par, 1, 0);
260  if (err)
261  return err;
262 
263  ff_fill_rgb2yuv_table(lcoeffs, tmp_mat);
264 
265  memset(par, 0, sizeof(*par));
266 
267  for (int y = 0; y < 3; y++)
268  for (int x = 0; x < 3; x++)
269  par->yuv_matrix[x][y] = tmp_mat[x][y];
270 
271  par->yuv_matrix[3][3] = 1.0;
272 
273  err = ff_vk_unmap_buffers(ctx, &s->params_buf, 1, 1);
274  if (err)
275  return err;
276 
277  s->params_desc.buffer = s->params_buf.buf;
278  s->params_desc.range = VK_WHOLE_SIZE;
279 
280  ff_vk_update_descriptor_set(ctx, s->pl, 1);
281  }
282 
283  /* Execution context */
284  RET(ff_vk_create_exec_ctx(ctx, &s->exec));
285 
286  s->initialized = 1;
287 
288  return 0;
289 
290 fail:
291  return err;
292 }
293 
294 static int process_frames(AVFilterContext *avctx, AVFrame *out_f, AVFrame *in_f)
295 {
296  int err = 0;
297  VkCommandBuffer cmd_buf;
298  ScaleVulkanContext *s = avctx->priv;
299  AVVkFrame *in = (AVVkFrame *)in_f->data[0];
300  AVVkFrame *out = (AVVkFrame *)out_f->data[0];
301  VkImageMemoryBarrier barriers[AV_NUM_DATA_POINTERS*2];
302  int barrier_count = 0;
303 
304  /* Update descriptors and init the exec context */
305  ff_vk_start_exec_recording(avctx, s->exec);
306  cmd_buf = ff_vk_get_exec_buf(avctx, s->exec);
307 
308  for (int i = 0; i < av_pix_fmt_count_planes(s->vkctx.input_format); i++) {
309  RET(ff_vk_create_imageview(avctx, s->exec, &s->input_images[i].imageView,
310  in->img[i],
313 
314  s->input_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
315  }
316 
317  for (int i = 0; i < av_pix_fmt_count_planes(s->vkctx.output_format); i++) {
318  RET(ff_vk_create_imageview(avctx, s->exec, &s->output_images[i].imageView,
319  out->img[i],
322 
323  s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
324  }
325 
326  ff_vk_update_descriptor_set(avctx, s->pl, 0);
327 
328  for (int i = 0; i < av_pix_fmt_count_planes(s->vkctx.input_format); i++) {
329  VkImageMemoryBarrier bar = {
330  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
331  .srcAccessMask = 0,
332  .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
333  .oldLayout = in->layout[i],
334  .newLayout = s->input_images[i].imageLayout,
335  .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
336  .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
337  .image = in->img[i],
338  .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
339  .subresourceRange.levelCount = 1,
340  .subresourceRange.layerCount = 1,
341  };
342 
343  memcpy(&barriers[barrier_count++], &bar, sizeof(VkImageMemoryBarrier));
344 
345  in->layout[i] = bar.newLayout;
346  in->access[i] = bar.dstAccessMask;
347  }
348 
349  for (int i = 0; i < av_pix_fmt_count_planes(s->vkctx.output_format); i++) {
350  VkImageMemoryBarrier bar = {
351  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
352  .srcAccessMask = 0,
353  .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
354  .oldLayout = out->layout[i],
355  .newLayout = s->output_images[i].imageLayout,
356  .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
357  .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
358  .image = out->img[i],
359  .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
360  .subresourceRange.levelCount = 1,
361  .subresourceRange.layerCount = 1,
362  };
363 
364  memcpy(&barriers[barrier_count++], &bar, sizeof(VkImageMemoryBarrier));
365 
366  out->layout[i] = bar.newLayout;
367  out->access[i] = bar.dstAccessMask;
368  }
369 
370  vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
371  VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
372  0, NULL, 0, NULL, barrier_count, barriers);
373 
374  ff_vk_bind_pipeline_exec(avctx, s->exec, s->pl);
375 
376  vkCmdDispatch(cmd_buf,
378  FFALIGN(s->vkctx.output_height, CGROUPS[1])/CGROUPS[1], 1);
379 
380  ff_vk_add_exec_dep(avctx, s->exec, in_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
381  ff_vk_add_exec_dep(avctx, s->exec, out_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
382 
383  err = ff_vk_submit_exec_queue(avctx, s->exec);
384  if (err)
385  return err;
386 
387  return err;
388 
389 fail:
390  ff_vk_discard_exec_deps(avctx, s->exec);
391  return err;
392 }
393 
395 {
396  int err;
397  AVFilterContext *ctx = link->dst;
398  ScaleVulkanContext *s = ctx->priv;
399  AVFilterLink *outlink = ctx->outputs[0];
400 
401  AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
402  if (!out) {
403  err = AVERROR(ENOMEM);
404  goto fail;
405  }
406 
407  if (!s->initialized)
408  RET(init_filter(ctx, in));
409 
410  RET(process_frames(ctx, out, in));
411 
412  err = av_frame_copy_props(out, in);
413  if (err < 0)
414  goto fail;
415 
417  out->color_range = s->out_range;
418  if (s->vkctx.output_format != s->vkctx.input_format)
420 
421  av_frame_free(&in);
422 
423  return ff_filter_frame(outlink, out);
424 
425 fail:
426  av_frame_free(&in);
427  av_frame_free(&out);
428  return err;
429 }
430 
432 {
433  int err;
434  AVFilterContext *avctx = outlink->src;
435  ScaleVulkanContext *s = avctx->priv;
436  AVFilterLink *inlink = outlink->src->inputs[0];
437 
438  err = ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, inlink, outlink,
439  &s->vkctx.output_width,
440  &s->vkctx.output_height);
441  if (err < 0)
442  return err;
443 
444  if (s->out_format_string) {
446  if (s->vkctx.output_format == AV_PIX_FMT_NONE) {
447  av_log(avctx, AV_LOG_ERROR, "Invalid output format.\n");
448  return AVERROR(EINVAL);
449  }
450  } else {
452  }
453 
454  if (s->vkctx.output_format != s->vkctx.input_format) {
456  av_log(avctx, AV_LOG_ERROR, "Unsupported input format for conversion\n");
457  return AVERROR(EINVAL);
458  }
459  if (s->vkctx.output_format != AV_PIX_FMT_NV12 &&
462  av_log(avctx, AV_LOG_ERROR, "Unsupported output format\n");
463  return AVERROR(EINVAL);
464  }
465  } else if (s->out_range != AVCOL_RANGE_UNSPECIFIED) {
466  av_log(avctx, AV_LOG_ERROR, "Cannot change range without converting format\n");
467  return AVERROR(EINVAL);
468  }
469 
470  err = ff_vk_filter_config_output(outlink);
471  if (err < 0)
472  return err;
473 
474  return 0;
475 }
476 
478 {
479  ScaleVulkanContext *s = avctx->priv;
480 
481  ff_vk_filter_uninit(avctx);
482  ff_vk_free_buf(avctx, &s->params_buf);
483 
484  s->initialized = 0;
485 }
486 
487 #define OFFSET(x) offsetof(ScaleVulkanContext, x)
488 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
489 static const AVOption scale_vulkan_options[] = {
490  { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = FLAGS },
491  { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS },
492  { "scaler", "Scaler function", OFFSET(scaler), AV_OPT_TYPE_INT, {.i64 = F_BILINEAR}, 0, F_NB, .flags = FLAGS, "scaler" },
493  { "bilinear", "Bilinear interpolation (fastest)", 0, AV_OPT_TYPE_CONST, {.i64 = F_BILINEAR}, 0, 0, .flags = FLAGS, "scaler" },
494  { "nearest", "Nearest (useful for pixel art)", 0, AV_OPT_TYPE_CONST, {.i64 = F_NEAREST}, 0, 0, .flags = FLAGS, "scaler" },
495  { "format", "Output video format (software format of hardware frames)", OFFSET(out_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS },
496  { "out_range", "Output colour range (from 0 to 2) (default 0)", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED}, AVCOL_RANGE_UNSPECIFIED, AVCOL_RANGE_JPEG, .flags = FLAGS, "range" },
497  { "full", "Full range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
498  { "limited", "Limited range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
499  { "jpeg", "Full range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
500  { "mpeg", "Limited range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
501  { "tv", "Limited range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
502  { "pc", "Full range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
503  { NULL },
504 };
505 
506 AVFILTER_DEFINE_CLASS(scale_vulkan);
507 
509  {
510  .name = "default",
511  .type = AVMEDIA_TYPE_VIDEO,
512  .filter_frame = &scale_vulkan_filter_frame,
513  .config_props = &ff_vk_filter_config_input,
514  },
515  { NULL }
516 };
517 
519  {
520  .name = "default",
521  .type = AVMEDIA_TYPE_VIDEO,
522  .config_props = &scale_vulkan_config_output,
523  },
524  { NULL }
525 };
526 
528  .name = "scale_vulkan",
529  .description = NULL_IF_CONFIG_SMALL("Scale Vulkan frames"),
530  .priv_size = sizeof(ScaleVulkanContext),
534  .inputs = scale_vulkan_inputs,
535  .outputs = scale_vulkan_outputs,
536  .priv_class = &scale_vulkan_class,
537  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
538 };
VulkanFilterContext vkctx
#define NULL
Definition: coverity.c:32
int ff_vk_add_exec_dep(AVFilterContext *avctx, FFVkExecContext *e, AVFrame *frame, VkPipelineStageFlagBits in_wait_dst_flag)
Adds a frame as a queue dependency.
Definition: vulkan.c:464
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition: internal.h:369
VkBuffer buf
Definition: vulkan.h:87
int ff_vk_init_pipeline_layout(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes the pipeline layout after all shaders and descriptor sets have been finished.
Definition: vulkan.c:1180
#define AV_NUM_DATA_POINTERS
Definition: frame.h:309
static const AVFilterPad scale_vulkan_outputs[]
int ff_vk_add_descriptor_set(AVFilterContext *avctx, VulkanPipeline *pl, SPIRVShader *shd, VulkanDescriptorSetBinding *desc, int num, int only_print_to_shader)
Adds a descriptor set to the shader and registers them in the pipeline.
Definition: vulkan.c:1020
This structure describes decoded (raw) audio or video data.
Definition: frame.h:308
void ff_vk_filter_uninit(AVFilterContext *avctx)
Definition: vulkan.c:1415
AVOption.
Definition: opt.h:248
const char * ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
Gets the glsl format string for a pixel format.
Definition: vulkan.c:817
VkDescriptorImageInfo output_images[3]
const char * name
Definition: vulkan.h:74
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2613
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int ff_vk_init_compute_pipeline(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes a compute pipeline.
Definition: vulkan.c:1281
static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
static int process_frames(AVFilterContext *avctx, AVFrame *out_f, AVFrame *in_f)
int ff_vk_create_imageview(AVFilterContext *avctx, FFVkExecContext *e, VkImageView *v, VkImage img, VkFormat fmt, const VkComponentMapping map)
Create an imageview.
Definition: vulkan.c:836
int ff_vk_filter_config_output(AVFilterLink *outlink)
Definition: vulkan.c:705
ScalerFunc
int ff_vk_start_exec_recording(AVFilterContext *avctx, FFVkExecContext *e)
Begin recording to the command buffer.
Definition: vulkan.c:417
static const char write_444[]
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
size_t crop_bottom
Definition: frame.h:669
FFVkExecContext * exec
const VkFormat * av_vkfmt_from_pixfmt(enum AVPixelFormat p)
Returns the format of each image up to the number of planes for a given sw_format.
VkDescriptorBufferInfo params_desc
VkImage img[AV_NUM_DATA_POINTERS]
Vulkan images to which the memory is bound to.
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
static const char rgb2yuv[]
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1091
uint8_t
VkDescriptorImageInfo input_images[3]
#define av_cold
Definition: attributes.h:88
static const AVOption scale_vulkan_options[]
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
AVOptions.
size_t crop_left
Definition: frame.h:670
#define f(width, name)
Definition: cbs_vp9.c:255
void ff_vk_set_compute_shader_sizes(AVFilterContext *avctx, SPIRVShader *shd, int local_size[3])
Writes the workgroup size for a shader.
Definition: vulkan.c:909
enum AVColorRange out_range
static const char write_420[]
int queue_family_comp_index
Queue family index for compute ops, and the amount of queues enabled.
int ff_vk_filter_init(AVFilterContext *avctx)
Definition: vulkan.c:756
AVFilter ff_vf_scale_vulkan
static const char scale_bilinear[]
AVColorRange
MPEG vs JPEG YUV range.
Definition: pixfmt.h:535
ptrdiff_t size
Definition: opengl_enc.c:100
const struct LumaCoefficients * ff_get_luma_coefficients(enum AVColorSpace csp)
Definition: colorspace.c:128
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers, int flush)
Unmaps the buffer from userspace.
Definition: vulkan.c:264
#define src
Definition: vp8dsp.c:254
int ff_vk_filter_query_formats(AVFilterContext *avctx)
General lavfi IO functions.
Definition: vulkan.c:592
enum AVPixelFormat input_format
Definition: vulkan.h:176
int width
Definition: frame.h:366
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
int ff_scale_eval_dimensions(void *log_ctx, const char *w_expr, const char *h_expr, AVFilterLink *inlink, AVFilterLink *outlink, int *ret_w, int *ret_h)
Parse and evaluate string expressions for width and height.
Definition: scale_eval.c:57
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
void * priv
private data for use by the filter
Definition: avfilter.h:353
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition: frame.h:552
unsigned int pos
Definition: spdifenc.c:410
int ff_vk_create_buf(AVFilterContext *avctx, FFVkBuffer *buf, size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags)
Create a VkBuffer with the specified parameters.
Definition: vulkan.c:150
enum AVColorSpace colorspace
YUV colorspace type.
Definition: frame.h:563
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:89
#define fail()
Definition: checkasm.h:123
size_t crop_top
Definition: frame.h:668
VkSampler * ff_vk_init_sampler(AVFilterContext *avctx, int unnorm_coords, VkFilter filt)
Create a Vulkan sampler, will be auto-freed in ff_vk_filter_uninit()
Definition: vulkan.c:769
int ff_vk_create_exec_ctx(AVFilterContext *avctx, FFVkExecContext **ctx)
Init an execution context for command recording and queue submission.
Definition: vulkan.c:339
VkAccessFlagBits access[AV_NUM_DATA_POINTERS]
Updated after every barrier.
ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2.
Definition: pixfmt.h:561
int ff_vk_submit_exec_queue(AVFilterContext *avctx, FFVkExecContext *e)
Submits a command buffer to the queue for execution.
Definition: vulkan.c:522
AVFormatContext * ctx
Definition: movenc.c:48
enum ScalerFunc scaler
#define GLSLF(N, S,...)
Definition: vulkan.h:40
#define s(width, name)
Definition: cbs_vp9.c:257
void ff_vk_free_buf(AVFilterContext *avctx, FFVkBuffer *buf)
Frees a buffer.
Definition: vulkan.c:306
int main(int argc, char *argv[])
#define GLSLC(N, S)
Definition: vulkan.h:38
#define FLAGS
void ff_vk_bind_pipeline_exec(AVFilterContext *avctx, FFVkExecContext *e, VulkanPipeline *pl)
Add a command to bind the completed pipeline and its descriptor sets.
Definition: vulkan.c:1316
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
the normal 2^n-1 "JPEG" YUV ranges
Definition: pixfmt.h:538
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s your new playground is ready Some little details about what s going which in turn will define variables for the build system and the C
#define CGROUPS
const VkComponentMapping ff_comp_identity_map
Definition: vulkan.c:44
static const AVFilterPad scale_vulkan_inputs[]
void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs, double rgb2yuv[3][3])
Definition: colorspace.c:141
int ff_vk_compile_shader(AVFilterContext *avctx, SPIRVShader *shd, const char *entrypoint)
Compiles the shader, entrypoint must be set to "main".
Definition: vulkan.c:942
int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt)
Returns 1 if the image is any sort of supported RGB.
Definition: vulkan.c:805
SPIRVShader * ff_vk_init_shader(AVFilterContext *avctx, VulkanPipeline *pl, const char *name, VkShaderStageFlags stage)
Inits a shader for a specific pipeline.
Definition: vulkan.c:888
size_t crop_right
Definition: frame.h:671
AVVulkanDeviceContext * hwctx
Definition: vulkan.h:165
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 inputs
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
Filter definition.
Definition: avfilter.h:144
VulkanPipeline * ff_vk_create_pipeline(AVFilterContext *avctx)
Inits a pipeline.
Definition: vulkan.c:1276
const char * name
Filter name.
Definition: avfilter.h:148
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 link
enum AVChromaLocation chroma_location
Definition: frame.h:565
VkCommandBuffer ff_vk_get_exec_buf(AVFilterContext *avctx, FFVkExecContext *e)
Gets the command buffer to use for this submission from the exe context.
Definition: vulkan.c:458
#define GET_QUEUE_COUNT(hwctx, graph, comp, tx)
Definition: vulkan.h:53
static const char write_nv12[]
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
void ff_vk_discard_exec_deps(AVFilterContext *avctx, FFVkExecContext *e)
Discards all queue dependencies.
Definition: vulkan.c:400
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:322
VulkanPipeline * pl
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
the normal 219*2^(n-8) "MPEG" YUV ranges
Definition: pixfmt.h:537
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
static int query_formats(AVFilterContext *ctx)
Definition: aeval.c:244
static int scale_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
static void scale_vulkan_uninit(AVFilterContext *avctx)
enum AVPixelFormat output_format
Definition: vulkan.h:175
static int scale_vulkan_config_output(AVFilterLink *outlink)
int ff_vk_map_buffers(AVFilterContext *avctx, FFVkBuffer *buf, uint8_t *mem[], int nb_buffers, int invalidate)
Maps the buffer to userspace.
Definition: vulkan.c:215
AVFILTER_DEFINE_CLASS(scale_vulkan)
#define GLSLD(D)
Definition: vulkan.h:41
int ff_vk_filter_config_input(AVFilterLink *inlink)
Definition: vulkan.c:635
#define OFFSET(x)
An instance of a filter.
Definition: avfilter.h:338
VkImageLayout layout[AV_NUM_DATA_POINTERS]
#define RET(x)
Definition: vulkan.h:46
int height
Definition: frame.h:366
FILE * out
Definition: movenc.c:54
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:120
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition: pixdesc.c:2501
#define DUP_SAMPLER_ARRAY4(x)
Definition: vulkan.h:64
internal API functions
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
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:671
int i
Definition: input.c:407
void ff_vk_update_descriptor_set(AVFilterContext *avctx, VulkanPipeline *pl, int set_id)
Updates a descriptor set via the updaters defined.
Definition: vulkan.c:1160