diff options
author | dec05eba <dec05eba@protonmail.com> | 2022-10-16 02:08:40 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2022-10-16 04:15:09 +0200 |
commit | a7e0dbd83381377bd05a3fa988511d3713996370 (patch) | |
tree | 0e18f4c7b95aa4cf79d6646bca77ed5f03c65fb3 /src/capture/nvfbc.c | |
parent | 93d46b976730bced7a70be1617a0171600167314 (diff) |
Refactor xcomposite into abstract capture api
Refactor c++ files into c files, more usable
Diffstat (limited to 'src/capture/nvfbc.c')
-rw-r--r-- | src/capture/nvfbc.c | 151 |
1 files changed, 118 insertions, 33 deletions
diff --git a/src/capture/nvfbc.c b/src/capture/nvfbc.c index a2648ef..a470879 100644 --- a/src/capture/nvfbc.c +++ b/src/capture/nvfbc.c @@ -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; } |