diff options
Diffstat (limited to 'src/encoder/video/vaapi.c')
-rw-r--r-- | src/encoder/video/vaapi.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/encoder/video/vaapi.c b/src/encoder/video/vaapi.c index 9470e76..2185ebc 100644 --- a/src/encoder/video/vaapi.c +++ b/src/encoder/video/vaapi.c @@ -6,9 +6,11 @@ #include <libavutil/hwcontext_vaapi.h> #include <va/va_drmcommon.h> +#include <va/va_drm.h> #include <stdlib.h> #include <unistd.h> +#include <fcntl.h> typedef struct { gsr_video_encoder_vaapi_params params; @@ -147,6 +149,174 @@ static bool gsr_video_encoder_vaapi_setup_textures(gsr_video_encoder_vaapi *self } } +static bool profile_is_h264(VAProfile profile) { + switch(profile) { + case 5: // VAProfileH264Baseline + case VAProfileH264Main: + case VAProfileH264High: + case VAProfileH264ConstrainedBaseline: + return true; + default: + return false; + } +} + +static bool profile_is_hevc_8bit(VAProfile profile) { + switch(profile) { + case VAProfileHEVCMain: + return true; + default: + return false; + } +} + +static bool profile_is_hevc_10bit(VAProfile profile) { + switch(profile) { + case VAProfileHEVCMain10: + //case VAProfileHEVCMain12: + //case VAProfileHEVCMain422_10: + //case VAProfileHEVCMain422_12: + //case VAProfileHEVCMain444: + //case VAProfileHEVCMain444_10: + //case VAProfileHEVCMain444_12: + return true; + default: + return false; + } +} + +static bool profile_is_av1(VAProfile profile) { + switch(profile) { + case VAProfileAV1Profile0: + case VAProfileAV1Profile1: + return true; + default: + return false; + } +} + +static bool profile_is_vp8(VAProfile profile) { + switch(profile) { + case VAProfileVP8Version0_3: + return true; + default: + return false; + } +} + +static bool profile_is_vp9(VAProfile profile) { + switch(profile) { + case VAProfileVP9Profile0: + case VAProfileVP9Profile1: + case VAProfileVP9Profile2: + case VAProfileVP9Profile3: + return true; + default: + return false; + } +} + +static bool profile_supports_video_encoding(VADisplay va_dpy, VAProfile profile) { + int num_entrypoints = vaMaxNumEntrypoints(va_dpy); + if(num_entrypoints <= 0) + return false; + + VAEntrypoint *entrypoint_list = calloc(num_entrypoints, sizeof(VAEntrypoint)); + if(!entrypoint_list) + return false; + + bool supported = false; + if(vaQueryConfigEntrypoints(va_dpy, profile, entrypoint_list, &num_entrypoints) == VA_STATUS_SUCCESS) { + for(int i = 0; i < num_entrypoints; ++i) { + if(entrypoint_list[i] == VAEntrypointEncSlice) { + supported = true; + break; + } + } + } + + free(entrypoint_list); + return supported; +} + +static bool get_supported_video_codecs(VADisplay va_dpy, gsr_supported_video_codecs *video_codecs, bool cleanup) { + *video_codecs = (gsr_supported_video_codecs){0}; + bool success = false; + VAProfile *profile_list = NULL; + + int va_major = 0; + int va_minor = 0; + if(vaInitialize(va_dpy, &va_major, &va_minor) != VA_STATUS_SUCCESS) + return false; + + int num_profiles = vaMaxNumProfiles(va_dpy); + if(num_profiles <= 0) + goto done; + + profile_list = calloc(num_profiles, sizeof(VAProfile)); + if(!profile_list || vaQueryConfigProfiles(va_dpy, profile_list, &num_profiles) != VA_STATUS_SUCCESS) + goto done; + + for(int i = 0; i < num_profiles; ++i) { + if(profile_is_h264(profile_list[i])) { + if(profile_supports_video_encoding(va_dpy, profile_list[i])) + video_codecs->h264 = true; + } else if(profile_is_hevc_8bit(profile_list[i])) { + if(profile_supports_video_encoding(va_dpy, profile_list[i])) + video_codecs->hevc = true; + } else if(profile_is_hevc_10bit(profile_list[i])) { + if(profile_supports_video_encoding(va_dpy, profile_list[i])) { + video_codecs->hevc_hdr = true; + video_codecs->hevc_10bit = true; + } + } else if(profile_is_av1(profile_list[i])) { + if(profile_supports_video_encoding(va_dpy, profile_list[i])) { + video_codecs->av1 = true; + video_codecs->av1_hdr = true; + video_codecs->av1_10bit = true; + } + } else if(profile_is_vp8(profile_list[i])) { + if(profile_supports_video_encoding(va_dpy, profile_list[i])) + video_codecs->vp8 = true; + } else if(profile_is_vp9(profile_list[i])) { + if(profile_supports_video_encoding(va_dpy, profile_list[i])) + video_codecs->vp9 = true; + } + } + + success = true; + done: + if(profile_list) + free(profile_list); + + if(cleanup) + vaTerminate(va_dpy); + + return success; +} + +static gsr_supported_video_codecs gsr_video_encoder_vaapi_get_supported_codecs(gsr_video_encoder *encoder, bool cleanup) { + gsr_video_encoder_vaapi *encoder_vaapi = encoder->priv; + gsr_supported_video_codecs supported_video_codecs = {0}; + + const int drm_fd = open(encoder_vaapi->params.egl->card_path, O_RDWR); + if(drm_fd == -1) { + fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_get_supported_codecs: failed to open device %s\n", encoder_vaapi->params.egl->card_path); + return supported_video_codecs; + } + + VADisplay va_dpy = vaGetDisplayDRM(drm_fd); + if(va_dpy) { + if(!get_supported_video_codecs(va_dpy, &supported_video_codecs, cleanup)) + fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_get_supported_codecs: failed to query supported video codecs for device %s\n", encoder_vaapi->params.egl->card_path); + } + + if(cleanup) + close(drm_fd); + + return supported_video_codecs; +} + static void gsr_video_encoder_vaapi_stop(gsr_video_encoder_vaapi *self, AVCodecContext *video_codec_context); static bool gsr_video_encoder_vaapi_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { @@ -234,6 +404,7 @@ gsr_video_encoder* gsr_video_encoder_vaapi_create(const gsr_video_encoder_vaapi_ encoder_vaapi->params = *params; *encoder = (gsr_video_encoder) { + .get_supported_codecs = gsr_video_encoder_vaapi_get_supported_codecs, .start = gsr_video_encoder_vaapi_start, .copy_textures_to_frame = NULL, .get_textures = gsr_video_encoder_vaapi_get_textures, |