JAVACV 读取摄像头流将rtsp转flv 通过http

编程入门 行业动态 更新时间:2024-10-21 14:28:50

JAVACV 读取<a href=https://www.elefans.com/category/jswz/34/1767894.html style=摄像头流将rtsp转flv 通过http"/>

JAVACV 读取摄像头流将rtsp转flv 通过http

1、pom

 <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.1</version>
</dependency>

 2、摄像头类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Camera  {/*** 摄像头*/private String cameraName;/***摄像头地址*/private String cameraUrl;/***观看人数*/private Integer viewsNumber;/***摄像头状态*/private Integer monitorState;/***闲置关闭时间*/private Integer recoveryTime;/***保存回放*/private Boolean savePlayback;/***分片大小*/private Integer fragmentSize;}

3、服务实现

@Service
public class CameraImpl extends ServiceImpl<CameraMapper, Camera> implements ICameraService {public static Map<Long,CameraHandle> cameraHandleMap = new HashMap<>();public static List<String> cameraKeyList = new ArrayList<>();/*** 获取是否存在推送流,并返回一个唯一key 用于获取flv流*/@Overridepublic String getCamera(Long id) {if (!cameraHandleMap.containsKey(id)){Camera camera = getById(id);camera.setMonitorState(1);CameraHandle cameraHandle = new CameraHandle();cameraHandle.setCamera(camera);cameraHandle.setCameraImpl(this);cameraHandle.start();cameraHandleMap.put(id,cameraHandle);updateById(camera);}String uuid = UUID.randomUUID().toString().replace("-","");cameraKeyList.add(uuid);return uuid;}/*** 开启录制*/@Overridepublic boolean openRecord(Long id) {Camera camera = getById(id);camera.setMonitorState(1);camera.setSavePlayback(true);if (!cameraHandleMap.containsKey(id)){CameraHandle cameraHandle = new CameraHandle();cameraHandle.setCamera(camera);cameraHandle.setCameraImpl(this);cameraHandle.start();cameraHandleMap.put(id,cameraHandle);}else{cameraHandleMap.get(id).setCamera(camera);}updateById(camera);return true;}/*** 关闭录制*/@Overridepublic boolean closeRecord(Long id) {if (cameraHandleMap.containsKey(id)){Camera camera = getById(id);camera.setSavePlayback(false);updateById(camera);cameraHandleMap.get(id).setCamera(camera);}return true;}/*** 客户端关闭推送flv流*/@Overridepublic boolean closeHttpFlv(Long id,String cameraKey) {if (cameraHandleMap.containsKey(id)){CameraHandle cameraHandle = cameraHandleMap.get(id);cameraHandle.streamMap.remove(cameraKey);Camera camera = new Camera();camera.setId(id);camera.setViewsNumber(camera.getViewsNumber()-1);updateById(camera);}return true;}/*** 推送flv流*/@Overridepublic void getHttpFlv(Long id,String cameraKey, HttpServletResponse response) {try{if (cameraHandleMap.containsKey(id)&&cameraKeyList.contains(cameraKey)) {cameraKeyList.remove(cameraKey);CameraHandle cameraHandle = cameraHandleMap.get(id);response.setStatus(HttpStatus.OK.value());response.addHeader("Content-Disposition", "attachment;filename=\"" + java.URLEncoder.encode(cameraHandle.fileName)+ "\"");response.setContentType("video/x-flv");response.setHeader("Connection", "keep-alive");response.setHeader("accept_ranges", "bytes");response.setHeader("pragma", "no-cache");response.setHeader("cache_control", "no-cache");response.setHeader("transfer_encoding", "CHUNKED");response.setHeader("SERVER", "hmsm");ServletOutputStream stream = response.getOutputStream();stream.write(cameraHandle.getFlvHeader());stream.flush();cameraHandle.streamMap.put(cameraKey,stream);cameraHandle.setMonitoring(true);try {Camera camera = cameraHandle.getCamera();camera.setViewsNumber(camera.getViewsNumber()+1);updateById(camera);}catch (Exception e){e.printStackTrace();}while (cameraHandle.streamMap.containsKey(cameraKey)){}}} catch (Exception e) {e.printStackTrace();}}
}

 4、拉流转码

