zhaowenyu
2025-11-19 e90d0fe42b652c9230c5e544d177dbedb3e57580
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java
@@ -17,16 +17,22 @@
import com.ard.work.service.IArdFlightTaskService;
import com.ard.work.service.IArdServerInfoService;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.net.ssl.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -62,7 +68,6 @@
    /**
     * 同步所有服务的飞行历史
     *
     */
    @Scheduled(fixedDelay = 10000)
    public void syncAllFlightHistory() {
@@ -162,21 +167,42 @@
    private void insertVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
        if (videoPathList != null && !videoPathList.isEmpty()) {
            for (String videoPath : videoPathList) {
                ArdMedia ardMedia =  ArdMedia.builder()
                ArdMedia ardMedia = ArdMedia.builder()
                        .id(IdUtils.simpleUUID())
                        .taskId(flightTask.getTaskId())
                        .mediaType(1) // 1表示视频
                        .sourceUrl(videoPath)
                        .fileSize(getFileSizeByUrl(videoPath))
                        .build();
                // 异步上传文件到OSS,并在上传完成后插入数据库
                CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), videoPath, "record1",
                                MimeTypeUtils.VIDEO_MP4), threadPoolTaskExecutor)
                        .thenAccept(url -> {
                            ardMedia.setMediaUrl(url);  // 获取上传后的文件 URL
                            ardMedia.setCreateTime(new Date());
                            ardMediaMapper.insertArdMedia(ardMedia);  // 插入数据库
                        });
                CompletableFuture.supplyAsync(() -> {
                    try {
                        // 上传视频
                        String videoUrl = uploadFileToOss(flightTask.getBoxSn(), videoPath, "record",
                                MimeTypeUtils.VIDEO_MP4);
                        ardMedia.setMediaUrl(videoUrl);
                        // 生成缩略图 InputStream
                        ByteArrayInputStream thumbnailStream = generateThumbnailInputStream(videoPath, 2, 200);
                        if (thumbnailStream != null) {
                            String thumbnailUrl = ossServiceContext.upload("record",
                                    flightTask.getBoxSn() + "/" + IdUtils.fastSimpleUUID() + ".jpg",
                                    thumbnailStream,
                                    MimeTypeUtils.IMAGE_JPEG);
                            ardMedia.setThumbnailUrl(thumbnailUrl);
                        }
                        ardMedia.setCreateTime(new Date());
                        return ardMedia;
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                }, threadPoolTaskExecutor).thenAccept(am -> {
                    if (am != null) {
                        ardMediaMapper.insertArdMedia(am);
                    }
                });
            }
        }
    }
@@ -203,30 +229,50 @@
            if (!newVideos.isEmpty()) {
                // 插入新的视频记录
                for (String videoPath : newVideos) {
                    ArdMedia ardMedia =  ArdMedia.builder()
                    ArdMedia ardMedia = ArdMedia.builder()
                            .id(IdUtils.simpleUUID())
                            .taskId(flightTask.getTaskId())
                            .mediaType(1) // 1表示视频
                            .fileSize(getFileSizeByUrl(videoPath))
                            .sourceUrl(videoPath)
                            .build();
                    // 异步上传文件到OSS,并在上传完成后插入数据库
                    CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), videoPath, "record1",
                                    MimeTypeUtils.VIDEO_MP4), threadPoolTaskExecutor)
                            .thenAccept(url -> {
                                ardMedia.setMediaUrl(url);  // 获取上传后的文件 URL
                                ardMedia.setCreateTime(new Date());
                                ardMediaMapper.insertArdMedia(ardMedia);  // 插入数据库
                            });
                }
                    CompletableFuture.supplyAsync(() -> {
                        try {
                            // 上传视频
                            String videoUrl = uploadFileToOss(flightTask.getBoxSn(), videoPath, "record",
                                    MimeTypeUtils.VIDEO_MP4);
                            ardMedia.setMediaUrl(videoUrl);
                            // 生成缩略图 InputStream
                            ByteArrayInputStream thumbnailStream = generateThumbnailInputStream(videoPath, 2, 200);
                            if (thumbnailStream != null) {
                                String thumbnailUrl = ossServiceContext.upload("record",
                                        flightTask.getBoxSn() + "/" + IdUtils.fastSimpleUUID() + ".jpg",
                                        thumbnailStream,
                                        MimeTypeUtils.IMAGE_JPEG);
                                ardMedia.setThumbnailUrl(thumbnailUrl);
                            }
                            ardMedia.setCreateTime(new Date());
                            return ardMedia;
                        } catch (Exception e) {
                            e.printStackTrace();
                            return null;
                        }
                    }, threadPoolTaskExecutor).thenAccept(am -> {
                        if (am != null) {
                            ardMediaMapper.insertArdMedia(am);
                        }
                    });
                }
                // 更新任务的视频数量
                flightTask.setVideoCount(flightTask.getVideoCount() + newVideos.size());
                ardFlightTaskMapper.updateArdFlightTask(flightTask);
            }
        }
    }
    // 插入图片记录
    private void insertPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
