目录
一.背景
RK项目投屏电脑失败,具体操作如下:
Test condition:1.笔记本与待测设备连接同一WiFi网络
2.进入"控制面板" > "网络和Internet" > "网络和共享中心",将网络类型改为"家庭网络
3.控制面板-投影到此电脑-点击"启动连接应用以投影到此电脑"
Package Path:qdisk:/Project/Module Project Files/Smart/RK3576/BA02/SH603Z/AP/NA/Fimware/Release/SH603ZAAPNAR01A01_BA02BP01K0M01_AP16.0.0.01.001_V02
Recurrence Probability:100%
1.使用笔记本电脑按操作设置好投影功能
2.设备与笔记本电脑连接同一WiFi
3.设备点击settings-Connected devices-Connection preferences-Cast,点击连接搜索到的笔记本设备,查看是否能勾投屏成功
Expected Result:
3.投屏成功,笔记本电脑屏幕显示待测设备屏幕信息
Contrast Test:\
Actual Result:
3.点击PC|进行连接无法成功
二.排查过程
首先整个设备投屏电脑过程的流程图如下

然后我们分析流程如下:
由于点击投屏的时候是几百毫秒后投屏失败,说明肯定是p2p连接成功了,并且是像电脑进行协商请求了,电脑给拒绝了,所以就是在RTSP这块有问题
然后根据日志进行详细排查
这份日志是绝佳的"案发现场铁证"!它百分之百证实了我们前面所有的推论!
在日志中,5 次尝试投屏(全部失败),每一次都完美记录了:上层发出了错误的 24
帧协商报文(idx=15),导致底层编码器在请求了几帧画面后被被迫关闭(shutting
down video encoder)。
下面为你逐条提取日志中的 3 大核心铁证:
铁证一:协商报文里明确写着 idx=15(720p 24帧)
看日志中的 第 17946 行(以及 19773、23381、24730、27911 行,每次尝试都一样):
行 17946: 07-18 10:07:47.415 732 2357 I WifiDisplaySource: M4 wfd_video_formats: 00 00 01 10 00008000 00000000 00000000 00 0000 0000 00 none none (profile=0 level=4 type=0 idx=15)
↑ ↑
【十六进制 Mask 00008000】 【明确写着 idx=15】
-
idx=15:在 Wi-Fi Display (WFD) 规范中,CEA Index 15 正好代表 1280x720p 24fps!
-
00008000:转成二进制第 15 位是 1,代表只勾选了 24 帧。
-
结论:这就是上层代码 WifiDisplaySource.cpp 在发"假消息"的现场抓包证据!
铁证二:电视(Sink)其实支持 30 帧,但被手机强行诱导选了 24 帧
看日志中的 第 17941 行(电视发给手机的能力):
行 17941: 07-18 10:07:47.415 732 2357 I WifiDisplaySource: Sink wfd_video_formats: 40 00 01 10 0001bdeb ...
↑
电视支持的掩码 0001bdeb
-
电视发来的掩码 0001bdeb 包含 0x00000020(代表电视完全支持 720p 30帧)。
-
但是手机的 WifiDisplaySource.cpp 因为写死了 idx=15,死板地挑了 24 帧(idx=15)发给电视。
铁证三:编码器刚启动,就被迫异常关闭(shutting down)
看日志中的 第 18005 ~ 18567 行(一次完整的崩溃周期):
行 18005: 10:07:47.515 I Converter: using audio bitrate of 128000 bps, video bitrate of 5000000 bps <-- 1. 编码器启动
行 18325: 10:07:47.649 I Converter: start cast and request IDR Frame <-- 2. 开始请求关键帧推流
行 18546: 10:07:50.111 I Converter: shutting down video encoder <-- 3. 2.4秒后,收到挂断,编码器被迫关闭!
行 18567: 10:07:50.118 I Converter: encoder (video/avc) shut down. <-- 4. H.264 视频编码器正式死亡
从 10:07:47 到 10:07:50,仅仅过了 2 秒钟:
-
底层 Converter 按照固定代码(30帧)初始化了编码器,并开始发 IDR 帧。
-
电视在校验完 RTSP 参数(24帧 vs 30帧)后,砸过来断开指令。
-
Converter 收到上层通知,打印 shutting down video encoder,投屏宣告失败。
💡 总结:日志完美印证了排查结论
你抓到的这 50 行日志,完整复现了循环失败的过程: 发送错误 M4(idx=15) \rightarrow Converter 按照 30帧 启动
\rightarrow 电视发现矛盾挂断 \rightarrow Converter 关闭(shutting down) \rightarrow
重试下一轮...
这直接解释了为什么当你把 WifiDisplaySource.cpp 里的 idx=15 改成 idx=5(720p 30帧) 后,问题就迎刃而解了!
根据上述排查,绘制出异常的流程图如下:

