Prepare for video codec query, cleanup readme, add libva-drm as dependency

This commit is contained in:
dec05eba
2024-08-29 22:22:46 +02:00
parent 1b356677ea
commit dfe2b17648
9 changed files with 329 additions and 74 deletions

View File

@@ -122,6 +122,24 @@ static bool gsr_video_encoder_cuda_setup_textures(gsr_video_encoder_cuda *self,
return true;
}
static gsr_supported_video_codecs gsr_video_encoder_cuda_get_supported_codecs(gsr_video_encoder *encoder, bool cleanup) {
(void)encoder;
(void)cleanup;
//gsr_video_encoder_cuda *encoder_cuda = encoder->priv;
// TODO: Query support
return (gsr_supported_video_codecs) {
.h264 = true,
.hevc = true,
.hevc_hdr = true,
.hevc_10bit = true,
.av1 = true,
.av1_hdr = true,
.av1_10bit = true,
.vp8 = false,
.vp9 = false
};
}
static void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context);
static bool gsr_video_encoder_cuda_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
@@ -225,6 +243,7 @@ gsr_video_encoder* gsr_video_encoder_cuda_create(const gsr_video_encoder_cuda_pa
encoder_cuda->params = *params;
*encoder = (gsr_video_encoder) {
.get_supported_codecs = gsr_video_encoder_cuda_get_supported_codecs,
.start = gsr_video_encoder_cuda_start,
.copy_textures_to_frame = gsr_video_encoder_cuda_copy_textures_to_frame,
.get_textures = gsr_video_encoder_cuda_get_textures,

View File

@@ -58,6 +58,22 @@ static bool gsr_video_encoder_software_setup_textures(gsr_video_encoder_software
return true;
}
static gsr_supported_video_codecs gsr_video_encoder_software_get_supported_codecs(gsr_video_encoder *encoder, bool cleanup) {
(void)encoder;
(void)cleanup;
return (gsr_supported_video_codecs) {
.h264 = true,
.hevc = false,
.hevc_hdr = false,
.hevc_10bit = false,
.av1 = false,
.av1_hdr = false,
.av1_10bit = false,
.vp8 = false,
.vp9 = false
};
}
static void gsr_video_encoder_software_stop(gsr_video_encoder_software *self, AVCodecContext *video_codec_context);
static bool gsr_video_encoder_software_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
@@ -126,6 +142,7 @@ gsr_video_encoder* gsr_video_encoder_software_create(const gsr_video_encoder_sof
encoder_software->params = *params;
*encoder = (gsr_video_encoder) {
.get_supported_codecs = gsr_video_encoder_software_get_supported_codecs,
.start = gsr_video_encoder_software_start,
.copy_textures_to_frame = gsr_video_encoder_software_copy_textures_to_frame,
.get_textures = gsr_video_encoder_software_get_textures,

View File

@@ -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,

View File

@@ -1,6 +1,10 @@
#include "../../../include/encoder/video/video.h"
#include <assert.h>
gsr_supported_video_codecs gsr_video_encoder_get_supported_codecs(gsr_video_encoder *encoder, bool cleanup) {
return encoder->get_supported_codecs(encoder, cleanup);
}
bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
assert(!encoder->started);
bool res = encoder->start(encoder, video_codec_context, frame);

View File

@@ -1686,6 +1686,39 @@ static int init_filter_graph(AVCodecContext *audio_codec_context, AVFilterGraph
return 0;
}
static gsr_video_encoder* create_video_encoder(gsr_egl *egl, bool overclock, gsr_color_depth color_depth, bool use_software_video_encoder) {
gsr_video_encoder *video_encoder = nullptr;
if(use_software_video_encoder) {
gsr_video_encoder_software_params params;
params.egl = egl;
params.color_depth = color_depth;
video_encoder = gsr_video_encoder_software_create(&params);
return video_encoder;
}
switch(egl->gpu_info.vendor) {
case GSR_GPU_VENDOR_AMD:
case GSR_GPU_VENDOR_INTEL: {
gsr_video_encoder_vaapi_params params;
params.egl = egl;
params.color_depth = color_depth;
video_encoder = gsr_video_encoder_vaapi_create(&params);
break;
}
case GSR_GPU_VENDOR_NVIDIA: {
gsr_video_encoder_cuda_params params;
params.egl = egl;
params.overclock = overclock;
params.color_depth = color_depth;
video_encoder = gsr_video_encoder_cuda_create(&params);
break;
}
}
return video_encoder;
}
static void xwayland_check_callback(const gsr_monitor *monitor, void *userdata) {
bool *xwayland_found = (bool*)userdata;
if(monitor->name_len >= 8 && strncmp(monitor->name, "XWAYLAND", 8) == 0)
@@ -1735,6 +1768,7 @@ static void list_gpu_info(gsr_egl *egl) {
}
static void list_supported_video_codecs(gsr_egl *egl, bool wayland) {
#if 1
if(find_h264_encoder(egl->gpu_info.vendor, egl->card_path))
puts("h264");
if(find_h264_software_encoder())
@@ -1755,6 +1789,34 @@ static void list_supported_video_codecs(gsr_egl *egl, bool wayland) {
puts("vp8");
if(find_vp9_encoder(egl->gpu_info.vendor, egl->card_path))
puts("vp9");
#else
// Dont clean it up on purpose to increase shutdown speed
gsr_video_encoder *video_encoder = create_video_encoder(egl, false, GSR_COLOR_DEPTH_8_BITS, false);
if(!video_encoder)
return;
const gsr_supported_video_codecs supported_video_codecs = gsr_video_encoder_get_supported_codecs(video_encoder, false);
if(supported_video_codecs.h264)
puts("h264");
if(find_h264_software_encoder())
puts("h264_software");
if(supported_video_codecs.hevc) {
puts("hevc");
if(wayland)
puts("hevc_hdr"); // TODO: Verify if it's actually supported
puts("hevc_10bit"); // TODO: Verify if it's actually supported
}
if(supported_video_codecs.av1) {
puts("av1");
if(wayland)
puts("av1_hdr"); // TODO: Verify if it's actually supported
puts("av1_10bit"); // TODO: Verify if it's actually supported
}
if(supported_video_codecs.vp8)
puts("vp8");
if(supported_video_codecs.vp9)
puts("vp9");
#endif
}
static bool monitor_capture_use_drm(gsr_egl *egl, bool wayland) {
@@ -1870,9 +1932,10 @@ static void info_command() {
fflush(stdout);
gsr_egl_unload(&egl);
if(dpy)
XCloseDisplay(dpy);
// Not needed as this will just slow down shutdown
//gsr_egl_unload(&egl);
//if(dpy)
// XCloseDisplay(dpy);
_exit(0);
}
@@ -2066,39 +2129,6 @@ static gsr_capture* create_capture_impl(const char *window_str, const char *scre
return capture;
}
static gsr_video_encoder* create_video_encoder(gsr_egl *egl, bool overclock, gsr_color_depth color_depth, bool use_software_video_encoder) {
gsr_video_encoder *video_encoder = nullptr;
if(use_software_video_encoder) {
gsr_video_encoder_software_params params;
params.egl = egl;
params.color_depth = color_depth;
video_encoder = gsr_video_encoder_software_create(&params);
return video_encoder;
}
switch(egl->gpu_info.vendor) {
case GSR_GPU_VENDOR_AMD:
case GSR_GPU_VENDOR_INTEL: {
gsr_video_encoder_vaapi_params params;
params.egl = egl;
params.color_depth = color_depth;
video_encoder = gsr_video_encoder_vaapi_create(&params);
break;
}
case GSR_GPU_VENDOR_NVIDIA: {
gsr_video_encoder_cuda_params params;
params.egl = egl;
params.overclock = overclock;
params.color_depth = color_depth;
video_encoder = gsr_video_encoder_cuda_create(&params);
break;
}
}
return video_encoder;
}
static AVPixelFormat get_pixel_format(gsr_gpu_vendor vendor, bool use_software_video_encoder) {
if(use_software_video_encoder) {
return AV_PIX_FMT_NV12;