How Time Lapse Recording Works with Sampling Intervals and MP4 Conversion in atomcam_tools

The atomcam_tools time-lapse feature captures frames at user-defined sampling intervals, stores them in a temporary binary container, and converts them to standards-compliant MP4 files by constructing ISO-BMFF metadata boxes on the fly.

The time-lapse subsystem is implemented in libcallback/timelapse.c and operates as a background thread that bridges raw H.264 frame acquisition with final MP4 packaging. This implementation allows the Atomcam camera to record long-duration events by sampling frames at configurable intervals while maintaining precise control over the playback frame rate in the resulting video file.

Overview of the Time-Lapse Architecture

The architecture follows a three-stage pipeline designed to minimize memory usage while maintaining data integrity. All operations are handled by the TimelapseThread background thread, synchronized via mutexes to ensure safe operation during start, stop, and restart commands.

  • Stage 1: Initialization. The Timelapse() function (lines 33-78) parses user parameters and creates two files: a binary metadata table (*.stsz) containing recording parameters, and a temporary video container (*._mp4) pre-structured with ftyp and placeholder mdat boxes.

  • Stage 2: Recording Loop. At each sampling interval, the thread grabs raw H.264 NAL units via video_get_frame(), writes them to the temporary MP4, and logs each frame's offset and size in the *.stsz file (lines 81-124).

  • Stage 3: MP4 Finalization. When recording completes, the AppendMoov() routine (lines 586-737) reads the metadata table, constructs the missing MP4 index boxes (moov, stsd, stts, stsc, stsz, stco), embeds H.264 codec configuration data, and renames the file to *.mp4.

How Sampling Intervals and FPS Are Configured

Command Syntax and Parameter Parsing

Users initiate recording through the command-line interface parsed in Timelapse() at lines 33-51:

timelapse <file> <interval> <count> [<out-fps>] [<schedule-no>]
  • <interval>: Seconds between frame captures (sampling interval).
  • <count>: Total number of snapshots to acquire.
  • [<out-fps>]: Playback frame rate for the final MP4 (defaults to 20 fps if unspecified).
  • [<schedule-no>]: Optional schedule identifier for automated triggers.

These parameters populate the StszHeaderSt structure written to the .stsz file header (lines 64-71), preserving the configuration across potential recording interruptions.

Frame Acquisition Timing Loop

The recording thread calculates target wall-clock timestamps to maintain the sampling interval. In lines 72-78, the code computes the next capture second:

int targetTime = ProcessingInfo.endTime -
     ((ProcessingInfo.endTime - now.tv_sec) * 1000 - 500) /
     (ProcessingInfo.interval * 1000) *
     ProcessingInfo.interval;

The thread sleeps in one-second increments until now.tv_sec reaches targetTime, ensuring frames are spaced by the user-defined interval with ±1 second granularity. This approach balances precision with power efficiency suitable for low-rate time-lapse capture.

Output Playback Frame Rate

The header's fps field determines the time-scale for the final video. During finalization (lines 554-558), AppendMoov() calculates:

unsigned int timeScale = 1000;          // milliseconds per second
unsigned int sampleDelta = timeScale / ProcessingInfo.fps;

This sampleDelta value populates the stts (Time to Sample) box, dictating that each frame displays for 1000/fps milliseconds. Consequently, a recording with a 10-second sampling interval and 30 fps output plays back 300 times faster than real-time.

MP4 Conversion and Finalization Process

Container Structure and Temporary Files

Upon initialization (lines 61-69), the system creates *._mp4 containing an ftyp (File Type) box identifying the file as MP4, followed by an mdat (Media Data) box with a placeholder size field. As frames arrive during recording, NAL units are appended immediately after the mdat header, and the size field updates dynamically to reflect the growing data payload.

H.264 Parameter Extraction

When converting to final MP4 format, AppendMoov() (lines 227-241) scans the temporary file for SPS (Sequence Parameter Set, NAL type 0x27) and PPS (Picture Parameter Set, NAL type 0x28) units. These essential decoder configuration parameters embed into the avcC box within the sample description table, ensuring playback compatibility across standard video players.

