diff --git a/libavfilter/vf_hwmap.c b/libavfilter/vf_hwmap.c index 11595bd6ca..f19d10f2c2 100644 --- a/libavfilter/vf_hwmap.c +++ b/libavfilter/vf_hwmap.c @@ -30,10 +30,10 @@ typedef struct HWMapContext { const AVClass *class; - AVBufferRef *hwdevice_ref; AVBufferRef *hwframes_ref; int mode; + char *derive_device_type; int map_backwards; } HWMapContext; @@ -52,6 +52,7 @@ static int hwmap_config_output(AVFilterLink *outlink) HWMapContext *ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; AVHWFramesContext *hwfc; + AVBufferRef *device; const AVPixFmtDescriptor *desc; int err; @@ -59,30 +60,58 @@ static int hwmap_config_output(AVFilterLink *outlink) av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(outlink->format)); + av_buffer_unref(&ctx->hwframes_ref); + + device = avctx->hw_device_ctx; + if (inlink->hw_frames_ctx) { hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + if (ctx->derive_device_type) { + enum AVHWDeviceType type; + + type = av_hwdevice_find_type_by_name(ctx->derive_device_type); + if (type == AV_HWDEVICE_TYPE_NONE) { + av_log(avctx, AV_LOG_ERROR, "Invalid device type.\n"); + goto fail; + } + + err = av_hwdevice_ctx_create_derived(&device, type, + hwfc->device_ref, 0); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to created derived " + "device context: %d.\n", err); + goto fail; + } + } + desc = av_pix_fmt_desc_get(outlink->format); - if (!desc) - return AVERROR(EINVAL); + if (!desc) { + err = AVERROR(EINVAL); + goto fail; + } if (inlink->format == hwfc->format && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { // Map between two hardware formats (including the case of // undoing an existing mapping). - ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx); - if (!ctx->hwdevice_ref) { - err = AVERROR(ENOMEM); + if (!device) { + av_log(avctx, AV_LOG_ERROR, "A device reference is " + "required to map to a hardware format.\n"); + err = AVERROR(EINVAL); goto fail; } err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, - ctx->hwdevice_ref, + device, inlink->hw_frames_ctx, 0); - if (err < 0) + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to create derived " + "frames context: %d.\n", err); goto fail; + } } else if ((outlink->format == hwfc->format && inlink->format == hwfc->sw_format) || @@ -90,8 +119,6 @@ static int hwmap_config_output(AVFilterLink *outlink) // Map from a hardware format to a software format, or // undo an existing such mapping. - ctx->hwdevice_ref = NULL; - ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); @@ -115,15 +142,17 @@ static int hwmap_config_output(AVFilterLink *outlink) // returns frames mapped from that to the previous link in // order to fill them without an additional copy. - ctx->map_backwards = 1; - - ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx); - if (!ctx->hwdevice_ref) { - err = AVERROR(ENOMEM); + if (!device) { + av_log(avctx, AV_LOG_ERROR, "A device reference is " + "required to create new frames with backwards " + "mapping.\n"); + err = AVERROR(EINVAL); goto fail; } - ctx->hwframes_ref = av_hwframe_ctx_alloc(ctx->hwdevice_ref); + ctx->map_backwards = 1; + + ctx->hwframes_ref = av_hwframe_ctx_alloc(device); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; @@ -161,7 +190,6 @@ static int hwmap_config_output(AVFilterLink *outlink) fail: av_buffer_unref(&ctx->hwframes_ref); - av_buffer_unref(&ctx->hwdevice_ref); return err; } @@ -269,7 +297,6 @@ static av_cold void hwmap_uninit(AVFilterContext *avctx) HWMapContext *ctx = avctx->priv; av_buffer_unref(&ctx->hwframes_ref); - av_buffer_unref(&ctx->hwdevice_ref); } #define OFFSET(x) offsetof(HWMapContext, x) @@ -293,6 +320,10 @@ static const AVOption hwmap_options[] = { 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_DIRECT }, INT_MIN, INT_MAX, FLAGS, "mode" }, + { "derive_device", "Derive a new device of this type", + OFFSET(derive_device_type), AV_OPT_TYPE_STRING, + { .str = NULL }, 0, 0, FLAGS }, + { NULL }, };