Currently I have 80mb movies that I want to use ffmpeg to convert down to say about 10mb or 15mb. I know there will be a quality loss but they will need to have sound. Is there a way to either specify a file size or higher compression than what I have done previously
ffmpeg -i movie.mp4 -b 2255k -s 1280x720 movie.hd.ogv
They are currently about 25mb a piece
Download and set up FFmpeg on your computer, use command line to compress video with FFmpeg by changing video codec format, lowering down bitrate, cutting video length, etc. For example, set CRF in FFmpeg to reduce video file size (ffmpeg -i input. mp4 -vcodec libx264 -crf 24 output.
To set the bitrate target in FFmpeg, use the -b:v code (bitrate:video) below : ffmpeg -i Test_1080p. MP4 -c:v libx264 -b:v 5000k Test_DR_5M.
Instead of -sameq (removed by FFMpeg), use -qscale 0 : the file size will increase but it will preserve the quality.
if you are targeting a certain output file size the best way is to use H.264 and Two-Pass encoding.
There is a great example here but it's too large to copy-paste: https://trac.ffmpeg.org/wiki/Encode/H.264#twopass
You calculate your target bitrate using bitrate = target size / duration
and you launch ffmpeg two times: one pass analyzes the media and the second does the actual encoding:
ffmpeg -y -i input -c:v libx264 -preset medium -b:v 555k -pass 1 -c:a libfdk_aac -b:a 128k -f mp4 /dev/null && \ ffmpeg -i input -c:v libx264 -preset medium -b:v 555k -pass 2 -c:a libfdk_aac -b:a 128k output.mp4
Edit: H.265 (HEVC) is even better at compression (50% of H.264 size in some cases) but support is not yet widespread so stick with H.264 for now.
Inspired by Hashbrown's answer. This version keeps the original audio quality, and resizes to the target size.
NEW
grep
(-P
switch not implemented in OSX grep)#!/bin/bash # # Re-encode a video to a target size in MB. # Example: # ./this_script.sh video.mp4 15 T_SIZE="$2" # target size in MB T_FILE="${1%.*}-$2MB.mp4" # filename out # Original duration in seconds O_DUR=$(\ ffprobe \ -v error \ -show_entries format=duration \ -of csv=p=0 "$1") # Original audio rate O_ARATE=$(\ ffprobe \ -v error \ -select_streams a:0 \ -show_entries stream=bit_rate \ -of csv=p=0 "$1") # Original audio rate in KiB/s O_ARATE=$(\ awk \ -v arate="$O_ARATE" \ 'BEGIN { printf "%.0f", (arate / 1024) }') # Target size is required to be less than the size of the original audio stream T_MINSIZE=$(\ awk \ -v arate="$O_ARATE" \ -v duration="$O_DUR" \ 'BEGIN { printf "%.2f", ( (arate * duration) / 8192 ) }') # Equals 1 if target size is ok, 0 otherwise IS_MINSIZE=$(\ awk \ -v size="$T_SIZE" \ -v minsize="$T_MINSIZE" \ 'BEGIN { print (minsize < size) }') # Give useful information if size is too small if [[ $IS_MINSIZE -eq 0 ]]; then printf "%s\n" "Target size ${T_SIZE}MB is too small!" >&2 printf "%s %s\n" "Try values larger than" "${T_MINSIZE}MB" >&2 exit 1 fi # Set target audio bitrate T_ARATE=$O_ARATE # Calculate target video rate - MB -> KiB/s T_VRATE=$(\ awk \ -v size="$T_SIZE" \ -v duration="$O_DUR" \ -v audio_rate="$O_ARATE" \ 'BEGIN { print ( ( size * 8192.0 ) / ( 1.048576 * duration ) - audio_rate) }') # Perform the conversion ffmpeg \ -y \ -i "$1" \ -c:v libx264 \ -b:v "$T_VRATE"k \ -pass 1 \ -an \ -f mp4 \ /dev/null \ && \ ffmpeg \ -i "$1" \ -c:v libx264 \ -b:v "$T_VRATE"k \ -pass 2 \ -c:a aac \ -b:a "$T_ARATE"k \ $T_FILE
Hashbrown's answer (in this thread)
Two Pass method
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With