add AttachmentVariant
This commit is contained in:
@@ -7,36 +7,58 @@ import org.bytedeco.javacv.Java2DFrameConverter;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2025-10-23 17:05
|
||||
*/
|
||||
/// JavaCV 工具类
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2025-10-23 17:05
|
||||
public class JavaCV {
|
||||
|
||||
public static ByteArrayOutputStream captureThumbnail(InputStream stream, double targetSeconds) throws Exception {
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(stream)) {
|
||||
grabber.start();
|
||||
long targetMillis = (long) (targetSeconds * 1000);
|
||||
grabber.setTimestamp(targetMillis);
|
||||
Frame frame;
|
||||
while ((frame = grabber.grabImage()) != null) {
|
||||
if (grabber.getTimestamp() >= targetMillis) {
|
||||
Java2DFrameConverter converter = new Java2DFrameConverter();
|
||||
try (converter) {
|
||||
BufferedImage bi = converter.getBufferedImage(frame);
|
||||
if (bi != null) {
|
||||
ImageIO.write(bi, "png", outStream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return outStream;
|
||||
}
|
||||
/// 从视频流顺序解码并提取指定时间附近的一帧 PNG 图片
|
||||
///
|
||||
/// 不执行时间定位,避免为了取实时缩略图而把整个视频复制到临时文件
|
||||
///
|
||||
/// @param stream 视频输入流
|
||||
/// @param targetSeconds 目标时间,单位为秒
|
||||
/// @return PNG 图片字节流
|
||||
/// @throws Exception 视频解析或取帧失败
|
||||
public static ByteArrayOutputStream captureThumbnail(InputStream stream, double targetSeconds) throws Exception {
|
||||
long targetMicros = toMicros(targetSeconds);
|
||||
ByteArrayOutputStream firstFrame = new ByteArrayOutputStream();
|
||||
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(stream)) {
|
||||
grabber.start();
|
||||
try (Java2DFrameConverter converter = new Java2DFrameConverter()) {
|
||||
Frame frame;
|
||||
while ((frame = grabber.grabImage()) != null) {
|
||||
BufferedImage image = converter.getBufferedImage(frame);
|
||||
if (image == null) {
|
||||
continue;
|
||||
}
|
||||
if (!(0 < firstFrame.size())) {
|
||||
firstFrame = toPng(image);
|
||||
}
|
||||
if (grabber.getTimestamp() >= targetMicros) {
|
||||
return targetMicros == 0 ? firstFrame : toPng(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 短视频提前结束时退回首个有效帧
|
||||
return firstFrame;
|
||||
}
|
||||
|
||||
private static long toMicros(double targetSeconds) {
|
||||
double seconds = Double.isFinite(targetSeconds) ? Math.max(0, targetSeconds) : 0;
|
||||
return Math.round(seconds * 1_000_000D);
|
||||
}
|
||||
|
||||
private static ByteArrayOutputStream toPng(BufferedImage image) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
if (ImageIO.write(image, "png", output)) {
|
||||
return output;
|
||||
}
|
||||
return new ByteArrayOutputStream();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user