当前位置: 首页 > news >正文

海纳思(Hi3798MV300)机顶盒遇到海思摄像头

海纳思机顶盒遇到海思摄像头,正好家里有个海思Hi3516的摄像头模组开发板,结合机顶盒来做个录像。

准备工作

  1. 海纳斯机顶盒
  2. 摄像机模组
  3. 两根网线、两个电源、路由器
  4. 一块64G固态硬盘

摄像机模组和机顶盒都接入路由器的LAN口,确保网络正常通信。
道具
摄像机模组

调试录像

摄像机模组

摄像机模组里的程序其实是基于海思的SDK里的demo稍作修改而成,没有做太复杂的功能,只加入了RTSP,对外提供RTSP接口服务。
这里用的rtsp服务的库代码比较好用,源码链接:https://gitee.com/fensnote/RtspServer

在电脑上用VLC测试拉流播放:
VLC

海纳斯盒子录像

关于录像,这里只是实现简单的文件存储、循环覆盖,并不是专业的录像,专业录像里会做的比较复杂。

  1. 直接用Ffmpeg命令行录取数据到文件里,为了方便播放保存为MP4文件。
  2. 写代码实现rtsp拉流存储,可以自己定义传参。
Ffmpeg录像

这个比较简单,一条命令即可,不过直接采用命令录像没法指定实现循环覆盖,要想实现可以再写个脚本取定时检测录像文件的个数。
首先需要先下载安装Ffmpeg:

sudo apt install ffmpeg

安装日志
我这里已经安装过了。
接下来就用可以执行录像了:

ffmpeg -rtsp_transport tcp -i rtsp://192.168.2.168:41667/live -c copy -f segment -segment_time 60 stream_piece_%d.mp4

这条命令里是指定了录像时长60秒,即一分钟切换一个文件。
ffmpeg
如下截图,录取一分钟后已切换文件,1分钟录像数据15M,数据量挺大了:
录像

上传上来播放一下看看:
上传
播放:
使用win11的系统播放器就可以播放
播放

写个代码录像

这里选用了go语言来写这个录像代码,是因为go语言的音视频、网络相关的库实在太多,比较好用,代码量也不大,可以提需求让AI去写,AI写的基本上稍作修改测试几次就可以用了。
Go还有个好处就是静态编译,真正的跨平台,一次编译,CPU架构一样都可以运行,感觉缺点就是可执行文件比较大。

这里采用的gortsplib,源码地址:https://gitee.com/fensnote/gortsplib.git

可以基于gortsplib/examples下的client-play-format-h264-save-to-disk示例代码做修改:
复制
我复制了命名为client-play-format-h264-save-to-disk-file,在这里修改,下面代码是调试完成的代码:

