当前位置: 首页 > 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页面查看录像文件,首页还是挺好看的:
首页
文件管理器录像文件
录像文件可以直接点击播放:

通过手机查看

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

播放

相关文章:

  • RT-Thread 深入系列 Part 5:物联网与网络应用实战
  • 51c视觉~合集37
  • 使用FastAPI微服务在AWS EKS上实现AI会话历史的管理
  • 计算机网络 4-2-2 网络层(IPv4)
  • 解锁 DevOps 新境界 :使用 Flux 进行 GitOps 现场演示 – 自动化您的 Kubernetes 部署
  • 【RT-Thread Studio】nor flash配置Fal分区
  • Windows:Powershell的使用
  • 程序代码篇---esp32视频流处理
  • Taro 编译不平不同平台小程序
  • 《类和对象(中)》
  • 分布式事务快速入门
  • Ubuntu 与 Windows 双系统环境下 NTFS 分区挂载教程
  • Autoware message_filters::Synchronizer链接错误问题
  • 如何删除网上下载的资源后面的文字
  • 数字孪生实战笔记(1)数字孪生的含义、应用及技术体系
  • zdir3个人网盘dockerfile打包
  • 深入解析:如何基于开源p-net快速开发Profinet从站服务
  • C# WinForm DataGridView 非常频繁地更新或重新绘制慢问题及解决
  • WPF 性能 UI 虚拟化 软件开发人员的思考
  • gvm安装go报错ERROR: Failed to use installed version
  • 玉渊谭天丨中方为何此时同意与美方接触?出于这三个考虑
  • 首家股份行旗下AIC来了,兴银金融资产投资有限公司获批筹建
  • 三大交易所多举措支持科创债再扩容,约160亿证券公司科创债有望近期落地
  • 印观察|印巴战火与莫迪政府三重冒险:南亚火药桶已至临界点
  • 公积金利率降至历史低位,百万房贷30年省5万
  • 巴方称印军发动24起袭击,巴境内6处地点遭袭致8人死亡