mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2026-08-06 15:54:48 +00:00
init go wgc
This commit is contained in:
parent
b4f481028c
commit
91f5da0781
105
go/main.go
Normal file
105
go/main.go
Normal 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
129
go/wgc.cpp
Normal 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
23
go/wgc.h
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user