From bcf8e8e88dc09637c2f4199b5ea63c6108700052 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Wed, 19 Mar 2025 16:57:33 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E5=85=B3=E8=81=94=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pc/device/entity/DeviceConfigEntity.java | 1 + .../com/ycwl/basic/task/VideoPieceGetter.java | 276 +++++++++++------- src/main/resources/mapper/DeviceMapper.xml | 3 +- 3 files changed, 167 insertions(+), 113 deletions(-) diff --git a/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceConfigEntity.java b/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceConfigEntity.java index 743c7ab..81374c4 100644 --- a/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceConfigEntity.java +++ b/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceConfigEntity.java @@ -60,4 +60,5 @@ public class DeviceConfigEntity { private Integer enablePreBook; private Integer imageFree; private Integer videoFree; + private Long pairDevice; } diff --git a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java index 53458b4..d90798d 100644 --- a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java +++ b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java @@ -6,6 +6,7 @@ import com.ycwl.basic.device.DeviceFactory; import com.ycwl.basic.device.entity.common.FileObject; import com.ycwl.basic.device.operator.IDeviceStorageOperator; import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity; +import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO; import com.ycwl.basic.repository.DeviceRepository; import com.ycwl.basic.mapper.FaceSampleMapper; import com.ycwl.basic.mapper.SourceMapper; @@ -20,6 +21,7 @@ import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.utils.SnowFlakeUtil; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; @@ -35,7 +37,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -117,6 +121,18 @@ public class VideoPieceGetter { final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 512, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(512)); List currentPlaceholder = new ArrayList<>(); List list = faceSampleMapper.listByIds(task.getFaceSampleIds()); + Map pairDeviceMap = new ConcurrentHashMap<>(); + if (!list.isEmpty()) { + Long scenicId = list.get(0).getScenicId(); + List allDeviceByScenicId = deviceRepository.getAllDeviceByScenicId(scenicId); + allDeviceByScenicId.forEach(device -> { + Long deviceId = device.getId(); + DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(deviceId); + if (deviceConfig != null && deviceConfig.getPairDevice() != null) { + pairDeviceMap.putIfAbsent(deviceId, deviceConfig.getPairDevice()); + } + }); + } Collection> collection = list.stream() .filter(faceSample -> { if (templatePlaceholder != null) { @@ -136,123 +152,45 @@ public class VideoPieceGetter { } catch (InterruptedException ignore) { } } + if (pairDeviceMap.containsValue(faceSample.getDeviceId())) { + // 有关联设备! + // 找到对应的deviceId + pairDeviceMap.entrySet().stream() + .filter(entry -> entry.getValue().equals(faceSample.getDeviceId())) + .map(Map.Entry::getKey).forEach(pairDeviceId -> { + log.info("找到同景区关联设备:{} -> {}", pairDeviceId, faceSample.getDeviceId()); + if (pairDeviceId != null) { + executor.execute(() -> { + boolean result = doCut(pairDeviceId, faceSample.getId(), faceSample.getCreateAt(), task); + if (templatePlaceholder != null) { + if (templatePlaceholder.contains(faceSample.getDeviceId().toString())) { + if (!currentPlaceholder.contains(faceSample.getDeviceId().toString())) { + if (result) { + currentPlaceholder.add(faceSample.getDeviceId().toString()); + } + } + } + log.info("当前进度:{}/{}", currentPlaceholder.size(), collection.size()); + if (currentPlaceholder.size() >= collection.size()) { + if (!invoke.get()) { + invoke.set(true); + task.getCallback().onInvoke(); + } + } + } + }); + } + }); + } isFirst.set(false); executor.execute(() -> { - DeviceEntity device = deviceRepository.getDevice(faceSample.getDeviceId()); - DeviceConfigEntity config = deviceRepository.getDeviceConfig(faceSample.getDeviceId()); - - SourceEntity source = sourceMapper.querySameVideo(faceSample.getId(), device.getId()); - - if (source == null) { - BigDecimal cutPre = BigDecimal.valueOf(5L); - BigDecimal cutPost = BigDecimal.valueOf(4L); - if (config == null) { - return; - } - // 有配置 - if (config.getCutPre() != null) { - cutPre = config.getCutPre(); - } - if (config.getCutPost() != null) { - cutPost = config.getCutPost(); - } - IDeviceStorageOperator pieceGetter = DeviceFactory.getDeviceStorageOperator(device, config); - if (pieceGetter == null) { - return; - } - BigDecimal duration = cutPre.add(cutPost); - List listByDtRange = pieceGetter.getFileListByDtRange( - new Date(faceSample.getCreateAt().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue()), - new Date(faceSample.getCreateAt().getTime() + cutPost.multiply(BigDecimal.valueOf(1000)).longValue()) - ); - if (listByDtRange.isEmpty()) { - log.warn("没有可用的文件"); - return; - } - log.info("查询到可用的文件: {}", listByDtRange); - // 如果完全一致,就不需要裁切 - String url; - if (listByDtRange.size() == 1 && listByDtRange.get(0).isExact()) { - url = listByDtRange.get(0).getUrl(); - } else { - long offset = faceSample.getCreateAt().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue() - listByDtRange.get(0).getCreateTime().getTime(); - FfmpegTask ffmpegTask = new FfmpegTask(); - ffmpegTask.setFileList(listByDtRange); - ffmpegTask.setDuration(duration); - ffmpegTask.setOffsetStart(BigDecimal.valueOf(offset, 3)); - File outFile = new File(faceSample.getDeviceId().toString() + "_" + faceSample.getId() + ".mp4"); - ffmpegTask.setOutputFile(outFile.getAbsolutePath()); - boolean result = startFfmpegTask(ffmpegTask); - if (!result) { - log.warn("视频裁切失败"); - return; - } - log.info("视频裁切成功"); - IStorageAdapter adapter = StorageFactory.use("assets"); - url = adapter.uploadFile(outFile, "video-source", outFile.getName()); - // 上传成功后删除文件 - outFile.delete(); - } - SourceEntity imgSource = sourceMapper.findBySampleId(faceSample.getId()); - SourceEntity sourceEntity = new SourceEntity(); - sourceEntity.setId(SnowFlakeUtil.getLongId()); - sourceEntity.setCreateTime(faceSample.getCreateAt()); - if (imgSource != null) { - sourceEntity.setUrl(imgSource.getUrl()); - sourceEntity.setPosJson(imgSource.getPosJson()); - } - sourceEntity.setVideoUrl(url); - sourceEntity.setFaceSampleId(faceSample.getId()); - sourceEntity.setScenicId(faceSample.getScenicId()); - sourceEntity.setDeviceId(faceSample.getDeviceId()); - sourceEntity.setType(1); - if (task.memberId != null && task.faceId != null) { - MemberSourceEntity videoSource = new MemberSourceEntity(); - videoSource.setMemberId(task.getMemberId()); - videoSource.setType(1); - videoSource.setFaceId(task.getFaceId()); - videoSource.setScenicId(faceSample.getScenicId()); - videoSource.setSourceId(sourceEntity.getId()); - IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), faceSample.getScenicId(), 1, task.getFaceId()); - if (isBuy.isBuy()) { // 如果用户买过 - videoSource.setIsBuy(1); - } else if (isBuy.isFree()) { // 全免费逻辑 - videoSource.setIsBuy(1); - } else { - videoSource.setIsBuy(0); - } - sourceMapper.addRelation(videoSource); - } - sourceMapper.add(sourceEntity); - } else { - // 有原视频 - if (task.memberId != null && task.faceId != null) { - int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1); - if (count <= 0) { - // 没有关联 - IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), faceSample.getScenicId(), 1, task.getFaceId()); - MemberSourceEntity videoSource = new MemberSourceEntity(); - videoSource.setId(SnowFlakeUtil.getLongId()); - videoSource.setScenicId(faceSample.getScenicId()); - videoSource.setFaceId(task.getFaceId()); - videoSource.setMemberId(task.getMemberId()); - videoSource.setType(1); - if (isBuy.isBuy()) { // 如果用户买过 - videoSource.setIsBuy(1); - } else if (isBuy.isFree()) { // 全免费逻辑 - videoSource.setIsBuy(1); - } else { - videoSource.setIsBuy(0); - } - videoSource.setSourceId(source.getId()); - sourceMapper.addRelation(videoSource); - } - } - } + boolean result = doCut(faceSample.getDeviceId(), faceSample.getId(), faceSample.getCreateAt(), task); if (templatePlaceholder != null) { if (templatePlaceholder.contains(faceSample.getDeviceId().toString())) { if (!currentPlaceholder.contains(faceSample.getDeviceId().toString())) { - currentPlaceholder.add(faceSample.getDeviceId().toString()); + if (result) { + currentPlaceholder.add(faceSample.getDeviceId().toString()); + } } } log.info("当前进度:{}/{}", currentPlaceholder.size(), collection.size()); @@ -288,6 +226,120 @@ public class VideoPieceGetter { } } + private boolean doCut(Long deviceId, Long faceSampleId, Date baseTime, Task task) { + DeviceEntity device = deviceRepository.getDevice(deviceId); + DeviceConfigEntity config = deviceRepository.getDeviceConfig(deviceId); + + SourceEntity source = sourceMapper.querySameVideo(faceSampleId, device.getId()); + + if (source == null) { + BigDecimal cutPre = BigDecimal.valueOf(5L); + BigDecimal cutPost = BigDecimal.valueOf(4L); + if (config != null) { + // 有配置 + if (config.getCutPre() != null) { + cutPre = config.getCutPre(); + } + if (config.getCutPost() != null) { + cutPost = config.getCutPost(); + } + } + IDeviceStorageOperator pieceGetter = DeviceFactory.getDeviceStorageOperator(device, config); + if (pieceGetter == null) { + return false; + } + BigDecimal duration = cutPre.add(cutPost); + List listByDtRange = pieceGetter.getFileListByDtRange( + new Date(baseTime.getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue()), + new Date(baseTime.getTime() + cutPost.multiply(BigDecimal.valueOf(1000)).longValue()) + ); + if (listByDtRange.isEmpty()) { + log.warn("没有可用的文件"); + return false; + } + log.info("查询到可用的文件: {}", listByDtRange); + // 如果完全一致,就不需要裁切 + String url; + if (listByDtRange.size() == 1 && listByDtRange.get(0).isExact()) { + url = listByDtRange.get(0).getUrl(); + } else { + long offset = baseTime.getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue() - listByDtRange.get(0).getCreateTime().getTime(); + FfmpegTask ffmpegTask = new FfmpegTask(); + ffmpegTask.setFileList(listByDtRange); + ffmpegTask.setDuration(duration); + ffmpegTask.setOffsetStart(BigDecimal.valueOf(offset, 3)); + File outFile = new File(deviceId.toString() + "_" + faceSampleId + ".mp4"); + ffmpegTask.setOutputFile(outFile.getAbsolutePath()); + boolean result = startFfmpegTask(ffmpegTask); + if (!result) { + log.warn("视频裁切失败"); + return false; + } + log.info("视频裁切成功"); + IStorageAdapter adapter = StorageFactory.use("assets"); + url = adapter.uploadFile(outFile, "video-source", outFile.getName()); + // 上传成功后删除文件 + outFile.delete(); + } + SourceEntity imgSource = sourceMapper.findBySampleId(faceSampleId); + SourceEntity sourceEntity = new SourceEntity(); + sourceEntity.setId(SnowFlakeUtil.getLongId()); + sourceEntity.setCreateTime(baseTime); + if (imgSource != null) { + sourceEntity.setUrl(imgSource.getUrl()); + sourceEntity.setPosJson(imgSource.getPosJson()); + } + sourceEntity.setVideoUrl(url); + sourceEntity.setFaceSampleId(faceSampleId); + sourceEntity.setScenicId(device.getScenicId()); + sourceEntity.setDeviceId(deviceId); + sourceEntity.setType(1); + if (task.memberId != null && task.faceId != null) { + MemberSourceEntity videoSource = new MemberSourceEntity(); + videoSource.setMemberId(task.getMemberId()); + videoSource.setType(1); + videoSource.setFaceId(task.getFaceId()); + videoSource.setScenicId(device.getScenicId()); + videoSource.setSourceId(sourceEntity.getId()); + IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), device.getScenicId(), 1, task.getFaceId()); + if (isBuy.isBuy()) { // 如果用户买过 + videoSource.setIsBuy(1); + } else if (isBuy.isFree()) { // 全免费逻辑 + videoSource.setIsBuy(1); + } else { + videoSource.setIsBuy(0); + } + sourceMapper.addRelation(videoSource); + } + sourceMapper.add(sourceEntity); + } else { + // 有原视频 + if (task.memberId != null && task.faceId != null) { + int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1); + if (count <= 0) { + // 没有关联 + IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), device.getScenicId(), 1, task.getFaceId()); + MemberSourceEntity videoSource = new MemberSourceEntity(); + videoSource.setId(SnowFlakeUtil.getLongId()); + videoSource.setScenicId(device.getScenicId()); + videoSource.setFaceId(task.getFaceId()); + videoSource.setMemberId(task.getMemberId()); + videoSource.setType(1); + if (isBuy.isBuy()) { // 如果用户买过 + videoSource.setIsBuy(1); + } else if (isBuy.isFree()) { // 全免费逻辑 + videoSource.setIsBuy(1); + } else { + videoSource.setIsBuy(0); + } + videoSource.setSourceId(source.getId()); + sourceMapper.addRelation(videoSource); + } + } + } + return true; + } + public boolean startFfmpegTask(FfmpegTask task) { boolean result; if (task.getFileList().size() == 1) { diff --git a/src/main/resources/mapper/DeviceMapper.xml b/src/main/resources/mapper/DeviceMapper.xml index 2c3333e..c586bcc 100644 --- a/src/main/resources/mapper/DeviceMapper.xml +++ b/src/main/resources/mapper/DeviceMapper.xml @@ -39,7 +39,8 @@ cut_post = #{cutPost}, enable_pre_book = #{enablePreBook}, image_free = #{imageFree}, - video_free = #{videoFree} + video_free = #{videoFree}, + pair_device = #{pairDevice} where id = #{id}