init go wgc

This commit is contained in:
pigeatgarlic 2026-04-04 10:11:21 +07:00
parent b4f481028c
commit 91f5da0781
4 changed files with 260 additions and 0 deletions

3
go/go.mod Normal file
View File

@ -0,0 +1,3 @@
module sunshine-wgc-go
go 1.25.0

105
go/main.go Normal file
View File

@ -0,0 +1,105 @@
package main
/*
#cgo CXXFLAGS: -std=c++20 -IC:/scoop/apps/msys2/current/mingw64/include
#cgo LDFLAGS: -lwindowsapp -lwtsapi32 -ld3d11 -ldxgi
#include "wgc.h"
extern void goFrameCallback(int width, int height, void* frame_data, void* user_data);
*/
import "C"
import (
"fmt"
"os"
"os/signal"
"runtime"
"runtime/cgo"
"syscall"
"unsafe"
)
func init() {
runtime.LockOSThread()
}
type Frame struct {
Width int
Height int
}
type Capturer struct {
OnFrame <-chan Frame
frameChan chan Frame
handle cgo.Handle
}
func NewCapturer() *Capturer {
c := &Capturer{
frameChan: make(chan Frame, 10),
}
c.OnFrame = c.frameChan
return c
}
func (c *Capturer) Start() error {
c.handle = cgo.NewHandle(c)
ret := C.start_capture((C.frame_callback_t)(unsafe.Pointer(C.goFrameCallback)), unsafe.Pointer(c.handle))
if ret != 0 {
c.handle.Delete()
return fmt.Errorf("failed to start capture: %d", int(ret))
}
return nil
}
func (c *Capturer) Stop() {
C.stop_capture()
if c.handle != 0 {
c.handle.Delete()
c.handle = 0
}
}
func (c *Capturer) handleFrame(width, height int, data unsafe.Pointer) {
select {
case c.frameChan <- Frame{Width: width, Height: height}:
default:
// Drop frame if channel is full
}
}
//export goFrameCallback
func goFrameCallback(width C.int, height C.int, frame_data unsafe.Pointer, user_data unsafe.Pointer) {
handle := cgo.Handle(user_data)
capturer := handle.Value().(*Capturer)
capturer.handleFrame(int(width), int(height), frame_data)
}
func main() {
fmt.Println("Starting WGC Screen Capture in Go...")
capturer := NewCapturer()
if err := capturer.Start(); err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer capturer.Stop()
fmt.Println("Capture started. Press Ctrl+C to stop.")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
count := 0
for {
select {
case frame := <-capturer.OnFrame:
count++
if count%60 == 0 {
fmt.Printf("Received 60 frames... Latest Resolution: %dx%d\n", frame.Width, frame.Height)
}
case <-sigChan:
fmt.Println("\nStopping capture...")
return
}
}
}

129
go/wgc.cpp Normal file
View File

