[FFmpeg-devel] [PATCH 2/4] vaapi: Implement device-only setup

Mark Thompson sw at jkqxz.net
Wed Mar 22 00:43:56 EET 2017


In this case, the user only supplies a device and the frame context
is allocated internally by lavc.

(cherry picked from commit 5dd9a4b88b287bf8c93520afda7becb1ad0d1894)
---
This doesn't work with ffmpeg.c yet (still uses hw_frames_ctx), but is accessible to lavc users.

See <https://git.libav.org/?p=libav.git;a=blob;f=avtools/avconv_hw.c> for the intended structure in ffmpeg.c (not yet merging because of further patches pending).


 libavcodec/vaapi_decode.c | 129 +++++++++++++++++++++++++++++++++++++++-------
 libavcodec/vaapi_decode.h |   3 ++
 libavcodec/version.h      |   2 +-
 3 files changed, 115 insertions(+), 19 deletions(-)

diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index da9e4aedde..b63fb94fc1 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -18,6 +18,7 @@
 
 #include "libavutil/avassert.h"
 #include "libavutil/common.h"
+#include "libavutil/pixdesc.h"
 
 #include "avcodec.h"
 #include "internal.h"
@@ -283,6 +284,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx)
     const AVCodecDescriptor *codec_desc;
     VAProfile profile, *profile_list = NULL;
     int profile_count, exact_match, alt_profile;
+    const AVPixFmtDescriptor *sw_desc, *desc;
 
     // Allowing a profile mismatch can be useful because streams may
     // over-declare their required capabilities - in particular, many
@@ -375,7 +377,9 @@ static int vaapi_decode_make_config(AVCodecContext *avctx)
         goto fail;
     }
 