三.具体修改
由于底层修改太过麻烦,而且可能要动硬件,所以我们在Framework层进行修改,patch如下:
diff --git a/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 42f4595..63154c3 100644
--- a/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/SYS_CODE/frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -74,13 +74,13 @@
mSupportedSourceVideoFormats.disableAll();
mSupportedSourceVideoFormats.setNativeResolution(
- VideoFormats::RESOLUTION_CEA, 15); // 1280x720 p23
+ VideoFormats::RESOLUTION_CEA, 5); // 1280x720 p30
- // Enable all resolutions up to 1280x720 p23
+ // The encoder is configured for 30 fps, so do not negotiate 720p24.
mSupportedSourceVideoFormats.enableResolutionUpto(
- VideoFormats::RESOLUTION_CEA, 15,
- VideoFormats::PROFILE_CHP, // Constrained High Profile
- VideoFormats::LEVEL_32); // Level 3.2
+ VideoFormats::RESOLUTION_CEA, 5,
+ VideoFormats::PROFILE_CBP, // Constrained Baseline Profile
+ VideoFormats::LEVEL_31); // Matches the encoder output
}
WifiDisplaySource::~WifiDisplaySource() {
@@ -577,6 +577,8 @@
chosenVideoFormat.disableAll();
chosenVideoFormat.setNativeResolution(
mChosenVideoResolutionType, mChosenVideoResolutionIndex);
+ chosenVideoFormat.setResolutionEnabled(
+ mChosenVideoResolutionType, mChosenVideoResolutionIndex, true);
chosenVideoFormat.setProfileLevel(
mChosenVideoResolutionType, mChosenVideoResolutionIndex,
mChosenVideoProfile, mChosenVideoLevel);
四.拓展知识(RTSP是啥)
简单来说:RTSP(Real-Time Streaming Protocol,实时流协议)就像是无线投屏里的"遥控器"和"商务谈判官"。
在投屏过程中,它不负责传输画面本身(画面是用 RTP 协议发传输的),它只负责发送控制命令和谈判参数。
一、 用生活中的通俗比喻理解 RTSP
把无线投屏比作 "两个人打视频电话":
-
RTSP(控制协议):相当于通话前的沟通和通话中的控制指令。
-
"喂,能听到吗?"
-
"你家电视能放 720p 的视频吗?"
-
"好的,那我准备按播放键了(PLAY)!"
-
"不看了,挂断吧(TEARDOWN)!"
-
RTP(媒体传输协议):相当于真正通过网络传输的摄像头画面和语音数据包。
二、 RTSP 在 Wi-Fi 投屏里具体做了什么?(4 大核心作用)
在手机(RK3576)和电视建立好 Wi-Fi 直连后,RTSP 会在背景建立一个专属的控制通道(TCP 端口 7236),顺次完成以下 4 件事:
1. 能力谈判 (M1\~M5)\] --\> \[2. 通道建立 (SETUP)\] --\> \[3. 启动播放 (PLAY)\] --\> \[4. 维持心跳/挂断 (TEARDOWN)
- 商务谈判:协商音视频格式(M1 ~ M5 报文)
-
这是本次 Bug 发生的重灾区!
-
手机通过 RTSP 问电视:"我支持 H.264 编码,你能解 720p 30 帧吗?"
-
电视回复:"可以,我也支持 720p 30 帧。"
-
双方达成一致。
- 搭桥开路:建立媒体通道(SETUP 报文)
-
手机对电视说:"一会儿我把视频画面发到你的 19000 端口,音频发到你的 19002 端口,你准备好接受了吗?"
-
电视回复:"准备好了,端口已打开。"
- 遥控开关:控制播放状态(PLAY / PAUSE 报文)
-
手机发出指令:PLAY(电视开始接收画面并播放)。
-
手机发出指令:PAUSE(暂停投屏)。
- 维持心跳与挂断(GET_PARAMETER / TEARDOWN 报文)
-
心跳:投屏过程中,RTSP 每隔几秒发一个微弱的信号,确保"你还活着",防止断连。
-
挂断:当你点击手机上的"停止投屏"时,RTSP 会发一条 TEARDOWN,电视收到后关闭解码器,退回主界面。
三、 RTSP 与 RTP 的分工对照表
很多小白容易把 RTSP 和视频流搞混,看下面这张表就彻底明白了:
| 维度 | RTSP (控制协议) | RTP (媒体数据协议) |
| :------------ | :----------------------- | :---------------------- |
| **形象比喻** | 司令部的**指挥电话/命令** | 前线的**运粮车/视频像素** |
| **传输内容** | 纯文本指令(如 `PLAY`, `SETUP`) | 压缩后的 H.264 视频帧、AAC 音频帧 |
| **传输网络** | TCP(保证指令 100% 准确不丢包) | UDP(追求速度,丢一两帧画面不影响) |
| **在本次故障中的角色** | **代码写错了谈判内容**(声明了 24 帧) | 实际上运送的是 30 帧的数据车,导致电视拒收 |
四、 回看本次问题
在你的 RK3576 项目中:
-
底层 Converter.cpp 已经准备好了 30 帧的视频流(RTP 准备就绪)。
-
但是上层 WifiDisplaySource.cpp 里的 RTSP 谈判官 跑去对电视说:"我们要发 24 帧哦!"
-
电视在 RTSP 的 SETUP 阶段 校验发现这名"谈判官"说假话,于是电视也通过 RTSP 协议 砸过来一条
TEARDOWN(终止会话命令),直接把投屏掐断了。