[libav-devel] [PATCH 1/1] ff_get_format: call ->get_format again if hwaccel init fails

Rémi Denis-Courmont remi at remlab.net
Wed Sep 10 19:38:44 CEST 2014


This allows the application to fallback to another hwaccel, or more
likely, to software decoding.
---
 libavcodec/utils.c | 47 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index c5fa50d..600854e 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -902,11 +902,26 @@ static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
 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;
+
+    while (fmt[n] != AV_PIX_FMT_NONE)
+        ++n;
+
+    choices = av_malloc(++n * sizeof(*choices));
+    if (choices == NULL)
+        return AV_PIX_FMT_NONE;
+
+    memcpy(choices, fmt, n * sizeof(*choices));
+retry:
+    ret = avctx->get_format(avctx, choices);
 
     desc = av_pix_fmt_desc_get(ret);
-    if (!desc)
+    if (!desc) {
+        av_freep(&choices);
         return AV_PIX_FMT_NONE;
+    }
 
     if (avctx->hwaccel && avctx->hwaccel->uninit)
         avctx->hwaccel->uninit(avctx);
@@ -915,32 +930,44 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
 
     if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
         AVHWAccel *hwaccel;
-        int err;
+        int err = 0;
 
         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;
+            err = AVERROR(ENOENT);
         }
 
-        if (hwaccel->priv_data_size) {
+        if (err == 0 && 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;
+                err = AVERROR(ENOMEM);
         }
 
-        if (hwaccel->init) {
+        if (err == 0 && hwaccel->init) {
             err = hwaccel->init(avctx);
-            if (err < 0) {
+            if (err < 0)
                 av_freep(&avctx->internal->hwaccel_priv_data);
-                return AV_PIX_FMT_NONE;
-            }
+        }
+
+        if (err < 0) {
+            /* Remove failed hwaccel from choices and reiterate */
+            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_assert0(n > 0);
+            goto retry;
         }
         avctx->hwaccel = hwaccel;
     }
 
+    av_freep(&choices);
     return ret;
 }
 
-- 
2.1.0



More information about the libav-devel mailing list