ffmpeg视频压缩/特定文件大小

问题描述 投票:0回答:6

目前我有 80mb 的电影,我想使用 ffmpeg 将其转换为大约 10mb 或 15mb。我知道质量会有所损失,但他们需要有声音。有没有办法指定文件大小或比我以前所做的更高的压缩

ffmpeg -i movie.mp4 -b 2255k -s 1280x720 movie.hd.ogv

目前每片大约 25mb

ffmpeg
6个回答
46
投票

如果您的目标是特定的输出文件大小,最好的方法是使用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。


40
投票

受到Hashbrown的回答的启发。此版本保留了原始音频质量,并调整为目标大小。

  1. 重命名变量以提高可读性和一致性。
  2. 删除了对
    grep
    的依赖(
    -P
    开关未在 OSX grep 中实现)
  3. 如果目标尺寸太小,脚本现在会退出并显示一条有用的消息。

脚本

#!/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"

注释

  • 请参阅可能的 Windows 版本的评论。

来源

Hashbrown 的回答(在这个帖子中)

双通道法

Windows 版本,因为评论中的链接不再有效

@echo off
REM Windows implementation of Marian Minar's answer to "ffmpeg video compression / specific file size" https://stackoverflow.com/a/61146975/2902367
SET "video=%~1"
SET "target_video_size_MB=%~2"
SET "output_file=%~dpn1 %~2MB.mp4"
REM I usually don't see a big difference between two-pass and single-pass... set to anything but "true" to turn off two-pass encoding
SET "twopass=true"
REM We need a way to do floating point arithmetic in CMD, here is a quick one. Change the path to a location that's convenient for you
set "mathPath=c:\bin\Math.vbs"
REM Creating the Math VBS file
if not exist "%mathPath%" echo Wscript.echo replace(eval(WScript.Arguments(0)),",",".")>%mathPath%

echo Converting to %target_video_size_MB% MB: "%video%"
echo -^> "%output_file%"
pause
SETLOCAL EnableDelayedExpansion
REM Getting the (audio) duration. TODO: watch out for differing audio/video durations?
FOR /F "delims=" %%i IN ('ffprobe -v error -show_streams -select_streams a "%~1"') DO (
    SET "line=%%i"
    if "!line:~0,9!" == "duration=" (
        SET "duration=!line:~9!"
    )
)
REM Getting the audio bitrate
FOR /F "delims=" %%i IN ('ffprobe -v error -pretty -show_streams -select_streams a "%~1"') DO (
    SET "line=%%i"
    SET /A "c=0"
    if "!line:~0,9!" == "bit_rate=" (
        FOR %%a IN (!line:~9!) DO (
            if "!c!" == "0" (
                SET "audio_rate=%%a"
            )
            SET /A "c+=1"
        )
    )
)
REM TODO: Adjust target audio bitrate. Use source bitrate for now.
SET "target_audio_bitrate=%audio_rate%"

call:Math %target_video_size_MB% * 8192 / (1.048576 * %duration%) - %target_audio_bitrate%
SET "target_video_bitrate=%result%"

echo %target_audio_bitrate% audio, %target_video_bitrate% video

SET "passString="
if "%twopass%" == "true" (
    echo Two-Pass Encoding
    ffmpeg ^
        -y ^
        -i "%~1" ^
        -c:v libx264 ^
        -b:v %target_video_bitrate%k ^
        -pass 1 ^
        -an ^
        -f mp4 ^
        nul
    SET "passString=-pass 2"
) else ( echo Single-Pass Encoding )
ffmpeg ^
    -i "%~1" ^
    -c:v libx264 ^
    -b:v %target_video_bitrate%k ^
    %passString% ^
    -c:a aac ^
    -b:a %target_audio_bitrate%k ^
    "%output_file%"
    
pause
GOTO :EOF

:Math
REM echo Working : "%*"
for /f %%a in ('cscript /nologo %mathPath% "%*"') do set "Result=%%a"
GOTO :EOF

11
投票

这是一种使用 bash 脚本自动完成此操作的方法
只需像

./script.sh file.mp4 15
那样拨打
15mB

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"

注意我正在切断音频


3
投票

使用 Windows 10、cmd 和 ffmpeg 将视频减小到预先确定的文件大小。

使用 H.264 和 Two-Pass 编码。

使用

bitrate = target file size / duration

计算您的比特率

目标文件大小(以千位为单位)。持续时间(以秒为单位)。 1 MB = 8192kb

将视频和音频的比特率分开,大约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

参见 https://trac.ffmpeg.org/wiki/Encode/H.264#twopass


0
投票

如果优先考虑音频,可以通过降低分辨率来将视频大小缩小到一小部分

-过滤器:v“比例=-1:ih * 1/2:force_original_aspect_ratio =减少”-max_mushing_queue_size 1024


-4
投票

只需降低帧速率 - 如果您不需要高帧速率,就像在教程中一样 - 您将显着减小视频文件的大小,并且使用此过滤器您希望失去音频同步

ffmpeg -i 输入.mp4 -filter:v fps=fps=10 输出.mp4

© www.soinside.com 2019 - 2024. All rights reserved.