我有一些80MB大小的电影文件,想用ffmpeg将它们转换成10MB或15MB大小。我知道这样会导致画质下降,但需要保证声音。是否可以指定文件大小或采用比之前更高的压缩率来实现呢?
ffmpeg -i movie.mp4 -b 2255k -s 1280x720 movie.hd.ogv
它们目前每个大约有25MB
我有一些80MB大小的电影文件,想用ffmpeg将它们转换成10MB或15MB大小。我知道这样会导致画质下降,但需要保证声音。是否可以指定文件大小或采用比之前更高的压缩率来实现呢?
ffmpeg -i movie.mp4 -b 2255k -s 1280x720 movie.hd.ogv
它们目前每个大约有25MB
如果您的目标是特定的输出文件大小,最好的方法是使用H.264和双通道编码。
这里有一个很好的例子,但太大了无法复制粘贴:https://trac.ffmpeg.org/wiki/Encode/H.264#twopass
您可以使用 bitrate = target size / duration
计算目标比特率,然后启动ffmpeg两次:第一遍分析媒体,第二遍进行实际编码:
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
编辑:H.265(HEVC)在压缩方面表现得更好(有时可以达到H.264大小的50%),但支持尚不普及,因此目前请继续使用H.264。
受Hashbrown答案的启发。此版本保持原始音频质量,并调整大小以适应目标大小。
新版
grep
的依赖(在OSX grep中未实现-P
开关)#!/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"
$1
。另外,“编辑必须至少为6个字符”这条规则对于一个编程网站来说是愚蠢的。 - 9072997origin_duration_s=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$1")
替换grep
。请注意,对于某些格式,例如Matroska (mkv)输入,origin_audio_bitrate_kbit_s
将无法正常工作。但是你也可以从中删除grep
: origin_audio_bitrate_kbit_s=$(ffprobe -v error -select_streams a:0 -show_entries stream=bit_rate -of csv=p=0 "$1")
。 - llogan./script.sh file.mp4 15
表示15兆字节
。bitrate="$(awk "BEGIN {print int($2 * 1024 * 1024 * 8 / $(ffprobe \
-v error \
-show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 \
"$1" \
) / 1000)}")k"
ffmpeg \
-y \
-i "$1" \
-c:v libx264 \
-preset medium \
-b:v $bitrate \
-pass 1 \
-an \
-f mp4 \
/dev/null \
&& \
ffmpeg \
-i "$1" \
-c:v libx264 \
-preset medium \
-b:v $bitrate \
-pass 2 \
-an \
"${1%.*}-$2mB.mp4"
我正在剪辑音频
-b:v
,还要确保这两个值正确相加。 - Hashbrownffmpeg -i in.mp4 -filter:v scale=640:-1 -c:a copy -b:v 630k out.mp4
;-c:a copy
使我在输出视频中获得原始音频。 - RJVB$(( $2 * 1024 * 1024 * 8 / $( ... ) ))
。这甚至不是bash,这是POSIX shell,甚至可以在dash、ash等中工作。 - Mecki使用Windows 10,cmd和ffmpeg将视频压缩到预定文件大小。
使用H.264和双通道编码。
计算比特率:比特率=目标文件大小/持续时间
目标文件大小以千位为单位。持续时间以秒为单位。1 MB = 8192 kb
将比特率分配给视频和音频,大约3/4的视频,1/4的音频。音频和视频比特率之和不能超过计算出的比特率。
-c:a libfdk_aac
对我无效。
ffmpeg -y -i input -c:v libx264 -b:v CALCULATED BITRATE HERE -pass 1 -an -f null nul && ^ffmpeg -y -i input -c:v libx264 -b:v CALCULATED BITRATE HERE -pass 2 -c:a aac -b:a CALCULATED BITRATE HERE output.mp4
ffmpeg -y -i 1.mp4 -c:v libx264 -b:v 555k -pass 1 -an -f null nul && ^ffmpeg -y -i 1.mp4 -c:v libx264 -b:v 555k -pass 2 -c:a aac -b:a 128k output.mp4
如果优先考虑音频,通过降低分辨率可以将视频大小大幅缩小。
-filter:v "scale=-1:ih*1/2:force_original_aspect_ratio=decrease" -max_muxing_queue_size 1024
如果您不需要高帧率,比如在教程中,只需降低帧率,就可以显著减小视频文件的大小。使用此过滤器,您不会失去音频同步。
ffmpeg -i input.mp4 -filter:v fps=fps=10 output.mp4
NUL && ^
代替dev null && \
。或者使用filenamehere && ^
来创建一个中间文件。 - undefined