diff options
author | RĂ©mi Denis-Courmont <remi@remlab.net> | 2014-09-16 22:17:47 +0300 |
---|---|---|
committer | Luca Barbato <lu_zero@gentoo.org> | 2014-09-26 21:28:36 +0200 |
commit | 1c80c9d7ef809180042257200c7b5f6b81d0b0e2 (patch) | |
tree | c642d47006c38dea27b5c1b3a3a87bf09efd3028 /libavcodec | |
parent | 9d2cee52d37c7340f85a5d41110282aac03e6855 (diff) | |
download | ffmpeg-1c80c9d7ef809180042257200c7b5f6b81d0b0e2.tar.gz |
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>
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/avcodec.h | 4 | ||||
-rw-r--r-- | libavcodec/utils.c | 98 |
2 files changed, 71 insertions, 31 deletions
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index bc5f1346f2..dfbab9b60f 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -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. diff --git a/libavcodec/utils.c b/libavcodec/utils.c index c5fa50d06b..a47207610d 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -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; - - if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { - AVHWAccel *hwaccel; - int err; - - 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; - } + memcpy(choices, fmt, (n + 1) * sizeof(*choices)); - 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; - } + for (;;) { + ret = avctx->get_format(avctx, choices); - if (hwaccel->init) { - err = hwaccel->init(avctx); - if (err < 0) { - av_freep(&avctx->internal->hwaccel_priv_data); - return AV_PIX_FMT_NONE; - } + desc = av_pix_fmt_desc_get(ret); + if (!desc) { + ret = AV_PIX_FMT_NONE; + break; } - avctx->hwaccel = hwaccel; + + if (avctx->hwaccel && avctx->hwaccel->uninit) + avctx->hwaccel->uninit(avctx); + av_freep(&avctx->internal->hwaccel_priv_data); + avctx->hwaccel = NULL; + + 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; } |