From 69055627323927882b020e5937e706270a77953f Mon Sep 17 00:00:00 2001 From: huanglinhuan Date: Thu, 18 Dec 2025 23:36:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8D=95=E8=8E=B7=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E4=BF=9D=E5=AD=98=E5=88=B0=E6=96=87=E4=BB=B6=E5=92=8C?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BC=96=E8=AF=91=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/windows_sender/README.md | 49 +++++++++++++++++++++++++---------- demo/windows_sender/main.cpp | 21 +++++++++++++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/demo/windows_sender/README.md b/demo/windows_sender/README.md index 2b35cd7..e7054e1 100644 --- a/demo/windows_sender/README.md +++ b/demo/windows_sender/README.md @@ -1,20 +1,24 @@ # Windows Sender Demo This is a simplified demo of the Windows Host sender for DisplayFlow. + It demonstrates: 1. Screen Capture using Desktop Duplication API (DXGI). -2. Hardware H.264 Encoding using Media Foundation (MF). +2. Hardware/Software H.264 Encoding using **FFmpeg** (switched from Media Foundation for better compatibility). 3. Network Transmission using UDP. ## Prerequisites - Windows 10/11 -- Visual Studio 2019 or later (with C++ Desktop Development) +- Visual Studio 2022 or later (with C++ Desktop Development) - CMake 3.10+ +- **FFmpeg Development Libraries** (Shared) + - Ensure you have the `include` and `lib` directories. + - Example path: `D:\tools\ffmpeg-8.0.1-full_build-shared` ## Build -1. Open a terminal (Developer Command Prompt for VS). +1. Open a terminal (Developer Command Prompt for VS or PowerShell). 2. Navigate to this directory: ```cmd cd demo\windows_sender @@ -24,30 +28,49 @@ It demonstrates: mkdir build cd build ``` -4. Configure and Build: +4. Configure and Build (Replace path with your FFmpeg location): ```cmd - cmake .. + cmake .. -DFFMPEG_ROOT="D:/tools/ffmpeg-8.0.1-full_build-shared" cmake --build . --config Release ``` + *Note: If your FFmpeg is installed elsewhere, change the path accordingly.* + +5. **Important**: Copy FFmpeg DLLs to the executable directory. + - Copy `avcodec-*.dll`, `avutil-*.dll`, `swscale-*.dll`, `avformat-*.dll` from your FFmpeg `bin` directory to `demo\windows_sender\build\Release`. ## Run -Run the executable with target IP and Port (optional): +Run the executable with optional arguments: Target IP, Port, and Output File. ```cmd -.\Release\WindowsSenderDemo.exe +.\Release\WindowsSenderDemo.exe [TargetIP] [Port] [OutputFile] ``` -Example: -```cmd -.\Release\WindowsSenderDemo.exe 192.168.1.100 8888 -``` +### Examples + +1. **Basic Streaming** (Default: 127.0.0.1:8888): + ```cmd + .\Release\WindowsSenderDemo.exe + ``` + +2. **Specify Target**: + ```cmd + .\Release\WindowsSenderDemo.exe 192.168.1.100 8888 + ``` + +3. **Stream and Save to File** (for debugging): + ```cmd + .\Release\WindowsSenderDemo.exe 127.0.0.1 8888 debug.h264 + ``` + You can play the saved `debug.h264` using VLC player to verify the encoding quality. ## Implementation Details - **ScreenCapture**: Uses `IDXGIOutputDuplication` to capture desktop frames. -- **VideoEncoder**: Uses `IMFTransform` (Media Foundation) to encode frames to H.264. - - *Note*: This demo attempts to feed RGB32 textures to the encoder. If the hardware encoder only supports NV12, conversion logic is needed (not fully implemented in this minimal demo). +- **VideoEncoder**: + - Uses **FFmpeg (libx264)** for encoding. + - Performs **BGRA to YUV420P** color conversion using `libswscale`. + - Configured for low latency (`zerolatency` tune, `ultrafast` preset). - **NetworkSender**: Fragments the H.264 stream into UDP packets (MTU ~1400 bytes) and sends them to the target. ## Protocol diff --git a/demo/windows_sender/main.cpp b/demo/windows_sender/main.cpp index 1ada164..24b97d6 100644 --- a/demo/windows_sender/main.cpp +++ b/demo/windows_sender/main.cpp @@ -4,16 +4,33 @@ #include #include #include +#include int main(int argc, char* argv[]) { std::string ip = "127.0.0.1"; int port = 8888; + std::string outputFileName = ""; if (argc > 1) ip = argv[1]; if (argc > 2) port = std::stoi(argv[2]); + if (argc > 3) outputFileName = argv[3]; std::cout << "Starting Windows Sender Demo..." << std::endl; std::cout << "Target: " << ip << ":" << port << std::endl; + if (!outputFileName.empty()) { + std::cout << "Output File: " << outputFileName << std::endl; + } + + // Debug: Open file to save H.264 stream if filename is provided + std::ofstream outFile; + if (!outputFileName.empty()) { + outFile.open(outputFileName, std::ios::binary); + if (outFile.is_open()) { + std::cout << "Debug: Saving video stream to '" << outputFileName << "'" << std::endl; + } else { + std::cerr << "Warning: Failed to open output file '" << outputFileName << "'" << std::endl; + } + } ScreenCapture capture; if (!capture.Initialize()) { @@ -67,6 +84,10 @@ int main(int argc, char* argv[]) { sender.SendFrame(encodedData, timestamp, width, height, isKeyFrame); // std::cout << "Sent frame: " << encodedData.size() << " bytes, Key: " << isKeyFrame << std::endl; + + if (outFile.is_open()) { + outFile.write(reinterpret_cast(encodedData.data()), encodedData.size()); + } } } capture.ReleaseFrame();