# PC端wpf

# nuget工具篇

### nuget包工具命令

```
//删除包
dotnet nuget delete -s https://nuget.lingyanspace.com/v3/index.json LingYanAutoUpdate 1.0.0 -k nugetlingyanspace --non-interactive


```

# 课纲目录

#### <span style="color: rgb(53, 152, 219);"> **模块Ⅰ：WPF高阶技术精讲**</span>

<span style="color: rgb(22, 145, 121);">**深入掌握自定义控件**</span>

```
主要是附加属性与控件加载部分
```

<span style="color: rgb(22, 145, 121);"> **深入掌握控件模板与数据模板**</span>

```
理解控件模板当中包含数据模板
数据模板当中又可以包含控件模板
来回组合学习
最终以模板选择器来弥补遗漏的部分
```

<span style="color: #169179;">**深入掌握资源样式与动态主题**</span>

```
资源字典如何加载
静态资源与动态资源区别
主题动态切换核心理念
以及后续写项目的规范
```

##### 埋坑

```
此处本来是想带大家完完全全手写一个wpf控件库

但是由于很多技术涉及到c#代码，所以先讲后续，高阶通信模块讲完之后再返回这儿

然后还有MAUI部分公开课要把讲xaml基础控件正好中间多学点儿做个过渡。

但是主要的xaml技术就是这三节内容和B站wpf公开课那一套视频看完
```

#### <span style="color: rgb(22, 145, 121);"> **<span style="color: rgb(53, 152, 219);">模块Ⅱ：高阶通信与高阶模式加并发控制</span>**</span>

**基础知识**

```
1、进程与线程 ：
2、进程与线程的区别。
3、线程生命周期（启动、运行、终止）。
4、同步与异步编程 ：
5、同步与异步的基本概念。
6、异步编程的优势与挑战。
7、C# 中的多线程基础 ：
8、Thread类和Task类。
9、如何创建和管理线程。
10、WPF 中的线程模型 ：
11、UI 线程与后台线程的关系。
12、使用Dispatcher更新 UI。
```

 **协议解析与错误处理模块**

```
1、Span<T> 优化二进制协议解析，使用Span<T>提高内存操作效率。
2、错误处理模式 ：异常传播与CancellationToken的结合。
3、WPF 中的应用 ：在 WPF 应用中处理网络通信错误，实现用户友好的错误提示机制。
```

**虚拟通信模拟模块**

```
1、TcpListener 模拟网络设备 ：
创建一个简单的 TCP 服务器。
处理客户端连接和数据传输。
2、SignalR 的内存模拟 ：
不依赖真实服务端的情况下，使用 SignalR 模拟实时通信。
3、WPF 中的应用 ：
在 WPF 应用中集成虚拟通信模拟工具。
实现一个简单的聊天窗口或状态监控界面。
```

**并发控制与任务调度模块**

```
1、线程同步机制 ：MonitorMutex,Semaphore等同步原语，Dispatcher与BackgroundWorker的协作。
2、异步编程与任务调度 ：async/await的深入讲解，使用TaskScheduler实现优先级队列。
3、TPL Dataflow 数据流水线 ：构建高效的生产者-消费者模型
4、WPF 中的应用 ：在 WPF 中实现多线程任务调度，避免 UI 冻结问题。
```

**高效数据处理模块**

```
1、TPL 数据流 ：构建数据流管道，实现并行数据处理。
2、内存管理 ：使用Span<T>和Memory<T>减少内存分配。
3、WPF 中的应用 ：在 WPF 中实现高性能的数据流处理，示例：实时处理传感器数据并在 UI 上显示。
```

**高级通信技术模块**

```
1、WebSocket 通信 ：使用System.Net.WebSockets实现 WebSocket 客户端和服务端。
2、SignalR 实时通信 ：构建基于 SignalR 的实时应用
3、跨平台通信 ：使用 gRPC 或 RESTful API 实现跨平台通信。
4、WPF 中的应用 ：在 WPF 中集成 WebSocket 或 SignalR，实现一个实时更新的仪表盘或聊天界面。
```

**性能优化与调试模块**

```
1、常见问题与解决方案 ：死锁与竞争条件。内存泄漏与资源耗尽。
2、WPF 中的性能优化 ：减少 UI 线程负担。使用虚拟化技术优化列表显示。
```

**实践巩固**

```
 实际项目实践模块
 
目标：
通过实际项目巩固所学知识。

项目主题 ：
实现一个简单的聊天应用。
构建一个实时监控系统。

功能要求 ：
支持多线程和异步通信。
使用协议解析和错误处理机制。
集成 SignalR 或 WebSocket。

WPF 界面开发 ：
设计一个用户友好的界面。
实现动态更新和多线程交互。

聊天应用 ：
使用 SignalR 实现实时消息传递。
使用Dispatcher更新聊天记录。

监控系统 ：
使用 TPL Dataflow 处理传感器数据。
使用TaskScheduler优化任务调度。
```

#### <span style="color: rgb(53, 152, 219);">**模块Ⅲ：高阶项目实战（全栈）**</span>

  
<span style="color: rgb(22, 145, 121);"> **3.1 综合项目案例**</span>  
<span style="color: rgb(22, 145, 121);"> **3.1.1 虚拟监控系统**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用ICollectionView实现动态数据过滤**</span>  
<span style="color: rgb(22, 145, 121);">**- 基于VisualStateManager的报警状态可视化**</span>

<span style="color: rgb(22, 145, 121);"> **3.1.2 日志与权限管理**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用NLog实现日志分级（Debug/Info/Error）**</span>  
<span style="color: rgb(22, 145, 121);">**- 基于角色的权限系统（RBAC）**</span>

  
<span style="color: rgb(22, 145, 121);"> **3.2 精细化案例**</span>  
<span style="color: rgb(22, 145, 121);"> **3.2.1 数据可视化**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用OxyPlot实现动态波形图**</span>  
<span style="color: rgb(22, 145, 121);">**- 基于WriteableBitmap的实时图像处理**</span>

####   
<span style="color: rgb(53, 152, 219);"> **模块Ⅳ：前沿技术与扩展**</span>

  
<span style="color: rgb(22, 145, 121);"> **4.1 跨平台开发**</span>  
<span style="color: rgb(22, 145, 121);"> **4.1.1 .NET MAUI深度集成**</span>  
<span style="color: rgb(22, 145, 121);">**- 共享业务逻辑层与UI分离设计**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用SkiaSharp实现跨平台绘图**</span>

<span style="color: rgb(22, 145, 121);"> **4.1.2 WPF与Web技术结合**</span>  
<span style="color: rgb(22, 145, 121);">**- 嵌入WebView2实现混合开发**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用WebAssembly与Blazor交互**</span>

<span style="color: rgb(22, 145, 121);"> **4.2 人工智能集成**</span>  
<span style="color: rgb(22, 145, 121);"> **4.2.1 机器学习模型集成**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用ML.NET实现本地预测**</span>  
<span style="color: rgb(22, 145, 121);">**- 基于ONNX的图像识别**</span>

<span style="color: rgb(22, 145, 121);"> **4.2.2 数据分析与可视化**</span>  
<span style="color: rgb(22, 145, 121);">**- 使用LiveCharts实现动态仪表盘**</span>  
<span style="color: rgb(22, 145, 121);">**- 基于Parallel.For的并行数据处理**</span>

# 打包篇

## inno 

### 中文环境【ChineseSimplified.isl】

