Browse code

Merge commit '2bfa067d0b636e7b2004fb0ad5a53d0d48c6de32'

* commit '2bfa067d0b636e7b2004fb0ad5a53d0d48c6de32':
vaapi_encode: Check config attributes before creating config

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>

Hendrik Leppkes authored on 2016/06/26 22:44:25
Showing 1 changed files
... ...
@@ -20,6 +20,7 @@
20 20
 #include <string.h>
21 21
 
22 22
 #include "libavutil/avassert.h"
23
+#include "libavutil/common.h"
23 24
 #include "libavutil/log.h"
24 25
 #include "libavutil/pixdesc.h"
25 26
 
... ...
@@ -887,6 +888,122 @@ fail:
887 887
     return err;
888 888
 }
889 889
 
890
+static av_cold int vaapi_encode_check_config(AVCodecContext *avctx)
891
+{
892
+    VAAPIEncodeContext *ctx = avctx->priv_data;
893
+    VAStatus vas;
894
+    int i, n, err;
895
+    VAProfile    *profiles    = NULL;
896
+    VAEntrypoint *entrypoints = NULL;
897
+    VAConfigAttrib attr[] = {
898
+        { VAConfigAttribRateControl     },
899
+        { VAConfigAttribEncMaxRefFrames },
900
+    };
901
+
902
+    n = vaMaxNumProfiles(ctx->hwctx->display);
903
+    profiles = av_malloc_array(n, sizeof(VAProfile));
904
+    if (!profiles) {
905
+        err = AVERROR(ENOMEM);
906
+        goto fail;
907
+    }
908
+    vas = vaQueryConfigProfiles(ctx->hwctx->display, profiles, &n);
909
+    if (vas != VA_STATUS_SUCCESS) {
910
+        av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n",
911
+               vas, vaErrorStr(vas));
912
+        err = AVERROR(ENOSYS);
913
+        goto fail;
914
+    }
915
+    for (i = 0; i < n; i++) {
916
+        if (profiles[i] == ctx->va_profile)
917
+            break;
918
+    }
919
+    if (i >= n) {
920
+        av_log(ctx, AV_LOG_ERROR, "Encoding profile not found (%d).\n",
921
+               ctx->va_profile);
922
+        err = AVERROR(ENOSYS);
923
+        goto fail;
924
+    }
925
+
926
+    n = vaMaxNumEntrypoints(ctx->hwctx->display);
927
+    entrypoints = av_malloc_array(n, sizeof(VAEntrypoint));
928
+    if (!entrypoints) {
929
+        err = AVERROR(ENOMEM);
930
+        goto fail;
931
+    }
932
+    vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile,
933
+                                   entrypoints, &n);
934
+    if (vas != VA_STATUS_SUCCESS) {
935
+        av_log(ctx, AV_LOG_ERROR, "Failed to query entrypoints for "
936
+               "profile %u: %d (%s).\n", ctx->va_profile,
937
+               vas, vaErrorStr(vas));
938
+        err = AVERROR(ENOSYS);
939
+        goto fail;
940
+    }
941
+    for (i = 0; i < n; i++) {
942
+        if (entrypoints[i] == ctx->va_entrypoint)
943
+            break;
944
+    }
945
+    if (i >= n) {
946
+        av_log(ctx, AV_LOG_ERROR, "Encoding entrypoint not found "
947
+               "(%d / %d).\n", ctx->va_profile, ctx->va_entrypoint);
948
+        err = AVERROR(ENOSYS);
949
+        goto fail;
950
+    }
951
+
952
+    vas = vaGetConfigAttributes(ctx->hwctx->display,
953
+                                ctx->va_profile, ctx->va_entrypoint,
954
+                                attr, FF_ARRAY_ELEMS(attr));
955
+    if (vas != VA_STATUS_SUCCESS) {
956
+        av_log(avctx, AV_LOG_ERROR, "Failed to fetch config "
957
+               "attributes: %d (%s).\n", vas, vaErrorStr(vas));
958
+        return AVERROR(EINVAL);
959
+    }
960
+
961
+    for (i = 0; i < FF_ARRAY_ELEMS(attr); i++) {
962
+        if (attr[i].value == VA_ATTRIB_NOT_SUPPORTED) {
963
+            // Unfortunately we have to treat this as "don't know" and hope
964
+            // for the best, because the Intel MJPEG encoder returns this
965
+            // for all the interesting attributes.
966
+            continue;
967
+        }
968
+        switch (attr[i].type) {
969
+        case VAConfigAttribRateControl:
970
+            if (!(ctx->va_rc_mode & attr[i].value)) {
971
+                av_log(avctx, AV_LOG_ERROR, "Rate control mode is not "
972
+                       "supported: %x\n", attr[i].value);
973
+                err = AVERROR(EINVAL);
974
+                goto fail;
975
+            }
976
+            break;
977
+        case VAConfigAttribEncMaxRefFrames:
978
+        {
979
+            unsigned int ref_l0 = attr[i].value & 0xffff;
980
+            unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff;
981
+
982
+            if (avctx->gop_size > 1 && ref_l0 < 1) {
983
+                av_log(avctx, AV_LOG_ERROR, "P frames are not "
984
+                       "supported (%x).\n", attr[i].value);
985
+                err = AVERROR(EINVAL);
986
+                goto fail;
987
+            }
988
+            if (avctx->max_b_frames > 0 && ref_l1 < 1) {
989
+                av_log(avctx, AV_LOG_ERROR, "B frames are not "
990
+                       "supported (%x).\n", attr[i].value);
991
+                err = AVERROR(EINVAL);
992
+                goto fail;
993
+            }
994
+        }
995
+        break;
996
+        }
997
+    }
998
+
999
+    err = 0;
1000
+fail:
1001
+    av_freep(&profiles);
1002
+    av_freep(&entrypoints);
1003
+    return err;
1004
+}
1005
+
890 1006
 av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
