Skip to content

Commit

Permalink
优化视频封面的生成
Browse files Browse the repository at this point in the history
  • Loading branch information
jamebal committed Mar 27, 2024
1 parent f0af225 commit 391e8a7
Showing 1 changed file with 31 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jmal.clouddisk.service.video;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
Expand Down Expand Up @@ -134,7 +135,8 @@ public String getVideoCover(String fileId, String username, String relativePath,
videoPath = url.toString();
}
}
ProcessBuilder processBuilder = getVideoCoverProcessBuilder(videoPath, outputPath);
double videoDuration = getVideoInfo(videoPath).getDuration();
ProcessBuilder processBuilder = getVideoCoverProcessBuilder(videoPath, outputPath, videoDuration);
Process process = processBuilder.start();
int exitCode = process.waitFor();
if (exitCode == 0) {
Expand All @@ -154,18 +156,29 @@ public String getVideoCover(String fileId, String username, String relativePath,
return null;
}

private static ProcessBuilder getVideoCoverProcessBuilder(String videoPath, String outputPath) {
private static ProcessBuilder getVideoCoverProcessBuilder(String videoPath, String outputPath, double videoDuration) {
double targetTimestamp = videoDuration * 0.1;
String formattedTimestamp = formatTimestamp(targetTimestamp);
log.info("formattedTimestamp: {}", formattedTimestamp);
ProcessBuilder processBuilder = new ProcessBuilder(
Constants.FFMPEG,
"-ss", formattedTimestamp,
"-i", videoPath,
"-vf", "thumbnail,scale='min(320,iw)':-1",
"-vf", "scale='min(320,iw)':-1",
"-frames:v", "1",
outputPath
);
processBuilder.redirectErrorStream(true);
return processBuilder;
}

private static String formatTimestamp(double timestamp) {
int hours = (int) (timestamp / 3600);
int minutes = (int) ((timestamp % 3600) / 60);
double seconds = timestamp % 60;
return String.format("%02d:%02d:%.3f", hours, minutes, seconds);
}

/**
* 获取视频文件缓存目录
*
Expand Down Expand Up @@ -244,7 +257,7 @@ private void videoToM3U8(String fileId, String username, String relativePath, St
startConvert(username, relativePath, fileName, fileId);
pushMessage = true;
}
transcodingProgress(fileAbsolutePath, line);
transcodingProgress(fileAbsolutePath, videoInfo.getDuration(), line);
}
}
int exitCode = process.waitFor();
Expand All @@ -264,7 +277,7 @@ private void videoToM3U8(String fileId, String username, String relativePath, St
* @return 是否需要转码
*/
private boolean needTranscode(VideoInfo videoInfo) {
if (videoInfo.getBitrate() <= 2500 || videoInfo.getHeight() <= 720) {
if ((videoInfo.getBitrate() > 0 && videoInfo.getBitrate() <= 2000) || videoInfo.getHeight() <= 720) {
return !isSupportedFormat(videoInfo.getFormat());
}
return true;
Expand All @@ -290,11 +303,12 @@ private boolean isSupportedFormat(String format) {

/**
* 解析转码进度 0
*
* @param fileAbsolutePath 视频文件绝对路径
* @param line 命令输出信息
* @param videoDuration 视频时长
* @param line 命令输出信息
*/
private void transcodingProgress(Path fileAbsolutePath, String line) {
double videoDuration = getVideoDuration(fileAbsolutePath.toString());
private void transcodingProgress(Path fileAbsolutePath, double videoDuration, String line) {
// 解析转码进度
if (line.contains("time=")) {
try {
Expand Down Expand Up @@ -337,37 +351,6 @@ private static void printErrorInfo(ProcessBuilder processBuilder) {
processBuilder.command().forEach(command -> Console.log(command + " \\"));
}

/**
* 获取视频时长
* @param videoPath 视频路径
* @return 视频时长(秒)
*/
private double getVideoDuration(String videoPath) {
try {
ProcessBuilder processBuilder = new ProcessBuilder(
"ffprobe", "-v", "error", "-show_entries", "format=duration", "-of",
"default=noprint_wrappers=1:nokey=1", videoPath);
Process process = processBuilder.start();

try (InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String durationStr = reader.readLine();
if (durationStr != null) {
return Double.parseDouble(durationStr);
}
}

int exitCode = process.waitFor();
if (exitCode != 0) {
printErrorInfo(processBuilder);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return 0.0;
}


/**
* 获取视频的分辨率和码率信息
* @param videoPath 视频路径
Expand All @@ -387,14 +370,17 @@ private VideoInfo getVideoInfo(String videoPath) {
JSONObject formatObject = jsonObject.getJSONObject("format");
String format = formatObject.getString("format_name");

// 获取视频时长
double duration = Convert.toDouble(formatObject.get("duration"), 0d);

// 获取视频流信息
JSONArray streamsArray = jsonObject.getJSONArray("streams");
if (!streamsArray.isEmpty()) {
JSONObject streamObject = streamsArray.getJSONObject(0);
int width = streamObject.getIntValue("width");
int height = streamObject.getIntValue("height");
int bitrate = streamObject.getIntValue("bit_rate") / 1000; // 转换为 kbps
return new VideoInfo(width, height, format, bitrate);
return new VideoInfo(width, height, format, bitrate, duration);
}
}

Expand All @@ -415,18 +401,21 @@ private static class VideoInfo {
private int height;
private int bitrate;
private String format;
private double duration;
public VideoInfo() {
this.width = 1920;
this.height = 1080;
this.format = "mov,mp4,m4a,3gp,3g2,mj2";
this.bitrate = 3000;
this.duration = 10d;
}
public VideoInfo(int width, int height, String format, int bitrate) {
public VideoInfo(int width, int height, String format, int bitrate, double duration) {
this.width = width;
this.height = height;
this.format = format;
this.bitrate = bitrate;
log.info("width: {}, height: {}, format: {}, bitrate: {}", width, height, format, bitrate);
this.duration = duration;
log.info("width: {}, height: {}, format: {}, bitrate: {}, duration: {}", width, height, format, bitrate, duration);
}
}

Expand Down

0 comments on commit 391e8a7

Please sign in to comment.