[ChineseSimplified.isl](https://book.lingyanspace.com/attachments/2)

### isl环境中文

```
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
```

# 完整的通信链路

### **OSI 七层模型与协议对照表**

<table id="bkmrk-%E5%B1%82%E6%AC%A1-%E5%8A%9F%E8%83%BD-%E5%B8%B8%E8%A7%81%E5%8D%8F%E8%AE%AE%2F%E6%A0%87%E5%87%86-%E5%B7%A5%E4%B8%9A%E5%8D%8F%E8%AE%AE-%E7%89%A9" style="width: 100%; height: 354.986px;"><thead><tr style="height: 29.6806px;"><th style="width: 7.3545%; height: 29.6806px;">**层次**</th><th style="width: 27.5811%; height: 29.6806px;">**功能**</th><th style="width: 34.1568%; height: 29.6806px;">**常见协议/标准**</th><th style="width: 30.8019%; height: 29.6806px;">**工业协议**</th></tr></thead><tbody><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**物理层**</td><td style="width: 27.5811%; height: 46.4722px;">定义硬件接口、电气特性、信号传输方式。</td><td style="width: 34.1568%; height: 46.4722px;">RS-232、RS-485、USB、Ethernet、CAN、Wi-Fi、蓝牙、ZigBee、LoRa、NFC</td><td style="width: 30.8019%; height: 46.4722px;">Modbus RTU（基于RS-485）、CANopen（基于CAN）</td></tr><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**数据链路层**</td><td style="width: 27.5811%; height: 46.4722px;">提供可靠的数据帧传输，处理错误检测和纠正。</td><td style="width: 34.1568%; height: 46.4722px;">Ethernet（IEEE 802.3）、Wi-Fi（IEEE 802.11）、PPP、HDLC</td><td style="width: 30.8019%; height: 46.4722px;">Profinet、EtherCAT</td></tr><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**网络层**</td><td style="width: 27.5811%; height: 46.4722px;">负责路由选择和逻辑地址分配，确保数据包跨网络传输。</td><td style="width: 34.1568%; height: 46.4722px;">IPv4、IPv6、ICMP、ARP</td><td style="width: 30.8019%; height: 46.4722px;">Modbus TCP（基于IP）、CIP（Common Industrial Protocol）</td></tr><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**传输层**</td><td style="width: 27.5811%; height: 46.4722px;">提供端到端的通信服务，负责数据分段、重组和流量控制。</td><td style="width: 34.1568%; height: 46.4722px;">TCP、UDP</td><td style="width: 30.8019%; height: 46.4722px;">MQTT（基于TCP）、CoAP（基于UDP）</td></tr><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**会话层**</td><td style="width: 27.5811%; height: 46.4722px;">管理会话（连接的建立、维护和终止）。</td><td style="width: 34.1568%; height: 46.4722px;">SMB、RPC</td><td style="width: 30.8019%; height: 46.4722px;">OPC UA</td></tr><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**表示层**</td><td style="width: 27.5811%; height: 46.4722px;">数据格式转换、加密解密、数据压缩。</td><td style="width: 34.1568%; height: 46.4722px;">TLS/SSL、JSON、XML</td><td style="width: 30.8019%; height: 46.4722px;">无特定工业协议，但加密和数据格式在工业通信中广泛使用。</td></tr><tr style="height: 46.4722px;"><td style="width: 7.3545%; height: 46.4722px;">**应用层**</td><td style="width: 27.5811%; height: 46.4722px;">为用户提供直接的网络服务，定义应用程序之间的通信规则。</td><td style="width: 34.1568%; height: 46.4722px;">HTTP/HTTPS、FTP/SFTP、SMTP/IMAP/POP3、WebSocket、gRPC</td><td style="width: 30.8019%; height: 46.4722px;">Modbus TCP（基于TCP）、OPC UA、BACnet（楼宇自动化控制网络）</td></tr></tbody></table>

---

### **IPC（进程间通信）方式与层次对照表**

<table id="bkmrk-%E9%80%9A%E4%BF%A1%E6%96%B9%E5%BC%8F-%E5%8A%9F%E8%83%BD-%E9%80%82%E7%94%A8%E5%B1%82%E6%AC%A1-%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF-%E4%BC%98%E7%82%B9"><tbody><tr><td>**通信方式**</td><td>**功能**</td><td>**适用层次**</td><td>**应用场景**</td><td>**优点**</td><td>**缺点**</td></tr><tr><td>**匿名管道**</td><td>单向或双向通信，适用于父子进程之间的数据传递。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>本地进程间通信，适用于简单的数据传递。</td><td>简单易用，操作系统原生支持。</td><td>仅限本地通信，数据量较小，父子进程关系限制。</td></tr><tr><td>**命名管道**</td><td>支持无亲缘关系的进程间通信，支持本地或网络通信。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>本地或网络进程间通信，适用于跨进程的数据传递。</td><td>支持跨进程和跨网络通信，灵活性高。</td><td>实现复杂度较高，性能受限于操作系统。</td></tr><tr><td>**消息队列**</td><td>通过消息队列传递数据，支持异步通信。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>本地或分布式系统中的任务调度和消息传递。</td><td>支持异步通信，适合任务队列和事件驱动模型。</td><td>消息队列可能存在阻塞，消息大小有限制。</td></tr><tr><td>**共享内存**</td><td>多个进程共享一块内存区域，速度快。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>实时性要求高的本地进程间通信。</td><td>速度快，适合大数据量传输。</td><td>需要进程同步机制（如信号量）避免竞争，开发复杂度高。</td></tr><tr><td>**信号量**</td><td>用于进程同步，避免资源竞争。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>进程间同步和资源管理。</td><td>简单高效，适合资源锁定和同步。</td><td>仅用于同步，不适合数据传输。</td></tr><tr><td>**套接字（Socket）**</td><td>支持本地和网络通信，基于 TCP/UDP。</td><td>传输层</td><td>本地或网络通信，适用于客户端与服务器之间的通信。</td><td>支持本地和远程通信，灵活性高，适合分布式系统。</td><td>需要手动管理连接和协议，开发复杂度较高。</td></tr><tr><td>**信号（Signal）**</td><td>用于进程间的简单通知机制。</td><td>操作系统层（不属于OSI模型）。</td><td>进程间的简单事件通知（如终止、暂停）。</td><td>简单高效，适合轻量级通知。</td><td>仅支持简单的信号传递，不适合复杂数据通信。</td></tr><tr><td>**文件映射（Memory-Mapped Files）**</td><td>通过文件共享内存区域，支持进程间通信。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>本地进程间通信，适用于大数据量的共享。</td><td>速度快，适合大数据量传输，支持持久化。</td><td>需要同步机制避免竞争，依赖文件系统。</td></tr><tr><td>**gRPC**</td><td>基于 HTTP/2 的高性能 RPC 框架。</td><td>应用层</td><td>微服务之间的高效通信。</td><td>高性能，支持流式通信，跨语言支持。</td><td>不适合浏览器直接使用，消息格式为二进制，调试较复杂。</td></tr><tr><td>**REST API**</td><td>基于 HTTP 的轻量级通信方式。</td><td>应用层</td><td>请求-响应模式的通信，如数据查询，前端与后端之间的通信，适用于 Web 应用。</td><td>简单易用，广泛支持，适合标准化的请求-响应模式。</td><td>不支持实时通信，延迟较高，需频繁轮询实现实时性。</td></tr><tr><td>**WebSocket**</td><td>基于 TCP 的全双工通信协议。</td><td>应用层</td><td>实时性要求高的前端与后端通信（如聊天应用、实时数据推送）。</td><td>延迟低，性能高，支持全双工通信，适合高并发场景。</td><td>需要手动管理连接和消息格式，开发复杂度较高。</td></tr><tr><td>**SignalR**</td><td>基于 WebSocket/SSE/Long Polling 的实时通信框架。</td><td>应用层</td><td>聊天、通知、仪表盘、多人协作。</td><td>自动选择最佳协议，开发简单，支持广播和组通信。</td><td>如果无法使用 WebSocket，性能可能下降（如 Long Polling）。</td></tr><tr><td>**MQTT**</td><td>基于 TCP 的轻量级发布/订阅协议。</td><td>应用层</td><td>物联网设备的轻量级通信。</td><td>轻量级，低带宽消耗，支持 QoS（服务质量）等级，适合低功耗设备。</td><td>需要专门的 MQTT Broker，消息格式简单，不适合复杂数据结构。</td></tr><tr><td>**D-Bus**</td><td>Linux 系统中用于进程间通信的消息总线。</td><td>操作系统层（不属于OSI模型，但常用于应用层之上）。</td><td>Linux 系统中的进程间通信（如桌面环境组件之间的通信）。</td><td>高效，支持广播和点对点通信，适合 Linux 环境。</td><td>仅适用于 Linux 系统，跨平台支持较差。</td></tr><tr><td>**ZeroMQ**</td><td>高性能消息队列库，支持多种通信模式（如发布/订阅、请求/响应）。</td><td>应用层</td><td>分布式系统中的高性能通信。</td><td>高性能，支持多种通信模式，跨平台支持好。</td><td>需要手动管理消息格式和连接，学习曲线较陡峭。</td></tr></tbody></table>

---

### **补充说明**

---

### **关于 Modbus 的位置说明**

- **Modbus RTU**：基于 RS-485 的物理层和数据链路层协议，主要用于工业现场设备之间的通信。
- **Modbus TCP**：基于 TCP/IP 的应用层协议，适用于工业自动化中设备与服务器之间的通信。

### **协议的组合应用示例**

#### **1. 下位机与上位机**

- **场景**：工业现场的传感器（下位机）通过 RS-485 与 PLC（上位机）通信。
- **协议组合**： 
    - **物理层**：RS-485。
    - **数据链路层**：Modbus RTU。
    - **应用层**：Modbus 协议解析传感器数据。

#### **2. 上位机与远程服务器**

- **场景**：PLC（上位机）通过以太网将数据上传到远程服务器。
- **协议组合**： 
    - **物理层**：Ethernet。
    - **数据链路层**：以太网帧。
    - **网络层**：IPv4。
    - **传输层**：TCP。
    - **应用层**：HTTP 或 MQTT。

#### **3. 远程服务器与前端客户**

- **场景**：远程服务器通过 Web 服务向前端客户提供实时数据。
- **协议组合**： 
    - **物理层**：光纤或 Wi-Fi。
    - **数据链路层**：以太网或 Wi-Fi。
    - **网络层**：IPv4/IPv6。
    - **传输层**：TCP。
    - **表示层**：TLS（HTTPS）。
    - **应用层**：REST API 或 WebSocket。

---

### **总结**

- **清晰的分层职责**：每一层都有明确的功能和协议，避免混淆。
- **Modbus 的位置**：RTU 属于物理层和数据链路层，TCP 属于应用层。
- **IPC 的层次划分**：大部分 IPC 通信方式位于操作系统层，但也可以延伸到传输层和应用层。
- **协议组合的灵活性**：根据场景 <div drawio-diagram="107"><img src="https://book.lingyanspace.com/uploads/images/drawio/2025-04/UfrMuS6yT0Fm7lXo-drawing-1-1744450431.png" alt=""/></div>
    
    需求，协议可以跨层组合使用，形成完整的通信链路。

# 基础篇

### 依赖属性propdb

```c#
        public int MyProperty
        {
            get { return (int)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
```

### 附加属性propa

```c#
    public static int GetMyProperty(DependencyObject obj)
    {
        return (int)obj.GetValue(MyPropertyProperty);
    }

    public static void SetMyProperty(DependencyObject obj, int value)
    {
        obj.SetValue(MyPropertyProperty, value);
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.RegisterAttached("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
```

## xaml资源键类型

<table id="bkmrk-%E5%AE%9A%E4%B9%89%E6%96%B9%E5%BC%8F-%E4%BC%98%E7%82%B9-%E7%BC%BA%E7%82%B9-%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF-%E6%99%AE%E9%80%9A%E5%AD%97%E7%AC%A6"><thead><tr><th>定义方式</th><th>优点</th><th>缺点</th><th>适用场景</th></tr></thead><tbody><tr><td>**普通字符串键**</td><td>简单直观，易于使用</td><td>命名冲突风险，无法跨程序集共享</td><td>小型项目，局部资源</td></tr><tr><td>**类型键**</td><td>自动应用，无需显式引用</td><td>灵活性较低</td><td>全局样式，基础样式复用</td></tr><tr><td>**静态资源键**</td><td>强类型支持，可维护性高</td><td>定义稍复杂</td><td>大型项目，组件化开发</td></tr><tr><td>**`ComponentResourceKey`**</td><td>跨程序集支持，语义化标识</td><td>定义和使用复杂</td><td>组件库开发，主题或样式库</td></tr><tr><td>**动态资源键**</td><td>动态绑定，灵活性高</td><td>性能开销</td><td>主题切换，多语言支持</td></tr></tbody></table>

```nginx
//普通字符串键
<Style x:Key="MyButtonStyle" TargetType="Button" />

//类型键（隐式样式）
<Style TargetType="Button">
    <Setter Property="Background" Value="LightBlue" />
</Style>

//静态资源键
public static class ResourceKeys
{
    public static readonly string CloseButtonStyle = "CloseButtonStyle";
}

<Style x:Key="{x:Static local:ResourceKeys.CloseButtonStyle}" TargetType="Button" />

//组件资源键ComponentResourceKey

    public partial class DataTemplateKeys
    {
        public static ComponentResourceKey ItemClose => new ComponentResourceKey(typeof(DataTemplateKeys), "S.DataTemplate.Item.Close");
    }
<DataTemplate x:Key="{ComponentResourceKey ResourceId=S.DataTemplate.Item.Close, TypeInTargetAssembly={x:Type local:DataTemplateKeys}}">

//静态资源键与组件资源键结合

public static class ResourceKeys
{
    public static readonly ComponentResourceKey CloseButtonStyleKey = new ComponentResourceKey(typeof(ResourceKeys), "CloseButtonStyle");
}

<Style x:Key="{x:Static local:ResourceKeys.CloseButtonStyleKey}" TargetType="Button" />

//动态资源键
<Button Style="{DynamicResource MyButtonStyle}" />
```

# 编译篇

### 编译后事件

```c#
:: 检查Lib、Dll文件夹路径是否存在
IF NOT EXIST "$(TargetDir)libs" (
    MD "$(TargetDir)libs"
)

:: 将指定的dll、xml、pdb、config文件移动到libs文件夹
move "$(TargetDir)*.dll" "$(TargetDir)libs"
move "$(TargetDir)*.xml" "$(TargetDir)libs"
move "$(TargetDir)*.pdb" "$(TargetDir)libs"
move "$(TargetDir)*.config" "$(TargetDir)libs"

:: 将runtimes文件夹移动到libs文件夹
move "$(TargetDir)runtimes" "$(TargetDir)libs"

:: 把主程序的相关文件从libs转移出来
move "$(TargetDir)libs\NLog.config" "$(TargetDir)NLog.config"
move "$(TargetDir)libs\$(ProjectName).exe.config" "$(TargetDir)$(ProjectName).exe.config"
move "$(TargetDir)libs\$(ProjectName).exe.xml" "$(TargetDir)$(ProjectName).exe.xml"
move "$(TargetDir)libs\$(ProjectName).pdb" "$(TargetDir)$(ProjectName).pdb"
```

### 加扫描文件夹

```
 <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <!-- 添加对libs文件夹的搜索路径 -->
      <probing privatePath="libs"/>      
    </assemblyBinding>
  </runtime>
```

# 扩展篇

### HttpCilent发送文件有进度

```
try
            {
                var lcaolSelectTeam = await this.ToGetSelectTeam();
                if (lcaolSelectTeam.Code != 20000)
                {
                    throw new Exception(lcaolSelectTeam.Message);
                }
                var localToken = await this.ToGetUserToken();
                if (localToken.Code != 20000)
                {
                    throw new Exception(localToken.Message);
                }
                var taskworkFloderBody = await this.ToGetTaskworkProxyFloder();
                if (taskworkFloderBody.Code != 20000)
                {
                    throw new Exception(taskworkFloderBody.Message);
                }
                var rootTaskworkFloder = taskworkFloderBody.Data.PathCombine(teamTaskwrokId.ToString());
                HttpClientHandler handler = new HttpClientHandler();
                ProgressMessageHandler progressMessageHandler = new ProgressMessageHandler(handler);
                progressMessageHandler.HttpSendProgress += (sender, e) =>
                {
                    action.Invoke(e.ProgressPercentage);
                };
                using (HttpClient httpClient = new HttpClient(progressMessageHandler))
                {
                    httpClient.BaseAddress = new Uri("https://lycg.lingyanspace.com/");
                    httpClient.DefaultRequestHeaders.Add("Authorization", localToken.Data);
                    using (var multipartFormData = new MultipartFormDataContent())
                    {
                        var bom = rootTaskworkFloder.PathCombine("bom").FileCombine("default.json");
                        if (File.Exists(bom) && needUploadCloudModel.BOM)
                        {
                            AddFile(multipartFormData, "bom", bom);
                        }
                        var bIfc = rootTaskworkFloder.PathCombine("bifc").FileCombine("default.ifc");
                        if (File.Exists(bIfc) && needUploadCloudModel.BIFC)
                        {
                            AddFile(multipartFormData, "bIfc", bIfc);
                        }
                        var nc1Files = Directory.GetFiles(rootTaskworkFloder.PathCombine("nc1"), "*.nc1", SearchOption.TopDirectoryOnly).ToList();
                        if (nc1Files != null && nc1Files.Count > 0 && needUploadCloudModel.NC1)
                        {
                            nc1Files.ForEach(f =>
                            {
                                AddFile(multipartFormData, "nc1Files", f);
                            });
                        }
                        var dxfFiles = Directory.GetFiles(rootTaskworkFloder.PathCombine("dxf"), "*.dxf", SearchOption.TopDirectoryOnly).ToList();
                        if (dxfFiles != null && dxfFiles.Count > 0 && needUploadCloudModel.DXF)
                        {
                            dxfFiles.ForEach(f =>
                            {
                                AddFile(multipartFormData, "dxfFiles", f);
                            });
                        }
                        var aifcFiles = Directory.GetFiles(rootTaskworkFloder.PathCombine("aifc"), "*.ifc", SearchOption.TopDirectoryOnly).ToList();
                        if (aifcFiles != null && aifcFiles.Count > 0 && needUploadCloudModel.AIFC)
                        {
                            aifcFiles.ForEach(f =>
                            {
                                AddFile(multipartFormData, "aifcFiles", f);
                            });
                        }
                        var pifcFiles = Directory.GetFiles(rootTaskworkFloder.PathCombine("pifc"), "*.ifc", SearchOption.TopDirectoryOnly).ToList();
                        if (pifcFiles != null && pifcFiles.Count > 0 && needUploadCloudModel.PIFC)
                        {
                            pifcFiles.ForEach(f =>
                            {
                                AddFile(multipartFormData, "pifcFiles", f);
                            });
                        }
                        var drawingFiles = Directory.GetFiles(rootTaskworkFloder.PathCombine("drawing"), "*.pdf", SearchOption.TopDirectoryOnly).
                            Concat(Directory.GetFiles(rootTaskworkFloder.PathCombine("drawing"), "*.dwg", SearchOption.TopDirectoryOnly)).ToList();
                        if (drawingFiles != null && drawingFiles.Count > 0 && needUploadCloudModel.Drawing)
                        {
                            drawingFiles.ForEach(f =>
                            {
                                AddFile(multipartFormData, "drawingFiles", f);
                            });
                        }
                        var response = await httpClient.PutAsync($"/api/Team/UploadTeamTaskworkBatchData?teamId={lcaolSelectTeam.Data.Id}&teamTaskwrokId={teamTaskwrokId}", multipartFormData);
                        if (response.IsSuccessStatusCode)
                        {
                            var data = await response.Content.ReadAsStringAsync();
                            var jsonBody = JsonConvert.DeserializeObject<ResponceBody<string>>(data);
                            return jsonBody;
                        }
                        else
                        {
                            throw new Exception(await response.Content.ReadAsStringAsync());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                return new ResponceBody<string>(40000, ex.Message, null);
            }
```

### 编号排序

```

    public class StringSortComparer : IComparer<string>
    {
        public bool MatchCase { get; }
        public StringSortComparer(bool matchCase)
        {
            MatchCase = matchCase;
        }
        private int CharCompare(char a, char b, bool matchCase)
        {
            char _a = char.MinValue, _b = char.MinValue;
            if (matchCase) { _a = a; _b = b; }
            else { _a = char.ToUpper(a); _b = char.ToUpper(b); }
            if (_a > _b) return 1;
            if (_a < _b) return -1;
            return 0;
        }
        public int Compare(string x, string y)
        {
            // 如果 y 为空，则 y 应该排在最后面
            if (string.IsNullOrEmpty(y)) return -1;
            // 如果 x 为空，而 y 不为空，则 x 应该排在 y 之前
            if (string.IsNullOrEmpty(x)) return 1;
            int len;
            if (x.Length > y.Length) len = x.Length;
            else len = y.Length;
            string numericx = "";
            string numericy = "";
            for (int i = 0; i < len; i++)
            {
                char cx = char.MinValue;
                char cy = char.MinValue;
                if (i < x.Length) cx = x[i];
                if (i < y.Length) cy = y[i];
                if (cx >= 48 && cx <= 57) numericx += cx;
                if (cy >= 48 && cy <= 57) numericy += cy;
                if (i == len - 1)
                {
                    if (numericx.Length > 0 && numericy.Length > 0)
                    {
                        if (decimal.Parse(numericx) < decimal.Parse(numericy)) return -1;
                        if (decimal.Parse(numericx) > decimal.Parse(numericy)) return 1;
                    }
                    return CharCompare(cy, cy, MatchCase);
                }
                if ((cx >= 48 && cx <= 57) && (cy >= 48 && cy <= 57)) continue;
                if (numericx.Length > 0 && numericy.Length > 0)
                {
                    if (decimal.Parse(numericx) < decimal.Parse(numericy)) return -1;
                    if (decimal.Parse(numericx) > decimal.Parse(numericy)) return 1;
                }
                if (CharCompare(cx, cy, MatchCase) == 0) continue;
                return CharCompare(cx, cy, MatchCase);
            }
            return 0;
        }
    }
```

### 下载文件进度

```
 public class HttpHelper
    {
        /// <summary>
        /// 下载单个文件
        /// </summary>
        /// <param name="action"></param>
        /// <param name="netWrokUrl"></param>
        /// <param name="localUrl"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static async Task<long> DownloadSingleFile(Action<double> action, string netWrokUrl, string localUrl)
        {
            long totalBytesReceived = 0;
            var progress = new Progress<HttpDownloadProgress>(p =>
            {
                if (p.TotalBytesToReceive.HasValue)
                {
                    totalBytesReceived = (long)p.BytesReceived;
                    double percent = (double)p.BytesReceived / p.TotalBytesToReceive.Value * 100.0;
                    action.Invoke(percent);
                }
                else
                {
                    LoggerHelper.DefaultLogger($"特殊情况：{netWrokUrl}的TotalBytesToReceive无值");
                }
            });
            var fileBytes = await new HttpClient().GetByteArrayAsync(new Uri(netWrokUrl), progress, CancellationToken.None);
            if (File.Exists(localUrl))
            {
                File.Delete(localUrl);
            }
            await localUrl.SaveLocalFileAsync(new MemoryStream(fileBytes));
            return totalBytesReceived;
        }
        private static async Task<long> DownloadSingleFile(Action<long, long> progressAction, string networkUrl, string localUrl, long totalBytes)
        {
            long bytesReceived = 0;
            var progress = new Progress<HttpDownloadProgress>(p =>
            {
                bytesReceived = (long)p.BytesReceived;
                progressAction(bytesReceived, totalBytes);
            });
            using (var httpClient = new HttpClient())
            {
                var fileBytes = await httpClient.GetByteArrayAsync(new Uri(networkUrl), progress, CancellationToken.None);
                if (File.Exists(localUrl))
                {
                    File.Delete(localUrl);
                }
                using (var fileStream = new FileStream(localUrl, FileMode.CreateNew))
                {
                    await fileStream.WriteAsync(fileBytes, 0, fileBytes.Length);
                }
                return bytesReceived;
            }
        }
        /// <summary>
        /// 下载文件集合
        /// </summary>
        /// <param name="overallProgressAction"></param>
        /// <param name="files"></param>
        /// <returns></returns>
        public static async Task DownloadMultipleFiles(Action<double> overallProgressAction,Dictionary<string, string> files)
        {
            var downloadTasks = new List<Task<long>>();
            long totalFileSize = 0;
            Dictionary<string, long> fileSizes = new Dictionary<string, long>();
            // 首先，预估所有文件的大小（可以通过HEAD请求或是其他方式获取）
            using (var httpClient = new HttpClient())
            {
                foreach (var file in files)
                {
                    var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, file.Key));
                    long contentLength = response.Content.Headers.ContentLength ?? 0;
                    fileSizes[file.Key] = contentLength;
                    totalFileSize += contentLength;
                }
            }
            // 存储每个文件的已接收字节
            Dictionary<string, long> receivedBytes = new Dictionary<string, long>();
            foreach (var file in files)
            {
                string networkUrl = file.Key;
                string localUrl = file.Value;
                Task<long> downloadTask = DownloadSingleFile(
                    (bytesReceived, totalBytes) =>
                    {
                        receivedBytes[networkUrl] = bytesReceived;
                        // 计算总体进度
                        long totalReceived = 0;
                        foreach (var received in receivedBytes.Values)
                        {
                            totalReceived += received;
                        }
                        double overallProgress = (double)totalReceived / totalFileSize * 100.0;
                        overallProgressAction(overallProgress);
                    },
                    networkUrl,
                    localUrl,
                    fileSizes[networkUrl]
                );
                downloadTasks.Add(downloadTask);
            }
            // 等待所有下载任务完成
            long[] results = await Task.WhenAll(downloadTasks);
        }
    }
```

### 下载byte

```
 public static class HttpClientExtension
    {
        private const int BufferSize = 262144;

        public static async Task<byte[]> GetByteArrayAsync(this HttpClient client, Uri requestUri, IProgress<HttpDownloadProgress> progress, CancellationToken cancellationToken)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }

            using (var responseMessage = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false))
            {
                responseMessage.EnsureSuccessStatusCode();

                var content = responseMessage.Content;
                if (content == null)
                {
                    return Array.Empty<byte>();
                }

                var headers = content.Headers;
                var contentLength = headers.ContentLength;
                using (var responseStream = await content.ReadAsStreamAsync().ConfigureAwait(false))
                {
                    var buffer = new byte[BufferSize];
                    int bytesRead;
                    var bytes = new List<byte>();

                    var downloadProgress = new HttpDownloadProgress();
                    if (contentLength.HasValue)
                    {
                        downloadProgress.TotalBytesToReceive = (ulong)contentLength.Value;
                    }
                    progress?.Report(downloadProgress);

                    while ((bytesRead = await responseStream.ReadAsync(buffer, 0, BufferSize, cancellationToken).ConfigureAwait(false)) > 0)
                    {
                        bytes.AddRange(buffer.Take(bytesRead));

                        downloadProgress.BytesReceived += (ulong)bytesRead;
                        progress?.Report(downloadProgress);
                    }

                    return bytes.ToArray();
                }
            }
        }
    }
    public struct HttpDownloadProgress
    {
        public ulong BytesReceived { get; set; }

        public ulong? TotalBytesToReceive { get; set; }
    }
```

# WPF大基本功

#### Application的生命周期

```
OnStartup：表示启动应用程序时
OnActivated：表示激活应用程序时
OnDeactivated：表示由激活状态变为非激活状态时
OnExit：表示退出应用程序时
```

#### Window窗体的生命周期

```
SourceInitialized	创建窗体源时引发此事件
Activated	当前窗体成为前台窗体时引发此事件
Loaded	当前窗体内部所有元素完成布局和呈现时引发此事件
ContentRendered	当前窗体的内容呈现之后引发此事件
------Deactivated	当前窗体成为后台窗体时引发此事件====Activated	当前窗体成为前台窗体时引发此事件
Closing	当前窗体关闭之前引发此事件
Deactivated	当前窗体成为后台窗体时引发此事件
Closed	当前窗体关闭之后引发此事件
Unloaded	当前窗体从元素树中删除时引发此事件
```

#### ContentControl

```
Content属性在ContentControl类中
```

#### 加载和解析 XAML

```
编译器会将 XAML 文件（如 MainWindow.xaml）编译为 BAML (Binary Application Markup Language)，这是一种压缩和优化的二进制格式。
运行时，CLR 会加载 BAML 并将其解析回一个对象树。这个过程会：
实例化 XAML 中定义的每一个元素（如 <Window>， <Grid>， <Button>）为 .NET 对象。
设置每个对象的属性（如 Width, Height, Content）。
根据元素的嵌套关系，建立起逻辑树 (Logical Tree)。
```

#### 对象初始化过程中，会按顺序引发一系列事件

```
Initialized: 元素已被初始化并从 XAML 中加载了基本属性。此时逻辑树已建立，但尚未进行布局测量和排列。
Loaded: 整个窗口（或页面）已加载完毕，逻辑树完整，并且即将被呈现到屏幕上。这是通常进行最终初始化操作（如加载数据）的地方。
```

- **逻辑树 (Logical Tree)**： 反映 XAML 中声明的控件层次结构，用于核心功能如属性继承、资源查找、事件路由。
- **可视树 (Visual Tree)**： 描述控件视觉结构的更底层、更详细的树，用于渲染和命中测试。你可以使用 `VisualTreeHelper` 来遍历它。
- **布局系统 (Layout System)**： 递归的 **测量(Measure) -&gt; 排列(Arrange)** 过程。任何影响布局的变化（如窗口大小调整、内容更改）都会触发一个新的布局传递 (Layout Pass)。
- **保留模式图形 (Retained Mode Graphics)**： 与“立即模式”（如 WinForms 的 `Paint` 事件）相反，WPF 维护一个可视化对象列表（可视树），并由系统负责在需要时重绘它们。开发者只需声明“要什么”，而不需关心“何时画”和“怎么画”。

#### 控件基类路线

```
Button->ButtonBase->ContentControl->Control->FrameworkElement->UIElement->Visual->DependencyObject->DispatcherObject
StackPanel->Panel->FrameworkElement->UIElement->Visual->DependencyObject->DispatcherObject
Rectangle->Shape->FrameworkElement->UIElement->Visual->DependencyObject->DispatcherObject
```

WPF用启动时，分别用于呈现界面（后台线程）和管理界面（UI线程）。

DispatcherObject的Dispatcher调度员提供了Invoke和BeginInvoke两个方法，供我们可以安全的访问UI线程中的控件

# c++音视频

<div class="qwen-markdown-paragraph" id="bkmrk-%E5%AF%B9%E9%BD%90%E5%A4%A7%E5%8E%82%E9%9F%B3%E8%A7%86%E9%A2%91%E5%B2%97%E9%9D%A2%E8%AF%95%E6%A0%87%E5%87%86%EF%BC%8C%E6%88%91%E5%B0%86-w1%7Ew">**<span class="qwen-markdown-text">对齐大厂音视频岗面试标准</span>**<span class="qwen-markdown-text">，我将 W1~W4 的技术栈、C++/QML 分工、具体用途、关键实现点拆解到底。原则只有一个：</span>**<span class="qwen-markdown-text">媒体管线 100% C++，QML 只做 UI 与状态展示</span>**<span class="qwen-markdown-text">。</span></div><div class="qwen-markdown-space" id="bkmrk-">  
</div><div class="qwen-markdown-hr" id="bkmrk--1">---

</div>### <span class="qwen-markdown-text">📐 核心分工原则（面试必讲）</span>

<div class="qwen-markdown-table-wrapper" id="bkmrk-%E5%B1%82%E7%BA%A7-%E8%AF%AD%E8%A8%80-%E8%81%8C%E8%B4%A3-%E7%BB%9D%E4%B8%8D%E8%B6%8A%E7%95%8C-media-"><div class="qwen-markdown-table-header"><div class="qwen-markdown-table-header-action-item"><span class="anticon" role="img"><svg aria-hidden="true" class="" fill="currentColor" focusable="false" height="1em" width="1em"></svg></span></div></div><div class="qwen-markdown-table-scroll-wrapper"><table class="qwen-markdown-table"><thead class="qwen-markdown-table-thead"><tr class="qwen-markdown-table-thead-tr"><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">层级</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">语言</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">职责</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">绝不越界</span></div></th></tr></thead><tbody class="qwen-markdown-table-tbody"><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">**<span class="qwen-markdown-text">Media Engine</span>**</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`C++`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">拉流、解复用、解码、AVSync、JitterBuffer、硬解管理、OpenGL 渲染线程</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">不碰 </span>`QQuickItem`<span class="qwen-markdown-text">，不依赖 Qt 事件循环</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">**<span class="qwen-markdown-text">UI / Business</span>**</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QML`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">播放控制、进度条、状态提示、调试面板、主题切换</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">不读 </span>`AVFrame`<span class="qwen-markdown-text">，不调 </span>`avcodec_*`<span class="qwen-markdown-text">，不阻塞主线程</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">**<span class="qwen-markdown-text">Bridge</span>**</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`C++ (QObject)`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`Q_PROPERTY`<span class="qwen-markdown-text"> 暴露状态、</span>`Q_INVOKABLE`<span class="qwen-markdown-text"> 暴露控制接口、</span>`QQuickFramebufferObject`<span class="qwen-markdown-text"> 渲染视频纹理</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">仅传递数据指针/ID，不跨线程传递裸对象</span></div></td></tr></tbody></table>

</div></div><div class="qwen-markdown-hr" id="bkmrk--2">---

</div>### <span class="qwen-markdown-text">🗓️ W1~W4 逐周技术拆解</span>

#### <span class="qwen-markdown-text">🔹 W1：FFmpeg 拉流+解码+OpenGL 渲染跑通</span>

<div class="qwen-markdown-table-wrapper" id="bkmrk-%E6%8A%80%E6%9C%AF-%E8%AF%AD%E8%A8%80-%E7%94%A8%E9%80%94-%E5%85%B3%E9%94%AE%E5%AE%9E%E7%8E%B0%E7%82%B9-libav"><div class="qwen-markdown-table-header"><div class="qwen-markdown-table-header-action-item"><span class="anticon" role="img"><svg aria-hidden="true" class="" fill="currentColor" focusable="false" height="1em" width="1em"></svg></span></div></div><div class="qwen-markdown-table-scroll-wrapper"><table class="qwen-markdown-table"><thead class="qwen-markdown-table-thead"><tr class="qwen-markdown-table-thead-tr"><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">技术</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">语言</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">用途</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">关键实现点</span></div></th></tr></thead><tbody class="qwen-markdown-table-tbody"><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`libavformat`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">打开文件/网络流，读取 </span>`AVPacket`<span class="qwen-markdown-text">，解析音视频流信息</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`avformat_open_input`<span class="qwen-markdown-text"> → </span>`avformat_find_stream_info`<span class="qwen-markdown-text"> → </span>`av_read_frame`</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`libavcodec`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">软解 H.264/H.265 视频、AAC/Opus 音频到 </span>`AVFrame`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`avcodec_send_packet`<span class="qwen-markdown-text"> / </span>`avcodec_receive_frame`<span class="qwen-markdown-text"> 异步非阻塞调用</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`libswscale`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">像素格式转换（YUV420P → RGBA）</span>**<span class="qwen-markdown-text">仅作为 CPU 降级方案</span>**</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">实际渲染应弃用，改由 OpenGL Shader 做 YUV→RGB</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`OpenGL 3.3+`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">GPU 渲染视频帧：YUV 纹理上传、Shader 转换、双缓冲</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">顶点着色器传 UV 坐标，片段着色器用 </span>`texture2D`<span class="qwen-markdown-text"> 采样 Y/U/V 平面，矩阵乘法转 RGB</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`std::thread`<span class="qwen-markdown-text"> / </span>`std::mutex`<span class="qwen-markdown-text"> / </span>`std::condition_variable`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">解复用线程、解码线程、渲染线程隔离，线程安全队列</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">用 </span>`std::queue<AVPacket*>`<span class="qwen-markdown-text"> + 条件变量控制生产消费，避免内存碎片</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QML`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">QML</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">仅显示“播放/暂停”按钮 + FPS 文本</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">通过 </span>`Q_PROPERTY`<span class="qwen-markdown-text"> 绑定 </span>`fps`<span class="qwen-markdown-text">，不干预渲染逻辑</span></div></td></tr></tbody></table>

</div></div><div class="qwen-markdown-paragraph" id="bkmrk-%E2%9C%85-%E4%BA%A4%E4%BB%98%E6%A0%87%E5%87%86%EF%BC%9A1080p-mp4-%E5%BE%AA%E7%8E%AF%E6%92%AD"><span class="qwen-markdown-text">✅ </span>**<span class="qwen-markdown-text">交付标准</span>**<span class="qwen-markdown-text">：1080p MP4 循环播放稳定 60 FPS，</span>`valgrind`<span class="qwen-markdown-text">/</span>`AddressSanitizer`<span class="qwen-markdown-text"> 零泄漏，CPU 占用 </span>`<15%`<span class="qwen-markdown-text">（软解）。</span></div><div class="qwen-markdown-space" id="bkmrk--3">  
</div><div class="qwen-markdown-hr" id="bkmrk--4">---

</div><div class="qwen-markdown-space" id="bkmrk--5">  
</div>#### <span class="qwen-markdown-text">🔹 W2：接入 SRT/UDP，实现基础 AVSync</span>

<div class="qwen-markdown-table-wrapper" id="bkmrk-%E6%8A%80%E6%9C%AF-%E8%AF%AD%E8%A8%80-%E7%94%A8%E9%80%94-%E5%85%B3%E9%94%AE%E5%AE%9E%E7%8E%B0%E7%82%B9-ffmpe"><div class="qwen-markdown-table-header"><div class="qwen-markdown-table-header-action-item"><span class="anticon" role="img"><svg aria-hidden="true" class="" fill="currentColor" focusable="false" height="1em" width="1em"></svg></span></div></div><div class="qwen-markdown-table-scroll-wrapper"><table class="qwen-markdown-table"><thead class="qwen-markdown-table-thead"><tr class="qwen-markdown-table-thead-tr"><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">技术</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">语言</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">用途</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">关键实现点</span></div></th></tr></thead><tbody class="qwen-markdown-table-tbody"><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`FFmpeg SRT 协议支持`<span class="qwen-markdown-text"> 或 </span>`libsrt`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">替换文件 I/O 为低延迟网络传输</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">FFmpeg 原生支持 </span>`srt://`<span class="qwen-markdown-text"> 协议；或 </span>`srt_create_socket`<span class="qwen-markdown-text"> + </span>`avio_alloc_context`<span class="qwen-markdown-text"> 注入自定义读写回调</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`SRTO_LATENCY`<span class="qwen-markdown-text"> / </span>`SRTO_TSBPDDELAY`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">控制 SRT 缓冲延迟，抗网络抖动</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">设置 </span>`latency=120`<span class="qwen-markdown-text">（毫秒级），面试需解释 TSBPD（Time-Sender-Based Packet Delivery）原理</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`音频主时钟`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">以音频播放进度为基准，计算音画时间差</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`audio_clock = sample_pos / sample_rate`<span class="qwen-markdown-text">；</span>`video_delay = video_pts - audio_clock`</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`动态丢帧/重复帧`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">根据 </span>`video_delay`<span class="qwen-markdown-text"> 调整渲染节奏</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`delay > 40ms`<span class="qwen-markdown-text"> 丢帧；</span>`delay < -30ms`<span class="qwen-markdown-text"> 重复渲染上一帧；</span>`std::this_thread::sleep_until`<span class="qwen-markdown-text"> 精准睡眠</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QAudioSink`<span class="qwen-markdown-text"> (Qt6) 或 </span>`PortAudio`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">音频播放输出，提供高精度时钟源</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">回调函数中更新 </span>`audio_clock`<span class="qwen-markdown-text">，确保时钟与硬件播放进度严格一致</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QML`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">QML</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">网络状态指示、延迟显示、手动同步开关</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">绑定 </span>`latency_ms`<span class="qwen-markdown-text">、</span>`sync_status`<span class="qwen-markdown-text">，提供 UI 调试入口</span></div></td></tr></tbody></table>

</div></div><div class="qwen-markdown-paragraph" id="bkmrk-%E2%9C%85-%E4%BA%A4%E4%BB%98%E6%A0%87%E5%87%86%EF%BC%9A%E5%B1%80%E5%9F%9F%E7%BD%91-1v1-%E5%AE%9E%E6%97%B6%E6%B5%81%EF%BC%8C%E7%AB%AF"><span class="qwen-markdown-text">✅ </span>**<span class="qwen-markdown-text">交付标准</span>**<span class="qwen-markdown-text" data-spm-anchor-id="a2ty_o01.29997173.0.i27.670755fbXkduH4">：局域网 1v1 实时流，端到端延迟 ≤200ms，音画同步误差 ≤±20ms（手机慢动作录制验证）。</span></div><div class="qwen-markdown-space" id="bkmrk--6">  
</div><div class="qwen-markdown-hr" id="bkmrk--7">---

</div><div class="qwen-markdown-space" id="bkmrk--8">  
</div>#### <span class="qwen-markdown-text">🔹 W3：硬解 Fallback + 零拷贝渲染 + 弱网 JitterBuffer</span>

<div class="qwen-markdown-table-wrapper" id="bkmrk-%E6%8A%80%E6%9C%AF-%E8%AF%AD%E8%A8%80-%E7%94%A8%E9%80%94-%E5%85%B3%E9%94%AE%E5%AE%9E%E7%8E%B0%E7%82%B9-avhwd"><div class="qwen-markdown-table-header"><div class="qwen-markdown-table-header-action-item"><span class="anticon" role="img"><svg aria-hidden="true" class="" fill="currentColor" focusable="false" height="1em" width="1em"></svg></span></div></div><div class="qwen-markdown-table-scroll-wrapper"><table class="qwen-markdown-table"><thead class="qwen-markdown-table-thead"><tr class="qwen-markdown-table-thead-tr"><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">技术</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">语言</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">用途</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">关键实现点</span></div></th></tr></thead><tbody class="qwen-markdown-table-tbody"><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`AVHWDeviceContext`<span class="qwen-markdown-text"> / </span>`AVHWFramesContext`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">管理硬件解码上下文（VAAPI/DXVA2/VideoToolbox）</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`av_hwdevice_ctx_create`<span class="qwen-markdown-text"> → 绑定到 </span>`AVCodecContext`<span class="qwen-markdown-text"> → 捕获 </span>`AVERROR(EAGAIN)`<span class="qwen-markdown-text"> 降级软解</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`PBO (Pixel Buffer Object)`<span class="qwen-markdown-text"> 或 </span>`EGLImageKHR`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">零拷贝渲染：GPU 解码帧直接映射为 OpenGL 纹理</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`glGenBuffers`<span class="qwen-markdown-text"> + </span>`glMapBufferRange`<span class="qwen-markdown-text"> 避免 </span>`glTexImage2D`<span class="qwen-markdown-text"> CPU-GPU 同步阻塞；Linux 用 </span>`EGLImage`<span class="qwen-markdown-text"> 直通</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`动态 Jitter Buffer`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">抗弱网：根据 RTT/丢包率动态调整缓冲队列大小</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">滑动窗口计算 </span>`jitter = max(inter_arrival) - min(inter_arrival)`<span class="qwen-markdown-text">；丢包 &gt;10% 扩容+插值，&lt;3% 缩容降延迟</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`PLC (Packet Loss Concealment)`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">音频丢包隐藏（基础版：线性插值/静音填充）</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">音频帧丢失时，用上一帧末尾波形外推，避免“咔嗒”爆音</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`tc qdisc`<span class="qwen-markdown-text"> (Linux) / </span>`Clumsy`<span class="qwen-markdown-text"> (Win)</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">工具</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">模拟弱网：丢包、延迟、乱序、带宽限制</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`tc qdisc add dev eth0 root netem loss 15% delay 50ms 20ms`</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`perf`<span class="qwen-markdown-text"> / </span>`RenderDoc`<span class="qwen-markdown-text"> / </span>`nvidia-smi`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">工具</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">性能剖析：CPU 热点、GPU 渲染管线、显存占用</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`perf record -g ./app`<span class="qwen-markdown-text"> → </span>`perf report`<span class="qwen-markdown-text">；RenderDoc 抓帧验证零拷贝路径</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QML`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">QML</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">实时性能面板：FPS、延迟、JitterBuffer 长度、硬解状态</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">使用 </span>`ChartView`<span class="qwen-markdown-text"> 或自定义 </span>`Canvas`<span class="qwen-markdown-text"> 绘制波形，绑定 C++ 信号</span></div></td></tr></tbody></table>

</div></div><div class="qwen-markdown-paragraph" id="bkmrk-%E2%9C%85-%E4%BA%A4%E4%BB%98%E6%A0%87%E5%87%86%EF%BC%9A%E5%8E%8B%E6%B5%8B%E6%8A%A5%E5%91%8A%EF%BC%88pdf%2Fmark"><span class="qwen-markdown-text">✅ </span>**<span class="qwen-markdown-text">交付标准</span>**<span class="qwen-markdown-text">：压测报告（PDF/Markdown）含：15% 丢包卡顿率 &lt;2%、硬解 CPU &lt;8%、PBO 渲染无 </span>`glReadPixels`<span class="qwen-markdown-text">、72h 内存波动 &lt;3%。</span></div><div class="qwen-markdown-space" id="bkmrk--9">  
</div><div class="qwen-markdown-hr" id="bkmrk--10">---

</div><div class="qwen-markdown-space" id="bkmrk--11">  
</div>#### <span class="qwen-markdown-text">🔹 W4：QML 对接 + 状态机 + 日志/Profiler 注入</span>

<div class="qwen-markdown-table-wrapper" id="bkmrk-%E6%8A%80%E6%9C%AF-%E8%AF%AD%E8%A8%80-%E7%94%A8%E9%80%94-%E5%85%B3%E9%94%AE%E5%AE%9E%E7%8E%B0%E7%82%B9-qquic"><div class="qwen-markdown-table-header"><div class="qwen-markdown-table-header-action-item"><span class="anticon" role="img"><svg aria-hidden="true" class="" fill="currentColor" focusable="false" height="1em" width="1em"></svg></span></div></div><div class="qwen-markdown-table-scroll-wrapper"><table class="qwen-markdown-table"><thead class="qwen-markdown-table-thead"><tr class="qwen-markdown-table-thead-tr"><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">技术</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">语言</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">用途</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">关键实现点</span></div></th></tr></thead><tbody class="qwen-markdown-table-tbody"><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QQuickFramebufferObject`<span class="qwen-markdown-text"> 或 </span>`QSGTexture`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">将 OpenGL 渲染上下文安全嵌入 QML 场景图</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">重写 </span>`createRenderer()`<span class="qwen-markdown-text"> 返回自定义 </span>`Renderer`<span class="qwen-markdown-text">，在 </span>`render()`<span class="qwen-markdown-text"> 中绑定 FBO 或纹理，</span>**<span class="qwen-markdown-text">禁用 </span>`QQuickPaintedItem`**</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QStateMachine`<span class="qwen-markdown-text"> (Qt6)</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">播放生命周期管理：</span>`IDLE → CONNECTING → STREAMING → RECONNECTING → ERROR`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">状态迁移绑定网络事件/用户操作，避免 </span>`if-else`<span class="qwen-markdown-text"> 嵌套地狱</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`spdlog`<span class="qwen-markdown-text"> 或 </span>`QtLogging`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">C++</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">结构化日志：时间戳、线程ID、模块名、性能指标</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`SPDLOG_INFO("decode", "pts={} delay={}ms", pts, delay)`<span class="qwen-markdown-text">；异步日志线程防阻塞</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`CMake`<span class="qwen-markdown-text"> + </span>`vcpkg`<span class="qwen-markdown-text">/</span>`Conan`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">构建系统</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">跨平台依赖管理、编译选项优化（</span>`-O3`<span class="qwen-markdown-text">、</span>`-march=native`<span class="qwen-markdown-text">）</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">显式链接 </span>`FFmpeg::avformat`<span class="qwen-markdown-text"> 等 Modern CMake Target，避免硬编码路径</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QML`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">QML</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">完整演示端：自定义按钮、主题切换、调试面板、状态反馈</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">使用你提供的 </span>`CustomButton`<span class="qwen-markdown-text">，通过 </span>`Qt.binding()`<span class="qwen-markdown-text"> 响应引擎状态变化</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`draw.io`<span class="qwen-markdown-text"> / </span>`PlantUML`</div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">文档</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">架构图、线程模型、数据流图、状态迁移图</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">面试直接投屏讲解，标注线程边界与队列容量</span></div></td></tr></tbody></table>

</div></div><div class="qwen-markdown-paragraph" id="bkmrk-%E2%9C%85-%E4%BA%A4%E4%BB%98%E6%A0%87%E5%87%86%EF%BC%9A%E5%AE%8C%E6%95%B4%E5%8F%AF%E8%BF%90%E8%A1%8C-demo-%2B-"><span class="qwen-markdown-text">✅ </span>**<span class="qwen-markdown-text">交付标准</span>**<span class="qwen-markdown-text">：完整可运行 Demo + 架构图 + 压测报告 + </span>`perf`<span class="qwen-markdown-text">/RenderDoc 截图 + 5 分钟演示视频。</span></div><div class="qwen-markdown-space" id="bkmrk--12">  
</div><div class="qwen-markdown-hr" id="bkmrk--13">---

</div>### <span class="qwen-markdown-text">技术栈归属速查表（面试防御用）</span>

<div class="qwen-markdown-table-wrapper" id="bkmrk-%E6%A8%A1%E5%9D%97-c%2B%2B-qml-%E8%AF%B4%E6%98%8E-%E7%BD%91%E7%BB%9C%E6%8B%89%E6%B5%81-%28"><div class="qwen-markdown-table-header"><div class="qwen-markdown-table-header-action-item"><span class="anticon" role="img"><svg aria-hidden="true" class="" fill="currentColor" focusable="false" height="1em" width="1em"></svg></span></div></div><div class="qwen-markdown-table-scroll-wrapper"><table class="qwen-markdown-table"><thead class="qwen-markdown-table-thead"><tr class="qwen-markdown-table-thead-tr"><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">模块</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">C++</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">QML</span></div></th><th class="qwen-markdown-table-thead-tr-th" scope="col"><div class="qwen-markdown-table-thead-tr-th-col"><span class="qwen-markdown-text">说明</span></div></th></tr></thead><tbody class="qwen-markdown-table-tbody"><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">网络拉流 (SRT/UDP)</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`avio`<span class="qwen-markdown-text"> 回调或 </span>`libsrt`<span class="qwen-markdown-text"> 封装</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">解复用/解码 (FFmpeg)</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">纯 C++ 异步管线</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">音视频同步 (AVSync)</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">音频主时钟 + 丢帧/重复帧逻辑</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">硬解 Fallback</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`AVHWDeviceContext`<span class="qwen-markdown-text"> 管理</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">零拷贝渲染 (PBO/EGL)</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">OpenGL + </span>`QQuickFramebufferObject`</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">Jitter Buffer / PLC</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">动态队列 + 音频插值</span></div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">状态机 / 日志 / 性能探针</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QStateMachine`<span class="qwen-markdown-text"> + </span>`spdlog`</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">UI 控件 / 主题 / 动画</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">❌</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">纯 QML，绑定 </span>`Q_PROPERTY`</div></td></tr><tr class="qwen-markdown-table-tbody-tr"><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">视频画面显示</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">⚠️ C++ 渲染，QML 占位</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col"><span class="qwen-markdown-text">✅</span></div></td><td class="qwen-markdown-table-tbody-tr-td"><div class="qwen-markdown-table-tbody-tr-td-col">`QQuickItem`<span class="qwen-markdown-text"> 仅占位，纹理由 C++ 注入</span></div></td></tr></tbody></table>

</div></div><div class="qwen-markdown-hr" id="bkmrk--14">---

</div>### <span class="qwen-markdown-text">面试怎么讲这套技术链？（话术模板）</span>

> <div class="qwen-markdown-paragraph"><span class="qwen-markdown-text">“项目采用 </span>**<span class="qwen-markdown-text">C++ 媒体引擎 + QML 表现层</span>**<span class="qwen-markdown-text"> 严格分离架构。底层基于 FFmpeg 实现解复用与软硬解码管线，通过 </span>`AVHWDeviceContext`<span class="qwen-markdown-text"> 管理硬件解码器，失败时自动 Fallback 到软解。渲染端使用 PBO 零拷贝技术将 GPU 帧直接映射为 OpenGL 纹理，通过 </span>`QQuickFramebufferObject`<span class="qwen-markdown-text"> 安全注入 QML 场景图，彻底避开 CPU-GPU 同步瓶颈。</span>  
> <span class="qwen-markdown-text">音视频同步采用</span>**<span class="qwen-markdown-text">音频主时钟策略</span>**<span class="qwen-markdown-text">，根据 PTS 与硬件播放进度差值动态丢帧/重复帧，同步误差控制在 ±15ms。弱网层实现动态 Jitter Buffer，基于 RTT 方差与丢包率滑动窗口调整缓冲深度，配合基础 PLC 保证 15% 丢包下卡顿率 &lt;2%。</span>  
> <span class="qwen-markdown-text">全链路通过 </span>`spdlog`<span class="qwen-markdown-text"> 埋点与 </span>`perf`<span class="qwen-markdown-text">/RenderDoc 压测，首帧 ≤450ms，1080p@30fps 硬解 CPU &lt;7%，内存 72h 压测波动 &lt;3%。”</span></div>

<div class="qwen-markdown-paragraph" id="bkmrk-%E6%9C%AC%E9%A1%B9%E7%9B%AE%E5%8D%87%E7%BA%A7%E8%B7%AF%E7%BA%BF-%E9%98%B6%E6%AE%B5%E4%B8%80-%E5%9F%BA%E7%A1%80%E6%92%AD%E6%94%BE%E7%AE%A1%E7%BA%BF%EF%BC%9A%E8%84%B1"><div class="qwen-markdown-paragraph" data-spm-anchor-id="a2ty_o01.29997173.0.i31.6dd955fb04UozS"><span class="qwen-markdown-text">本项目升级路线 阶段一 基础播放管线：脱离QtMultimedia，直接使用FFmpeg API实现解复用，软解码，音画同步，完成MP4与HLS基础播放 阶段二 硬件加速与渲染：接入DXVA2或NVDEC实现硬解，完成YUV到RGB色彩空间转换，使用OpenGL或DirectX实现零拷贝渲染，优化首屏耗时 阶段三 流控与质量保障：实现HLS自适应码率切换逻辑，设计多级缓冲策略，添加网络状态监控，实现卡顿统计与播放质量数据上报 阶段四 工程化架构重构：将播放引擎抽离为独立C加加动态库，提供线程安全接口，实现配置热加载，日志分级，内存池管理，补充单元测试与压测脚本</span></div></div>