X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=fftools%2Fffmpeg_hw.c;h=fc4a5d31d6aeaeca7a4dd762dc485a5d364c55ce;hb=8b3e6ce5f4ab1ebf3a54ff7e0ff440a1a5f842f7;hp=2ec181385430b260c662b53ea97275a80aa7c59f;hpb=1c9ac700dd141e545538a824f5a8cb81bb0a375d;p=ffmpeg diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c index 2ec18138543..fc4a5d31d6a 100644 --- a/fftools/ffmpeg_hw.c +++ b/fftools/ffmpeg_hw.c @@ -19,6 +19,8 @@ #include #include "libavutil/avstring.h" +#include "libavutil/pixdesc.h" +#include "libavfilter/buffersink.h" #include "ffmpeg.h" @@ -99,7 +101,7 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) // -> av_hwdevice_ctx_create_derived() AVDictionary *options = NULL; - char *type_name = NULL, *name = NULL, *device = NULL; + const char *type_name = NULL, *name = NULL, *device = NULL; enum AVHWDeviceType type; HWDevice *dev, *src; AVBufferRef *device_ref = NULL; @@ -155,10 +157,12 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) ++p; q = strchr(p, ','); if (q) { - device = av_strndup(p, q - p); - if (!device) { - err = AVERROR(ENOMEM); - goto fail; + if (q - p > 0) { + device = av_strndup(p, q - p); + if (!device) { + err = AVERROR(ENOMEM); + goto fail; + } } err = av_dict_parse_string(&options, q + 1, "=", ",", 0); if (err < 0) { @@ -168,7 +172,8 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) } err = av_hwdevice_ctx_create(&device_ref, type, - device ? device : p, options, 0); + q ? device : p[0] ? p : NULL, + options, 0); if (err < 0) goto fail; @@ -413,18 +418,57 @@ int hw_device_setup_for_decode(InputStream *ist) int hw_device_setup_for_encode(OutputStream *ost) { - HWDevice *dev; + const AVCodecHWConfig *config; + HWDevice *dev = NULL; + AVBufferRef *frames_ref = NULL; + int i; + + if (ost->filter) { + frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter); + if (frames_ref && + ((AVHWFramesContext*)frames_ref->data)->format == + ost->enc_ctx->pix_fmt) { + // Matching format, will try to use hw_frames_ctx. + } else { + frames_ref = NULL; + } + } + + for (i = 0;; i++) { + config = avcodec_get_hw_config(ost->enc, i); + if (!config) + break; + + if (frames_ref && + config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX && + (config->pix_fmt == AV_PIX_FMT_NONE || + config->pix_fmt == ost->enc_ctx->pix_fmt)) { + av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using input " + "frames context (format %s) with %s encoder.\n", + av_get_pix_fmt_name(ost->enc_ctx->pix_fmt), + ost->enc->name); + ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref); + if (!ost->enc_ctx->hw_frames_ctx) + return AVERROR(ENOMEM); + return 0; + } + + if (!dev && + config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) + dev = hw_device_get_by_type(config->device_type); + } - dev = hw_device_match_by_codec(ost->enc); if (dev) { + av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using device %s " + "(type %s) with %s encoder.\n", dev->name, + av_hwdevice_get_type_name(dev->type), ost->enc->name); ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); if (!ost->enc_ctx->hw_device_ctx) return AVERROR(ENOMEM); - return 0; } else { // No device required, or no device available. - return 0; } + return 0; } static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input) @@ -477,3 +521,31 @@ int hwaccel_decode_init(AVCodecContext *avctx) return 0; } + +int hw_device_setup_for_filter(FilterGraph *fg) +{ + HWDevice *dev; + int i; + + // If the user has supplied exactly one hardware device then just + // give it straight to every filter for convenience. If more than + // one device is available then the user needs to pick one explcitly + // with the filter_hw_device option. + if (filter_hw_device) + dev = filter_hw_device; + else if (nb_hw_devices == 1) + dev = hw_devices[0]; + else + dev = NULL; + + if (dev) { + for (i = 0; i < fg->graph->nb_filters; i++) { + fg->graph->filters[i]->hw_device_ctx = + av_buffer_ref(dev->device_ref); + if (!fg->graph->filters[i]->hw_device_ctx) + return AVERROR(ENOMEM); + } + } + + return 0; +}