diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index db7f05a3e0..4616a4239e 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -765,6 +765,17 @@ deriving it from the existing device with the name @var{source}. @item -init_hw_device list List all hardware device types supported in this build of ffmpeg. +@item -filter_hw_device @var{name} +Pass the hardware device called @var{name} to all filters in any filter graph. +This can be used to set the device to upload to with the @code{hwupload} filter, +or the device to map to with the @code{hwmap} filter. Other filters may also +make use of this parameter when they require a hardware device. Note that this +is typically only required when the input is not already in hardware frames - +when it is, filters will derive the device they require from the context of the +frames they receive as input. + +This is a global setting, so all filters will receive the same device. + @item -hwaccel[:@var{stream_specifier}] @var{hwaccel} (@emph{input,per-stream}) Use hardware acceleration to decode the matching stream(s). The allowed values of @var{hwaccel} are: diff --git a/ffmpeg.h b/ffmpeg.h index fbb9172d74..c3854bcb4a 100644 --- a/ffmpeg.h +++ b/ffmpeg.h @@ -628,6 +628,7 @@ extern AVBufferRef *hw_device_ctx; #if CONFIG_QSV extern char *qsv_device; #endif +extern HWDevice *filter_hw_device; void term_init(void); diff --git a/ffmpeg_filter.c b/ffmpeg_filter.c index 817f48f473..aacc185059 100644 --- a/ffmpeg_filter.c +++ b/ffmpeg_filter.c @@ -1046,9 +1046,15 @@ int configure_filtergraph(FilterGraph *fg) if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) goto fail; - if (hw_device_ctx) { + if (filter_hw_device || hw_device_ctx) { + AVBufferRef *device = filter_hw_device ? filter_hw_device->device_ref + : hw_device_ctx; for (i = 0; i < fg->graph->nb_filters; i++) { - fg->graph->filters[i]->hw_device_ctx = av_buffer_ref(hw_device_ctx); + fg->graph->filters[i]->hw_device_ctx = av_buffer_ref(device); + if (!fg->graph->filters[i]->hw_device_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } } } diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index be9c6fb6ac..bb6001f534 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -98,6 +98,7 @@ const HWAccel hwaccels[] = { }; int hwaccel_lax_profile_check = 0; AVBufferRef *hw_device_ctx; +HWDevice *filter_hw_device; char *vstats_filename; char *sdp_filename; @@ -495,6 +496,20 @@ static int opt_init_hw_device(void *optctx, const char *opt, const char *arg) } } +static int opt_filter_hw_device(void *optctx, const char *opt, const char *arg) +{ + if (filter_hw_device) { + av_log(NULL, AV_LOG_ERROR, "Only one filter device can be used.\n"); + return AVERROR(EINVAL); + } + filter_hw_device = hw_device_get_by_name(arg); + if (!filter_hw_device) { + av_log(NULL, AV_LOG_ERROR, "Invalid filter device %s.\n", arg); + return AVERROR(EINVAL); + } + return 0; +} + /** * Parse a metadata specifier passed as 'arg' parameter. * @param arg metadata string to parse @@ -3708,6 +3723,8 @@ const OptionDef options[] = { { "init_hw_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_init_hw_device }, "initialise hardware device", "args" }, + { "filter_hw_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_hw_device }, + "set hardware device used when filtering", "device" }, { NULL, }, };