@@ -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
@@ -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
+
+@table @option
+@item fbdetile
+Specify type of CPU based FrameBuffer layout detiling to apply. The supported values are
+@table @var
+@item 0
+Dont do sw detiling (the default).
+@item 1
+Auto detect detile logic to apply (for hwcontext_drm).
+@item 2
+intel tile-x to linear conversion.
+@item 3
+intel tile-y to linear conversion.
+@item 4
+intel tile-yf to linear conversion.
+@end table
+@end table
+
@section hwmap
Map hardware frames to system memory or to another device.
@@ -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,
};