This allows the application to fallback to another hwaccel, or more
likely, to software decoding.
---
 libavcodec/avcodec.h |  4 ++++
 libavcodec/utils.c   | 64 ++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 51 insertions(+), 17 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 253e45a..9f7922f 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 c5fa50d..816a11e 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -902,45 +902,75 @@ 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;
 
-    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 == NULL)
         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) {
+    for (;;)
+    {
         AVHWAccel *hwaccel;
-        int err;
+        int err = 0;
+
+        ret = avctx->get_format(avctx, choices);
+
+        desc = av_pix_fmt_desc_get(ret);
+        if (!desc) {
+            ret = AV_PIX_FMT_NONE;
+            break;
+        }
+
+        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;
 
         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;
-            }
         }
-        avctx->hwaccel = hwaccel;
+
+        if (err == 0) {
+            avctx->hwaccel = hwaccel;
+            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;
 }
 
-- 
1.8.1.5

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to