1111
This commit is contained in:
parent
1923a5c438
commit
f8d4665c59
@ -0,0 +1,69 @@
|
|||||||
|
package com.ycwl.basic.device.repository;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.ycwl.basic.mapper.DeviceMapper;
|
||||||
|
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||||
|
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||||
|
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DeviceRepository {
|
||||||
|
@Autowired
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
|
|
||||||
|
public static final String DEVICE_CACHE_KEY = "device:%s";
|
||||||
|
public static final String DEVICE_CONFIG_CACHE_KEY = "device:%s:config";
|
||||||
|
|
||||||
|
public DeviceEntity getDevice(Long deviceId) {
|
||||||
|
if (redisTemplate.hasKey(String.format(DEVICE_CACHE_KEY, deviceId))) {
|
||||||
|
return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(DEVICE_CACHE_KEY, deviceId)), DeviceEntity.class);
|
||||||
|
}
|
||||||
|
DeviceEntity device = deviceMapper.getByDeviceId(deviceId);
|
||||||
|
if (null != device) {
|
||||||
|
redisTemplate.opsForValue().set(String.format(DEVICE_CACHE_KEY, deviceId), JSONObject.toJSONString(device));
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceEntity getDeviceByDeviceNo(String deviceNo) {
|
||||||
|
if (redisTemplate.hasKey(String.format(DEVICE_CACHE_KEY, deviceNo))) {
|
||||||
|
return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(DEVICE_CACHE_KEY, deviceNo)), DeviceEntity.class);
|
||||||
|
}
|
||||||
|
DeviceEntity device = deviceMapper.getByDeviceNo(deviceNo);
|
||||||
|
if (null != device) {
|
||||||
|
redisTemplate.opsForValue().set(String.format(DEVICE_CACHE_KEY, deviceNo), JSONObject.toJSONString(device));
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceConfigEntity getDeviceConfig(Long deviceId) {
|
||||||
|
if (redisTemplate.hasKey(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId))) {
|
||||||
|
return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId)), DeviceConfigEntity.class);
|
||||||
|
}
|
||||||
|
DeviceConfigEntity deviceConfig = deviceMapper.getConfigByDeviceId(deviceId);
|
||||||
|
if (null == deviceConfig) {
|
||||||
|
deviceConfig = new DeviceConfigEntity();
|
||||||
|
deviceConfig.setId(SnowFlakeUtil.getLongId());
|
||||||
|
deviceConfig.setDeviceId(deviceId);
|
||||||
|
deviceMapper.addConfig(deviceConfig);
|
||||||
|
}
|
||||||
|
redisTemplate.opsForValue().set(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId), JSONObject.toJSONString(deviceConfig));
|
||||||
|
return deviceConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean clearDeviceCache(Long deviceId) {
|
||||||
|
if (redisTemplate.hasKey(String.format(DEVICE_CACHE_KEY, deviceId))) {
|
||||||
|
DeviceEntity device = getDevice(deviceId);
|
||||||
|
redisTemplate.delete(String.format(DEVICE_CACHE_KEY, device.getNo()));
|
||||||
|
redisTemplate.delete(String.format(DEVICE_CONFIG_CACHE_KEY, device.getNo()));
|
||||||
|
}
|
||||||
|
redisTemplate.delete(String.format(DEVICE_CACHE_KEY, deviceId));
|
||||||
|
redisTemplate.delete(String.format(DEVICE_CONFIG_CACHE_KEY, deviceId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.ycwl.basic.service.impl.pc;
|
|||||||
|
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
|
import com.ycwl.basic.device.repository.DeviceRepository;
|
||||||
import com.ycwl.basic.mapper.DeviceMapper;
|
import com.ycwl.basic.mapper.DeviceMapper;
|
||||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||||
import com.ycwl.basic.model.pc.device.req.DeviceAddOrUpdateReq;
|
import com.ycwl.basic.model.pc.device.req.DeviceAddOrUpdateReq;
|
||||||
@ -24,6 +25,8 @@ import java.util.List;
|
|||||||
public class DeviceServiceImpl implements DeviceService {
|
public class DeviceServiceImpl implements DeviceService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeviceMapper deviceMapper;
|
private DeviceMapper deviceMapper;
|
||||||
|
@Autowired
|
||||||
|
private DeviceRepository deviceRepository;
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<PageInfo<DeviceRespVO>> pageQuery(DeviceReqQuery deviceReqQuery) {
|
public ApiResponse<PageInfo<DeviceRespVO>> pageQuery(DeviceReqQuery deviceReqQuery) {
|
||||||
PageHelper.startPage(deviceReqQuery.getPageNum(), deviceReqQuery.getPageSize());
|
PageHelper.startPage(deviceReqQuery.getPageNum(), deviceReqQuery.getPageSize());
|
||||||
@ -53,7 +56,10 @@ public class DeviceServiceImpl implements DeviceService {
|
|||||||
deviceReqQuery.setStatus(0);
|
deviceReqQuery.setStatus(0);
|
||||||
return ApiResponse.success(deviceMapper.add(deviceReqQuery));
|
return ApiResponse.success(deviceMapper.add(deviceReqQuery));
|
||||||
} else {
|
} else {
|
||||||
return ApiResponse.success(deviceMapper.update(deviceReqQuery));
|
deviceRepository.clearDeviceCache(deviceReqQuery.getId());
|
||||||
|
deviceMapper.update(deviceReqQuery);
|
||||||
|
deviceRepository.clearDeviceCache(deviceReqQuery.getId());
|
||||||
|
return ApiResponse.success(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,14 +202,11 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
return memberSourceEntity;
|
return memberSourceEntity;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
sourceMapper.addRelations(memberSourceEntityList);
|
sourceMapper.addRelations(memberSourceEntityList);
|
||||||
List<FaceSampleRespVO> faceSampleList = faceSampleMapper.listByIds(sampleListIds);
|
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
||||||
for (FaceSampleRespVO sampleRespVO : faceSampleList) {
|
task.faceId = faceEntity.getId();
|
||||||
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
task.faceSampleId = sampleListIds;
|
||||||
task.faceId = faceEntity.getId();
|
task.memberId = userId;
|
||||||
task.faceSampleId = sampleRespVO.getId();
|
VideoPieceGetter.addTask(task);
|
||||||
task.memberId = userId;
|
|
||||||
VideoPieceGetter.addTask(task);
|
|
||||||
}
|
|
||||||
taskTaskService.autoCreateTaskByFaceId(faceEntity.getId());
|
taskTaskService.autoCreateTaskByFaceId(faceEntity.getId());
|
||||||
StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
|
StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
|
||||||
statisticsRecordAddReq.setMemberId(userId);
|
statisticsRecordAddReq.setMemberId(userId);
|
||||||
|
@ -224,7 +224,8 @@ public class TaskTaskServiceImpl implements TaskService {
|
|||||||
if (faceSampleList.isEmpty()) {
|
if (faceSampleList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<SourceEntity> sourceList = sourceMapper.listBySampleIds(faceSampleList.stream().map(FaceSampleRespVO::getId).collect(Collectors.toList()));
|
List<Long> faceSampleIds = faceSampleList.stream().map(FaceSampleRespVO::getId).collect(Collectors.toList());
|
||||||
|
List<SourceEntity> sourceList = sourceMapper.listBySampleIds(faceSampleIds);
|
||||||
if (sourceList.isEmpty()) {
|
if (sourceList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -237,16 +238,10 @@ public class TaskTaskServiceImpl implements TaskService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
faceSampleList.stream().map(sample -> {
|
|
||||||
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
|
||||||
task.setFaceSampleId(sample.getId());
|
|
||||||
task.setMemberId(faceRespVO.getMemberId());
|
|
||||||
return task;
|
|
||||||
}).forEach(VideoPieceGetter::addTask);
|
|
||||||
|
|
||||||
|
|
||||||
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
||||||
task.type = "callback";
|
task.faceId = faceId;
|
||||||
|
task.faceSampleId = faceSampleIds;
|
||||||
|
task.memberId = faceRespVO.getMemberId();
|
||||||
task.callback = () -> {
|
task.callback = () -> {
|
||||||
List<SourceEntity> videoSourceList = sourceMapper.listVideoByFaceRelation(faceId);
|
List<SourceEntity> videoSourceList = sourceMapper.listVideoByFaceRelation(faceId);
|
||||||
Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
|
Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
|
||||||
|
@ -3,6 +3,7 @@ package com.ycwl.basic.task;
|
|||||||
import com.ycwl.basic.device.DeviceFactory;
|
import com.ycwl.basic.device.DeviceFactory;
|
||||||
import com.ycwl.basic.device.entity.common.FileObject;
|
import com.ycwl.basic.device.entity.common.FileObject;
|
||||||
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
|
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
|
||||||
|
import com.ycwl.basic.device.repository.DeviceRepository;
|
||||||
import com.ycwl.basic.mapper.DeviceMapper;
|
import com.ycwl.basic.mapper.DeviceMapper;
|
||||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||||
import com.ycwl.basic.mapper.SourceMapper;
|
import com.ycwl.basic.mapper.SourceMapper;
|
||||||
@ -47,12 +48,14 @@ public class VideoPieceGetter {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DeviceMapper deviceMapper;
|
private DeviceMapper deviceMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private DeviceRepository deviceRepository;
|
||||||
|
@Autowired
|
||||||
private SourceMapper sourceMapper;
|
private SourceMapper sourceMapper;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class Task {
|
public static class Task {
|
||||||
public String type = "normal";
|
public String type = "normal";
|
||||||
public Long faceSampleId;
|
public List<Long> faceSampleId;
|
||||||
public Callback callback;
|
public Callback callback;
|
||||||
public Long memberId;
|
public Long memberId;
|
||||||
public Long faceId;
|
public Long faceId;
|
||||||
@ -86,92 +89,95 @@ public class VideoPieceGetter {
|
|||||||
task.getCallback().onInvoke();
|
task.getCallback().onInvoke();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FaceSampleRespVO faceSample = faceSampleMapper.getById(task.getFaceSampleId());
|
task.getFaceSampleId().parallelStream().forEach(faceSampleId -> {
|
||||||
DeviceEntity device = deviceMapper.getByDeviceId(faceSample.getDeviceId());
|
FaceSampleRespVO faceSample = faceSampleMapper.getById(faceSampleId);
|
||||||
DeviceConfigEntity config = deviceMapper.getConfigByDeviceId(faceSample.getDeviceId());
|
DeviceEntity device = deviceRepository.getDevice(faceSample.getDeviceId());
|
||||||
|
DeviceConfigEntity config = deviceRepository.getDeviceConfig(faceSample.getDeviceId());
|
||||||
|
|
||||||
SourceEntity source = sourceMapper.querySameVideo(faceSample.getId(), device.getId());
|
SourceEntity source = sourceMapper.querySameVideo(faceSample.getId(), device.getId());
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
// 有原视频
|
// 有原视频
|
||||||
int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1);
|
int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MemberSourceEntity videoSource = new MemberSourceEntity();
|
||||||
|
videoSource.setId(SnowFlakeUtil.getLongId());
|
||||||
|
videoSource.setScenicId(faceSample.getScenicId());
|
||||||
|
videoSource.setFaceId(task.getFaceId());
|
||||||
|
videoSource.setMemberId(task.getMemberId());
|
||||||
|
videoSource.setType(1);
|
||||||
|
videoSource.setIsBuy(0);
|
||||||
|
videoSource.setSourceId(source.getId());
|
||||||
|
sourceMapper.addRelation(videoSource);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
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<FileObject> 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;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
String 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());
|
||||||
MemberSourceEntity videoSource = new MemberSourceEntity();
|
MemberSourceEntity videoSource = new MemberSourceEntity();
|
||||||
videoSource.setId(SnowFlakeUtil.getLongId());
|
|
||||||
videoSource.setScenicId(faceSample.getScenicId());
|
|
||||||
videoSource.setFaceId(task.getFaceId());
|
|
||||||
videoSource.setMemberId(task.getMemberId());
|
videoSource.setMemberId(task.getMemberId());
|
||||||
videoSource.setType(1);
|
videoSource.setType(1);
|
||||||
videoSource.setIsBuy(0);
|
videoSource.setIsBuy(0);
|
||||||
videoSource.setSourceId(source.getId());
|
videoSource.setFaceId(task.getFaceId());
|
||||||
|
videoSource.setScenicId(faceSample.getScenicId());
|
||||||
|
videoSource.setSourceId(sourceEntity.getId());
|
||||||
|
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);
|
||||||
|
sourceMapper.add(sourceEntity);
|
||||||
sourceMapper.addRelation(videoSource);
|
sourceMapper.addRelation(videoSource);
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
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<FileObject> 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;
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
String 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());
|
|
||||||
MemberSourceEntity videoSource = new MemberSourceEntity();
|
|
||||||
videoSource.setMemberId(task.getMemberId());
|
|
||||||
videoSource.setType(1);
|
|
||||||
videoSource.setIsBuy(0);
|
|
||||||
videoSource.setFaceId(task.getFaceId());
|
|
||||||
videoSource.setScenicId(faceSample.getScenicId());
|
|
||||||
videoSource.setSourceId(sourceEntity.getId());
|
|
||||||
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);
|
|
||||||
sourceMapper.add(sourceEntity);
|
|
||||||
sourceMapper.addRelation(videoSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean startFfmpegTask(FfmpegTask task) {
|
public boolean startFfmpegTask(FfmpegTask task) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user