用FFmpeg来生成带背景和视频信息的缩略图(一)

in FFmpeg with 8427 comments

  FFmpeg是一款著名的开源音视频处理软件,它可以完成记录、转换数字音频、视频,并能将其转化为流等功能。

  我们可以运用其强大的滤镜功能来完成一些对视频、音频的处理。而对于视频而言,如果只截取视频中的一帧图像,那么就可以完成对视频的截图。命令中可以使用-vframes代替-frames:v

ffmpeg -ss HH:MM:SS -i input -frames:v 1 output

  但事实上,FFmpeg并不能截取对应时间准确的一帧。因为对于某些格式的视频而言,使用FFmpeg-ss参数只能只能截取到欲截取帧前的关键帧。

  如果想生成一个简单的缩略图,则需要使用一定数量的图片然后拼接起来。这里以3*3的截图为例,那么我们所需要获取到的就是九张截图。如果想要等时间间隔的生成九张图片,那么我们首先要获取到的便是视频的时长。

ffprobe -i input -show_entries format=duration -v quiet -of csv="p=0"

  通过以上命令我们可以获得,以秒为单位的视频时长。所以我们可以把视频时长分成十份,然后用这九个间隔所在的点作为截图点。

def get_point(length: str) -> list:
        length = int(float(length))
        interval = length / (10)
        time_list = []
        # 生成截图时间点
        for i in range(9):
            time_list.append(interval * (i + 1))
        return time_list

  既然截图的时间点已经得到,那么我们就可以利用这些时间点来进行截图了。不过如果仅仅是将截图简单地获取并输出,那么我们就无法区分各个截图之间的区别。所以我们可以通过FFmpeg的滤镜,在输出截图的同时将截图在视频中的时间点一并输出在截图上。

ffmpeg -start_at_zero -copyts -ss HH:MM:SS -i input \
    -vf "drawtext=fontfile=./Arial.ttf:fontsize=20:fontcolor=yellow:x=5:y=5:text='Time\\: %{{pts\\:hms}}'" \
    -vframes 1 output

  在这段代码中,使用到的-start_at_zero-copyts两个参数一般使用在视频截取中,保留原有的时间轴。-vf-filter:v,drawtext是视频滤镜的一种,用法可以查看这里。这里用以在图片左上角生成对应帧的时间戳。

import subprocess
import datetime
import shlex

def get_screenshot(video_name: str, time_list: list) -> list:
    # 注意请将对应的字体文件放置于视频目录,避免出错。此处使用的是Arial字体。
    ffmpeg_sh = '''ffmpeg -start_at_zero -copyts -ss {timestamp} -i {input} \
    -vf "drawtext=fontfile=./Arial.ttf:fontsize=20:fontcolor=yellow:x=5:y=5:text='Time\\: %{{pts\\:hms}}'" \
    -vframes 1 "{output}"'''
    thumb_list = []
    for i in time_list:
        time = str(datetime.timedelta(seconds=i))
        # 按现在时间生成截图名
        time_now = str(datetime.datetime.now().strftime("%Y%m%d_%H%M%S.%f"))  
        output_name = video_name + "_" + time_now
        cmd = ffmpeg_sh.format(timestamp=time, input=video_name, output=output_name)
        cmd = shlex.split(cmd)
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        
        thumb_list.append(output_name)
        while True:
            if p.poll() is not None:
                break
    
    return thumb_list

  通过以上代码我们就获取到了九张截图,以及九张截图的名字,接下来我们要做的就是将这九张截图组合成一张3*3的截图。

Comments are closed.