TL;DR: 与上述内容等效的 bash 版本:

TL;DR: 与上述内容等效的 bash 版本:

如何使用 ffmpeg 生成仅包含几帧的 Web 预览视频?例如,当您将鼠标移到视频上时,它会在加载实际视频之前播放几帧预览?

答案1

TL;DR: 与上述内容等效的 bash 版本:

width=384
height=216

frame_count=$(ffprobe -v error -show_entries format=duration "/input/file.mp4" -of default=noprint_wrappers=1:nokey=1)
frame_target=$( expr ${frame_count%.*} / 10)


ffmpeg -threads 2 -i "/input/file.mp4" -an -qscale:v 1 -vframes 10 -f image2pipe -vcodec ppm \
    -vf "fps=1/$frame_target, scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih):flags=lanczos, pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2, unsharp=5:5:0.5:5:5:0.5" -\
| ffmpeg -y -threads 2 -framerate 1 -i pipe:0 -c:v libx264 -profile:v baseline -level 3.0 -tune stillimage -r 30 -pix_fmt yuv420p "/output/preview.mp4"

可调整的 Python 脚本

作为阿泽维多的回答我编写了一个脚本,以便可以使用 unix 环境轻松地制作不同大小的预览。

generate_preview_video.sh

tmp_dir=$(mktemp -d -t {tmp_prefix}-XXXXXXXXXX)
echo $tmp_dir

width={width}
height={height}

frame_count=$(ffprobe -v error -show_entries format=duration "{input_filepath}" -of default=noprint_wrappers=1:nokey=1)
frame_target=$( expr ${{frame_count%.*}} / {output_frame_count})



ffmpeg -threads {threads} -i "{input_filepath}" -an -qscale:v 1 -vframes {output_frame_count} -f image2pipe -vcodec ppm \
    -vf "fps=1/$frame_target, scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih):flags=lanczos, pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2, unsharp=5:5:0.5:5:5:0.5" - \
| ffmpeg -y -threads {threads} -framerate {framerate} -i pipe:0 -c:v libx264 -profile:v baseline -level 3.0 -tune stillimage -r 30 -pix_fmt yuv420p "$tmp_dir/{output_filename}"

echo $tmp_dir/{output_filename}

preview_gen.py

import os
import shutil
import argparse


def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("tmp_prefix", help="used to generate temporary dir to work in")
    parser.add_argument("input", help="path of input file")
    parser.add_argument("output_path", help="path to output result")
    parser.add_argument("output_filename", help="desired name of output file")
    parser.add_argument("-t", "--threads", type=int, default=2)
    parser.add_argument("--width", type=int, default=384, help="output width")
    parser.add_argument("--height", type=int, default=216, help="output height")
    parser.add_argument("--framerate", type=int, default=1, help="output video framerate")
    parser.add_argument("--seconds", type=int, default=10, help="length of output video")
    args = parser.parse_args()

    with open('generate_preview_video.sh', 'r') as file:
        generate_script = file.read()

    generate_previews_command = str(generate_script).format(
        threads=args.threads,
        tmp_prefix=args.tmp_prefix,
        width=args.width,
        height=args.height,
        framerate=args.framerate,
        output_frame_count=args.framerate*args.seconds,
        input_filepath=args.input,
        output_filename=args.output_filename
    )

    stream = os.popen(generate_previews_command)
    output = stream.readlines()

    tmp_dir = output[0].strip()
    file_path = output[2].strip()

    shutil.move(file_path, args.output_filename+ args.output_file)
    shutil.rmtree(tmp_dir)

if __name__ == "__main__":
    main()

答案2

下面的批处理脚本可以实现这一点。它针对 Web 进行了优化,生成一个预览视频,其中包含从原始视频中截取的 10 幅图像。每幅图像显示 1 秒。脚本会相应地获取图像样本,因此预览图像取自整个视频。

  • 只需要 ffmpeg。(以及 ffmpeg 包的一部分 ffprobe)

  • 输出:mp4/h.264 ~ 120Kb(无论原始视频大小)

  • 完全可配置。

  • 优化了 lanczos 和锐化滤镜。

  • 将原始视频放入 16:9(384x216)的框架中,保持原始视频的宽高比(必要时填充侧面的黑条)。

  • 没有使用临时文件。(从 ffmpeg 到 ffmpeg 的即时管道)

  • HTML5友好。

这里有两个 gif 示例,仅供预览。 实际输出是mp4/h.264:

16:9 视频源。输出:

16:9 宽屏

4:3 视频源。输出:

4:3 标准差

在 Windows 上运行,但可以轻松转换为 bash 脚本(Linux)。

该脚本创建一个文件夹./preview来存储所有生成的预览:

/My videos
    movie1.mp4 ~ any size
    movie2.mp4 ~ any size
    /preview
        movie1.mp4 ~ 120Kb
        movie2.mp4 ~ 120Kb 

它可以被调整以在单个文件上运行。

预览生成器.cmd:

REM ----------------------------------------------
set folder=C:\My videos
set vframes=10
set width=384
set height=216
    rem w = h*16/9
set filetypes=*.mp4
REM ----------------------------------------------
setlocal EnableDelayedExpansion

pushd "%folder%"
if not exist preview md preview
for /f "usebackq delims=" %%f in (`dir /b %filetypes%`) do (
    if not exist "preview\%%~nf.mp4" (  
        for /f %%i in ('ffprobe -v error -show_entries format^=duration "%%f" -of default^=noprint_wrappers^=1:nokey^=1') do set length=%%i
        set /a length=!length!+0
        set /a fps=!length!/%vframes%
        ffmpeg -threads 2 -i "%%f" -an -qscale:v 1 -vf "fps=1/!fps!, scale=iw*min(%width%/iw\,%height%/ih):ih*min(%width%/iw\,%height%/ih):flags=lanczos, pad=%width%:%height%:(%width%-iw*min(%width%/iw\,%height%/ih))/2:(%height%-ih*min(%width%/iw\,%height%/ih))/2, unsharp=5:5:0.5:5:5:0.5" -vframes %vframes% -f image2pipe -vcodec ppm - ^
        | ffmpeg -y -threads 2 -framerate 1 -i pipe:0 -c:v libx264 -profile:v baseline -level 3.0 -tune stillimage -r 30 -pix_fmt yuv420p "preview\%%~nf.mp4"
    )
cls
)

更新: 您可以轻松控制 HTML5 中的播放速率,<video>如下所示这里

为什么不使用 gif 来代替?

  • .gif 格式的质量最差(像素化颜色/最多 256 种颜色)

  • .gif 文件大小至少大 2 倍。

  • 构建后,您无法控制播放速度/暂停 gif 动画。

相关内容