summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2022-04-03 20:12:50 -0700
committerPhilip Langdale <github.philipl@overt.org>2022-09-21 09:39:34 -0700
commitf221666ade9a60195a37d809973fbc18391306ed (patch)
tree787e48c1ba96a02ec5d11644352fe2fa442b1b2b
parent7b84e6fa8988f31e297cbc3adcd8a81e18e63bc8 (diff)
downloadmpv-f221666ade9a60195a37d809973fbc18391306ed.tar.bz2
mpv-f221666ade9a60195a37d809973fbc18391306ed.tar.xz
f_hwtransfer: mp_image_pool: support HW -> HW mapping
Certain combinations of hardware formats require the use of hwmap to transfer frames between the formats, rather than hwupload, which will fail if attempted. To keep the usage of vf_format for HW -> HW transfers as intuitive as possible, we should detect these cases and do the map operation instead of uploading. For now, the relevant cases are moving between VAAPI and Vulkan, and VAAPI and DRM Prime, in both directions. I have introduced the IMGFMT entry for Vulkan here so that I can put in the complete mapping table. It's actually not useless, as you can map to Vulkan, use a Vulkan filter and then map back to VAAPI for display output.
-rw-r--r--filters/f_hwtransfer.c47
-rw-r--r--filters/f_lavfi.c4
-rw-r--r--test/ref/img_formats.txt2
-rw-r--r--video/fmt-conversion.c1
-rw-r--r--video/img_format.h1
-rw-r--r--video/mp_image_pool.c27
-rw-r--r--video/mp_image_pool.h2
7 files changed, 80 insertions, 4 deletions
diff --git a/filters/f_hwtransfer.c b/filters/f_hwtransfer.c
index 649d28497c..9640f406ad 100644
--- a/filters/f_hwtransfer.c
+++ b/filters/f_hwtransfer.c
@@ -35,6 +35,10 @@ struct priv {
int *fmt_upload_index;
int *fmt_upload_num;
+ // List of source formats that require hwmap instead of hwupload.
+ int *map_fmts;
+ int num_map_fmts;
+
struct mp_hwupload public;
};
@@ -58,6 +62,25 @@ static const struct ffmpeg_and_other_bugs shitlist[] = {
{0}
};
+struct hwmap_pairs {
+ int first_fmt;
+ int second_fmt;
+};
+
+// We cannot discover which pairs of hardware formats need to use hwmap to
+// convert between the formats, so we need a lookup table.
+static const struct hwmap_pairs hwmap_pairs[] = {
+ {
+ .first_fmt = IMGFMT_VAAPI,
+ .second_fmt = IMGFMT_VULKAN,
+ },
+ {
+ .first_fmt = IMGFMT_DRMPRIME,
+ .second_fmt = IMGFMT_VAAPI,
+ },
+ {0}
+};
+
static bool select_format(struct priv *p, int input_fmt,
int *out_sw_fmt, int *out_upload_fmt)
{
@@ -183,7 +206,19 @@ static void process(struct mp_filter *f)
goto error;
}
- struct mp_image *dst = mp_av_pool_image_hw_upload(p->hw_pool, src);
+ struct mp_image *dst;
+ bool map_images = false;
+ for (int n = 0; n < p->num_map_fmts; n++) {
+ if (src->imgfmt == p->map_fmts[n]) {
+ map_images = true;
+ break;
+ }
+ }
+
+ if (map_images)
+ dst = mp_av_pool_image_hw_map(p->hw_pool, src);
+ else
+ dst = mp_av_pool_image_hw_upload(p->hw_pool, src);
if (!dst)
goto error;
@@ -296,6 +331,16 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
}
}
+ for (int n = 0; hwmap_pairs[n].first_fmt; n++) {
+ if (hwmap_pairs[n].first_fmt == hw_imgfmt) {
+ MP_TARRAY_APPEND(p, p->map_fmts, p->num_map_fmts,
+ hwmap_pairs[n].second_fmt);
+ } else if (hwmap_pairs[n].second_fmt == hw_imgfmt) {
+ MP_TARRAY_APPEND(p, p->map_fmts, p->num_map_fmts,
+ hwmap_pairs[n].first_fmt);
+ }
+ }
+
for (int n = 0; cstr->valid_sw_formats &&
cstr->valid_sw_formats[n] != AV_PIX_FMT_NONE; n++)
{
diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c
index cbb3066430..41a3ea4eac 100644
--- a/filters/f_lavfi.c
+++ b/filters/f_lavfi.c
@@ -561,8 +561,8 @@ static void init_graph(struct lavfi *c)
hwdec_ctx = hwdec_devices_get_first(info->hwdec_devs);
}
if (hwdec_ctx && hwdec_ctx->av_device_ref) {
- MP_VERBOSE(c, "Configuring hwdec_interop=%s for filters\n",
- hwdec_ctx->driver_name);
+ MP_VERBOSE(c, "Configuring hwdec_interop=%s for filter graph: %s\n",
+ hwdec_ctx->driver_name, c->graph_string);
for (int n = 0; n < c->graph->nb_filters; n++) {
AVFilterContext *filter = c->graph->filters[n];
filter->hw_device_ctx =
diff --git a/test/ref/img_formats.txt b/test/ref/img_formats.txt
index 2b1cca1522..cd84963b6a 100644
--- a/test/ref/img_formats.txt
+++ b/test/ref/img_formats.txt
@@ -1239,7 +1239,7 @@ videotoolbox: ctype=unknown
planes=0, chroma=0:0 align=1:1
{}
AVD: name=videotoolbox_vld chroma=0:0 flags=0x8 [hw]
-vulkan: [GENERIC] ctype=unknown
+vulkan: ctype=unknown
Basic desc: [le][be][hw]
planes=0, chroma=0:0 align=1:1
{}
diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c
index 5194221d50..d200a5db31 100644
--- a/video/fmt-conversion.c
+++ b/video/fmt-conversion.c
@@ -67,6 +67,7 @@ static const struct {
{IMGFMT_CUDA, AV_PIX_FMT_CUDA},
{IMGFMT_P010, AV_PIX_FMT_P010},
{IMGFMT_DRMPRIME, AV_PIX_FMT_DRM_PRIME},
+ {IMGFMT_VULKAN, AV_PIX_FMT_VULKAN},
{0, AV_PIX_FMT_NONE}
};
diff --git a/video/img_format.h b/video/img_format.h
index ebdbd66e29..7559c8c172 100644
--- a/video/img_format.h
+++ b/video/img_format.h
@@ -319,6 +319,7 @@ enum mp_imgfmt {
IMGFMT_VDPAU_OUTPUT, // VdpOutputSurface
IMGFMT_VAAPI,
IMGFMT_VIDEOTOOLBOX, // CVPixelBufferRef
+ IMGFMT_VULKAN, // VKImage
// Generic pass-through of AV_PIX_FMT_*. Used for formats which don't have
// a corresponding IMGFMT_ value.
diff --git a/video/mp_image_pool.c b/video/mp_image_pool.c
index 2a4a8940c0..d80c65d3b5 100644
--- a/video/mp_image_pool.c
+++ b/video/mp_image_pool.c
@@ -426,3 +426,30 @@ struct mp_image *mp_av_pool_image_hw_upload(struct AVBufferRef *hw_frames_ctx,
mp_image_copy_attributes(dst, src);
return dst;
}
+
+struct mp_image *mp_av_pool_image_hw_map(struct AVBufferRef *hw_frames_ctx,
+ struct mp_image *src)
+{
+ AVFrame *dst_frame = av_frame_alloc();
+ if (!dst_frame)
+ return NULL;
+
+ dst_frame->format = ((AVHWFramesContext*)hw_frames_ctx->data)->format;
+ dst_frame->hw_frames_ctx = av_buffer_ref(hw_frames_ctx);
+
+ AVFrame *src_frame = mp_image_to_av_frame(src);
+ if (av_hwframe_map(dst_frame, src_frame, 0) < 0) {
+ av_frame_free(&src_frame);
+ av_frame_free(&dst_frame);
+ return NULL;
+ }
+ av_frame_free(&src_frame);
+
+ struct mp_image *dst = mp_image_from_av_frame(dst_frame);
+ av_frame_free(&dst_frame);
+ if (!dst)
+ return NULL;
+
+ mp_image_copy_attributes(dst, src);
+ return dst;
+}
diff --git a/video/mp_image_pool.h b/video/mp_image_pool.h
index 3c7e6221d1..ab9065e6e9 100644
--- a/video/mp_image_pool.h
+++ b/video/mp_image_pool.h
@@ -41,4 +41,6 @@ bool mp_update_av_hw_frames_pool(struct AVBufferRef **hw_frames_ctx,
struct mp_image *mp_av_pool_image_hw_upload(struct AVBufferRef *hw_frames_ctx,
struct mp_image *src);
+struct mp_image *mp_av_pool_image_hw_map(struct AVBufferRef *hw_frames_ctx,
+ struct mp_image *src);
#endif