Jave 提取视频中的图片
本文档介绍如何使用 JAVE 库内置的 FFmpeg 功能来从视频中提取图片,并通过控制器将其整合到 Web 应用中。
使用 FFmpeg 命令提取图片
获取 FFmpeg 命令路径
JAVE 库内置了一个 DefaultFFMPEGLocator
类,该类在实例化时会将 FFmpeg 可执行文件复制到系统的临时文件夹中。通过该类可以获取 FFmpeg 可执行文件的路径,从而在程序中调用 FFmpeg。
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;
public class FfmpegPathExample {
public static void main(String[] args) {
// 创建一个locator对象
DefaultFFMPEGLocator locator = new DefaultFFMPEGLocator();
// 获取路径
String executablePath = locator.getExecutablePath();
// 示例输出路径:C:\Users\Administrator\AppData\Local\Temp\jave\ffmpeg-amd64-3.5.0.exe
System.out.println(executablePath);
}
}
调用 FFmpeg 命令提取图片
使用 FFmpeg 命令可以从视频中提取帧并保存为图片。以下代码展示了如何使用 FFmpeg 从视频中每秒提取一帧,并将这些帧保存到指定的输出目录中。
import java.io.File;
import java.io.IOException;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;
public class FrameExtractor {
public static void main(String[] args) {
File source = new File("input.mp4");
File outputDir = new File("output/");
outputDir.mkdirs(); // 创建输出目录
// 创建一个locator对象
DefaultFFMPEGLocator locator = new DefaultFFMPEGLocator();
try {
// 构建 FFmpeg 命令
String[] command = {
locator.getExecutablePath(),
"-i", source.getAbsolutePath(), // 输入视频文件
"-vf", "fps=1", // 每秒提取一帧
outputDir.getAbsolutePath() + "/frame%d.jpg" // 输出文件路径
};
// 执行 FFmpeg 命令
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
process.waitFor(); // 等待命令执行完成
System.out.println("Frames extracted successfully.");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("finish");
}
}
添加图片水印
在提取图片的同时,你可以通过使用 FFmpeg 的 drawtext
过滤器在图片上添加水印。以下代码展示了如何将帧编号作为水印添加到图片上。
import java.io.File;
import java.io.IOException;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;
public class FrameExtractorWithWatermark {
public static void main(String[] args) {
String filePath = "video.mp4";
File source = new File(filePath);
File outputDir = new File("output/");
outputDir.mkdirs(); // 创建输出目录
// 创建一个locator对象
DefaultFFMPEGLocator locator = new DefaultFFMPEGLocator();
try {
// 构建 FFmpeg 命令,添加水印
String[] command = {
locator.getExecutablePath(),
"-i", source.getAbsolutePath(), // 输入视频文件
"-vf", "fps=1,drawtext=text='%{n}':x=10:y=H-th-10:fontsize=50:fontcolor=red", // 添加帧号水印
outputDir.getAbsolutePath() + "/frame%d.jpg" // 输出文件路径
};
// 执行 FFmpeg 命令
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
process.waitFor(); // 等待命令执行完成
System.out.println("Frames extracted successfully with watermark.");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("finish");
}
}
- FFmpeg drawtext 过滤器:
drawtext=text='%{n}': 在图片上添加文本水印,%{n} 表示当前帧的编号。
x=10:y=H-th-10: 指定文本在图像上的位置,x=10 和 y=H-th-10 分别表示文本的左上角坐标。
fontsize=50: 指定字体大小为 50。
fontcolor=red: 指定字体颜色为白色。
2.ProcessBuilder:
使用 ProcessBuilder 来执行 FFmpeg 命令。
3.输出路径:
图片文件将保存在 output 目录下,文件名格式为 frame%d.jpg,其中 %d 表示帧号。
整合到 Controller 中
接下来,我们将上述功能整合到 Web 应用中,使用户可以通过上传视频文件来提取图片。
配置文件
首先,我们需要设置静态文件的访问路径。将静态文件的根目录设置为 pages
目录:
server.resources.static-locations = pages
可以通过以下代码获取页面的根路径:
String pageRoot = TioBootServer.me().getHttpConfig().getPageRoot();
编写 Controller
编写一个控制器来处理用户上传的文件,并调用 VideoService
来提取视频中的帧,最后返回生成的图片文件路径。
public HttpResponse frames(UploadFile file) {
HttpResponse response = TioRequestContext.getResponse();
String pageRoot = TioBootServer.me().getHttpConfig().getPageRoot();
if (file == null) {
response.setStatus(400);
response.setJson(RespBodyVo.fail("upload file is empty"));
return response;
}
String inputFolderName = "input";
String outputFolderName = pageRoot + File.separator + "output";
byte[] fileData = file.getData();
File inputFolder = new File(inputFolderName);
if (!inputFolder.exists()) {
inputFolder.mkdirs(); // 创建输入目录
}
File outputFolder = new File(outputFolderName);
if (!outputFolder.exists()) {
outputFolder.mkdirs(); // 创建输出目录
}
File source = new File(inputFolderName + "/" + file.getName());
FileUtil.writeBytes(fileData, source);
VideoService videoService = Aop.get(VideoService.class);
videoService.frames(outputFolder, source);
String[] filenames = outputFolder.list();
List<String> filePaths = new ArrayList<>(filenames.length);
for (String string : filenames) {
filePaths.add("/output/" + string);
}
return response.setJson(RespBodyVo.ok(filePaths));
}
编写 Service
VideoService
类用于封装帧提取的逻辑:
package com.litongjava.jave.server.service;
import java.io.File;
import java.io.IOException;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;
public class VideoService {
public void frames(File outputFolder, File source) {
// 创建一个locator对象
DefaultFFMPEGLocator locator = new DefaultFFMPEGLocator();
try {
// 构建 FFmpeg 命令,提取帧并添加水印
String[] command = {
locator.getExecutablePath(),
"-i", source.getAbsolutePath(), // 输入视频文件
"-vf", "fps=1,drawtext=text='%{n}':x=10:y=H-th-10:fontsize=50:fontcolor=red", // 添加帧号水印
outputFolder.getAbsolutePath() + "/frame_%d.jpg" // 输出文件路径
};
// 执行 FFmpeg 命令
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
process.waitFor(); // 等待命令执行完成
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
调用 Controller
调用上面定义的控制器后,将返回提取的图片路径,格式如下:
{
"data": ["/output/frame1.jpg", "/output/frame10.jpg", "/output/frame11.jpg"],
"ok": true,
"code": 1,
"msg": null
}
访问生成的图片
通过 Tio-boot 的静态资源处理器,用户可以访问生成的图片。访问地址格式如下:
http://localhost/output/frame1.jpg
总结
本文档详细介绍了如何使用 JAVE 内置的 FFmpeg 提取视频中的帧,并添加水印。我们还展示了如何将这一功能集成到 Web 应用中,通过控制器和服务类实现视频帧的提取和图片文件的访问。希望通过此文档,您可以更好地理解和实现类似的功能。