Skip to content

marcodelpin/jl-dv-viewer

Repository files navigation

jl-dv-viewer icon

jl-dv-viewer

Minimal Android viewer for cheap WiFi dashcams / rearview cameras that run a Jieli-DV-style streaming firmware. A self-contained Kotlin client — no AppCompat, no media-player library, no external deps — that connects to the camera's local Wi-Fi access point, performs the length-prefixed JSON handshake, reassembles MJPEG frames from a custom UDP chunk framing, and renders them. Includes an in-app region-of-interest picker with fullscreen zoom, 4-position rotation, and a supervisor state machine that auto-reconnects on stale stream / keepalive failure with exponential backoff.

Built APK footprint: ~18 KB (release, R8-shrunk).

What it is / what it is not

  • Independent interoperability client for a WiFi video protocol observed on low-cost aftermarket car cameras. Operates entirely on the camera's own AP; no cloud, no tracking, no accounts.
  • Not affiliated with any camera manufacturer, retailer, or chipset vendor. All trademarks belong to their respective owners; references in this repository are purely descriptive.

Supported hardware

Any camera whose companion app uses an ASCII framing that starts with the literal bytes CTP:, JSON payloads of the form {"errno":N,"op":"PUT|GET|NOTIFY","param":{…}}, a fixed TCP control port 3333, and a dynamic UDP video port announced at handshake time. This pattern is common on 2.4 GHz Wi-Fi rearview cameras sold under many white-label brands that internally ship a Zhuhai-Jieli-derived dashcam SDK (the "DV running" family).

If your camera's companion app on Android has a package id looking like com.<vendor>.stream.dv.<something>, there is a good chance this client speaks its protocol.

The protocol is documented in docs/protocol.md. If your device works with a slightly different framing, that file is the place to start adapting.

Features

  • Zero-dependency Kotlin, one Activity, plain DatagramSocket + BitmapFactory
  • Full CTP handshake (APP_ACCESS, DATE_TIME, LANGUAGE, OPEN_RT_STREAM, CTP_KEEP_ALIVE)
  • UDP chunk reassembly with multi-chunk-per-datagram parsing (~27 chunks per 720p frame at steady state)
  • MJPEG rendering at native camera frame rate (tested at 25 fps, 1280×720)
  • Long-press-drag to draw a region of interest; tap ✓ ROI to zoom fullscreen, ✕ FULL to reset
  • Landscape-only, no title bar, status overlay in top-left
  • minSdk 21, targetSdk 35, arm64 only (universal trivially possible)

Build

Requires JDK 17, Android SDK (platform 35 + build-tools 35.0.0).

./gradlew :app:assembleRelease
# Output: app/build/outputs/apk/release/app-release.apk

Install:

adb install app/build/outputs/apk/release/app-release.apk

Run

  1. Connect the phone to the camera's Wi-Fi AP (typically open, SSID starts with the camera's brand + MAC suffix)
  2. Launch jl-dv-viewer
  3. Camera IP is hard-coded to 192.168.1.1 (the standard AP gateway for this family); the app opens TCP 3333, completes the handshake, and starts receiving video within ~200 ms
  4. Long-press and drag on the preview to draw a crop rectangle; tap ✓ ROI to fill the view with only that region

Runtime logs under the WCam / WCam-rx logcat tags.

Protocol summary

See docs/protocol.md for the full wire format, command vocabulary, and reassembly algorithm. Short version:

  • TCP 3333 — control channel. Framing: "CTP:" (4 B) + cmdLen (u16 LE) + cmdName + jsonLen (u32 LE) + UTF-8 JSON
  • Camera streams a burst of NOTIFY frames after the first APP_ACCESS with its full state (SSID, UUID, video params, battery, TF card, language, etc.)
  • After the client sends OPEN_RT_STREAM {w,h,fps,format:0} the camera begins emitting UDP datagrams to an ephemeral port on the client
  • Each UDP datagram carries one or more back-to-back 20-byte-header chunks. Type 0x02 = mid-frame chunk; type 0x82 = last chunk of a frame. Reassemble by frame_seq, sort by chunk_off, concatenate → complete JPEG

Legal notice

Independent interoperability project. Not affiliated with, endorsed by, or sponsored by any camera manufacturer, chipset vendor, or retailer. Trademarks referenced in the documentation belong to their respective owners; all uses are nominative/descriptive.

Reverse engineering was performed on hardware legally owned by the contributors, strictly to produce an interoperable independent client, as permitted by:

  • EU Directive 2009/24/EC, art. 6 (decompilation for interoperability)
  • Italy D.Lgs. 518/1992, art. 64-quater
  • US DMCA §1201(f) (reverse engineering for interoperability)

No technological protection measures were circumvented. The original vendor firmware is not distributed and is not required to use this client.

Provided AS IS, without warranty of any kind. See LICENSE (MIT).

Contributing

PRs welcome — especially additional camera models that speak a CTP:-style framing, and improvements to the reassembly heuristic for lossy Wi-Fi conditions. Please do not include vendor APKs, vendor firmware blobs, vendor documentation PDFs, or pcaps containing identifying MAC/UUID data in PRs. Wire-format findings belong in docs/protocol.md with identifiers redacted.

About

Minimal 26 KB Android viewer for Jieli-DV WiFi rearview/dashcam cameras. Independent interoperability client — reverse-engineered CTP protocol, MJPEG UDP reassembly, ROI zoom with rotation, auto-reconnect supervisor. Kotlin, zero dependencies.

Topics

Resources

License

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages