summaryrefslogtreecommitdiff
path: root/libavutil
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2019-10-23 18:01:52 -0700
committerLynne <dev@lynne.ee>2020-02-04 23:19:48 +0000
commitd7210ce7f5418508d6f8eec6e90d978e06a2d49e (patch)
tree6390e00e0f891a774025bd5ab6d408cd05957deb /libavutil
parentd84a30e1238b9feed1c957809108fc5e39d80629 (diff)
lavu/hwcontext: Add support for HW -> HW transfers
We are beginning to consider scenarios where a given HW Context may be able to transfer frames to another HW Context without passing via system memory - this would usually be when two contexts represent different APIs on the same device (eg: Vulkan and CUDA). This is modelled as a transfer, as we have today, but where both the src and the dst are hardware frames with hw contexts. We need to be careful to ensure the contexts are compatible - particularly, we cannot do transfers where one of the frames has been mapped via a derived frames context - we can only do transfers for frames that were directly allocated by the specified context. Additionally, as we have two hardware contexts, the transfer function could be implemented by either (or indeed both). To handle this uncertainty, we explicitly look for ENOSYS as an indicator to try the transfer in the other direction before giving up.
Diffstat (limited to 'libavutil')
-rw-r--r--libavutil/hwcontext.c53
1 files changed, 43 insertions, 10 deletions
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index f1e404ab20..3189391c07 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -444,21 +444,54 @@ int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
if (!dst->buf[0])
return transfer_data_alloc(dst, src, flags);
- if (src->hw_frames_ctx) {
- ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
+ /*
+ * Hardware -> Hardware Transfer.
+ * Unlike Software -> Hardware or Hardware -> Software, the transfer
+ * function could be provided by either the src or dst, depending on
+ * the specific combination of hardware.
+ */
+ if (src->hw_frames_ctx && dst->hw_frames_ctx) {
+ AVHWFramesContext *src_ctx =
+ (AVHWFramesContext*)src->hw_frames_ctx->data;
+ AVHWFramesContext *dst_ctx =
+ (AVHWFramesContext*)dst->hw_frames_ctx->data;
+
+ if (src_ctx->internal->source_frames) {
+ av_log(src_ctx, AV_LOG_ERROR,
+ "A device with a derived frame context cannot be used as "
+ "the source of a HW -> HW transfer.");
+ return AVERROR(ENOSYS);
+ }
- ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src);
- if (ret < 0)
- return ret;
- } else if (dst->hw_frames_ctx) {
- ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data;
+ if (dst_ctx->internal->source_frames) {
+ av_log(src_ctx, AV_LOG_ERROR,
+ "A device with a derived frame context cannot be used as "
+ "the destination of a HW -> HW transfer.");
+ return AVERROR(ENOSYS);
+ }
- ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src);
+ ret = src_ctx->internal->hw_type->transfer_data_from(src_ctx, dst, src);
+ if (ret == AVERROR(ENOSYS))
+ ret = dst_ctx->internal->hw_type->transfer_data_to(dst_ctx, dst, src);
if (ret < 0)
return ret;
- } else
- return AVERROR(ENOSYS);
+ } else {
+ if (src->hw_frames_ctx) {
+ ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
+
+ ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src);
+ if (ret < 0)
+ return ret;
+ } else if (dst->hw_frames_ctx) {
+ ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data;
+ ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src);
+ if (ret < 0)
+ return ret;
+ } else {
+ return AVERROR(ENOSYS);
+ }
+ }
return 0;
}