Repository navigation
Releases: OpenIPC/PixelPilot
Releases · OpenIPC/PixelPilot
Release list
v0.25.0
Bound how long the packet queue holds a frame back (#120) * Bound how long the packet queue holds a frame back BufferedPacketQueue reorders the RTP stream before it reaches the parser. When a packet is missing it holds everything behind the gap, which is right for a reorder and wrong for a loss - and past wfb-ng, on a loopback socket, a gap is almost always a loss that FEC could not recover. Three things made that wait longer than it needs to be. The monotonic-increase escape hatch, which exists precisely to notice "the sequence numbers keep climbing but the gap is not filling", never fires. calculateDistance(a, b) is how far b is ahead of a - seqLessThan reads it that way - but the call site asks for the distance from the incoming packet to the last delivered one. For a gap ahead of us that is negative, so the else branch clears the counter on every single packet. Fixing the argument order alone is not enough: the counter is only incremented while abs(dist) < MONOTONIC_THRESHOLD, and dist grows by one with every packet held back. Compared against the same constant that gates it, the counter tops out at three and can never reach five. The gate is now its own constant, so a run past a gap releases the buffer after five packets instead of never. That leaves MAX_BUFFER_SIZE as the only bound, and how much latency fifteen packets is depends entirely on the packet rate: about 20ms on a 1080p video stream, but roughly 300ms on the audio stream, which runs at a fraction of it. The buffer is now also bounded in time, so the worst case is the same on both. Twenty milliseconds is a little over one frame at 60fps and several orders of magnitude more than a loopback socket needs to reorder anything. Nothing is dropped by any of this - the buffered packets are still delivered, just without waiting on one that is not coming. The test target could not be built on a case-sensitive filesystem, since CMakeLists.txt spelled the source BufferedPacketqueue_test.cpp. The existing two cases both turn out to feed a strictly in-order stream, so neither reached the buffer at all; the new ones cover a permanent gap, the age bound, a reorder that resolves inside it, and a jump too large to be one. They drive the clock themselves rather than reading it, so the age bound cannot make them flaky on a loaded machine. * Advance the queue past everything a flush delivered Two problems with the flush, both found in review. restartBuffering() set mLastPacketIdx to the packet that triggered the flush rather than the newest one delivered. With 1..5 delivered, 6 lost, then 7 8 9 12 10, the flush hands over 7 8 9 10 12 but leaves the pointer on 10 - so 11 would be delivered after 12, and 13..16 are held until 17 arrives. The queue re-created the stall it exists to prevent. bufferPacket() always runs before the flush, so the triggering packet is in the buffer either way and mLastPacketIdx = drainBufferInOrder() is all that was needed; restartBuffering() is gone. That alone would have broken the resync on a large jump, because drainBufferInOrder() seeded `highest` from mLastPacketIdx and compared with calculateDistance(), which reads as negative past half the sequence space. RTP starts at a random sequence number, so a VTX that reboots mid-session lands exactly there: fed 1, 2, then 40000, 40001, ..., neither the seed nor the comparison ever moves and every packet comes out one flush late, forever. On video the fifteen-packet cap used to paper over it by rewinding to currPacketIdx; on audio nothing did. `highest` is now seeded from a packet that is actually in the buffer. While sorting the flush: by raw value a block straddling the wrap point (65534, 65535, 0, 1) sorts to 0, 1, 65534, 65535 and was handed to the parser in that order. Sorting by distance from the last delivered packet fixes the order and makes the last element the newest. Three tests added, one per problem. The large-jump case uses 40000 - the existing LargeJumpFallsBackToTheBufferCap uses 30000, which is still positive as an int16 and does not reach any of this.
v0.24.0
Feat: Add Real-time Object Detection with MediaPipe (#108) * feat(detection): add real-time object detection using Google MediaPipe - Replace main SurfaceView with TextureView to support capturing frame Bitmaps via getBitmap(). - Add ObjectDetectorHelper to encapsulate MediaPipe Object Detector Task API with CPU/GPU delegates. - Create OverlayView for scaling and rendering bounding boxes and classification labels onto standard video stream. - Integrate background detection thread execution loop (~10 FPS) in VideoActivity with lifecycle management. - Set up automated downloads for EfficientDet-Lite0 and EfficientDet-Lite2 model assets in app/build.gradle. - Add user menu toggles for object detection settings, persisting config values via SharedPreferences. - Update README.md with detailed instructions for the object detection feature. Reference: https://github.com/google-ai-edge/mediapipe-samples/tree/main/examples/object_detection * Optimize size - Removed tflite file from apk; - Optimize MediaPipe size (Keep arm64, remove 32bit support); - Compress releasefile Final apk 9.4MB :app-release_object_detection.apk
Test build — MediaTek no-video fix (issue #6)
Unofficial test build for #6 (no video on MediaTek devices).
Contains the devourer 16 KB RX URB fix (OpenIPC/devourer#317) + heap RX ring, built from branch restore-mtk-16k-fix (PR #107) at commit 609110e. Not an official release — for validation on affected MediaTek devices (Dimensity 810, Helio G99, MT6765) before the PR is merged.
Built by GitHub Actions from the PR branch. Reproduce: check out PR #107.
v0.23.1
v0.23.0
v0.22.0
This release fixes compatibility issue with Bonnet device
v0.21.0
v0.9.0
Fix FEC calculation for 0 FEC, initialise FEC properly (#71)
v0.8.1
v0.8.0
Stop VPN service when minimized (#70)