Recording & Storage

SkyView records locally in segments by default, with the option to attach 115 Cloud for cloud backup. This chapter explains the recording mechanism, retention policies, and 115 integration.

How recording is written

SkyView cuts each camera's video into standard MP4 files by time, fixed at 60 seconds per segment. MediaMTX first writes out fMP4 segments; the instant a segment finishes, the runOnRecordSegmentComplete hook fires, and ffmpeg remuxes it in place with -c copy into a standard MP4 with faststart (moov at the head), so every player can seek directly. The on-disk path:

text
data/recordings/
  <camera_id>/
    2026-05-18_14-30-00.mp4
    2026-05-18_14-31-00.mp4
    2026-05-18_14-32-00.mp4
    ...
Segmented recording lets playback seek precisely to any time point. If one segment is corrupted (power loss, network jitter), you lose at most 60 seconds and adjacent segments are unaffected. The timestamp in the filename is the segment's start time (local time zone).

Path after archiving

In local storage mode, once a segment is recorded into the database and marked archived, it's atomically renamed under data/recordings/_archive/<camera_id>/, mirroring the directory structure and filename exactly, to distinguish it from the inbox being actively written. The _archive/ prefix is a convention; the uploader's discovery scan skips it so archived files aren't reprocessed. In 115 Cloud mode, whether the local copy is kept is governed by the delete_after_upload setting (default: delete on successful upload).

Local storage path

Recordings are written to /app/data/recordings (nested mount, can be pointed at a large disk / NAS separately); small state like the database / cookies / logs lives in /app/data, and AI models are bundled in the image rather than in the data directory. For production, always point the recordings directory at a disk with ample capacity, and don't cram it onto the same partition as the system disk — a full recordings disk will keep your server from booting.

bash
# Recommended: mount recordings on a separate large disk / NAS (small state stays in data/)
sudo mkdir -p /mnt/recordings
# One-line script: point --recordings-dir at the large disk
curl -fsSL https://cdn.yun-kan.com/yunkan-install.sh | bash -s -- --recordings-dir /mnt/recordings
# Or nest-mount the recordings volume in a manual docker run
docker run -v $(pwd)/data:/app/data -v /mnt/recordings:/app/data/recordings ...

Retention policy and disk space

Web admin → Settings → Recording retention to enable and configure automatic cleanup (off by default, must be turned on manually). Once on, the two rules below both apply and either one triggers deletion; only archived recordings (uploaded successfully, or local mode) are cleaned, and pending / uploading / failed states are never touched:

  • By days: recordings older than the retention days (default 30) → deleted; set 0 = don't trigger by time
  • By capacity: when disk usage exceeds the threshold (default 90%) → delete starting from the oldest; set 100 = don't trigger by space

Off by default

On a fresh install the [cleanup] service has enabled=false — left off, everything is kept; when the disk fills, writes fail but SkyView won't delete on its own. For home deployments we strongly recommend turning it on and letting the system handle your worries via the two rules above.
ResolutionBitrateRough usage per stream per 24 hours
1080p H.2642 Mbps~21 GB / day
1080p H.2651 Mbps~10 GB / day
4K H.2654 Mbps~42 GB / day

Capacity estimation formula

Total disk ≈ streams × per-stream daily usage × retention days × 1.2 (thumbnails + database headroom). 10 streams of 1080p H.265 kept for 30 days ≈ 3.6 TB.

115 Cloud storage (optional)

Asynchronously upload local recordings to 115 Cloud, essentially a "cloud NVR". With instant-upload support, existing recordings don't consume bandwidth.

  1. 1

    Scan to log in

    Web admin → 115 → show the QR code and authorize by scanning with the 115 mobile app. SkyView saves the login info encrypted in the data directory.

  2. 2

    Choose the target folder

    Create an empty folder in 115 (e.g. "SkyView Recordings"), return to SkyView, and select it as the upload destination

  3. 3

    Switch the storage backend

    Settings → Storage → choose 115 → Save. The switch is a hot swap that doesn't restart the process, taking effect on the next upload

  4. 4

    Verify it's working

    The Web Admin currently has no upload queue / progress panel. To confirm recordings are uploading, pick any of three ways: ① the Settings → 115 page to check that VIP status and remaining capacity look right; ② the Logs page (sidebar → Logs), select the uploader service on the left to watch each segment's start / finish / failure lines in real time; ③ open the 115 app or website and go into the target folder to see whether new recordings are arriving.

