System designTroubleshooting

MJPEG recording writes zero bytes to SD card: format and close checks

An MJPEG recording stuck at zero bytes on the SD card is a filesystem fault, not a codec fault: format FAT32, verify the frame count, close before power-down.

LumaSpec Vision11 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does an MJPEG recording stay at zero bytes until close?
  2. 02Is the codec broken or is it the card's filesystem?
  3. 03Why does the same script work on one module and fail on another?
  4. 04What format should the SD card be?
  5. 05How do you prove frames reached the card before you close?
  6. 06How much recording fits on a 32 GB card, and when must a file rotate?
  7. 07When should recording move off the camera module to a controller?
  8. 08What do you check before the next recording run?
  9. 09Questions

A camera-module recorder that opens an MJPEG file, adds frames for minutes, then dies at close leaves a signature behind: the file on the SD card is zero bytes long. The same script that worked on one board-level camera module fails after you migrate to another, which makes it look like a code problem. It is a storage problem, and it turns on one decision: which filesystem the card carries, and whether the firmware's writer supports it. This page gives you the format decision for cards at and under 32 GB, the close-time checks that prove frames reached the card, the arithmetic that times file rotation, and the point at which recording belongs on a vision controller rather than the module.

Why does an MJPEG recording stay at zero bytes until close?

Because the frames never reached the card: open and add_frame only fill buffers in the module's RAM, the container's index and data flush to the SD card during the close call, so every step before close can report success while 0 bytes land on the card.

The open call succeeds because it only creates a file entry. Each add_frame compresses the image and parks the bytes in RAM; a recorder flushes lazily, in card-sized clusters, as its buffers fill. The clip only becomes a playable file at close, when the writer goes back, fills in the frame index, duration and counts, and pushes everything outstanding to the card. If the filesystem layer under that final flush is broken, close is the first place the fault shows — a crash, a hang, or a clean return with nothing on the card.

Two bench observations confirm the storage layer is at fault. Resolution is innocent: an 80 × 60 test recording that fails exactly like a 640 × 480 one rules out frame size and encoder load. And a module that stops talking over USB until you remove and reapply power is showing a wedged filesystem stack, not a fault in your loop.

Container choice is its own decision once recording works; the encoding and container trade-offs live in Write MP4 video from a camera on an embedded board.

Is the codec broken or is it the card's filesystem?

Test the storage path before you blame the codec: write a small plain file of a few KB to the same card with the same file API, record a short clip in another container such as GIF, then read both back and compare sizes.

Work down these causes in order; the first explains most close-time failures.

  1. Filesystem the firmware cannot write. The card is exFAT and the firmware's exFAT path is absent or broken. Creating the file entry needs almost nothing, so open succeeds; close dies on the first real cluster write. Test: reformat the card FAT32 and rerun the identical script.
  2. Close never finalized the file. The close call was skipped, or it ran without the counter the writer needs to fill in its index. Test: log every open, add_frame and close call; frames added with no close always leave a header-only file.
  3. Card too slow or misreported. A card that cannot sustain the stream usually truncates or corrupts playback rather than writing zero bytes. Test: save a run of plain JPEGs to the same card and compare the sustained rate with the bandwidth numbers below.
  4. Power removed mid-write. A crash followed by a module that will not re-enumerate over USB until re-powered points at a wedged filesystem, and repeated hard power-cuts can trash the card's allocation tables.

If plain files write fine and only the video container dies, the container writer is the suspect. Frames that decode as corrupted images on the PC are a different repair: Corrupt JPEG data extraneous bytes before marker: fix MJPEG streams covers that path.

Why does the same script work on one module and fail on another?

Because identical code can run on different firmware, and the firmware owns the filesystem: a build with experimental exFAT support behaves differently from an older build on the same card, which is exactly what a module-to-module migration exposes.

The release notes between the two builds name the change. At least one embedded camera family shipped precisely this sequence: exFAT switched on for its speed on cards above 32 GB, close-time write failures reported against it, then exFAT disabled again in the next release. The script never changed; the storage stack underneath it did.