package mainimport ("flag""fmt""log""os""os/signal""syscall""time""github.com/bluenviron/gortsplib/v4""github.com/bluenviron/gortsplib/v4/pkg/base""github.com/bluenviron/gortsplib/v4/pkg/format""github.com/bluenviron/gortsplib/v4/pkg/format/rtph264""github.com/pion/rtp"
)const (filePrefix = "rec"    // 文件名前缀fileSuffix = ".mp4"   // 文件名后缀
)func main() {// Define command line flagsrtspURL := flag.String("r", "", "RTSP URL")maxFilesPtr := flag.Int("c", 0, "文件数")startFileNumPtr := flag.Int("s", 0, "起始文件编号")durationPtr := flag.Int("t", 60, "单个文件录像时长")modePtr := flag.String("m", "loop", "录像模式,单次模式:\"once\",循环模式:\"loop\", 注意要加双引号")// Parse command line flagsflag.Parse()// Check if the required arguments are providedif *rtspURL == "" || *maxFilesPtr == 0 { //|| *startFileNumPtr == 0 	flag.PrintDefaults() // Print usage informationlog.Fatal("Missing required command line arguments")}if *startFileNumPtr < 0 || *startFileNumPtr > *maxFilesPtr {log.Fatalf("起始文件编号必须是0~%d", *maxFilesPtr)}// Check if the RTSP URL is validu, err := base.ParseURL(*rtspURL)if err != nil {log.Fatalf("无效的RTSP URL: %v", err)}c := gortsplib.Client{}// Connect to the servererr = c.Start(u.Scheme, u.Host)if err != nil {log.Fatalf("连接 RTSP server 失败: %v", err)}
//	defer c.Close()// Find available mediasdesc, _, err := c.Describe(u)if err != nil {log.Fatalf("Failed to describe RTSP stream: %v", err)}// Find the H264 media and formatvar forma *format.H264medi := desc.FindFormat(&forma)if medi == nil {log.Fatal("H264 media not found")}// Setup RTP -> H264 decoderrtpDec, err := forma.CreateDecoder()if err != nil {log.Fatalf("Failed to create H264 decoder: %v", err)}var mpegtsMuxer *mpegtsMuxervar fileCounter intvar recordingStartTime time.Time// var bakPts int64;// var sub int// Create the first file immediately when the program startsfileCounter = *startFileNumPtrnewFileName := fmt.Sprintf("%s%03d%s", filePrefix, fileCounter, fileSuffix)mpegtsMuxer = newMpegtsMuxer(newFileName, forma.SPS, forma.PPS)err = mpegtsMuxer.initialize()if err != nil {log.Fatalf("Failed to initialize MPEG-TS muxer: %v", err)}log.Printf("New file created: %s", newFileName)recordingStartTime = time.Now()// Setup a single media_, err = c.Setup(desc.BaseURL, medi, 0, 0)if err != nil {log.Fatalf("Failed to setup media: %v", err)}// Create a ticker to create a new file based on the specified durationduration := time.Duration(*durationPtr) * time.Secondticker := time.NewTicker(duration)duration = duration + 100000000 // Add 200ms to the duration to ensure the ticker fires after the durationdefer ticker.Stop()// bakPts = 0// Called when a RTP packet arrivesc.OnPacketRTP(medi, forma, func(pkt *rtp.Packet) {// Decode timestamppts, ok := c.PacketPTS2(medi, pkt)if !ok {//log.Printf("Waiting for timestamp")pts = int64(pkt.Timestamp)//return}// if bakPts == 0 {// 	bakPts = pts// }// Extract access unit from RTP packetsau, err := rtpDec.Decode(pkt)if err != nil {if err != rtph264.ErrNonStartingPacketAndNoPrevious && err != rtph264.ErrMorePacketsNeeded {log.Printf("ERR: %v", err)}return}// sub = (int)(pts - bakPts)/100000// Encode the access unit into MPEG-TSif mpegtsMuxer != nil {err = mpegtsMuxer.writeH264(au, pts)if err != nil {log.Printf("ERR: %v", err)return}// log.Printf("Saved TS packet, pts: %d,sub:%d",pts,sub)}// Check if it's time to create a new file or exit// if sub >= *durationPtr {if time.Since(recordingStartTime) >= duration {mpegtsMuxer.close()if *modePtr == "once" {log.Println("Recording duration reached, exiting...")c.Close() // Close the RTSP client connectionos.Exit(0) // Exit the program immediately} else {fileCounter = (fileCounter + 1) % *maxFilesPtrnewFileName := fmt.Sprintf("%s%03d%s", filePrefix, fileCounter, fileSuffix)mpegtsMuxer = newMpegtsMuxer(newFileName, forma.SPS, forma.PPS)err = mpegtsMuxer.initialize()if err != nil {log.Fatalf("ERR: %v", err)c.Close() // Close the RTSP client connectionos.Exit(-1) // Exit the program immediately}log.Printf("New file created: %s", newFileName)recordingStartTime = time.Now()//bakPts = pts}}})// Start playing_, err = c.Play(nil)if err != nil {log.Fatalf("Failed to play RTSP stream: %v", err)}// Wait for interrupt signal or recording durationsigChan := make(chan os.Signal, 1)signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)go func() {for {select {case <-ticker.C:if *modePtr == "once" {log.Println("Recording duration reached, exiting...")c.Close()os.Exit(0)}case <-sigChan:log.Println("Interrupt signal received, exiting...")c.Close()os.Exit(0)}}}()// Block main goroutine foreverselect {}
}

代码编译

export GOOS=linux
export GOARCH=arm
export GOARM=5
#export CGO_ENABLED=1go build -ldflags '-s -w'

录像测试

 vrec-c int文件数-m string录像模式,单次模式:"once",循环模式:"loop", 注意要加双引号 (default "loop")-r stringRTSP URL-s int起始文件编号-t int单个文件录像时长 (default 60)
2025/05/10 09:30:59 Missing required command line arguments
#录像命令参数:
vrec -c 1200 -m "loop" -s 0 -t 60  -r rtsp://192.168.2.168:41667/live

录像文件播放
录像文件查看,这是录了一晚上的,文件比较多:
测试

通过电脑查看

在海纳思的内置web页面查看录像文件,首页还是挺好看的:
首页
文件管理器录像文件
录像文件可以直接点击播放:

通过手机查看

手机
文件管理录像列表
点击播放

播放

http://www.xdnf.cn/news/378703.html

相关文章:

  • 贪心算法专题(Part1)
  • AI大模型学习十七、利用Dify搭建 AI 图片生成应用
  • STL-to-ASCII-Generator 实用教程
  • SpringBoot2集成xxl-job详解
  • 大模型微调指南之 LLaMA-Factory 篇:一键启动LLaMA系列模型高效微调
  • 差动讯号(3)弱耦合与强耦合
  • Linux数据库篇、第一章_01MySQL5.7的安装部署
  • Java基础 5.10
  • 致远A8V5-9.0安装包(包含信创版)【附百度网盘链接】
  • LeetCode 热题 100 24. 两两交换链表中的节点
  • 计算机网络八股文--day1
  • suricata之日志截断
  • Python实例题:Python协程详解公开课
  • JAVA练习题(1) 卖飞机票
  • vue开发用户注册功能
  • 【入门】数字走向I
  • 求数组中的两数之和--暴力/哈希表
  • 构建休闲企业服务实训室:融合凯禾瑞华产品打造产教融合新生态
  • 红黑树删除的实现与四种情况的证明
  • 北京导游资格证备考单选题题库及答案【2025年】
  • 大型旋转机械信号分解算法模块
  • 猿人学第十二题-js入门
  • c++——二叉树进阶
  • SAP Commerce(Hybris)开发实战(一)
  • 《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-《打砖块:向量反射与实时物理模拟》MATLAB教程
  • Python-77:古生物DNA序列血缘分析
  • 网络世界的“快递站”:深入浅出OSI七层模型
  • Python 包管理新选择:uv
  • 便签软件哪个好用?2025年桌面记事本便签软件推荐大全
  • 【ospf综合实验】