【问题标题】:ffmpeg video compression / specific file sizeffmpeg 视频压缩/特定文件大小
【发布时间】:2015-05-18 21:32:40
【问题描述】:

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

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

它们目前约为 25mb 一块

【问题讨论】:

    标签: ffmpeg


    【解决方案1】:

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

    【讨论】:

    • 在您的计算中,文件大小和持续时间的单位是什么?
    • @DrewChapin 千比特/秒
    • H.265 也可能对速度较慢的 PC 或移动设备不利,因为它占用大量 CPU 资源。
    • 我们如何在 Windows 命令终端又名 MSDOS 中执行此操作,因为它使用奇怪的两行语法?
    【解决方案2】:

    受到 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
    

    注意事项

    • 请参阅 cmets 了解可能的 Windows 版本。

    来源

    Hashbrown's answer (in this thread)

    Two Pass method

    【讨论】:

    • $1 应在第 4 行和第 5 行引用,以防文件路径包含空格。在相关说明中,“编辑必须至少 6 个字符”是编程网站的愚蠢规则。
    • $1s 现在引用感谢 9072997。还是简称为 907?
    • 如果您的输入包含多个音频流,您可能需要在两条 ffprobe 行上将 -select_streams a 更改为 -select_streams a:0
    • 它不应该是一个整数,我没有运行你的,但我的原版采用“7.5”,所以我认为你的可能/可以。这很方便,因为算法似乎过冲(8 生成一个 8.5mB 的文件,这不和谐不会喜欢,但 7.8 已经完全死了,没有下降到 7-flat)
    • origin_duration_s=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$1") 消除grep。请注意,origin_audio_bitrate_kbit_s 不适用于所有格式,尤其是 Matroska (mkv) 输入。但是您也可以从中删除greporigin_audio_bitrate_kbit_s=$(ffprobe -v error -select_streams a:0 -show_entries stream=bit_rate -of csv=p=0 "$1")
    【解决方案3】:

    这是一种使用 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"
    

    注意,我正在切断音频

    【讨论】:

    • 如何不剪切音频?
    • 好的。解决方案是删除带有-an 的行
    • 嗯,我只是没有尝试,因为它不再符合您想要制作的尺寸。要包含音频并具有文件大小上限,您需要确定比特率并降低音频质量,而不仅仅是 -b:v,还要确保这两者相加正确。
    • 如果您想“按原样”保留音频(我通常想要),那么您当然可以使用 ffprobe 之类的东西来确定音轨的大小。从目标大小中减去该大小以获得可用于视频轨道的剩余大小。我发现你需要从 MP4 容器中减去 2Mb。最近的一个例子,将 200Mb、720p 视频缩小到 640x360 版本,目标是 64Mb(获得 63.9Mb):ffmpeg -i in.mp4 -filter:v scale=640:-1 -c:a copy -b:v 630k out.mp4-c:a copy 为我提供了输出视频中的原始音频。
    【解决方案4】:

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

    使用 H.264 和两次编码。

    使用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

    【讨论】:

    • 为什么看起来你这里有 4 个 ffmpeg 调用?
    【解决方案5】:

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

    ffmpeg -i input.mp4 -filter:v fps=fps=10 output.mp4

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-28
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-13
      相关资源
      最近更新 更多