package com.chinaunicom.zwboy.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinaunicom.common.base.convert.BaseConvert;
import com.chinaunicom.common.base.feign.RemoteUserGbCodeService;
import com.chinaunicom.common.base.feign.model.DeviceCommandPtzReqBaseDto;
import com.chinaunicom.common.core.constant.SecurityConstants;
import com.chinaunicom.video.entity.Lives;
import com.chinaunicom.video.entity.SvAircraftVideoRecord;
import com.chinaunicom.video.service.LivesService;
import com.chinaunicom.video.util.RedisUtil;
import com.chinaunicom.video.util.WoYunOssUtils;
import com.chinaunicom.zwboy.model.PushData;
import com.chinaunicom.zwboy.model.PushTask;
import com.chinaunicom.zwboy.service.*;
import com.chinaunicom.zwboy.service.impl.SaveRecordThreadManagerImpl;
import com.chinaunicom.zwboy.util.FileOperUtils;
import com.lh.service.SaveRecord;
import com.lh.service.SliceType;
import com.lh.service.impl.SaveRecordImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.*;
@Slf4j
@RestController
//@RequestMapping("/pushAsync")
public class PushLhController {
@Autowired
private SaveRecordThreadManagerImpl saveRecordThreadManagerImpl;
@Autowired
private PushAsyncService pushAsyncService;
@Autowired
private PushLhService pushLhService;
@Autowired
private RedisUtil redisUtil;
@Autowired
private WoYunOssUtils woYunOssUtils;
@Autowired
private LivesService livesService;
@Autowired
private MyTaskService myTaskService;
@Value("${linux.path}")
private String linuxPath;
@Value("${redisTime.expiredTime}")
private Integer expiredTime;
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
capableBeanFactory.autowireBean(forwardTask);
// 创建一个定长线程池,支持定时及周期性任务执行,建立一个延时任务,1000毫秒之后执行
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
@PostMapping(value = "/pushers")
@ResponseBody
public String pusherAndStop(HttpServletRequest request, HttpServletResponse response, @RequestBody String param) {
log.info("PushLhController PusherAndStop() param="+Thread.currentThread().getName()+" "+param);
log.info("PushLhController PusherAndStop() linuxPath="+linuxPath);
log.info("PushLhController PusherAndStop() expiredTime="+expiredTime);
JSONObject jsonObject = JSONObject.parseObject(param);
String stream = jsonObject.getString("stream");
QueryWrapper<Lives> queryWrapperByid = BaseConvert.buildDelQueryWrapper();
queryWrapperByid.eq("c_id", stream);
Lives lives = livesService.getOne(queryWrapperByid);
log.info("PushLhController PusherAndStop() lives="+ JSON.toJSONString(lives));
if(lives==null){//无视
return "0";
}
try {
//校验推送流还是关闭流
if (jsonObject.getString("action").equals("on_publish")) {
PushData pushTask = new PushData();
String uuid = UUID.randomUUID().toString().replace("-", "");
pushTask.setId(uuid);
pushTask.setPushSrcUrl(lives.getRtmpUrl());//推流源地址/改成播放地址
pushTask.setPushDescUrl(linuxPath);
pushTask.setStream(stream);
String pushTaskJson = JSONUtil.toJsonStr(pushTask);
log.info("PushLhController PusherAndStop() on_publish pushTaskJson="+pushTaskJson);
//生成磁盘录像文件 //上传沃云成功并保存本地表记录
//pushLhService.asyncStart(pushTask);
String pushSrcUrl = pushTask.getPushSrcUrl();
String pushDescUrl = pushTask.getPushDescUrl();
String streamId = pushTask.getStream();
// 参数"1234", "rtmp://172.16.10.196:1935/live/5e7367809f32448682177561af153f9d", "D:/tmp/", true, SliceType.DURATION, 10
saveRecordThreadManagerImpl.start(streamId,pushSrcUrl,pushDescUrl,true, SliceType.DURATION, expiredTime);
long initialDelay = 3L; //定时任务延时启动30秒
long period = expiredTime+3L; //定时任务时间间隔5分钟,
log.info("PushLhController PusherAndStop() period="+period);
executor.scheduleAtFixedRate(myTaskService,initialDelay ,period, TimeUnit.SECONDS);
//SaveRecord saveRecord = new SaveRecordImpl();
//saveRecord.start("1234", "rtmp://172.16.10.196:1935/live/5e7367809f32448682177561af153f9d","D:/tmp/", true, SliceType.DURATION, 30);
return "0";
} else if (jsonObject.getString("action").equals("on_unpublish")) {
//停止推流
if(StringUtils.isNotBlank(stream)) {
pushLhService.asyncStop(stream);
}
return "0";
}
}catch (Exception e){
e.printStackTrace();
}
return "0";
}
}
package com.chinaunicom.zwboy.service.impl;
import com.chinaunicom.zwboy.service.SaveRecordService;
import com.chinaunicom.zwboy.util.ApplicationContextUtil;
import com.lh.service.SliceType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Service
public class SaveRecordThreadManagerImpl {
Map<String, SaveRecordService> saveRecordMap = new HashMap<>();
/**
*
* @param id 线程id
* @param inputFile 网络输入流 rtmp
* @param outputFile 输出mp4文件
* @param needAudio 是否录音
* @param sliceType
* @param arg 多久生成一个mp4 单位秒
*/
@Async
public void start(String id, String inputFile, String outputFile, Boolean needAudio, SliceType sliceType, int arg) {
SaveRecordService saveRecord;
synchronized (saveRecordMap) {
saveRecord = saveRecordMap.get(id);
if (saveRecord == null) {
saveRecord = new SaveRecordServiceImpl();
//saveRecord = ApplicationContextUtil.getBean("saveRecordServiceImpl");
saveRecordMap.put(id, saveRecord);
}
}
saveRecord.start(id, inputFile, outputFile, needAudio, sliceType, arg);
}
public void stop(String id) {
SaveRecordService saveRecord;
synchronized (saveRecordMap) {
saveRecord = saveRecordMap.get(id);
saveRecordMap.remove(id);
}
if (saveRecord != null)
saveRecord.stop(id);
}
}
package com.chinaunicom.zwboy.service.impl;
import com.chinaunicom.zwboy.service.NewRecordService;
import com.chinaunicom.zwboy.service.SaveRecordService;
import com.lh.service.SliceType;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@Service("saveRecordServiceImpl")
public class SaveRecordServiceImpl implements SaveRecordService {
private FFmpegFrameGrabber grabber;
private FFmpegFrameRecorder recorder;
private NewRecordService newRecordService;
private String id;
private Boolean isStart = false;
private int seconds;
@Value("5000000")
private String stimeout; // 连接输入视频流超时, us
@Value("3000000")
private String timeout; // tcp/udp超时, us
private String inputFile; // 输入视频流地址
private String outPath; // 输出路径
private String outputFile; // 输出文件
private Boolean needAudio; // 是否需要音频
private Date startTime;
SliceType sliceType; // 切片类型
int sliceArg; // 切片参数
Frame lastKeyFrame;
Integer index = 0;
@Override
public void start(String id, String inputFile, String outPath, Boolean needAudio, SliceType sliceType, int arg) {
synchronized (isStart) {
if (isStart)
return;
this.id = id;
this.inputFile = inputFile;
if (outPath.charAt(outPath.length() - 1) != '/')
this.outPath = outPath + "/";
else
this.outPath = outPath;
this.needAudio = needAudio;
this.sliceType = sliceType;
this.sliceArg = arg;
this.isStart = true;
}
save_record();
}
@Override
public void stop(String id) {
synchronized (isStart) {
if (!isStart)
return;
isStart = false;
}
}
@Async
public void save_record() {
while (isStart) {
try {
// 打开视频流
if (grabber == null) {
try {
log.info("打开流地址={}", inputFile);
grabber = new FFmpegFrameGrabber(inputFile);
grabber.setOption("stimeout", stimeout);
grabber.setOption("timeout", timeout);
grabber.start();
} catch (FrameGrabber.Exception e) {
log.error("grabber打开失败, {}", e.toString());
grabber = null;
continue;
}
}
getFilename();
recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(),
needAudio ? 1 : 0);
recorder.start();
startTime = new Date();
Frame frame = null;
try {
while (isStart) {
if (lastKeyFrame == null)
frame = grabber.grabFrame();
else {
frame = lastKeyFrame;
lastKeyFrame = null;
}
if (needSlice(frame)) {
lastKeyFrame = frame;
saveRecord();
break;
}
if (frame != null) {
recorder.record(frame);
}
}
} catch (FrameRecorder.Exception e) {
log.error("save_record 1= 写录像出错, {}", e.toString());
}
saveRecord();
} catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
log.error("save_record 2= 初始化失败", e.toString());
e.printStackTrace();
} finally {
saveRecord();
}
}
}
// 判断是否需要切片
boolean needSlice(Frame frame) {
switch (sliceType) {
case DURATION:
return sliceArg <= getDuration() && frame.keyFrame;
case SIZE:
break;
default:
assert false;
}
return false;
}
// 保存当前的录像
void saveRecord() {
try {
if (recorder != null) {
recorder.stop();
Date cur = new Date();
log.info("saveRecourdFile=新录像生成={}, startTime={}, duration={}", outputFile, startTime, getDuration());
//log.info("deleteRecourdFile=新录像删除={}, startTime={}, duration={}", outputFile, startTime, getDuration());
//newRecordService.newRocord(id, outputFile, startTime, getDuration());
newRecordService=new NewRecordServiceImpl();
newRecordService.delNewRocord(id, outputFile, startTime, getDuration());
recorder = null;
}
} catch (FrameRecorder.Exception e) {
log.info("saveRecord FrameRecorder:"+e.getMessage());
e.printStackTrace();
}
}
long getDuration() {
Date cur = new Date();
return (cur.getTime() - startTime.getTime()) / 1000;
}
void getFilename() {
DateFormat df = new SimpleDateFormat("yyMMddHHmmssSSS"); // add S if you need millisecon// ds
String filename = df.format(new Date());
outputFile = outPath + filename + "_" + id + ".mp4";
index += 1;
}
}
package com.chinaunicom.zwboy.service.impl;
import com.chinaunicom.video.service.LivesService;
import com.chinaunicom.video.util.WoYunOssUtils;
import com.chinaunicom.zwboy.service.NewRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.Date;
@Slf4j
@Service
public class NewRecordServiceImpl implements NewRecordService {
@Value("${linux.path}")
private String linuxPath;
@Value("${redisTime.expiredTime}")
private Long expiredTime;
@Autowired
private WoYunOssUtils woYunOssUtils;
@Autowired
private LivesService livesService;
int count=0;
@Override
public void newRocord(String id, String fileName, Date startTime, long duration) {
// 定时任务业务逻辑
count++;
log.info("NewRecordServiceImpl newRocord fileName:" + fileName+"id:"+id+" count:"+count++);
/*File child = new File(fileName);
if (child.length() <= 258) {
return;
}
String stream = id;
log.info("NewRecordServiceImpl toUpload2 fileName=" + fileName);
InputStream inputStream = null;
try {
inputStream = new FileInputStream(child);
DateFormat df = new SimpleDateFormat(FileOperUtils.dateFormatStr); // add S if you need millisecon// ds
String filename = df.format(new Date());
String fileName2 = filename + "-" + stream + ".mp4";
String url = woYunOssUtils.uploadFileToMp4(inputStream, fileName2, child.length());
PushData pushData = new PushData();
String uuid = UUID.randomUUID().toString().replace("-", "");
pushData.setId(uuid);
pushData.setPushDescUrl(fileName2);
pushData.setStream(stream);
pushData.setRecordCreateTime(new Date());
pushData.setRecordName(fileName2);
pushData.setRecordStorePath(url);
log.info("NewRecordServiceImpl toUpload2 pushData=" + JSON.toJSONString(pushData));
QueryWrapper<Lives> queryWrapperByid = BaseConvert.buildDelQueryWrapper();
queryWrapperByid.eq("c_id", pushData.getStream());
Lives lives = livesService.getOne(queryWrapperByid);
log.info("NewRecordServiceImpl toUpload() lives:" + JSON.toJSONString(lives));
SvAircraftVideoRecord svAircraftVideoRecord = new SvAircraftVideoRecord();
svAircraftVideoRecord.setSvLiveId(lives.getCId());
svAircraftVideoRecord.setFileSize(child.length());
svAircraftVideoRecord.setRecordName(pushData.getRecordName());
svAircraftVideoRecord.setRecordStorePath(pushData.getRecordStorePath());
svAircraftVideoRecord.setRecordCreateTime(pushData.getRecordCreateTime());
log.info("NewRecordServiceImpl toUpload2 svAircraftVideoRecord=" + JSON.toJSONString(svAircraftVideoRecord));
//livesService.saveSvAircraftVideoRecord(svAircraftVideoRecord);
//上传完沃云删除服务器本地文件
//child.delete();
} catch (Exception e) {
e.printStackTrace();
}*/
}
@Override
public void delNewRocord(String id, String filename, Date startTime, long duration) {
//log.info("NewRecordServiceImpl delNewRocord :" + filename);
File root = new File(filename);
if (root.isFile()) {
if(root.length()<=258) {
root.delete();
}
}
}
}
package com.chinaunicom.zwboy.service;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinaunicom.common.base.convert.BaseConvert;
import com.chinaunicom.video.entity.Lives;
import com.chinaunicom.video.entity.SvAircraftVideoRecord;
import com.chinaunicom.video.service.LivesService;
import com.chinaunicom.video.util.WoYunOssUtils;
import com.chinaunicom.zwboy.model.PushData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.UUID;
@Slf4j
@Service
public class MyTaskService implements Runnable{
@Value("${linux.path}")
private String linuxPath;
@Value("${redisTime.expiredTime}")
private Long expiredTime;
@Autowired
private WoYunOssUtils woYunOssUtils;
@Autowired
private LivesService livesService;
@Override
public void run() {
// 定时任务业务逻辑
log.info("MyTaskService runLinuxPath :"+linuxPath);
File root = new File(linuxPath);
if (root != null && root.exists()) {
if (root.isDirectory()) {
File[] children = root.listFiles();
if (children != null) {
for (File child : children) {
String fileName = child.getName();
if (child.isFile() && fileName.endsWith("mp4")) {
long fileSize = child.length();
if(fileSize<=258){
child.delete();
}else {
String[] fileNames = fileName.split("_");
String streamId = fileNames[1];
Integer nameIndex2 = streamId.lastIndexOf(".");
String stream = streamId.substring(0, nameIndex2);
log.info("MyTaskService child.length() :" + fileSize + "fileName:" + fileName);
InputStream inputStream = null;
try {
if(fileSize<=258){
child.delete();
continue;
}
inputStream = new FileInputStream(child);
String url = woYunOssUtils.uploadFileToMp4(inputStream, fileName, fileSize);
PushData pushData = new PushData();
String uuid = UUID.randomUUID().toString().replace("-", "");
pushData.setId(uuid);
pushData.setPushDescUrl(fileName);
pushData.setStream(stream);
pushData.setRecordCreateTime(new Date());
pushData.setRecordName(fileName);
pushData.setRecordStorePath(url);
log.info("MyTaskService toUpload2 pushData=" + JSON.toJSONString(pushData));
QueryWrapper<Lives> queryWrapperByid = BaseConvert.buildDelQueryWrapper();
queryWrapperByid.eq("c_id", pushData.getStream());
Lives lives = livesService.getOne(queryWrapperByid);
log.info("MyTaskService toUpload2() lives:" + JSON.toJSONString(lives));
if(lives!=null) {
SvAircraftVideoRecord svAircraftVideoRecord = new SvAircraftVideoRecord();
svAircraftVideoRecord.setSvLiveId(lives.getCId());
svAircraftVideoRecord.setSvLiveName(lives.getName());
svAircraftVideoRecord.setFileSize(fileSize);
svAircraftVideoRecord.setRecordName(pushData.getRecordName());
svAircraftVideoRecord.setRecordStorePath(pushData.getRecordStorePath());
svAircraftVideoRecord.setRecordCreateTime(pushData.getRecordCreateTime());
log.info("MyTaskService toUpload2 svAircraftVideoRecord=" + JSON.toJSONString(svAircraftVideoRecord));
livesService.saveSvAircraftVideoRecord(svAircraftVideoRecord);
//上传完沃云删除服务器本地文件
child.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
}
java多线程按照时间段切割视频流片段
最新推荐文章于 2025-03-30 16:40:51 发布