-    hwconfig = av_hwdevice_hwconfig_alloc(ctx->frames->device_ref);
+    hwconfig = av_hwdevice_hwconfig_alloc(avctx->hw_device_ctx ?
+                                          avctx->hw_device_ctx :
+                                          ctx->frames->device_ref);
     if (!hwconfig) {
         err = AVERROR(ENOMEM);
         goto fail;
@@ -383,24 +387,77 @@ static int vaapi_decode_make_config(AVCodecContext *avctx)
     hwconfig->config_id = ctx->va_config;
 
     constraints =
-        av_hwdevice_get_hwframe_constraints(ctx->frames->device_ref,
+        av_hwdevice_get_hwframe_constraints(avctx->hw_device_ctx ?
+                                            avctx->hw_device_ctx :
+                                            ctx->frames->device_ref,
                                             hwconfig);
     if (!constraints) {
-        // Ignore.
-    } else {
-        if (avctx->coded_width  < constraints->min_width  ||
-            avctx->coded_height < constraints->min_height ||
-            avctx->coded_width  > constraints->max_width  ||
-            avctx->coded_height > constraints->max_height) {
-            av_log(avctx, AV_LOG_ERROR, "Hardware does not support image "
-                   "size %dx%d (constraints: width %d-%d height %d-%d).\n",
-                   avctx->coded_width, avctx->coded_height,
-                   constraints->min_width,  constraints->max_width,
-                   constraints->min_height, constraints->max_height);
-            err = AVERROR(EINVAL);
-            goto fail;
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    if (avctx->coded_width  < constraints->min_width  ||
+        avctx->coded_height < constraints->min_height ||
+        avctx->coded_width  > constraints->max_width  ||
+        avctx->coded_height > constraints->max_height) {
+        av_log(avctx, AV_LOG_ERROR, "Hardware does not support image "
+               "size %dx%d (constraints: width %d-%d height %d-%d).\n",
+               avctx->coded_width, avctx->coded_height,
+               constraints->min_width,  constraints->max_width,
+               constraints->min_height, constraints->max_height);
+        err = AVERROR(EINVAL);
+        goto fail;
+    }
+    if (!constraints->valid_sw_formats ||
+        constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) {
+        av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any "
+               "usable surface formats.\n");
+        err = AVERROR(EINVAL);
+        goto fail;
+    }
+
+    // Find the first format in the list which matches the expected
+    // bit depth and subsampling.  If none are found (this can happen
+    // when 10-bit streams are decoded to 8-bit surfaces, for example)
+    // then just take the first format on the list.
+    ctx->surface_format = constraints->valid_sw_formats[0];
+    sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
+    for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
+        desc = av_pix_fmt_desc_get(constraints->valid_sw_formats[i]);
+        if (desc->nb_components != sw_desc->nb_components ||
+            desc->log2_chroma_w != sw_desc->log2_chroma_w ||
+            desc->log2_chroma_h != sw_desc->log2_chroma_h)
+            continue;
+        for (j = 0; j < desc->nb_components; j++) {
+            if (desc->comp[j].depth != sw_desc->comp[j].depth)
+                break;
         }
+        if (j < desc->nb_components)
+            continue;
+        ctx->surface_format = constraints->valid_sw_formats[i];
+        break;
+    }
+
+    // Start with at least four surfaces.
+    ctx->surface_count = 4;
+    // Add per-codec number of surfaces used for storing reference frames.
+    switch (avctx->codec_id) {
+    case AV_CODEC_ID_H264:
+    case AV_CODEC_ID_HEVC:
+        ctx->surface_count += 16;
+        break;
+    case AV_CODEC_ID_VP9:
+        ctx->surface_count += 8;
+        break;
+    case AV_CODEC_ID_VP8:
+        ctx->surface_count += 3;
+        break;
+    default:
+        ctx->surface_count += 2;
     }
+    // Add an additional surface per thread is frame threading is enabled.
+    if (avctx->active_thread_type & FF_THREAD_FRAME)
+        ctx->surface_count += avctx->thread_count;
 
     av_hwframe_constraints_free(&constraints);
     av_freep(&hwconfig);
@@ -463,13 +520,24 @@ int ff_vaapi_decode_init(AVCodecContext *avctx)
 
         ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
         ctx->hwfc   = ctx->frames->hwctx;
-
         ctx->device = ctx->frames->device_ctx;
         ctx->hwctx  = ctx->device->hwctx;
 
+    } else if (avctx->hw_device_ctx) {
+        ctx->device = (AVHWDeviceContext*)avctx->hw_device_ctx->data;
+        ctx->hwctx  = ctx->device->hwctx;
+
+        if (ctx->device->type != AV_HWDEVICE_TYPE_VAAPI) {
+            av_log(avctx, AV_LOG_ERROR, "Device supplied for VAAPI "
+                   "decoding must be a VAAPI device (not %d).\n",
+                   ctx->device->type);
+            err = AVERROR(EINVAL);
+            goto fail;
+        }
+
     } else {
-        av_log(avctx, AV_LOG_ERROR, "A hardware frames context is "
-               "required for VAAPI decoding.\n");
+        av_log(avctx, AV_LOG_ERROR, "A hardware device or frames context "
+               "is required for VAAPI decoding.\n");
         err = AVERROR(EINVAL);
         goto fail;
     }
@@ -488,6 +556,31 @@ int ff_vaapi_decode_init(AVCodecContext *avctx)
     if (err)
         goto fail;
 
+    if (!avctx->hw_frames_ctx) {
+        avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
+        if (!avctx->hw_frames_ctx) {
+            err = AVERROR(ENOMEM);
+            goto fail;
+        }
+        ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+
+        ctx->frames->format = AV_PIX_FMT_VAAPI;
+        ctx->frames->width  = avctx->coded_width;
+        ctx->frames->height = avctx->coded_height;
+
+        ctx->frames->sw_format         = ctx->surface_format;
+        ctx->frames->initial_pool_size = ctx->surface_count;
+
+        err = av_hwframe_ctx_init(avctx->hw_frames_ctx);
+        if (err < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal "
+                   "frames context: %d.\n", err);
+            goto fail;
+        }
+
+        ctx->hwfc = ctx->frames->hwctx;
+    }
+
     vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
                           avctx->coded_width, avctx->coded_height,
                           VA_PROGRESSIVE,
diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h
index 5ac3069ef3..4fe414c504 100644
--- a/libavcodec/vaapi_decode.h
+++ b/libavcodec/vaapi_decode.h
@@ -69,6 +69,9 @@ typedef struct VAAPIDecodeContext {
 
     AVHWFramesContext    *frames;
     AVVAAPIFramesContext *hwfc;
+
+    enum AVPixelFormat    surface_format;
+    int                   surface_count;
 } VAAPIDecodeContext;
 
 
diff --git a/libavcodec/version.h b/libavcodec/version.h
index ec8651f086..8d9dda7675 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #define LIBAVCODEC_VERSION_MAJOR  57
 #define LIBAVCODEC_VERSION_MINOR  83
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MICRO 102
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
-- 
2.11.0



More information about the ffmpeg-devel mailing list