1.下载Spout2 源码
git clone https://github.com/leadedge/Spout2.git
2. 开始编译

3C74681C-DE64-4dad-8CBF-7270D1969994.png
- 如果需要
DirectX, 需要开启SPOUT_BUILD_SPOUTD -
Configure,Generate就能得到Visual Studio 2022项目; -
Open Project打开项目
3. 生成动态库

A30EB1A9-2B71-42ee-9616-B17D906BD67B.png
- 选择需要的系统架构,生成对应产物
4. 创建c++ 控制台项目,引入动态库
4.1 复制产物到自己的工程
-
third_party\Spout2\bin\x64
CE8C754F-A5B6-417b-AE16-24A6E936024B.png -
third_party\Spout2\lib\x64
817196C6-36CB-427c-A032-8577F3D961B1.png -
third_party\Spout2\include
8289410D-299E-412d-8DC3-6AEB8D58560A.png
4.2 配置工程引入动态库
-
$(ProjectDir)third_party\Spout2\include
9DDED3F6-E384-4d61-A189-DDCE731038FB.png -
$(ProjectDir)third_party\Spout2\lib\x64
8B78C5E4-478F-44fe-A625-1881C9A394B1.png xcopy /y /d /s /e "$(ProjectDir)third_party\Spout2\bin\x64\*.*" "$(TargetDir)"

