diff options
-rw-r--r-- | libavutil/hwcontext.c | 53 |
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; } |