@ -0,0 +1,129 @@
#define ____FIReference_1_boolean_INTERFACE_DEFINED__
#include "wgc.h"
#include <windows.graphics.capture.interop.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <iostream>
#include <future>
#include <thread>
using namespace winrt::Windows::Graphics::Capture;
using namespace winrt::Windows::Graphics::DirectX::Direct3D11;
namespace winrt {
struct
#if WINRT_IMPL_HAS_DECLSPEC_UUID
__declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
#endif
IDirect3DDxgiInterfaceAccess: ::IUnknown {
virtual HRESULT __stdcall GetInterface(REFIID id, void **object) = 0;
};
}
#if !WINRT_IMPL_HAS_DECLSPEC_UUID
static constexpr GUID GUID__IDirect3DDxgiInterfaceAccess = {
0xA9B3D012, 0x3DF2, 0x4EE3, { 0xB8, 0xD1, 0x86, 0x95, 0xF4, 0x57, 0xD3, 0xC1 }
};
template <>
constexpr auto
__mingw_uuidof<winrt::IDirect3DDxgiInterfaceAccess>() -> GUID const & {
return GUID__IDirect3DDxgiInterfaceAccess;
}
#endif
typedef HRESULT (WINAPI *pCreateDirect3D11DeviceFromDXGIDevice)(IDXGIDevice*, IInspectable**);
static frame_callback_t g_callback = nullptr;
static void* g_user_data = nullptr;
static GraphicsCaptureSession g_session{ nullptr };
static Direct3D11CaptureFramePool g_frame_pool{ nullptr };
static Direct3D11CaptureFramePool::FrameArrived_revoker g_frame_arrived_revoker;
extern "C" int start_capture(frame_callback_t callback, void* user_data) {
try {
winrt::init_apartment();
if (!GraphicsCaptureSession::IsSupported()) {
return -1;
}
g_callback = callback;
g_user_data = user_data;
// 1. Create D3D11 Device
winrt::com_ptr<ID3D11Device> d3d_device;
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr);
if (FAILED(hr)) return -2;
// 2. Create WinRT Device
winrt::com_ptr<IDXGIDevice> dxgi_device = d3d_device.as<IDXGIDevice>();
winrt::com_ptr<::IInspectable> inspectable;
HMODULE d3d11_dll = GetModuleHandleW(L"d3d11.dll");
if (!d3d11_dll) d3d11_dll = LoadLibraryW(L"d3d11.dll");
if (d3d11_dll) {
auto func = (pCreateDirect3D11DeviceFromDXGIDevice)GetProcAddress(d3d11_dll, "CreateDirect3D11DeviceFromDXGIDevice");
if (func) {
hr = func(dxgi_device.get(), inspectable.put());
} else { return -3; }
} else { return -3; }
if (FAILED(hr)) return -4;
IDirect3DDevice uwp_device = inspectable.as<IDirect3DDevice>();
// 3. Select Primary Monitor
HMONITOR hMonitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
// 4. Create Capture Item
auto monitor_factory = winrt::get_activation_factory<GraphicsCaptureItem, IGraphicsCaptureItemInterop>();
GraphicsCaptureItem item{ nullptr };
hr = monitor_factory->CreateForMonitor(hMonitor, winrt::guid_of<GraphicsCaptureItem>(), winrt::put_abi(item));
if (FAILED(hr)) return -5;
auto size = item.Size();
// 5. Create Frame Pool
g_frame_pool = Direct3D11CaptureFramePool::CreateFreeThreaded(uwp_device, winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, size);
// 6. Setup Event Handler
g_frame_arrived_revoker = g_frame_pool.FrameArrived(winrt::auto_revoke, [](Direct3D11CaptureFramePool const& sender, winrt::Windows::Foundation::IInspectable const&) {
auto frame = sender.TryGetNextFrame();
if (frame && g_callback) {
auto size = frame.ContentSize();
g_callback(size.Width, size.Height, winrt::get_abi(frame), g_user_data);
}
});
// 7. Start Session
g_session = g_frame_pool.CreateCaptureSession(item);
if (winrt::Windows::Foundation::Metadata::ApiInformation::IsPropertyPresent(L"Windows.Graphics.Capture.GraphicsCaptureSession", L"IsBorderRequired")) {
g_session.IsBorderRequired(false);
}
g_session.StartCapture();
return 0;
} catch (...) {
return -99;
}
}
extern "C" void stop_capture() {
if (g_session) {
g_session.Close();
g_session = nullptr;
}
if (g_frame_pool) {
g_frame_arrived_revoker.revoke();
g_frame_pool.Close();
g_frame_pool = nullptr;
}
}

23
go/wgc.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef WGC_H
#define WGC_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*frame_callback_t)(int width, int height, void* frame_data, void* user_data);
typedef struct {
int width;
int height;
int status;
} capture_status_t;
int start_capture(frame_callback_t callback, void* user_data);
void stop_capture();
#ifdef __cplusplus
}
#endif
#endif