ISO-BMFF Box Construction

The AppendMoov() function (lines 254-560 and 586-737) manually constructs the MP4 container hierarchy byte-by-byte:

  • moov (Movie) box contains the metadata track
  • trak (Track) box defines the video stream
  • mdia (Media) and minf (Media Information) boxes wrap the sample tables
  • stbl (Sample Table) box contains:
    • stsd: Sample description with H.264 configuration
    • stts: Time-to-sample mappings using the calculated sampleDelta
    • stsc: Sample-to-chunk mappings (optimizing with 8 samples per chunk)
    • stsz: Individual sample sizes retrieved from the .stsz metadata file
    • stco: Chunk offset locations within the file (lines 617-702)

File Finalization

After writing all index tables, the system performs atomic completion (lines 734-737):

  1. Renames *._mp4 to *.mp4
  2. Removes the auxiliary *.stsz metadata file
  3. Calls sync() to flush filesystem buffers

The result is a self-contained, seekable MP4 file compliant with ISO Base Media File Format specifications.

Practical Usage Examples

Start a New Time-Lapse Session


# Capture every 10 seconds, 120 frames total, playback at 30 fps

timelapse /media/mmc/timelapse 10 120 30

This creates timelapse.stsz with metadata and timelapse._mp4 for raw H.264 storage, then begins the background acquisition thread.

Stop Recording Early

timelapse stop

The thread receives Directive_Stop, exits the acquisition loop while preserving captured data, and keeps the partial ._mp4 file available for finalization.

Convert Raw Data to MP4

timelapse mp4 /media/mmc/timelapse

AppendMoov() processes the existing .stsz table and ._mp4 payload, constructing the complete MP4 index and producing timelapse.mp4.

Resume Interrupted Sessions

timelapse restart

The system reloads the existing .stsz file, updates internal pointers, and continues appending frames where the previous session ended.

Key Source Files and Functions

Summary

  • atomcam_tools implements time-lapse recording in libcallback/timelapse.c using a dedicated background thread and mutex synchronization.
  • The system stores frame offsets in a proprietary .stsz metadata file while buffering raw H.264 data in a temporary ._mp4 container.
  • Sampling intervals are enforced through wall-clock time calculations with one-second precision, independent of the output playback frame rate.
  • Final MP4 conversion constructs ISO-BMFF boxes manually, including critical H.264 SPS/PPS extraction and time-scale calculations based on the user-specified output fps.
  • The architecture supports interruption recovery through the restart command and metadata persistence in the StszHeaderSt structure.

Frequently Asked Questions

What file formats does atomcam_tools use during time-lapse recording?

During active recording, atomcam_tools maintains two files: a binary metadata table with the .stsz extension containing frame sizes and offsets, and a temporary video file ending in ._mp4 holding raw H.264 NAL units. Upon completion, the AppendMoov() function consolidates these into a standards-compliant .mp4 file and removes the auxiliary metadata.

How does the sampling interval affect the final MP4 playback speed?

The sampling interval determines how much wall-clock time passes between captured frames, while the output fps parameter (default 20) controls playback speed. For example, a 60-second sampling interval with 30 fps output produces video playing 1800 times faster than reality. The stts box in the final MP4 uses sampleDelta = 1000 / fps to enforce this timing.

Can I recover a time-lapse recording if the camera loses power?

Yes, provided the .stsz metadata file and ._mp4 temporary file remain intact on the storage medium. The timelapse restart command reloads the existing StszHeaderSt structure from the .stsz file and resumes appending frames. If recording cannot continue, timelapse mp4 <file> finalizes the partial data into a playable video up to the point of interruption.

Where does atomcam_tools store H.264 codec configuration data?

During MP4 finalization, AppendMoov() scans the temporary video file for SPS (NAL type 0x27) and PPS (NAL type 0x28) units (lines 227-241). These parameters embed into the avcC configuration record within the stsd (Sample Description) box, ensuring the final MP4 contains the necessary decoder initialization data for standard playback.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →