Skip to content

fix: YL3 frames from several pieces in one datagram (#187) - #224

Merged
compot-dev merged 4 commits into
v2from
fix/jieli-pieces-187
Oct 16, 2026
Merged

compot-dev merged 4 commits into
v2from
fix/jieli-pieces-187

Conversation

@compot-dev

@compot-dev compot-dev commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #187. Version 2.16 (#220 moves to 2.17).

The YL3 report on 2.15 showed the picture upright and whole but freezing after 0.5–1 s, with odd colours and blocks. Its log and raw frame explain it: a datagram on UDP 2224 can hold several pieces one after another, each with its own 20-byte header (3104 bytes = 20 + 2964 + 20 + 100 for a 3064-byte frame; 4640 = 20 + 2964 + 20 + 1636 for a 4600-byte one).

  • Test build 3 read the whole datagram as one piece: the second header went into the JPEG (broken lower half, wrong colours).
  • 2.15 read only the first piece: every frame longer than 2964 bytes stayed incomplete (92 of 96 packets dropped) and only small ~2 KB frames, blocky and reddish as the toy sends them, were shown — so the picture froze.

RtStream.feed() now walks all pieces in a datagram; a completed frame is copied out, so a datagram that also starts the next frame doesn't overwrite it. Tests: rtStreamTwoPiecesInOneDatagram, existing ones.

@compot-dev

Copy link
Copy Markdown
Collaborator Author

Checked on Aceline-1 (2.17, 4309e31) with a fake YL3 on the lab host (CTP on TCP 3333, then 240×320 JPEGs of ~21 KB at 10 fps to UDP 2224, cut into 2964-byte pieces, all pieces of a frame in one datagram, headers as the real toy sends them): 90 datagrams → 90 frames, 0 dropped, 10 fps, turned 90° and upright, picture and colours as sent. Grid and the other slots play as before.

@compot-dev
compot-dev marked this pull request as ready for review October 16, 2026 19:02
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix YL3 video frames spanning multiple pieces in one UDP datagram

🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Parse every JPEG piece in YL3 UDP datagrams to prevent incomplete or corrupted frames.
• Preserve completed frames when a datagram also contains pieces of the next frame.
• Add regression coverage and document YL3 support in version 2.16.
Diagram

graph TD
  UDP["UDP 2224"] --> Walk["Datagram walker"] --> Piece["Piece parser"] --> Assemble["Frame assembly"] --> Check{"JPEG complete?"}
  Check -->|yes| Ready["Ready frame"] --> Listener["Video listener"]
  Check -->|no| Walk
  Ready -->|more pieces| Walk
Loading
High-Level Assessment

Extending the existing RtStream assembler is appropriate: it retains established handling for offsets, duplicates, and incomplete frames while fixing datagram traversal. A separate parser or frame queue would add complexity without a demonstrated need.

Files changed (5) +83 / -34

Bug fix (1) +40 / -19
Jieli.javaParse successive YL3 pieces within each datagram +40/-19

Parse successive YL3 pieces within each datagram

• RtStream.feed now advances through all piece headers and payloads instead of processing only the first piece. A separate ready buffer retains the latest completed JPEG when parsing continues into another frame.

android/app/src/main/java/com/openipc/decoder/Jieli.java

Tests (1) +30 / -2
JieliTest.javaCover multiple pieces and frames in one datagram +30/-2

Cover multiple pieces and frames in one datagram

• Adds a regression test for a 3064-byte JPEG split across two pieces in one datagram and checks that the later of two completed frames is returned. Revises the existing piece-boundary test comment.

android/app/src/test/java/com/openipc/decoder/JieliTest.java

Documentation (2) +11 / -11
toys.mdDocument confirmed YL3 support and piece framing +10/-10

Document confirmed YL3 support and piece framing

• Marks YL3 video as working since 2.16 and explains that one UDP datagram may contain several header-prefixed JPEG pieces. Updates the tested-toy status and describes the symptoms caused by earlier parsing behavior.

docs/toys.md

transports.mdMark the Jieli transport as working with YL3 +1/-1

Mark the Jieli transport as working with YL3

• Replaces the experimental 2.15 status with confirmed YL3 support since 2.16.

docs/transports.md

Other (1) +2 / -2
build.gradleBump Android version to 2.16 +2/-2

Bump Android version to 2.16

• Increases versionCode from 40 to 41 and versionName from 2.15 to 2.16.

android/app/build.gradle

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Trailing pieces can discard a live frame ✓ Resolved
Description
feed() parses every suffix longer than 20 bytes as another piece, and piece() starts a new
assembly whenever that piece declares a different frame size. If a datagram contains a current
fragment followed by a delayed fragment from an earlier frame, the delayed fragment discards the
current assembly before its remaining pieces arrive.
Code

android/app/src/main/java/com/openipc/decoder/Jieli.java[R634-638]

+            while (end - pos > HEADER) {
+                int length = (b[pos + 2] & 0xFF) | (b[pos + 3] & 0xFF) << 8;
+                // No length, or more than is left: the rest of the datagram is the piece
+                if (length == 0 || length > end - pos - HEADER) length = end - pos - HEADER;
+                int n = piece(b, pos, length);
Evidence
The new loop passes each trailing segment to piece(). A different declared total then calls
startFrame(), which drops an unfinished assembly; the repository's trailing-data test establishes
that data after a declared piece need not belong to the current frame.

android/app/src/main/java/com/openipc/decoder/Jieli.java[630-645]
android/app/src/main/java/com/openipc/decoder/Jieli.java[655-670]
android/app/src/main/java/com/openipc/decoder/Jieli.java[695-700]
android/app/src/test/java/com/openipc/decoder/JieliTest.java[159-172]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Parsing every trailing piece allows a delayed fragment from an older frame to replace the frame currently being assembled.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Jieli.java[630-670]
- android/app/src/test/java/com/openipc/decoder/JieliTest.java[131-172]
## Recommended Fix
Use the header's frame or packet counter to distinguish delayed pieces from a new frame before calling `startFrame`. Add a test with a current fragment, a trailing older-frame fragment, and the current frame's remaining fragment.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can pick a display mode instead of tweaking every Display option by hand

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread android/app/src/main/java/com/openipc/decoder/Jieli.java
@compot-dev
compot-dev merged commit 06a2ad6 into v2 Oct 16, 2026
4 checks passed
compot-dev added a commit that referenced this pull request Oct 16, 2026
@compot-dev
compot-dev deleted the fix/jieli-pieces-187 branch October 16, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

new feature: receiving udp video strem from cheap toys with wifi cam's

1 participant