mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
Faster startup (faster video codec query), fix some video codec callback logic
This commit is contained in:
4285
external/nvEncodeAPI.h
vendored
Normal file
4285
external/nvEncodeAPI.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,6 @@ typedef struct {
|
|||||||
vec2i pos;
|
vec2i pos;
|
||||||
vec2i size;
|
vec2i size;
|
||||||
bool direct_capture;
|
bool direct_capture;
|
||||||
bool overclock;
|
|
||||||
gsr_color_depth color_depth;
|
gsr_color_depth color_depth;
|
||||||
gsr_color_range color_range;
|
gsr_color_range color_range;
|
||||||
bool record_cursor;
|
bool record_cursor;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "../../include/capture/nvfbc.h"
|
#include "../../include/capture/nvfbc.h"
|
||||||
#include "../../external/NvFBC.h"
|
#include "../../external/NvFBC.h"
|
||||||
#include "../../include/cuda.h"
|
|
||||||
#include "../../include/egl.h"
|
#include "../../include/egl.h"
|
||||||
#include "../../include/utils.h"
|
#include "../../include/utils.h"
|
||||||
#include "../../include/color_conversion.h"
|
#include "../../include/color_conversion.h"
|
||||||
@@ -24,7 +23,6 @@ typedef struct {
|
|||||||
bool fbc_handle_created;
|
bool fbc_handle_created;
|
||||||
bool capture_session_created;
|
bool capture_session_created;
|
||||||
|
|
||||||
gsr_cuda cuda;
|
|
||||||
NVFBC_TOGL_SETUP_PARAMS setup_params;
|
NVFBC_TOGL_SETUP_PARAMS setup_params;
|
||||||
|
|
||||||
bool supports_direct_cursor;
|
bool supports_direct_cursor;
|
||||||
@@ -290,7 +288,6 @@ static int gsr_capture_nvfbc_setup_session(gsr_capture_nvfbc *cap_nvfbc) {
|
|||||||
|
|
||||||
static void gsr_capture_nvfbc_stop(gsr_capture_nvfbc *cap_nvfbc) {
|
static void gsr_capture_nvfbc_stop(gsr_capture_nvfbc *cap_nvfbc) {
|
||||||
gsr_capture_nvfbc_destroy_session_and_handle(cap_nvfbc);
|
gsr_capture_nvfbc_destroy_session_and_handle(cap_nvfbc);
|
||||||
gsr_cuda_unload(&cap_nvfbc->cuda);
|
|
||||||
if(cap_nvfbc->library) {
|
if(cap_nvfbc->library) {
|
||||||
dlclose(cap_nvfbc->library);
|
dlclose(cap_nvfbc->library);
|
||||||
cap_nvfbc->library = NULL;
|
cap_nvfbc->library = NULL;
|
||||||
@@ -304,15 +301,8 @@ static void gsr_capture_nvfbc_stop(gsr_capture_nvfbc *cap_nvfbc) {
|
|||||||
static int gsr_capture_nvfbc_start(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame) {
|
static int gsr_capture_nvfbc_start(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame) {
|
||||||
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
||||||
|
|
||||||
if(!cap_nvfbc->params.use_software_video_encoder) {
|
if(!gsr_capture_nvfbc_load_library(cap))
|
||||||
if(!gsr_cuda_load(&cap_nvfbc->cuda, cap_nvfbc->params.egl->x11.dpy, cap_nvfbc->params.overclock))
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!gsr_capture_nvfbc_load_library(cap)) {
|
|
||||||
gsr_cuda_unload(&cap_nvfbc->cuda);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
cap_nvfbc->x = max_int(cap_nvfbc->params.pos.x, 0);
|
cap_nvfbc->x = max_int(cap_nvfbc->params.pos.x, 0);
|
||||||
cap_nvfbc->y = max_int(cap_nvfbc->params.pos.y, 0);
|
cap_nvfbc->y = max_int(cap_nvfbc->params.pos.y, 0);
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#include "../../../include/encoder/video/cuda.h"
|
#include "../../../include/encoder/video/cuda.h"
|
||||||
#include "../../../include/egl.h"
|
#include "../../../include/egl.h"
|
||||||
#include "../../../include/cuda.h"
|
#include "../../../include/cuda.h"
|
||||||
|
#include "../../../external/nvEncodeAPI.h"
|
||||||
|
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavutil/hwcontext_cuda.h>
|
#include <libavutil/hwcontext_cuda.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gsr_video_encoder_cuda_params params;
|
gsr_video_encoder_cuda_params params;
|
||||||
@@ -122,22 +124,224 @@ static bool gsr_video_encoder_cuda_setup_textures(gsr_video_encoder_cuda *self,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* open_nvenc_library(void) {
|
||||||
|
dlerror(); /* clear */
|
||||||
|
void *lib = dlopen("libnvidia-encode.so.1", RTLD_LAZY);
|
||||||
|
if(!lib) {
|
||||||
|
lib = dlopen("libnvidia-encode.so", RTLD_LAZY);
|
||||||
|
if(!lib) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs failed: failed to load libnvidia-encode.so/libnvidia-encode.so.1, error: %s\n", dlerror());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool profile_is_h264(const GUID *profile_guid) {
|
||||||
|
const GUID *h264_guids[] = {
|
||||||
|
&NV_ENC_H264_PROFILE_BASELINE_GUID,
|
||||||
|
&NV_ENC_H264_PROFILE_MAIN_GUID,
|
||||||
|
&NV_ENC_H264_PROFILE_HIGH_GUID,
|
||||||
|
&NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID,
|
||||||
|
&NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i = 0; i < 5; ++i) {
|
||||||
|
if(memcmp(profile_guid, h264_guids[i], sizeof(GUID)) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool profile_is_hevc(const GUID *profile_guid) {
|
||||||
|
const GUID *h264_guids[] = {
|
||||||
|
&NV_ENC_HEVC_PROFILE_MAIN_GUID,
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i = 0; i < 1; ++i) {
|
||||||
|
if(memcmp(profile_guid, h264_guids[i], sizeof(GUID)) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool profile_is_hevc_10bit(const GUID *profile_guid) {
|
||||||
|
const GUID *h264_guids[] = {
|
||||||
|
&NV_ENC_HEVC_PROFILE_MAIN10_GUID,
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i = 0; i < 1; ++i) {
|
||||||
|
if(memcmp(profile_guid, h264_guids[i], sizeof(GUID)) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool profile_is_av1(const GUID *profile_guid) {
|
||||||
|
const GUID *h264_guids[] = {
|
||||||
|
&NV_ENC_AV1_PROFILE_MAIN_GUID,
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i = 0; i < 1; ++i) {
|
||||||
|
if(memcmp(profile_guid, h264_guids[i], sizeof(GUID)) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool encoder_get_supported_profiles(const NV_ENCODE_API_FUNCTION_LIST *function_list, void *nvenc_encoder, const GUID *encoder_guid, gsr_supported_video_codecs *supported_video_codecs) {
|
||||||
|
bool success = false;
|
||||||
|
GUID *profile_guids = NULL;
|
||||||
|
|
||||||
|
uint32_t profile_guid_count = 0;
|
||||||
|
if(function_list->nvEncGetEncodeProfileGUIDCount(nvenc_encoder, *encoder_guid, &profile_guid_count) != NV_ENC_SUCCESS) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: nvEncGetEncodeProfileGUIDCount failed, error: %s\n", function_list->nvEncGetLastErrorString(nvenc_encoder));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(profile_guid_count == 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
profile_guids = calloc(profile_guid_count, sizeof(GUID));
|
||||||
|
if(!profile_guids) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: failed to allocate %d guids\n", (int)profile_guid_count);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(function_list->nvEncGetEncodeProfileGUIDs(nvenc_encoder, *encoder_guid, profile_guids, profile_guid_count, &profile_guid_count) != NV_ENC_SUCCESS) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: nvEncGetEncodeProfileGUIDs failed, error: %s\n", function_list->nvEncGetLastErrorString(nvenc_encoder));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < profile_guid_count; ++i) {
|
||||||
|
if(profile_is_h264(&profile_guids[i])) {
|
||||||
|
supported_video_codecs->h264 = true;
|
||||||
|
} else if(profile_is_hevc(&profile_guids[i])) {
|
||||||
|
supported_video_codecs->hevc = true;
|
||||||
|
} else if(profile_is_hevc_10bit(&profile_guids[i])) {
|
||||||
|
supported_video_codecs->hevc_hdr = true;
|
||||||
|
supported_video_codecs->hevc_10bit = true;
|
||||||
|
} else if(profile_is_av1(&profile_guids[i])) {
|
||||||
|
supported_video_codecs->av1 = true;
|
||||||
|
supported_video_codecs->av1_hdr = true;
|
||||||
|
supported_video_codecs->av1_10bit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
fail:
|
||||||
|
|
||||||
|
if(profile_guids)
|
||||||
|
free(profile_guids);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_supported_video_codecs(const NV_ENCODE_API_FUNCTION_LIST *function_list, void *nvenc_encoder, gsr_supported_video_codecs *supported_video_codecs) {
|
||||||
|
bool success = false;
|
||||||
|
GUID *encoder_guids = NULL;
|
||||||
|
*supported_video_codecs = (gsr_supported_video_codecs){0};
|
||||||
|
|
||||||
|
uint32_t encode_guid_count = 0;
|
||||||
|
if(function_list->nvEncGetEncodeGUIDCount(nvenc_encoder, &encode_guid_count) != NV_ENC_SUCCESS) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: nvEncGetEncodeGUIDCount failed, error: %s\n", function_list->nvEncGetLastErrorString(nvenc_encoder));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encode_guid_count == 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
encoder_guids = calloc(encode_guid_count, sizeof(GUID));
|
||||||
|
if(!encoder_guids) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: failed to allocate %d guids\n", (int)encode_guid_count);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(function_list->nvEncGetEncodeGUIDs(nvenc_encoder, encoder_guids, encode_guid_count, &encode_guid_count) != NV_ENC_SUCCESS) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: nvEncGetEncodeGUIDs failed, error: %s\n", function_list->nvEncGetLastErrorString(nvenc_encoder));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < encode_guid_count; ++i) {
|
||||||
|
encoder_get_supported_profiles(function_list, nvenc_encoder, &encoder_guids[i], supported_video_codecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
fail:
|
||||||
|
|
||||||
|
if(encoder_guids)
|
||||||
|
free(encoder_guids);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NVENCAPI_VERSION_470 (11 | (1 << 24))
|
||||||
|
|
||||||
static gsr_supported_video_codecs gsr_video_encoder_cuda_get_supported_codecs(gsr_video_encoder *encoder, bool cleanup) {
|
static gsr_supported_video_codecs gsr_video_encoder_cuda_get_supported_codecs(gsr_video_encoder *encoder, bool cleanup) {
|
||||||
(void)encoder;
|
(void)encoder;
|
||||||
(void)cleanup;
|
|
||||||
//gsr_video_encoder_cuda *encoder_cuda = encoder->priv;
|
void *nvenc_lib = NULL;
|
||||||
// TODO: Query support
|
gsr_cuda cuda;
|
||||||
return (gsr_supported_video_codecs) {
|
memset(&cuda, 0, sizeof(cuda));
|
||||||
.h264 = true,
|
gsr_supported_video_codecs supported_video_codecs = {0};
|
||||||
.hevc = true,
|
|
||||||
.hevc_hdr = true,
|
if(!gsr_cuda_load(&cuda, NULL, false)) {
|
||||||
.hevc_10bit = true,
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: failed to load cuda\n");
|
||||||
.av1 = true,
|
goto done;
|
||||||
.av1_hdr = true,
|
}
|
||||||
.av1_10bit = true,
|
|
||||||
.vp8 = false,
|
nvenc_lib = open_nvenc_library();
|
||||||
.vp9 = false
|
if(!nvenc_lib)
|
||||||
};
|
goto done;
|
||||||
|
|
||||||
|
typedef NVENCSTATUS NVENCAPI (*FUNC_NvEncodeAPICreateInstance)(NV_ENCODE_API_FUNCTION_LIST *functionList);
|
||||||
|
FUNC_NvEncodeAPICreateInstance NvEncodeAPICreateInstance = (FUNC_NvEncodeAPICreateInstance)dlsym(nvenc_lib, "NvEncodeAPICreateInstance");
|
||||||
|
if(!NvEncodeAPICreateInstance) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: failed to find NvEncodeAPICreateInstance in libnvidia-encode.so\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
NV_ENCODE_API_FUNCTION_LIST function_list;
|
||||||
|
memset(&function_list, 0, sizeof(function_list));
|
||||||
|
function_list.version = NV_ENCODE_API_FUNCTION_LIST_VER;
|
||||||
|
if(NvEncodeAPICreateInstance(&function_list) != NV_ENC_SUCCESS) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: NvEncodeAPICreateInstance failed\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params;
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
|
||||||
|
params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
|
||||||
|
params.device = cuda.cu_ctx;
|
||||||
|
params.apiVersion = NVENCAPI_VERSION;
|
||||||
|
|
||||||
|
void *nvenc_encoder = NULL;
|
||||||
|
if(function_list.nvEncOpenEncodeSessionEx(¶ms, &nvenc_encoder) != NV_ENC_SUCCESS) {
|
||||||
|
// Old nvidia gpus dont support the new nvenc api (which is required for av1).
|
||||||
|
// In such cases fallback to old api version if possible and try again.
|
||||||
|
params.apiVersion = NVENCAPI_VERSION_470;
|
||||||
|
if(function_list.nvEncOpenEncodeSessionEx(¶ms, &nvenc_encoder) != NV_ENC_SUCCESS) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_get_supported_codecs: NvEncOpenEncodeSessionEx failed\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_supported_video_codecs(&function_list, nvenc_encoder, &supported_video_codecs);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if(cleanup) {
|
||||||
|
function_list.nvEncDestroyEncoder(nvenc_encoder);
|
||||||
|
if(nvenc_lib)
|
||||||
|
dlclose(nvenc_lib);
|
||||||
|
gsr_cuda_unload(&cuda);
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported_video_codecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context);
|
static void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecContext *video_codec_context);
|
||||||
@@ -145,8 +349,8 @@ static void gsr_video_encoder_cuda_stop(gsr_video_encoder_cuda *self, AVCodecCon
|
|||||||
static bool gsr_video_encoder_cuda_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
|
static bool gsr_video_encoder_cuda_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
|
||||||
gsr_video_encoder_cuda *encoder_cuda = encoder->priv;
|
gsr_video_encoder_cuda *encoder_cuda = encoder->priv;
|
||||||
|
|
||||||
// TODO: Force set overclock to false if wayland
|
const bool overclock = gsr_egl_get_display_server(encoder_cuda->params.egl) == GSR_DISPLAY_SERVER_X11 ? encoder_cuda->params.overclock : false;
|
||||||
if(!gsr_cuda_load(&encoder_cuda->cuda, encoder_cuda->params.egl->x11.dpy, encoder_cuda->params.overclock)) {
|
if(!gsr_cuda_load(&encoder_cuda->cuda, encoder_cuda->params.egl->x11.dpy, overclock)) {
|
||||||
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_start: failed to load cuda\n");
|
fprintf(stderr, "gsr error: gsr_video_encoder_cuda_start: failed to load cuda\n");
|
||||||
gsr_video_encoder_cuda_stop(encoder_cuda, video_codec_context);
|
gsr_video_encoder_cuda_stop(encoder_cuda, video_codec_context);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -246,16 +246,18 @@ static bool get_supported_video_codecs(VADisplay va_dpy, gsr_supported_video_cod
|
|||||||
|
|
||||||
int va_major = 0;
|
int va_major = 0;
|
||||||
int va_minor = 0;
|
int va_minor = 0;
|
||||||
if(vaInitialize(va_dpy, &va_major, &va_minor) != VA_STATUS_SUCCESS)
|
if(vaInitialize(va_dpy, &va_major, &va_minor) != VA_STATUS_SUCCESS) {
|
||||||
return false;
|
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_get_supported_codecs: vaInitialize failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
int num_profiles = vaMaxNumProfiles(va_dpy);
|
int num_profiles = vaMaxNumProfiles(va_dpy);
|
||||||
if(num_profiles <= 0)
|
if(num_profiles <= 0)
|
||||||
goto done;
|
goto fail;
|
||||||
|
|
||||||
profile_list = calloc(num_profiles, sizeof(VAProfile));
|
profile_list = calloc(num_profiles, sizeof(VAProfile));
|
||||||
if(!profile_list || vaQueryConfigProfiles(va_dpy, profile_list, &num_profiles) != VA_STATUS_SUCCESS)
|
if(!profile_list || vaQueryConfigProfiles(va_dpy, profile_list, &num_profiles) != VA_STATUS_SUCCESS)
|
||||||
goto done;
|
goto fail;
|
||||||
|
|
||||||
for(int i = 0; i < num_profiles; ++i) {
|
for(int i = 0; i < num_profiles; ++i) {
|
||||||
if(profile_is_h264(profile_list[i])) {
|
if(profile_is_h264(profile_list[i])) {
|
||||||
@@ -285,7 +287,7 @@ static bool get_supported_video_codecs(VADisplay va_dpy, gsr_supported_video_cod
|
|||||||
}
|
}
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
done:
|
fail:
|
||||||
if(profile_list)
|
if(profile_list)
|
||||||
free(profile_list);
|
free(profile_list);
|
||||||
|
|
||||||
@@ -299,16 +301,22 @@ static gsr_supported_video_codecs gsr_video_encoder_vaapi_get_supported_codecs(g
|
|||||||
gsr_video_encoder_vaapi *encoder_vaapi = encoder->priv;
|
gsr_video_encoder_vaapi *encoder_vaapi = encoder->priv;
|
||||||
gsr_supported_video_codecs supported_video_codecs = {0};
|
gsr_supported_video_codecs supported_video_codecs = {0};
|
||||||
|
|
||||||
const int drm_fd = open(encoder_vaapi->params.egl->card_path, O_RDWR);
|
char render_path[128];
|
||||||
|
if(!gsr_card_path_get_render_path(encoder_vaapi->params.egl->card_path, render_path)) {
|
||||||
|
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_get_supported_codecs: failed to get /dev/dri/renderDXXX file from %s\n", encoder_vaapi->params.egl->card_path);
|
||||||
|
return supported_video_codecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int drm_fd = open(render_path, O_RDWR);
|
||||||
if(drm_fd == -1) {
|
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);
|
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_get_supported_codecs: failed to open device %s\n", render_path);
|
||||||
return supported_video_codecs;
|
return supported_video_codecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
VADisplay va_dpy = vaGetDisplayDRM(drm_fd);
|
VADisplay va_dpy = vaGetDisplayDRM(drm_fd);
|
||||||
if(va_dpy) {
|
if(va_dpy) {
|
||||||
if(!get_supported_video_codecs(va_dpy, &supported_video_codecs, cleanup))
|
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);
|
fprintf(stderr, "gsr error: gsr_video_encoder_vaapi_get_supported_codecs: failed to query supported video codecs for device %s\n", render_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cleanup)
|
if(cleanup)
|
||||||
|
|||||||
528
src/main.cpp
528
src/main.cpp
@@ -584,170 +584,6 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt,
|
|||||||
return codec_context;
|
return codec_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool vaapi_create_codec_context(AVCodecContext *video_codec_context, const char *card_path) {
|
|
||||||
char render_path[128];
|
|
||||||
if(!gsr_card_path_get_render_path(card_path, render_path)) {
|
|
||||||
fprintf(stderr, "gsr error: failed to get /dev/dri/renderDXXX file from %s\n", card_path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVBufferRef *device_ctx;
|
|
||||||
if(av_hwdevice_ctx_create(&device_ctx, AV_HWDEVICE_TYPE_VAAPI, render_path, NULL, 0) < 0) {
|
|
||||||
fprintf(stderr, "Error: Failed to create hardware device context\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVBufferRef *frame_context = av_hwframe_ctx_alloc(device_ctx);
|
|
||||||
if(!frame_context) {
|
|
||||||
fprintf(stderr, "Error: Failed to create hwframe context\n");
|
|
||||||
av_buffer_unref(&device_ctx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVHWFramesContext *hw_frame_context =
|
|
||||||
(AVHWFramesContext *)frame_context->data;
|
|
||||||
hw_frame_context->width = video_codec_context->width;
|
|
||||||
hw_frame_context->height = video_codec_context->height;
|
|
||||||
hw_frame_context->sw_format = AV_PIX_FMT_NV12;
|
|
||||||
hw_frame_context->format = video_codec_context->pix_fmt;
|
|
||||||
hw_frame_context->device_ref = device_ctx;
|
|
||||||
hw_frame_context->device_ctx = (AVHWDeviceContext*)device_ctx->data;
|
|
||||||
|
|
||||||
//hw_frame_context->initial_pool_size = 1;
|
|
||||||
|
|
||||||
if (av_hwframe_ctx_init(frame_context) < 0) {
|
|
||||||
fprintf(stderr, "Error: Failed to initialize hardware frame context "
|
|
||||||
"(note: ffmpeg version needs to be > 4.0)\n");
|
|
||||||
av_buffer_unref(&device_ctx);
|
|
||||||
//av_buffer_unref(&frame_context);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
video_codec_context->hw_device_ctx = av_buffer_ref(device_ctx);
|
|
||||||
video_codec_context->hw_frames_ctx = av_buffer_ref(frame_context);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool check_if_codec_valid_for_hardware(const AVCodec *codec, gsr_gpu_vendor vendor, const char *card_path) {
|
|
||||||
// Do not use AV_PIX_FMT_CUDA because we dont want to do full check with hardware context
|
|
||||||
AVCodecContext *codec_context = create_video_codec_context(vendor == GSR_GPU_VENDOR_NVIDIA ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_VAAPI, VideoQuality::VERY_HIGH, 60, codec, false, vendor, FramerateMode::CONSTANT, false, GSR_COLOR_RANGE_LIMITED, 2, false, BitrateMode::QP);
|
|
||||||
if(!codec_context)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
codec_context->width = 512;
|
|
||||||
codec_context->height = 512;
|
|
||||||
|
|
||||||
if(vendor != GSR_GPU_VENDOR_NVIDIA) {
|
|
||||||
if(!vaapi_create_codec_context(codec_context, card_path)) {
|
|
||||||
avcodec_free_context(&codec_context);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
success = avcodec_open2(codec_context, codec_context->codec, NULL) == 0;
|
|
||||||
if(codec_context->hw_device_ctx)
|
|
||||||
av_buffer_unref(&codec_context->hw_device_ctx);
|
|
||||||
if(codec_context->hw_frames_ctx)
|
|
||||||
av_buffer_unref(&codec_context->hw_frames_ctx);
|
|
||||||
avcodec_free_context(&codec_context);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AVCodec* find_h264_software_encoder() {
|
|
||||||
return avcodec_find_encoder_by_name("libx264");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AVCodec* find_h264_encoder(gsr_gpu_vendor vendor, const char *card_path) {
|
|
||||||
const AVCodec *codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "h264_nvenc" : "h264_vaapi");
|
|
||||||
if(!codec)
|
|
||||||
codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "nvenc_h264" : "vaapi_h264");
|
|
||||||
|
|
||||||
if(!codec)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
static bool checked = false;
|
|
||||||
static bool checked_success = true;
|
|
||||||
if(!checked) {
|
|
||||||
checked = true;
|
|
||||||
if(!check_if_codec_valid_for_hardware(codec, vendor, card_path))
|
|
||||||
checked_success = false;
|
|
||||||
}
|
|
||||||
return checked_success ? codec : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AVCodec* find_hevc_encoder(gsr_gpu_vendor vendor, const char *card_path) {
|
|
||||||
const AVCodec *codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "hevc_nvenc" : "hevc_vaapi");
|
|
||||||
if(!codec)
|
|
||||||
codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "nvenc_hevc" : "vaapi_hevc");
|
|
||||||
|
|
||||||
if(!codec)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
static bool checked = false;
|
|
||||||
static bool checked_success = true;
|
|
||||||
if(!checked) {
|
|
||||||
checked = true;
|
|
||||||
if(!check_if_codec_valid_for_hardware(codec, vendor, card_path))
|
|
||||||
checked_success = false;
|
|
||||||
}
|
|
||||||
return checked_success ? codec : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AVCodec* find_av1_encoder(gsr_gpu_vendor vendor, const char *card_path) {
|
|
||||||
// Workaround bug with av1 nvidia in older ffmpeg versions that causes the whole application to crash
|
|
||||||
// when avcodec_open2 is opened with av1_nvenc
|
|
||||||
if(vendor == GSR_GPU_VENDOR_NVIDIA && LIBAVCODEC_BUILD < AV_VERSION_INT(60, 30, 100)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AVCodec *codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "av1_nvenc" : "av1_vaapi");
|
|
||||||
if(!codec)
|
|
||||||
codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "nvenc_av1" : "vaapi_av1");
|
|
||||||
|
|
||||||
if(!codec)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
static bool checked = false;
|
|
||||||
static bool checked_success = true;
|
|
||||||
if(!checked) {
|
|
||||||
checked = true;
|
|
||||||
if(!check_if_codec_valid_for_hardware(codec, vendor, card_path))
|
|
||||||
checked_success = false;
|
|
||||||
}
|
|
||||||
return checked_success ? codec : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AVCodec* find_vp8_encoder(gsr_gpu_vendor vendor, const char *card_path) {
|
|
||||||
const AVCodec *codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "vp8_nvenc" : "vp8_vaapi");
|
|
||||||
if(!codec)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
static bool checked = false;
|
|
||||||
static bool checked_success = true;
|
|
||||||
if(!checked) {
|
|
||||||
checked = true;
|
|
||||||
if(!check_if_codec_valid_for_hardware(codec, vendor, card_path))
|
|
||||||
checked_success = false;
|
|
||||||
}
|
|
||||||
return checked_success ? codec : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AVCodec* find_vp9_encoder(gsr_gpu_vendor vendor, const char *card_path) {
|
|
||||||
const AVCodec *codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "vp9_nvenc" : "vp9_vaapi");
|
|
||||||
if(!codec)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
static bool checked = false;
|
|
||||||
static bool checked_success = true;
|
|
||||||
if(!checked) {
|
|
||||||
checked = true;
|
|
||||||
if(!check_if_codec_valid_for_hardware(codec, vendor, card_path))
|
|
||||||
checked_success = false;
|
|
||||||
}
|
|
||||||
return checked_success ? codec : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void open_audio(AVCodecContext *audio_codec_context) {
|
static void open_audio(AVCodecContext *audio_codec_context) {
|
||||||
AVDictionary *options = nullptr;
|
AVDictionary *options = nullptr;
|
||||||
av_dict_set(&options, "strict", "experimental", 0);
|
av_dict_set(&options, "strict", "experimental", 0);
|
||||||
@@ -1803,56 +1639,81 @@ static void list_gpu_info(gsr_egl *egl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const AVCodec* get_ffmpeg_video_codec(VideoCodec video_codec, gsr_gpu_vendor vendor) {
|
||||||
|
switch(video_codec) {
|
||||||
|
case VideoCodec::H264:
|
||||||
|
return avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "h264_nvenc" : "h264_vaapi");
|
||||||
|
case VideoCodec::HEVC:
|
||||||
|
case VideoCodec::HEVC_HDR:
|
||||||
|
case VideoCodec::HEVC_10BIT:
|
||||||
|
return avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "hevc_nvenc" : "hevc_vaapi");
|
||||||
|
case VideoCodec::AV1:
|
||||||
|
case VideoCodec::AV1_HDR:
|
||||||
|
case VideoCodec::AV1_10BIT:
|
||||||
|
return avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "av1_nvenc" : "av1_vaapi");
|
||||||
|
case VideoCodec::VP8:
|
||||||
|
return avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "vp8_nvenc" : "vp8_vaapi");
|
||||||
|
case VideoCodec::VP9:
|
||||||
|
return avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "vp9_nvenc" : "vp9_vaapi");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_supported_video_codecs_ffmpeg(gsr_supported_video_codecs *supported_video_codecs, gsr_gpu_vendor vendor) {
|
||||||
|
if(!get_ffmpeg_video_codec(VideoCodec::H264, vendor)) {
|
||||||
|
supported_video_codecs->h264 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!get_ffmpeg_video_codec(VideoCodec::HEVC, vendor)) {
|
||||||
|
supported_video_codecs->hevc = false;
|
||||||
|
supported_video_codecs->hevc_hdr = false;
|
||||||
|
supported_video_codecs->hevc_10bit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!get_ffmpeg_video_codec(VideoCodec::AV1, vendor)) {
|
||||||
|
supported_video_codecs->av1 = false;
|
||||||
|
supported_video_codecs->av1_hdr = false;
|
||||||
|
supported_video_codecs->av1_10bit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!get_ffmpeg_video_codec(VideoCodec::VP8, vendor)) {
|
||||||
|
supported_video_codecs->vp8 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!get_ffmpeg_video_codec(VideoCodec::VP9, vendor)) {
|
||||||
|
supported_video_codecs->vp9 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void list_supported_video_codecs(gsr_egl *egl, bool wayland) {
|
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())
|
|
||||||
puts("h264_software");
|
|
||||||
if(find_hevc_encoder(egl->gpu_info.vendor, egl->card_path)) {
|
|
||||||
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(find_av1_encoder(egl->gpu_info.vendor, egl->card_path)) {
|
|
||||||
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(find_vp8_encoder(egl->gpu_info.vendor, egl->card_path))
|
|
||||||
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
|
// 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);
|
gsr_video_encoder *video_encoder = create_video_encoder(egl, false, GSR_COLOR_DEPTH_8_BITS, false);
|
||||||
if(!video_encoder)
|
if(!video_encoder)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const gsr_supported_video_codecs supported_video_codecs = gsr_video_encoder_get_supported_codecs(video_encoder, false);
|
gsr_supported_video_codecs supported_video_codecs = gsr_video_encoder_get_supported_codecs(video_encoder, false);
|
||||||
|
set_supported_video_codecs_ffmpeg(&supported_video_codecs, egl->gpu_info.vendor);
|
||||||
|
|
||||||
if(supported_video_codecs.h264)
|
if(supported_video_codecs.h264)
|
||||||
puts("h264");
|
puts("h264");
|
||||||
if(find_h264_software_encoder())
|
if(avcodec_find_encoder_by_name("libx264"))
|
||||||
puts("h264_software");
|
puts("h264_software");
|
||||||
if(supported_video_codecs.hevc) {
|
if(supported_video_codecs.hevc)
|
||||||
puts("hevc");
|
puts("hevc");
|
||||||
if(wayland)
|
if(supported_video_codecs.hevc_hdr && wayland)
|
||||||
puts("hevc_hdr"); // TODO: Verify if it's actually supported
|
puts("hevc_hdr");
|
||||||
puts("hevc_10bit"); // TODO: Verify if it's actually supported
|
if(supported_video_codecs.hevc_10bit)
|
||||||
}
|
puts("hevc_10bit");
|
||||||
if(supported_video_codecs.av1) {
|
if(supported_video_codecs.av1)
|
||||||
puts("av1");
|
puts("av1");
|
||||||
if(wayland)
|
if(supported_video_codecs.av1_hdr && wayland)
|
||||||
puts("av1_hdr"); // TODO: Verify if it's actually supported
|
puts("av1_hdr");
|
||||||
puts("av1_10bit"); // TODO: Verify if it's actually supported
|
if(supported_video_codecs.av1_10bit)
|
||||||
}
|
puts("av1_10bit");
|
||||||
if(supported_video_codecs.vp8)
|
if(supported_video_codecs.vp8)
|
||||||
puts("vp8");
|
puts("vp8");
|
||||||
if(supported_video_codecs.vp9)
|
if(supported_video_codecs.vp9)
|
||||||
puts("vp9");
|
puts("vp9");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool monitor_capture_use_drm(gsr_egl *egl, bool wayland) {
|
static bool monitor_capture_use_drm(gsr_egl *egl, bool wayland) {
|
||||||
@@ -1992,7 +1853,7 @@ static void list_audio_devices_command() {
|
|||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gsr_capture* create_capture_impl(const char *window_str, const char *screen_region, bool wayland, gsr_egl *egl, int fps, bool overclock, VideoCodec video_codec, gsr_color_range color_range,
|
static gsr_capture* create_capture_impl(const char *window_str, const char *screen_region, bool wayland, gsr_egl *egl, int fps, VideoCodec video_codec, gsr_color_range color_range,
|
||||||
bool record_cursor, bool track_damage, bool use_software_video_encoder, bool restore_portal_session, const char *portal_session_token_filepath,
|
bool record_cursor, bool track_damage, bool use_software_video_encoder, bool restore_portal_session, const char *portal_session_token_filepath,
|
||||||
gsr_color_depth color_depth)
|
gsr_color_depth color_depth)
|
||||||
{
|
{
|
||||||
@@ -2112,7 +1973,6 @@ static gsr_capture* create_capture_impl(const char *window_str, const char *scre
|
|||||||
nvfbc_params.pos = { 0, 0 };
|
nvfbc_params.pos = { 0, 0 };
|
||||||
nvfbc_params.size = { 0, 0 };
|
nvfbc_params.size = { 0, 0 };
|
||||||
nvfbc_params.direct_capture = direct_capture;
|
nvfbc_params.direct_capture = direct_capture;
|
||||||
nvfbc_params.overclock = overclock;
|
|
||||||
nvfbc_params.color_depth = color_depth;
|
nvfbc_params.color_depth = color_depth;
|
||||||
nvfbc_params.color_range = color_range;
|
nvfbc_params.color_range = color_range;
|
||||||
nvfbc_params.record_cursor = record_cursor;
|
nvfbc_params.record_cursor = record_cursor;
|
||||||
@@ -2284,26 +2144,162 @@ static AudioCodec select_audio_codec_with_fallback(AudioCodec audio_codec, const
|
|||||||
return audio_codec;
|
return audio_codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AVCodec* select_video_codec_with_fallback(VideoCodec video_codec, const char *video_codec_to_use, const char *file_extension, bool use_software_video_encoder, const gsr_egl *egl) {
|
static const char* video_codec_to_string(VideoCodec video_codec) {
|
||||||
|
switch(video_codec) {
|
||||||
|
case VideoCodec::H264: return "h264";
|
||||||
|
case VideoCodec::HEVC: return "hevc";
|
||||||
|
case VideoCodec::HEVC_HDR: return "hevc_hdr";
|
||||||
|
case VideoCodec::HEVC_10BIT: return "hevc_10bit";
|
||||||
|
case VideoCodec::AV1: return "av1";
|
||||||
|
case VideoCodec::AV1_HDR: return "av1_hdr";
|
||||||
|
case VideoCodec::AV1_10BIT: return "av1_10bit";
|
||||||
|
case VideoCodec::VP8: return "vp8";
|
||||||
|
case VideoCodec::VP9: return "vp9";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const AVCodec* pick_video_codec(VideoCodec *video_codec, gsr_egl *egl, bool use_software_video_encoder, bool video_codec_auto, const char *video_codec_to_use, bool is_flv) {
|
||||||
|
// TODO: software encoder for hevc, av1, vp8 and vp9
|
||||||
|
|
||||||
|
gsr_video_encoder *video_encoder = create_video_encoder(egl, false, GSR_COLOR_DEPTH_8_BITS, use_software_video_encoder);
|
||||||
|
if(!video_encoder) {
|
||||||
|
fprintf(stderr, "Error: failed to create video encoder\n");
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gsr_supported_video_codecs supported_video_codecs = gsr_video_encoder_get_supported_codecs(video_encoder, true);
|
||||||
|
const AVCodec *video_codec_f = nullptr;
|
||||||
|
|
||||||
|
// TODO: Cleanup
|
||||||
|
// gsr_video_encoder_destroy
|
||||||
|
|
||||||
|
switch(*video_codec) {
|
||||||
|
case VideoCodec::H264: {
|
||||||
|
if(use_software_video_encoder)
|
||||||
|
video_codec_f = avcodec_find_encoder_by_name("libx264");
|
||||||
|
else if(supported_video_codecs.h264)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::HEVC: {
|
||||||
|
if(supported_video_codecs.hevc)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::HEVC_HDR: {
|
||||||
|
if(supported_video_codecs.hevc_hdr)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::HEVC_10BIT: {
|
||||||
|
if(supported_video_codecs.hevc_10bit)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::AV1: {
|
||||||
|
if(supported_video_codecs.av1)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::AV1_HDR: {
|
||||||
|
if(supported_video_codecs.av1_hdr)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::AV1_10BIT: {
|
||||||
|
if(supported_video_codecs.av1_10bit)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::VP8: {
|
||||||
|
if(supported_video_codecs.vp8)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::VP9: {
|
||||||
|
if(supported_video_codecs.vp9)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!video_codec_auto && !video_codec_f && !is_flv) {
|
||||||
|
switch(*video_codec) {
|
||||||
|
case VideoCodec::H264: {
|
||||||
|
fprintf(stderr, "Warning: selected video codec h264 is not supported, trying hevc instead\n");
|
||||||
|
video_codec_to_use = "hevc";
|
||||||
|
if(supported_video_codecs.hevc)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::HEVC:
|
||||||
|
case VideoCodec::HEVC_HDR:
|
||||||
|
case VideoCodec::HEVC_10BIT: {
|
||||||
|
fprintf(stderr, "Warning: selected video codec hevc is not supported, trying h264 instead\n");
|
||||||
|
video_codec_to_use = "h264";
|
||||||
|
*video_codec = VideoCodec::H264;
|
||||||
|
if(supported_video_codecs.h264)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::AV1:
|
||||||
|
case VideoCodec::AV1_HDR:
|
||||||
|
case VideoCodec::AV1_10BIT: {
|
||||||
|
fprintf(stderr, "Warning: selected video codec av1 is not supported, trying h264 instead\n");
|
||||||
|
video_codec_to_use = "h264";
|
||||||
|
*video_codec = VideoCodec::H264;
|
||||||
|
if(supported_video_codecs.h264)
|
||||||
|
video_codec_f = get_ffmpeg_video_codec(*video_codec, egl->gpu_info.vendor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VideoCodec::VP8:
|
||||||
|
case VideoCodec::VP9:
|
||||||
|
// TODO: Cant fallback to other codec because webm only supports vp8/vp9
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)video_codec_to_use;
|
||||||
|
|
||||||
|
if(!video_codec_f) {
|
||||||
|
const char *video_codec_name = video_codec_to_string(*video_codec);
|
||||||
|
fprintf(stderr, "Error: your gpu does not support '%s' video codec. If you are sure that your gpu does support '%s' video encoding and you are using an AMD/Intel GPU,\n"
|
||||||
|
" then make sure you have installed the GPU specific vaapi packages (intel-media-driver, libva-intel-driver, libva-mesa-driver and linux-firmware).\n"
|
||||||
|
" It's also possible that your distro has disabled hardware accelerated video encoding for '%s' video codec.\n"
|
||||||
|
" This may be the case on corporate distros such as Manjaro, Fedora or OpenSUSE.\n"
|
||||||
|
" You can test this by running 'vainfo | grep VAEntrypointEncSlice' to see if it matches any H264/HEVC/AV1/VP8/VP9 profile.\n"
|
||||||
|
" On such distros, you need to manually install mesa from source to enable H264/HEVC hardware acceleration, or use a more user friendly distro. Alternatively record with AV1 if supported by your GPU.\n"
|
||||||
|
" You can alternatively use the flatpak version of GPU Screen Recorder (https://flathub.org/apps/com.dec05eba.gpu_screen_recorder) which bypasses system issues with patented H264/HEVC codecs.\n"
|
||||||
|
" Make sure you have mesa-extra freedesktop runtime installed when using the flatpak (this should be the default), which can be installed with this command:\n"
|
||||||
|
" flatpak install --system org.freedesktop.Platform.GL.default//23.08-extra\n"
|
||||||
|
" If your GPU doesn't support hardware accelerated video encoding then you can use '-encoder cpu' option to encode with your cpu instead.\n", video_codec_name, video_codec_name, video_codec_name);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return video_codec_f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const AVCodec* select_video_codec_with_fallback(VideoCodec *video_codec, const char *video_codec_to_use, const char *file_extension, bool use_software_video_encoder, gsr_egl *egl) {
|
||||||
const bool video_codec_auto = strcmp(video_codec_to_use, "auto") == 0;
|
const bool video_codec_auto = strcmp(video_codec_to_use, "auto") == 0;
|
||||||
if(video_codec_auto) {
|
if(video_codec_auto) {
|
||||||
if(strcmp(file_extension, "webm") == 0) {
|
if(strcmp(file_extension, "webm") == 0) {
|
||||||
fprintf(stderr, "Info: using vp8 encoder because a codec was not specified and the file extension is .webm\n");
|
fprintf(stderr, "Info: using vp8 encoder because a codec was not specified and the file extension is .webm\n");
|
||||||
video_codec_to_use = "vp8";
|
video_codec_to_use = "vp8";
|
||||||
video_codec = VideoCodec::VP8;
|
*video_codec = VideoCodec::VP8;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Info: using h264 encoder because a codec was not specified\n");
|
fprintf(stderr, "Info: using h264 encoder because a codec was not specified\n");
|
||||||
video_codec_to_use = "h264";
|
video_codec_to_use = "h264";
|
||||||
video_codec = VideoCodec::H264;
|
*video_codec = VideoCodec::H264;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Allow hevc, vp9 and av1 in (enhanced) flv (supported since ffmpeg 6.1)
|
// TODO: Allow hevc, vp9 and av1 in (enhanced) flv (supported since ffmpeg 6.1)
|
||||||
const bool is_flv = strcmp(file_extension, "flv") == 0;
|
const bool is_flv = strcmp(file_extension, "flv") == 0;
|
||||||
if(is_flv) {
|
if(is_flv) {
|
||||||
if(video_codec != VideoCodec::H264) {
|
if(*video_codec != VideoCodec::H264) {
|
||||||
video_codec_to_use = "h264";
|
video_codec_to_use = "h264";
|
||||||
video_codec = VideoCodec::H264;
|
*video_codec = VideoCodec::H264;
|
||||||
fprintf(stderr, "Warning: hevc/av1 is not compatible with flv, falling back to h264 instead.\n");
|
fprintf(stderr, "Warning: hevc/av1 is not compatible with flv, falling back to h264 instead.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2316,9 +2312,9 @@ static const AVCodec* select_video_codec_with_fallback(VideoCodec video_codec, c
|
|||||||
|
|
||||||
const bool is_hls = strcmp(file_extension, "m3u8") == 0;
|
const bool is_hls = strcmp(file_extension, "m3u8") == 0;
|
||||||
if(is_hls) {
|
if(is_hls) {
|
||||||
if(video_codec_is_av1(video_codec)) {
|
if(video_codec_is_av1(*video_codec)) {
|
||||||
video_codec_to_use = "hevc";
|
video_codec_to_use = "hevc";
|
||||||
video_codec = VideoCodec::HEVC;
|
*video_codec = VideoCodec::HEVC;
|
||||||
fprintf(stderr, "Warning: av1 is not compatible with hls (m3u8), falling back to hevc instead.\n");
|
fprintf(stderr, "Warning: av1 is not compatible with hls (m3u8), falling back to hevc instead.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2329,120 +2325,12 @@ static const AVCodec* select_video_codec_with_fallback(VideoCodec video_codec, c
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
if(use_software_video_encoder && video_codec != VideoCodec::H264) {
|
if(use_software_video_encoder && *video_codec != VideoCodec::H264) {
|
||||||
fprintf(stderr, "Error: \"-encoder cpu\" option is currently only available when using h264 codec option (-k)\n");
|
fprintf(stderr, "Error: \"-encoder cpu\" option is currently only available when using h264 codec option (-k)\n");
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
const AVCodec *video_codec_f = nullptr;
|
return pick_video_codec(video_codec, egl, use_software_video_encoder, video_codec_auto, video_codec_to_use, is_flv);
|
||||||
switch(video_codec) {
|
|
||||||
case VideoCodec::H264: {
|
|
||||||
if(use_software_video_encoder) {
|
|
||||||
video_codec_f = find_h264_software_encoder();
|
|
||||||
} else {
|
|
||||||
video_codec_f = find_h264_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::HEVC:
|
|
||||||
case VideoCodec::HEVC_HDR:
|
|
||||||
case VideoCodec::HEVC_10BIT:
|
|
||||||
// TODO: software encoder
|
|
||||||
video_codec_f = find_hevc_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
case VideoCodec::AV1:
|
|
||||||
case VideoCodec::AV1_HDR:
|
|
||||||
case VideoCodec::AV1_10BIT:
|
|
||||||
// TODO: software encoder
|
|
||||||
video_codec_f = find_av1_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
case VideoCodec::VP8:
|
|
||||||
// TODO: software encoder
|
|
||||||
video_codec_f = find_vp8_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
case VideoCodec::VP9:
|
|
||||||
// TODO: software encoder
|
|
||||||
video_codec_f = find_vp9_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!video_codec_auto && !video_codec_f && !is_flv) {
|
|
||||||
switch(video_codec) {
|
|
||||||
case VideoCodec::H264: {
|
|
||||||
fprintf(stderr, "Warning: selected video codec h264 is not supported, trying hevc instead\n");
|
|
||||||
video_codec_to_use = "hevc";
|
|
||||||
video_codec = VideoCodec::HEVC;
|
|
||||||
video_codec_f = find_hevc_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::HEVC:
|
|
||||||
case VideoCodec::HEVC_HDR:
|
|
||||||
case VideoCodec::HEVC_10BIT: {
|
|
||||||
fprintf(stderr, "Warning: selected video codec hevc is not supported, trying h264 instead\n");
|
|
||||||
video_codec_to_use = "h264";
|
|
||||||
video_codec = VideoCodec::H264;
|
|
||||||
video_codec_f = find_h264_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::AV1:
|
|
||||||
case VideoCodec::AV1_HDR:
|
|
||||||
case VideoCodec::AV1_10BIT: {
|
|
||||||
fprintf(stderr, "Warning: selected video codec av1 is not supported, trying h264 instead\n");
|
|
||||||
video_codec_to_use = "h264";
|
|
||||||
video_codec = VideoCodec::H264;
|
|
||||||
video_codec_f = find_h264_encoder(egl->gpu_info.vendor, egl->card_path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::VP8:
|
|
||||||
case VideoCodec::VP9:
|
|
||||||
// TODO:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!video_codec_f) {
|
|
||||||
const char *video_codec_name = "";
|
|
||||||
switch(video_codec) {
|
|
||||||
case VideoCodec::H264: {
|
|
||||||
video_codec_name = "h264";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::HEVC:
|
|
||||||
case VideoCodec::HEVC_HDR:
|
|
||||||
case VideoCodec::HEVC_10BIT: {
|
|
||||||
video_codec_name = "hevc";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::AV1:
|
|
||||||
case VideoCodec::AV1_HDR:
|
|
||||||
case VideoCodec::AV1_10BIT: {
|
|
||||||
video_codec_name = "av1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::VP8: {
|
|
||||||
video_codec_name = "vp8";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VideoCodec::VP9: {
|
|
||||||
video_codec_name = "vp9";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Error: your gpu does not support '%s' video codec. If you are sure that your gpu does support '%s' video encoding and you are using an AMD/Intel GPU,\n"
|
|
||||||
" then make sure you have installed the GPU specific vaapi packages (intel-media-driver, libva-intel-driver, libva-mesa-driver and linux-firmware).\n"
|
|
||||||
" It's also possible that your distro has disabled hardware accelerated video encoding for '%s' video codec.\n"
|
|
||||||
" This may be the case on corporate distros such as Manjaro, Fedora or OpenSUSE.\n"
|
|
||||||
" You can test this by running 'vainfo | grep VAEntrypointEncSlice' to see if it matches any H264/HEVC profile.\n"
|
|
||||||
" On such distros, you need to manually install mesa from source to enable H264/HEVC hardware acceleration, or use a more user friendly distro. Alternatively record with AV1 if supported by your GPU.\n"
|
|
||||||
" You can alternatively use the flatpak version of GPU Screen Recorder (https://flathub.org/apps/com.dec05eba.gpu_screen_recorder) which bypasses system issues with patented H264/HEVC codecs.\n"
|
|
||||||
" Make sure you have mesa-extra freedesktop runtime installed when using the flatpak (this should be the default), which can be installed with this command:\n"
|
|
||||||
" flatpak install --system org.freedesktop.Platform.GL.default//23.08-extra\n"
|
|
||||||
" If your GPU doesn't support hardware accelerated video encoding then you can use '-encoder cpu' option to encode with your cpu instead.\n", video_codec_name, video_codec_name, video_codec_name);
|
|
||||||
_exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return video_codec_f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
@@ -3009,10 +2897,10 @@ int main(int argc, char **argv) {
|
|||||||
const double target_fps = 1.0 / (double)fps;
|
const double target_fps = 1.0 / (double)fps;
|
||||||
|
|
||||||
audio_codec = select_audio_codec_with_fallback(audio_codec, file_extension, uses_amix);
|
audio_codec = select_audio_codec_with_fallback(audio_codec, file_extension, uses_amix);
|
||||||
const AVCodec *video_codec_f = select_video_codec_with_fallback(video_codec, video_codec_to_use, file_extension.c_str(), use_software_video_encoder, &egl);
|
const AVCodec *video_codec_f = select_video_codec_with_fallback(&video_codec, video_codec_to_use, file_extension.c_str(), use_software_video_encoder, &egl);
|
||||||
|
|
||||||
const gsr_color_depth color_depth = video_codec_to_bit_depth(video_codec);
|
const gsr_color_depth color_depth = video_codec_to_bit_depth(video_codec);
|
||||||
gsr_capture *capture = create_capture_impl(window_str, screen_region, wayland, &egl, fps, overclock, video_codec, color_range, record_cursor, framerate_mode == FramerateMode::CONTENT, use_software_video_encoder, restore_portal_session, portal_session_token_filepath, color_depth);
|
gsr_capture *capture = create_capture_impl(window_str, screen_region, wayland, &egl, fps, video_codec, color_range, record_cursor, framerate_mode == FramerateMode::CONTENT, use_software_video_encoder, restore_portal_session, portal_session_token_filepath, color_depth);
|
||||||
|
|
||||||
// (Some?) livestreaming services require at least one audio track to work.
|
// (Some?) livestreaming services require at least one audio track to work.
|
||||||
// If not audio is provided then create one silent audio track.
|
// If not audio is provided then create one silent audio track.
|
||||||
|
|||||||
Reference in New Issue
Block a user