要从ffmpeg输出单个帧,我可以执行以下操作:
ffmpeg -i input.flv -ss 00:00:14.435 -vframes 1 out.png
要每秒输出一张图像,我可以:
ffmpeg -i input.flv -vf fps=1 out%d.png
是否有一种方法可以从这些输出创建一个缩略图精灵,以帮助创建一个vtt文件的拇指在寻找位置?
tjjdgumg1#
下面的示例使用ffmpeg从mp4视频创建jpeg文件(280x180),然后使用PHP gd2 +为视频播放器编写VTT文件将这些缩略图组装成sprite(png格式)。首先使用ffmpeg每秒创建1张图像:
ffmpeg -i sprite/MyVideoFile.mp4 -r 1 -s 280x180 -f image2 sprite/thumbs/thumb-%%d.jpg
然后创建sprite文件+ vtt文件(例如PHP):
$dirToScan = 'thumbs/'; $filePrefix = 'thumb-'; $fileSuffix = '.jpg'; $thumbWidth = 280; $thumbHeight = 180; $imageFiles = array(); $spriteFile = 'sprite.png'; $imageLine = 20; $vttFile = 'sprite.vtt'; $dst_x = 0; $dst_y = 0; # read the directory with thumbnails, file name in array foreach (glob($dirToScan.$filePrefix.'*'.$fileSuffix) as $filename) { array_push($imageFiles,$filename); } natsort($imageFiles); #calculate dimension for the sprite $spriteWidth = $thumbWidth*$imageLine; $spriteHeight = $thumbHeight*(floor(count($imageFiles)/$imageLine)+1); # create png file for sprite $png = imagecreatetruecolor($spriteWidth,$spriteHeight); # open vtt file $handle = fopen($vttFile,'wb+'); fwrite($handle,'WEBVTT'."\n"); # insert thumbs in sprite and write the vtt file foreach($imageFiles AS $file) { $counter = str_replace($filePrefix,'',str_replace($fileSuffix,'',str_replace($dirToScan,'',$file))); $imageSrc = imagecreatefromjpeg($file); imagecopyresized ($png, $imageSrc, $dst_x , $dst_y , 0, 0, $thumbWidth, $thumbHeight, $thumbWidth,$thumbHeight); $varTCstart = gmdate("H:i:s", $counter-1).'.000'; $varTCend = gmdate("H:i:s", $counter).'.000'; $varSprite = $spriteFile.'#xywh='.$dst_x.','.$dst_y.','.$thumbWidth.','.$thumbHeight; fwrite($handle,$counter."\n".$varTCstart.' --> '.$varTCend."\n".$varSprite."\n\n"); create new line after 20 images if ($counter % $imageLine == 0) { $dst_x=0; $dst_y+=$thumbHeight; } else { $dst_x+=$thumbWidth; } } imagepng($png,$spriteFile); fclose($handle);
VTT文件如下所示:
WEBVTT 1 00:00:00.000 --> 00:00:01.000 sprite.png#xywh=0,0,280,180 2 00:00:01.000 --> 00:00:02.000 sprite.png#xywh=280,0,280,180 3 00:00:02.000 --> 00:00:03.000 sprite.png#xywh=560,0,280,180 ...
pprl5pva2#
我不完全确定你需要/意味着什么与sprite的vtt文件,但有一个很好的工具,让你把单个图像组合成一个大的概览图片:ImageMagick附带了一个名为montage的方便工具蒙太奇-通过组合几个独立的图像来创建一个合成图像。2这些图像平铺在合成图像上,可以选择用边框、框架、图像名称等进行装饰。您可以使用以下命令将缩略图放在一个或多个图像上:
montage
montage *.png -tile 4x4 overview.png
它会自动生成所需的图片数量,给予你一个概览。
xpcnnkqh3#
对answer given by MR_1204的一点改进建议:如果最后的sprite是PNG,我会避免JPG压缩导致的质量下降,而是将临时缩略图保存为PNG:
ffmpeg -i sprite/MyVideoFile.mp4 -r 1 -s 280x180 -f image2 sprite/thumbs/thumb-%%d.png
此外,保存到PNG通常比保存到JPG快(很小)一点点。相反,为了保持下载量小,(仅)将最终的sprite图像保存为JPG可能是有意义的,在PHP和GD的情况下,只需要将imagepng(...)替换为imagejpeg(...)。
jobtbby34#
MR_1204的Python解决方案
import ffmpeg import logging from pathlib import Path from config import temp import os from PIL import Image from datetime import datetime, timedelta import math logger = logging.getLogger(__name__) class ScreenshotExtractor: def __init__(self): self.screenshot_folder = f"{temp}ss" self.gap = 10 self.size = "177x100" self.col = 5 self.ss_width = 177 self.ss_height = 100 def create_sprite_sheet(self, name): path, dirs, files = next(os.walk(self.screenshot_folder)) file_count = len(files) img_width = self.ss_width * self.col img_height = self.ss_height * math.ceil(file_count/self.col) file_name = f"{name}.jpg" out_image = Image.new('RGB', (img_width, img_height)) webvtt = "WEBVTT\n\n" for count, img_file in enumerate(files): img = Image.open(f"{self.screenshot_folder}/{img_file}") st_time = timedelta(seconds=count * self.gap) end_time = timedelta(seconds=(count + 1) * self.gap) # Adding img to out_file x_mod = int(count / self.col) x = 0 + (count - (self.col * x_mod)) * self.ss_width y = 0 + x_mod * self.ss_height out_image.paste(img, (x, y)) sprite = f"{file_name}#xywh={x},{y},{self.ss_width},{self.ss_height}" webvtt += f"{count + 1}\n0{str(st_time)}.000 --> 0{str(end_time)}.000\n{sprite}\n\n" out_image.save(f"{temp}{file_name}", quality=90) f = open(f"{temp}{name}.vtt", "w") f.write(webvtt) f.close() return True def extract_screenshots(self, file_uri, name): try: Path(self.screenshot_folder).mkdir(parents=True, exist_ok=True) vod = ffmpeg.input(file_uri) vod.output(f"{self.screenshot_folder}/{name}_%04d.png", r=1/self.gap, s=self.size).run() return True except Exception as e: logger.warning(e) return False def run(self, file_uri, name): # TODO - Actually do logic here self.extract_screenshots(file_uri, name) self.create_sprite_sheet(name)
希望这能帮助到一些人
6pp0gazn5#
所有这些解决方案对我来说都过于复杂了,你唯一需要的是视频输入的帧率和持续时间(ffprobe),简单地做以下的例子(python):
sprites_output = str(job['output_dir'] + '/' + 'sprites.webp') tile_rows = math.ceil(job["duration"] / 100) frame_modulus = math.ceil(float(job["video"][0]["frame_rate"]) * 10) # Create sprites command_string = f'{options["path_ffmpeg"]} -i "{job["input"]}" -vf "select=not(mod(n\,{frame_modulus})),scale=192:108,tile=10x{tile_rows}" "{sprites_output}"' task_command = subprocess.Popen(command_string, shell=True, stdout=subprocess.PIPE) task_command.wait()
这将给予你一个新的帧每10秒跨越宽度的10张图片,所有打包成一个webp文件。如果你想要一个不同的格式,只需改变输出扩展名,ffmpeg将为你处理。此外,这比任何python脚本快得多。
5条答案
按热度按时间tjjdgumg1#
下面的示例使用ffmpeg从mp4视频创建jpeg文件(280x180),然后使用PHP gd2 +为视频播放器编写VTT文件将这些缩略图组装成sprite(png格式)。
首先使用ffmpeg每秒创建1张图像:
然后创建sprite文件+ vtt文件(例如PHP):
VTT文件如下所示:
pprl5pva2#
我不完全确定你需要/意味着什么与sprite的vtt文件,但有一个很好的工具,让你把单个图像组合成一个大的概览图片:
ImageMagick附带了一个名为
montage
的方便工具蒙太奇-通过组合几个独立的图像来创建一个合成图像。2这些图像平铺在合成图像上,可以选择用边框、框架、图像名称等进行装饰。
您可以使用以下命令将缩略图放在一个或多个图像上:
它会自动生成所需的图片数量,给予你一个概览。
xpcnnkqh3#
对answer given by MR_1204的一点改进建议:如果最后的sprite是PNG,我会避免JPG压缩导致的质量下降,而是将临时缩略图保存为PNG:
此外,保存到PNG通常比保存到JPG快(很小)一点点。
相反,为了保持下载量小,(仅)将最终的sprite图像保存为JPG可能是有意义的,在PHP和GD的情况下,只需要将imagepng(...)替换为imagejpeg(...)。
jobtbby34#
MR_1204的Python解决方案
希望这能帮助到一些人
6pp0gazn5#
所有这些解决方案对我来说都过于复杂了,你唯一需要的是视频输入的帧率和持续时间(ffprobe),简单地做以下的例子(python):
这将给予你一个新的帧每10秒跨越宽度的10张图片,所有打包成一个webp文件。如果你想要一个不同的格式,只需改变输出扩展名,ffmpeg将为你处理。此外,这比任何python脚本快得多。