How to Shrink an MP4 File with FFmpeg

September 5, 2026 · RenderIO

You've just recorded a five-minute demo, exported it as an MP4, and tried to attach it to an email. The upload stops at the limit, the recipient needs the file immediately, and lowering random settings feels like guesswork. The reliable way to shrink an MP4 file is to diagnose what created the size, then change the smallest number of variables necessary.

FFmpeg gives you that control. You can preserve the frame size and adjust quality, switch codecs, reduce resolution, control audio, or target a strict bitrate. The right choice depends on whether your file is oversized because of its video stream, audio stream, dimensions, frame rate, or delivery requirements.

Table of Contents

Why MP4 Files Become Too Large

An MP4 isn't a single block of video data. It's a container that wraps separate video and audio streams, along with timing and metadata. Changing the extension, renaming the file, or moving those streams into another container with a muxing-only operation doesn't recompress them, so the file usually stays the same size.

The size problem normally starts earlier. A camera or screen recorder may use a high video bitrate, large frame dimensions, or a high frame rate by default. HDR and 10-bit footage can require more data, while an uncompressed or high-bitrate audio track adds its own share. A long recording multiplies the effect because total size is driven largely by duration and bitrate.

A diagram explaining factors that cause MP4 files to become large including resolution, bitrate, and audio settings.

The container isn't the compression lever

The meaningful operation is re-encoding. FFmpeg decodes the existing video, applies a new codec and quality model, then writes a new stream into an MP4 container. That's different from copying the original stream with -c:v copy, which is useful for repackaging but won't make the encoded video smaller.

H.264/AVC became the foundational technology behind modern MP4 shrinking workflows. The H.264 historical overview records its ITU-T approval on 30 May 2003 and describes its development for higher compression in streaming, storage, broadcasting, and related distribution use cases. The standard's purpose matters here: shrinking an MP4 generally means encoding the stream more efficiently, not manipulating the .mp4 label.

Find the oversized component first

A useful diagnostic model is simple:

  • High bitrate: Re-encode with CRF or a lower target bitrate.
  • Inefficient codec: Test H.265 if the playback environment supports it.
  • Large dimensions: Scale 4K or oversized 1080p footage to the delivery frame size.
  • Excessive frame rate: Reduce it when the material doesn't need high-motion smoothness.
  • Bulky audio: Encode speech-heavy tracks as AAC at an appropriate bitrate.
  • Unnecessary duration: Trim silence, dead air, or unused footage before encoding.

Practical rule: Change one major lever first. If you reduce resolution, frame rate, codec efficiency, and quality simultaneously, you won't know which change caused a visible defect.

The next step is to inspect the streams instead of guessing.

Inspecting the Source Before Compression

Start by recording what you have. FFmpeg's companion tool, ffprobe, can expose the container and stream details without producing a new file. The broad header view is useful when you're unfamiliar with the source:

ffprobe -hide_banner -i input.mp4

For a compact summary, use:

ffprobe -v error -show_entries stream=codec_type,codec_name,bit_rate,width,height,r_frame_rate,sample_rate,channels -of default input.mp4

This reports the fields that normally determine your first compression decision. A 4K source with a moderate bitrate calls for a different approach from a 1080p source whose bitrate is unnecessarily high.

Capture the fields that affect the decision

Field Example value Why it matters
Video codec h264 Shows whether a codec change could improve efficiency
Video bitrate 8000000 Reveals how much data the encoder spends per second
Width and height 1920x1080 Determines whether scaling can remove excess pixels
Frame rate 30000/1001 Helps identify high-motion or unnecessarily dense output
Pixel format yuv420p Affects compatibility and color handling
Audio codec aac Confirms whether audio needs conversion
Sample rate 48000 Helps preserve suitable audio timing
Channels 2 Indicates stereo or multi-channel overhead

For a more detailed explanation of how to read these fields, use this FFprobe tutorial for stream inspection.

The bit_rate field may be missing, especially with variable-bitrate streams. That isn't necessarily an error. Calculate an approximate overall bitrate from the file size and duration, then compare that result with the individual stream values. The container summary from this command can also help:

ffmpeg -i input.mp4 -f null -

FFmpeg will print duration, frame-rate information, stream details, and a muxer-level bitrate summary while it reads the file.

Make a baseline before exporting

Record these values in a note or spreadsheet:

  • Source file size
  • Duration
  • Video codec and bitrate
  • Width, height, and frame rate
  • Pixel format and color characteristics
  • Audio codec, bitrate, sample rate, and channel count

After compression, capture the same fields. Comparing like with like prevents a common mistake, declaring success because the file is smaller while overlooking a resolution change, missing audio stream, or incompatible pixel format.

Compressing MP4 Files With FFmpeg

For a general-purpose H.264 MP4, start with a quality-based encode:

ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart output.mp4

This command re-encodes the video, converts the audio to AAC, and prepares the MP4 for progressive web playback. It's a sensible baseline for sharing when compatibility matters more than achieving the absolute smallest file.

