mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
hwaccel: Call ->get_format again if hwaccel init fails
This allows the application to fall back on another hwaccel or, more likely, software decoding. Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
This commit is contained in:
parent
9d2cee52d3
commit
1c80c9d7ef
@ -1294,6 +1294,10 @@ typedef struct AVCodecContext {
|
||||
* @param fmt is the list of formats which are supported by the codec,
|
||||
* it is terminated by -1 as 0 is a valid format, the formats are ordered by quality.
|
||||
* The first is always the native one.
|
||||
* @note The callback may be called again immediately if initialization for
|
||||
* the selected (hardware-accelerated) pixel format failed.
|
||||
* @warning Behavior is undefined if the callback returns a value not
|
||||
* in the fmt list of formats.
|
||||
* @return the chosen format
|
||||
* - encoding: unused
|
||||
* - decoding: Set by user, if not set the native format will be chosen.
|
||||
|
@ -898,49 +898,85 @@ static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int setup_hwaccel(AVCodecContext *avctx,
|
||||
const enum AVPixelFormat fmt,
|
||||
const char *name)
|
||||
{
|
||||
AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt);
|
||||
int ret = 0;
|
||||
|
||||
if (!hwa) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"Could not find an AVHWAccel for the pixel format: %s",
|
||||
name);
|
||||
return AVERROR(ENOENT);
|
||||
}
|
||||
|
||||
if (hwa->priv_data_size) {
|
||||
avctx->internal->hwaccel_priv_data = av_mallocz(hwa->priv_data_size);
|
||||
if (!avctx->internal->hwaccel_priv_data)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
if (hwa->init) {
|
||||
ret = hwa->init(avctx);
|
||||
if (ret < 0) {
|
||||
av_freep(&avctx->internal->hwaccel_priv_data);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
avctx->hwaccel = hwa;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc;
|
||||
enum AVPixelFormat ret = avctx->get_format(avctx, fmt);
|
||||
enum AVPixelFormat *choices;
|
||||
enum AVPixelFormat ret;
|
||||
unsigned n = 0;
|
||||
|
||||
desc = av_pix_fmt_desc_get(ret);
|
||||
if (!desc)
|
||||
while (fmt[n] != AV_PIX_FMT_NONE)
|
||||
++n;
|
||||
|
||||
choices = av_malloc_array(n + 1, sizeof(*choices));
|
||||
if (!choices)
|
||||
return AV_PIX_FMT_NONE;
|
||||
|
||||
if (avctx->hwaccel && avctx->hwaccel->uninit)
|
||||
avctx->hwaccel->uninit(avctx);
|
||||
av_freep(&avctx->internal->hwaccel_priv_data);
|
||||
avctx->hwaccel = NULL;
|
||||
memcpy(choices, fmt, (n + 1) * sizeof(*choices));
|
||||
|
||||
if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
|
||||
AVHWAccel *hwaccel;
|
||||
int err;
|
||||
for (;;) {
|
||||
ret = avctx->get_format(avctx, choices);
|
||||
|
||||
hwaccel = find_hwaccel(avctx->codec_id, ret);
|
||||
if (!hwaccel) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"Could not find an AVHWAccel for the pixel format: %s",
|
||||
desc->name);
|
||||
return AV_PIX_FMT_NONE;
|
||||
desc = av_pix_fmt_desc_get(ret);
|
||||
if (!desc) {
|
||||
ret = AV_PIX_FMT_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hwaccel->priv_data_size) {
|
||||
avctx->internal->hwaccel_priv_data = av_mallocz(hwaccel->priv_data_size);
|
||||
if (!avctx->internal->hwaccel_priv_data)
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
if (avctx->hwaccel && avctx->hwaccel->uninit)
|
||||
avctx->hwaccel->uninit(avctx);
|
||||
av_freep(&avctx->internal->hwaccel_priv_data);
|
||||
avctx->hwaccel = NULL;
|
||||
|
||||
if (hwaccel->init) {
|
||||
err = hwaccel->init(avctx);
|
||||
if (err < 0) {
|
||||
av_freep(&avctx->internal->hwaccel_priv_data);
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
}
|
||||
avctx->hwaccel = hwaccel;
|
||||
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
|
||||
break;
|
||||
|
||||
if (!setup_hwaccel(avctx, ret, desc->name))
|
||||
break;
|
||||
|
||||
/* Remove failed hwaccel from choices */
|
||||
for (n = 0; choices[n] != ret; n++)
|
||||
av_assert0(choices[n] != AV_PIX_FMT_NONE);
|
||||
|
||||
do
|
||||
choices[n] = choices[n + 1];
|
||||
while (choices[n] != AV_PIX_FMT_NONE);
|
||||
}
|
||||
|
||||
av_freep(&choices);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user