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