[FFmpeg-devel] [PATCH v06 4/5] hwdownload detile framebuffer, if requested by user

hanishkvc hanishkvc at gmail.com
Sat Jul 4 16:17:16 EEST 2020


Added logic to support detiling of framebuffer.

By default this is disabled. Only if requested by the user, the
logic will be triggered.

It uses the fbtile helper routines to do the detiling. Currently
32bit RGB pixel format based framebuffers are supported.

If the underlying hardware context provides linear layouts, then
nothing is done. Only if the underlying hardware context generates
tiled layout, then user can use this to detile, where possible.

./ffmpeg -f kmsgrab -i - -vf hwdownload=1,format=bgr0 out.mp4
---
 Changelog                   |  1 +
 doc/filters.texi            | 19 ++++++++++
 libavfilter/vf_hwdownload.c | 74 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/Changelog b/Changelog
index b6a4ad1b34..6174770ce1 100644
--- a/Changelog
+++ b/Changelog
@@ -2,6 +2,7 @@ Entries are sorted chronologically from oldest to youngest within each release,
 releases are sorted from youngest to oldest.
 
 version <next>:
+- hwdownload framebuffer layout detiling (Intel tile-x|y|yf layouts)
 - hwcontext_drm detiles non linear layouts, if possible
 - kmsgrab GetFB2 format_modifier, if user doesnt specify
 - AudioToolbox output device
diff --git a/doc/filters.texi b/doc/filters.texi
index 67892e0afb..c783e059c2 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -12097,6 +12097,25 @@ Not all formats will be supported on the output - it may be necessary to insert
 an additional @option{format} filter immediately following in the graph to get
 the output in a supported format.
 
+It supports the following optional parameters
+
+ at table @option
+ at item fbdetile
+Specify type of CPU based FrameBuffer layout detiling to apply. The supported values are
+ at table @var
+ at item 0
+Dont do sw detiling (the default).
+ at item 1
+Auto detect detile logic to apply (for hwcontext_drm).
+ at item 2
+intel tile-x to linear conversion.
+ at item 3
+intel tile-y to linear conversion.
+ at item 4
+intel tile-yf to linear conversion.
+ at end table
+ at end table
+
 @section hwmap
 
 Map hardware frames to system memory or to another device.
diff --git a/libavfilter/vf_hwdownload.c b/libavfilter/vf_hwdownload.c
index 33af30cf40..5413ff104d 100644
--- a/libavfilter/vf_hwdownload.c
+++ b/libavfilter/vf_hwdownload.c
@@ -22,6 +22,10 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/fbtile.h"
+#if CONFIG_LIBDRM
+#include "libavutil/hwcontext_drm.h"
+#endif
 
 #include "avfilter.h"
 #include "formats.h"
@@ -33,8 +37,23 @@ typedef struct HWDownloadContext {
 
     AVBufferRef       *hwframes_ref;
     AVHWFramesContext *hwframes;
+    int fbdetile;
 } HWDownloadContext;
 
