海报设计免费软件,seo李守洪排名大师,中国建设银行积分商城网站,做视频网站 视频放在哪里找前言
哪一天我心血来潮#xff0c;想把我儿子学校的摄像头视频流录制下来#xff0c;并保存到云盘上#xff0c;这样我就可以在有空的时候看看我儿子在学校干嘛。想到么就干#xff0c;当时花了一些时间开发了一个后端服务#xff0c;通过数据库配置录制参数#xff0c;…前言
哪一天我心血来潮想把我儿子学校的摄像头视频流录制下来并保存到云盘上这样我就可以在有空的时候看看我儿子在学校干嘛。想到么就干当时花了一些时间开发了一个后端服务通过数据库配置录制参数以后的设想是能够通过页面去配置能够自动捕获直播视频流这还得要求自己先学会vue所以还得缓缓。
实现
技术栈Spring Boot、Webflux、r2dbc、javacv
架构图 流程很简单主要还是要用到JavaCV从视频流里捕获视频先报错到本地然后有一个定时任务会定时去检测目录内是否有新生成的文件有就上传到配置的云盘百度云。
1、创建pom
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.6.4/versionrelativePath / !-- lookup parent from repository --/parentgroupIdnet.178le/groupIdartifactIdvideo-cloud-record/artifactIdversion0.0.1-SNAPSHOT/versionnamevideo-cloud-record/namedescription视频云录制/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-webflux/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-r2dbc/artifactId/dependencydependencygroupIddev.miku/groupIdartifactIdr2dbc-mysql/artifactId/dependencydependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.7.22/version/dependencydependencygroupIdorg.bytedeco/groupIdartifactIdjavacv-platform/artifactIdversion1.4.4/version/dependencydependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpcore/artifactIdversion4.4.10/version/dependencydependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpclient/artifactIdversion4.5.6/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdio.projectreactor/groupIdartifactIdreactor-test/artifactIdscopetest/scope/dependency/dependenciesbuildfinalNamevideo-cloud-record/finalNamepluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/plugin/plugins/build/project2、定时异常信息
package net.video.record.config;import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import lombok.extern.slf4j.Slf4j;/*** desc 全局异常捕捉并转换异常*/
Slf4j
RestControllerAdvice(basePackages net.video.record)
public class GlobalExceptionHandler {ExceptionHandler(Exception.class)public ResultString handleException(Exception e) {log.error({}, e);return Result.error(, e.getMessage());}}
3、统一结果集
package net.video.record.config;import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;Data
AllArgsConstructor
public class ResultT {private String code;private T data;private String msg;public static T ResultT ok(T data) {return new ResultT(0, data, );}public static T ResultT error(String code, String msg) {code StrUtil.isEmpty(code)? 500 : code;return new ResultT(code, null, msg);}
}
4、定义两个Model
TaskList 用来保存用户相关的录制任务
package net.video.record.entity.model;import java.time.LocalDateTime;
import java.util.Date;import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;import lombok.Data;Data
Table(task_list)
public class TaskList {Idprivate Integer id;private String name;private String streamUrl;private Integer userId;private Integer status;private Integer delFlag;private LocalDateTime createTime;private LocalDateTime modifyTime;private String runRule;private LocalDateTime lastRunTime;private Integer recordTime;private Integer segTime;}
User 定义用户信息保存了用过相关的录制参数
package net.video.record.entity.model;import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;import lombok.Data;
import lombok.experimental.Accessors;Data
Accessors(chain true)
Table(user)
public class User {public static MapInteger, User userMap new ConcurrentHashMapInteger, User();Idprivate Integer id;private String userName;private String password;private String bdAccessToken;private String bdRefreshToken;private LocalDateTime createTime;private LocalDateTime modifyTime;}
5、几个VO
TaskReq 任务请求参数
package net.video.record.entity.vo;import lombok.Data;
import lombok.experimental.Accessors;Data
Accessors(chain true)
public class TaskReq {private Integer taskId;
}
UserReq
package net.video.record.entity.vo;import lombok.Data;Data
public class UserReq {private String userName;private String password;
}
UserRes
package net.video.record.entity.vo;import java.time.LocalDateTime;import com.fasterxml.jackson.annotation.JsonFormat;import lombok.Data;Data
public class UserRes {private Integer id;private String userName;private String password;JsonFormat(pattern yyyy-MM-dd HH:mm:ss)private LocalDateTime createTime;JsonFormat(pattern yyyy-MM-dd HH:mm:ss)private LocalDateTime modifyTime;
}
6、把网盘接口封装一下
我封装的是百度网盘可以去网盘开放平台查看文档这里贴出主要的上传代码。
public String upload(BdFileUpload req, TaskList task) {User user User.userMap.get(task.getUserId());if (user null) {throw new RuntimeException(用户信息不存在);}//大于4m的话分片这里先不处理分片File file req.getFile();req.setAccess_token(user.getBdAccessToken());ListString fileMd5 Arrays.asList(SecureUtil.md5(file));PreCreateReq preCreateReq new PreCreateReq().setAccess_token(req.getAccess_token()).setAutoinit(1).setIsdir(0).setRtype(1).setPath(/apps/直播云存储/ task.getId() / DateUtil.today() / file.getName()).setSize(String.valueOf(file.length())).setBlock_list(JSONUtil.toJsonStr(fileMd5));PreCreateRes preCreate preCreate(preCreateReq);for (int i 0; i fileMd5.size(); i) {SegUploadReq segUploadReq new SegUploadReq().setAccess_token(req.getAccess_token()).setPath(preCreate.getPath()).setUploadid(preCreate.getUploadid()).setPartseq(i).setFile(req.getFile());SegUploadRes segUploadRes SegUpload(segUploadReq);}CreateFileReq createFileReq new CreateFileReq().setAccess_token(req.getAccess_token()).setBlock_list(JSONUtil.toJsonStr(fileMd5)).setPath(preCreateReq.getPath()).setSize(preCreateReq.getSize()).setIsdir(preCreateReq.getIsdir()).setRtype(preCreateReq.getRtype()).setUploadid(preCreate.getUploadid());CreateFileRes createFile createFile(createFileReq);return createFile.getServer_filename();}7、视频流录制部分
/*** 录制视频* param inputFile 该地址可以是网络直播/录播地址也可以是远程/本地文件路径* param outputFile 该地址只能是文件地址如果使用该方法推送流媒体服务器会报错原因是没有设置编码格式* param audioChannel 是否录制音频 1录制* param time 录制时间* throws Exception* throws org.bytedeco.javacv.FrameRecorder.Exception*/public void frameRecord(String inputFile, String outputFile, int audioChannel, int time)throws Exception, org.bytedeco.javacv.FrameRecorder.Exception {// 获取视频源FFmpegFrameGrabber grabber new FFmpegFrameGrabber(inputFile);// 流媒体输出地址分辨率长高是否录制音频0:不录制/1:录制FFmpegFrameRecorder recorder new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel);recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//设置分片recorder.setFormat(segment);//生成模式 实时recorder.setOption(segment_list_flags, live);//分片时长 60srecorder.setOption(segment_time, 60);//锁定分片时长recorder.setOption(segment_atclocktime, 1);//用来严格控制分片时长recorder.setOption(break_non_keyframes, 1);//设置日志级别avutil.av_log_set_level(avutil.AV_LOG_ERROR);// 开始取视频源try {grabber.start();recorder.start();Frame frame null;Date startDate new Date();while ((frame grabber.grabFrame()) ! null DateUtil.between(startDate, new Date(), DateUnit.SECOND) time * 60) {recorder.record(frame);}recorder.stop();grabber.stop();} finally {if (grabber ! null) {grabber.stop();}}}总结
这里我只贴出了部分代码如果有想要了解具体实现的也可以留言跟我交流。这个系统我也只是快速实现了一下只达到能用的程度其中对javacv、webflux进行了一定学习研究后续的完善还要看我哪天再次心血来潮。 作者其他文章推荐 基于Spring Boot 3.1.0 系列文章 Spring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解Spring Boot 监听器详解Spring Boot banner详解Spring Boot 属性配置解析Spring Boot 属性加载原理解析Spring Boot 异常报告器解析Spring Boot 3.x 自动配置详解