WIP: Support osmo action 1 - #11
Draft
KonradIT wants to merge 5 commits into
Draft
Conversation
…record layout corrected
The older Osmo Action generation answers the file list with a flat array of fixed 65-byte
DCF records instead of CompositePack — no paths, no filenames, files addressed by a packed
index. The WIP for this lived on a branch 109 commits behind, in a file the refactor has
since split; this ports it to DcfRecords, where the stride was already reserved for it.
Its first 14 bytes turn out to be laid out exactly like the drone's 94-byte record — mtime,
size, packed index, duration at the same offsets — despite the years between the two
firmwares. Only the epoch differs: unix seconds here, FAT/DOS packing on the drone.
Two fields were being read wrong, and both mattered:
- +12 was taken for the DCF file number and used to synthesise filenames, so a clip whose
real name on the card is DJI_0593.MP4 was displayed and addressed as DJI_..._0117_...
It is the duration in whole seconds.
- +10 was taken for the DCF directory. It is the high half of the u32 packed index — the
same mis-slicing that hides internal storage on a drone. Directory and file number now
come out of DcfIndex.
What identifies the fields is +38, previously guessed to be a size: it is the duration in
milliseconds, and it agrees with +12 on all seven records in the fixture (117 <-> 117550,
306 <-> 306606). The "photo record reads ~0.6 MB" once read there is 667 ms.
That also exposed a trap. One record's whole-second duration is 0, which the drone's
"durationSec == 0 => still" rule would misfile as a photo, but its UUID appears among the
camera's own DjiMovDmx video entries — it is a 0.667 s clip. Sub-second durations round up
to 1 s so the rule still holds downstream.
The fixture is the raw capture; the camera's own log independently states FileNumToSend: 7,
SizeToSend: 463 and both end indices, so the counts are corroborated rather than self-asserted.
Not yet run against the camera. Note that two things this needs already landed here for
other reasons: the datalink keepalive ACKs ~2x/s so the AP cannot sleep (the July run lost
the AP 27 s after the grid, which invalidated its only download attempt), and the browse
session now holds playback mode, which is the state the HTTP server was suspected of being
gated on.
(cherry picked from commit 110efc3)
A tester's Osmo Action 1 (not the unit the layout was derived from) hex-dumped its whole manifest through the shipped build's unknown-layout diagnostic: 0000 01000000490000002984e65cc4909e05 7800640007000610032f018aa2d2eb03 0020 00040000000100050000000a0000ce1c 00000000000000000000000000000000 0040 000000000000000000 73 bytes: count=1, total=73, and 8 + 1*65 == 73 exactly. decodeAction1 takes it unmodified and yields one file — index 0x00640078 -> SD / 100MEDIA / DJI_0120, 94,277,828 bytes, 7374 ms. That is the confirmation the layout was missing. Action1RecordsTest pins it against the camera it was derived from, and a layout can always be fitted to the data that produced it; holding on a different unit, with a different file count and a different clip, is what makes it a format rather than a fit. The bitrate falls out sane too (~12.8 MB/s, 4K) — a field mis-mapping shows up there immediately, and the old decoder's +12 read would have named this DJI_0007. Also settles why that camera's grid was empty on a stock build: main has no index-list decoder at all, and the card holds exactly one file (118.4 of 119.1 GB free), so "empty grid" and "empty card" looked identical from outside. Playback remains unresolved — listing is not the blocker, :80 is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 3ad1047)
ROADMAP #6's open question, asked directly instead of reasoned about. The Action 1 refuses :80 while WiFi and the datalink are both up, so downloads are blocked on an unidentified transport: static lighttpd once the camera is coaxed into playback, or DUML via DjiTransSrv — the service that already sends us the list. The drone work makes the second cheap to test. 0x4a transfers run as a family per transfer kind: +0 query, +1 reply, +2 proceed, +3 state, +4 release. A media list is 0x00-0x04 and a thumbnail is 0x20-0x24 on a Mavic 3 — same machinery, different base. The Action 1 demonstrably speaks the list half of that family, so if its file transfer is DUML at all it is likely another base in the same family. DcfTransferProbe queries each candidate base for a real file index and reports what answers; a +3 state frame is the signal, since that is what a device raises before it starts sending. Runs once per session when an Action-1 manifest decodes, while the session is provably alive. Every probe releases, answer or not. A leaked slot made a Mavic 3 stop answering media queries while telemetry streamed on — the link looks healthy and serves nothing, which is indistinguishable from "unsupported" and would send us away from a route that works. Read-only: query and release, nothing that writes to the card. A silent result is deliberately reported as weak. The query payload mirrors the list query's header with the file index where the list puts its cursor, which is a guess — no capture of this camera transferring a file exists, and a wrong shape looks exactly like an unsupported kind. Only a positive is strong, and the log says so rather than letting an empty result read as "ruled out". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit bf02b18)
… preview A tester's Action 1 started rebooting on the build that added the probe. The probe is NOT established as the cause — that same build was also the first to decode the media list, so preview became reachable in the very same step, and the log cannot separate them. But sending speculative transfer frames to 2019 firmware is exactly the kind of thing that could reboot it, and running an experiment we can't exonerate on someone else's camera is not defensible. So the probe is now opt-in (--ez probe4a true), off by default. The next tester build answers the question that matters: with no probe running, does opening the preview still reboot the camera? That isolates it in one run. The log was blind to the half we most needed. MediaPreviewActivity logged with a bare Log.i, so "Save logs" captured the whole connect flow and went silent the moment a preview opened — a log covering a camera that misbehaved *during playback* contained no trace of playback. It now writes to FileLog like MainActivity does. Also corrects what the probe claims. On the Action 1, base 0x20 answered our query with a `release` (4a240e1060...) and nothing else. That is a real finding: the transfer family IS understood at 0x20, since a foreign base is ignored outright. But the camera closed the transfer rather than raising a state and sending, so the summary calling any reply "datalink transfer is LIVE" overstated it. It now separates "raised STATE — a transfer started" from "replied but refused — most likely our query payload is wrong", which is the honest reading of a guessed payload shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6cd1c32)
… on a dead port The probe is off and the camera no longer reboots, so the 0x4a probe is now the prime suspect for that — one run, but the only variable that changed. With preview finally visible in the log, what the tester saw is plain: preview stream http://192.168.2.1/v1?file_index=6553720&file_subtype=18... (30 s) preview ERROR what=1 extra=-2147483648 preview falling back to file_subtype=0 what=1 / extra=0x80000000 after exactly 30 s is MediaPlayer timing out on a port that is not listening, twice, once per candidate. That is the "endless cycling": a minute of spinner ending in a generic failure. So a connect with a 2.5 s timeout now runs first, and a refused port says so immediately and specifically instead of pretending to load. Correction to an earlier reading: `WiFi: onLost` appears in this log too, on a run where the tester confirms the camera did NOT reboot. It is the AP going away for its own reasons, not evidence of a restart, and I had cited it as such. And the actual experiment. ROADMAP #6's leading theory is that :80 is enabled by duss_proxy only once dji_media_server is in playback — every attempt so far was made in whatever mode the camera woke up in, so the theory has never been tested. The session now enters playback with 0x02/0x0c 01 01 00 01 — the same command we already send every other Osmo to page its media list, not a speculative frame — and then tries a socket to :80 three times, reporting each result. If :80 opens, HTTP media is reachable and the download follows. If it stays refused, that weakens playback-gating without ruling out a further activation step, and the log says exactly that rather than either overclaiming. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 5d7891f)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.