891 1007
                                  const VAAPIEncodeType *type)
892 1008
 {
... ...
@@ -907,6 +1024,9 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
907 907
     ctx->codec = type;
908 908
     ctx->codec_options = ctx->codec_options_data;
909 909
 
910
+    ctx->va_config  = VA_INVALID_ID;
911
+    ctx->va_context = VA_INVALID_ID;
912
+
910 913
     ctx->priv_data = av_mallocz(type->priv_data_size);
911 914
     if (!ctx->priv_data) {
912 915
         err = AVERROR(ENOMEM);
... ...
@@ -932,6 +1052,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx,
932 932
     if (err < 0)
933 933
         goto fail;
934 934
 
935
+    err = vaapi_encode_check_config(avctx);
936
+    if (err < 0)
937
+        goto fail;
938
+
935 939
     vas = vaCreateConfig(ctx->hwctx->display,
936 940
                          ctx->va_profile, ctx->va_entrypoint,
937 941
                          ctx->config_attributes, ctx->nb_config_attributes,
... ...
@@ -1088,11 +1212,15 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
1088 1088
         vaapi_encode_free(avctx, pic);
1089 1089
     }
1090 1090
 
1091
-    if (ctx->va_context != VA_INVALID_ID)
1091
+    if (ctx->va_context != VA_INVALID_ID) {
1092 1092
         vaDestroyContext(ctx->hwctx->display, ctx->va_context);
1093
+        ctx->va_context = VA_INVALID_ID;
1094
+    }
1093 1095
 
1094
-    if (ctx->va_config != VA_INVALID_ID)
1096
+    if (ctx->va_config != VA_INVALID_ID) {
1095 1097
         vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
1098
+        ctx->va_config = VA_INVALID_ID;
1099
+    }
1096 1100
 
1097 1101
     if (ctx->codec->close)
1098 1102
         ctx->codec->close(avctx);