Skip to content

Releases: GingerFluffyCat/PixelPilot

v0.5.0 - Rebased onto devourer's rebuild-on-upstream

Choose a tag to compare

@GingerFluffyCat GingerFluffyCat released this 24 Jul 22:37

The devourer submodule now points at v0.5.1 (rebuild-on-upstream): upstream
OpenIPC/devourer's current architecture (async-URB-pool RX -> IRtlDevice::
StartRxLoop, PCIe transport, Jaguar2/3/Kestrel chip support) with every
APFPV capability re-ported and verified building — no regression:

  • Full WPA2/CCMP station-mode connect (scan -> arm -> auth -> assoc -> 4-way
    -> DHCP -> RTP/LQ streaming), driver-level auto-reconnect, SSH-over-dongle.
  • The close-range DIG-saturation fix (hardware-validated RSSI-tracked gain).
  • A-MPDU RX reorder + the station RX-filter fix.
  • AP mode rewired onto upstream's real hardware beacon/ACK primitives
    (IRtlDevice::StartBeacon/StopBeacon) instead of the old manual register
    pokes + a software beacon-poll loop, per upstream's own bench-validated
    docs/ap-mode.md recipe. Also fixes a real bug: AP-mode TX was calling
    send_packet synchronously from the RX callback thread (returns BUSY by
    design) — now queued to a separate TX-pump thread. Real-hardware
    association is still untested this round.
  • The Android JNI bridge (apfpv_jni.cpp, WfbngLink.cpp) ported onto the new
    IRtlDevice/RtlJaguarDevice API, including a rewritten
    app/wfbngrtl8812/src/main/cpp/CMakeLists.txt (the old file mixed the
    pre-rebuild extern/WiFiDriver/{hal,src} tree with the rebuilt devourer/
    {hal,src} tree on one include path, which broke the build with duplicate
    type definitions). WFB-ng's protocol layer (TxFrame/RxFrame/
    SignalQualityCalculator, no upstream equivalent) still comes from
    extern/WiFiDriver, now re-registered as a proper submodule.

Also: the settings menu now hides dongle-only APFPV actions (VRX beacon
cal, dongle AP test, Reconnect/adapter picker, DE-legal-limits, channel/
width ranges) when in phone-Wi-Fi mode, where there's no dongle for them
to act on.

Verified: a full clean assembleDebug (arm64-v8a + x86_64) builds with zero
errors. Real-hardware validation (dongle connect/stream, AP-mode
association) is still outstanding — this release is a clean build/
architecture milestone, not a hardware-tested one.

v0.4.4 - Upstream merge: UDP forwarding, new adapter recognition

Choose a tag to compare

@GingerFluffyCat GingerFluffyCat released this 24 Jul 20:36

Merged 3 commits from OpenIPC/PixelPilot upstream:

  • UDP Forwarding: new menu option to forward the received video stream
    to a second IP:port. Independent of the APFPV/wfb-ng video path.
  • RTL8812EU/RTL8822EU USB device recognition: new device IDs in
    usb_device_filter.xml so the app requests USB permission for these
    dongles. Note: this only affects device recognition -- our devourer/
    WiFiDriver fork doesn't have driver support for these (Jaguar3-generation)
    chips yet, only the RTL8812AU family (Jaguar1).
  • Docs fix (gs.key link).

Our own APFPV-specific code (WPA2 station-mode, RxDeframe, ApfpvStation,
LqFeedback, the DVR-duration/GL-fanout/dongle-reconnect fixes from v0.4.3)
is unaffected -- verified by resolving each merge conflict to protect it,
then rebuilding.

Debug APK, built 2026-07-24.

v0.4.3 - DVR duration, GL fan-out refresh-rate, dongle reconnect

Choose a tag to compare

@GingerFluffyCat GingerFluffyCat released this 24 Jul 19:20
  • DVR recording duration bug fixed: mp4_h26x_write_nal's last argument
    is the sample's duration, not an absolute timestamp -- was passing the
    cumulative-since-start value, which made recordings play progressively
    slower the longer they ran.
  • GL fan-out now matches the real display refresh rate: the display-swap
    throttle assumed a fixed 60Hz panel; on a 120Hz panel that read as judder
    even though stream and panel were both genuinely ~120fps.
  • Dongle physical unplug/replug reconnect hardening (WFB-ng and APFPV
    dongle paths): openDevice() returning null (a real race right after a
    replug) is now handled instead of crashing with an NPE; USB connections are
    closed on stop so a reattach's openDevice() doesn't race against a
    leaked fd; a stale internal device-map entry from the torn-down session no
    longer gets silently reused on reattach.

Debug APK, built 2026-07-24. CI: https://github.com/AlaEddine-Zoghlami/PixelPilot/actions/runs/30120151316

v0.4.2

Choose a tag to compare

@GingerFluffyCat GingerFluffyCat released this 23 Jul 15:19

