mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-05-05 22:40:42 +09:00
Refactor xcomposite into abstract capture api
Refactor c++ files into c files, more usable
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
#include "../../include/capture/nvfbc.h"
|
||||
#include "../../external/NvFBC.h"
|
||||
#include "../../include/cuda.h"
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <libavutil/hwcontext.h>
|
||||
#include <libavutil/hwcontext_cuda.h>
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/version.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
typedef struct {
|
||||
gsr_capture_nvfbc_params params;
|
||||
@@ -14,6 +20,8 @@ typedef struct {
|
||||
PNVFBCCREATEINSTANCE nv_fbc_create_instance;
|
||||
NVFBC_API_FUNCTION_LIST nv_fbc_function_list;
|
||||
bool fbc_handle_created;
|
||||
|
||||
gsr_cuda cuda;
|
||||
} gsr_capture_nvfbc;
|
||||
|
||||
#if defined(_WIN64) || defined(__LP64__)
|
||||
@@ -28,13 +36,16 @@ static int max_int(int a, int b) {
|
||||
}
|
||||
|
||||
/* Returns 0 on failure */
|
||||
static uint32_t get_output_id_from_display_name(NVFBC_RANDR_OUTPUT_INFO *outputs, uint32_t num_outputs, const char *display_name) {
|
||||
static uint32_t get_output_id_from_display_name(NVFBC_RANDR_OUTPUT_INFO *outputs, uint32_t num_outputs, const char *display_name, uint32_t *width, uint32_t *height) {
|
||||
if(!outputs)
|
||||
return 0;
|
||||
|
||||
for(uint32_t i = 0; i < num_outputs; ++i) {
|
||||
if(strcmp(outputs[i].name, display_name) == 0)
|
||||
if(strcmp(outputs[i].name, display_name) == 0) {
|
||||
*width = outputs[i].trackedBox.w;
|
||||
*height = outputs[i].trackedBox.h;
|
||||
return outputs[i].dwId;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -95,16 +106,78 @@ static bool gsr_capture_nvfbc_load_library(gsr_capture *cap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int gsr_capture_nvfbc_start(gsr_capture *cap) {
|
||||
#if LIBAVUTIL_VERSION_MAJOR < 57
|
||||
static AVBufferRef* dummy_hw_frame_init(int size) {
|
||||
return av_buffer_alloc(size);
|
||||
}
|
||||
#else
|
||||
static AVBufferRef* dummy_hw_frame_init(size_t size) {
|
||||
return av_buffer_alloc(size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool ffmpeg_create_cuda_contexts(gsr_capture_nvfbc *cap_nvfbc, AVCodecContext *video_codec_context) {
|
||||
AVBufferRef *device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
|
||||
if(!device_ctx) {
|
||||
fprintf(stderr, "gsr error: cuda_create_codec_context failed: failed to create hardware device context\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
AVHWDeviceContext *hw_device_context = (AVHWDeviceContext*)device_ctx->data;
|
||||
AVCUDADeviceContext *cuda_device_context = (AVCUDADeviceContext*)hw_device_context->hwctx;
|
||||
cuda_device_context->cuda_ctx = cap_nvfbc->cuda.cu_ctx;
|
||||
if(av_hwdevice_ctx_init(device_ctx) < 0) {
|
||||
fprintf(stderr, "gsr error: cuda_create_codec_context failed: failed to create hardware device context\n");
|
||||
av_buffer_unref(&device_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
AVBufferRef *frame_context = av_hwframe_ctx_alloc(device_ctx);
|
||||
if(!frame_context) {
|
||||
fprintf(stderr, "gsr error: cuda_create_codec_context failed: 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_0RGB32;
|
||||
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->pool = av_buffer_pool_init(1, dummy_hw_frame_init);
|
||||
hw_frame_context->initial_pool_size = 1;
|
||||
|
||||
if (av_hwframe_ctx_init(frame_context) < 0) {
|
||||
fprintf(stderr, "gsr error: cuda_create_codec_context failed: 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 = device_ctx;
|
||||
video_codec_context->hw_frames_ctx = frame_context;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int gsr_capture_nvfbc_start(gsr_capture *cap, AVCodecContext *video_codec_context) {
|
||||
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
||||
if(!gsr_cuda_load(&cap_nvfbc->cuda))
|
||||
return -1;
|
||||
|
||||
if(!gsr_capture_nvfbc_load_library(cap)) {
|
||||
gsr_cuda_unload(&cap_nvfbc->cuda);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t x = max_int(cap_nvfbc->params.pos.x, 0);
|
||||
const uint32_t y = max_int(cap_nvfbc->params.pos.y, 0);
|
||||
const uint32_t width = max_int(cap_nvfbc->params.size.x, 0);
|
||||
const uint32_t height = max_int(cap_nvfbc->params.size.y, 0);
|
||||
|
||||
if(!cap_nvfbc->library || !cap_nvfbc->params.display_to_capture || cap_nvfbc->fbc_handle_created)
|
||||
return -1;
|
||||
|
||||
const bool capture_region = (x > 0 || y > 0 || width > 0 || height > 0);
|
||||
|
||||
NVFBCSTATUS status;
|
||||
@@ -127,7 +200,7 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap) {
|
||||
status = cap_nvfbc->nv_fbc_function_list.nvFBCCreateHandle(&cap_nvfbc->nv_fbc_handle, &create_params);
|
||||
if(status != NVFBC_SUCCESS) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_nvfbc_start failed: %s\n", cap_nvfbc->nv_fbc_function_list.nvFBCGetLastErrorStr(cap_nvfbc->nv_fbc_handle));
|
||||
return -1;
|
||||
goto error_cleanup;
|
||||
}
|
||||
}
|
||||
cap_nvfbc->fbc_handle_created = true;
|
||||
@@ -147,6 +220,8 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap) {
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
uint32_t tracking_width = XWidthOfScreen(DefaultScreenOfDisplay(cap_nvfbc->params.dpy));
|
||||
uint32_t tracking_height = XHeightOfScreen(DefaultScreenOfDisplay(cap_nvfbc->params.dpy));
|
||||
tracking_type = strcmp(cap_nvfbc->params.display_to_capture, "screen") == 0 ? NVFBC_TRACKING_SCREEN : NVFBC_TRACKING_OUTPUT;
|
||||
if(tracking_type == NVFBC_TRACKING_OUTPUT) {
|
||||
if(!status_params.bXRandRAvailable) {
|
||||
@@ -159,7 +234,7 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap) {
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
output_id = get_output_id_from_display_name(status_params.outputs, status_params.dwOutputNum, cap_nvfbc->params.display_to_capture);
|
||||
output_id = get_output_id_from_display_name(status_params.outputs, status_params.dwOutputNum, cap_nvfbc->params.display_to_capture, &tracking_width, &tracking_height);
|
||||
if(output_id == 0) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_nvfbc_start failed: display '%s' not found\n", cap_nvfbc->params.display_to_capture);
|
||||
goto error_cleanup;
|
||||
@@ -198,6 +273,17 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap) {
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
if(capture_region) {
|
||||
video_codec_context->width = width & ~1;
|
||||
video_codec_context->height = height & ~1;
|
||||
} else {
|
||||
video_codec_context->width = tracking_width & ~1;
|
||||
video_codec_context->height = tracking_height & ~1;
|
||||
}
|
||||
|
||||
if(!ffmpeg_create_cuda_contexts(cap_nvfbc, video_codec_context))
|
||||
goto error_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
error_cleanup:
|
||||
@@ -215,17 +301,16 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap) {
|
||||
cap_nvfbc->nv_fbc_function_list.nvFBCDestroyHandle(cap_nvfbc->nv_fbc_handle, &destroy_params);
|
||||
cap_nvfbc->fbc_handle_created = false;
|
||||
}
|
||||
output_id = 0;
|
||||
|
||||
av_buffer_unref(&video_codec_context->hw_device_ctx);
|
||||
av_buffer_unref(&video_codec_context->hw_frames_ctx);
|
||||
gsr_cuda_unload(&cap_nvfbc->cuda);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void gsr_capture_nvfbc_stop(gsr_capture *cap) {
|
||||
static void gsr_capture_nvfbc_destroy_session(gsr_capture *cap) {
|
||||
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
||||
|
||||
/* Intentionally ignore failure on destroy */
|
||||
if(!cap_nvfbc->nv_fbc_handle)
|
||||
return;
|
||||
|
||||
NVFBC_DESTROY_CAPTURE_SESSION_PARAMS destroy_capture_params;
|
||||
memset(&destroy_capture_params, 0, sizeof(destroy_capture_params));
|
||||
destroy_capture_params.dwVersion = NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER;
|
||||
@@ -241,8 +326,6 @@ static void gsr_capture_nvfbc_stop(gsr_capture *cap) {
|
||||
|
||||
static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame) {
|
||||
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
||||
if(!cap_nvfbc->library || !cap_nvfbc->fbc_handle_created)
|
||||
return -1;
|
||||
|
||||
CUdeviceptr cu_device_ptr = 0;
|
||||
|
||||
@@ -274,18 +357,19 @@ static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gsr_capture_nvfbc_destroy(gsr_capture *cap) {
|
||||
if(cap) {
|
||||
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
||||
gsr_capture_nvfbc_stop(cap);
|
||||
if(cap_nvfbc) {
|
||||
dlclose(cap_nvfbc->library);
|
||||
free((void*)cap_nvfbc->params.display_to_capture);
|
||||
free(cap->priv);
|
||||
cap->priv = NULL;
|
||||
}
|
||||
free(cap);
|
||||
static void gsr_capture_nvfbc_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
|
||||
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
|
||||
gsr_capture_nvfbc_destroy_session(cap);
|
||||
av_buffer_unref(&video_codec_context->hw_device_ctx);
|
||||
av_buffer_unref(&video_codec_context->hw_frames_ctx);
|
||||
if(cap_nvfbc) {
|
||||
gsr_cuda_unload(&cap_nvfbc->cuda);
|
||||
dlclose(cap_nvfbc->library);
|
||||
free((void*)cap_nvfbc->params.display_to_capture);
|
||||
free(cap->priv);
|
||||
cap->priv = NULL;
|
||||
}
|
||||
free(cap);
|
||||
}
|
||||
|
||||
gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params) {
|
||||
@@ -294,6 +378,11 @@ gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!params->display_to_capture) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_nvfbc_create params.display_to_capture is NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gsr_capture *cap = calloc(1, sizeof(gsr_capture));
|
||||
if(!cap)
|
||||
return NULL;
|
||||
@@ -317,16 +406,12 @@ gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params) {
|
||||
|
||||
*cap = (gsr_capture) {
|
||||
.start = gsr_capture_nvfbc_start,
|
||||
.stop = gsr_capture_nvfbc_stop,
|
||||
.tick = NULL,
|
||||
.should_stop = NULL,
|
||||
.capture = gsr_capture_nvfbc_capture,
|
||||
.destroy = gsr_capture_nvfbc_destroy,
|
||||
.priv = cap_nvfbc
|
||||
};
|
||||
|
||||
if(!gsr_capture_nvfbc_load_library(cap)) {
|
||||
gsr_capture_nvfbc_destroy(cap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user