summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}