118 lines
3.5 KiB
C++
118 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <functional>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <map>
|
|
#include <cstdint>
|
|
|
|
#ifdef __linux__
|
|
#include <spa/utils/hook.h>
|
|
#include <spa/pod/pod.h>
|
|
#endif
|
|
|
|
// Forward declarations for Pipewire/sdbus to avoid header pollution
|
|
struct pw_thread_loop;
|
|
struct pw_stream;
|
|
struct pw_context;
|
|
|
|
namespace sdbus {
|
|
class IConnection;
|
|
class IProxy;
|
|
class Variant;
|
|
}
|
|
|
|
namespace scar {
|
|
|
|
class VideoEncoder; // Forward declaration
|
|
|
|
enum class ScreenCaptureBackend {
|
|
FFMPEG_X11, // X11 via ffmpeg
|
|
FFMPEG_WAYLAND, // Wayland via ffmpeg + portal
|
|
FFMPEG_WINDOWS, // Windows GDI via ffmpeg
|
|
PORTAL_PIPEWIRE // xdg-desktop-portal + Pipewire (Wayland/Hyprland)
|
|
};
|
|
|
|
// Screen capture supporting multiple backends
|
|
class ScreenCapture {
|
|
public:
|
|
ScreenCapture();
|
|
~ScreenCapture();
|
|
|
|
// Auto-detect and start screen capture
|
|
bool start();
|
|
|
|
// Start with specific backend
|
|
bool start(ScreenCaptureBackend backend);
|
|
|
|
// Stop capturing
|
|
void stop();
|
|
|
|
// Check if currently capturing
|
|
bool isCapturing() const { return capturing_; }
|
|
|
|
// Set frame callback
|
|
using FrameCallback = std::function<void(const std::vector<uint8_t>& frameData, int width, int height)>;
|
|
void setFrameCallback(FrameCallback callback);
|
|
|
|
private:
|
|
ScreenCaptureBackend detectBestBackend();
|
|
|
|
bool startX11Capture();
|
|
bool startWaylandCapture();
|
|
bool startWindowsCapture();
|
|
bool startPortalCapture();
|
|
|
|
// sdbus Portal methods
|
|
bool initPortalConnection();
|
|
void cleanupPortalConnection();
|
|
std::string createPortalSession();
|
|
bool selectPortalSources(const std::string& session_handle);
|
|
bool startPortalSession(const std::string& session_handle, uint32_t& node_id);
|
|
int openPipeWireRemote(const std::string& session_handle);
|
|
uint32_t getStreamsNodeId(const std::string& session_handle);
|
|
|
|
// Portal async response handlers
|
|
void onCreateSessionResponse(uint32_t response, const std::map<std::string, sdbus::Variant>& results);
|
|
void onSelectSourcesResponse(uint32_t response, const std::map<std::string, sdbus::Variant>& results);
|
|
void onStartSessionResponse(uint32_t response, const std::map<std::string, sdbus::Variant>& results);
|
|
void setupResponseSignal(const std::string& request_handle,
|
|
std::function<void(uint32_t, const std::map<std::string, sdbus::Variant>&)> callback);
|
|
|
|
// Pipewire methods
|
|
bool initPipewire(int fd, uint32_t node_id);
|
|
void cleanupPipewire();
|
|
static void onStreamProcess(void* userdata);
|
|
static void onStreamParamChanged(void* userdata, uint32_t id, const struct spa_pod* param);
|
|
|
|
bool capturing_;
|
|
ScreenCaptureBackend backend_;
|
|
FrameCallback frameCallback_;
|
|
|
|
// sdbus members
|
|
std::shared_ptr<sdbus::IConnection> portal_connection_;
|
|
std::unique_ptr<sdbus::IProxy> screencast_proxy_;
|
|
std::vector<std::unique_ptr<sdbus::IProxy>> request_proxies_; // Keep request proxies alive for signal handlers
|
|
std::string session_path_;
|
|
std::string pending_request_path_;
|
|
bool portal_session_ready_;
|
|
bool portal_sources_selected_;
|
|
bool portal_started_;
|
|
|
|
// Pipewire members
|
|
pw_thread_loop* pw_loop_;
|
|
pw_stream* pw_stream_;
|
|
pw_context* pw_context_;
|
|
spa_hook stream_listener_;
|
|
|
|
int frame_width_;
|
|
int frame_height_;
|
|
uint32_t frame_format_; // SPA video format from PipeWire
|
|
|
|
// Video encoder
|
|
std::unique_ptr<VideoEncoder> encoder_;
|
|
};
|
|
|
|
} // namespace scar
|