如何使用 ffmpeg 生成具有几帧的网络预览视频?

Aze*_*edo 3 ffmpeg html5

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

Aru*_*sti 5

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"
Run Code Online (Sandbox Code Playgroud)

可调整的Python脚本

作为Azevedo 答案的扩展,我制作了一个脚本,这样我就可以使用 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}
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)