Screenshot from https://example.com/screenshots/ffmpeg-crf-compress.png

Understand CRF and preset separately

CRF, or Constant Rate Factor, controls perceived video quality rather than demanding one fixed bitrate. Lower values preserve more detail and create larger files. Higher values accept more compression and create smaller files. Industry guidance commonly places H.264 CRF 18–23 in the visually lossless to high-quality range, with 23–28 used for more aggressive online compression, as documented in this FFmpeg video compression guide.

Use -crf 18 when retaining fine detail is important. Use -crf 23 as a practical starting point. Try -crf 28 only after checking motion, text, gradients, and dark areas in a sample. The source content matters, so a static screen recording and a fast camera shot won't produce the same size at the same CRF.

The preset controls encoding effort, not the requested quality. ultrafast finishes quickly but usually produces a less efficient file. medium is a balanced default. slow and veryslow spend more processing time searching for compression decisions that can reduce the final size at a comparable quality level.

Quality check: A slower preset doesn't rescue an excessively high CRF. Set an acceptable quality target first, then use the preset to trade encoding time for efficiency.

Audio and web playback flags

The -c:a aac -b:a 128k portion is appropriate for many speech-heavy stereo tracks. Music and sound-design-heavy work may need a higher audio setting, while voice-only material can often tolerate a leaner track after listening tests.

-movflags +faststart relocates the MP4 metadata needed for playback toward the beginning of the file. It doesn't meaningfully compress the media streams, but it helps browsers begin progressive playback before the entire file has downloaded.

After the command finishes, compare the source and output with:

ls -lh input.mp4 output.mp4

Then inspect the new streams:

ffprobe -v error -show_entries stream=codec_name,bit_rate,width,height,r_frame_rate,sample_rate,channels -of default output.mp4

If the output is still too large, change one setting at a time. Raise CRF modestly, use a slower preset, lower the resolution, or test a more efficient codec. Don't assume that adding +faststart or changing the container alone will create a size reduction.

This video walkthrough shows the same CRF-oriented workflow in action:

Choosing Bitrate, Codec, and Resolution

Different constraints call for different controls. CRF is usually the right starting point when you want consistent visual quality. A fixed bitrate is better when a platform or attachment limit gives you a strict size ceiling. Resolution is the strongest spatial lever, while codec selection changes how efficiently the encoder represents the same visual information.

H.264 remains the safer compatibility choice. H.265/HEVC can deliver roughly 40–50% bitrate reduction versus H.264 at comparable visual quality, according to technical comparisons of H.264, H.265, and AV1. That reduction can translate into a smaller MP4, but only if the target devices and platforms decode HEVC reliably. Older systems may fail to play it or may fall back to slower software decoding.

Match the lever to the constraint

Approach Best For Typical Size Cut Example Command
CRF encoding Quality-first sharing Content-dependent ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mp4
Fixed bitrate Strict upload or delivery limits Depends on target bitrate and duration ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -c:a aac -b:a 128k output.mp4
H.265 encoding Smaller files on compatible devices Roughly 40–50% bitrate reduction versus H.264 at similar quality ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a aac -b:a 128k output.mp4
Resolution scaling Aggressive bandwidth or storage reduction Content-dependent ffmpeg -i input.mp4 -vf scale=1280:-2 -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mp4

The “Typical Size Cut” column is intentionally qualitative except where the codec comparison provides a sourced range. Real output varies with texture, movement, text, noise, source compression, and duration.

For a strict limit, estimate the total bitrate required from the permitted file size and clip duration, then reserve part of that budget for audio and container overhead. A two-pass encode can distribute a fixed video bitrate more intelligently across a longer clip than a rushed single-pass target:

ffmpeg -y -i input.mp4 -c:v libx264 -b:v 1500k -pass 1 -an -f mp4 /dev/null

ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 2 -c:a aac -b:a 128k -movflags +faststart output.mp4

On Windows, replace /dev/null with NUL. Don't skip the first pass. The second pass depends on the analysis generated by the first.

Resolution should be reduced only when the destination doesn't need the original dimensions. A guide from VideoLearningAI on practical video compression techniques is useful when you're weighing dimensions, bitrate, and codec together. For a broader workflow focused on reducing output size, see RenderIO's video file size guide.

Frame-rate reduction can help when the source uses more frames than the viewing context requires, but it can damage cursor movement, animation, gameplay, or fast camera work. Test it rather than applying it automatically.

Testing Size and Quality Changes

A ten-second test clip is cheaper than discovering a bad setting after a full export. Pick a representative segment with motion, text, gradients, faces, and any scene that tends to expose artifacts. A static opening frame won't tell you whether the encoder handles the difficult parts.

Create a sample with:

ffmpeg -ss 00:00:20 -i input.mp4 -t 10 -c copy test-source.mp4

For a clean test, re-encode that sample with one adjustment:

ffmpeg -i test-source.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart test-crf23.mp4

Capture size and stream properties with:

ffprobe -v error -show_entries format=size,duration,bit_rate:stream=codec_name,bit_rate,width,height,r_frame_rate -of csv=p=0 test-crf23.mp4

A diagram illustrating the video compression workflow using FFmpeg, ffprobe, and parameter adjustments to optimize file size.

Compare measurements with what viewers see

Objective metrics can help, but they're not a substitute for visual review. FFmpeg can generate PSNR and SSIM comparisons when you keep the source and encoded test aligned:

ffmpeg -i test-source.mp4 -i test-crf23.mp4 -lavfi "[0:v][1:v]psnr=stats_file=psnr.log;[0:v][1:v]ssim=stats_file=ssim.log" -f null -

For frame-level inspection, extract matching stills:

ffmpeg -ss 00:00:04 -i test-source.mp4 -frames:v 1 source-frame.png

ffmpeg -ss 00:00:04 -i test-crf23.mp4 -frames:v 1 compressed-frame.png

Review small text, sharp edges, skin tones, shadows, and gradients at normal playback size. A technically strong score can still hide a defect that matters to your audience, especially around UI text or animation.

As a practical streaming-oriented reference, you can treat PSNR above 40 dB and SSIM above 0.98 as useful quality targets, but interpret them alongside playback and frame inspection. These thresholds aren't guarantees of perceived quality.

A simple shell loop can make repeated tests easier:

for crf in 23 25 27; do ffmpeg -y -i test-source.mp4 -c:v libx264 -crf "$crf" -preset medium -c:a aac -b:a 128k "test-crf${crf}.mp4" 2> "test-crf${crf}.log"; printf "%s," "$crf"; ffprobe -v error -show_entries format=size,bit_rate -of csv=p=0 "test-crf${crf}.mp4"; done

Change only the parameter you're evaluating. Keep a small log of CRF, preset, codec, dimensions, output size, and visual observations.

Automating Compression With RenderIO

A local FFmpeg command works well for occasional files. A library of uploads needs a repeatable job model, reliable storage, progress reporting, and failure handling. RenderIO accepts FFmpeg 7.x commands through a REST workflow, so the compression settings you validate locally can become a remote processing preset without redesigning the encode itself.

The request should provide an input URL, an output destination or output URL, the FFmpeg argument string, and webhook configuration. The command portion can use the same settings tested above, such as:

-i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart output.mp4

In production, treat the command as configuration rather than concatenating untrusted user input. Store named presets for compatibility-first H.264, smaller HEVC delivery, and resolution-scaled exports. Each project can then use a deliberate profile instead of changing flags by hand for every clip.

Screenshot from https://renderio.example/screenshots/renderio-ffmpeg-job-submit.png

Build observability into the job

FFmpeg writes progress and diagnostic information to stderr. Capture those lines and expose meaningful states such as queued, running, completed, and failed. Preserve the complete stderr output for debugging because codec support, malformed inputs, permissions, and incompatible filters often become obvious there.

Webhook delivery lets your application receive the finished output without repeatedly checking the job. Add idempotency so a network retry doesn't create duplicate encodes, and retry transient failures separately from permanent media errors. For implementation details, use the RenderIO video compression guide.

For large batches, queue files and process independent jobs in parallel within your resource limits. Keep the original source, selected preset, encoder version, output metadata, and final probe results together. That record makes it possible to reproduce a delivery asset and identify why one source compresses differently from another.

Troubleshooting and Final Recommendations

A smaller output isn't automatically a successful output. If the file barely changed, check whether you used -c:v copy or another muxing-only operation. If it became larger, a fixed bitrate may be higher than the source's effective bitrate, or the source may already be efficiently encoded.

If quality dropped sharply, inspect the CRF, dimensions, pixel format, and frame rate. H.264 values around 18–28 are a useful working range from the cited FFmpeg guidance, but content still determines the result. Upscaling before encoding wastes data, while skipping the first pass makes a two-pass workflow ineffective.

Use this order when making the next adjustment:

  1. Verify the stream changed. Run ffprobe on the output and confirm the codec, dimensions, bitrate, and audio settings.
  2. Adjust quality carefully. Raise CRF by a small amount for a smaller file, or lower it if artifacts are visible.
  3. Change encoding effort. Move from medium toward slow when processing time is available.
  4. Reduce dimensions. Scale oversized material only when the destination doesn't need the source resolution.
  5. Control audio. Encode speech-heavy audio as AAC around 128k and listen before adopting the setting.
  6. Use delivery flags. Add -movflags +faststart for progressive web playback.
  7. Use two-pass encoding. Choose it when a fixed file-size target matters more than a simple quality-based workflow.

Run the probe again after every meaningful change. Once the short sample meets the size, compatibility, and visual requirements, apply that exact preset to the full-length file.


RenderIO lets you submit the FFmpeg compression command you've already tested, then automate input retrieval, output delivery, progress updates, retries, and batch processing. Visit RenderIO to turn a one-off MP4 shrink workflow into a repeatable video pipeline.