@@ -245,7 +291,7 @@
    private void updatePhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
        int count = flightTask.getPhotoCount(); //获取本地库图片数量
        // 查询图片
        BoxPhotosDTO boxPhotosDTO =  BoxPhotosDTO.builder()
        BoxPhotosDTO boxPhotosDTO = BoxPhotosDTO.builder()
                .taskId(flightTask.getTaskId())
                .boxSn(boxSn)
                .pageIndex(1)
@@ -296,7 +342,7 @@
                    .captureTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, photo.getTimeStamp()))
                    .build();
            // 异步上传文件到OSS,并在上传完成后插入数据库
            CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), photo.getImgUrl(), "pic1",
            CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), photo.getImgUrl(), "pic",
                            MimeTypeUtils.IMAGE_JPG), threadPoolTaskExecutor)
                    .thenAccept(url -> {
                        ardMedia.setMediaUrl(url);  // 获取上传后的文件 URL
@@ -337,12 +383,7 @@
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            // 创建所有主机名都信任的HostnameVerifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            HostnameVerifier allHostsValid = (hostname, session) -> true;
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            // 现在可以正常访问
@@ -374,7 +415,7 @@
        return fileOssUrl; // 返回上传后的文件OSS URL
    }
    //获取文件大小
    // 获取文件大小
    private long getFileSizeByUrl(String fileUrl) {
        try {
            URL url = new URL(fileUrl);
@@ -387,4 +428,69 @@
        }
    }
    // 生成视频缩略图
    public ByteArrayInputStream generateThumbnailInputStream(String videoFile,
                                                             int skipFrames,
                                                             int targetWidth) throws Exception {
        long start = System.currentTimeMillis();
        FFmpegFrameGrabber grabber = null;
        try {
            grabber = new FFmpegFrameGrabber(videoFile);
            grabber.start();
            int totalFrames = grabber.getLengthInFrames();
            System.out.println("视频总帧数: " + totalFrames);
            System.out.println("视频时长: " + grabber.getLengthInTime() / 1000000 + "秒");
            Frame frame = null;
            int currentFrame = 0;
            // 读取指定帧数后的第一帧有效图像
            while (currentFrame < totalFrames) {
                frame = grabber.grabImage();
                if (frame == null) {
                    break;
                }
                if (currentFrame > skipFrames && frame.image != null) {
                    break;
                }
                currentFrame++;
            }
            if (frame == null || frame.image == null) {
                throw new Exception("无法获取有效视频帧");
            }
            // 转换 Frame 为 BufferedImage
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage image = converter.getBufferedImage(frame);
            // 按目标宽度等比缩放
            int targetHeight = (int) ((double) targetWidth / image.getWidth() * image.getHeight());
            BufferedImage scaledImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_3BYTE_BGR);
            scaledImage.getGraphics().drawImage(image, 0, 0, targetWidth, targetHeight, null);
            // 转成 ByteArrayInputStream
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(scaledImage, "jpg", baos);
            long cost = System.currentTimeMillis() - start;
            System.out.println("处理耗时: " + cost + "ms");
            return new ByteArrayInputStream(baos.toByteArray());
        } finally {
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}