Prove it on your bench by holding the card constant and varying the firmware: one known-good FAT32 card, both builds, the same 30-second test recording. If the older build writes and the newer one does not, stop editing code — the fix is the filesystem choice, or a release that repairs the storage stack.

What format should the SD card be?

Format the card FAT32: every card of 32 GB and under is FAT32 by the SD standard anyway, that is the filesystem embedded recorders write most reliably, so re-formatting removes the close-time failure mode outright.

The SD standard ties format to card class: cards up to 2 GB carry FAT16, SDHC cards of 4-32 GB carry FAT32, and SDXC cards above 32 GB ship as exFAT. The table is the decision:

Card Ships as What to do
4-32 GB (SDHC) FAT32 Format FAT32 and record; the safe default
Above 32 GB (SDXC) exFAT Use only with exFAT support the firmware documents
Above 32 GB, reformatted FAT32 Valid up to FAT32's 2 TB volume ceiling, 4 GB per file

A PC's built-in Format tool refuses to create FAT32 on volumes above 32 GB, so an SDXC card needs a dedicated FAT32 formatter to come over; where the module offers its own format function, use it, because the writer then lays down the card's clusters itself. Buy industrial-grade cards for a recorder that runs daily — commodity cards wear faster under continuous writes, and a worn card fails exactly when the recording matters.

How do you prove frames reached the card before you close?

Close with the frame counter the API expects and read the file size back: a finished MJPEG file must weigh about header plus frames times bytes per frame, and anything near zero means the data never left RAM.

  1. Count frames yourself, incrementing a counter on every accepted frame, so you hold the number independently of the writer.
  2. Close with the counter. The writer needs the frame-rate value to fill in the index — one widely used module spells the call m.close(clock.fps()) — so a bare close() leaves a hollow file.
  3. Read the size back after close returns and compare it with N × average frame bytes plus a few KB of header; a 200-frame clip at 50 KB per frame must land near 10 MB.
  4. Log the count, the size and the close result, then allow power-down. A clean close return is necessary but not sufficient; the size readback is the proof.

Open one recorder session per clip and keep it open to the end; per-frame open and close cycles leak handles the same way camera open close cycles leak handles describes for capture devices. When the read-back on the PC throws a file I/O error instead of playing, the file has bytes but a broken structure — AVI codec file IO error: get frames from converted video covers that repair.

How much recording fits on a 32 GB card, and when must a file rotate?

At 640 × 480 and 30 fps, a typical 50 KB per frame MJPEG stream runs at 1.5 MB/s, so a 32 GB card holds about 5.9 hours, while FAT32's 4 GB single-file ceiling limits any one file to roughly 48 minutes.

stream (MB/s) = fps × KB per frame / 1000 hours on card = card GB × 1000 / (stream × 3600) rotation limit (s) = 4294967295 / (stream × 1000000)

Worked example, 640 × 480 at 30 fps and 50 KB per frame:

  • Stream rate: 50 × 30 = 1,500 KB/s = 1.5 MB/s.
  • Per hour: 1.5 MB/s × 3,600 s = 5,400 MB, about 5.4 GB.
  • Card capacity: 32,000 MB ÷ 5,400 MB/h = 5.9 h of recording.
  • FAT32 file ceiling: 4,294,967,295 bytes ÷ 1,500,000 bytes/s = 2,863 s ≈ 47.7 min; rotate filenames every 45 minutes to stay clear of it.
  • Card speed: a Class 10 rating guarantees 10 MB/s sustained, about 6.7 times the stream, which absorbs JPEG frames that balloon on detailed scenes.

Measure your own bytes per frame once — recorded file size divided by frame count — because scene detail moves the number: the same camera writes about 30 KB per frame on a bare bench and 80 KB on a densely printed board. Recompute the rotation interval from your measured value, and check the card's real sustained write rate before a long campaign; a stream at the card's limit stalls the pipeline and drops frames.

When should recording move off the camera module to a controller?

Move the recorder to a vision controller as soon as recordings feed production decisions: a controller writes to an SSD or HDD over GigE or USB3, carries no SD-card filesystem quirks, and keeps the detection load and the archive in one place.

