Skip to content

Commit db28a77

Browse files
committed
feat: the U cell decodes first once its stream plays (#94; Qodo on #111)
1 parent b25bbab commit db28a77

4 files changed

Lines changed: 13 additions & 6 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ adb shell am start -a android.intent.action.SEND -t text/plain \
8989

9090
### Multi-view (Quad)
9191

92-
Shows the configured slots in a 2×2 grid, or in a 3×3 grid once any of slots 5–8 is used. The ninth cell of the 3×3 grid, the **U** cell, plays a camera that pushes RTP over UDP to port 5600 of the device (`udp://@:5600`, see [udp:// slots](#udp-slots-majestic-outgoing)); until a stream arrives it shows every address of the device to send to. **U** in the menu opens it full-screen. Other ports or multicast groups go into a slot as a `udp://` URL. Each cell has its own connection and decoder, and the device's video decoder has a fixed budget: the AG-216 test box, for example, decodes about two 1080p30 streams at full rate. So the grid adapts: cells start on key frames only, then decode every frame in priority order (the cell whose sound plays, then slot order) while the decoder keeps up. Cells beyond that stay on key frames, with the picture updated once per key frame interval (`key frames` in the corner text, menu **D**). The limit is learnt on each device by measurement. Substreams of the cameras, where available, let more cells play at full rate. A cell over the decoder's instance limit shows `Decoder limit: N × H.265`. Some cameras accept only one RTSP client at a time. Long-press a cell to play its audio (long-press it again to mute); the selected cell shows an AUDIO badge and is remembered. Tap any cell to open the menu.
92+
Shows the configured slots in a 2×2 grid, or in a 3×3 grid once any of slots 5–8 is used. The ninth cell of the 3×3 grid, the **U** cell, plays a camera that pushes RTP over UDP to port 5600 of the device (`udp://@:5600`, see [udp:// slots](#udp-slots-majestic-outgoing)); until a stream arrives it shows every address of the device to send to. **U** in the menu opens it full-screen. Other ports or multicast groups go into a slot as a `udp://` URL. Each cell has its own connection and decoder, and the device's video decoder has a fixed budget: the AG-216 test box, for example, decodes about two 1080p30 streams at full rate. So the grid adapts: cells start on key frames only, then decode every frame in priority order (the U cell while it receives a stream, the cell whose sound plays, then slot order) while the decoder keeps up. Cells beyond that stay on key frames, with the picture updated once per key frame interval (`key frames` in the corner text, menu **D**). The limit is learnt on each device by measurement. Substreams of the cameras, where available, let more cells play at full rate. A cell over the decoder's instance limit shows `Decoder limit: N × H.265`. Some cameras accept only one RTSP client at a time. Long-press a cell to play its audio (long-press it again to mute); the selected cell shows an AUDIO badge and is remembered. Tap any cell to open the menu.
9393

9494
## Transports
9595

‎README.ru.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ adb shell am start -a android.intent.action.SEND -t text/plain \
8989

9090
### Мультивид (Quad)
9191

92-
Показывает настроенные слоты сеткой 2×2, а если занят хотя бы один из слотов 5–8 — сеткой 3×3. Девятая ячейка сетки 3×3, ячейка **U**, показывает камеру, которая сама отправляет RTP по UDP на порт 5600 устройства (`udp://@:5600`, см. [слоты udp://](#слоты-udp-majestic-outgoing)); пока поток не пришёл, в ней перечислены все адреса устройства, куда его слать. Кнопка **U** в меню открывает её на весь экран. Другие порты и multicast-группы указываются в слоте адресом `udp://`. У каждой ячейки своё подключение и свой декодер, а у видеодекодера устройства постоянный бюджет: тестовая приставка AG-216, например, декодирует в полном темпе примерно два потока 1080p30. Поэтому сетка подстраивается: ячейки стартуют на ключевых кадрах, затем по приоритету (ячейка со звуком, потом по номеру слота) переходят на все кадры, пока декодер успевает. Остальные остаются на ключевых кадрах — картинка обновляется раз в интервал между ключевыми кадрами (в тексте в углу — `key frames`, меню **D**). Предел определяется замером на каждом устройстве. Дополнительные потоки камер (substream), если они есть, позволяют показать в полном темпе больше ячеек. Ячейка сверх лимита экземпляров декодера показывает `Decoder limit: N × H.265`. Некоторые камеры допускают только одно RTSP-подключение одновременно. Долгое нажатие на ячейку включает её звук (повторное — выключает); у выбранной ячейки виден значок AUDIO, выбор запоминается. Коснитесь любой ячейки, чтобы открыть меню.
92+
Показывает настроенные слоты сеткой 2×2, а если занят хотя бы один из слотов 5–8 — сеткой 3×3. Девятая ячейка сетки 3×3, ячейка **U**, показывает камеру, которая сама отправляет RTP по UDP на порт 5600 устройства (`udp://@:5600`, см. [слоты udp://](#слоты-udp-majestic-outgoing)); пока поток не пришёл, в ней перечислены все адреса устройства, куда его слать. Кнопка **U** в меню открывает её на весь экран. Другие порты и multicast-группы указываются в слоте адресом `udp://`. У каждой ячейки своё подключение и свой декодер, а у видеодекодера устройства постоянный бюджет: тестовая приставка AG-216, например, декодирует в полном темпе примерно два потока 1080p30. Поэтому сетка подстраивается: ячейки стартуют на ключевых кадрах, затем по приоритету (ячейка U, пока в неё идёт поток, ячейка со звуком, потом по номеру слота) переходят на все кадры, пока декодер успевает. Остальные остаются на ключевых кадрах — картинка обновляется раз в интервал между ключевыми кадрами (в тексте в углу — `key frames`, меню **D**). Предел определяется замером на каждом устройстве. Дополнительные потоки камер (substream), если они есть, позволяют показать в полном темпе больше ячеек. Ячейка сверх лимита экземпляров декодера показывает `Decoder limit: N × H.265`. Некоторые камеры допускают только одно RTSP-подключение одновременно. Долгое нажатие на ячейку включает её звук (повторное — выключает); у выбранной ячейки виден значок AUDIO, выбор запоминается. Коснитесь любой ячейки, чтобы открыть меню.
9393

9494
## Транспорты
9595

‎README.zh-CN.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ adb shell am start -a android.intent.action.SEND -t text/plain \
8989

9090
### 多画面模式(Quad)
9191

92-
以 2×2 网格显示已配置的槽位;只要使用了第 5–8 个槽位中的任意一个,就改为 3×3 网格。3×3 网格的第九格即 **U** 画面,播放通过 UDP 向本设备 5600 端口主动推送 RTP 的摄像机(`udp://@:5600`,参见 [udp:// 槽位](#udp-槽位-majestic-outgoing));收到流之前,其中列出本设备可用于推流的所有地址。菜单中的 **U** 可将其全屏显示。其他端口或组播组请在槽位中填写 `udp://` 地址。每个画面都有独立的连接和解码器,而设备视频解码器的处理能力是固定的:例如测试用的 AG-216 盒子以全帧率大约只能解码两路 1080p30。因此网格会自适应:各画面先只解码关键帧,然后按优先级(正在播放声音的画面,其次按槽位顺序)在解码器跟得上时切换为全帧率。其余画面保持只解码关键帧,画面按关键帧间隔更新(角落文字显示 `key frames`,菜单 **D**)。上限在每台设备上通过实测确定。如摄像机提供子码流,可让更多画面以全帧率播放。超出解码器实例上限的画面显示 `Decoder limit: N × H.265`。部分摄像机同一时间只允许一个 RTSP 客户端。长按某个画面即可播放其声音(再次长按则静音);被选中的画面显示 AUDIO 标记,选择会被记住。点击任意画面即可打开菜单。
92+
以 2×2 网格显示已配置的槽位;只要使用了第 5–8 个槽位中的任意一个,就改为 3×3 网格。3×3 网格的第九格即 **U** 画面,播放通过 UDP 向本设备 5600 端口主动推送 RTP 的摄像机(`udp://@:5600`,参见 [udp:// 槽位](#udp-槽位-majestic-outgoing));收到流之前,其中列出本设备可用于推流的所有地址。菜单中的 **U** 可将其全屏显示。其他端口或组播组请在槽位中填写 `udp://` 地址。每个画面都有独立的连接和解码器,而设备视频解码器的处理能力是固定的:例如测试用的 AG-216 盒子以全帧率大约只能解码两路 1080p30。因此网格会自适应:各画面先只解码关键帧,然后按优先级(正在接收流的 U 画面,其次是正在播放声音的画面,再按槽位顺序)在解码器跟得上时切换为全帧率。其余画面保持只解码关键帧,画面按关键帧间隔更新(角落文字显示 `key frames`,菜单 **D**)。上限在每台设备上通过实测确定。如摄像机提供子码流,可让更多画面以全帧率播放。超出解码器实例上限的画面显示 `Decoder limit: N × H.265`。部分摄像机同一时间只允许一个 RTSP 客户端。长按某个画面即可播放其声音(再次长按则静音);被选中的画面显示 AUDIO 标记,选择会被记住。点击任意画面即可打开菜单。
9393

9494
## 传输方式
9595

‎android/app/src/main/java/com/openipc/decoder/Decoder.java‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,12 +990,19 @@ private void planDecoding(QuadCell[] cells, long now) {
990990
boolean learntBefore = planner.isLearnt();
991991

992992
java.util.List<DecodePlanner.Cell> order = new java.util.ArrayList<>();
993-
// Priority: the cell whose sound plays, then slot order
994-
if (quadAudio >= 0 && quadAudio < cells.length && cells[quadAudio] != null) {
993+
// Priority: the U cell once its stream plays (#94), the cell whose sound plays, then
994+
// slot order. While U receives nothing it stays last and takes no share
995+
int first = U_CELL < cells.length && cells[U_CELL] != null && cells[U_CELL].isPlaying()
996+
? U_CELL : -1;
997+
if (first >= 0) order.add(plannerCell(first, cells[first], now));
998+
if (quadAudio >= 0 && quadAudio < cells.length && cells[quadAudio] != null
999+
&& quadAudio != first) {
9951000
order.add(plannerCell(quadAudio, cells[quadAudio], now));
9961001
}
9971002
for (int i = 0; i < cells.length; i++) {
998-
if (cells[i] != null && i != quadAudio) order.add(plannerCell(i, cells[i], now));
1003+
if (cells[i] != null && i != quadAudio && i != first) {
1004+
order.add(plannerCell(i, cells[i], now));
1005+
}
9991006
}
10001007
DecodePlanner.Decision d = planner.step(order, now);
10011008
if (d.action != DecodePlanner.Action.NONE) {

0 commit comments

Comments
 (0)