目录
需求
实现
前端播放海康摄像头的画面
录制视频
方法一:HTMLVideoElement(废弃)
方法二:HTMLCanvasElement(废弃)
方法三:javaCV
代码
问题
需求
前端接收webrtc-streamer从rtsp转换来的hls流
点击开始按钮开始录制一段时间
点击停止按钮停止录制
点击上传将视频存放到服务器
实现
前端播放海康摄像头的画面
由于监控设备多采用rtsp流传输视频,但H5无法接收该类型的视频流,使用webrtc-streamer进行转流播放
录制视频
方法一:HTMLVideoElement(废弃)
1、使用HTMLVideoElement的caputure捕捉video组件中正在播放的视频流
2、将视频流放入列表
3、将列表转换成blob数据类型
4、使用axios将存储的blob数据传向后端
5、后端接收blob数据存储到磁盘中,并将路径存储数据库
弊端:传统html可实现,vue3适配的ts格式的HTMLElement还未提供HTMLVideoElement.captureStreamer方法
方法二:HTMLCanvasElement(废弃)
1、使用video组件播放视频
2、将video绘制到canvas
3、捕捉canvas媒体流
4、使用axios将存储的blob数据传向后端
5、后端接收blob数据存储到磁盘中,并将路径存储数据库
弊端:将video绘制到canvas,然后捕捉canvas的媒体流,适用于秒级的录制
方法三:javaCV
1、前端获取时间戳与任务信息传向后端
2、后端使用javaCV拉取rtsp流,读取帧,根据时间戳记录角度帧
好处:适合长时间存储视频
代码
public class SceneService {
private volatile boolean stopFlag = false;
private volatile String videoPath;
private final SceneMapper sceneMapper;
private FFmpegFrameGrabber grabber;
private FFmpegFrameRecorder videoWriter;
private Thread videoThread;
@Autowired
public SceneService(SceneMapper sceneMapper){
this.sceneMapper = sceneMapper;
}
public void recordVideo(String taskName){
// 设置rtsp流地址
String rtspUrl = "rtsp://你的用户名:你的密码@127.0.0.1:8554/stream";
// 设置保存路径
String rootDir = "E:\\ProgramSoftware\\java\\AIDetectCloudPlatform\\recordVideo";
String fileName = taskName + ".mp4";
this.videoPath = Paths.get(rootDir, fileName).toString();
// 使用FFmpegFrameGrabber 类拉取rtsp流
try {
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
// 禁用音频
grabber.setOption("rtsp_transport", "tcp");
grabber.start();
System.out.println("开始拉流");
// 设置视频读取器
int width = grabber.getImageWidth();
int height = grabber.getImageHeight();
videoWriter = new FFmpegFrameRecorder(this.videoPath, width, height);
videoWriter.setFormat("mp4");
videoWriter.setAudioChannels(2);
videoWriter.start();
System.out.println("开始记录");
// 创建新的线程来处理循环
this.videoThread = new Thread(() -> {
try {
while (!this.videoThread.isInterrupted() && !this.stopFlag) {
Frame frame = grabber.grab();
if (frame == null) {
System.out.println("记录结束");
break;
}
long currentTimestamp = frame.timestamp;
System.out.printf("frame timeStamp %s \n", currentTimestamp);
// 向目标地址存储
videoWriter.record(frame);
}
videoWriter.stop();
grabber.stop();
this.stopFlag = false;
}catch (Exception e){
e.printStackTrace();
}
});
this.videoThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stopRecordVideo(String taskId) {
this.stopFlag = true;
// 关闭线程
if ( this.videoThread != null && this.videoThread.isAlive()) {
System.out.println("记录结束");
this.videoThread.interrupt();
}
// 将录像与任务关联
sceneMapper.collectTaskVideo(taskId, this.videoPath);
}
}
问题
1、传统html提供了对video组件的媒体流captureStream方法,vue3使用的ts所适配的HTMLELEMNT中的还没有提供直接对video组件提取媒体流的方法
2、将video重绘到canvas,HTMLELEMENT提供了对canvas的媒体流获取的方法,但是只适用于短时间录制
3、报错:java.lang.UnsatisfiedLinkError: Could not find jniavutil in class, module, and library paths.
只引入了javacv依赖还需要引入ffmepg-platform
4、报错:No audio output stream (Is audioChannels > 0 and has start() been called?)
没有为FFmpegFrameRecorder类的实例对象设置setAudioChannels