Fixed

  • MTK HW HEVC decode — root-caused and fixed the long-standing "MTK HW HEVC freezes" workaround: the H.265 csd-0 buffer (VPS+SPS+PPS) was built in reverse order (PPS,SPS,VPS) due to an insert(begin()) bug, which the software decoder tolerated but the hardware decoder didn't. HW decode is now the default on MTK and sustains 120fps with 0 discards.
  • Decoder stall-recovery watchdog — a MediaTek video-firmware throughput ceiling (confirmed via kernel-level atrace, transport-independent) could permanently freeze the decoder under sustained high bitrate. Added a watchdog that detects "data arriving, 0 frames decoded" and forces a recovery flush, turning a permanent freeze into a bounded ~2-4s recoverable stutter.
  • Stale-frame flush storm — the flush-to-keyframe path could enter a self-sustaining loop on any decoder that fell behind; previously only disabled for the software-decoder fallback, now disabled for MTK regardless of which decoder is active.
  • App-resume reconnect (phone-Wi-Fi)onPause() wasn't stopping ApfpvWifiManager, so its running-guard never reset and onResume()'s reconnect silently no-op'd.
  • Decode-feed thread decouple — a slow decode step could stall the RTP-receive/parse thread; feeding the decoder now runs on its own thread with a bounded, drop-oldest queue.
  • Mutex-starvation fix (devourer/WiFiDriver) — the decoder feed thread's input-buffer retry loop could win a mutex re-acquire race indefinitely against the stall watchdog's recovery flush; added a yield point so recovery can actually land.
  • UAF-prone RX teardown (devourer/WiFiDriver)stopAsyncRx() could free USB transfers libusb still owned after a sleep-poll timeout, surfacing later as a destroyed-mutex SIGABRT on replug. Now actively pumps libusb events itself and leaks (rather than frees) a transfer that's still genuinely stuck.
  • Exception-unsafe pause/resume around RF calibration (devourer/WiFiDriver) — an exception during arm()/IQK left the async RX pool permanently paused, compounding into the UAF above. Guarded with RAII so resume always runs.

Added

  • Diagnostics: feed-queue overflow logging, URB free-list depth/pool-empty events (rxd-pool), GL fan-out stage timing, and live-tunable BA buffer-size / LQ-feedback-interval / RTP-reorder-timeout knobs (debug.pixelpilot.* props) for A/B testing the dongle's accept-vs-decline BlockAck tradeoff without a rebuild per value.

Full changelog: see CHANGELOG.md.

v0.4.1 — recording FPS fix, GLFanout encode-only, JSch ProGuard fix

Choose a tag to compare

@GingerFluffyCat GingerFluffyCat released this 19 Jul 15:04

PixelPilot v0.4.1

Bumps the Devourer submodule to v0.4.1 (RTP-sequence reorder → fixes dongle
video quality drops) plus three app-side fixes.

1. Recording FPS: no more progressive slowdown

The mp4 muxer stamped every sample with a fixed 90000/fps cadence. When the
actual decode rate (60 / 90 / 120 fps) != the configured fps, each sample's
timestamp was wrong by a constant factor, so a long recording's total duration
drifted from real time — the longer you recorded, the slower playback got.

Now samples are stamped from the real wall-clock encoder PTS
(\eglPresentationTimeANDROID, fed through \AMediaCodecBufferInfo.presentationTimeUs)
for the GL-fanout DVR, and from the NALU \creationTime\ for the legacy DVR path.
Duration tracks wall-clock at any source fps.

2. GLFanout: encode-only render path

The DVR encoder now receives every decoded frame at the full decode rate
while the display surface is throttled (prevents BLAST buffer exhaustion). The
encoder's timestamps stay in sync with the source, avoiding the drift above.

3. ProGuard: JSch ClassNotFoundException fix

Release builds (\minifyEnabled = true) stripped \com.jcraft.jsch.jce.*
because JSch loads its crypto providers reflectively
(\getJceName()\ → \Class.forName). Opening SSH/settings then threw
\ClassNotFoundException: com.jcraft.jsch.jce.Random.

Added -keep class com.jcraft.jsch.**\ and -dontwarn\ for JSch's optional
Android-absent deps (jna / bouncycastle / log4j / slf4j / newsclub / ietf-jgss).

Verification

On-device: 0 ClassNotFoundException on settings/SSH path; connect stable
(state→7); RTP reorder backlog 0; render 89–91 fps; recording duration matches
wall-clock.

Full diff: \c1cfbb0\ (one commit since v0.4.0). Devourer submodule at v0.4.1.

v0.4.0

Choose a tag to compare

@GingerFluffyCat GingerFluffyCat released this 17 Jul 10:25

APFPV reconnect-on-resume fix (release + close the dongle UsbDeviceConnection on pause so resume re-opens cleanly). Decode drop-to-freshest, GL fan-out DVR, colortrans reversal shader. VTX IP route (VpnService) + SSH-over-dongle + phone-wifi manager. Bumps embedded Devourer v0.4.0.

v0.3.8

Choose a tag to compare

@github-actions github-actions released this 29 Jun 15:00
APFPV: add channel/width RANGE selector matching the air WebUI

The AP operates on channel ranges (primary+secondary/center): 40 MHz "36_40"
has primary ch36, 80 MHz "36_48" primary ch36. A userspace station can't follow
a runtime CSA, so it must arm to the AP's EXACT primary. Picking a bare "40"
mismatched (AP 40 MHz range = 36_40, primary 36) -> connect-then-drop. New
"APFPV Channel/Width" submenu mirrors aalinkFPV-channel.cgi 1:1 and arms the
dongle to the range's primary; legalApfpvChannel(primary,bw) reproduces the AP's
exact secondary-offset/center. Legal DE 5.2 GHz UNII-1 (5170-5250) only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

v0.3.7

Choose a tag to compare

@github-actions github-actions released this 29 Jun 13:35
PixelPilot v0.3.7 — APFPV: remove Taiga/ch52 hardcode; VR single-decode

v0.3.6

Choose a tag to compare

@github-actions github-actions released this 28 Jun 13:02
PixelPilot v0.3.6 — VR single-decode dual-eye fan-out (fixes eye free…

v0.3.5

Choose a tag to compare

@github-actions github-actions released this 28 Jun 12:41
PixelPilot v0.3.5 — fix VR eye freezing (GLFanout renderTask gate re-…