FadCam fMP4 Recording Performance: MediaCodec and Fragmented MP4 Optimization

FadCam achieves high-performance fMP4 recording on Android by combining hardware-accelerated MediaCodec encoding with zero-copy Surface input, fragmented MP4 segmentation for streaming, cache-first disk I/O, and background FFmpeg remuxing with atomic task counting.

FadCam (anonfaded/FadCam) implements a sophisticated video recording pipeline designed for real-time fMP4 recording performance across diverse Android hardware. The application leverages fragmented MP4 (fMP4) containerization to balance encoding efficiency, storage management, and network streaming capabilities. Understanding these architectural decisions helps developers optimize their own MediaCodec implementations while maintaining smooth recording even on low-power devices.

Hardware-Accelerated Encoding with MediaCodec

At the core of FadCam's performance strategy is the GLRecordingPipeline class, which orchestrates hardware-accelerated video encoding without burdening the CPU.

Zero-Copy Surface Input

The pipeline eliminates expensive memory copies by feeding frames directly into the encoder via a Surface object. In app/src/main/java/com/fadcam/opengl/GLRecordingPipeline.java, the encoder initialization uses:

// Line 1274-1275
videoEncoder = MediaCodec.createEncoderByType(currentMimeType);
videoEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

By avoiding ByteBuffer copies in Java memory, this approach keeps the main thread responsive and reduces garbage collection pressure during long recording sessions.

Adaptive Bitrate Control

FadCam selects between constant bitrate (CBR) and variable bitrate (VBR) modes based on device capabilities (lines 1143-1144 in GLRecordingPipeline.java). CBR mode provides predictable file sizes for storage-constrained environments, while VBR mode adapts to scene complexity, delivering better visual quality without over-taxing the encoder during high-motion sequences.

Fragmented MP4 Architecture for Streaming

The fMP4 container format enables FadCam to support both local recording and live streaming simultaneously without duplicating the encoding effort.

Streaming-Optimized Init Segments

The FragmentedMp4MuxerWrapper (located at app/src/main/java/com/fadcam/playback/FragmentedMp4MuxerWrapper.java) generates an init.mp4 initialization segment separate from media fragments. This segment is served statically by LiveM3U8Server.java (lines 99-132), allowing HLS players to begin playback immediately while the recording continues. Because the init segment remains unencrypted (SegmentEncryptor.java:26), clients avoid decryption overhead during stream startup.

Configurable Segment Boundaries

To prevent individual files from growing unwieldy, FadCam implements configurable segment sizing in GLRecordingPipeline.java (lines 367-370). The maxFileSizeBytes parameter ensures that no single fragment exceeds memory-safe thresholds, enabling efficient fast-forward and rewind operations without loading massive files into memory.

Disk I/O and Storage Optimization

FadCam minimizes storage-related performance bottlenecks through strategic file handling and optimized directory scanning.

Cache-First Write Strategy

When operating in STREAM_ONLY mode, RecordingService.java (lines 6611-6613) writes to temporary cache files before moving to final storage:

File outputFile = new File(getCacheDir(),
        "stream_temp_" + System.currentTimeMillis() + ".mp4");
pipelineBuilder.setOutputFile(outputFile.getAbsolutePath());

This approach leverages the faster internal storage partition for active recording, deferring slower Storage Access Framework (SAF) operations until the recording completes.

High-Performance File Scanning

The FastFileScanner class (app/src/main/java/com/fadcam/data/FastFileScanner.java) replaces the standard DocumentFile.listFiles() method with bulk File scanning (lines 31-456). This optimization reduces inter-process communication (IPC) calls when enumerating large video libraries, preventing UI freezes on devices with thousands of recordings.

Background Processing and Thread Safety

Post-processing operations utilize FFmpegKit with careful thread management to prevent UI blocking.

Atomic Task Counting

RecordingService.java maintains an AtomicInteger named ffmpegProcessingTaskCount (line 153) to track background operations. Before executing FFmpeg commands, the counter increments; upon completion, it decrements. The application checks this count before updating UI elements (line 5309), ensuring that CPU-intensive remuxing never blocks the main thread.

Copy-Only Remuxing

The FragmentedMp4Remuxer (app/src/main/java/com/fadcam/playback/FragmentedMp4Remuxer.java) performs format conversion without re-encoding:

String ffmpegCmd = String.format("-y -i %s -c copy %s", inputPath, outputPath);
FFmpegKit.executeAsync(ffmpegCmd, session -> {
    // Background completion callback
});

Using the -c copy flag avoids decode/encode cycles, reducing processing time from minutes to seconds even on low-power devices.

Memory Management Strategies

FadCam implements aggressive memory conservation during bitmap operations to prevent OutOfMemoryError crashes during extended recording sessions.

Bitmap Recycling

When capturing photos from live recordings (RecordingService.java:22-28), bitmaps are processed on background handlers, scaled to target dimensions, and immediately recycled via bitmap.recycle(). This pattern appears throughout the codebase, including AudioWaveformView and AudioExtractor, maintaining a minimal Java heap footprint.

Summary

  • Hardware-accelerated encoding via MediaCodec.createEncoderByType() offloads compression to the GPU, reducing CPU utilization.
  • Zero-copy Surface input eliminates expensive ByteBuffer operations and keeps the main thread responsive.
  • Fragmented MP4 containers enable simultaneous recording and streaming through separate init and media segments.
  • Cache-first file writes minimize SAF overhead by writing to internal storage before moving to external destinations.
  • Atomic task counting ensures FFmpeg operations run on background threads without blocking UI updates.
  • Copy-only remuxing provides fast post-processing without re-encoding video streams.

Frequently Asked Questions

How does FadCam prevent video encoding from slowing down the Android UI?

FadCam utilizes MediaCodec.createEncoderByType() with Surface input in GLRecordingPipeline.java, which offloads encoding to dedicated hardware. This zero-copy approach prevents the main thread from processing raw frame data. Additionally, all FFmpeg operations run asynchronously with an AtomicInteger task counter (RecordingService.java:153) that guards UI updates until background work completes.

What makes fragmented MP4 (fMP4) better for streaming than standard MP4?

Standard MP4 files require the complete file to be written before the metadata (moov atom) is valid, preventing playback until recording finishes. FadCam's FragmentedMp4MuxerWrapper writes an init.mp4 segment containing metadata upfront, followed by media fragments. This structure allows LiveM3U8Server to serve HLS streams immediately while recording continues, with unencrypted init segments (SegmentEncryptor.java:26) ensuring minimal client startup delay.

Why does FadCam write recordings to cache before moving to final storage?

Writing directly to external storage via Storage Access Framework (SAF) introduces significant latency due to repeated IPC calls. RecordingService.java (lines 6611-6613) writes to getCacheDir() first, leveraging the faster internal storage partition. The temporary file moves to its final destination only after recording stops, batching the slower SAF operations and preventing frame drops during active capture.

How does FadCam handle large video libraries without UI freezing?

The FastFileScanner class (app/src/main/java/com/fadcam/data/FastFileScanner.java) replaces DocumentFile.listFiles() with bulk File scanning across lines 31-456. This reduces IPC overhead when enumerating thousands of video files, while FFprobeKit media information caching in VideoSourceBottomSheet.java (lines 719-721) prevents repeated metadata extraction during audio processing tasks.

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 →