This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 71e5dfbf890e16dcfad53c9d059ee0c32f949a2b Author: Philip Langdale <[email protected]> AuthorDate: Sun Jun 21 10:20:36 2026 -0700 Commit: Philip Langdale <[email protected]> CommitDate: Sat Aug 29 17:07:53 2026 -0700 avfilter/fruc_vulkan: expose optical flow perf level and grid size Add the two options that tune the NV optical flow session: * perf: performance level (slow/medium/fast), previously hard-coded to slow. Trades motion-estimation quality for speed. * grid: output grid size in pixels (auto/1/2/4/8), previously always the finest grid the device supported. A coarser grid computes fewer flow vectors, so it is faster and uses less memory at the cost of detail. These settings are important as you can't handle high resolution input in realtime at the highest quality settings. For example, 2160p24 movie content needs reduced settings (eg: pref=medium,grid=2) for the filter to run comfortably. --- doc/filters.texi | 19 +++++++++++ libavfilter/vf_fruc_vulkan.c | 79 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 9cde5321b4..4ba53ac5d9 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -29694,6 +29694,25 @@ more than 16 bits integer data per component, such as @code{rgb96} and A string describing the desired output frame rate, evaluated as an expression. The following constants are available: @code{source_fps}. The default value is @code{60}. + +@item perf +Optical flow performance level, trading motion-estimation quality for speed. +This is the dominant cost at high resolutions. Possible values are: +@table @samp +@item slow +Highest quality, slowest. This is the default. +@item medium +Balanced quality and speed. +@item fast +Lowest quality, fastest. +@end table + +@item grid +Optical flow output grid size in pixels. A coarser grid computes fewer flow +vectors, making it faster and less memory hungry at the cost of flow detail. +Possible values are @code{auto} (the default; selects the finest grid the +device supports, usually 1x1), @code{1}, @code{2}, @code{4} and @code{8}. Only +grid sizes the device advertises are accepted. @end table @section gblur_vulkan diff --git a/libavfilter/vf_fruc_vulkan.c b/libavfilter/vf_fruc_vulkan.c index 357b8da586..4b9091b137 100644 --- a/libavfilter/vf_fruc_vulkan.c +++ b/libavfilter/vf_fruc_vulkan.c @@ -89,6 +89,10 @@ typedef struct FRUCVulkanContext { VkFormat input_format; ///< grayscale input format VkFormat flow_format; ///< flow vector format + /* Tuning options. */ + int perf_level; ///< VkOpticalFlowPerformanceLevelNV + int opt_grid_size; ///< requested grid in pixels (0 = finest) + int width; ///< luma width int height; ///< luma height int flow_width; @@ -131,6 +135,24 @@ typedef struct FRUCVulkanContext { static const AVOption fruc_vulkan_options[] = { { "fps", "A string describing the desired output frame rate", OFFSET(requested_frame_rate), AV_OPT_TYPE_STRING, { .str = "60" }, 0, 0, FLAGS }, + { "perf", "Optical flow performance level (quality versus speed)", + OFFSET(perf_level), AV_OPT_TYPE_INT, { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV }, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV, VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV, + FLAGS, .unit = "perf" }, + { "slow", "Highest quality, slowest", 0, AV_OPT_TYPE_CONST, + { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV }, 0, 0, FLAGS, .unit = "perf" }, + { "medium", "Balanced quality and speed", 0, AV_OPT_TYPE_CONST, + { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV }, 0, 0, FLAGS, .unit = "perf" }, + { "fast", "Lowest quality, fastest", 0, AV_OPT_TYPE_CONST, + { .i64 = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV }, 0, 0, FLAGS, .unit = "perf" }, + { "grid", "Optical flow output grid size in pixels (coarser is faster)", + OFFSET(opt_grid_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8, FLAGS, .unit = "grid" }, + { "auto", "Finest grid the device supports", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, 0, 0, FLAGS, .unit = "grid" }, + { "1", "1x1", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, .unit = "grid" }, + { "2", "2x2", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, .unit = "grid" }, + { "4", "4x4", 0, AV_OPT_TYPE_CONST, { .i64 = 4 }, 0, 0, FLAGS, .unit = "grid" }, + { "8", "8x8", 0, AV_OPT_TYPE_CONST, { .i64 = 8 }, 0, 0, FLAGS, .unit = "grid" }, { NULL } }; @@ -495,29 +517,52 @@ static av_cold int init_filter(AVFilterContext *avctx) return AVERROR(ENOTSUP); } + static const struct { + int size; + VkOpticalFlowGridSizeFlagsNV bit; + } grid_map[] = { + { 1, VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV }, + { 2, VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV }, + { 4, VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV }, + { 8, VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV }, + }; + grids = vkctx->optical_flow_props.supportedOutputGridSizes; - if (grids & VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV) { - s->grid_size = 1; - s->grid_bit = VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV; - } else if (grids & VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV) { - s->grid_size = 2; - s->grid_bit = VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV; - } else if (grids & VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV) { - s->grid_size = 4; - s->grid_bit = VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV; - } else if (grids & VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV) { - s->grid_size = 8; - s->grid_bit = VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV; + if (s->opt_grid_size) { + /* Honour an explicit grid request, erroring if the device lacks it. */ + VkOpticalFlowGridSizeFlagsNV want = 0; + for (int i = 0; i < FF_ARRAY_ELEMS(grid_map); i++) + if (grid_map[i].size == s->opt_grid_size) + want = grid_map[i].bit; + if (!want || !(grids & want)) { + av_log(avctx, AV_LOG_ERROR, "Requested optical flow grid size %d is not " + "supported by the device (supported mask 0x%x)\n", + s->opt_grid_size, grids); + return AVERROR(ENOTSUP); + } + s->grid_size = s->opt_grid_size; + s->grid_bit = want; } else { - av_log(avctx, AV_LOG_ERROR, "No supported optical flow output grid size\n"); - return AVERROR(ENOTSUP); + /* Auto: pick the finest (smallest) grid the device supports. */ + s->grid_size = 0; + for (int i = 0; i < FF_ARRAY_ELEMS(grid_map); i++) { + if (grids & grid_map[i].bit) { + s->grid_size = grid_map[i].size; + s->grid_bit = grid_map[i].bit; + break; + } + } + if (!s->grid_size) { + av_log(avctx, AV_LOG_ERROR, "No supported optical flow output grid size\n"); + return AVERROR(ENOTSUP); + } } s->flow_width = (s->width + s->grid_size - 1) / s->grid_size; s->flow_height = (s->height + s->grid_size - 1) / s->grid_size; - av_log(avctx, AV_LOG_INFO, "optical flow: grid %d, flow %dx%d, bidir=%d, " - "min %dx%d max %dx%d\n", s->grid_size, s->flow_width, s->flow_height, + av_log(avctx, AV_LOG_INFO, "optical flow: perf %d, grid %d, flow %dx%d, bidir=%d, " + "min %dx%d max %dx%d\n", s->perf_level, s->grid_size, s->flow_width, s->flow_height, vkctx->optical_flow_props.bidirectionalFlowSupported, vkctx->optical_flow_props.minWidth, vkctx->optical_flow_props.minHeight, vkctx->optical_flow_props.maxWidth, vkctx->optical_flow_props.maxHeight); @@ -595,7 +640,7 @@ static av_cold int init_filter(AVFilterContext *avctx) .imageFormat = s->input_format, .flowVectorFormat = s->flow_format, .outputGridSize = s->grid_bit, - .performanceLevel = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV, + .performanceLevel = s->perf_level, .flags = VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV, }, vkctx->hwctx->alloc, &s->session); if (ret != VK_SUCCESS) { -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