Run the bandwidth numbers: the example's 1.5 MB/s is about 1.3% of a GigE link's practical 118 MB/s, so even eight cameras streaming at once (8 × 1.5 = 12 MB/s) share one link with room to spare. And if the module's own frame rate sags once recording starts, that is the sustained-throughput problem the embedded vision box guide dissects — another reason to move the writer to bigger storage.

A controller with camera ports and local storage takes the recorder role:

Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$1,679.00View partBuild a system with it

The MV-VC2140-128G40-1T pairs a 128 GB SSD with a 1 TB HDD for the archive and brings 3-4 LAN ports for cameras. At the example's 5.4 GB/h, that HDD holds about 7.7 days of single-camera recording before anything needs trimming.

More camera ports or PoE change the pick:

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$2,419.00View part
Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$4,479.00 · quotedView and quote

The MV-VC3301H-128G66 adds PCIe expansion on top of a 128 GB SSD; the MV-VC5525-256G70-NN brings PoE camera ports, 32 GB of memory and a 256 GB SSD. Compare the rest of the range by camera ports, memory and storage on the vision controllers category page before you settle on one.

What do you check before the next recording run?

Run five checks before the camera goes live: card formatted FAT32, a 30-second test clip read back on a PC, frame count matched against your counter, file size near frames times bytes per frame, and a power-down path that closes the file first.

Before deployment

  • Format the card FAT32 — in the recorder where it offers formatting, otherwise in a formatter tool.
  • Record a 30-second clip, read it back on a PC, and confirm it plays at full length.
  • Measure bytes per frame once and set the rotation interval below the 4 GB ceiling.

During the run

  • Log frame count, file size and close result for every clip.
  • Rotate filenames on a counter so no file approaches the ceiling.
  • Cut power only after close returns and the size check passes.

On failure

  • Rerun with the reference FAT32 card before touching code.
  • If a failed close wedges the module, power-cycle fully, then expect settings that need an explicit save — the camera's bitrate among them — to require rechecking after a hard power-cut: Keep camera bitrate settings after power cycle.
  • Escalate to a controller when recordings start feeding production decisions.

The decision in one line: format FAT32, prove the close with a size readback, rotate every 45 minutes, and move the recorder the day the clips become evidence. Pick the controller that matches your camera count and retention target, or reach the applications team through the contact page with your camera count and retention target. The systems topic page collects the rest of the recording and storage repairs.

Questions

Can I format a 64 GB or 128 GB card as FAT32?

Yes. A PC's built-in Format dialog refuses to create FAT32 above 32 GB, but a dedicated FAT32 formatter utility writes it on SDXC cards up to the format's 2 TB ceiling. Leave the cluster size at the default, format the card in or for the recorder, and run a short test recording with a size readback before trusting the card in production.

How large should a finished MJPEG file be?

Estimate it before you shoot: a few KB of container header plus frames times average bytes per frame. A 30-second clip at 30 fps and 50 KB per frame should land near 30 × 30 × 50 KB = 45,000 KB, about 45 MB. A finished file far short of that number never received its frames, even when close returned cleanly.

When does exFAT make sense on an embedded camera?

Only when the module's firmware documents exFAT support as working, not experimental. exFAT lifts FAT32's 4 GB single-file ceiling and manages large cards with less bookkeeping, which suits long unattended recordings. Without that support in place, exFAT is the most likely cause of a recording that opens cleanly and writes zero bytes, so FAT32 with filename rotation remains the safe default.

What write speed does the SD card need for MJPEG recording?

Size the card to your measured stream. Take the stream in MB/s and demand a sustained class roughly 6 times higher: the example's 1.5 MB/s stream runs on a Class 10 card, whose guaranteed sustained floor is 10 MB/s. Speed classes are sustained minimums rather than burst figures, which is what continuous video needs. Avoid unbranded cards, whose real sustained speed often falls well below the printed class.

GIF clips record but MJPEG fails on the same card — is the card bad?

Usually not. The two writers exercise different code paths, so a failure confined to one container, with plain files writing fine, points at the video writer or its filesystem interaction rather than the card hardware. Keep the card if it formats cleanly, holds a plain file, and passes a sustained write check; change the filesystem to FAT32 or the firmware before spending money on new cards.