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 
119  s->vkctx.queue_family_idx = s->vkctx.hwctx->queue_family_comp_index;
120  s->vkctx.queue_count = GET_QUEUE_COUNT(s->vkctx.hwctx, 0, 1, 0);
121  s->vkctx.cur_queue_idx = av_get_random_seed() % s->vkctx.queue_count;
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,
147  .elems = av_pix_fmt_count_planes(s->vkctx.input_format),
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,
158  .elems = av_pix_fmt_count_planes(s->vkctx.output_format),
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 
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],
311  av_vkfmt_from_pixfmt(s->vkctx.input_format)[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],
320  av_vkfmt_from_pixfmt(s->vkctx.output_format)[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,
377  FFALIGN(s->vkctx.output_width, CGROUPS[0])/CGROUPS[0],
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 
411 
412  err = av_frame_copy_props(out, in);
413  if (err < 0)
414  goto fail;
415 
416  if (s->out_range != AVCOL_RANGE_UNSPECIFIED)
417  out->color_range = s->out_range;
418  if (s->vkctx.output_format != s->vkctx.input_format)
419  out->chroma_location = AVCHROMA_LOC_TOPLEFT;
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) {
445  s->vkctx.output_format = av_get_pix_fmt(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 {
451  s->vkctx.output_format = s->vkctx.input_format;
452  }
453 
454  if (s->vkctx.output_format != s->vkctx.input_format) {
455  if (!ff_vk_mt_is_np_rgb(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 &&
460  s->vkctx.output_format != AV_PIX_FMT_YUV420P &&
461  s->vkctx.output_format != AV_PIX_FMT_YUV444P) {
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),
536  .priv_class = &scale_vulkan_class,
537  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
538 };
ff_vk_filter_query_formats
int ff_vk_filter_query_formats(AVFilterContext *avctx)
General lavfi IO functions.
Definition: vulkan.c:592
ff_get_video_buffer
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
VulkanDescriptorSetBinding::elems
uint32_t elems
Definition: vulkan.h:80
process_frames
static int process_frames(AVFilterContext *avctx, AVFrame *out_f, AVFrame *in_f)
Definition: vf_scale_vulkan.c:294
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
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
opt.h
out
FILE * out
Definition: movenc.c:54
FF_FILTER_FLAG_HWFRAME_AWARE
#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:365
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1075
RET
#define RET(x)
Definition: vulkan.h:46
ff_vf_scale_vulkan
AVFilter ff_vf_scale_vulkan
Definition: vf_scale_vulkan.c:527
inlink
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
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
OFFSET
#define OFFSET(x)
Definition: vf_scale_vulkan.c:487
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
the normal 2^n-1 "JPEG" YUV ranges
Definition: pixfmt.h:535
scale_vulkan_outputs
static const AVFilterPad scale_vulkan_outputs[]
Definition: vf_scale_vulkan.c:518
ff_vk_mt_is_np_rgb
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
VulkanDescriptorSetBinding
Definition: vulkan.h:73
AVOption
AVOption.
Definition: opt.h:246
scale_vulkan_options
static const AVOption scale_vulkan_options[]
Definition: vf_scale_vulkan.c:489
LumaCoefficients
Definition: colorspace.h:28
rgb2yuv
static const char rgb2yuv[]
Definition: vf_scale_vulkan.c:65
write_nv12
static const char write_nv12[]
Definition: vf_scale_vulkan.c:79
ff_vk_init_sampler
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
ff_scale_eval_dimensions
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
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:148
write_420
static const char write_420[]
Definition: vf_scale_vulkan.c:88
DUP_SAMPLER_ARRAY4
#define DUP_SAMPLER_ARRAY4(x)
Definition: vulkan.h:64
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:314
av_get_random_seed
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:120
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(scale_vulkan)
ScalerFunc
ScalerFunc
Definition: vf_scale_vulkan.c:28
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2589
ff_vk_init_shader
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
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:353
fail
#define fail()
Definition: checkasm.h:123
SPIRVShader
Definition: vulkan.h:66
ff_vk_create_pipeline
VulkanPipeline * ff_vk_create_pipeline(AVFilterContext *avctx)
Inits a pipeline.
Definition: vulkan.c:1276
colorspace.h
ff_vk_add_exec_dep
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
ScaleVulkanContext::exec
FFVkExecContext * exec
Definition: vf_scale_vulkan.c:39
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
ff_vk_compile_shader
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
ff_get_luma_coefficients
const struct LumaCoefficients * ff_get_luma_coefficients(enum AVColorSpace csp)
Definition: colorspace.c:128
C
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
Definition: writing_filters.txt:58
GLSLC
#define GLSLC(N, S)
Definition: vulkan.h:38
ff_vk_filter_uninit
void ff_vk_filter_uninit(AVFilterContext *avctx)
Definition: vulkan.c:1415
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
av_cold
#define av_cold
Definition: attributes.h:90
F_NEAREST
@ F_NEAREST
Definition: vf_scale_vulkan.c:30
s
#define s(width, name)
Definition: cbs_vp9.c:257
ff_vk_filter_config_input
int ff_vk_filter_config_input(AVFilterLink *inlink)
Definition: vulkan.c:635
ff_comp_identity_map
const VkComponentMapping ff_comp_identity_map
Definition: vulkan.c:44
F_BILINEAR
@ F_BILINEAR
Definition: vf_scale_vulkan.c:29
ff_fill_rgb2yuv_table
void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs, double rgb2yuv[3][3])
Definition: colorspace.c:141
scale_vulkan_filter_frame
static int scale_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
Definition: vf_scale_vulkan.c:394
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ff_vk_map_buffers
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
ff_vk_init_pipeline_layout
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
GLSLD
#define GLSLD(D)
Definition: vulkan.h:41
ff_vk_add_descriptor_set
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
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
VulkanPipeline
Definition: vulkan.h:92
f
#define f(width, name)
Definition: cbs_vp9.c:255
link
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
Definition: filter_design.txt:23
ff_vk_set_compute_shader_sizes
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
ff_vk_bind_pipeline_exec
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
av_vkfmt_from_pixfmt
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.
Definition: hwcontext_vulkan.c:175
main
int main(int argc, char *argv[])
Definition: avio_list_dir.c:112
NULL
#define NULL
Definition: coverity.c:32
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:659
ScaleVulkanContext::params_buf
FFVkBuffer params_buf
Definition: vf_scale_vulkan.c:41
scale_vulkan_uninit
static void scale_vulkan_uninit(AVFilterContext *avctx)
Definition: vf_scale_vulkan.c:477
ScaleVulkanContext::h_expr
char * h_expr
Definition: vf_scale_vulkan.c:52
AVCHROMA_LOC_TOPLEFT
@ AVCHROMA_LOC_TOPLEFT
ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2.
Definition: pixfmt.h:558
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
src
#define src
Definition: vp8dsp.c:254
ff_vk_get_exec_buf
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
inputs
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
Definition: filter_design.txt:243
ScaleVulkanContext::out_range
enum AVColorRange out_range
Definition: vf_scale_vulkan.c:50
F_NB
@ F_NB
Definition: vf_scale_vulkan.c:32
FLAGS
#define FLAGS
Definition: vf_scale_vulkan.c:488
AVCOL_RANGE_UNSPECIFIED
@ AVCOL_RANGE_UNSPECIFIED
Definition: pixfmt.h:533
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
GET_QUEUE_COUNT
#define GET_QUEUE_COUNT(hwctx, graph, comp, tx)
Definition: vulkan.h:53
AVVkFrame
Definition: hwcontext_vulkan.h:149
vulkan.h
size
int size
Definition: twinvq_data.h:11134
AV_NUM_DATA_POINTERS
#define AV_NUM_DATA_POINTERS
Definition: frame.h:301
VulkanDescriptorSetBinding::name
const char * name
Definition: vulkan.h:74
scale_eval.h
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
FFVkExecContext
Definition: vulkan.h:136
ff_vk_filter_init
int ff_vk_filter_init(AVFilterContext *avctx)
Definition: vulkan.c:756
ff_vk_update_descriptor_set
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
ScaleVulkanContext::input_images
VkDescriptorImageInfo input_images[3]
Definition: vf_scale_vulkan.c:44
internal.h
ScaleVulkanContext::scaler
enum ScalerFunc scaler
Definition: vf_scale_vulkan.c:48
in
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
Definition: audio_convert.c:326
ScaleVulkanContext::w_expr
char * w_expr
Definition: vf_scale_vulkan.c:51
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
scale_bilinear
static const char scale_bilinear[]
Definition: vf_scale_vulkan.c:55
write_444
static const char write_444[]
Definition: vf_scale_vulkan.c:98
uint8_t
uint8_t
Definition: audio_convert.c:194
scale_vulkan_inputs
static const AVFilterPad scale_vulkan_inputs[]
Definition: vf_scale_vulkan.c:508
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
AVCOL_RANGE_MPEG
@ AVCOL_RANGE_MPEG
the normal 219*2^(n-8) "MPEG" YUV ranges
Definition: pixfmt.h:534
AVFilter
Filter definition.
Definition: avfilter.h:144
AV_PIX_FMT_NV12
@ AV_PIX_FMT_NV12
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
ff_vk_start_exec_recording
int ff_vk_start_exec_recording(AVFilterContext *avctx, FFVkExecContext *e)
Begin recording to the command buffer.
Definition: vulkan.c:417
pos
unsigned int pos
Definition: spdifenc.c:412
ff_vk_create_buf
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
ff_vk_submit_exec_queue
int ff_vk_submit_exec_queue(AVFilterContext *avctx, FFVkExecContext *e)
Submits a command buffer to the queue for execution.
Definition: vulkan.c:522
av_get_pix_fmt
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition: pixdesc.c:2477
ff_vk_shader_rep_fmt
const char * ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
Gets the glsl format string for a pixel format.
Definition: vulkan.c:817
random_seed.h
ff_vk_free_buf
void ff_vk_free_buf(AVFilterContext *avctx, FFVkBuffer *buf)
Frees a buffer.
Definition: vulkan.c:306
ff_vk_unmap_buffers
int ff_vk_unmap_buffers(AVFilterContext *avctx, FFVkBuffer *buf, int nb_buffers, int flush)
Unmaps the buffer from userspace.
Definition: vulkan.c:264
ScaleVulkanContext::initialized
int initialized
Definition: vf_scale_vulkan.c:38
GLSLF
#define GLSLF(N, S,...)
Definition: vulkan.h:40
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:223
CGROUPS
#define CGROUPS
Definition: vf_scale_vulkan.c:26
ScaleVulkanContext::output_images
VkDescriptorImageInfo output_images[3]
Definition: vf_scale_vulkan.c:45
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
AVFilterContext
An instance of a filter.
Definition: avfilter.h:338
ScaleVulkanContext
Definition: vf_scale_vulkan.c:35
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
ff_vk_create_exec_ctx
int ff_vk_create_exec_ctx(AVFilterContext *avctx, FFVkExecContext **ctx)
Init an execution context for command recording and queue submission.
Definition: vulkan.c:339
VulkanFilterContext
Definition: vulkan.h:159
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:48
ff_vk_discard_exec_deps
void ff_vk_discard_exec_deps(AVFilterContext *avctx, FFVkExecContext *e)
Discards all queue dependencies.
Definition: vulkan.c:400
FFVkBuffer
Definition: vulkan.h:86
ScaleVulkanContext::pl
VulkanPipeline * pl
Definition: vf_scale_vulkan.c:40
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: aeval.c:244
scale_vulkan_config_output
static int scale_vulkan_config_output(AVFilterLink *outlink)
Definition: vf_scale_vulkan.c:431
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
ff_vk_init_compute_pipeline
int ff_vk_init_compute_pipeline(AVFilterContext *avctx, VulkanPipeline *pl)
Initializes a compute pipeline.
Definition: vulkan.c:1281
uninit
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
init_filter
static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
Definition: vf_scale_vulkan.c:107
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:227
AVColorRange
AVColorRange
MPEG vs JPEG YUV range.
Definition: pixfmt.h:532
ff_vk_create_imageview
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
ScaleVulkanContext::params_desc
VkDescriptorBufferInfo params_desc
Definition: vf_scale_vulkan.c:46
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:232
ff_vk_filter_config_output
int ff_vk_filter_config_output(AVFilterLink *outlink)
Definition: vulkan.c:705
ScaleVulkanContext::vkctx
VulkanFilterContext vkctx
Definition: vf_scale_vulkan.c:36
ScaleVulkanContext::out_format_string
char * out_format_string
Definition: vf_scale_vulkan.c:49