使用javacv对摄像头视频转码并实现播放

要实现Java接受RTSP流解码,并推送给前端实现播放实时流,可以使用一些流媒体处理库,比如JavaCV或者FFmpeg等。以下是一个简单的示例代码:

1.控制层方面的

根据视频rtsp流链接打开转换,通过响应写出流到前台使用flvjs播放视频

 一个播放器销毁时,将对应转换器线程暂停

@RestController
@RequestMapping("flv")
public class FlvVideoController {@Autowiredprivate IFLVService iflvService;/*** 根据视频rtsp流链接打开转换,通过响应写出流到前台使用flvjs播放视频* @param url 视频链接* @param httpServletResponse 响应请求* @author xufeng*/@RequestMapping(method = RequestMethod.GET, value = "/open/{param}")public void open(@PathVariable(value = "param") String url, HttpServletResponse httpServletResponse) {try {System.out.println("==url="+url);if(StringUtils.isBlank(url)) {url="";}BASE64Decoder base64Decoder = new BASE64Decoder();//获取当前登录用户主键String userId = "1";//String userId = UserContext.getCurrentUser().getId();//为保持url长度,需要先对前端传来的url进行base64解码,再调用flvService接口iflvService.open(new String(base64Decoder.decodeBuffer(url)), userId, httpServletResponse);} catch (Exception e) {e.printStackTrace();}}/*** 一个播放器销毁时,将对应转换器线程暂停* @author xufeng* @param videoUrl 视频流链接* @return EosDataTransferObject*/@ResponseBody@RequestMapping(method = RequestMethod.GET, value = "/closeTransThread")public JsonResult closeTransThread(/*@RequestParam(value = "videoUrl") String videoUrl*/) {try {String videoUrl="rtsp://admin:xxx:554/cam/realmonitor?channel=1&subtype=0";//视频流链接为空直接返回if (StringUtils.isBlank(videoUrl)) {return new JsonResult();}//获取当前登录用户主键String userId = "1";//String userId = UserContext.getCurrentUser().getId();//使用主键获取当前所有转换器ConcurrentHashMap<String, Converter> conMaps = ConverterRegistration.getAllConverters(userId);//通过视频流链接取对应的转换器Converter converter = ConverterRegistration.isExist(videoUrl, conMaps);if (null != converter) {//暂停转换器线程,1分钟无新线程创建,该线程即被销毁converter.exit();}} catch (Exception e) {e.printStackTrace();}return new JsonResult();}}

2.视频流转换接口

public interface IFLVService {/*** 打开一个流地址** @param url rtsp流链接* @param userId 用户主键* @param response 响应请求* @author xufeng*/void open(String url,String userId, Object response);}
FLV流转换
@Service("flvService")
public class FLVService implements IFLVService {/*** 打开一个流地址,写入response* @param url 流地址* @param userId 用户主键* @param object HttpServletResponse* @author xufeng*/@Overridepublic void open(String url, String userId, Object object) {//创建转换器线程并启动Converter c = ConverterRegistration.open(url, userId);//UUID设置一个key值String key = UUID.randomUUID().toString();//创建输出字节流OutputStreamEntity outEntity = new OutputStreamEntity(new ByteArrayOutputStream(), System.currentTimeMillis(),key);//添加流输出System.out.println("==添加流输出=="+key);c.addOutputStreamEntity(key, outEntity);try {HttpServletResponse response = (HttpServletResponse) object;//设置响应头response.setContentType("video/x-flv");response.setHeader("Connection", "keep-alive");response.setStatus(HttpServletResponse.SC_OK);//写出缓冲信息,并清空response.flushBuffer();//循环读取outEntity里的流输出给前台System.out.println(c.getConverterState()+"==(response)循环读取outEntity里的流输出给前台==");readFlvStream(c, outEntity, response);} catch (Exception e) {//客户端长连接过程中被异常关闭,关闭该长连接对应的转换器线程c.exit();e.printStackTrace();//c.removeOutputStreamEntity(outEntity.getKey());}}/*** 递归读取转换好的视频流** @param c 转换器* @param outEntity 输出流* @param response 响应* @author xufeng* @throws Exception*/public void readFlvStream(Converter c, OutputStreamEntity outEntity, HttpServletResponse response)throws Exception {//根据转换器状态来决定是继续等待、读取、结束流输出switch (c.getConverterState()) {case INITIAL:Thread.sleep(300);readFlvStream(c, outEntity, response);break;case OPEN:Thread.sleep(100);//System.out.println("=== OPEN递归读取转换好的视频流=="+c.getUrl());readFlvStream(c, outEntity, response);break;case RUN:if (outEntity.getOutput().size() > 0) {byte[] b = outEntity.getOutput().toByteArray();outEntity.getOutput().reset();response.getOutputStream().write(b);outEntity.setUpdateTime(System.currentTimeMillis());}System.out.println("=== RUN递归读取转换好的视频流=="+c.getUrl());c.setUpdateTime(System.currentTimeMillis());Thread.sleep(100);readFlvStream(c, outEntity, response);break;case CLOSE://log.info("close");break;default:break;}}}

3.转换

public class ConverterRegistration {/*** 转换器集合(根据用户ID分类)*/private static ConcurrentHashMap<String, ConcurrentHashMap<String, Converter>> converters = new ConcurrentHashMap<>();/*** 线程池*/private static ExecutorService executorService = Executors.newCachedThreadPool();/*** 开始一个转换<br/>* 如果已存在这个流的转换就直接返回已存在的转换器* @author xufeng* @param url 视频流链接* @param userId 用户主键* @return converter*/public static Converter open(String url, String userId) {System.out.println("===开始一个转换==="+url);//判断当前用户是否存在转换器线程集合,没有则新建ConcurrentHashMap<String, Converter> concurrentHashMap = converters.get(userId);if (concurrentHashMap == null) {concurrentHashMap = new ConcurrentHashMap<>(16);converters.put(userId, concurrentHashMap);}//判断是否已存在该转换器Converter c = isExist(url, concurrentHashMap);System.out.println("===判断是否已经存在转换器=="+c);try {if (null == c) {String key = UUID.randomUUID().toString();//创建线程c = new ConverterFactories(url, UUID.randomUUID().toString(), converters.get(userId));//记录到集合concurrentHashMap.put(key, c);//c.start();//用线程池启动executorService.execute((Runnable) c);}}catch (Exception e) {e.printStackTrace();}//如果该线程存在,但处于停止状态,则重新设置状态播放if (!c.isRuning()) {//设置运行状态c.setRuning(true);//设置初始化标志c.setState(ConverterState.INITIAL);//线程池启动executorService.execute((Runnable) c);}return c;}/*** 如果流已存在,就共用一个* @author xufeng* @param url 链接* @param concurrentHashMap 转换器集合* @return converter*/public static Converter isExist(String url, ConcurrentHashMap<String, Converter> concurrentHashMap) {//遍历集合,根据url判断是否已存在该流视频for (Converter c : concurrentHashMap.values()) {if (url.equals(c.getUrl())) {return c;}}return null;}/*** 返回集合中的所有转换器* @author xufeng* @param userId 用户主键* @return converters*/public static ConcurrentHashMap<String, Converter> getAllConverters(String userId){return converters.get(userId);}
}

4.使用javacv

public class ConverterFactories extends Thread implements Converter {/*** 运行状态*/public volatile boolean runing = true;/*** 读流器*/private FFmpegFrameGrabber grabber;/*** 转码器*/private FFmpegFrameRecorder recorder;/*** 转FLV格式的头信息<br/>* 如果有第二个客户端播放首先要返回头信息*/private byte[] headers;/*** 保存转换好的流*/private ByteArrayOutputStream stream;/*** 流地址,h264,aac*/private String url;/*** 流输出*/private Map<String, OutputStreamEntity> outEntitys;/*** 当前转换器状态*/private ConverterState state = ConverterState.INITIAL;/*** key用于表示这个转换器*/private String key;/*** 上次更新时间<br/>* 客户端读取是刷新<br/>* 如果没有客户端读取,会在一分钟后销毁这个转换器*/private long updateTime;/*** 转换队列*/private Map<String, Converter> factories;public ConverterFactories(String url, String key, Map<String, Converter> factories) {this.url = url;this.key = key;this.factories = factories;this.updateTime = System.currentTimeMillis();}@Overridepublic void run() {try {//使用ffmpeg抓取流,创建读流器grabber = new FFmpegFrameGrabber(url);//如果为rtsp流,增加配置if ("rtsp".equals(url.substring(0, 4))) {//设置打开协议tcp / udpgrabber.setOption("rtsp_transport", "tcp");//设置未响应超时时间 0.5秒grabber.setOption("stimeout", "500000");//设置缓存大小,提高画质、减少卡顿花屏//grabber.setOption("buffer_size", "1024000");//设置视频比例//grabber.setAspectRatio(1.7777);} else {grabber.setOption("timeout", "500000");}grabber.start();stream = new ByteArrayOutputStream();outEntitys = new ConcurrentHashMap<>();//设置转换状态为打开state = ConverterState.OPEN;//创建转码器recorder = new FFmpegFrameRecorder(stream, grabber.getImageWidth(),grabber.getImageHeight(),grabber.getAudioChannels());//配置转码器recorder.setFrameRate(grabber.getFrameRate());recorder.setSampleRate(grabber.getSampleRate());if (grabber.getAudioChannels() > 0) {recorder.setAudioChannels(grabber.getAudioChannels());recorder.setAudioBitrate(grabber.getAudioBitrate());recorder.setAudioCodec(grabber.getAudioCodec());//设置视频比例//recorder.setAspectRatio(grabber.getAspectRatio());}recorder.setFormat("flv");recorder.setVideoBitrate(grabber.getVideoBitrate());recorder.setVideoCodec(grabber.getVideoCodec());recorder.start(grabber.getFormatContext());//进入写入运行状态state = ConverterState.RUN;if (headers == null) {headers = stream.toByteArray();stream.reset();for (OutputStreamEntity o : outEntitys.values()) {o.getOutput().write(headers);}}int errorNum = 0;//线程运行时while (runing) {//FFmpeg读流压缩AVPacket k = grabber.grabPacket();if (k != null) {try {//转换器转换recorder.recordPacket(k);} catch (Exception e) {}byte[] b = stream.toByteArray();stream.reset();for (OutputStreamEntity o : outEntitys.values()) {if (o.getOutput().size() < (1024 * 1024)) {o.getOutput().write(b);}}errorNum = 0;} else {errorNum++;if (errorNum > 500) {break;}}}} catch (Exception e) {//log.error(e.getMessage(), e);state = ConverterState.ERROR;} finally {closeConverter();//log.info("exit");state = ConverterState.CLOSE;factories.remove(this.key);}}/*** 退出转换*/public void closeConverter() {try {//停止转码器if (null != recorder) {recorder.stop();}//停止、关闭读流器grabber.stop();grabber.close();//关闭转码器if (null != recorder) {recorder.close();}//关闭流if (null != stream) {stream.close();}if (null != outEntitys) {for (OutputStreamEntity o : outEntitys.values()) {o.getOutput().close();}}} catch (Exception e) {e.printStackTrace();//log.error(e.getMessage(), e);}}@Overridepublic String getKey() {return this.key;}@Overridepublic String getUrl() {return this.url;}@Overridepublic ConverterState getConverterState() {return this.state;}@Overridepublic void addOutputStreamEntity(String key, OutputStreamEntity entity) {try {switch (this.state) {case INITIAL:Thread.sleep(100);addOutputStreamEntity(key, entity);break;case OPEN:outEntitys.put(key, entity);break;case RUN:entity.getOutput().write(this.headers);outEntitys.put(key, entity);break;default:break;}} catch (Exception e) {//log.error(e.getMessage(), e);}}@Overridepublic void setUpdateTime(long updateTime) {this.updateTime = updateTime;}@Overridepublic long getUpdateTime() {return this.updateTime;}@Overridepublic void exit() {//设置线程状态为非运行状态,最后会进入finally块关闭读流器、转码器、流this.runing = false;try {this.join();} catch (Exception e) {e.printStackTrace();//log.error(e.getMessage(), e);}}@Overridepublic OutputStreamEntity getOutputStream(String key) {if (outEntitys.containsKey(key)) {return outEntitys.get(key);}return null;}@Overridepublic Map<String, OutputStreamEntity> allOutEntity() {return this.outEntitys;}@Overridepublic void removeOutputStreamEntity(String key) {this.outEntitys.remove(key);}@Overridepublic boolean isRuning() {return runing;}@Overridepublic void setRuning(boolean runing) {this.runing = runing;}@Overridepublic void setState(ConverterState state) {this.state = state;}
}

rtsp流转换器接口

public interface Converter {/*** 设置线程状态* @param state 状态标志*/void setState(ConverterState state);/*** 获取该转换的key*/public String getKey();/*** 获取该转换的url** @return*/public String getUrl();/*** 获取转换的状态** @return*/public ConverterState getConverterState();/*** 添加一个流输出** @param entity*/public void addOutputStreamEntity(String key, OutputStreamEntity entity);/*** 所有流输出** @return*/public Map<String, OutputStreamEntity> allOutEntity();/*** 移除一个流输出** @param key*/public void removeOutputStreamEntity(String key);/*** 设置修改时间** @param updateTime*/public void setUpdateTime(long updateTime);/*** 获取修改时间** @return*/public long getUpdateTime();/*** 退出转换*/public void exit();/*** 启动*/public void start();/*** 获取输出的流** @param key* @return*/public OutputStreamEntity getOutputStream(String key);/*** 判断线程是否在运行* @return boolean*/public boolean isRuning();/*** 设置运行状态* @param runing 运行标志*/public void setRuning(boolean runing);
}

6.输出视频流

public class OutputStreamEntity {public OutputStreamEntity(ByteArrayOutputStream output, long updateTime, String key) {super();this.output = output;this.updateTime = updateTime;this.key = key;}/*** 字节数组输出流*/private ByteArrayOutputStream output;/*** 更新时间*/private long updateTime;/*** key标识*/private String key;public ByteArrayOutputStream getOutput() {return output;}public void setOutput(ByteArrayOutputStream output) {this.output = output;}public long getUpdateTime() {return updateTime;}public void setUpdateTime(long updateTime) {this.updateTime = updateTime;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}}
转换器状态(初始化、打开、关闭、错误、运行)
public enum ConverterState {INITIAL, OPEN, CLOSE, ERROR, RUN
}
public class JsonResult extends HashMap<String, Object> implements Serializable {private static final long serialVersionUID = 1L;public static final int SUCCESS = 200;public JsonResult() {}/*** 返回成功*/public static JsonResult ok() {return ok("操作成功");}/*** 返回成功*/public static JsonResult okFallBack() {return okFallBack("操作成功");}/*** 返回成功*/public JsonResult put(Object obj) {return this.put("data", obj);}/*** 返回成功*/public static JsonResult ok(String message) {return result(200, message);}/*** 降级函数 - 返回成功*/public static JsonResult okFallBack(String message) {return result(205, message);}/*** 返回成功*/public static JsonResult result(int code, String message) {JsonResult jsonResult = new JsonResult();jsonResult.put("timestamp", System.currentTimeMillis());jsonResult.put("status", code);jsonResult.put("message", message);return jsonResult;}/*** 返回失败*/public static JsonResult error() {return error("操作失败");}/*** 返回失败*/public static JsonResult error(String message) {return error(500, message);}/*** 返回失败*/public static JsonResult error(int code, String message) {JsonResult jsonResult = new JsonResult();jsonResult.put("timestamp", System.currentTimeMillis());jsonResult.put("status", code);jsonResult.put("message", message);return jsonResult;}/*** 设置code*/public JsonResult setCode(int code) {super.put("status", code);return this;}/*** 设置message*/public JsonResult setMessage(String message) {super.put("message", message);return this;}/*** 放入object*/@Overridepublic JsonResult put(String key, Object object) {super.put(key, object);return this;}/*** 权限禁止*/public static JsonResult forbidden(String message) {JsonResult jsonResult = new JsonResult();jsonResult.put("timestamp", System.currentTimeMillis());jsonResult.put("status", 401);jsonResult.put("message", message);return jsonResult;}/*@Overridepublic String toString() {return JSONObject.toJSONString(this);}public JSONObject toJSONObject() {return JSONObject.parseObject(toString());}*/}

7.前端展现

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
*{margin: 0px;padding: 0px;overflow: hidden;
}
video{object-fit:fill;width: 100%;height: 100%;
}
</style>
</head>
<body><div class="video-video-div"><video id="video" width="100%" height="100%"></video></div><input type="text" id="url" value="rtsp://127.0.0.1/myvideo"><button id="play">play</button>
</body>
<script type="text/javascript" src="js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="js/flv.min.js"></script>
<script type="text/javascript">var videoObject={init:function(id,src){var self=this;this.src=src;this.id=id;this.flvPlayer = flvjs.createPlayer({type: 'flv',url:src,isLive: true,hasAudio: false,hasVideo: true,enableStashBuffer: true},{});this.flvPlayer.attachMediaElement(document.getElementById(id));this.flvPlayer.load();this.flvPlayer.play();this.reLoad=function(){self.flvPlayer.unload();self.flvPlayer.destroy();window.v=videoObject.init(self.id,self.src);}return this;}}
$(function(){$("#play").click(function(){var src=$("#url").val();if($.trim(src)!=""){if(window.v){window.v.flvPlayer.unload();window.v.flvPlayer.destroy();}window.v=videoObject.init("video","/flv/open/"+window.btoa(src));}	});});//获取地址栏参数
function getParameter(name,win){var params;if(null==win||undefined==win){params = window.location.search;}else{params = win.location.search;}params = params.substring(1, params.length);params = params.split("&");for (var i =0; i < params.length; i++){var items = params[i].split("=");var pname = items[0];if(pname == name){return items[1];}}
}
</script>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/21114.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go语言初学04

Go 语言近年来发展迅速&#xff0c;并且出现了许多优秀的开发框架和组件来支持各种不同的开发需求。以下是一些常用的 Go 语言开发框架和组件&#xff1a; Web 框架 Gin&#xff1a; URL: Gin简单、高效、易用&#xff0c;适合构建高性能的 Web 应用。 Echo&#xff1a; URL: …

crossover软件是干什么的 crossover软件安装使用教程 crossover软件如何使用

CrossOver 以其出色的跨平台兼容性&#xff0c;让用户在Mac设备上轻松运行各种Windows软件&#xff0c;无需复杂的设置或额外的配置&#xff0c;支持多种语言&#xff0c;满足不同国家和地区用户的需求。 CrossOver 软件是干嘛的 使用CrossOver 不必购买Windows 授权&#xf…

Winform ListView 嵌入组合框、布尔、图片等复杂控件

一、Winform ListView 显示复杂控件示例 以下展示了两种实现思路方案。最后修改日期 2024-05 surfsky 1.1 方案一&#xff1a;ListView 结合组合框进行模拟编辑 基本思路 在界面上放置一个lisview和一个combobox&#xff0c;combobox平时是隐藏的。点击listview&#xff0c…

ArrayList源码讲解

ArrayList 底层采用的是数组队列&#xff0c;相当于动态数组。 ArrayList内部使用一个可重新分配的Object数组来存储元素&#xff0c;这个数组会随着元素的添加自动增长以容纳更多的元素&#xff0c;这就是所谓的“动态数组”。 1.实现了RandomAccess接口&#xff0c;可以随机…

rust嵌入式开发之总结

我们用rust开发的新版产品刚刚交付&#xff0c;已经在海上安装测试完毕并顺利投产。终于松了口气&#xff0c;同时也有时间和精力来做个全面的总结了。 这个产品&#xff0c;目前差不多有三版&#xff1a; 第一个版本是用crt-thread写的&#xff0c;投产后出了一个内存泄露的…

521源码-源码论坛-宝塔面板操作日志是存放在哪里的? 如何删除部分日志记录

我们帮别人搭建或者登录了&#xff08;不是自己权属的宝塔面板&#xff09;&#xff0c;会留下登录及操作的日志&#xff0c;我们不想留下这些操作日志&#xff0c;可以通过下面的方法处理掉&#xff0c;以达到无痕迹访问操作的目的&#xff1a; 如图所示的面板操作日志&#…

Python-3.12.0文档解读-内置函数sum()详细说明+记忆策略+常用场景+巧妙用法+综合技巧

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 详细说明 sum(iterable, /, start0) 参数&#xff1a; 返回值&#xff1a; 注意事…

骑砍2霸主MOD开发(10)-游戏大地图(MapScene)制作

一.MapScene中初始化NavMeshFaceID与TerrainType public TerrainType GetFaceTerrainType(PathFaceRecord navMeshFace){switch (navMeshFace.FaceGroupIndex){case 1:return TerrainType.Plain;case 2:return TerrainType.Desert;case 3:return TerrainType.Snow;case 4:retur…

算法优化:空间与时间复杂度的权衡

引言 在软件开发中&#xff0c;算法的性能至关重要。算法的性能通常通过其时间复杂度和空间复杂度来衡量。时间复杂度指的是算法执行时间与输入规模的关系&#xff0c;而空间复杂度则关注算法执行过程中所占用的存储空间。本文将探讨如何权衡这两者&#xff0c;以实现算法的最…

排序方法大汇总

以下所有排序方法均以排升序为例 一.插入排序 1.直接插入排序 1>方法介绍&#xff1a;假定前n个数据有序&#xff0c;将第n1个数据依次与前n个数据相比&#xff0c;若比第i个数据小且比第i-1个数据大则插入两者之间 2>时间复杂度&#xff1a;O(N^2) 空间复杂度&#…

【JS】对象转变成数组

1、Object.keys() 方法&#xff1a; 将对象的键转换为数组 const a { name: aa,age: 18 }; const arr Object.keys(a); console.log(arr); // 输出 [name, age] 2、Object.values() 方法&#xff1a; 将对象的值转换为数组 const a { name: aa,age: 18 }; const arr Obj…

BUUCTF中的密码题目解密

BUUCTF 1.MD5 题目名称就是MD5&#xff0c;这个题目肯定和md5密码有关&#xff0c;下载题目&#xff0c;打开后发现这确实是一个md5加密的密文 Md5在线解密网站&#xff1a;md5在线解密破解,md5解密加密 经过MD5在线解密网站解密后&#xff0c;获取到flag为&#xff1a;flag{…

域名主机服务器配置失败的原因和解决方法

域名主机服务器配置失败的原因可能涉及多个方面&#xff0c;包括域名设置、DNS配置、服务器设置、网络问题等。以下是一些常见的原因和相应的解决方案&#xff1a; 1. DNS配置错误 原因&#xff1a; 域名解析错误&#xff1a;域名没有正确指向服务器的IP地址。 DNS记录未更新&a…

网络编程TCP

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; &#x1f649; 内容推荐:Java网络编程(下)&#x1f649; &#x1f439;今日诗词: 壮士当唱大风哥, 宵小之徒能几何&#xff1f;&#x1f439; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微…

CentOS7单用户模式,救援模式操作记录

CentOS7单用户模式&#xff0c;救援模式操作记录 1. 单用户模式 单用户模式进入不需要密码&#xff0c;无网络连接&#xff0c;拥有root权限&#xff0c;禁止远程登陆。一般用于用于系统维护&#xff0c;例如忘记root密码后可以通过进入单用户模式进行重置。 开机启动&#…

数据结构 实验 1

题目一&#xff1a;用线性表实现文具店的货品管理问题 问题描述&#xff1a;在文具店的日常经营过程中&#xff0c;存在对各种文具的管理问题。当库存文具不足或缺货时&#xff0c;需要进货。日常销售时需要出库。当盘点货物时&#xff0c;需要查询货物信息。请根据这些要求编…

使用低代码系统的意义与价值主要体现在哪里?

使用低代码系统的意义与价值主要体现在以下几个方面&#xff0c;这些观点基于驰骋低代码设计者的专业洞察和行业经验&#xff1a; 快速原型创建&#xff1a; 低代码平台通过提供图形化界面和预构建的模块&#xff0c;极大地加速了系统原型的创建过程。这意味着企业能够更快地验…

60 关于 SegmentFault 的一些场景 (1)

前言 呵呵 此问题主要是来自于 帖子 月经结贴 -- 《Segmentation Fault in Linux》 这里主要也是 结合了作者的相关 case, 来做的一些 调试分享 当然 很多的情况还是 蛮有意思 本文主要问题如下 1. 访问可执行文件中的 只读数据 2. 访问不存在的虚拟地址 3. 访问内核地址…

嵌入式笔试面试刷题(day16)

文章目录 前言一、PWM波形的占空比计算公式是什么&#xff1f;二、ADC和DAC在嵌入式系统中的应用场景有哪些&#xff1f;三、watchdog定时器的作用及其在系统中的使用是什么&#xff1f;四、JTAG接口在嵌入式开发中的作用是什么&#xff1f;五、实时操作系统(RTOS)的任务调度策…

嵌入式工程师人生提质的十大成长型思维分享

大家好,作为一名嵌入式开发者,很多时候,需要考虑个人未来的发展,人生旅途复杂多变,时常面临各种各样的挑战。如何在这个复杂多变的社会中稳步向前,不断成长,成为每个人都应该思考的问题。实际上,思维方式的差异决定我们应对挑战的能力与成长的速度。 第一:寻找自我坐…