mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
ffmpeg: Don't require a known device to pass a frames context to an encoder
The previous code here did not handle passing a frames context when ffmpeg itself did not know about the device it came from (for example, because it was created by device derivation inside a filter graph), which would break encoders requiring that input. Fix that by checking for HW frames and device context methods independently, and prefer to use a frames context method if possible. At the same time, revert the encoding additions to the device matching function because the additional complexity was not relevant to decoding. Also fixes #8637, which is the same case but with the device creation hidden in the ad-hoc libmfx setup code.
This commit is contained in:
parent
1a9684c08a
commit
706ed34ce7
@ -19,6 +19,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libavutil/avstring.h"
|
#include "libavutil/avstring.h"
|
||||||
|
#include "libavutil/pixdesc.h"
|
||||||
#include "libavfilter/buffersink.h"
|
#include "libavfilter/buffersink.h"
|
||||||
|
|
||||||
#include "ffmpeg.h"
|
#include "ffmpeg.h"
|
||||||
@ -282,10 +283,7 @@ void hw_device_free_all(void)
|
|||||||
nb_hw_devices = 0;
|
nb_hw_devices = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HWDevice *hw_device_match_by_codec(const AVCodec *codec,
|
static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
|
||||||
enum AVPixelFormat format,
|
|
||||||
int possible_methods,
|
|
||||||
int *matched_methods)
|
|
||||||
{
|
{
|
||||||
const AVCodecHWConfig *config;
|
const AVCodecHWConfig *config;
|
||||||
HWDevice *dev;
|
HWDevice *dev;
|
||||||
@ -294,20 +292,13 @@ static HWDevice *hw_device_match_by_codec(const AVCodec *codec,
|
|||||||
config = avcodec_get_hw_config(codec, i);
|
config = avcodec_get_hw_config(codec, i);
|
||||||
if (!config)
|
if (!config)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (format != AV_PIX_FMT_NONE &&
|
if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
|
||||||
config->pix_fmt != AV_PIX_FMT_NONE &&
|
|
||||||
config->pix_fmt != format)
|
|
||||||
continue;
|
|
||||||
if (!(config->methods & possible_methods))
|
|
||||||
continue;
|
continue;
|
||||||
dev = hw_device_get_by_type(config->device_type);
|
dev = hw_device_get_by_type(config->device_type);
|
||||||
if (dev) {
|
if (dev)
|
||||||
if (matched_methods)
|
|
||||||
*matched_methods = config->methods & possible_methods;
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int hw_device_setup_for_decode(InputStream *ist)
|
int hw_device_setup_for_decode(InputStream *ist)
|
||||||
{
|
{
|
||||||
@ -351,9 +342,7 @@ int hw_device_setup_for_decode(InputStream *ist)
|
|||||||
if (!dev)
|
if (!dev)
|
||||||
err = hw_device_init_from_type(type, NULL, &dev);
|
err = hw_device_init_from_type(type, NULL, &dev);
|
||||||
} else {
|
} else {
|
||||||
dev = hw_device_match_by_codec(ist->dec, AV_PIX_FMT_NONE,
|
dev = hw_device_match_by_codec(ist->dec);
|
||||||
AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
|
|
||||||
NULL);
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
// No device for this codec, but not using generic hwaccel
|
// No device for this codec, but not using generic hwaccel
|
||||||
// and therefore may well not need one - ignore.
|
// and therefore may well not need one - ignore.
|
||||||
@ -429,37 +418,57 @@ int hw_device_setup_for_decode(InputStream *ist)
|
|||||||
|
|
||||||
int hw_device_setup_for_encode(OutputStream *ost)
|
int hw_device_setup_for_encode(OutputStream *ost)
|
||||||
{
|
{
|
||||||
HWDevice *dev;
|
const AVCodecHWConfig *config;
|
||||||
AVBufferRef *frames_ref;
|
HWDevice *dev = NULL;
|
||||||
int methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX;
|
AVBufferRef *frames_ref = NULL;
|
||||||
int matched_methods;
|
int i;
|
||||||
|
|
||||||
if (ost->filter) {
|
if (ost->filter) {
|
||||||
frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter);
|
frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter);
|
||||||
if (frames_ref &&
|
if (frames_ref &&
|
||||||
((AVHWFramesContext*)frames_ref->data)->format ==
|
((AVHWFramesContext*)frames_ref->data)->format ==
|
||||||
ost->enc_ctx->pix_fmt)
|
ost->enc_ctx->pix_fmt) {
|
||||||
methods |= AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX;
|
// Matching format, will try to use hw_frames_ctx.
|
||||||
|
} else {
|
||||||
|
frames_ref = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = hw_device_match_by_codec(ost->enc, ost->enc_ctx->pix_fmt,
|
for (i = 0;; i++) {
|
||||||
methods, &matched_methods);
|
config = avcodec_get_hw_config(ost->enc, i);
|
||||||
if (dev) {
|
if (!config)
|
||||||
if (matched_methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) {
|
break;
|
||||||
ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
|
|
||||||
if (!ost->enc_ctx->hw_device_ctx)
|
if (frames_ref &&
|
||||||
return AVERROR(ENOMEM);
|
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX &&
|
||||||
}
|
(config->pix_fmt == AV_PIX_FMT_NONE ||
|
||||||
if (matched_methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) {
|
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);
|
ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref);
|
||||||
if (!ost->enc_ctx->hw_frames_ctx)
|
if (!ost->enc_ctx->hw_frames_ctx)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev &&
|
||||||
|
config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
|
||||||
|
dev = hw_device_get_by_type(config->device_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
} else {
|
} else {
|
||||||
// No device required, or no device available.
|
// No device required, or no device available.
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
|
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user