+#define OFFSET(x) offsetof(HWDownloadContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption hwdownload_options[] = {
+    { "fbdetile", "set framebuffer detile mode", OFFSET(fbdetile), AV_OPT_TYPE_INT, {.i64=TILE_NONE}, 0, TILE_NONE_END-1, FLAGS, "fbdetile" },
+        { "none", "No SW detiling", 0, AV_OPT_TYPE_CONST, {.i64=TILE_NONE}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+        { "auto", "auto select based on format_modifier", 0, AV_OPT_TYPE_CONST, {.i64=TILE_AUTO}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+        { "intelx", "Intel Tile-X layout", 0, AV_OPT_TYPE_CONST, {.i64=TILE_INTELX}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+        { "intely", "Intel Tile-Y layout", 0, AV_OPT_TYPE_CONST, {.i64=TILE_INTELY}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+        { "intelyf", "Intel Tile-Yf layout", 0, AV_OPT_TYPE_CONST, {.i64=TILE_INTELYF}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+        { "intelgx", "Intel Tile-X layout, GenericDetile", 0, AV_OPT_TYPE_CONST, {.i64=TILE_INTELGX}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+        { "intelgy", "Intel Tile-Y layout, GenericDetile", 0, AV_OPT_TYPE_CONST, {.i64=TILE_INTELGY}, INT_MIN, INT_MAX, FLAGS, "fbdetile" },
+    { NULL }
+};
+
 static int hwdownload_query_formats(AVFilterContext *avctx)
 {
     AVFilterFormats  *infmts = NULL;
@@ -81,6 +100,16 @@ static int hwdownload_config_input(AVFilterLink *inlink)
 
     ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
 
+    int found = 0;
+    if (ctx->fbdetile != 0) {
+        found = fbtile_checkpixformats(ctx->hwframes->sw_format, fbtilePixFormats[0]);
+        if (!found) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid input format %s for fbdetile.\n",
+                   av_get_pix_fmt_name(ctx->hwframes->sw_format));
+            return AVERROR(EINVAL);
+        }
+    }
+
     return 0;
 }
 
@@ -116,6 +145,15 @@ static int hwdownload_config_output(AVFilterLink *outlink)
         return AVERROR(EINVAL);
     }
 
+    if (ctx->fbdetile != 0) {
+        found = fbtile_checkpixformats(outlink->format, fbtilePixFormats[0]);
+        if (!found) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid output format %s for fbdetile.\n",
+                   av_get_pix_fmt_name(outlink->format));
+            return AVERROR(EINVAL);
+        }
+    }
+
     outlink->w = inlink->w;
     outlink->h = inlink->h;
 
@@ -128,6 +166,7 @@ static int hwdownload_filter_frame(AVFilterLink *link, AVFrame *input)
     AVFilterLink  *outlink = avctx->outputs[0];
     HWDownloadContext *ctx = avctx->priv;
     AVFrame *output = NULL;
+    AVFrame *output2 = NULL;
     int err;
 
     if (!ctx->hwframes_ref || !input->hw_frames_ctx) {
@@ -162,13 +201,44 @@ static int hwdownload_filter_frame(AVFilterLink *link, AVFrame *input)
     if (err < 0)
         goto fail;
 
+    if (ctx->fbdetile == 0) {
+        av_frame_free(&input);
+        return ff_filter_frame(avctx->outputs[0], output);
+    }
+
+    output2 = ff_get_video_buffer(outlink, ctx->hwframes->width,
+                                  ctx->hwframes->height);
+    if (!output2) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    output2->width  = outlink->w;
+    output2->height = outlink->h;
+    uint64_t formatModifier = 0;
+#if CONFIG_LIBDRM
+    if (input->format  == AV_PIX_FMT_DRM_PRIME) {
+        AVDRMFrameDescriptor *drmFrame = input->data[0];
+        formatModifier = drmFrame->objects[0].format_modifier;
+    }
+#endif
+    detile_this(ctx->fbdetile, formatModifier, output2->width, output2->height,
+                output2->data[0], output2->linesize[0],
+                output->data[0], output->linesize[0], 4);
+
+    err = av_frame_copy_props(output2, input);
+    if (err < 0)
+        goto fail;
+
     av_frame_free(&input);
+    av_frame_free(&output);
 
-    return ff_filter_frame(avctx->outputs[0], output);
+    return ff_filter_frame(avctx->outputs[0], output2);
 
 fail:
     av_frame_free(&input);
     av_frame_free(&output);
+    av_frame_free(&output2);
     return err;
 }
 
@@ -182,7 +252,7 @@ static av_cold void hwdownload_uninit(AVFilterContext *avctx)
 static const AVClass hwdownload_class = {
     .class_name = "hwdownload",
     .item_name  = av_default_item_name,
-    .option     = NULL,
+    .option     = hwdownload_options,
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
-- 
2.25.1



More information about the ffmpeg-devel mailing list