aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/NvFBC.h2006
-rw-r--r--include/NvFBCLibrary.hpp246
-rw-r--r--include/args_parser.h106
-rw-r--r--include/capture/capture.h52
-rw-r--r--include/capture/kms.h19
-rw-r--r--include/capture/nvfbc.h20
-rw-r--r--include/capture/portal.h17
-rw-r--r--include/capture/xcomposite.h17
-rw-r--r--include/capture/ximage.h18
-rw-r--r--include/codec_query/codec_query.h23
-rw-r--r--include/codec_query/nvenc.h8
-rw-r--r--include/codec_query/vaapi.h8
-rw-r--r--include/codec_query/vulkan.h8
-rw-r--r--include/color_conversion.h85
-rw-r--r--include/cuda.h108
-rw-r--r--include/cursor.h28
-rw-r--r--include/damage.h52
-rw-r--r--include/dbus.h49
-rw-r--r--include/defs.h112
-rw-r--r--include/egl.h329
-rw-r--r--include/encoder/encoder.h43
-rw-r--r--include/encoder/video/nvenc.h16
-rw-r--r--include/encoder/video/software.h15
-rw-r--r--include/encoder/video/vaapi.h15
-rw-r--r--include/encoder/video/video.h30
-rw-r--r--include/encoder/video/vulkan.h15
-rw-r--r--include/image_writer.h35
-rw-r--r--include/library_loader.h17
-rw-r--r--include/overclock.h17
-rw-r--r--include/pipewire_audio.h156
-rw-r--r--include/pipewire_video.h117
-rw-r--r--include/replay_buffer/replay_buffer.h54
-rw-r--r--include/replay_buffer/replay_buffer_disk.h44
-rw-r--r--include/replay_buffer/replay_buffer_ram.h22
-rw-r--r--include/shader.h23
-rw-r--r--include/sound.hpp52
-rw-r--r--include/utils.h61
-rw-r--r--include/vec2.h16
-rw-r--r--include/window/wayland.h8
-rw-r--r--include/window/window.h37
-rw-r--r--include/window/x11.h10
-rw-r--r--include/window_texture.h28
-rw-r--r--include/xnvctrl.h45
43 files changed, 1928 insertions, 2259 deletions
diff --git a/include/NvFBC.h b/include/NvFBC.h
deleted file mode 100644
index 8990eea..0000000
--- a/include/NvFBC.h
+++ /dev/null
@@ -1,2006 +0,0 @@
-/*!
- * \file
- *
- * This file contains the interface constants, structure definitions and
- * function prototypes defining the NvFBC API for Linux.
- *
- * Copyright (c) 2013-2020, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NVFBC_H_
-#define _NVFBC_H_
-
-#include <stdint.h>
-
-/*!
- * \mainpage NVIDIA Framebuffer Capture (NvFBC) for Linux.
- *
- * NvFBC is a high performance, low latency API to capture the framebuffer of
- * an X server screen.
- *
- * The output from NvFBC captures everything that would be visible if we were
- * directly looking at the monitor. This includes window manager decoration,
- * mouse cursor, overlay, etc.
- *
- * It is ideally suited to desktop or fullscreen application capture and
- * remoting.
- */
-
-/*!
- * \defgroup FBC_REQ Requirements
- *
- * The following requirements are provided by the regular NVIDIA Display Driver
- * package:
- *
- * - OpenGL core >= 4.2:
- * Required. NvFBC relies on OpenGL to perform frame capture and
- * post-processing.
- *
- * - Vulkan 1.1:
- * Required.
- *
- * - libcuda.so.1 >= 5.5:
- * Optional. Used for capture to video memory with CUDA interop.
- *
- * The following requirements must be installed separately depending on the
- * Linux distribution being used:
- *
- * - XRandR extension >= 1.2:
- * Optional. Used for RandR output tracking.
- *
- * - libX11-xcb.so.1 >= 1.2:
- * Required. NvFBC uses a mix of Xlib and XCB. Xlib is needed to use GLX,
- * XCB is needed to make NvFBC more resilient against X server terminations
- * while a capture session is active.
- *
- * - libxcb.so.1 >= 1.3:
- * Required. See above.
- *
- * - xorg-server >= 1.3:
- * Optional. Required for push model to work properly.
- *
- * Note that all optional dependencies are dlopen()'d at runtime. Failure to
- * load an optional library is not fatal.
- */
-
-/*!
- * \defgroup FBC_CHANGES ChangeLog
- *
- * NvFBC Linux API version 0.1
- * - Initial BETA release.
- *
- * NvFBC Linux API version 0.2
- * - Added 'bEnableMSE' field to NVFBC_H264_HW_ENC_CONFIG.
- * - Added 'dwMSE' field to NVFBC_TOH264_GRAB_FRAME_PARAMS.
- * - Added 'bEnableAQ' field to NVFBC_H264_HW_ENC_CONFIG.
- * - Added 'NVFBC_H264_PRESET_LOSSLESS_HP' enum to NVFBC_H264_PRESET.
- * - Added 'NVFBC_BUFFER_FORMAT_YUV444P' enum to NVFBC_BUFFER_FORMAT.
- * - Added 'eInputBufferFormat' field to NVFBC_H264_HW_ENC_CONFIG.
- * - Added '0' and '244' values for NVFBC_H264_HW_ENC_CONFIG::dwProfile.
- *
- * NvFBC Linux API version 0.3
- * - Improved multi-threaded support by implementing an API locking mechanism.
- * - Added 'nvFBCBindContext' API entry point.
- * - Added 'nvFBCReleaseContext' API entry point.
- *
- * NvFBC Linux API version 1.0
- * - Added codec agnostic interface for HW encoding.
- * - Deprecated H.264 interface.
- * - Added support for H.265/HEVC HW encoding.
- *
- * NvFBC Linux API version 1.1
- * - Added 'nvFBCToHwGetCaps' API entry point.
- * - Added 'dwDiffMapScalingFactor' field to NVFBC_TOSYS_SETUP_PARAMS.
- *
- * NvFBC Linux API version 1.2
- * - Deprecated ToHwEnc interface.
- * - Added ToGL interface that captures frames to an OpenGL texture in video
- * memory.
- * - Added 'bDisableAutoModesetRecovery' field to
- * NVFBC_CREATE_CAPTURE_SESSION_PARAMS.
- * - Added 'bExternallyManagedContext' field to NVFBC_CREATE_HANDLE_PARAMS.
- *
- * NvFBC Linux API version 1.3
- * - Added NVFBC_BUFFER_FORMAT_RGBA
- * - Added 'dwTimeoutMs' field to NVFBC_TOSYS_GRAB_FRAME_PARAMS,
- * NVFBC_TOCUDA_GRAB_FRAME_PARAMS, and NVFBC_TOGL_GRAB_FRAME_PARAMS.
- *
- * NvFBC Linux API version 1.4
- * - Clarified that NVFBC_BUFFER_FORMAT_{ARGB,RGB,RGBA} are byte-order formats.
- * - Renamed NVFBC_BUFFER_FORMAT_YUV420P to NVFBC_BUFFER_FORMAT_NV12.
- * - Added new requirements.
- * - Made NvFBC more resilient against the X server terminating during an active
- * capture session. See new comments for ::NVFBC_ERR_X.
- * - Relaxed requirement that 'frameSize' must have a width being a multiple of
- * 4 and a height being a multiple of 2.
- * - Added 'bRoundFrameSize' field to NVFBC_CREATE_CAPTURE_SESSION_PARAMS.
- * - Relaxed requirement that the scaling factor for differential maps must be
- * a multiple of the size of the frame.
- * - Added 'diffMapSize' field to NVFBC_TOSYS_SETUP_PARAMS and
- * NVFBC_TOGL_SETUP_PARAMS.
- *
- * NvFBC Linux API version 1.5
- * - Added NVFBC_BUFFER_FORMAT_BGRA
- *
- * NvFBC Linux API version 1.6
- * - Added the 'NVFBC_TOSYS_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY',
- * 'NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY', and
- * 'NVFBC_TOGL_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY' capture flags.
- * - Exposed debug and performance logs through the NVFBC_LOG_LEVEL environment
- * variable. Setting it to "1" enables performance logs, setting it to "2"
- * enables debugging logs, setting it to "3" enables both.
- * - Logs are printed to stdout or to the file pointed by the NVFBC_LOG_FILE
- * environment variable.
- * - Added 'ulTimestampUs' to NVFBC_FRAME_GRAB_INFO.
- * - Added 'dwSamplingRateMs' to NVFBC_CREATE_CAPTURE_SESSION_PARAMS.
- * - Added 'bPushModel' to NVFBC_CREATE_CAPTURE_SESSION_PARAMS.
- *
- * NvFBC Linux API version 1.7
- * - Retired the NVFBC_CAPTURE_TO_HW_ENCODER interface.
- * This interface has been deprecated since NvFBC 1.2 and has received no
- * updates or new features since. We recommend using the NVIDIA Video Codec
- * SDK to encode NvFBC frames.
- * See: https://developer.nvidia.com/nvidia-video-codec-sdk
- * - Added a 'Capture Modes' section to those headers.
- * - Added a 'Post Processing' section to those headers.
- * - Added an 'Environment Variables' section to those headers.
- * - Added 'bInModeset' to NVFBC_GET_STATUS_PARAMS.
- * - Added 'bAllowDirectCapture' to NVFBC_CREATE_CAPTURE_SESSION_PARAMS.
- * - Added 'bDirectCaptured' to NVFBC_FRAME_GRAB_INFO.
- * - Added 'bRequiredPostProcessing' to NVFBC_FRAME_GRAB_INFO.
- */
-
-/*!
- * \defgroup FBC_MODES Capture Modes
- *
- * When creating a capture session, NvFBC instantiates a capture subsystem
- * living in the NVIDIA X driver.
- *
- * This subsystem listens for damage events coming from applications then
- * generates (composites) frames for NvFBC when new content is available.
- *
- * This capture server can operate on a timer where it periodically checks if
- * there are any pending damage events, or it can generate frames as soon as it
- * receives a new damage event.
- * See NVFBC_CREATE_CAPTURE_SESSION_PARAMS::dwSamplingRateMs,
- * and NVFBC_CREATE_CAPTURE_SESSION_PARAMS::bPushModel.
- *
- * NvFBC can also attach itself to a fullscreen unoccluded application and have
- * it copy its frames directly into a buffer owned by NvFBC upon present. This
- * mode bypasses the X server.
- * See NVFBC_CREATE_CAPTURE_SESSION_PARAMS::bAllowDirectCapture.
- *
- * NvFBC is designed to capture frames with as few copies as possible. The
- * NVIDIA X driver composites frames directly into the NvFBC buffers, and
- * direct capture copies frames directly into these buffers as well.
- *
- * Depending on the configuration of a capture session, an extra copy (rendering
- * pass) may be needed. See the 'Post Processing' section.
- */
-
-/*!
- * \defgroup FBC_PP Post Processing
- *
- * Depending on the configuration of a capture session, NvFBC might require to
- * do post processing on frames.
- *
- * Post processing is required for the following reasons:
- * - NvFBC needs to do a pixel format conversion.
- * - Diffmaps are requested.
- * - Capture to system memory is requested.
- *
- * NvFBC needs to do a conversion if the requested pixel format does not match
- * the native format. The native format is NVFBC_BUFFER_FORMAT_BGRA.
- *
- * Note: post processing is *not* required for frame scaling and frame cropping.
- *
- * Skipping post processing can reduce capture latency. An application can know
- * whether post processing was required by checking
- * NVFBC_FRAME_GRAB_INFO::bRequiredPostProcessing.
- */
-
-/*!
- * \defgroup FBC_ENVVAR Environment Variables
- *
- * Below are the environment variables supported by NvFBC:
- *
- * - NVFBC_LOG_LEVEL
- * Bitfield where the first bit enables debug logs and the second bit enables
- * performance logs. Both can be enabled by setting this envvar to 3.
- *
- * - NVFBC_LOG_FILE
- * Write all NvFBC logs to the given file.
- *
- * - NVFBC_FORCE_ALLOW_DIRECT_CAPTURE
- * Used to override NVFBC_CREATE_CAPTURE_SESSION_PARAMS::bAllowDirectCapture.
- *
- * - NVFBC_FORCE_POST_PROCESSING
- * Used to force the post processing step, even if it could be skipped.
- * See the 'Post Processing' section.
- */
-
-/*!
- * \defgroup FBC_STRUCT Structure Definition
- *
- * @{
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*!
- * Calling convention.
- */
-#define NVFBCAPI
-
-/*!
- * NvFBC API major version.
- */
-#define NVFBC_VERSION_MAJOR 1
-
-/*!
- * NvFBC API minor version.
- */
-#define NVFBC_VERSION_MINOR 7
-
-/*!
- * NvFBC API version.
- */
-#define NVFBC_VERSION (uint32_t) (NVFBC_VERSION_MINOR | (NVFBC_VERSION_MAJOR << 8))
-
-/*!
- * Creates a version number for structure parameters.
- */
-#define NVFBC_STRUCT_VERSION(typeName, ver) \
- (uint32_t) (sizeof(typeName) | ((ver) << 16) | (NVFBC_VERSION << 24))
-
-/*!
- * Defines error codes.
- *
- * \see NvFBCGetLastErrorStr
- */
-typedef enum _NVFBCSTATUS
-{
- /*!
- * This indicates that the API call returned with no errors.
- */
- NVFBC_SUCCESS = 0,
- /*!
- * This indicates that the API version between the client and the library
- * is not compatible.
- */
- NVFBC_ERR_API_VERSION = 1,
- /*!
- * An internal error occurred.
- */
- NVFBC_ERR_INTERNAL = 2,
- /*!
- * This indicates that one or more of the parameter passed to the API call
- * is invalid.
- */
- NVFBC_ERR_INVALID_PARAM = 3,
- /*!
- * This indicates that one or more of the pointers passed to the API call
- * is invalid.
- */
- NVFBC_ERR_INVALID_PTR = 4,
- /*!
- * This indicates that the handle passed to the API call to identify the
- * client is invalid.
- */
- NVFBC_ERR_INVALID_HANDLE = 5,
- /*!
- * This indicates that the maximum number of threaded clients of the same
- * process has been reached. The limit is 10 threads per process.
- * There is no limit on the number of process.
- */
- NVFBC_ERR_MAX_CLIENTS = 6,
- /*!
- * This indicates that the requested feature is not currently supported
- * by the library.
- */
- NVFBC_ERR_UNSUPPORTED = 7,
- /*!
- * This indicates that the API call failed because it was unable to allocate
- * enough memory to perform the requested operation.
- */
- NVFBC_ERR_OUT_OF_MEMORY = 8,
- /*!
- * This indicates that the API call was not expected. This happens when
- * API calls are performed in a wrong order, such as trying to capture
- * a frame prior to creating a new capture session; or trying to set up
- * a capture to video memory although a capture session to system memory
- * was created.
- */
- NVFBC_ERR_BAD_REQUEST = 9,
- /*!
- * This indicates an X error, most likely meaning that the X server has
- * been terminated. When this error is returned, the only resort is to
- * create another FBC handle using NvFBCCreateHandle().
- *
- * The previous handle should still be freed with NvFBCDestroyHandle(), but
- * it might leak resources, in particular X, GLX, and GL resources since
- * it is no longer possible to communicate with an X server to free them
- * through the driver.
- *
- * The best course of action to eliminate this potential leak is to close
- * the OpenGL driver, close the forked process running the capture, or
- * restart the application.
- */
- NVFBC_ERR_X = 10,
- /*!
- * This indicates a GLX error.
- */
- NVFBC_ERR_GLX = 11,
- /*!
- * This indicates an OpenGL error.
- */
- NVFBC_ERR_GL = 12,
- /*!
- * This indicates a CUDA error.
- */
- NVFBC_ERR_CUDA = 13,
- /*!
- * This indicates a HW encoder error.
- */
- NVFBC_ERR_ENCODER = 14,
- /*!
- * This indicates an NvFBC context error.
- */
- NVFBC_ERR_CONTEXT = 15,
- /*!
- * This indicates that the application must recreate the capture session.
- *
- * This error can be returned if a modeset event occurred while capturing
- * frames, and NVFBC_CREATE_HANDLE_PARAMS::bDisableAutoModesetRecovery
- * was set to NVFBC_TRUE.
- */
- NVFBC_ERR_MUST_RECREATE = 16,
- /*!
- * This indicates a Vulkan error.
- */
- NVFBC_ERR_VULKAN = 17,
-} NVFBCSTATUS;
-
-/*!
- * Defines boolean values.
- */
-typedef enum _NVFBC_BOOL
-{
- /*!
- * False value.
- */
- NVFBC_FALSE = 0,
- /*!
- * True value.
- */
- NVFBC_TRUE,
-} NVFBC_BOOL;
-
-/*!
- * Maximum size in bytes of an error string.
- */
-#define NVFBC_ERR_STR_LEN 512
-
-/*!
- * Capture type.
- */
-typedef enum _NVFBC_CAPTURE_TYPE
-{
- /*!
- * Capture frames to a buffer in system memory.
- */
- NVFBC_CAPTURE_TO_SYS = 0,
- /*!
- * Capture frames to a CUDA device in video memory.
- *
- * Specifying this will dlopen() libcuda.so.1 and fail if not available.
- */
- NVFBC_CAPTURE_SHARED_CUDA,
- /*!
- * Retired. Do not use.
- */
- /* NVFBC_CAPTURE_TO_HW_ENCODER, */
- /*!
- * Capture frames to an OpenGL buffer in video memory.
- */
- NVFBC_CAPTURE_TO_GL = 3,
-} NVFBC_CAPTURE_TYPE;
-
-/*!
- * Tracking type.
- *
- * NvFBC can track a specific region of the framebuffer to capture.
- *
- * An X screen corresponds to the entire framebuffer.
- *
- * An RandR CRTC is a component of the GPU that reads pixels from a region of
- * the X screen and sends them through a pipeline to an RandR output.
- * A physical monitor can be connected to an RandR output. Tracking an RandR
- * output captures the region of the X screen that the RandR CRTC is sending to
- * the RandR output.
- */
-typedef enum
-{
- /*!
- * By default, NvFBC tries to track a connected primary output. If none is
- * found, then it tries to track the first connected output. If none is
- * found then it tracks the entire X screen.
- *
- * If the XRandR extension is not available, this option has the same effect
- * as ::NVFBC_TRACKING_SCREEN.
- *
- * This default behavior might be subject to changes in the future.
- */
- NVFBC_TRACKING_DEFAULT = 0,
- /*!
- * Track an RandR output specified by its ID in the appropriate field.
- *
- * The list of connected outputs can be queried via NvFBCGetStatus().
- * This list can also be obtained using e.g., xrandr(1).
- *
- * If the XRandR extension is not available, setting this option returns an
- * error.
- */
- NVFBC_TRACKING_OUTPUT,
- /*!
- * Track the entire X screen.
- */
- NVFBC_TRACKING_SCREEN,
-} NVFBC_TRACKING_TYPE;
-
-/*!
- * Buffer format.
- */
-typedef enum _NVFBC_BUFFER_FORMAT
-{
- /*!
- * Data will be converted to ARGB8888 byte-order format. 32 bpp.
- */
- NVFBC_BUFFER_FORMAT_ARGB = 0,
- /*!
- * Data will be converted to RGB888 byte-order format. 24 bpp.
- */
- NVFBC_BUFFER_FORMAT_RGB,
- /*!
- * Data will be converted to NV12 format using HDTV weights
- * according to ITU-R BT.709. 12 bpp.
- */
- NVFBC_BUFFER_FORMAT_NV12,
- /*!
- * Data will be converted to YUV 444 planar format using HDTV weights
- * according to ITU-R BT.709. 24 bpp
- */
- NVFBC_BUFFER_FORMAT_YUV444P,
- /*!
- * Data will be converted to RGBA8888 byte-order format. 32 bpp.
- */
- NVFBC_BUFFER_FORMAT_RGBA,
- /*!
- * Native format. No pixel conversion needed.
- * BGRA8888 byte-order format. 32 bpp.
- */
- NVFBC_BUFFER_FORMAT_BGRA,
-} NVFBC_BUFFER_FORMAT;
-
-#define NVFBC_BUFFER_FORMAT_YUV420P NVFBC_BUFFER_FORMAT_NV12
-
-/*!
- * Handle used to identify an NvFBC session.
- */
-typedef uint64_t NVFBC_SESSION_HANDLE;
-
-/*!
- * Box used to describe an area of the tracked region to capture.
- *
- * The coordinates are relative to the tracked region.
- *
- * E.g., if the size of the X screen is 3520x1200 and the tracked RandR output
- * scans a region of 1600x1200+1920+0, then setting a capture box of
- * 800x600+100+50 effectively captures a region of 800x600+2020+50 relative to
- * the X screen.
- */
-typedef struct _NVFBC_BOX
-{
- /*!
- * [in] X offset of the box.
- */
- uint32_t x;
- /*!
- * [in] Y offset of the box.
- */
- uint32_t y;
- /*!
- * [in] Width of the box.
- */
- uint32_t w;
- /*!
- * [in] Height of the box.
- */
- uint32_t h;
-} NVFBC_BOX;
-
-/*!
- * Size used to describe the size of a frame.
- */
-typedef struct _NVFBC_SIZE
-{
- /*!
- * [in] Width.
- */
- uint32_t w;
- /*!
- * [in] Height.
- */
- uint32_t h;
-} NVFBC_SIZE;
-
-/*!
- * Describes information about a captured frame.
- */
-typedef struct _NVFBC_FRAME_GRAB_INFO
-{
- /*!
- * [out] Width of the captured frame.
- */
- uint32_t dwWidth;
- /*!
- * [out] Height of the captured frame.
- */
- uint32_t dwHeight;
- /*!
- * [out] Size of the frame in bytes.
- */
- uint32_t dwByteSize;
- /*!
- * [out] Incremental ID of the current frame.
- *
- * This can be used to identify a frame.
- */
- uint32_t dwCurrentFrame;
- /*!
- * [out] Whether the captured frame is a new frame.
- *
- * When using non blocking calls it is possible to capture a frame
- * that was already captured before if the display server did not
- * render a new frame in the meantime. In that case, this flag
- * will be set to NVFBC_FALSE.
- *
- * When using blocking calls each captured frame will have
- * this flag set to NVFBC_TRUE since the blocking mechanism waits for
- * the display server to render a new frame.
- *
- * Note that this flag does not guarantee that the content of
- * the frame will be different compared to the previous captured frame.
- *
- * In particular, some compositing managers report the entire
- * framebuffer as damaged when an application refreshes its content.
- *
- * Consider a single X screen spanned across physical displays A and B
- * and an NvFBC application tracking display A. Depending on the
- * compositing manager, it is possible that an application refreshing
- * itself on display B will trigger a frame capture on display A.
- *
- * Workarounds include:
- * - Using separate X screens
- * - Disabling the composite extension
- * - Using a compositing manager that properly reports what regions
- * are damaged
- * - Using NvFBC's diffmaps to find out if the frame changed
- */
- NVFBC_BOOL bIsNewFrame;
- /*!
- * [out] Frame timestamp
- *
- * Time in micro seconds when the display server started rendering the
- * frame.
- *
- * This does not account for when the frame was captured. If capturing an
- * old frame (e.g., bIsNewFrame is NVFBC_FALSE) the reported timestamp
- * will reflect the time when the old frame was rendered by the display
- * server.
- */
- uint64_t ulTimestampUs;
- /*
- * [out] Number of frames generated since the last capture.
- *
- * This can help applications tell whether they missed frames or there
- * were no frames generated by the server since the last capture.
- */
- uint32_t dwMissedFrames;
- /*
- * [out] Whether the captured frame required post processing.
- *
- * See the 'Post Processing' section.
- */
- NVFBC_BOOL bRequiredPostProcessing;
- /*
- * [out] Whether this frame was obtained via direct capture.
- *
- * See NVFBC_CREATE_CAPTURE_SESSION_PARAMS::bAllowDirectCapture.
- */
- NVFBC_BOOL bDirectCapture;
-} NVFBC_FRAME_GRAB_INFO;
-
-/*!
- * Defines parameters for the CreateHandle() API call.
- */
-typedef struct _NVFBC_CREATE_HANDLE_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_CREATE_HANDLE_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [in] Application specific private information passed to the NvFBC
- * session.
- */
- const void *privateData;
- /*!
- * [in] Size of the application specific private information passed to the
- * NvFBC session.
- */
- uint32_t privateDataSize;
- /*!
- * [in] Whether NvFBC should not create and manage its own graphics context
- *
- * NvFBC internally uses OpenGL to perfom graphics operations on the
- * captured frames. By default, NvFBC will create and manage (e.g., make
- * current, detect new threads, etc.) its own OpenGL context.
- *
- * If set to NVFBC_TRUE, NvFBC will use the application's context. It will
- * be the application's responsibility to make sure that a context is
- * current on the thread calling into the NvFBC API.
- */
- NVFBC_BOOL bExternallyManagedContext;
- /*!
- * [in] GLX context
- *
- * GLX context that NvFBC should use internally to create pixmaps and
- * make them current when creating a new capture session.
- *
- * Note: NvFBC expects a context created against a GLX_RGBA_TYPE render
- * type.
- */
- void *glxCtx;
- /*!
- * [in] GLX framebuffer configuration
- *
- * Framebuffer configuration that was used to create the GLX context, and
- * that will be used to create pixmaps internally.
- *
- * Note: NvFBC expects a configuration having at least the following
- * attributes:
- * GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT
- * GLX_BIND_TO_TEXTURE_RGBA_EXT, 1
- * GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT
- */
- void *glxFBConfig;
-} NVFBC_CREATE_HANDLE_PARAMS;
-
-/*!
- * NVFBC_CREATE_HANDLE_PARAMS structure version.
- */
-#define NVFBC_CREATE_HANDLE_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_CREATE_HANDLE_PARAMS, 2)
-
-/*!
- * Defines parameters for the ::NvFBCDestroyHandle() API call.
- */
-typedef struct _NVFBC_DESTROY_HANDLE_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_DESTROY_HANDLE_PARAMS_VER
- */
- uint32_t dwVersion;
-} NVFBC_DESTROY_HANDLE_PARAMS;
-
-/*!
- * NVFBC_DESTROY_HANDLE_PARAMS structure version.
- */
-#define NVFBC_DESTROY_HANDLE_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_DESTROY_HANDLE_PARAMS, 1)
-
-/*!
- * Maximum number of connected RandR outputs to an X screen.
- */
-#define NVFBC_OUTPUT_MAX 5
-
-/*!
- * Maximum size in bytes of an RandR output name.
- */
-#define NVFBC_OUTPUT_NAME_LEN 128
-
-/*!
- * Describes an RandR output.
- *
- * Filling this structure relies on the XRandR extension. This feature cannot
- * be used if the extension is missing or its version is below the requirements.
- *
- * \see Requirements
- */
-typedef struct _NVFBC_OUTPUT
-{
- /*!
- * Identifier of the RandR output.
- */
- uint32_t dwId;
- /*!
- * Name of the RandR output, as reported by tools such as xrandr(1).
- *
- * Example: "DVI-I-0"
- */
- char name[NVFBC_OUTPUT_NAME_LEN];
- /*!
- * Region of the X screen tracked by the RandR CRTC driving this RandR
- * output.
- */
- NVFBC_BOX trackedBox;
-} NVFBC_RANDR_OUTPUT_INFO;
-
-/*!
- * Defines parameters for the ::NvFBCGetStatus() API call.
- */
-typedef struct _NVFBC_GET_STATUS_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_GET_STATUS_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [out] Whether or not framebuffer capture is supported by the graphics
- * driver.
- */
- NVFBC_BOOL bIsCapturePossible;
- /*!
- * [out] Whether or not there is already a capture session on this system.
- */
- NVFBC_BOOL bCurrentlyCapturing;
- /*!
- * [out] Whether or not it is possible to create a capture session on this
- * system.
- */
- NVFBC_BOOL bCanCreateNow;
- /*!
- * [out] Size of the X screen (framebuffer).
- */
- NVFBC_SIZE screenSize;
- /*!
- * [out] Whether the XRandR extension is available.
- *
- * If this extension is not available then it is not possible to have
- * information about RandR outputs.
- */
- NVFBC_BOOL bXRandRAvailable;
- /*!
- * [out] Array of outputs connected to the X screen.
- *
- * An application can track a specific output by specifying its ID when
- * creating a capture session.
- *
- * Only if XRandR is available.
- */
- NVFBC_RANDR_OUTPUT_INFO outputs[NVFBC_OUTPUT_MAX];
- /*!
- * [out] Number of outputs connected to the X screen.
- *
- * This must be used to parse the array of connected outputs.
- *
- * Only if XRandR is available.
- */
- uint32_t dwOutputNum;
- /*!
- * [out] Version of the NvFBC library running on this system.
- */
- uint32_t dwNvFBCVersion;
- /*!
- * [out] Whether the X server is currently in modeset.
- *
- * When the X server is in modeset, it must give up all its video
- * memory allocations. It is not possible to create a capture
- * session until the modeset is over.
- *
- * Note that VT-switches are considered modesets.
- */
- NVFBC_BOOL bInModeset;
-} NVFBC_GET_STATUS_PARAMS;
-
-/*!
- * NVFBC_GET_STATUS_PARAMS structure version.
- */
-#define NVFBC_GET_STATUS_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_GET_STATUS_PARAMS, 2)
-
-/*!
- * Defines parameters for the ::NvFBCCreateCaptureSession() API call.
- */
-typedef struct _NVFBC_CREATE_CAPTURE_SESSION_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [in] Desired capture type.
- *
- * Note that when specyfing ::NVFBC_CAPTURE_SHARED_CUDA NvFBC will try to
- * dlopen() the corresponding libraries. This means that NvFBC can run on
- * a system without the CUDA library since it does not link against them.
- */
- NVFBC_CAPTURE_TYPE eCaptureType;
- /*!
- * [in] What region of the framebuffer should be tracked.
- */
- NVFBC_TRACKING_TYPE eTrackingType;
- /*!
- * [in] ID of the output to track if eTrackingType is set to
- * ::NVFBC_TRACKING_OUTPUT.
- */
- uint32_t dwOutputId;
- /*!
- * [in] Crop the tracked region.
- *
- * The coordinates are relative to the tracked region.
- *
- * It can be set to 0 to capture the entire tracked region.
- */
- NVFBC_BOX captureBox;
- /*!
- * [in] Desired size of the captured frame.
- *
- * This parameter allow to scale the captured frame.
- *
- * It can be set to 0 to disable frame resizing.
- */
- NVFBC_SIZE frameSize;
- /*!
- * [in] Whether the mouse cursor should be composited to the frame.
- *
- * Disabling the cursor will not generate new frames when only the cursor
- * is moved.
- */
- NVFBC_BOOL bWithCursor;
- /*!
- * [in] Whether NvFBC should not attempt to recover from modesets.
- *
- * NvFBC is able to detect when a modeset event occured and can automatically
- * re-create a capture session with the same settings as before, then resume
- * its frame capture session transparently.
- *
- * This option allows to disable this behavior. NVFBC_ERR_MUST_RECREATE
- * will be returned in that case.
- *
- * It can be useful in the cases when an application needs to do some work
- * between setting up a capture and grabbing the first frame.
- *
- * For example: an application using the ToGL interface needs to register
- * resources with EncodeAPI prior to encoding frames.
- *
- * Note that during modeset recovery, NvFBC will try to re-create the
- * capture session every second until it succeeds.
- */
- NVFBC_BOOL bDisableAutoModesetRecovery;
- /*!
- * [in] Whether NvFBC should round the requested frameSize.
- *
- * When disabled, NvFBC will not attempt to round the requested resolution.
- *
- * However, some pixel formats have resolution requirements. E.g., YUV/NV
- * formats must have a width being a multiple of 4, and a height being a
- * multiple of 2. RGB formats don't have such requirements.
- *
- * If the resolution doesn't meet the requirements of the format, then NvFBC
- * will fail at setup time.
- *
- * When enabled, NvFBC will round the requested width to the next multiple
- * of 4 and the requested height to the next multiple of 2.
- *
- * In this case, requesting any resolution will always work with every
- * format. However, an NvFBC client must be prepared to handle the case
- * where the requested resolution is different than the captured resolution.
- *
- * NVFBC_FRAME_GRAB_INFO::dwWidth and NVFBC_FRAME_GRAB_INFO::dwHeight should
- * always be used for getting information about captured frames.
- */
- NVFBC_BOOL bRoundFrameSize;
- /*!
- * [in] Rate in ms at which the display server generates new frames
- *
- * This controls the frequency at which the display server will generate
- * new frames if new content is available. This effectively controls the
- * capture rate when using blocking calls.
- *
- * Note that lower values will increase the CPU and GPU loads.
- *
- * The default value is 16ms (~ 60 Hz).
- */
- uint32_t dwSamplingRateMs;
- /*!
- * [in] Enable push model for frame capture
- *
- * When set to NVFBC_TRUE, the display server will generate frames whenever
- * it receives a damage event from applications.
- *
- * Setting this to NVFBC_TRUE will ignore ::dwSamplingRateMs.
- *
- * Using push model with the NVFBC_*_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY
- * capture flag should guarantee the shortest amount of time between an
- * application rendering a frame and an NvFBC client capturing it, provided
- * that the NvFBC client is able to process the frames quickly enough.
- *
- * Note that applications running at high frame rates will increase CPU and
- * GPU loads.
- */
- NVFBC_BOOL bPushModel;
- /*!
- * [in] Allow direct capture
- *
- * Direct capture allows NvFBC to attach itself to a fullscreen graphics
- * application. Whenever that application presents a frame, it makes a copy
- * of it directly into a buffer owned by NvFBC thus bypassing the X server.
- *
- * When direct capture is *not* enabled, the NVIDIA X driver generates a
- * frame for NvFBC when it receives a damage event from an application if push
- * model is enabled, or periodically checks if there are any pending damage
- * events otherwise (see NVFBC_CREATE_CAPTURE_SESSION_PARAMS::dwSamplingRateMs).
- *
- * Direct capture is possible under the following conditions:
- * - Direct capture is allowed
- * - Push model is enabled (see NVFBC_CREATE_CAPTURE_SESSION_PARAMS::bPushModel)
- * - The mouse cursor is not composited (see NVFBC_CREATE_CAPTURE_SESSION_PARAMS::bWithCursor)
- * - No viewport transformation is required. This happens when the remote
- * desktop is e.g. rotated.
- *
- * When direct capture is possible, NvFBC will automatically attach itself
- * to a fullscreen unoccluded application, if such exists.
- *
- * Notes:
- * - This includes compositing desktops such as GNOME (e.g., gnome-shell
- * is the fullscreen unoccluded application).
- * - There can be only one fullscreen unoccluded application at a time.
- * - The NVIDIA X driver monitors which application qualifies or no
- * longer qualifies.
- *
- * For example, if a fullscreen application is launched in GNOME, NvFBC will
- * detach from gnome-shell and attach to that application.
- *
- * Attaching and detaching happens automatically from the perspective of an
- * NvFBC client. When detaching from an application, the X driver will
- * transparently resume generating frames for NvFBC.
- *
- * An application can know whether a given frame was obtained through
- * direct capture by checking NVFBC_FRAME_GRAB_INFO::bDirectCapture.
- */
- NVFBC_BOOL bAllowDirectCapture;
-} NVFBC_CREATE_CAPTURE_SESSION_PARAMS;
-
-/*!
- * NVFBC_CREATE_CAPTURE_SESSION_PARAMS structure version.
- */
-#define NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_CREATE_CAPTURE_SESSION_PARAMS, 6)
-
-/*!
- * Defines parameters for the ::NvFBCDestroyCaptureSession() API call.
- */
-typedef struct _NVFBC_DESTROY_CAPTURE_SESSION_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER
- */
- uint32_t dwVersion;
-} NVFBC_DESTROY_CAPTURE_SESSION_PARAMS;
-
-/*!
- * NVFBC_DESTROY_CAPTURE_SESSION_PARAMS structure version.
- */
-#define NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_DESTROY_CAPTURE_SESSION_PARAMS, 1)
-
-/*!
- * Defines parameters for the ::NvFBCBindContext() API call.
- */
-typedef struct _NVFBC_BIND_CONTEXT_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_BIND_CONTEXT_PARAMS_VER
- */
- uint32_t dwVersion;
-} NVFBC_BIND_CONTEXT_PARAMS;
-
-/*!
- * NVFBC_BIND_CONTEXT_PARAMS structure version.
- */
-#define NVFBC_BIND_CONTEXT_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_BIND_CONTEXT_PARAMS, 1)
-
-/*!
- * Defines parameters for the ::NvFBCReleaseContext() API call.
- */
-typedef struct _NVFBC_RELEASE_CONTEXT_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_RELEASE_CONTEXT_PARAMS_VER
- */
- uint32_t dwVersion;
-} NVFBC_RELEASE_CONTEXT_PARAMS;
-
-/*!
- * NVFBC_RELEASE_CONTEXT_PARAMS structure version.
- */
-#define NVFBC_RELEASE_CONTEXT_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_RELEASE_CONTEXT_PARAMS, 1)
-
-/*!
- * Defines flags that can be used when capturing to system memory.
- */
-typedef enum
-{
- /*!
- * Default, capturing waits for a new frame or mouse move.
- *
- * The default behavior of blocking grabs is to wait for a new frame until
- * after the call was made. But it's possible that there is a frame already
- * ready that the client hasn't seen.
- * \see NVFBC_TOSYS_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY
- */
- NVFBC_TOSYS_GRAB_FLAGS_NOFLAGS = 0,
- /*!
- * Capturing does not wait for a new frame nor a mouse move.
- *
- * It is therefore possible to capture the same frame multiple times.
- * When this occurs, the dwCurrentFrame parameter of the
- * NVFBC_FRAME_GRAB_INFO structure is not incremented.
- */
- NVFBC_TOSYS_GRAB_FLAGS_NOWAIT = (1 << 0),
- /*!
- * Forces the destination buffer to be refreshed even if the frame has not
- * changed since previous capture.
- *
- * By default, if the captured frame is identical to the previous one, NvFBC
- * will omit one copy and not update the destination buffer.
- *
- * Setting that flag will prevent this behavior. This can be useful e.g.,
- * if the application has modified the buffer in the meantime.
- */
- NVFBC_TOSYS_GRAB_FLAGS_FORCE_REFRESH = (1 << 1),
- /*!
- * Similar to NVFBC_TOSYS_GRAB_FLAGS_NOFLAGS, except that the capture will
- * not wait if there is already a frame available that the client has
- * never seen yet.
- */
- NVFBC_TOSYS_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY = (1 << 2),
-} NVFBC_TOSYS_GRAB_FLAGS;
-
-/*!
- * Defines parameters for the ::NvFBCToSysSetUp() API call.
- */
-typedef struct _NVFBC_TOSYS_SETUP_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_TOSYS_SETUP_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [in] Desired buffer format.
- */
- NVFBC_BUFFER_FORMAT eBufferFormat;
- /*!
- * [out] Pointer to a pointer to a buffer in system memory.
- *
- * This buffer contains the pixel value of the requested format. Refer to
- * the description of the buffer formats to understand the memory layout.
- *
- * The application does not need to allocate memory for this buffer. It
- * should not free this buffer either. This buffer is automatically
- * re-allocated when needed (e.g., when the resolution changes).
- *
- * This buffer is allocated by the NvFBC library to the proper size. This
- * size is returned in the dwByteSize field of the
- * ::NVFBC_FRAME_GRAB_INFO structure.
- */
- void **ppBuffer;
- /*!
- * [in] Whether differential maps should be generated.
- */
- NVFBC_BOOL bWithDiffMap;
- /*!
- * [out] Pointer to a pointer to a buffer in system memory.
- *
- * This buffer contains the differential map of two frames. It must be read
- * as an array of unsigned char. Each unsigned char is either 0 or
- * non-zero. 0 means that the pixel value at the given location has not
- * changed since the previous captured frame. Non-zero means that the pixel
- * value has changed.
- *
- * The application does not need to allocate memory for this buffer. It
- * should not free this buffer either. This buffer is automatically
- * re-allocated when needed (e.g., when the resolution changes).
- *
- * This buffer is allocated by the NvFBC library to the proper size. The
- * size of the differential map is returned in ::diffMapSize.
- *
- * This option is not compatible with the ::NVFBC_BUFFER_FORMAT_YUV420P and
- * ::NVFBC_BUFFER_FORMAT_YUV444P buffer formats.
- */
- void **ppDiffMap;
- /*!
- * [in] Scaling factor of the differential maps.
- *
- * For example, a scaling factor of 16 means that one pixel of the diffmap
- * will represent 16x16 pixels of the original frames.
- *
- * If any of these 16x16 pixels is different between the current and the
- * previous frame, then the corresponding pixel in the diffmap will be set
- * to non-zero.
- *
- * The default scaling factor is 1. A dwDiffMapScalingFactor of 0 will be
- * set to 1.
- */
- uint32_t dwDiffMapScalingFactor;
- /*!
- * [out] Size of the differential map.
- *
- * Only set if bWithDiffMap is set to NVFBC_TRUE.
- */
- NVFBC_SIZE diffMapSize;
-} NVFBC_TOSYS_SETUP_PARAMS;
-
-/*!
- * NVFBC_TOSYS_SETUP_PARAMS structure version.
- */
-#define NVFBC_TOSYS_SETUP_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_TOSYS_SETUP_PARAMS, 3)
-
-/*!
- * Defines parameters for the ::NvFBCToSysGrabFrame() API call.
- */
-typedef struct _NVFBC_TOSYS_GRAB_FRAME_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [in] Flags defining the behavior of this frame capture.
- */
- uint32_t dwFlags;
- /*!
- * [out] Information about the captured frame.
- *
- * Can be NULL.
- */
- NVFBC_FRAME_GRAB_INFO *pFrameGrabInfo;
- /*!
- * [in] Wait timeout in milliseconds.
- *
- * When capturing frames with the NVFBC_TOSYS_GRAB_FLAGS_NOFLAGS or
- * NVFBC_TOSYS_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY flags,
- * NvFBC will wait for a new frame or mouse move until the below timer
- * expires.
- *
- * When timing out, the last captured frame will be returned. Note that as
- * long as the NVFBC_TOSYS_GRAB_FLAGS_FORCE_REFRESH flag is not set,
- * returning an old frame will incur no performance penalty.
- *
- * NvFBC clients can use the return value of the grab frame operation to
- * find out whether a new frame was captured, or the timer expired.
- *
- * Note that the behavior of blocking calls is to wait for a new frame
- * *after* the call has been made. When using timeouts, it is possible
- * that NvFBC will return a new frame (e.g., it has never been captured
- * before) even though no new frame was generated after the grab call.
- *
- * For the precise definition of what constitutes a new frame, see
- * ::bIsNewFrame.
- *
- * Set to 0 to disable timeouts.
- */
- uint32_t dwTimeoutMs;
-} NVFBC_TOSYS_GRAB_FRAME_PARAMS;
-
-/*!
- * NVFBC_TOSYS_GRAB_FRAME_PARAMS structure version.
- */
-#define NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_TOSYS_GRAB_FRAME_PARAMS, 2)
-
-/*!
- * Defines flags that can be used when capturing to a CUDA buffer in video memory.
- */
-typedef enum
-{
- /*!
- * Default, capturing waits for a new frame or mouse move.
- *
- * The default behavior of blocking grabs is to wait for a new frame until
- * after the call was made. But it's possible that there is a frame already
- * ready that the client hasn't seen.
- * \see NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY
- */
- NVFBC_TOCUDA_GRAB_FLAGS_NOFLAGS = 0,
- /*!
- * Capturing does not wait for a new frame nor a mouse move.
- *
- * It is therefore possible to capture the same frame multiple times.
- * When this occurs, the dwCurrentFrame parameter of the
- * NVFBC_FRAME_GRAB_INFO structure is not incremented.
- */
- NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT = (1 << 0),
- /*!
- * [in] Forces the destination buffer to be refreshed even if the frame
- * has not changed since previous capture.
- *
- * By default, if the captured frame is identical to the previous one, NvFBC
- * will omit one copy and not update the destination buffer.
- *
- * Setting that flag will prevent this behavior. This can be useful e.g.,
- * if the application has modified the buffer in the meantime.
- */
- NVFBC_TOCUDA_GRAB_FLAGS_FORCE_REFRESH = (1 << 1),
- /*!
- * Similar to NVFBC_TOCUDA_GRAB_FLAGS_NOFLAGS, except that the capture will
- * not wait if there is already a frame available that the client has
- * never seen yet.
- */
- NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY = (1 << 2),
-} NVFBC_TOCUDA_FLAGS;
-
-/*!
- * Defines parameters for the ::NvFBCToCudaSetUp() API call.
- */
-typedef struct _NVFBC_TOCUDA_SETUP_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_TOCUDA_SETUP_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [in] Desired buffer format.
- */
- NVFBC_BUFFER_FORMAT eBufferFormat;
-} NVFBC_TOCUDA_SETUP_PARAMS;
-
-/*!
- * NVFBC_TOCUDA_SETUP_PARAMS structure version.
- */
-#define NVFBC_TOCUDA_SETUP_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_TOCUDA_SETUP_PARAMS, 1)
-
-/*!
- * Defines parameters for the ::NvFBCToCudaGrabFrame() API call.
- */
-typedef struct _NVFBC_TOCUDA_GRAB_FRAME_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_TOCUDA_GRAB_FRAME_PARAMS_VER.
- */
- uint32_t dwVersion;
- /*!
- * [in] Flags defining the behavior of this frame capture.
- */
- uint32_t dwFlags;
- /*!
- * [out] Pointer to a ::CUdeviceptr
- *
- * The application does not need to allocate memory for this CUDA device.
- *
- * The application does need to create its own CUDA context to use this
- * CUDA device.
- *
- * This ::CUdeviceptr will be mapped to a segment in video memory containing
- * the frame. It is not possible to process a CUDA device while capturing
- * a new frame. If the application wants to do so, it must copy the CUDA
- * device using ::cuMemcpyDtoD or ::cuMemcpyDtoH beforehand.
- */
- void *pCUDADeviceBuffer;
- /*!
- * [out] Information about the captured frame.
- *
- * Can be NULL.
- */
- NVFBC_FRAME_GRAB_INFO *pFrameGrabInfo;
- /*!
- * [in] Wait timeout in milliseconds.
- *
- * When capturing frames with the NVFBC_TOCUDA_GRAB_FLAGS_NOFLAGS or
- * NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY flags,
- * NvFBC will wait for a new frame or mouse move until the below timer
- * expires.
- *
- * When timing out, the last captured frame will be returned. Note that as
- * long as the NVFBC_TOCUDA_GRAB_FLAGS_FORCE_REFRESH flag is not set,
- * returning an old frame will incur no performance penalty.
- *
- * NvFBC clients can use the return value of the grab frame operation to
- * find out whether a new frame was captured, or the timer expired.
- *
- * Note that the behavior of blocking calls is to wait for a new frame
- * *after* the call has been made. When using timeouts, it is possible
- * that NvFBC will return a new frame (e.g., it has never been captured
- * before) even though no new frame was generated after the grab call.
- *
- * For the precise definition of what constitutes a new frame, see
- * ::bIsNewFrame.
- *
- * Set to 0 to disable timeouts.
- */
- uint32_t dwTimeoutMs;
-} NVFBC_TOCUDA_GRAB_FRAME_PARAMS;
-
-/*!
- * NVFBC_TOCUDA_GRAB_FRAME_PARAMS structure version.
- */
-#define NVFBC_TOCUDA_GRAB_FRAME_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_TOCUDA_GRAB_FRAME_PARAMS, 2)
-
-/*!
- * Defines flags that can be used when capturing to an OpenGL buffer in video memory.
- */
-typedef enum
-{
- /*!
- * Default, capturing waits for a new frame or mouse move.
- *
- * The default behavior of blocking grabs is to wait for a new frame until
- * after the call was made. But it's possible that there is a frame already
- * ready that the client hasn't seen.
- * \see NVFBC_TOGL_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY
- */
- NVFBC_TOGL_GRAB_FLAGS_NOFLAGS = 0,
- /*!
- * Capturing does not wait for a new frame nor a mouse move.
- *
- * It is therefore possible to capture the same frame multiple times.
- * When this occurs, the dwCurrentFrame parameter of the
- * NVFBC_FRAME_GRAB_INFO structure is not incremented.
- */
- NVFBC_TOGL_GRAB_FLAGS_NOWAIT = (1 << 0),
- /*!
- * [in] Forces the destination buffer to be refreshed even if the frame
- * has not changed since previous capture.
- *
- * By default, if the captured frame is identical to the previous one, NvFBC
- * will omit one copy and not update the destination buffer.
- *
- * Setting that flag will prevent this behavior. This can be useful e.g.,
- * if the application has modified the buffer in the meantime.
- */
- NVFBC_TOGL_GRAB_FLAGS_FORCE_REFRESH = (1 << 1),
- /*!
- * Similar to NVFBC_TOGL_GRAB_FLAGS_NOFLAGS, except that the capture will
- * not wait if there is already a frame available that the client has
- * never seen yet.
- */
- NVFBC_TOGL_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY = (1 << 2),
-} NVFBC_TOGL_FLAGS;
-
-/*!
- * Maximum number of GL textures that can be used to store frames.
- */
-#define NVFBC_TOGL_TEXTURES_MAX 2
-
-/*!
- * Defines parameters for the ::NvFBCToGLSetUp() API call.
- */
-typedef struct _NVFBC_TOGL_SETUP_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_TOGL_SETUP_PARAMS_VER
- */
- uint32_t dwVersion;
- /*!
- * [in] Desired buffer format.
- */
- NVFBC_BUFFER_FORMAT eBufferFormat;
- /*!
- * [in] Whether differential maps should be generated.
- */
- NVFBC_BOOL bWithDiffMap;
- /*!
- * [out] Pointer to a pointer to a buffer in system memory.
- *
- * \see NVFBC_TOSYS_SETUP_PARAMS::ppDiffMap
- */
- void **ppDiffMap;
- /*!
- * [in] Scaling factor of the differential maps.
- *
- * \see NVFBC_TOSYS_SETUP_PARAMS::dwDiffMapScalingFactor
- */
- uint32_t dwDiffMapScalingFactor;
- /*!
- * [out] List of GL textures that will store the captured frames.
- *
- * This array is 0 terminated. The number of textures varies depending on
- * the capture settings (such as whether diffmaps are enabled).
- *
- * An application wishing to interop with, for example, EncodeAPI will need
- * to register these textures prior to start encoding frames.
- *
- * After each frame capture, the texture holding the current frame will be
- * returned in NVFBC_TOGL_GRAB_FRAME_PARAMS::dwTexture.
- */
- uint32_t dwTextures[NVFBC_TOGL_TEXTURES_MAX];
- /*!
- * [out] GL target to which the texture should be bound.
- */
- uint32_t dwTexTarget;
- /*!
- * [out] GL format of the textures.
- */
- uint32_t dwTexFormat;
- /*!
- * [out] GL type of the textures.
- */
- uint32_t dwTexType;
- /*!
- * [out] Size of the differential map.
- *
- * Only set if bWithDiffMap is set to NVFBC_TRUE.
- */
- NVFBC_SIZE diffMapSize;
-} NVFBC_TOGL_SETUP_PARAMS;
-
-/*!
- * NVFBC_TOGL_SETUP_PARAMS structure version.
- */
-#define NVFBC_TOGL_SETUP_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_TOGL_SETUP_PARAMS, 2)
-
-/*!
- * Defines parameters for the ::NvFBCToGLGrabFrame() API call.
- */
-typedef struct _NVFBC_TOGL_GRAB_FRAME_PARAMS
-{
- /*!
- * [in] Must be set to NVFBC_TOGL_GRAB_FRAME_PARAMS_VER.
- */
- uint32_t dwVersion;
- /*!
- * [in] Flags defining the behavior of this frame capture.
- */
- uint32_t dwFlags;
- /*!
- * [out] Index of the texture storing the current frame.
- *
- * This is an index in the NVFBC_TOGL_SETUP_PARAMS::dwTextures array.
- */
- uint32_t dwTextureIndex;
- /*!
- * [out] Information about the captured frame.
- *
- * Can be NULL.
- */
- NVFBC_FRAME_GRAB_INFO *pFrameGrabInfo;
- /*!
- * [in] Wait timeout in milliseconds.
- *
- * When capturing frames with the NVFBC_TOGL_GRAB_FLAGS_NOFLAGS or
- * NVFBC_TOGL_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY flags,
- * NvFBC will wait for a new frame or mouse move until the below timer
- * expires.
- *
- * When timing out, the last captured frame will be returned. Note that as
- * long as the NVFBC_TOGL_GRAB_FLAGS_FORCE_REFRESH flag is not set,
- * returning an old frame will incur no performance penalty.
- *
- * NvFBC clients can use the return value of the grab frame operation to
- * find out whether a new frame was captured, or the timer expired.
- *
- * Note that the behavior of blocking calls is to wait for a new frame
- * *after* the call has been made. When using timeouts, it is possible
- * that NvFBC will return a new frame (e.g., it has never been captured
- * before) even though no new frame was generated after the grab call.
- *
- * For the precise definition of what constitutes a new frame, see
- * ::bIsNewFrame.
- *
- * Set to 0 to disable timeouts.
- */
- uint32_t dwTimeoutMs;
-} NVFBC_TOGL_GRAB_FRAME_PARAMS;
-
-/*!
- * NVFBC_TOGL_GRAB_FRAME_PARAMS structure version.
- */
-#define NVFBC_TOGL_GRAB_FRAME_PARAMS_VER NVFBC_STRUCT_VERSION(NVFBC_TOGL_GRAB_FRAME_PARAMS, 2)
-
-/*! @} FBC_STRUCT */
-
-/*!
- * \defgroup FBC_FUNC API Entry Points
- *
- * Entry points are thread-safe and can be called concurrently.
- *
- * The locking model includes a global lock that protects session handle
- * management (\see NvFBCCreateHandle, \see NvFBCDestroyHandle).
- *
- * Each NvFBC session uses a local lock to protect other entry points. Note
- * that in certain cases, a thread can hold the local lock for an undefined
- * amount of time, such as grabbing a frame using a blocking call.
- *
- * Note that a context is associated with each session. NvFBC clients wishing
- * to share a session between different threads are expected to release and
- * bind the context appropriately (\see NvFBCBindContext,
- * \see NvFBCReleaseContext). This is not required when each thread uses its
- * own NvFBC session.
- *
- * @{
- */
-
-/*!
- * Gets the last error message that got recorded for a client.
- *
- * When NvFBC returns an error, it will save an error message that can be
- * queried through this API call. Only the last message is saved.
- * The message and the return code should give enough information about
- * what went wrong.
- *
- * \param [in] sessionHandle
- * Handle to the NvFBC client.
- * \return
- * A NULL terminated error message, or an empty string. Its maximum length
- * is NVFBC_ERROR_STR_LEN.
- */
-const char* NVFBCAPI NvFBCGetLastErrorStr(const NVFBC_SESSION_HANDLE sessionHandle);
-
-/*!
- * \brief Allocates a new handle for an NvFBC client.
- *
- * This function allocates a session handle used to identify an FBC client.
- *
- * This function implicitly calls NvFBCBindContext().
- *
- * \param [out] pSessionHandle
- * Pointer that will hold the allocated session handle.
- * \param [in] pParams
- * ::NVFBC_CREATE_HANDLE_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_PTR \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_OUT_OF_MEMORY \n
- * ::NVFBC_ERR_MAX_CLIENTS \n
- * ::NVFBC_ERR_X \n
- * ::NVFBC_ERR_GLX \n
- * ::NVFBC_ERR_GL
- *
- */
-NVFBCSTATUS NVFBCAPI NvFBCCreateHandle(NVFBC_SESSION_HANDLE *pSessionHandle, NVFBC_CREATE_HANDLE_PARAMS *pParams);
-
-/*!
- * \brief Destroys the handle of an NvFBC client.
- *
- * This function uninitializes an FBC client.
- *
- * This function implicitly calls NvFBCReleaseContext().
- *
- * After this fucntion returns, it is not possible to use this session handle
- * for any further API call.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_DESTROY_HANDLE_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCDestroyHandle(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_HANDLE_PARAMS *pParams);
-
-/*!
- * \brief Gets the current status of the display driver.
- *
- * This function queries the display driver for various information.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_GET_STATUS_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCGetStatus(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_GET_STATUS_PARAMS *pParams);
-
-/*!
- * \brief Binds the FBC context to the calling thread.
- *
- * The NvFBC library internally relies on objects that must be bound to a
- * thread. Such objects are OpenGL contexts and CUDA contexts.
- *
- * This function binds these objects to the calling thread.
- *
- * The FBC context must be bound to the calling thread for most NvFBC entry
- * points, otherwise ::NVFBC_ERR_CONTEXT is returned.
- *
- * If the FBC context is already bound to a different thread,
- * ::NVFBC_ERR_CONTEXT is returned. The other thread must release the context
- * first by calling the ReleaseContext() entry point.
- *
- * If the FBC context is already bound to the current thread, this function has
- * no effects.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_DESTROY_CAPTURE_SESSION_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCBindContext(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_BIND_CONTEXT_PARAMS *pParams);
-
-/*!
- * \brief Releases the FBC context from the calling thread.
- *
- * If the FBC context is bound to a different thread, ::NVFBC_ERR_CONTEXT is
- * returned.
- *
- * If the FBC context is already released, this functino has no effects.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCReleaseContext(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_RELEASE_CONTEXT_PARAMS *pParams);
-
-/*!
- * \brief Creates a capture session for an FBC client.
- *
- * This function starts a capture session of the desired type (system memory,
- * video memory with CUDA interop, or H.264 compressed frames in system memory).
- *
- * Not all types are supported on all systems. Also, it is possible to use
- * NvFBC without having the CUDA library. In this case, requesting a capture
- * session of the concerned type will return an error.
- *
- * After this function returns, the display driver will start generating frames
- * that can be captured using the corresponding API call.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_CREATE_CAPTURE_SESSION_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INVALID_PARAM \n
- * ::NVFBC_ERR_OUT_OF_MEMORY \n
- * ::NVFBC_ERR_X \n
- * ::NVFBC_ERR_GLX \n
- * ::NVFBC_ERR_GL \n
- * ::NVFBC_ERR_CUDA \n
- * ::NVFBC_ERR_MUST_RECREATE \n
- * ::NVFBC_ERR_INTERNAL
- */
-NVFBCSTATUS NVFBCAPI NvFBCCreateCaptureSession(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_CREATE_CAPTURE_SESSION_PARAMS *pParams);
-
-/*!
- * \brief Destroys a capture session for an FBC client.
- *
- * This function stops a capture session and frees allocated objects.
- *
- * After this function returns, it is possible to create another capture
- * session using the corresponding API call.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_DESTROY_CAPTURE_SESSION_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCDestroyCaptureSession(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_CAPTURE_SESSION_PARAMS *pParams);
-
-/*!
- * \brief Sets up a capture to system memory session.
- *
- * This function configures how the capture to system memory should behave. It
- * can be called anytime and several times after the capture session has been
- * created. However, it must be called at least once prior to start capturing
- * frames.
- *
- * This function allocates the buffer that will contain the captured frame.
- * The application does not need to free this buffer. The size of this buffer
- * is returned in the ::NVFBC_FRAME_GRAB_INFO structure.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_TOSYS_SETUP_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_UNSUPPORTED \n
- * ::NVFBC_ERR_INVALID_PTR \n
- * ::NVFBC_ERR_INVALID_PARAM \n
- * ::NVFBC_ERR_OUT_OF_MEMORY \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCToSysSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_SETUP_PARAMS *pParams);
-
-/*!
- * \brief Captures a frame to a buffer in system memory.
- *
- * This function triggers a frame capture to a buffer in system memory that was
- * registered with the ToSysSetUp() API call.
- *
- * Note that it is possible that the resolution of the desktop changes while
- * capturing frames. This should be transparent for the application.
- *
- * When the resolution changes, the capture session is recreated using the same
- * parameters, and necessary buffers are re-allocated. The frame counter is not
- * reset.
- *
- * An application can detect that the resolution changed by comparing the
- * dwByteSize member of the ::NVFBC_FRAME_GRAB_INFO against a previous
- * frame and/or dwWidth and dwHeight.
- *
- * During a change of resolution the capture is paused even in asynchronous
- * mode.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- * \param [in] pParams
- * ::NVFBC_TOSYS_GRAB_FRAME_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INVALID_PTR \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X \n
- * ::NVFBC_ERR_MUST_RECREATE \n
- * \see NvFBCCreateCaptureSession \n
- * \see NvFBCToSysSetUp
- */
-NVFBCSTATUS NVFBCAPI NvFBCToSysGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_GRAB_FRAME_PARAMS *pParams);
-
-/*!
- * \brief Sets up a capture to video memory session.
- *
- * This function configures how the capture to video memory with CUDA interop
- * should behave. It can be called anytime and several times after the capture
- * session has been created. However, it must be called at least once prior
- * to start capturing frames.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- *
- * \param [in] pParams
- * ::NVFBC_TOCUDA_SETUP_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_UNSUPPORTED \n
- * ::NVFBC_ERR_GL \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCToCudaSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_SETUP_PARAMS *pParams);
-
-/*!
- * \brief Captures a frame to a CUDA device in video memory.
- *
- * This function triggers a frame capture to a CUDA device in video memory.
- *
- * Note about changes of resolution: \see NvFBCToSysGrabFrame
- *
- * \param [in] sessionHandle
- * FBC session handle.
- *
- * \param [in] pParams
- * ::NVFBC_TOCUDA_GRAB_FRAME_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INVALID_PTR \n
- * ::NVFBC_ERR_CUDA \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X \n
- * ::NVFBC_ERR_MUST_RECREATE \n
- * \see NvFBCCreateCaptureSession \n
- * \see NvFBCToCudaSetUp
- */
-NVFBCSTATUS NVFBCAPI NvFBCToCudaGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_GRAB_FRAME_PARAMS *pParams);
-
-/*!
- * \brief Sets up a capture to OpenGL buffer in video memory session.
- *
- * This function configures how the capture to video memory should behave.
- * It can be called anytime and several times after the capture session has been
- * created. However, it must be called at least once prior to start capturing
- * frames.
- *
- * \param [in] sessionHandle
- * FBC session handle.
- *
- * \param [in] pParams
- * ::NVFBC_TOGL_SETUP_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_UNSUPPORTED \n
- * ::NVFBC_ERR_GL \n
- * ::NVFBC_ERR_X
- */
-NVFBCSTATUS NVFBCAPI NvFBCToGLSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_SETUP_PARAMS *pParams);
-
-/*!
- * \brief Captures a frame to an OpenGL buffer in video memory.
- *
- * This function triggers a frame capture to a selected resource in video memory.
- *
- * Note about changes of resolution: \see NvFBCToSysGrabFrame
- *
- * \param [in] sessionHandle
- * FBC session handle.
- *
- * \param [in] pParams
- * ::NVFBC_TOGL_GRAB_FRAME_PARAMS
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_HANDLE \n
- * ::NVFBC_ERR_API_VERSION \n
- * ::NVFBC_ERR_BAD_REQUEST \n
- * ::NVFBC_ERR_CONTEXT \n
- * ::NVFBC_ERR_INVALID_PTR \n
- * ::NVFBC_ERR_INTERNAL \n
- * ::NVFBC_ERR_X \n
- * ::NVFBC_ERR_MUST_RECREATE \n
- * \see NvFBCCreateCaptureSession \n
- * \see NvFBCToCudaSetUp
- */
-NVFBCSTATUS NVFBCAPI NvFBCToGLGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_GRAB_FRAME_PARAMS *pParams);
-
-/*!
- * \cond FBC_PFN
- *
- * Defines API function pointers
- */
-typedef const char* (NVFBCAPI* PNVFBCGETLASTERRORSTR)(const NVFBC_SESSION_HANDLE sessionHandle);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCCREATEHANDLE)(NVFBC_SESSION_HANDLE *pSessionHandle, NVFBC_CREATE_HANDLE_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCDESTROYHANDLE)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_HANDLE_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCBINDCONTEXT)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_BIND_CONTEXT_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCRELEASECONTEXT)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_RELEASE_CONTEXT_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCGETSTATUS)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_GET_STATUS_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCCREATECAPTURESESSION)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_CREATE_CAPTURE_SESSION_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCDESTROYCAPTURESESSION)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_CAPTURE_SESSION_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCTOSYSSETUP)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_SETUP_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCTOSYSGRABFRAME)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_GRAB_FRAME_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCTOCUDASETUP)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_SETUP_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCTOCUDAGRABFRAME)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_GRAB_FRAME_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCTOGLSETUP)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_SETUP_PARAMS *pParams);
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCTOGLGRABFRAME)(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_GRAB_FRAME_PARAMS *pParams);
-
-/// \endcond
-
-/*! @} FBC_FUNC */
-
-/*!
- * \ingroup FBC_STRUCT
- *
- * Structure populated with API function pointers.
- */
-typedef struct
-{
- uint32_t dwVersion; //!< [in] Must be set to NVFBC_VERSION.
- PNVFBCGETLASTERRORSTR nvFBCGetLastErrorStr; //!< [out] Pointer to ::NvFBCGetLastErrorStr().
- PNVFBCCREATEHANDLE nvFBCCreateHandle; //!< [out] Pointer to ::NvFBCCreateHandle().
- PNVFBCDESTROYHANDLE nvFBCDestroyHandle; //!< [out] Pointer to ::NvFBCDestroyHandle().
- PNVFBCGETSTATUS nvFBCGetStatus; //!< [out] Pointer to ::NvFBCGetStatus().
- PNVFBCCREATECAPTURESESSION nvFBCCreateCaptureSession; //!< [out] Pointer to ::NvFBCCreateCaptureSession().
- PNVFBCDESTROYCAPTURESESSION nvFBCDestroyCaptureSession; //!< [out] Pointer to ::NvFBCDestroyCaptureSession().
- PNVFBCTOSYSSETUP nvFBCToSysSetUp; //!< [out] Pointer to ::NvFBCToSysSetUp().
- PNVFBCTOSYSGRABFRAME nvFBCToSysGrabFrame; //!< [out] Pointer to ::NvFBCToSysGrabFrame().
- PNVFBCTOCUDASETUP nvFBCToCudaSetUp; //!< [out] Pointer to ::NvFBCToCudaSetUp().
- PNVFBCTOCUDAGRABFRAME nvFBCToCudaGrabFrame; //!< [out] Pointer to ::NvFBCToCudaGrabFrame().
- void* pad1; //!< [out] Retired. Do not use.
- void* pad2; //!< [out] Retired. Do not use.
- void* pad3; //!< [out] Retired. Do not use.
- PNVFBCBINDCONTEXT nvFBCBindContext; //!< [out] Pointer to ::NvFBCBindContext().
- PNVFBCRELEASECONTEXT nvFBCReleaseContext; //!< [out] Pointer to ::NvFBCReleaseContext().
- void* pad4; //!< [out] Retired. Do not use.
- void* pad5; //!< [out] Retired. Do not use.
- void* pad6; //!< [out] Retired. Do not use.
- void* pad7; //!< [out] Retired. Do not use.
- PNVFBCTOGLSETUP nvFBCToGLSetUp; //!< [out] Pointer to ::nvFBCToGLSetup().
- PNVFBCTOGLGRABFRAME nvFBCToGLGrabFrame; //!< [out] Pointer to ::nvFBCToGLGrabFrame().
-} NVFBC_API_FUNCTION_LIST;
-
-/*!
- * \ingroup FBC_FUNC
- *
- * \brief Entry Points to the NvFBC interface.
- *
- * Creates an instance of the NvFBC interface, and populates the
- * pFunctionList with function pointers to the API routines implemented by
- * the NvFBC interface.
- *
- * \param [out] pFunctionList
- *
- * \return
- * ::NVFBC_SUCCESS \n
- * ::NVFBC_ERR_INVALID_PTR \n
- * ::NVFBC_ERR_API_VERSION
- */
-NVFBCSTATUS NVFBCAPI NvFBCCreateInstance(NVFBC_API_FUNCTION_LIST *pFunctionList);
-/*!
- * \ingroup FBC_FUNC
- *
- * Defines function pointer for the ::NvFBCCreateInstance() API call.
- */
-typedef NVFBCSTATUS (NVFBCAPI* PNVFBCCREATEINSTANCE)(NVFBC_API_FUNCTION_LIST *pFunctionList);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _NVFBC_H_
diff --git a/include/NvFBCLibrary.hpp b/include/NvFBCLibrary.hpp
deleted file mode 100644
index 6d115a4..0000000
--- a/include/NvFBCLibrary.hpp
+++ /dev/null
@@ -1,246 +0,0 @@
-#pragma once
-
-#include "NvFBC.h"
-#include <cuda.h>
-
-#include <dlfcn.h>
-#include <string.h>
-#include <stdio.h>
-
-class NvFBCLibrary {
-public:
- ~NvFBCLibrary() {
- if(fbc_handle_created) {
- 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;
- nv_fbc_function_list.nvFBCDestroyCaptureSession(nv_fbc_handle, &destroy_capture_params);
-
- NVFBC_DESTROY_HANDLE_PARAMS destroy_params;
- memset(&destroy_params, 0, sizeof(destroy_params));
- destroy_params.dwVersion = NVFBC_DESTROY_HANDLE_PARAMS_VER;
- nv_fbc_function_list.nvFBCDestroyHandle(nv_fbc_handle, &destroy_params);
- }
-
- if(library)
- dlclose(library);
- }
-
- bool load() {
- if(library)
- return true;
-
- dlerror(); // clear
- void *lib = dlopen("libnvidia-fbc.so.1", RTLD_NOW);
- if(!lib) {
- fprintf(stderr, "Error: failed to load libnvidia-fbc.so.1, error: %s\n", dlerror());
- return false;
- }
-
- nv_fbc_create_instance = (PNVFBCCREATEINSTANCE)dlsym(lib, "NvFBCCreateInstance");
- if(!nv_fbc_create_instance) {
- fprintf(stderr, "Error: unable to resolve symbol 'NvFBCCreateInstance'\n");
- dlclose(lib);
- return false;
- }
-
- memset(&nv_fbc_function_list, 0, sizeof(nv_fbc_function_list));
- nv_fbc_function_list.dwVersion = NVFBC_VERSION;
- NVFBCSTATUS status = nv_fbc_create_instance(&nv_fbc_function_list);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: failed to create NvFBC instance (status: %d)\n", status);
- dlclose(lib);
- return false;
- }
-
- library = lib;
- return true;
- }
-
- // If |display_to_capture| is "screen", then the entire x11 screen is captured (all displays)
- bool create(const char *display_to_capture, uint32_t fps, /*out*/ uint32_t *display_width, /*out*/ uint32_t *display_height, uint32_t x = 0, uint32_t y = 0, uint32_t width = 0, uint32_t height = 0, bool direct_capture = false) {
- if(!library || !display_to_capture || !display_width || !display_height || fbc_handle_created)
- return false;
-
- const bool capture_region = (x > 0 || y > 0 || width > 0 || height > 0);
-
- NVFBCSTATUS status;
- NVFBC_TRACKING_TYPE tracking_type;
- bool capture_session_created = false;
- uint32_t output_id = 0;
- fbc_handle_created = false;
-
- NVFBC_CREATE_HANDLE_PARAMS create_params;
- memset(&create_params, 0, sizeof(create_params));
- create_params.dwVersion = NVFBC_CREATE_HANDLE_PARAMS_VER;
-
- status = nv_fbc_function_list.nvFBCCreateHandle(&nv_fbc_handle, &create_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- return false;
- }
- fbc_handle_created = true;
-
- NVFBC_GET_STATUS_PARAMS status_params;
- memset(&status_params, 0, sizeof(status_params));
- status_params.dwVersion = NVFBC_GET_STATUS_PARAMS_VER;
-
- status = nv_fbc_function_list.nvFBCGetStatus(nv_fbc_handle, &status_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- goto error_cleanup;
- }
-
- if(status_params.bCanCreateNow == NVFBC_FALSE) {
- fprintf(stderr, "Error: it's not possible to create a capture session on this system\n");
- goto error_cleanup;
- }
-
- tracking_type = strcmp(display_to_capture, "screen") == 0 ? NVFBC_TRACKING_SCREEN : NVFBC_TRACKING_OUTPUT;
- if(tracking_type == NVFBC_TRACKING_OUTPUT) {
- if(!status_params.bXRandRAvailable) {
- fprintf(stderr, "Error: the xrandr extension is not available\n");
- goto error_cleanup;
- }
-
- if(status_params.bInModeset) {
- fprintf(stderr, "Error: the x server is in modeset, unable to record\n");
- goto error_cleanup;
- }
-
- output_id = get_output_id_from_display_name(status_params.outputs, status_params.dwOutputNum, display_to_capture, display_width, display_height);
- if(output_id == 0) {
- fprintf(stderr, "Error: display '%s' not found\n", display_to_capture);
- goto error_cleanup;
- }
- } else {
- *display_width = status_params.screenSize.w;
- *display_height = status_params.screenSize.h;
- }
-
- NVFBC_CREATE_CAPTURE_SESSION_PARAMS create_capture_params;
- memset(&create_capture_params, 0, sizeof(create_capture_params));
- create_capture_params.dwVersion = NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER;
- create_capture_params.eCaptureType = NVFBC_CAPTURE_SHARED_CUDA;
- create_capture_params.bWithCursor = direct_capture ? NVFBC_FALSE : NVFBC_TRUE;
- if(capture_region) {
- create_capture_params.captureBox = { x, y, width, height };
- *display_width = width;
- *display_height = height;
- }
- create_capture_params.eTrackingType = tracking_type;
- create_capture_params.dwSamplingRateMs = 1000 / fps;
- create_capture_params.bAllowDirectCapture = direct_capture ? NVFBC_TRUE : NVFBC_FALSE;
- create_capture_params.bPushModel = direct_capture ? NVFBC_TRUE : NVFBC_FALSE;
- if(tracking_type == NVFBC_TRACKING_OUTPUT)
- create_capture_params.dwOutputId = output_id;
-
- status = nv_fbc_function_list.nvFBCCreateCaptureSession(nv_fbc_handle, &create_capture_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- goto error_cleanup;
- }
- capture_session_created = true;
-
- NVFBC_TOCUDA_SETUP_PARAMS setup_params;
- memset(&setup_params, 0, sizeof(setup_params));
- setup_params.dwVersion = NVFBC_TOCUDA_SETUP_PARAMS_VER;
- setup_params.eBufferFormat = NVFBC_BUFFER_FORMAT_BGRA;
-
- status = nv_fbc_function_list.nvFBCToCudaSetUp(nv_fbc_handle, &setup_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- goto error_cleanup;
- }
-
- return true;
-
- error_cleanup:
- if(fbc_handle_created) {
- if(capture_session_created) {
- 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;
- nv_fbc_function_list.nvFBCDestroyCaptureSession(nv_fbc_handle, &destroy_capture_params);
- }
-
- NVFBC_DESTROY_HANDLE_PARAMS destroy_params;
- memset(&destroy_params, 0, sizeof(destroy_params));
- destroy_params.dwVersion = NVFBC_DESTROY_HANDLE_PARAMS_VER;
- nv_fbc_function_list.nvFBCDestroyHandle(nv_fbc_handle, &destroy_params);
- fbc_handle_created = false;
- }
- output_id = 0;
- return false;
- }
-
- bool capture(/*out*/ CUdeviceptr *cu_device_ptr, uint32_t *byte_size) {
- if(!library || !fbc_handle_created || !cu_device_ptr || !byte_size)
- return false;
-
- NVFBCSTATUS status;
- NVFBC_FRAME_GRAB_INFO frame_info;
- memset(&frame_info, 0, sizeof(frame_info));
-
- NVFBC_TOCUDA_GRAB_FRAME_PARAMS grab_params;
- memset(&grab_params, 0, sizeof(grab_params));
- grab_params.dwVersion = NVFBC_TOCUDA_GRAB_FRAME_PARAMS_VER;
- grab_params.dwFlags = NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT;
- grab_params.pFrameGrabInfo = &frame_info;
- grab_params.pCUDADeviceBuffer = cu_device_ptr;
-
- status = nv_fbc_function_list.nvFBCToCudaGrabFrame(nv_fbc_handle, &grab_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- return false;
- }
-
- *byte_size = frame_info.dwByteSize;
- // TODO: Check bIsNewFrame
- // TODO: Check dwWidth and dwHeight and update size in video output in ffmpeg. This can happen when xrandr is used to change monitor resolution
-
- return true;
- }
-private:
- static char to_upper(char c) {
- if(c >= 'a' && c <= 'z')
- return c - 32;
- else
- return c;
- }
-
- static bool strcase_equals(const char *str1, const char *str2) {
- for(;;) {
- char c1 = to_upper(*str1);
- char c2 = to_upper(*str2);
- if(c1 != c2)
- return false;
- if(c1 == '\0' || c2 == '\0')
- return true;
- ++str1;
- ++str2;
- }
- }
-
- // Returns 0 on failure
- uint32_t get_output_id_from_display_name(NVFBC_RANDR_OUTPUT_INFO *outputs, uint32_t num_outputs, const char *display_name, uint32_t *display_width, uint32_t *display_height) {
- if(!outputs)
- return 0;
-
- for(uint32_t i = 0; i < num_outputs; ++i) {
- if(strcase_equals(outputs[i].name, display_name)) {
- *display_width = outputs[i].trackedBox.w;
- *display_height = outputs[i].trackedBox.h;
- return outputs[i].dwId;
- }
- }
-
- return 0;
- }
-private:
- void *library = nullptr;
- PNVFBCCREATEINSTANCE nv_fbc_create_instance = nullptr;
- NVFBC_API_FUNCTION_LIST nv_fbc_function_list;
- NVFBC_SESSION_HANDLE nv_fbc_handle;
- bool fbc_handle_created = false;
-}; \ No newline at end of file
diff --git a/include/args_parser.h b/include/args_parser.h
new file mode 100644
index 0000000..e2fa46e
--- /dev/null
+++ b/include/args_parser.h
@@ -0,0 +1,106 @@
+#ifndef GSR_ARGS_PARSER_H
+#define GSR_ARGS_PARSER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "defs.h"
+#include "vec2.h"
+
+typedef struct gsr_egl gsr_egl;
+
+#define NUM_ARGS 30
+
+typedef enum {
+ ARG_TYPE_STRING,
+ ARG_TYPE_BOOLEAN,
+ ARG_TYPE_ENUM,
+ ARG_TYPE_I64,
+ ARG_TYPE_DOUBLE,
+} ArgType;
+
+typedef struct {
+ const char *name;
+ int value;
+} ArgEnum;
+
+typedef struct {
+ ArgType type;
+ const char **values;
+ int capacity_num_values;
+ int num_values;
+
+ const char *key;
+ bool optional;
+ bool list;
+
+ const ArgEnum *enum_values;
+ int num_enum_values;
+
+ int64_t integer_value_min;
+ int64_t integer_value_max;
+
+ union {
+ bool boolean;
+ int enum_value;
+ int64_t i64_value;
+ double d_value;
+ } typed_value;
+} Arg;
+
+typedef struct {
+ void (*version)(void *userdata);
+ void (*info)(void *userdata);
+ void (*list_audio_devices)(void *userdata);
+ void (*list_application_audio)(void *userdata);
+ void (*list_capture_options)(const char *card_path, void *userdata);
+} args_handlers;
+
+typedef struct {
+ Arg args[NUM_ARGS];
+
+ gsr_video_encoder_hardware video_encoder;
+ gsr_pixel_format pixel_format;
+ gsr_framerate_mode framerate_mode;
+ gsr_color_range color_range;
+ gsr_tune tune;
+ gsr_video_codec video_codec;
+ gsr_audio_codec audio_codec;
+ gsr_bitrate_mode bitrate_mode;
+ gsr_video_quality video_quality;
+ gsr_replay_storage replay_storage;
+ char window[64];
+ const char *container_format;
+ const char *filename;
+ const char *replay_recording_directory;
+ const char *portal_session_token_filepath;
+ const char *recording_saved_script;
+ bool verbose;
+ bool gl_debug;
+ bool record_cursor;
+ bool date_folders;
+ bool restore_portal_session;
+ bool restart_replay_on_save;
+ bool overclock;
+ bool is_livestream;
+ bool is_output_piped;
+ bool low_latency_recording;
+ bool very_old_gpu;
+ int64_t video_bitrate;
+ int64_t audio_bitrate;
+ int64_t fps;
+ int64_t replay_buffer_size_secs;
+ double keyint;
+ vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
+} args_parser;
+
+/* |argv| is stored as a reference */
+bool args_parser_parse(args_parser *self, int argc, char **argv, const args_handlers *args_handlers, void *userdata);
+void args_parser_deinit(args_parser *self);
+
+bool args_parser_validate_with_gl_info(args_parser *self, gsr_egl *egl);
+void args_parser_print_usage(void);
+Arg* args_parser_get_arg(args_parser *self, const char *arg_name);
+
+#endif /* GSR_ARGS_PARSER_H */
diff --git a/include/capture/capture.h b/include/capture/capture.h
new file mode 100644
index 0000000..c2128c5
--- /dev/null
+++ b/include/capture/capture.h
@@ -0,0 +1,52 @@
+#ifndef GSR_CAPTURE_CAPTURE_H
+#define GSR_CAPTURE_CAPTURE_H
+
+#include "../color_conversion.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVStream AVStream;
+typedef struct AVFrame AVFrame;
+typedef struct AVMasteringDisplayMetadata AVMasteringDisplayMetadata;
+typedef struct AVContentLightMetadata AVContentLightMetadata;
+typedef struct gsr_capture gsr_capture;
+
+typedef struct {
+ int width;
+ int height;
+ int fps;
+ AVCodecContext *video_codec_context; /* can be NULL */
+ AVFrame *frame; /* can be NULL, but will never be NULL if |video_codec_context| is set */
+} gsr_capture_metadata;
+
+struct gsr_capture {
+ /* These methods should not be called manually. Call gsr_capture_* instead. |capture_metdata->width| and |capture_metadata->height| should be set by this function */
+ int (*start)(gsr_capture *cap, gsr_capture_metadata *capture_metadata);
+ void (*on_event)(gsr_capture *cap, gsr_egl *egl); /* can be NULL */
+ void (*tick)(gsr_capture *cap); /* can be NULL. If there is an event then |on_event| is called before this */
+ bool (*should_stop)(gsr_capture *cap, bool *err); /* can be NULL. If NULL, return false */
+ bool (*capture_has_synchronous_task)(gsr_capture *cap); /* can be NULL. If this returns true then the time spent in |capture| is ignored for video/audio (capture is paused while the synchronous task happens) */
+ int (*capture)(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion); /* Return 0 if the frame was captured */
+ bool (*uses_external_image)(gsr_capture *cap); /* can be NULL. If NULL, return false */
+ bool (*set_hdr_metadata)(gsr_capture *cap, AVMasteringDisplayMetadata *mastering_display_metadata, AVContentLightMetadata *light_metadata); /* can be NULL. If NULL, return false */
+ uint64_t (*get_window_id)(gsr_capture *cap); /* can be NULL. Returns 0 if unknown */
+ bool (*is_damaged)(gsr_capture *cap); /* can be NULL */
+ void (*clear_damage)(gsr_capture *cap); /* can be NULL */
+ void (*destroy)(gsr_capture *cap);
+
+ void *priv; /* can be NULL */
+ bool started;
+};
+
+int gsr_capture_start(gsr_capture *cap, gsr_capture_metadata *capture_metadata);
+void gsr_capture_on_event(gsr_capture *cap, gsr_egl *egl);
+void gsr_capture_tick(gsr_capture *cap);
+bool gsr_capture_should_stop(gsr_capture *cap, bool *err);
+int gsr_capture_capture(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion);
+bool gsr_capture_uses_external_image(gsr_capture *cap);
+bool gsr_capture_set_hdr_metadata(gsr_capture *cap, AVMasteringDisplayMetadata *mastering_display_metadata, AVContentLightMetadata *light_metadata);
+void gsr_capture_destroy(gsr_capture *cap);
+
+#endif /* GSR_CAPTURE_CAPTURE_H */
diff --git a/include/capture/kms.h b/include/capture/kms.h
new file mode 100644
index 0000000..ce09817
--- /dev/null
+++ b/include/capture/kms.h
@@ -0,0 +1,19 @@
+#ifndef GSR_CAPTURE_KMS_H
+#define GSR_CAPTURE_KMS_H
+
+#include "capture.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* A copy is made of this */
+ bool hdr;
+ bool record_cursor;
+ int fps;
+ vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
+} gsr_capture_kms_params;
+
+gsr_capture* gsr_capture_kms_create(const gsr_capture_kms_params *params);
+
+#endif /* GSR_CAPTURE_KMS_H */
diff --git a/include/capture/nvfbc.h b/include/capture/nvfbc.h
new file mode 100644
index 0000000..7e30d01
--- /dev/null
+++ b/include/capture/nvfbc.h
@@ -0,0 +1,20 @@
+#ifndef GSR_CAPTURE_NVFBC_H
+#define GSR_CAPTURE_NVFBC_H
+
+#include "capture.h"
+#include "../vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */
+ int fps;
+ bool direct_capture;
+ bool record_cursor;
+ vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
+} gsr_capture_nvfbc_params;
+
+gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params);
+
+#endif /* GSR_CAPTURE_NVFBC_H */
diff --git a/include/capture/portal.h b/include/capture/portal.h
new file mode 100644
index 0000000..74cdba9
--- /dev/null
+++ b/include/capture/portal.h
@@ -0,0 +1,17 @@
+#ifndef GSR_CAPTURE_PORTAL_H
+#define GSR_CAPTURE_PORTAL_H
+
+#include "capture.h"
+
+typedef struct {
+ gsr_egl *egl;
+ bool record_cursor;
+ bool restore_portal_session;
+ /* If this is set to NULL then this defaults to $XDG_CONFIG_HOME/gpu-screen-recorder/restore_token ($XDG_CONFIG_HOME defaults to $HOME/.config) */
+ const char *portal_session_token_filepath;
+ vec2i output_resolution;
+} gsr_capture_portal_params;
+
+gsr_capture* gsr_capture_portal_create(const gsr_capture_portal_params *params);
+
+#endif /* GSR_CAPTURE_PORTAL_H */
diff --git a/include/capture/xcomposite.h b/include/capture/xcomposite.h
new file mode 100644
index 0000000..bf6532e
--- /dev/null
+++ b/include/capture/xcomposite.h
@@ -0,0 +1,17 @@
+#ifndef GSR_CAPTURE_XCOMPOSITE_H
+#define GSR_CAPTURE_XCOMPOSITE_H
+
+#include "capture.h"
+#include "../vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ unsigned long window;
+ bool follow_focused; /* If this is set then |window| is ignored */
+ bool record_cursor;
+ vec2i output_resolution;
+} gsr_capture_xcomposite_params;
+
+gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params *params);
+
+#endif /* GSR_CAPTURE_XCOMPOSITE_H */
diff --git a/include/capture/ximage.h b/include/capture/ximage.h
new file mode 100644
index 0000000..e6c3607
--- /dev/null
+++ b/include/capture/ximage.h
@@ -0,0 +1,18 @@
+#ifndef GSR_CAPTURE_XIMAGE_H
+#define GSR_CAPTURE_XIMAGE_H
+
+#include "capture.h"
+#include "../vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* A copy is made of this */
+ bool record_cursor;
+ vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
+} gsr_capture_ximage_params;
+
+gsr_capture* gsr_capture_ximage_create(const gsr_capture_ximage_params *params);
+
+#endif /* GSR_CAPTURE_XIMAGE_H */
diff --git a/include/codec_query/codec_query.h b/include/codec_query/codec_query.h
new file mode 100644
index 0000000..316217d
--- /dev/null
+++ b/include/codec_query/codec_query.h
@@ -0,0 +1,23 @@
+#ifndef GSR_CODEC_QUERY_H
+#define GSR_CODEC_QUERY_H
+
+#include <stdbool.h>
+
+typedef struct {
+ bool supported;
+ bool low_power;
+} gsr_supported_video_codec;
+
+typedef struct {
+ gsr_supported_video_codec h264;
+ gsr_supported_video_codec hevc;
+ gsr_supported_video_codec hevc_hdr;
+ gsr_supported_video_codec hevc_10bit;
+ gsr_supported_video_codec av1;
+ gsr_supported_video_codec av1_hdr;
+ gsr_supported_video_codec av1_10bit;
+ gsr_supported_video_codec vp8;
+ gsr_supported_video_codec vp9;
+} gsr_supported_video_codecs;
+
+#endif /* GSR_CODEC_QUERY_H */
diff --git a/include/codec_query/nvenc.h b/include/codec_query/nvenc.h
new file mode 100644
index 0000000..c01acf6
--- /dev/null
+++ b/include/codec_query/nvenc.h
@@ -0,0 +1,8 @@
+#ifndef GSR_CODEC_QUERY_NVENC_H
+#define GSR_CODEC_QUERY_NVENC_H
+
+#include "codec_query.h"
+
+bool gsr_get_supported_video_codecs_nvenc(gsr_supported_video_codecs *video_codecs, bool cleanup);
+
+#endif /* GSR_CODEC_QUERY_NVENC_H */
diff --git a/include/codec_query/vaapi.h b/include/codec_query/vaapi.h
new file mode 100644
index 0000000..60bdeca
--- /dev/null
+++ b/include/codec_query/vaapi.h
@@ -0,0 +1,8 @@
+#ifndef GSR_CODEC_QUERY_VAAPI_H
+#define GSR_CODEC_QUERY_VAAPI_H
+
+#include "codec_query.h"
+
+bool gsr_get_supported_video_codecs_vaapi(gsr_supported_video_codecs *video_codecs, const char *card_path, bool cleanup);
+
+#endif /* GSR_CODEC_QUERY_VAAPI_H */
diff --git a/include/codec_query/vulkan.h b/include/codec_query/vulkan.h
new file mode 100644
index 0000000..bb06c6b
--- /dev/null
+++ b/include/codec_query/vulkan.h
@@ -0,0 +1,8 @@
+#ifndef GSR_CODEC_QUERY_VULKAN_H
+#define GSR_CODEC_QUERY_VULKAN_H
+
+#include "codec_query.h"
+
+bool gsr_get_supported_video_codecs_vulkan(gsr_supported_video_codecs *video_codecs, const char *card_path, bool cleanup);
+
+#endif /* GSR_CODEC_QUERY_VULKAN_H */
diff --git a/include/color_conversion.h b/include/color_conversion.h
new file mode 100644
index 0000000..cb074a1
--- /dev/null
+++ b/include/color_conversion.h
@@ -0,0 +1,85 @@
+#ifndef GSR_COLOR_CONVERSION_H
+#define GSR_COLOR_CONVERSION_H
+
+#include "shader.h"
+#include "defs.h"
+#include "vec2.h"
+#include <stdbool.h>
+
+#define GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS 12
+#define GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS 6
+#define GSR_COLOR_CONVERSION_MAX_FRAMEBUFFERS 2
+
+typedef enum {
+ GSR_SOURCE_COLOR_RGB,
+ GSR_SOURCE_COLOR_BGR
+} gsr_source_color;
+
+typedef enum {
+ GSR_DESTINATION_COLOR_NV12, /* YUV420, BT709, 8-bit */
+ GSR_DESTINATION_COLOR_P010, /* YUV420, BT2020, 10-bit */
+ GSR_DESTINATION_COLOR_RGB8
+} gsr_destination_color;
+
+typedef enum {
+ GSR_ROT_0,
+ GSR_ROT_90,
+ GSR_ROT_180,
+ GSR_ROT_270
+} gsr_rotation;
+
+typedef struct {
+ int rotation_matrix;
+ int offset;
+} gsr_color_graphics_uniforms;
+
+typedef struct {
+ int rotation_matrix;
+ int source_position;
+ int target_position;
+ int scale;
+} gsr_color_compute_uniforms;
+
+typedef struct {
+ gsr_egl *egl;
+
+ gsr_destination_color destination_color;
+
+ unsigned int destination_textures[2];
+ int num_destination_textures;
+
+ gsr_color_range color_range;
+ bool load_external_image_shader;
+ bool force_graphics_shader;
+} gsr_color_conversion_params;
+
+typedef struct {
+ gsr_color_conversion_params params;
+ gsr_color_compute_uniforms compute_uniforms[GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS];
+ gsr_shader compute_shaders[GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS];
+
+ /* These are only loader if compute shaders (of the same type) fail to load */
+ gsr_color_graphics_uniforms graphics_uniforms[GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS];
+ gsr_shader graphics_shaders[GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS];
+
+ bool compute_shaders_failed_to_load;
+ bool external_compute_shaders_failed_to_load;
+
+ unsigned int framebuffers[GSR_COLOR_CONVERSION_MAX_FRAMEBUFFERS];
+
+ unsigned int vertex_array_object_id;
+ unsigned int vertex_buffer_object_id;
+
+ int max_local_size_dim;
+} gsr_color_conversion;
+
+int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params);
+void gsr_color_conversion_deinit(gsr_color_conversion *self);
+
+void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i destination_pos, vec2i destination_size, vec2i source_pos, vec2i source_size, vec2i texture_size, gsr_rotation rotation, gsr_source_color source_color, bool external_texture, bool alpha_blending);
+void gsr_color_conversion_clear(gsr_color_conversion *self);
+void gsr_color_conversion_read_destination_texture(gsr_color_conversion *self, int destination_texture_index, int x, int y, int width, int height, unsigned int color_format, unsigned int data_format, void *pixels);
+
+gsr_rotation gsr_monitor_rotation_to_rotation(gsr_monitor_rotation monitor_rotation);
+
+#endif /* GSR_COLOR_CONVERSION_H */
diff --git a/include/cuda.h b/include/cuda.h
new file mode 100644
index 0000000..fd1f9f9
--- /dev/null
+++ b/include/cuda.h
@@ -0,0 +1,108 @@
+#ifndef GSR_CUDA_H
+#define GSR_CUDA_H
+
+#include "overclock.h"
+#include <stddef.h>
+#include <stdbool.h>
+
+// To prevent hwcontext_cuda.h from including cuda.h
+#define CUDA_VERSION 11070
+
+#define CU_CTX_SCHED_AUTO 0
+
+#if defined(_WIN64) || defined(__LP64__)
+typedef unsigned long long CUdeviceptr_v2;
+#else
+typedef unsigned int CUdeviceptr_v2;
+#endif
+typedef CUdeviceptr_v2 CUdeviceptr;
+
+typedef int CUresult;
+typedef int CUdevice_v1;
+typedef CUdevice_v1 CUdevice;
+typedef struct CUctx_st *CUcontext;
+typedef struct CUstream_st *CUstream;
+typedef struct CUarray_st *CUarray;
+
+#define CUDA_SUCCESS 0
+
+typedef enum CUgraphicsMapResourceFlags_enum {
+ CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE = 0x00,
+ CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY = 0x01,
+ CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD = 0x02
+} CUgraphicsMapResourceFlags;
+
+typedef enum CUgraphicsRegisterFlags_enum {
+ CU_GRAPHICS_REGISTER_FLAGS_NONE = 0x00,
+ CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY = 0x01,
+ CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 0x02,
+ CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST = 0x04,
+ CU_GRAPHICS_REGISTER_FLAGS_TEXTURE_GATHER = 0x08
+} CUgraphicsRegisterFlags;
+
+typedef enum CUmemorytype_enum {
+ CU_MEMORYTYPE_HOST = 0x01, /**< Host memory */
+ CU_MEMORYTYPE_DEVICE = 0x02, /**< Device memory */
+ CU_MEMORYTYPE_ARRAY = 0x03, /**< Array memory */
+ CU_MEMORYTYPE_UNIFIED = 0x04 /**< Unified device or host memory */
+} CUmemorytype;
+
+typedef struct CUDA_MEMCPY2D_st {
+ size_t srcXInBytes; /**< Source X in bytes */
+ size_t srcY; /**< Source Y */
+
+ CUmemorytype srcMemoryType; /**< Source memory type (host, device, array) */
+ const void *srcHost; /**< Source host pointer */
+ CUdeviceptr srcDevice; /**< Source device pointer */
+ CUarray srcArray; /**< Source array reference */
+ size_t srcPitch; /**< Source pitch (ignored when src is array) */
+
+ size_t dstXInBytes; /**< Destination X in bytes */
+ size_t dstY; /**< Destination Y */
+
+ CUmemorytype dstMemoryType; /**< Destination memory type (host, device, array) */
+ void *dstHost; /**< Destination host pointer */
+ CUdeviceptr dstDevice; /**< Destination device pointer */
+ CUarray dstArray; /**< Destination array reference */
+ size_t dstPitch; /**< Destination pitch (ignored when dst is array) */
+
+ size_t WidthInBytes; /**< Width of 2D memory copy in bytes */
+ size_t Height; /**< Height of 2D memory copy */
+} CUDA_MEMCPY2D_v2;
+typedef CUDA_MEMCPY2D_v2 CUDA_MEMCPY2D;
+
+typedef struct CUgraphicsResource_st *CUgraphicsResource;
+
+typedef struct gsr_cuda gsr_cuda;
+struct gsr_cuda {
+ gsr_overclock overclock;
+ bool do_overclock;
+
+ void *library;
+ CUcontext cu_ctx;
+
+ CUresult (*cuInit)(unsigned int Flags);
+ CUresult (*cuDeviceGetCount)(int *count);
+ CUresult (*cuDeviceGet)(CUdevice *device, int ordinal);
+ CUresult (*cuCtxCreate_v2)(CUcontext *pctx, unsigned int flags, CUdevice dev);
+ CUresult (*cuCtxDestroy_v2)(CUcontext ctx);
+ CUresult (*cuCtxPushCurrent_v2)(CUcontext ctx);
+ CUresult (*cuCtxPopCurrent_v2)(CUcontext *pctx);
+ CUresult (*cuGetErrorString)(CUresult error, const char **pStr);
+ CUresult (*cuMemcpy2D_v2)(const CUDA_MEMCPY2D *pCopy);
+ CUresult (*cuMemcpy2DAsync_v2)(const CUDA_MEMCPY2D *pcopy, CUstream hStream);
+ CUresult (*cuStreamSynchronize)(CUstream hStream);
+
+ CUresult (*cuGraphicsGLRegisterImage)(CUgraphicsResource *pCudaResource, unsigned int image, unsigned int target, unsigned int flags);
+ CUresult (*cuGraphicsEGLRegisterImage)(CUgraphicsResource *pCudaResource, void *image, unsigned int flags);
+ CUresult (*cuGraphicsResourceSetMapFlags)(CUgraphicsResource resource, unsigned int flags);
+ CUresult (*cuGraphicsMapResources)(unsigned int count, CUgraphicsResource *resources, CUstream hStream);
+ CUresult (*cuGraphicsUnmapResources)(unsigned int count, CUgraphicsResource *resources, CUstream hStream);
+ CUresult (*cuGraphicsUnregisterResource)(CUgraphicsResource resource);
+ CUresult (*cuGraphicsSubResourceGetMappedArray)(CUarray *pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);
+};
+
+bool gsr_cuda_load(gsr_cuda *self, Display *display, bool overclock);
+void gsr_cuda_unload(gsr_cuda *self);
+
+#endif /* GSR_CUDA_H */
diff --git a/include/cursor.h b/include/cursor.h
new file mode 100644
index 0000000..1564714
--- /dev/null
+++ b/include/cursor.h
@@ -0,0 +1,28 @@
+#ifndef GSR_CURSOR_H
+#define GSR_CURSOR_H
+
+#include "egl.h"
+#include "vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ Display *display;
+ int x_fixes_event_base;
+
+ unsigned int texture_id;
+ vec2i size;
+ vec2i hotspot;
+ vec2i position;
+
+ bool cursor_image_set;
+ bool visible;
+} gsr_cursor;
+
+int gsr_cursor_init(gsr_cursor *self, gsr_egl *egl, Display *display);
+void gsr_cursor_deinit(gsr_cursor *self);
+
+/* Returns true if the cursor image has updated or if the cursor has moved */
+bool gsr_cursor_on_event(gsr_cursor *self, XEvent *xev);
+void gsr_cursor_tick(gsr_cursor *self, Window relative_to);
+
+#endif /* GSR_CURSOR_H */
diff --git a/include/damage.h b/include/damage.h
new file mode 100644
index 0000000..4b10e58
--- /dev/null
+++ b/include/damage.h
@@ -0,0 +1,52 @@
+#ifndef GSR_DAMAGE_H
+#define GSR_DAMAGE_H
+
+#include "cursor.h"
+#include "utils.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct _XDisplay Display;
+typedef union _XEvent XEvent;
+
+typedef enum {
+ GSR_DAMAGE_TRACK_NONE,
+ GSR_DAMAGE_TRACK_WINDOW,
+ GSR_DAMAGE_TRACK_MONITOR
+} gsr_damage_track_type;
+
+typedef struct {
+ gsr_egl *egl;
+ Display *display;
+ bool track_cursor;
+ gsr_damage_track_type track_type;
+
+ int damage_event;
+ int damage_error;
+ uint64_t damage;
+ bool damaged;
+
+ int randr_event;
+ int randr_error;
+
+ uint64_t window;
+ //vec2i window_pos;
+ vec2i window_size;
+
+ gsr_cursor cursor; /* Relative to |window| */
+ gsr_monitor monitor;
+ char monitor_name[32];
+} gsr_damage;
+
+bool gsr_damage_init(gsr_damage *self, gsr_egl *egl, bool track_cursor);
+void gsr_damage_deinit(gsr_damage *self);
+
+bool gsr_damage_set_target_window(gsr_damage *self, uint64_t window);
+bool gsr_damage_set_target_monitor(gsr_damage *self, const char *monitor_name);
+void gsr_damage_on_event(gsr_damage *self, XEvent *xev);
+void gsr_damage_tick(gsr_damage *self);
+/* Also returns true if damage tracking is not available */
+bool gsr_damage_is_damaged(gsr_damage *self);
+void gsr_damage_clear(gsr_damage *self);
+
+#endif /* GSR_DAMAGE_H */
diff --git a/include/dbus.h b/include/dbus.h
new file mode 100644
index 0000000..229f7ea
--- /dev/null
+++ b/include/dbus.h
@@ -0,0 +1,49 @@
+#ifndef GSR_DBUS_H
+#define GSR_DBUS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <dbus/dbus.h>
+
+#define DBUS_RANDOM_STR_SIZE 16
+
+typedef enum {
+ GSR_PORTAL_CAPTURE_TYPE_MONITOR = 1 << 0,
+ GSR_PORTAL_CAPTURE_TYPE_WINDOW = 1 << 1,
+ GSR_PORTAL_CAPTURE_TYPE_VIRTUAL = 1 << 2,
+ GSR_PORTAL_CAPTURE_TYPE_ALL = GSR_PORTAL_CAPTURE_TYPE_MONITOR | GSR_PORTAL_CAPTURE_TYPE_WINDOW | GSR_PORTAL_CAPTURE_TYPE_VIRTUAL
+} gsr_portal_capture_type;
+
+typedef enum {
+ GSR_PORTAL_CURSOR_MODE_HIDDEN = 1 << 0,
+ GSR_PORTAL_CURSOR_MODE_EMBEDDED = 1 << 1,
+ GSR_PORTAL_CURSOR_MODE_METADATA = 1 << 2
+} gsr_portal_cursor_mode;
+
+typedef struct {
+ DBusConnection *con;
+ DBusError err;
+ char random_str[DBUS_RANDOM_STR_SIZE + 1];
+ unsigned int handle_counter;
+ bool desktop_portal_rule_added;
+ uint32_t screencast_version;
+ char *screencast_restore_token;
+} gsr_dbus;
+
+/* Blocking. TODO: Make non-blocking */
+bool gsr_dbus_init(gsr_dbus *self, const char *screencast_restore_token);
+void gsr_dbus_deinit(gsr_dbus *self);
+
+/* The follow functions should be called in order to setup ScreenCast properly */
+/* These functions that return an int return the response status code */
+int gsr_dbus_screencast_create_session(gsr_dbus *self, char **session_handle);
+/*
+ |capture_type| is a bitmask of gsr_portal_capture_type values. gsr_portal_capture_type values that are not supported by the desktop portal will be ignored.
+ |gsr_portal_cursor_mode| is a bitmask of gsr_portal_cursor_mode values. gsr_portal_cursor_mode values that are not supported will be ignored.
+*/
+int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode);
+int gsr_dbus_screencast_start(gsr_dbus *self, const char *session_handle, uint32_t *pipewire_node);
+bool gsr_dbus_screencast_open_pipewire_remote(gsr_dbus *self, const char *session_handle, int *pipewire_fd);
+const char* gsr_dbus_screencast_get_restore_token(gsr_dbus *self);
+
+#endif /* GSR_DBUS_H */
diff --git a/include/defs.h b/include/defs.h
new file mode 100644
index 0000000..d780005
--- /dev/null
+++ b/include/defs.h
@@ -0,0 +1,112 @@
+#ifndef GSR_DEFS_H
+#define GSR_DEFS_H
+
+#include <stdbool.h>
+
+#define GSR_VIDEO_CODEC_AUTO -1
+#define GSR_BITRATE_MODE_AUTO -1
+
+typedef enum {
+ GSR_GPU_VENDOR_AMD,
+ GSR_GPU_VENDOR_INTEL,
+ GSR_GPU_VENDOR_NVIDIA,
+ GSR_GPU_VENDOR_BROADCOM,
+} gsr_gpu_vendor;
+
+typedef struct {
+ gsr_gpu_vendor vendor;
+ int gpu_version; /* 0 if unknown */
+ bool is_steam_deck;
+} gsr_gpu_info;
+
+typedef enum {
+ GSR_MONITOR_ROT_0,
+ GSR_MONITOR_ROT_90,
+ GSR_MONITOR_ROT_180,
+ GSR_MONITOR_ROT_270,
+} gsr_monitor_rotation;
+
+typedef enum {
+ GSR_CONNECTION_X11,
+ GSR_CONNECTION_WAYLAND,
+ GSR_CONNECTION_DRM,
+} gsr_connection_type;
+
+typedef enum {
+ GSR_VIDEO_QUALITY_MEDIUM,
+ GSR_VIDEO_QUALITY_HIGH,
+ GSR_VIDEO_QUALITY_VERY_HIGH,
+ GSR_VIDEO_QUALITY_ULTRA,
+} gsr_video_quality;
+
+typedef enum {
+ GSR_VIDEO_CODEC_H264,
+ GSR_VIDEO_CODEC_HEVC,
+ GSR_VIDEO_CODEC_HEVC_HDR,
+ GSR_VIDEO_CODEC_HEVC_10BIT,
+ GSR_VIDEO_CODEC_AV1,
+ GSR_VIDEO_CODEC_AV1_HDR,
+ GSR_VIDEO_CODEC_AV1_10BIT,
+ GSR_VIDEO_CODEC_VP8,
+ GSR_VIDEO_CODEC_VP9,
+ GSR_VIDEO_CODEC_H264_VULKAN,
+ GSR_VIDEO_CODEC_HEVC_VULKAN,
+} gsr_video_codec;
+
+typedef enum {
+ GSR_AUDIO_CODEC_AAC,
+ GSR_AUDIO_CODEC_OPUS,
+ GSR_AUDIO_CODEC_FLAC,
+} gsr_audio_codec;
+
+typedef enum {
+ GSR_PIXEL_FORMAT_YUV420,
+ GSR_PIXEL_FORMAT_YUV444,
+} gsr_pixel_format;
+
+typedef enum {
+ GSR_FRAMERATE_MODE_CONSTANT,
+ GSR_FRAMERATE_MODE_VARIABLE,
+ GSR_FRAMERATE_MODE_CONTENT,
+} gsr_framerate_mode;
+
+typedef enum {
+ GSR_BITRATE_MODE_QP,
+ GSR_BITRATE_MODE_VBR,
+ GSR_BITRATE_MODE_CBR,
+} gsr_bitrate_mode;
+
+typedef enum {
+ GSR_TUNE_PERFORMANCE,
+ GSR_TUNE_QUALITY,
+} gsr_tune;
+
+typedef enum {
+ GSR_VIDEO_ENCODER_HW_GPU,
+ GSR_VIDEO_ENCODER_HW_CPU,
+} gsr_video_encoder_hardware;
+
+typedef enum {
+ GSR_COLOR_RANGE_LIMITED,
+ GSR_COLOR_RANGE_FULL,
+} gsr_color_range;
+
+typedef enum {
+ GSR_COLOR_DEPTH_8_BITS,
+ GSR_COLOR_DEPTH_10_BITS,
+} gsr_color_depth;
+
+typedef enum {
+ GSR_REPLAY_STORAGE_RAM,
+ GSR_REPLAY_STORAGE_DISK,
+} gsr_replay_storage;
+
+bool video_codec_is_hdr(gsr_video_codec video_codec);
+gsr_video_codec hdr_video_codec_to_sdr_video_codec(gsr_video_codec video_codec);
+gsr_color_depth video_codec_to_bit_depth(gsr_video_codec video_codec);
+const char* video_codec_to_string(gsr_video_codec video_codec);
+bool video_codec_is_av1(gsr_video_codec video_codec);
+bool video_codec_is_vulkan(gsr_video_codec video_codec);
+const char* audio_codec_get_name(gsr_audio_codec audio_codec);
+
+#endif /* GSR_DEFS_H */
diff --git a/include/egl.h b/include/egl.h
new file mode 100644
index 0000000..e11557e
--- /dev/null
+++ b/include/egl.h
@@ -0,0 +1,329 @@
+#ifndef GSR_EGL_H
+#define GSR_EGL_H
+
+/* OpenGL EGL library with a hidden window context (to allow using the opengl functions) */
+
+#include <X11/X.h>
+#include <X11/Xutil.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "vec2.h"
+#include "defs.h"
+
+typedef struct gsr_window gsr_window;
+
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+typedef void* EGLDisplay;
+typedef void* EGLNativeDisplayType;
+typedef uintptr_t EGLNativeWindowType;
+typedef uintptr_t EGLNativePixmapType;
+typedef void* EGLConfig;
+typedef void* EGLSurface;
+typedef void* EGLContext;
+typedef void* EGLClientBuffer;
+typedef void* EGLImage;
+typedef void* EGLImageKHR;
+typedef void *GLeglImageOES;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+typedef struct __GLXFBConfigRec *GLXFBConfig;
+typedef struct __GLXcontextRec *GLXContext;
+typedef XID GLXDrawable;
+typedef void(*__GLXextFuncPtr)(void);
+
+#define EGL_SUCCESS 0x3000
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_OPENGL_ES3_BIT 0x00000040
+#define EGL_NONE 0x3038
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_TRUE 1
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_WIDTH 0x3057
+#define EGL_HEIGHT 0x3056
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_RED_SIZE 0x3024
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#define EGL_DEVICE_EXT 0x322C
+#define EGL_DRM_DEVICE_FILE_EXT 0x3233
+
+#define GL_FLOAT 0x1406
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_TRIANGLES 0x0004
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_RED 0x1903
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
+#define GL_ALPHA 0x1906
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_RG 0x8227
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_RGB8 0x8051
+#define GL_RGBA8 0x8058
+#define GL_R8 0x8229
+#define GL_RG8 0x822B
+#define GL_R16 0x822A
+#define GL_RG16 0x822C
+#define GL_RGB16 0x8054
+#define GL_RGBA32F 0x8814
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_NEAREST 0x2600
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_LINEAR 0x2601
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_BLEND 0x0BE2
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DEBUG_OUTPUT 0x92E0
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_READ_WRITE 0x88BA
+#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS 0x90EB
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPUTE_SHADER 0x91B9
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+
+typedef unsigned int (*FUNC_eglExportDMABUFImageQueryMESA)(EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, uint64_t *modifiers);
+typedef unsigned int (*FUNC_eglExportDMABUFImageMESA)(EGLDisplay dpy, EGLImageKHR image, int *fds, int32_t *strides, int32_t *offsets);
+typedef void (*FUNC_glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image);
+typedef GLXContext (*FUNC_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
+typedef void (*FUNC_glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval);
+typedef int (*FUNC_glXSwapIntervalMESA)(unsigned int interval);
+typedef int (*FUNC_glXSwapIntervalSGI)(int interval);
+typedef void (*GLDEBUGPROC)(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char *message, const void *userParam);
+typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value);
+typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name);
+typedef int (*FUNC_eglQueryDmaBufModifiersEXT)(EGLDisplay dpy, int32_t format, int32_t max_modifiers, uint64_t *modifiers, int *external_only, int32_t *num_modifiers);
+typedef void (*FUNC_glCreateMemoryObjectsEXT)(int n, unsigned int *memoryObjects);
+typedef void (*FUNC_glImportMemoryFdEXT)(unsigned int memory, uint64_t size, unsigned int handleType, int fd);
+typedef unsigned char (*FUNC_glIsMemoryObjectEXT)(unsigned int memoryObject);
+typedef void (*FUNC_glTexStorageMem2DEXT)(unsigned int target, int levels, unsigned int internalFormat, int width, int height, unsigned int memory, uint64_t offset);
+typedef void (*FUNC_glBufferStorageMemEXT)(unsigned int target, ssize_t size, unsigned int memory, uint64_t offset);
+typedef void (*FUNC_glNamedBufferStorageMemEXT)(unsigned int buffer, ssize_t size, unsigned int memory, uint64_t offset);
+typedef void (*FUNC_glMemoryObjectParameterivEXT)(unsigned int memoryObject, unsigned int pname, const int *params);
+
+typedef enum {
+ GSR_GL_CONTEXT_TYPE_EGL,
+ GSR_GL_CONTEXT_TYPE_GLX
+} gsr_gl_context_type;
+
+typedef struct gsr_egl gsr_egl;
+struct gsr_egl {
+ void *egl_library;
+ void *glx_library;
+ void *gl_library;
+
+ gsr_gl_context_type context_type;
+ gsr_window *window;
+
+ EGLDisplay egl_display;
+ EGLSurface egl_surface;
+ EGLContext egl_context;
+ const char *dri_card_path;
+
+ void *glx_context;
+ void *glx_fb_config;
+
+ gsr_gpu_info gpu_info;
+
+ char card_path[128];
+
+ int32_t (*eglGetError)(void);
+ EGLDisplay (*eglGetDisplay)(EGLNativeDisplayType display_id);
+ unsigned int (*eglInitialize)(EGLDisplay dpy, int32_t *major, int32_t *minor);
+ unsigned int (*eglTerminate)(EGLDisplay dpy);
+ unsigned int (*eglChooseConfig)(EGLDisplay dpy, const int32_t *attrib_list, EGLConfig *configs, int32_t config_size, int32_t *num_config);
+ EGLSurface (*eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const int32_t *attrib_list);
+ EGLContext (*eglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const int32_t *attrib_list);
+ unsigned int (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+ EGLImage (*eglCreateImage)(EGLDisplay dpy, EGLContext ctx, unsigned int target, EGLClientBuffer buffer, const intptr_t *attrib_list);
+ unsigned int (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx);
+ unsigned int (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
+ unsigned int (*eglDestroyImage)(EGLDisplay dpy, EGLImage image);
+ unsigned int (*eglSwapInterval)(EGLDisplay dpy, int32_t interval);
+ unsigned int (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
+ unsigned int (*eglBindAPI)(unsigned int api);
+ __eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname);
+
+ FUNC_eglExportDMABUFImageQueryMESA eglExportDMABUFImageQueryMESA;
+ FUNC_eglExportDMABUFImageMESA eglExportDMABUFImageMESA;
+ FUNC_glEGLImageTargetTexture2DOES glEGLImageTargetTexture2DOES;
+ FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT;
+ FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT;
+ FUNC_eglQueryDmaBufModifiersEXT eglQueryDmaBufModifiersEXT;
+ FUNC_glCreateMemoryObjectsEXT glCreateMemoryObjectsEXT;
+ FUNC_glImportMemoryFdEXT glImportMemoryFdEXT;
+ FUNC_glIsMemoryObjectEXT glIsMemoryObjectEXT;
+ FUNC_glTexStorageMem2DEXT glTexStorageMem2DEXT;
+ FUNC_glBufferStorageMemEXT glBufferStorageMemEXT;
+ FUNC_glNamedBufferStorageMemEXT glNamedBufferStorageMemEXT;
+ FUNC_glMemoryObjectParameterivEXT glMemoryObjectParameterivEXT;
+
+ __GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName);
+ GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems);
+ Bool (*glXMakeContextCurrent)(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+ // TODO: Remove
+ GLXContext (*glXCreateNewContext)(Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct);
+ void (*glXDestroyContext)(Display *dpy, GLXContext ctx);
+ void (*glXSwapBuffers)(Display *dpy, GLXDrawable drawable);
+ FUNC_glXCreateContextAttribsARB glXCreateContextAttribsARB;
+
+ /* Optional */
+ FUNC_glXSwapIntervalEXT glXSwapIntervalEXT;
+ FUNC_glXSwapIntervalMESA glXSwapIntervalMESA;
+ FUNC_glXSwapIntervalSGI glXSwapIntervalSGI;
+
+ unsigned int (*glGetError)(void);
+ const unsigned char* (*glGetString)(unsigned int name);
+ void (*glFlush)(void);
+ void (*glFinish)(void);
+ void (*glClear)(unsigned int mask);
+ void (*glClearColor)(float red, float green, float blue, float alpha);
+ void (*glGenTextures)(int n, unsigned int *textures);
+ void (*glDeleteTextures)(int n, const unsigned int *texture);
+ void (*glActiveTexture)(unsigned int texture);
+ void (*glBindTexture)(unsigned int target, unsigned int texture);
+ void (*glBindImageTexture)(unsigned int unit, unsigned int texture, int level, unsigned char layered, int layer, unsigned int access, unsigned int format);
+ void (*glTexParameteri)(unsigned int target, unsigned int pname, int param);
+ void (*glTexParameteriv)(unsigned int target, unsigned int pname, const int *params);
+ void (*glTexParameterfv)(unsigned int target, unsigned int pname, const float *params);
+ void (*glGetTexLevelParameteriv)(unsigned int target, int level, unsigned int pname, int *params);
+ void (*glTexImage2D)(unsigned int target, int level, int internalFormat, int width, int height, int border, unsigned int format, unsigned int type, const void *pixels);
+ void (*glTexSubImage2D)(unsigned int target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, const void *pixels);
+ void (*glTexStorage2D)(unsigned int target, int levels, unsigned int internalformat, int width, int height);
+ void (*glGetTexImage)(unsigned int target, int level, unsigned int format, unsigned int type, void *pixels);
+ void (*glGenFramebuffers)(int n, unsigned int *framebuffers);
+ void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer);
+ void (*glDeleteFramebuffers)(int n, const unsigned int *framebuffers);
+ void (*glDispatchCompute)(unsigned int num_groups_x, unsigned int num_groups_y, unsigned int num_groups_z);
+ void (*glMemoryBarrier)(unsigned int barriers);
+ void (*glViewport)(int x, int y, int width, int height);
+ void (*glFramebufferTexture2D)(unsigned int target, unsigned int attachment, unsigned int textarget, unsigned int texture, int level);
+ void (*glDrawBuffers)(int n, const unsigned int *bufs);
+ unsigned int (*glCheckFramebufferStatus)(unsigned int target);
+ void (*glBindBuffer)(unsigned int target, unsigned int buffer);
+ void (*glGenBuffers)(int n, unsigned int *buffers);
+ void (*glBufferData)(unsigned int target, khronos_ssize_t size, const void *data, unsigned int usage);
+ void (*glBufferSubData)(unsigned int target, khronos_intptr_t offset, khronos_ssize_t size, const void *data);
+ void (*glDeleteBuffers)(int n, const unsigned int *buffers);
+ void (*glGenVertexArrays)(int n, unsigned int *arrays);
+ void (*glBindVertexArray)(unsigned int array);
+ void (*glDeleteVertexArrays)(int n, const unsigned int *arrays);
+ unsigned int (*glCreateProgram)(void);
+ unsigned int (*glCreateShader)(unsigned int type);
+ void (*glAttachShader)(unsigned int program, unsigned int shader);
+ void (*glBindAttribLocation)(unsigned int program, unsigned int index, const char *name);
+ void (*glCompileShader)(unsigned int shader);
+ void (*glLinkProgram)(unsigned int program);
+ void (*glShaderSource)(unsigned int shader, int count, const char *const*string, const int *length);
+ void (*glUseProgram)(unsigned int program);
+ void (*glGetProgramInfoLog)(unsigned int program, int bufSize, int *length, char *infoLog);
+ void (*glGetShaderiv)(unsigned int shader, unsigned int pname, int *params);
+ void (*glGetShaderInfoLog)(unsigned int shader, int bufSize, int *length, char *infoLog);
+ void (*glDeleteProgram)(unsigned int program);
+ void (*glDeleteShader)(unsigned int shader);
+ void (*glGetProgramiv)(unsigned int program, unsigned int pname, int *params);
+ void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer);
+ void (*glEnableVertexAttribArray)(unsigned int index);
+ void (*glDrawArrays)(unsigned int mode, int first, int count);
+ void (*glEnable)(unsigned int cap);
+ void (*glDisable)(unsigned int cap);
+ void (*glBlendFunc)(unsigned int sfactor, unsigned int dfactor);
+ void (*glPixelStorei)(unsigned int pname, int param);
+ int (*glGetUniformLocation)(unsigned int program, const char *name);
+ void (*glUniform1f)(int location, float v0);
+ void (*glUniform2f)(int location, float v0, float v1);
+ void (*glUniform1i)(int location, int v0);
+ void (*glUniform2i)(int location, int v0, int v1);
+ void (*glUniformMatrix2fv)(int location, int count, unsigned char transpose, const float *value);
+ void (*glDebugMessageCallback)(GLDEBUGPROC callback, const void *userParam);
+ void (*glScissor)(int x, int y, int width, int height);
+ void (*glCreateBuffers)(int n, unsigned int *buffers);
+ void (*glReadPixels)(int x, int y, int width, int height, unsigned int format, unsigned int type, void *pixels);
+ void* (*glMapBuffer)(unsigned int target, unsigned int access);
+ unsigned char (*glUnmapBuffer)(unsigned int target);
+ void (*glGetIntegerv)(unsigned int pname, int *params);
+};
+
+bool gsr_egl_load(gsr_egl *self, gsr_window *window, bool is_monitor_capture, bool enable_debug);
+void gsr_egl_unload(gsr_egl *self);
+
+/* Does opengl swap with egl or glx, depending on which one is active */
+void gsr_egl_swap_buffers(gsr_egl *self);
+
+#endif /* GSR_EGL_H */
diff --git a/include/encoder/encoder.h b/include/encoder/encoder.h
new file mode 100644
index 0000000..7e550f6
--- /dev/null
+++ b/include/encoder/encoder.h
@@ -0,0 +1,43 @@
+#ifndef GSR_ENCODER_H
+#define GSR_ENCODER_H
+
+#include "../replay_buffer/replay_buffer.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <pthread.h>
+
+#define GSR_MAX_RECORDING_DESTINATIONS 128
+
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVFormatContext AVFormatContext;
+typedef struct AVStream AVStream;
+
+typedef struct {
+ size_t id;
+ AVCodecContext *codec_context;
+ AVFormatContext *format_context;
+ AVStream *stream;
+ int64_t start_pts;
+ bool has_received_keyframe;
+} gsr_encoder_recording_destination;
+
+typedef struct {
+ gsr_replay_buffer *replay_buffer;
+ pthread_mutex_t file_write_mutex;
+ bool mutex_created;
+
+ gsr_encoder_recording_destination recording_destinations[GSR_MAX_RECORDING_DESTINATIONS];
+ size_t num_recording_destinations;
+ size_t recording_destination_id_counter;
+} gsr_encoder;
+
+bool gsr_encoder_init(gsr_encoder *self, gsr_replay_storage replay_storage, size_t replay_buffer_num_packets, double replay_buffer_time, const char *replay_directory);
+void gsr_encoder_deinit(gsr_encoder *self);
+
+void gsr_encoder_receive_packets(gsr_encoder *self, AVCodecContext *codec_context, int64_t pts, int stream_index);
+/* Returns the id to the recording destination, or -1 on error */
+size_t gsr_encoder_add_recording_destination(gsr_encoder *self, AVCodecContext *codec_context, AVFormatContext *format_context, AVStream *stream, int64_t start_pts);
+bool gsr_encoder_remove_recording_destination(gsr_encoder *self, size_t id);
+
+#endif /* GSR_ENCODER_H */
diff --git a/include/encoder/video/nvenc.h b/include/encoder/video/nvenc.h
new file mode 100644
index 0000000..d4a906b
--- /dev/null
+++ b/include/encoder/video/nvenc.h
@@ -0,0 +1,16 @@
+#ifndef GSR_ENCODER_VIDEO_NVENC_H
+#define GSR_ENCODER_VIDEO_NVENC_H
+
+#include "video.h"
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ gsr_egl *egl;
+ bool overclock;
+ gsr_color_depth color_depth;
+} gsr_video_encoder_nvenc_params;
+
+gsr_video_encoder* gsr_video_encoder_nvenc_create(const gsr_video_encoder_nvenc_params *params);
+
+#endif /* GSR_ENCODER_VIDEO_NVENC_H */
diff --git a/include/encoder/video/software.h b/include/encoder/video/software.h
new file mode 100644
index 0000000..fd2dc6b
--- /dev/null
+++ b/include/encoder/video/software.h
@@ -0,0 +1,15 @@
+#ifndef GSR_ENCODER_VIDEO_SOFTWARE_H
+#define GSR_ENCODER_VIDEO_SOFTWARE_H
+
+#include "video.h"
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ gsr_egl *egl;
+ gsr_color_depth color_depth;
+} gsr_video_encoder_software_params;
+
+gsr_video_encoder* gsr_video_encoder_software_create(const gsr_video_encoder_software_params *params);
+
+#endif /* GSR_ENCODER_VIDEO_SOFTWARE_H */
diff --git a/include/encoder/video/vaapi.h b/include/encoder/video/vaapi.h
new file mode 100644
index 0000000..b509f17
--- /dev/null
+++ b/include/encoder/video/vaapi.h
@@ -0,0 +1,15 @@
+#ifndef GSR_ENCODER_VIDEO_VAAPI_H
+#define GSR_ENCODER_VIDEO_VAAPI_H
+
+#include "video.h"
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ gsr_egl *egl;
+ gsr_color_depth color_depth;
+} gsr_video_encoder_vaapi_params;
+
+gsr_video_encoder* gsr_video_encoder_vaapi_create(const gsr_video_encoder_vaapi_params *params);
+
+#endif /* GSR_ENCODER_VIDEO_VAAPI_H */
diff --git a/include/encoder/video/video.h b/include/encoder/video/video.h
new file mode 100644
index 0000000..7a706b5
--- /dev/null
+++ b/include/encoder/video/video.h
@@ -0,0 +1,30 @@
+#ifndef GSR_ENCODER_VIDEO_H
+#define GSR_ENCODER_VIDEO_H
+
+#include "../../color_conversion.h"
+#include <stdbool.h>
+
+#define GSR_MAX_RECORDING_DESTINATIONS 128
+
+typedef struct gsr_video_encoder gsr_video_encoder;
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVFrame AVFrame;
+
+struct gsr_video_encoder {
+ bool (*start)(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame);
+ void (*destroy)(gsr_video_encoder *encoder, AVCodecContext *video_codec_context);
+ void (*copy_textures_to_frame)(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion); /* Can be NULL */
+ /* |textures| should be able to fit 2 elements */
+ void (*get_textures)(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color);
+
+ void *priv;
+ bool started;
+};
+
+/* Set |replay_buffer_time_seconds| and |fps| to 0 to disable replay buffer */
+bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame);
+void gsr_video_encoder_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context);
+void gsr_video_encoder_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion);
+void gsr_video_encoder_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color);
+
+#endif /* GSR_ENCODER_VIDEO_H */
diff --git a/include/encoder/video/vulkan.h b/include/encoder/video/vulkan.h
new file mode 100644
index 0000000..383fc4f
--- /dev/null
+++ b/include/encoder/video/vulkan.h
@@ -0,0 +1,15 @@
+#ifndef GSR_ENCODER_VIDEO_VULKAN_H
+#define GSR_ENCODER_VIDEO_VULKAN_H
+
+#include "video.h"
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ gsr_egl *egl;
+ gsr_color_depth color_depth;
+} gsr_video_encoder_vulkan_params;
+
+gsr_video_encoder* gsr_video_encoder_vulkan_create(const gsr_video_encoder_vulkan_params *params);
+
+#endif /* GSR_ENCODER_VIDEO_VULKAN_H */
diff --git a/include/image_writer.h b/include/image_writer.h
new file mode 100644
index 0000000..65e7497
--- /dev/null
+++ b/include/image_writer.h
@@ -0,0 +1,35 @@
+#ifndef GSR_IMAGE_WRITER_H
+#define GSR_IMAGE_WRITER_H
+
+#include <stdbool.h>
+
+typedef struct gsr_egl gsr_egl;
+
+typedef enum {
+ GSR_IMAGE_FORMAT_JPEG,
+ GSR_IMAGE_FORMAT_PNG
+} gsr_image_format;
+
+typedef enum {
+ GSR_IMAGE_WRITER_SOURCE_OPENGL,
+ GSR_IMAGE_WRITER_SOURCE_MEMORY
+} gsr_image_writer_source;
+
+typedef struct {
+ gsr_image_writer_source source;
+ gsr_egl *egl;
+ int width;
+ int height;
+ unsigned int texture;
+ const void *memory; /* Reference */
+} gsr_image_writer;
+
+bool gsr_image_writer_init_opengl(gsr_image_writer *self, gsr_egl *egl, int width, int height);
+/* |memory| is taken as a reference. The data is expected to be in rgba8 format (8 bit rgba) */
+bool gsr_image_writer_init_memory(gsr_image_writer *self, const void *memory, int width, int height);
+void gsr_image_writer_deinit(gsr_image_writer *self);
+
+/* Quality is between 1 and 100 where 100 is the max quality. Quality doesn't apply to lossless formats */
+bool gsr_image_writer_write_to_file(gsr_image_writer *self, const char *filepath, gsr_image_format image_format, int quality);
+
+#endif /* GSR_IMAGE_WRITER_H */
diff --git a/include/library_loader.h b/include/library_loader.h
new file mode 100644
index 0000000..47bc9f0
--- /dev/null
+++ b/include/library_loader.h
@@ -0,0 +1,17 @@
+#ifndef GSR_LIBRARY_LOADER_H
+#define GSR_LIBRARY_LOADER_H
+
+#include <stdbool.h>
+
+typedef struct {
+ void **func;
+ const char *name;
+} dlsym_assign;
+
+void* dlsym_print_fail(void *handle, const char *name, bool required);
+/* |dlsyms| should be null terminated */
+bool dlsym_load_list(void *handle, const dlsym_assign *dlsyms);
+/* |dlsyms| should be null terminated */
+void dlsym_load_list_optional(void *handle, const dlsym_assign *dlsyms);
+
+#endif /* GSR_LIBRARY_LOADER_H */
diff --git a/include/overclock.h b/include/overclock.h
new file mode 100644
index 0000000..d6ff901
--- /dev/null
+++ b/include/overclock.h
@@ -0,0 +1,17 @@
+#ifndef GSR_OVERCLOCK_H
+#define GSR_OVERCLOCK_H
+
+#include "xnvctrl.h"
+
+typedef struct {
+ gsr_xnvctrl xnvctrl;
+ int num_performance_levels;
+} gsr_overclock;
+
+bool gsr_overclock_load(gsr_overclock *self, Display *display);
+void gsr_overclock_unload(gsr_overclock *self);
+
+bool gsr_overclock_start(gsr_overclock *self);
+void gsr_overclock_stop(gsr_overclock *self);
+
+#endif /* GSR_OVERCLOCK_H */
diff --git a/include/pipewire_audio.h b/include/pipewire_audio.h
new file mode 100644
index 0000000..68e5356
--- /dev/null
+++ b/include/pipewire_audio.h
@@ -0,0 +1,156 @@
+#ifndef GSR_PIPEWIRE_AUDIO_H
+#define GSR_PIPEWIRE_AUDIO_H
+
+#include <pipewire/thread-loop.h>
+#include <pipewire/context.h>
+#include <pipewire/core.h>
+#include <spa/utils/hook.h>
+
+#include <stdbool.h>
+
+typedef enum {
+ GSR_PIPEWIRE_AUDIO_NODE_TYPE_STREAM_OUTPUT, /* Application audio */
+ GSR_PIPEWIRE_AUDIO_NODE_TYPE_STREAM_INPUT, /* Audio recording input */
+ GSR_PIPEWIRE_AUDIO_NODE_TYPE_SINK_OR_SOURCE /* Audio output or input device or combined (virtual) sink */
+} gsr_pipewire_audio_node_type;
+
+typedef struct {
+ uint32_t id;
+ char *name;
+ gsr_pipewire_audio_node_type type;
+} gsr_pipewire_audio_node;
+
+typedef enum {
+ GSR_PIPEWIRE_AUDIO_PORT_DIRECTION_INPUT,
+ GSR_PIPEWIRE_AUDIO_PORT_DIRECTION_OUTPUT
+} gsr_pipewire_audio_port_direction;
+
+typedef struct {
+ uint32_t id;
+ uint32_t node_id;
+ gsr_pipewire_audio_port_direction direction;
+ char *name;
+} gsr_pipewire_audio_port;
+
+typedef struct {
+ uint32_t id;
+ uint32_t output_node_id;
+ uint32_t input_node_id;
+} gsr_pipewire_audio_link;
+
+typedef enum {
+ GSR_PIPEWIRE_AUDIO_LINK_INPUT_TYPE_STREAM, /* Application */
+ GSR_PIPEWIRE_AUDIO_LINK_INPUT_TYPE_SINK /* Combined (virtual) sink */
+} gsr_pipewire_audio_link_input_type;
+
+typedef enum {
+ GSR_PIPEWIRE_AUDIO_REQUESTED_TYPE_STANDARD,
+ GSR_PIPEWIRE_AUDIO_REQUESTED_TYPE_DEFAULT_OUTPUT,
+ GSR_PIPEWIRE_AUDIO_REQUESTED_TYPE_DEFAULT_INPUT
+} gsr_pipewire_audio_requested_type;
+
+typedef struct {
+ char *name;
+ gsr_pipewire_audio_requested_type type;
+} gsr_pipewire_audio_requested_output;
+
+typedef struct {
+ gsr_pipewire_audio_requested_output *outputs;
+ int num_outputs;
+ char *input_name;
+ bool inverted;
+ gsr_pipewire_audio_node_type output_type;
+ gsr_pipewire_audio_link_input_type input_type;
+} gsr_pipewire_audio_requested_link;
+
+typedef struct {
+ struct pw_thread_loop *thread_loop;
+ struct pw_context *context;
+ struct pw_core *core;
+ struct spa_hook core_listener;
+ struct pw_registry *registry;
+ struct spa_hook registry_listener;
+ int server_version_sync;
+
+ struct pw_proxy *metadata_proxy;
+ struct spa_hook metadata_listener;
+ struct spa_hook metadata_proxy_listener;
+ char default_output_device_name[128];
+ char default_input_device_name[128];
+
+ gsr_pipewire_audio_node *stream_nodes;
+ size_t num_stream_nodes;
+ size_t stream_nodes_capacity_items;
+
+ gsr_pipewire_audio_port *ports;
+ size_t num_ports;
+ size_t ports_capacity_items;
+
+ gsr_pipewire_audio_link *links;
+ size_t num_links;
+ size_t links_capacity_items;
+
+ gsr_pipewire_audio_requested_link *requested_links;
+ size_t num_requested_links;
+ size_t requested_links_capacity_items;
+
+ struct pw_proxy **virtual_sink_proxies;
+ size_t num_virtual_sink_proxies;
+ size_t virtual_sink_proxies_capacity_items;
+} gsr_pipewire_audio;
+
+bool gsr_pipewire_audio_init(gsr_pipewire_audio *self);
+void gsr_pipewire_audio_deinit(gsr_pipewire_audio *self);
+
+bool gsr_pipewire_audio_create_virtual_sink(gsr_pipewire_audio *self, const char *name);
+
+/*
+ This function links audio source outputs from applications that match the name |app_names| to the input
+ that matches the name |stream_name_input|.
+ If an application or a new application starts outputting audio after this function is called and the app name matches
+ then it will automatically link the audio sources.
+ |app_names| and |stream_name_input| are case-insensitive matches.
+*/
+bool gsr_pipewire_audio_add_link_from_apps_to_stream(gsr_pipewire_audio *self, const char **app_names, int num_app_names, const char *stream_name_input);
+/*
+ This function links audio source outputs from all applications except the ones that match the name |app_names| to the input
+ that matches the name |stream_name_input|.
+ If an application or a new application starts outputting audio after this function is called and the app name doesn't match
+ then it will automatically link the audio sources.
+ |app_names| and |stream_name_input| are case-insensitive matches.
+*/
+bool gsr_pipewire_audio_add_link_from_apps_to_stream_inverted(gsr_pipewire_audio *self, const char **app_names, int num_app_names, const char *stream_name_input);
+
+/*
+ This function links audio source outputs from applications that match the name |app_names| to the input
+ that matches the name |sink_name_input|.
+ If an application or a new application starts outputting audio after this function is called and the app name matches
+ then it will automatically link the audio sources.
+ |app_names| and |sink_name_input| are case-insensitive matches.
+*/
+bool gsr_pipewire_audio_add_link_from_apps_to_sink(gsr_pipewire_audio *self, const char **app_names, int num_app_names, const char *sink_name_input);
+/*
+ This function links audio source outputs from all applications except the ones that match the name |app_names| to the input
+ that matches the name |sink_name_input|.
+ If an application or a new application starts outputting audio after this function is called and the app name doesn't match
+ then it will automatically link the audio sources.
+ |app_names| and |sink_name_input| are case-insensitive matches.
+*/
+bool gsr_pipewire_audio_add_link_from_apps_to_sink_inverted(gsr_pipewire_audio *self, const char **app_names, int num_app_names, const char *sink_name_input);
+
+/*
+ This function links audio source outputs from devices that match the name |source_names| to the input
+ that matches the name |sink_name_input|.
+ If a device or a new device starts outputting audio after this function is called and the device name matches
+ then it will automatically link the audio sources.
+ |source_names| and |sink_name_input| are case-insensitive matches.
+ |source_names| can include "default_output" or "default_input" to use the default output/input
+ and it will automatically switch when the default output/input is changed in system audio settings.
+*/
+bool gsr_pipewire_audio_add_link_from_sources_to_sink(gsr_pipewire_audio *self, const char **source_names, int num_source_names, const char *sink_name_input);
+
+/* Return true to continue */
+typedef bool (*gsr_pipewire_audio_app_query_callback)(const char *app_name, void *userdata);
+void gsr_pipewire_audio_for_each_app(gsr_pipewire_audio *self, gsr_pipewire_audio_app_query_callback callback, void *userdata);
+
+#endif /* GSR_PIPEWIRE_AUDIO_H */
diff --git a/include/pipewire_video.h b/include/pipewire_video.h
new file mode 100644
index 0000000..d98e43d
--- /dev/null
+++ b/include/pipewire_video.h
@@ -0,0 +1,117 @@
+#ifndef GSR_PIPEWIRE_VIDEO_H
+#define GSR_PIPEWIRE_VIDEO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#include <spa/utils/hook.h>
+#include <spa/param/video/format.h>
+
+#define GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS 1024
+#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 6
+#define GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES 4
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ int major;
+ int minor;
+ int micro;
+} gsr_pipewire_video_data_version;
+
+typedef struct {
+ uint32_t fps_num;
+ uint32_t fps_den;
+} gsr_pipewire_video_video_info;
+
+typedef struct {
+ int fd;
+ uint32_t offset;
+ int32_t stride;
+} gsr_pipewire_video_dmabuf_data;
+
+typedef struct {
+ int x, y;
+ int width, height;
+} gsr_pipewire_video_region;
+
+typedef struct {
+ enum spa_video_format format;
+ size_t modifiers_index;
+ size_t modifiers_size;
+} gsr_video_format;
+
+typedef struct {
+ unsigned int texture_id;
+ unsigned int external_texture_id;
+ unsigned int cursor_texture_id;
+} gsr_texture_map;
+
+typedef struct {
+ gsr_egl *egl;
+ int fd;
+ uint32_t node;
+ pthread_mutex_t mutex;
+ bool mutex_initialized;
+
+ struct pw_thread_loop *thread_loop;
+ struct pw_context *context;
+ struct pw_core *core;
+ struct spa_hook core_listener;
+ struct pw_stream *stream;
+ struct spa_hook stream_listener;
+ struct spa_source *reneg;
+ struct spa_video_info format;
+ int server_version_sync;
+ bool negotiated;
+ bool renegotiated;
+ bool damaged;
+
+ struct {
+ bool visible;
+ bool valid;
+ uint8_t *data;
+ int x, y;
+ int hotspot_x, hotspot_y;
+ int width, height;
+ } cursor;
+
+ struct {
+ bool valid;
+ int x, y;
+ uint32_t width, height;
+ } crop;
+
+ gsr_video_format supported_video_formats[GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS];
+
+ gsr_pipewire_video_data_version server_version;
+ gsr_pipewire_video_video_info video_info;
+ gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
+ size_t dmabuf_num_planes;
+
+ bool no_modifiers_fallback;
+ bool external_texture_fallback;
+
+ uint64_t modifiers[GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS];
+ size_t num_modifiers;
+
+ bool paused;
+ double paused_start_secs;
+} gsr_pipewire_video;
+
+/*
+ |capture_cursor| only applies to when capturing a window or region.
+ In other cases |pipewire_node|'s setup will determine if the cursor is included.
+ Note that the cursor is not guaranteed to be shown even if set to true, it depends on the wayland compositor.
+*/
+bool gsr_pipewire_video_init(gsr_pipewire_video *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl);
+void gsr_pipewire_video_deinit(gsr_pipewire_video *self);
+
+/* |dmabuf_data| should be at least GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES in size */
+bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map texture_map, gsr_pipewire_video_region *region, gsr_pipewire_video_region *cursor_region, gsr_pipewire_video_dmabuf_data *dmabuf_data, int *num_dmabuf_data, uint32_t *fourcc, uint64_t *modifiers, bool *using_external_image);
+bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self);
+void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self);
+bool gsr_pipewire_video_should_restart(gsr_pipewire_video *self);
+
+#endif /* GSR_PIPEWIRE_VIDEO_H */
diff --git a/include/replay_buffer/replay_buffer.h b/include/replay_buffer/replay_buffer.h
new file mode 100644
index 0000000..a04a3be
--- /dev/null
+++ b/include/replay_buffer/replay_buffer.h
@@ -0,0 +1,54 @@
+#ifndef GSR_REPLAY_BUFFER_H
+#define GSR_REPLAY_BUFFER_H
+
+#include "../defs.h"
+#include <pthread.h>
+#include <stdbool.h>
+#include <libavcodec/packet.h>
+
+typedef struct gsr_replay_buffer gsr_replay_buffer;
+
+typedef struct {
+ size_t packet_index;
+ size_t file_index;
+} gsr_replay_buffer_iterator;
+
+struct gsr_replay_buffer {
+ void (*destroy)(gsr_replay_buffer *self);
+ bool (*append)(gsr_replay_buffer *self, const AVPacket *av_packet, double timestamp);
+ void (*clear)(gsr_replay_buffer *self);
+ AVPacket* (*iterator_get_packet)(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+ /* The returned data should be free'd with free */
+ uint8_t* (*iterator_get_packet_data)(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+ /* The clone has to be destroyed before the replay buffer it clones is destroyed */
+ gsr_replay_buffer* (*clone)(gsr_replay_buffer *self);
+ /* Returns {0, 0} if replay buffer is empty */
+ gsr_replay_buffer_iterator (*find_packet_index_by_time_passed)(gsr_replay_buffer *self, int seconds);
+ /* Returns {-1, 0} if not found */
+ gsr_replay_buffer_iterator (*find_keyframe)(gsr_replay_buffer *self, gsr_replay_buffer_iterator start_iterator, int stream_index, bool invert_stream_index);
+ bool (*iterator_next)(gsr_replay_buffer *self, gsr_replay_buffer_iterator *iterator);
+
+ pthread_mutex_t mutex;
+ bool mutex_initialized;
+ gsr_replay_buffer *original_replay_buffer;
+};
+
+gsr_replay_buffer* gsr_replay_buffer_create(gsr_replay_storage replay_storage, const char *replay_directory, double replay_buffer_time, size_t replay_buffer_num_packets);
+void gsr_replay_buffer_destroy(gsr_replay_buffer *self);
+
+void gsr_replay_buffer_lock(gsr_replay_buffer *self);
+void gsr_replay_buffer_unlock(gsr_replay_buffer *self);
+bool gsr_replay_buffer_append(gsr_replay_buffer *self, const AVPacket *av_packet, double timestamp);
+void gsr_replay_buffer_clear(gsr_replay_buffer *self);
+AVPacket* gsr_replay_buffer_iterator_get_packet(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+/* The returned data should be free'd with free */
+uint8_t* gsr_replay_buffer_iterator_get_packet_data(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+/* The clone has to be destroyed before the replay buffer it clones is destroyed */
+gsr_replay_buffer* gsr_replay_buffer_clone(gsr_replay_buffer *self);
+/* Returns {0, 0} if replay buffer is empty */
+gsr_replay_buffer_iterator gsr_replay_buffer_find_packet_index_by_time_passed(gsr_replay_buffer *self, int seconds);
+/* Returns {-1, 0} if not found */
+gsr_replay_buffer_iterator gsr_replay_buffer_find_keyframe(gsr_replay_buffer *self, gsr_replay_buffer_iterator start_iterator, int stream_index, bool invert_stream_index);
+bool gsr_replay_buffer_iterator_next(gsr_replay_buffer *self, gsr_replay_buffer_iterator *iterator);
+
+#endif /* GSR_REPLAY_BUFFER_H */ \ No newline at end of file
diff --git a/include/replay_buffer/replay_buffer_disk.h b/include/replay_buffer/replay_buffer_disk.h
new file mode 100644
index 0000000..6873bb0
--- /dev/null
+++ b/include/replay_buffer/replay_buffer_disk.h
@@ -0,0 +1,44 @@
+#ifndef GSR_REPLAY_BUFFER_DISK_H
+#define GSR_REPLAY_BUFFER_DISK_H
+
+#include "replay_buffer.h"
+#include <limits.h>
+
+#define GSR_REPLAY_BUFFER_CAPACITY_NUM_FILES 1024
+
+typedef struct {
+ AVPacket packet;
+ size_t data_index;
+ double timestamp;
+} gsr_av_packet_disk;
+
+typedef struct {
+ size_t id;
+ double start_timestamp;
+ double end_timestamp;
+ int ref_counter;
+ int fd;
+
+ gsr_av_packet_disk *packets;
+ size_t capacity_num_packets;
+ size_t num_packets;
+} gsr_replay_buffer_file;
+
+typedef struct {
+ gsr_replay_buffer replay_buffer;
+ double replay_buffer_time;
+
+ size_t storage_counter;
+ size_t storage_num_bytes_written;
+ int storage_fd;
+ gsr_replay_buffer_file *files[GSR_REPLAY_BUFFER_CAPACITY_NUM_FILES]; // GSR_REPLAY_BUFFER_CAPACITY_NUM_FILES * REPLAY_BUFFER_FILE_SIZE_BYTES = 256gb, should be enough for everybody
+ size_t num_files;
+
+ char replay_directory[PATH_MAX];
+
+ bool owns_directory;
+} gsr_replay_buffer_disk;
+
+gsr_replay_buffer* gsr_replay_buffer_disk_create(const char *replay_directory, double replay_buffer_time);
+
+#endif /* GSR_REPLAY_BUFFER_DISK_H */ \ No newline at end of file
diff --git a/include/replay_buffer/replay_buffer_ram.h b/include/replay_buffer/replay_buffer_ram.h
new file mode 100644
index 0000000..a43d1b9
--- /dev/null
+++ b/include/replay_buffer/replay_buffer_ram.h
@@ -0,0 +1,22 @@
+#ifndef GSR_REPLAY_BUFFER_RAM_H
+#define GSR_REPLAY_BUFFER_RAM_H
+
+#include "replay_buffer.h"
+
+typedef struct {
+ AVPacket packet;
+ int ref_counter;
+ double timestamp;
+} gsr_av_packet_ram;
+
+typedef struct {
+ gsr_replay_buffer replay_buffer;
+ gsr_av_packet_ram **packets;
+ size_t capacity_num_packets;
+ size_t num_packets;
+ size_t index;
+} gsr_replay_buffer_ram;
+
+gsr_replay_buffer* gsr_replay_buffer_ram_create(size_t replay_buffer_num_packets);
+
+#endif /* GSR_REPLAY_BUFFER_RAM_H */ \ No newline at end of file
diff --git a/include/shader.h b/include/shader.h
new file mode 100644
index 0000000..285758d
--- /dev/null
+++ b/include/shader.h
@@ -0,0 +1,23 @@
+#ifndef GSR_SHADER_H
+#define GSR_SHADER_H
+
+#include <stdbool.h>
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ gsr_egl *egl;
+ unsigned int program_id;
+} gsr_shader;
+
+/* |vertex_shader| or |fragment_shader| may be NULL */
+int gsr_shader_init(gsr_shader *self, gsr_egl *egl, const char *vertex_shader, const char *fragment_shader, const char *compute_shader);
+void gsr_shader_deinit(gsr_shader *self);
+
+int gsr_shader_bind_attribute_location(gsr_shader *self, const char *attribute, int location);
+void gsr_shader_use(gsr_shader *self);
+void gsr_shader_use_none(gsr_shader *self);
+
+void gsr_shader_enable_debug_output(bool enable);
+
+#endif /* GSR_SHADER_H */
diff --git a/include/sound.hpp b/include/sound.hpp
index 666d009..87e2e2d 100644
--- a/include/sound.hpp
+++ b/include/sound.hpp
@@ -18,20 +18,55 @@
#ifndef GPU_SCREEN_RECORDER_H
#define GPU_SCREEN_RECORDER_H
+#include <vector>
+#include <string>
+
typedef struct {
void *handle;
- void *buffer;
- int buffer_size;
unsigned int frames;
} SoundDevice;
+struct AudioDevice {
+ std::string name;
+ std::string description;
+};
+
+struct AudioDevices {
+ std::string default_output;
+ std::string default_input;
+ std::vector<AudioDevice> audio_inputs;
+};
+
+enum class AudioInputType {
+ DEVICE,
+ APPLICATION
+};
+
+struct AudioInput {
+ std::string name;
+ AudioInputType type = AudioInputType::DEVICE;
+ bool inverted = false;
+};
+
+struct MergedAudioInputs {
+ std::string track_name;
+ std::vector<AudioInput> audio_inputs;
+};
+
+typedef enum {
+ S16,
+ S32,
+ F32
+} AudioFormat;
+
/*
- Get a sound device by name, returning the device into the @device parameter.
- The device should be closed with @sound_device_close after it has been used
- to clean up internal resources.
+ Get a sound device by name, returning the device into the |device| parameter.
+ |device_name| can be a device name or "default_output" or "default_input".
+ If the device name is "default_output" or "default_input" then it will automatically switch which
+ device is records from when the default output/input is changed in the system audio settings.
Returns 0 on success, or a negative value on failure.
*/
-int sound_device_get_by_name(SoundDevice *device, const char *name = "default", unsigned int num_channels = 2, unsigned int period_frame_size = 32);
+int sound_device_get_by_name(SoundDevice *device, const char *device_name, const char *description, unsigned int num_channels, unsigned int period_frame_size, AudioFormat audio_format);
void sound_device_close(SoundDevice *device);
@@ -39,6 +74,9 @@ void sound_device_close(SoundDevice *device);
Returns the next chunk of audio into @buffer.
Returns the number of frames read, or a negative value on failure.
*/
-int sound_device_read_next_chunk(SoundDevice *device, void **buffer);
+int sound_device_read_next_chunk(SoundDevice *device, void **buffer, double timeout_sec, double *latency_seconds);
+
+AudioDevices get_pulseaudio_inputs();
+bool pulseaudio_server_is_pipewire();
#endif /* GPU_SCREEN_RECORDER_H */
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..74ccf18
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,61 @@
+#ifndef GSR_UTILS_H
+#define GSR_UTILS_H
+
+#include "vec2.h"
+#include "../include/egl.h"
+#include "../include/defs.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVFrame AVFrame;
+
+typedef struct {
+ const char *name;
+ int name_len;
+ vec2i pos; /* This is 0, 0 on wayland. Use |drm_monitor_get_display_server_data| to get the position */
+ vec2i size;
+ uint32_t connector_id; /* Only on x11 and drm */
+ gsr_monitor_rotation rotation; /* Only on x11 and wayland */
+ uint32_t monitor_identifier; /* On x11 this is the crtc id */
+} gsr_monitor;
+
+typedef struct {
+ const char *name;
+ int name_len;
+ gsr_monitor *monitor;
+ bool found_monitor;
+} get_monitor_by_name_userdata;
+
+double clock_get_monotonic_seconds(void);
+bool generate_random_characters(char *buffer, int buffer_size, const char *alphabet, size_t alphabet_size);
+bool generate_random_characters_standard_alphabet(char *buffer, int buffer_size);
+
+typedef void (*active_monitor_callback)(const gsr_monitor *monitor, void *userdata);
+void for_each_active_monitor_output_x11_not_cached(Display *display, active_monitor_callback callback, void *userdata);
+void for_each_active_monitor_output(const gsr_window *window, const char *card_path, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata);
+bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type, const char *name, gsr_monitor *monitor);
+bool drm_monitor_get_display_server_data(const gsr_window *window, const gsr_monitor *monitor, gsr_monitor_rotation *monitor_rotation, vec2i *monitor_position);
+
+int get_connector_type_by_name(const char *name);
+int get_connector_type_id_by_name(const char *name);
+uint32_t monitor_identifier_from_type_and_count(int monitor_type_index, int monitor_type_count);
+
+bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info);
+
+bool try_card_has_valid_plane(const char *card_path);
+/* |output| should be at least 128 bytes in size */
+bool gsr_get_valid_card_path(gsr_egl *egl, char *output, bool is_monitor_capture);
+/* |render_path| should be at least 128 bytes in size */
+bool gsr_card_path_get_render_path(const char *card_path, char *render_path);
+
+int create_directory_recursive(char *path);
+
+/* |img_attr| needs to be at least 44 in size */
+void setup_dma_buf_attrs(intptr_t *img_attr, uint32_t format, uint32_t width, uint32_t height, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, int num_planes, bool use_modifier);
+
+vec2i scale_keep_aspect_ratio(vec2i from, vec2i to);
+
+unsigned int gl_create_texture(gsr_egl *egl, int width, int height, int internal_format, unsigned int format, int filter);
+
+#endif /* GSR_UTILS_H */
diff --git a/include/vec2.h b/include/vec2.h
new file mode 100644
index 0000000..8fd3858
--- /dev/null
+++ b/include/vec2.h
@@ -0,0 +1,16 @@
+#ifndef VEC2_H
+#define VEC2_H
+
+typedef struct {
+ int x, y;
+} vec2i;
+
+typedef struct {
+ float x, y;
+} vec2f;
+
+typedef struct {
+ double x, y;
+} vec2d;
+
+#endif /* VEC2_H */
diff --git a/include/window/wayland.h b/include/window/wayland.h
new file mode 100644
index 0000000..3535b0f
--- /dev/null
+++ b/include/window/wayland.h
@@ -0,0 +1,8 @@
+#ifndef GSR_WINDOW_WAYLAND_H
+#define GSR_WINDOW_WAYLAND_H
+
+#include "window.h"
+
+gsr_window* gsr_window_wayland_create(void);
+
+#endif /* GSR_WINDOW_WAYLAND_H */
diff --git a/include/window/window.h b/include/window/window.h
new file mode 100644
index 0000000..7839f6a
--- /dev/null
+++ b/include/window/window.h
@@ -0,0 +1,37 @@
+#ifndef GSR_WINDOW_H
+#define GSR_WINDOW_H
+
+#include "../utils.h"
+#include <stdbool.h>
+
+typedef union _XEvent XEvent;
+typedef struct gsr_window gsr_window;
+
+typedef enum {
+ GSR_DISPLAY_SERVER_X11,
+ GSR_DISPLAY_SERVER_WAYLAND
+} gsr_display_server;
+
+struct gsr_window {
+ void (*destroy)(gsr_window *self);
+ /* Returns true if an event is available */
+ bool (*process_event)(gsr_window *self);
+ XEvent* (*get_event_data)(gsr_window *self); /* can be NULL */
+ gsr_display_server (*get_display_server)(void);
+ void* (*get_display)(gsr_window *self);
+ void* (*get_window)(gsr_window *self);
+ void (*for_each_active_monitor_output_cached)(const gsr_window *self, active_monitor_callback callback, void *userdata);
+ void *priv;
+};
+
+void gsr_window_destroy(gsr_window *self);
+
+/* Returns true if an event is available */
+bool gsr_window_process_event(gsr_window *self);
+XEvent* gsr_window_get_event_data(gsr_window *self);
+gsr_display_server gsr_window_get_display_server(const gsr_window *self);
+void* gsr_window_get_display(gsr_window *self);
+void* gsr_window_get_window(gsr_window *self);
+void gsr_window_for_each_active_monitor_output_cached(const gsr_window *self, active_monitor_callback callback, void *userdata);
+
+#endif /* GSR_WINDOW_H */
diff --git a/include/window/x11.h b/include/window/x11.h
new file mode 100644
index 0000000..e0c2948
--- /dev/null
+++ b/include/window/x11.h
@@ -0,0 +1,10 @@
+#ifndef GSR_WINDOW_X11_H
+#define GSR_WINDOW_X11_H
+
+#include "window.h"
+
+typedef struct _XDisplay Display;
+
+gsr_window* gsr_window_x11_create(Display *display);
+
+#endif /* GSR_WINDOW_X11_H */
diff --git a/include/window_texture.h b/include/window_texture.h
new file mode 100644
index 0000000..6ee5df4
--- /dev/null
+++ b/include/window_texture.h
@@ -0,0 +1,28 @@
+#ifndef WINDOW_TEXTURE_H
+#define WINDOW_TEXTURE_H
+
+#include "egl.h"
+
+typedef struct {
+ Display *display;
+ Window window;
+ Pixmap pixmap;
+ EGLImage image;
+ unsigned int texture_id;
+ int redirected;
+ gsr_egl *egl;
+} WindowTexture;
+
+/* Returns 0 on success */
+int window_texture_init(WindowTexture *window_texture, Display *display, Window window, gsr_egl *egl);
+void window_texture_deinit(WindowTexture *self);
+
+/*
+ This should ONLY be called when the target window is resized.
+ Returns 0 on success.
+*/
+int window_texture_on_resize(WindowTexture *self);
+
+unsigned int window_texture_get_opengl_texture_id(WindowTexture *self);
+
+#endif /* WINDOW_TEXTURE_H */
diff --git a/include/xnvctrl.h b/include/xnvctrl.h
new file mode 100644
index 0000000..33fc442
--- /dev/null
+++ b/include/xnvctrl.h
@@ -0,0 +1,45 @@
+#ifndef GSR_XNVCTRL_H
+#define GSR_XNVCTRL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define NV_CTRL_GPU_NVCLOCK_OFFSET 409
+#define NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET 410
+#define NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS 424
+#define NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS 425
+
+#define NV_CTRL_TARGET_TYPE_GPU 1
+
+#define NV_CTRL_STRING_PERFORMANCE_MODES 29
+
+typedef struct _XDisplay Display;
+
+typedef struct {
+ int type;
+ union {
+ struct {
+ int64_t min;
+ int64_t max;
+ } range;
+ struct {
+ unsigned int ints;
+ } bits;
+ } u;
+ unsigned int permissions;
+} NVCTRLAttributeValidValuesRec;
+
+typedef struct {
+ Display *display;
+ void *library;
+
+ int (*XNVCTRLQueryExtension)(Display *dpy, int *event_basep, int *error_basep);
+ int (*XNVCTRLSetTargetAttributeAndGetStatus)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, int value);
+ int (*XNVCTRLQueryValidTargetAttributeValues)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, NVCTRLAttributeValidValuesRec *values);
+ int (*XNVCTRLQueryTargetStringAttribute)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, char **ptr);
+} gsr_xnvctrl;
+
+bool gsr_xnvctrl_load(gsr_xnvctrl *self, Display *display);
+void gsr_xnvctrl_unload(gsr_xnvctrl *self);
+
+#endif /* GSR_XNVCTRL_H */