115 login expires

You need to re-scan about every 30 days. When it expires, SkyView sends a push notification; just re-scan promptly, and recordings keep writing locally and aren't lost in the meantime.

What if you don't use 115

Currently only the local + 115 backends are supported. Aliyun Drive / S3 and others will be added later; if you have a specific cloud-drive need, file a ticket to let us know the priority.

Download / export

The playback page supports "export by time range" — choose a start and end time, and the backend re-encodes and trims it into a single MP4 for the client to download, with frame-level precision on the start/end (<40ms error). It auto-selects hardware: NVIDIA NVENC (50-200x real time, tens of seconds per hour on an RTX) → Intel iGPU VAAPI (25-50x, a minute or two per hour on an N100) → libx264 software encode (1.5-3x, ten-odd minutes per hour). Any tier that fails automatically falls back to the next. All three of Web Admin, Android, and iOS support it.

  1. 1

    Open the playback page

    Select the camera and date to export. Drag the timeline near the target range so the center marker lands on that recording segment.

  2. 2

    Click the export button

    Web Admin: the ⬇ icon at the far right of the playback control bar; Android / iOS: "Export" to the right of the "Speed" button on the control bar. A range-selection panel pops up, defaulting to the current playback position ±30 seconds.

  3. 3

    Adjust the start/end → submit

    Change the start/end times in the panel and it computes the estimated size in real time (1080p H.264 ≈ 250 KB/s). The maximum per export is 1 hour; longer is rejected. Click "Start export".

  4. 4

    Watch the progress

    A progress card appears at the bottom-right (Web) / below the control bar (Android/iOS). Web refreshes in real time via SSE; mobile polls every 2 seconds. Once queued, a task usually completes in seconds to tens of seconds (depending on the segment count + whether cloud segments must be pulled from 115).

  5. 5

    Download

    Once the progress card turns into a "Download" button, click it: Web downloads directly via the browser; Android uses the system DownloadManager to save to Downloads/SkyView/ with a status-bar notification; iOS opens a ShareSheet to "Save to Files / Photos" or share to WeChat.

Auto-selected hardware acceleration NVENC > VAAPI > libx264

Probed automatically at process startup, prioritized fastest to slowest: - NVENC (NVIDIA discrete GPU): needs the cuda image variant + --gpus all; ~30-60 seconds for 1h of video on RTX 30/40 series - VAAPI (Intel/AMD iGPU): needs the openvino/all-in-one image + /dev/dri passthrough; ~1-2 minutes for 1h of video on an N100, etc. - libx264 (CPU only): fallback when there's no GPU; ~20-40 minutes for 1h of video (depending on the CPU) Any tier that fails at runtime (incompatible driver, session limit, etc.) automatically falls back to the next. To force a specific one, use recording.export.hwaccel = "nvenc" / "vaapi" / "none".

Start/end times are frame-precise

All three encoding paths (NVENC / VAAPI / libx264) are frame-precise on start/end (<40ms). The quality parameters are aligned: NVENC qp=23 / VAAPI qp=23 / libx264 crf=23 — output is visually nearly identical across hardware (NVENC files may be slightly larger, <10%). Configure recording.export.{nvenc,vaapi}_qp to tune quality separately (0-51, lower = higher quality).

115 Cloud storage mode is supported too

If recordings are on 115, the backend first streams each segment in the range from 115 to a temp directory on the server, then concatenates them, clearing the temp files when done. Subject to 115's rate limit, 1 hour of cloud segments may take a few minutes — you can go do something else; the export task runs independently on the server side, and closing the app doesn't affect it.

Exported files are kept for 24 hours

The assembled MP4 lands at data/recordings/_exports/<job_id>.mp4 on the server and is auto-deleted by cleanup after 24 hours by default (to avoid filling the disk). Within that window you can re-click "Download" from any client at any time for the same file. After it expires, re-initiate to get it again.

Want to grab raw segments, bypassing the UI

The raw 60-second segments are at data/recordings/<camera_id>/<YYYY-MM-DD_HH-MM-SS>.mp4 (after local archiving, under data/recordings/_archive/<camera_id>/), each a standard MP4. You can also GET /api/recordings/<id>/download with a JWT to fetch a single segment.
Recording & Storage - SkyView Docs