#include <string.h>
#include "libavutil/avstring.h"
+#include "libavutil/pixdesc.h"
+#include "libavfilter/buffersink.h"
#include "ffmpeg.h"
// -> 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;
++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) {
}
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;
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)
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;
+}