# Windows Host → Android Client 视频流向详解 本文档详细说明 Windows 设备作为 Host,Android 设备作为 Client 时的完整视频流向。 ## 完整数据流图 ``` ┌─────────────────────────────────────────────────────────────────┐ │ Windows Host 设备(发送端) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ [1] 屏幕捕获层 │ │ Desktop Duplication API / GDI BitBlt │ │ ↓ 输出:D3D11 纹理(GPU 纹理,零拷贝) │ │ │ │ [2] 编码层 │ │ Media Foundation H.264 硬件编码器 / D3D11 Video Encoder │ │ ↓ 输出:H.264 NAL 单元(压缩后的视频数据) │ │ │ │ [3] 协议封装层 │ │ FlatBuffers 序列化 │ │ - 帧头信息(时间戳、分辨率、帧类型 I/P) │ │ - 编码数据(NAL 单元) │ │ ↓ 输出:序列化的协议消息(二进制数据) │ │ │ │ [4] 网络传输层 │ │ UDP Socket (USB RNDIS / Wi-Fi / 以太网) │ │ - 分包处理(MTU 限制,通常 1500 字节) │ │ - 重传机制(关键帧 I-frame) │ │ ↓ 输出:UDP 数据包 │ │ │ └─────────────────────────────────────────────────────────────────┘ ↓ 网络传输 ↓ 延迟:1-5ms (USB RNDIS) / 5-20ms (Wi-Fi) ┌─────────────────────────────────────────────────────────────────┐ │ Android Client 设备(接收端) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ [5] 网络接收层 │ │ UDP Socket 接收 │ │ - 包重组(处理分包) │ │ - 顺序保证(处理乱序) │ │ ↓ 输出:完整的协议消息 │ │ │ │ [6] 协议解析层 │ │ FlatBuffers 反序列化 │ │ - 提取帧头信息 │ │ - 提取编码数据(NAL 单元) │ │ ↓ 输出:H.264 NAL 单元 │ │ │ │ [7] 解码层 │ │ AMediaCodec (H.264 硬件解码器) │ │ ↓ 输出:GPU 纹理(AHardwareBuffer,零拷贝) │ │ │ │ [8] 渲染层 │ │ OpenGL ES / ANativeWindow │ │ - 纹理复制到渲染目标 │ │ - Surface 更新 │ │ ↓ 输出:渲染后的画面 │ │ │ │ [9] 显示输出 │ │ Android Surface / SurfaceView │ │ - 直接显示在 Android 屏幕上 │ │ - 支持全屏或窗口模式 │ │ ↓ 最终显示在 Android 设备屏幕上 │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ## 各阶段详细说明 ### Windows Host 端 #### [1] 屏幕捕获层 **技术方案:Desktop Duplication API(推荐)** ```cpp // platforms/windows/src/capture/screen_capture.cpp #include #include class ScreenCapture { public: bool Initialize() { // 创建 D3D11 设备 D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device_, nullptr, &context_ ); // 获取 DXGI 输出 IDXGIOutput* output = nullptr; // ... 获取主显示器输出 // 创建 Desktop Duplication IDXGIOutput1* output1 = nullptr; output->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output1); output1->DuplicateOutput(device_, &duplication_); return true; } bool CaptureFrame(ID3D11Texture2D** texture) { DXGI_OUTDUPL_FRAME_INFO frameInfo; IDXGIResource* resource = nullptr; // 获取桌面帧 HRESULT hr = duplication_->AcquireNextFrame( 0, &frameInfo, &resource ); if (SUCCEEDED(hr)) { // 获取纹理 resource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)texture); duplication_->ReleaseFrame(); return true; } return false; } private: ID3D11Device* device_ = nullptr; ID3D11DeviceContext* context_ = nullptr; IDXGIOutputDuplication* duplication_ = nullptr; }; ``` **特点:** - 使用 Desktop Duplication API(Windows 8+) - 直接获取 GPU 纹理,零拷贝 - 支持多显示器 - 性能最优 **备选方案:GDI BitBlt** - 适用于较旧的 Windows 版本 - 需要 CPU 拷贝,性能较低 #### [2] 编码层 **技术方案:Media Foundation H.264 硬件编码器** ```cpp // platforms/windows/src/codec/windows_h264_encoder.cpp #include #include #include class WindowsH264Encoder { public: bool Initialize(int width, int height, int bitrate, int fps) { // 创建 Media Foundation 编码器 IMFActivate** activates = nullptr; UINT32 count = 0; MFTEnum( MFT_CATEGORY_VIDEO_ENCODER, MFT_ENUM_FLAG_HARDWARE, &inputType, nullptr, &activates, &count ); // 选择 H.264 编码器 activates[0]->ActivateObject(IID_PPV_ARGS(&encoder_)); // 配置编码器 IMFMediaType* inputType = nullptr; MFCreateMediaType(&inputType); inputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); inputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); inputType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); MFSetAttributeSize(inputType, MF_MT_FRAME_SIZE, width, height); MFSetAttributeRatio(inputType, MF_MT_FRAME_RATE, fps, 1); IMFMediaType* outputType = nullptr; MFCreateMediaType(&outputType); outputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); outputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); outputType->SetUINT32(MF_MT_AVG_BITRATE, bitrate); outputType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); encoder_->SetInputType(0, inputType, 0); encoder_->SetOutputType(0, outputType, 0); encoder_->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0); encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); return true; } bool EncodeFrame(ID3D11Texture2D* inputTexture, std::vector& output) { // 将 D3D11 纹理转换为 Media Foundation Sample IMFSample* sample = nullptr; // ... 转换逻辑 // 编码 encoder_->ProcessInput(0, sample, 0); // 获取编码输出 MFT_OUTPUT_DATA_BUFFER outputBuffer = {}; DWORD status = 0; encoder_->ProcessOutput(0, 1, &outputBuffer, &status); // 提取编码数据 IMFMediaBuffer* buffer = nullptr; outputBuffer.pSample->ConvertToContiguousBuffer(&buffer); BYTE* data = nullptr; DWORD length = 0; buffer->Lock(&data, nullptr, &length); output.assign(data, data + length); buffer->Unlock(); return true; } private: IMFTransform* encoder_ = nullptr; }; ``` **特点:** - 使用 Media Foundation 硬件编码器 - 支持 H.264 编码 - 硬件加速,CPU 占用低 - 支持动态码率调整 **备选方案:D3D11 Video Encoder** - 更底层的 API - 性能可能更好,但实现更复杂 #### [3] 协议封装层 ```cpp // core/src/protocol/message_serializer.cpp #include "displayflow/core/protocol/message_serializer.h" class MessageSerializer { public: ByteArray SerializeVideoFrame(const VideoFrame& frame) { // 使用 FlatBuffers 序列化 flatbuffers::FlatBufferBuilder builder; auto frameData = builder.CreateVector(frame.data.data(), frame.data.size()); auto message = CreateVideoFrameMessage( builder, frame.timestamp, frame.width, frame.height, frame.frameType, // I-frame or P-frame frameData ); builder.Finish(message); return ByteArray(builder.GetBufferPointer(), builder.GetBufferPointer() + builder.GetSize()); } }; ``` #### [4] 网络传输层 ```cpp // core/src/network/network_manager.cpp class NetworkManager { public: bool SendVideoFrame(const ByteArray& data) { // UDP Socket 发送 // 处理分包(MTU 限制) const size_t MTU = 1500; size_t offset = 0; while (offset < data.size()) { size_t chunkSize = std::min(MTU, data.size() - offset); sendto(socket_, data.data() + offset, chunkSize, 0, (sockaddr*)&clientAddr_, sizeof(clientAddr_)); offset += chunkSize; } return true; } }; ``` ### Android Client 端 #### [5] 网络接收层 ```cpp // core/src/network/network_manager.cpp class NetworkManager { public: bool ReceiveVideoFrame(ByteArray& data) { // UDP Socket 接收 // 包重组和顺序保证 char buffer[MTU]; sockaddr_in fromAddr; socklen_t addrLen = sizeof(fromAddr); ssize_t received = recvfrom(socket_, buffer, MTU, 0, (sockaddr*)&fromAddr, &addrLen); if (received > 0) { // 处理分包重组 // 保证顺序 data.insert(data.end(), buffer, buffer + received); return true; } return false; } }; ``` #### [6] 协议解析层 ```cpp // core/src/protocol/message_serializer.cpp class MessageSerializer { public: bool DeserializeVideoFrame(const ByteArray& data, VideoFrame& frame) { // FlatBuffers 反序列化 auto message = GetVideoFrameMessage(data.data()); frame.timestamp = message->timestamp(); frame.width = message->width(); frame.height = message->height(); frame.frameType = message->frameType(); auto frameData = message->data(); frame.data.assign(frameData->begin(), frameData->end()); return true; } }; ``` #### [7] 解码层 **技术方案:AMediaCodec 硬件解码器** ```cpp // platforms/android/src/render/render_engine.cpp #include #include class RenderEngine { public: bool Initialize(int width, int height) { // 创建解码器 const char* mimeType = "video/avc"; decoder_ = AMediaCodec_createDecoderByType(mimeType); // 配置解码器 AMediaFormat* format = AMediaFormat_new(); AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, width); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height); // 获取输出 Surface(用于渲染) ANativeWindow* surface = GetOutputSurface(); AMediaCodec_configure(decoder_, format, surface, nullptr, 0); AMediaCodec_start(decoder_); return true; } bool DecodeFrame(const ByteArray& h264Data) { // 输入编码数据 ssize_t inputBufferId = AMediaCodec_dequeueInputBuffer(decoder_, 10000); if (inputBufferId >= 0) { size_t inputSize = 0; uint8_t* inputBuffer = AMediaCodec_getInputBuffer( decoder_, inputBufferId, &inputSize); memcpy(inputBuffer, h264Data.data(), h264Data.size()); AMediaCodec_queueInputBuffer( decoder_, inputBufferId, 0, h264Data.size(), 0, 0); } // 获取解码输出 AMediaCodecBufferInfo bufferInfo; ssize_t outputBufferId = AMediaCodec_dequeueOutputBuffer( decoder_, &bufferInfo, 10000); if (outputBufferId >= 0) { // 解码完成,直接渲染到 Surface(零拷贝) AMediaCodec_releaseOutputBuffer(decoder_, outputBufferId, true); return true; } return false; } private: AMediaCodec* decoder_ = nullptr; }; ``` **特点:** - 使用 AMediaCodec 硬件解码器 - 直接输出到 Surface,零拷贝 - 硬件加速,性能最优 #### [8] 渲染层 **技术方案:ANativeWindow + OpenGL ES** ```cpp // platforms/android/src/render/render_engine.cpp #include #include class RenderEngine { public: bool Initialize(ANativeWindow* window) { nativeWindow_ = window; // 创建 EGL 上下文 display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display_, nullptr, nullptr); EGLConfig config; EGLint numConfigs; eglChooseConfig(display_, attribs, &config, 1, &numConfigs); surface_ = eglCreateWindowSurface(display_, config, nativeWindow_, nullptr); context_ = eglCreateContext(display_, config, EGL_NO_CONTEXT, contextAttribs); eglMakeCurrent(display_, surface_, surface_, context_); return true; } void RenderFrame() { // 如果使用 AMediaCodec 直接输出到 Surface,这里可能不需要额外渲染 // 或者使用 OpenGL ES 进行后处理 eglSwapBuffers(display_, surface_); } private: ANativeWindow* nativeWindow_ = nullptr; EGLDisplay display_ = nullptr; EGLSurface surface_ = nullptr; EGLContext context_ = nullptr; }; ``` **特点:** - 使用 ANativeWindow 作为渲染目标 - 支持 OpenGL ES 后处理 - 直接显示在 Android Surface 上 #### [9] 显示输出 **技术方案:Android Surface / SurfaceView** ```cpp // 在 Java/Kotlin 层创建 SurfaceView // 或使用 ANativeWindow 直接显示 // 在 C++ 层获取 Surface ANativeWindow* GetOutputSurface() { // 从 Java 层传入 Surface,转换为 ANativeWindow // 或直接使用 ANativeWindow return nativeWindow_; } ``` ## 延迟分析 | 阶段 | 操作 | 典型延迟 | 优化措施 | |------|------|----------|----------| | 1. 屏幕捕获 | Desktop Duplication API | 1-3ms | GPU 纹理,零拷贝 | | 2. 编码 | H.264 硬件编码 | 2-5ms | Media Foundation 硬件编码器 | | 3. 协议封装 | FlatBuffers 序列化 | <1ms | 零拷贝序列化 | | 4. 网络传输 | UDP 传输 | 1-20ms | USB RNDIS 优先 | | 5. 网络接收 | UDP 接收 | <1ms | 高效 Socket 处理 | | 6. 协议解析 | FlatBuffers 反序列化 | <1ms | 零拷贝反序列化 | | 7. 解码 | H.264 硬件解码 | 2-5ms | AMediaCodec 硬件解码器 | | 8. 渲染 | OpenGL ES / Surface | 1-2ms | GPU 渲染 | | 9. 显示 | Android Surface 输出 | 0-1ms | 直接 Surface 显示 | | **总计** | **端到端延迟** | **<30ms** | **(USB RNDIS 模式)** | ## 关键特性 1. **零拷贝**: - Windows 端:Desktop Duplication → D3D11 纹理 → 编码器(GPU) - Android 端:解码器 → Surface(GPU),无需 CPU 拷贝 2. **硬件加速**: - Windows:Media Foundation 硬件编码器 - Android:AMediaCodec 硬件解码器 3. **自适应码率**: - 根据网络状况动态调整编码参数 - 关键帧(I-frame)重传机制 4. **多显示器支持**: - Windows 端支持选择特定显示器捕获 - 支持多显示器扩展模式 ## 实现优先级 1. **第一阶段**:基础功能 - [ ] Windows 屏幕捕获(Desktop Duplication API) - [ ] Windows H.264 编码(Media Foundation) - [ ] Android H.264 解码(AMediaCodec) - [ ] Android Surface 显示 2. **第二阶段**:优化 - [ ] 零拷贝优化 - [ ] 帧率控制 - [ ] 自适应码率 3. **第三阶段**:高级功能 - [ ] 多显示器支持 - [ ] 延迟优化 - [ ] 错误恢复