@Data
public class CameraHandle extends Thread {/*** 是否开始拉流解码*/private boolean isStart = true;FFmpegFrameGrabber grabber;FFmpegFrameRecorder recorder;/*** 视频流*/ByteArrayOutputStream pipedOutputStream;/*** 推流*/Map<String,ServletOutputStream>  streamMap = new HashMap<>();/*** 是否实时推流到客户端*/private boolean isMonitoring = false;/*** flv header 输出流的头部信息*/private byte[] flvHeader = null;/*** 没有客户链接的开始时间*/protected long frameTime = System.currentTimeMillis();CameraImpl cameraImpl;Camera camera;String fileName;public CameraHandle() {pipedOutputStream = new ByteArrayOutputStream();}/*** 关闭流*/public void close() {this.isStart = false;}/*** 拉取摄像头信息*/@Overridepublic void run() {try {fileName = camera.getCameraName() + DateTime.now().toString("yyyy_MM_dd") + ".flv";//设置日志级别avutil.av_log_set_level(avutil.AV_LOG_ERROR);//FFmpegLogCallback.set();init();int countErr = 0;while (isStart) {//获取画面  使用grabImage实时预览会等待2-3分钟Frame frame = grabber.grabFrame();if (frame != null) {recorder.record(frame);//业务需求 这个判断可以不要 设置太大实时预览会导致卡顿if (pipedOutputStream.size() > camera.getFragmentSize()) {//实时预览sendFlvFrameData(pipedOutputStream.toByteArray());//存储本地 用于历史回放if (camera.getSavePlayback()) {frameTime = System.currentTimeMillis();if (Files.exists(Paths.get(fileName))) {Files.write(Paths.get(fileName), pipedOutputStream.toByteArray(), StandardOpenOption.APPEND);} else {Files.write(Paths.get(fileName), flvHeader);Files.write(Paths.get(fileName), pipedOutputStream.toByteArray(), StandardOpenOption.APPEND);}}pipedOutputStream.reset();}} else {countErr++;if (countErr > 10) {System.out.println("拉流错误重启");grabber.restart();grabber.flush();countErr = 0;}}long date = System.currentTimeMillis();//5分钟没录制或预览关闭if ((date - frameTime) > camera.getRecoveryTime()) {close();System.out.println("退出:"+camera.getCameraUrl());}}} catch (Exception e) {e.printStackTrace();} finally {try {recorder.stop();recorder.release();} catch (FrameRecorder.Exception exception) {exception.printStackTrace();}try {grabber.stop();} catch (FrameGrabber.Exception exception) {exception.printStackTrace();}try {isMonitoring = false;camera.setMonitorState(0);camera.setSavePlayback(false);cameraImpl.updateById(camera);CameraImpl.cameraHandleMap.remove(camera.getId());} catch (Exception exception) {exception.printStackTrace();}}}private void init() throws FFmpegFrameRecorder.Exception, FrameGrabber.Exception {grabber = new FFmpegFrameGrabber(camera.getCameraUrl());// 超时时间(5秒)grabber.setOption("stimoout", "5000000");grabber.setOption("threads", "1");grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);// 设置缓存大小,提高画质、减少卡顿花屏grabber.setOption("buffer_size", "1024000");//grabber.setOption("buffer_size", "100");// 如果为rtsp流,增加配置if ("rtsp".equals(camera.getCameraUrl().substring(0, 4))) {// 设置打开协议tcp / udpgrabber.setOption("rtsp_transport", "tcp");//首选TCP进行RTP传输grabber.setOption("rtsp_flags", "prefer_tcp");//设置超时时间// -stimeout的单位是us 微秒(1秒=1*1000*1000微秒)。grabber.setOption("stimeout", "5*1000*1000");}grabber.start();recorder = new FFmpegFrameRecorder(pipedOutputStream, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());// 设置比特率recorder.setVideoBitrate(grabber.getVideoBitrate());recorder.setFormat("flv");/* recorder.setInterleaved(false);recorder.setVideoOption("tune", "zerolatency");recorder.setVideoOption("preset", "ultrafast");recorder.setVideoOption("crf", "26");recorder.setVideoOption("threads", "1");recorder.setVideoCodecName("libx264");*/recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);recorder.setSampleRate(grabber.getSampleRate());recorder.setAudioChannels(grabber.getAudioChannels());recorder.setPixelFormat(recorder.getPixelFormat());recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);// 视频帧率(保证视频质量的情况下最低25,低于25会出现闪屏)recorder.setFrameRate(grabber.getFrameRate());// 关键帧间隔,一般与帧率相同或者是视频帧率的两倍recorder.setGopSize((int) grabber.getFrameRate() * 2);recorder.setVideoQuality(1.0);//获取头文件信息recorder.start();grabber.flush();flvHeader = pipedOutputStream.toByteArray();pipedOutputStream.reset();}private void sendFlvFrameData(byte[] bytes) {try {if (streamMap.size()>0&& isMonitoring) {frameTime = System.currentTimeMillis();Iterator<Map.Entry<String, ServletOutputStream>> iterator = streamMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, ServletOutputStream> next = iterator.next();ServletOutputStream outputStream = null;try {outputStream = next.getValue();if (bytes.length > 0) {outputStream.write(bytes, 0, bytes.length);outputStream.flush();}} catch (Exception e) {try {if (null != outputStream) {outputStream.close();}} catch (IOException ioException) {ioException.printStackTrace();}iterator.remove();camera.setViewsNumber(camera.getViewsNumber()-1);cameraImpl.updateById(camera);System.out.println("响应输出流出现错误");e.printStackTrace();}}}}catch (Exception e) {}}}

5、前端(vue)

安装flv.js   npm install --save flv.js

<template><div class="live-preview" style="background: #f0f2f5; width: 100%"><video id="liveVideo" controls autoplay muted width="1024" height="576">Your browser is too old which doesn't support HTML5 video.</video></div>
</template>
<script>
import flvjs from "flv.js";
export default {data() {return {};},mounted: function () {this.$nextTick(function () {this.createPlayer();});},methods: {createPlayer() {if (flvjs.isSupported()) {var videoEle = document.getElementById("liveVideo"); //!注意:如果播放直播流(监控视频)必须将参数isLive:true加上,不然会导致短时间内断流会造成视频页面卡顿//需先请求getCamera获取cameraKeylet player = flvjs.createPlayer({type: "flv",url: "http://localhost:8101/camera/v1/camera/getHttpFlv?id=1&cameraKey=36ae75e6fe8941d8b8b56f174f749c0e", isLive: true, //直播流},{enableWorker: false, //不启用分离线程enableStashBuffer: false, //关闭IO隐藏缓冲区stashInitialSize: 128, // 减少首帧显示等待时长lazyLoad: false, //如果有足够的数据可播放,则中止http连接});player.attachMediaElement(videoEle);player.load();player.play();videoEle.play();player.on(flvjs.Events.ERROR,(errorType, errorDetail, errorInfo) => {console.log("errorType:", errorType);console.log("errorDetail:", errorDetail);console.log("errorInfo:", errorInfo);});} else {this.$message.error("不支持flv格式视频");}},},
};
</script>

更多推荐

JAVACV 读取摄像头流将rtsp转flv 通过http

本文发布于:2024-03-09 09:54:16,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724653.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:摄像头   JAVACV   rtsp   http   flv

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!