64DB2943-2710-4b9d-809E-757695CA412A.png
5. 修改主文件
#include <iostream>
#include <windows.h>
#include <vector>
#include <ctime>
#include <iomanip>
#include <sstream>
// 1. 引入纯 DX11 专门类头文件
#include "SpoutDX.h"
// 2. 核心桥梁:强制让链接器去寻找微软原生 D3D11 图形库
#pragma comment(lib, "d3d11.lib")
// 3. 链接你编译出的全功能库
#pragma comment(lib, "SpoutDX.lib")
#pragma comment(lib, "Spout.lib")
// =================================================================
// 🔑 极简 8x16 点阵字库:支持数字 '0'-'9' 和冒号 ':'
// 每一个字节代表一行,1代表有像素(白色),0代表无像素(透明)
// =================================================================
const unsigned char Font8x16[11][16] = {
{0x00,0x3c,0x46,0x46,0x4e,0x56,0x66,0x66,0x66,0x66,0x6c,0x64,0x64,0x3c,0x00,0x00}, // '0'
{0x00,0x18,0x1c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00}, // '1'
{0x00,0x3c,0x46,0x46,0x46,0x06,0x0c,0x18,0x30,0x60,0x40,0x42,0x42,0x7e,0x00,0x00}, // '2'
{0x00,0x3c,0x46,0x46,0x06,0x06,0x1c,0x06,0x06,0x06,0x06,0x46,0x46,0x3c,0x00,0x00}, // '3'
{0x00,0x0c,0x1c,0x3c,0x2c,0x5c,0x4c,0x8c,0x8c,0xff,0x0c,0x0c,0x0c,0x1e,0x00,0x00}, // '4'
{0x00,0x7e,0x40,0x40,0x40,0x7c,0x46,0x06,0x06,0x06,0x06,0x46,0x46,0x3c,0x00,0x00}, // '5'
{0x00,0x1c,0x30,0x60,0x60,0x7c,0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00,0x00}, // '6'
{0x00,0x7e,0x46,0x46,0x06,0x0c,0x0c,0x18,0x18,0x30,0x30,0x30,0x30,0x30,0x00,0x00}, // '7'
{0x00,0x3c,0x66,0x66,0x66,0x3c,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00,0x00}, // '8'
{0x00,0x18,0x3c,0x66,0x66,0x66,0x66,0x66,0x3e,0x06,0x06,0x0c,0x18,0x38,0x00,0x00}, // '9'
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00} // ':'
};
// 根据字符获取字库索引
int GetFontIndex(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c == ':') return 10;
return -1;
}
// 🔑 在内存像素缓冲区上绘制单个 8x16 字符的函数 (带像素放大系数 scale,让字变大)
void DrawChar(std::vector<unsigned char>& buffer, unsigned int bufW, unsigned int bufH,
int startX, int startY, char c, unsigned char r, unsigned char g, unsigned char b, int scale = 4) {
int fontIdx = GetFontIndex(c);
if (fontIdx == -1) return;
// 遍历 16 行
for (int row = 0; row < 16; ++row) {
unsigned char rowData = Font8x16[fontIdx][row];
// 遍历 8 列 (从高位到低位检测二进制位)
for (int col = 0; col < 8; ++col) {
if ((rowData >> (7 - col)) & 0x01) {
// 1 表示有像素,根据 scale 放大系数,填充一个矩形区域
for (int sy = 0; sy < scale; ++sy) {
for (int sx = 0; sx < scale; ++sx) {
unsigned int pixelX = startX + col * scale + sx;
unsigned int pixelY = startY + row * scale + sy;
// 边界检查,防止内存越界
if (pixelX < bufW && pixelY < bufH) {
unsigned int idx = (pixelY * bufW + pixelX) * 4;
buffer[idx + 0] = r; // R
buffer[idx + 1] = g; // G
buffer[idx + 2] = b; // B
buffer[idx + 3] = 255; // A (不透明)
}
}
}
}
}
}
}
// 🔑 在内存像素缓冲区上绘制整串字符串
void DrawString(std::vector<unsigned char>& buffer, unsigned int bufW, unsigned int bufH,
int startX, int startY, const std::string& str, unsigned char r, unsigned char g, unsigned char b, int scale = 4) {
int currentX = startX;
for (char c : str) {
DrawChar(buffer, bufW, bufH, currentX, startY, c, r, g, b, scale);
currentX += 8 * scale + 2; // 每个字符横向右移,2为字间距
}
}
int main() {
std::cout << "===================================================" << std::endl;
std::cout << "=== Spout2 纯 DX11 裸像素投递 (包含实时系统时间) ===" << std::endl;
std::cout << "===================================================" << std::endl;
spoutDX sender;
if (!sender.OpenDirectX11()) {
std::cout << "【错误】spoutDX 初始化 DX11 环境失败!" << std::endl;
return -1;
}
const char* streamName = "My_DX11_Pixel_Stream";
sender.SetSenderName(streamName);
unsigned int width = 1920;
unsigned int height = 1080;
std::cout << "【成功】spoutDX 广播全线就绪!通道名: " << streamName << std::endl;
// 开辟 1080P RGBA 像素内存
std::vector<unsigned char> pixelBuffer(width * height * 4, 0);
std::cout << "\n>>> 正在实时刷新时间并投递画面,请在 OBS 里观察..." << std::endl;
std::cout << ">>> 提示:在当前窗口按下 [ESC] 键可安全退出程序。\n" << std::endl;
unsigned char colorOffset = 0;
// 主循环
while (true) {
colorOffset += 1; // 背景渐变速度
// 1. 渲染背景底色(随时间渐变的深色流体背景,方便看清白色的时间字)
for (unsigned int i = 0; i < width * height; ++i) {
unsigned int idx = i * 4;
pixelBuffer[idx + 0] = colorOffset; // R
pixelBuffer[idx + 1] = 40; // G
pixelBuffer[idx + 2] = 90; // B
pixelBuffer[idx + 3] = 255; // A
}
// 2. 获取当前 Windows 系统的高精度本地时间
std::time_t t = std::time(nullptr);
std::tm now;
localtime_s(&now, &t);
// 格式化时间字符串为 "HH:MM:SS"
std::ostringstream timeStream;
timeStream << std::setfill('0')
<< std::setw(2) << now.tm_hour << ":"
<< std::setw(2) << now.tm_min << ":"
<< std::setw(2) << now.tm_sec;
std::string timeStr = timeStream.str();
// 🔑 3. 核心灌入:把时间文字直接画到像素内存缓冲区中
// 参数:像素矩阵, 宽, 高, 起始X(100), 起始Y(100), 时间字符串, 颜色R(255), G(255), B(255), 放大倍数(5倍,让字很大很清晰)
DrawString(pixelBuffer, width, height, 100, 100, timeStr, 255, 255, 255, 5);
// 4. 清理 Alpha 并发送图像
sender.spoutcopy.ClearAlpha(pixelBuffer.data(), width, height, 255);
sender.SendImage(pixelBuffer.data(), width, height);
// 5. 帧率锁死 60 帧
sender.HoldFps(60);
if (GetAsyncKeyState(VK_ESCAPE)) break;
}
std::cout << "正在关闭 spoutDX 通道..." << std::endl;
sender.ReleaseSender();
sender.CloseDirectX11();
std::cout << "程序已安全退出。" << std::endl;
return 0;
}
6. 使用obs 添加我们共享的纹理

59F49A38-5720-4621-9399-807165A2AC62.png




