庐山派K230_CanMV RTSP服务器API手册从创建到音视频流推送的完整指南最近在庐山派K230开发板上做视频监控项目需要把摄像头画面通过网络推出去用VLC或者手机App就能实时观看。折腾了一圈发现用板载的RTSP服务器模块是最方便的办法。今天我就把自己整理的使用心得和踩过的坑结合官方API手把手教你怎么在K230_CanMV上玩转RTSP流媒体。这篇文章就是一份实战指南我会带你从零开始理解每个API是干什么的怎么用最后组合成一个完整的、能跑起来的推流程序。即使你之前没接触过流媒体跟着步骤走也能搞定。1. RTSP服务器是干什么的为什么需要它在开始敲代码之前咱们先搞明白RTSP是啥。你可以把它想象成一个“网络电视直播台”。你的K230开发板就是电视台它采集摄像头画面视频和麦克风声音音频然后编码成H.264/H.265这样的格式。RTSP服务器呢就是这个电视台的“播出控制中心”。它负责建立连接当你的电脑VLC播放器想看电视时就向这个“控制中心”发起请求。管理会话告诉播放器现在有哪些“频道”会话可以看比如“主摄像头”、“门口监控”。发送数据按照播放器的请求把编码好的音视频数据流通过网络稳定地推送过去。所以用K230_CanMV的multimedia.rtspserver模块我们就能在板子上搭建这样一个“电视台”把本地采集的音视频变成网络流非常方便。2. 核心API详解从创建到推流庐山派K230_CanMV的RTSP功能被封装在multimedia模块里提供了11个主要的API。咱们别被数量吓到其实它们逻辑非常清晰我把它分成四个阶段来理解服务器生命周期管理、会话管理、服务器控制和数据推送。2.1 第一阶段服务器的生与死创建与销毁任何服务都得先启动用完了要关闭RTSP服务器也一样。multimedia.rtspserver_create()这是第一步创建一个RTSP服务器实例。你可以理解为向系统申请了一个“电视台”的牌照和基础框架。参数无。返回值0表示创建成功非0表示失败。实际编程中我们通常不直接调用它而是通过mm.rtsp_server()这个类来实例化它内部会处理好创建逻辑。multimedia.rtspserver_destroy()项目结束或者程序退出时记得销毁服务器释放资源。好比电视台停播要归还牌照和场地。参数无。返回值0表示销毁成功。注意在实际的示例代码中我们通常使用self.rtspserver mm.rtsp_server()来创建对象其生命周期会随着对象的创建和销毁而自动管理一般不需要手动调用create和destroy。2.2 第二阶段配置与初始化拿到“牌照”后得给电视台找个演播厅配置好设备。multimedia.rtspserver_init(port)初始化服务器最关键的是指定它在哪个“网络端口”上监听客户端的连接请求。参数port: RTSP服务器的监听端口号。常用的是554RTSP标准端口或8554很多开源软件用的替代端口。如果端口被占用服务器会启动失败。返回值无。示例# 在端口8554上启动RTSP服务 self.rtspserver.rtspserver_init(8554)multimedia.rtspserver_deinit()与init对应反初始化关闭监听端口清理网络资源。参数无。返回值无。2.3 第三阶段管理“电视频道”会话一个电视台可以有多个频道RTSP服务器也可以管理多个会话Session每个会话对应一个独立的音视频流。multimedia.rtspserver_createsession(session_name, video_type, enable_audio)创建一个流媒体会话也就是开设一个“频道”。参数session_name: 会话名称字符串类型。比如main_camera。客户端连接时需要指定这个名称。video_type: 视频编码类型字符串。目前支持h264或h265。enable_audio: 布尔值True表示这个会话同时包含音频流False表示只有视频。返回值无。示例# 创建一个名为“livingroom”的H.264视频流不带音频 self.rtspserver.rtspserver_createsession(livingroom, h264, False)multimedia.rtspserver_destroysession(session_name)关闭指定的会话频道。参数session_name: 要销毁的会话名称。返回值无。multimedia.rtspserver_getrtspurl(session_name)获取指定会话的RTSP播放地址。有了这个地址播放器才能找到你的流。参数session_name: 会话名称。返回值返回一个字符串即完整的RTSP URL。示例url self.rtspserver.rtspserver_getrtspurl(livingroom) print(url) # 输出类似rtsp://192.168.1.100:8554/livingroom2.4 第四阶段控制播出与推送内容一切准备就绪可以开始“播出”了。multimedia.rtspserver_start()启动RTSP服务器。调用后服务器开始监听网络端口等待客户端连接。参数无。返回值无。multimedia.rtspserver_stop()停止RTSP服务器。所有连接将被断开。参数无。返回值无。multimedia.rtspserver_sendvideodata(session_name, data, size, timestamp)这是核心推送函数把一帧编码后的视频数据如H.264 NALU单元发送到指定的会话。参数session_name: 目标会话名称。data: 视频数据bytes类型。size: 视频数据的大小字节数。timestamp: 时间戳单位通常是毫秒用于音视频同步和播放器缓冲。需要你根据采集帧率递增。返回值无。示例# 假设从编码器获取了一帧数据 frame_data get_encoded_video_frame() frame_size len(frame_data) current_timestamp int(time.time() * 1000) # 获取当前毫秒时间戳 self.rtspserver.rtspserver_sendvideodata(livingroom, frame_data, frame_size, current_timestamp)multimedia.rtspserver_sendaudiodata(session_name, data, size, timestamp)向指定会话发送一帧音频数据如AAC帧。用法和视频发送类似。参数与sendvideodata类似只是数据是音频的。返回值无。3. 手把手实战构建一个完整的RTSP推流程序看完了所有API咱们把它们串起来写一个真正能跑的程序。下面的代码基于官方示例我加了更详细的注释并解释几个关键点。from media.vencoder import * from media.sensor import * from media.media import * import time, os import _thread import multimedia as mm from time import * class RtspServer: def __init__(self, session_nametest, port8554, video_typemm.multi_media_type.media_h264, enable_audioFalse): # 初始化参数 self.session_name session_name # 会话名称客户端通过它连接 self.video_type video_type # 视频编码类型H.264 self.enable_audio enable_audio # 本例暂不启用音频 self.port port # RTSP服务器端口 self.rtspserver mm.rtsp_server() # 创建RTSP服务器对象 self.venc_chn VENC_CHN_ID_0 # 使用0号视频编码通道 self.start_stream False # 推流线程控制标志 self.runthread_over False # 线程结束标志 def start(self): # 1. 初始化媒体流摄像头、编码器 self._init_stream() # 2. 初始化RTSP服务器绑定端口 self.rtspserver.rtspserver_init(self.port) # 3. 创建RTSP会话我们的“频道” self.rtspserver.rtspserver_createsession(self.session_name, self.video_type, self.enable_audio) # 4. 启动RTSP服务器开始监听网络 self.rtspserver.rtspserver_start() # 5. 启动摄像头和编码器开始产生数据 self._start_stream() # 6. 启动一个后台线程专门负责循环获取数据并推流 self.start_stream True _thread.start_new_thread(self._do_rtsp_stream, ()) def stop(self): if not self.start_stream: return # 1. 通知推流线程退出 self.start_stream False # 2. 等待推流线程安全结束 while not self.runthread_over: sleep(0.1) self.runthread_over False # 3. 停止摄像头和编码器 self._stop_stream() # 4. 停止并反初始化RTSP服务器 self.rtspserver.rtspserver_stop() self.rtspserver.rtspserver_deinit() def get_rtsp_url(self): # 获取当前会话的播放地址 return self.rtspserver.rtspserver_getrtspurl(self.session_name) def _init_stream(self): 初始化摄像头传感器和视频编码器 width 1280 height 720 width ALIGN_UP(width, 16) # 宽度需要16字节对齐硬件要求 # 初始化摄像头传感器 self.sensor Sensor() self.sensor.reset() self.sensor.set_framesize(widthwidth, heightheight, alignment12) self.sensor.set_pixformat(Sensor.YUV420SP) # 设置采集格式为YUV420SP # 创建视频编码器实例 self.encoder Encoder() # 为编码通道设置输出缓冲区 self.encoder.SetOutBufs(self.venc_chn, 8, width, height) # 关键步骤将摄像头数据源与编码器通道绑定 # 这建立了“摄像头-编码器”的数据通路 self.link MediaManager.link(self.sensor.bind_info()[src], (VIDEO_ENCODE_MOD_ID, VENC_DEV_ID, self.venc_chn)) # 初始化媒体管理模块 MediaManager.init() # 配置并创建H.264编码器 chnAttr ChnAttrStr(self.encoder.PAYLOAD_TYPE_H264, self.encoder.H264_PROFILE_MAIN, width, height) self.encoder.Create(self.venc_chn, chnAttr) def _start_stream(self): 启动编码器和摄像头 self.encoder.Start(self.venc_chn) # 启动编码器 self.sensor.run() # 启动摄像头采集 def _stop_stream(self): 停止媒体流释放资源 self.sensor.stop() # 停止摄像头 del self.link # 解除摄像头与编码器的绑定 self.encoder.Stop(self.venc_chn) # 停止编码器 self.encoder.Destroy(self.venc_chn) # 销毁编码器 MediaManager.deinit() # 反初始化媒体管理模块 def _do_rtsp_stream(self): 核心推流线程循环获取编码数据并发送给RTSP服务器 try: streamData StreamData() # 用于存放获取的码流数据 while self.start_stream: # 主循环受start_stream标志控制 os.exitpoint() # 检查退出点用于线程安全退出 # 从编码器获取一帧压缩后的视频数据H.264码流 self.encoder.GetStream(self.venc_chn, streamData) # 一帧数据可能包含多个包NALU需要逐个发送 for pack_idx in range(0, streamData.pack_cnt): # 将数据转换为bytes类型 stream_data bytes(uctypes.bytearray_at(streamData.data[pack_idx], streamData.data_size[pack_idx])) # 关键调用将视频包发送到RTSP服务器 # 时间戳这里简单用了1000实际项目应根据帧率计算递增的时间戳 self.rtspserver.rtspserver_sendvideodata(self.session_name, stream_data, streamData.data_size[pack_idx], 1000) # 释放当前帧数据准备获取下一帧 self.encoder.ReleaseStream(self.venc_chn, streamData) except BaseException as e: print(f推流线程异常: {e}) finally: # 线程结束时设置标志并停止服务器 self.runthread_over True self.stop() self.runthread_over True if __name__ __main__: os.exitpoint(os.EXITPOINT_ENABLE) # 启用线程退出点检查 # 1. 创建RTSP服务器对象使用默认参数会话名test, 端口8554, H.264编码 rtspserver RtspServer() # 2. 启动服务器会初始化硬件、创建会话、启动推流线程 rtspserver.start() # 3. 打印出RTSP播放地址用这个地址在VLC等播放器中打开 print(RTSP服务器已启动URL为:, rtspserver.get_rtsp_url()) # 4. 让服务器运行60秒 sleep(60) # 5. 停止服务器释放所有资源 rtspserver.stop() print(推流结束)4. 关键点解析与避坑指南结合上面的代码我总结几个新手容易迷糊和出错的地方1. 数据流管道是关键整个程序的核心是建立摄像头Sensor - 编码器Encoder - RTSP服务器这条数据流。MediaManager.link()这一步就是在硬件层面把前两者连接起来让摄像头采集的原始YUV数据能自动喂给编码器。如果这一步失败后面GetStream就拿不到数据。2. 推流要在独立线程中进行注意看_do_rtsp_stream函数是在一个由_thread.start_new_thread创建的新线程里运行的。这是因为GetStream函数通常是阻塞的等待一帧编码完成如果放在主线程整个程序就卡住不能做别的事了。用后台线程专门负责循环获取和发送数据是标准的做法。3. 时间戳的处理示例代码里发送数据时时间戳固定用了1000。这在实际播放中可能导致问题比如播放速度不对或音画不同步。一个简单的改进方法是start_time time.time() frame_count 0 fps 30 # 假设帧率是30帧 while self.start_stream: # ... 获取stream_data ... timestamp int((frame_count / fps) * 1000) # 计算基于帧序的毫秒时间戳 # 或者使用相对时间 # timestamp int((time.time() - start_time) * 1000) self.rtspserver.rtspserver_sendvideodata(..., timestamp) frame_count 14. 资源的顺序先创建后销毁初始化顺序必须是传感器/编码器 - RTSP服务器初始化 - 创建会话 - 启动服务器。 销毁顺序则要严格相反停止推流线程 - 停止服务器 - 销毁会话 - 反初始化服务器 - 停止编码器和传感器。顺序错了可能导致资源泄露或程序崩溃。5. 如何测试你的RTSP流程序运行并打印出URL如rtsp://192.168.1.100:8554/test后你可以在同一局域网的电脑或手机上测试电脑VLC打开VLC播放器点击“媒体” - “打开网络串流”粘贴上面的URL。手机如VLC for Mobile在App的网络流地址栏输入相同URL。 如果网络通畅且程序正确就能看到实时的摄像头画面了。把这个流程跑通你就掌握了在庐山派K230上进行网络流媒体开发的核心技能。基于这个框架你可以增加音频采集、动态调整分辨率、甚至同时推多个流做出更复杂的应用。
3.9 庐山派K230_CanMV RTSP服务器API手册:从创建到音视频流推送的完整指南
庐山派K230_CanMV RTSP服务器API手册从创建到音视频流推送的完整指南最近在庐山派K230开发板上做视频监控项目需要把摄像头画面通过网络推出去用VLC或者手机App就能实时观看。折腾了一圈发现用板载的RTSP服务器模块是最方便的办法。今天我就把自己整理的使用心得和踩过的坑结合官方API手把手教你怎么在K230_CanMV上玩转RTSP流媒体。这篇文章就是一份实战指南我会带你从零开始理解每个API是干什么的怎么用最后组合成一个完整的、能跑起来的推流程序。即使你之前没接触过流媒体跟着步骤走也能搞定。1. RTSP服务器是干什么的为什么需要它在开始敲代码之前咱们先搞明白RTSP是啥。你可以把它想象成一个“网络电视直播台”。你的K230开发板就是电视台它采集摄像头画面视频和麦克风声音音频然后编码成H.264/H.265这样的格式。RTSP服务器呢就是这个电视台的“播出控制中心”。它负责建立连接当你的电脑VLC播放器想看电视时就向这个“控制中心”发起请求。管理会话告诉播放器现在有哪些“频道”会话可以看比如“主摄像头”、“门口监控”。发送数据按照播放器的请求把编码好的音视频数据流通过网络稳定地推送过去。所以用K230_CanMV的multimedia.rtspserver模块我们就能在板子上搭建这样一个“电视台”把本地采集的音视频变成网络流非常方便。2. 核心API详解从创建到推流庐山派K230_CanMV的RTSP功能被封装在multimedia模块里提供了11个主要的API。咱们别被数量吓到其实它们逻辑非常清晰我把它分成四个阶段来理解服务器生命周期管理、会话管理、服务器控制和数据推送。2.1 第一阶段服务器的生与死创建与销毁任何服务都得先启动用完了要关闭RTSP服务器也一样。multimedia.rtspserver_create()这是第一步创建一个RTSP服务器实例。你可以理解为向系统申请了一个“电视台”的牌照和基础框架。参数无。返回值0表示创建成功非0表示失败。实际编程中我们通常不直接调用它而是通过mm.rtsp_server()这个类来实例化它内部会处理好创建逻辑。multimedia.rtspserver_destroy()项目结束或者程序退出时记得销毁服务器释放资源。好比电视台停播要归还牌照和场地。参数无。返回值0表示销毁成功。注意在实际的示例代码中我们通常使用self.rtspserver mm.rtsp_server()来创建对象其生命周期会随着对象的创建和销毁而自动管理一般不需要手动调用create和destroy。2.2 第二阶段配置与初始化拿到“牌照”后得给电视台找个演播厅配置好设备。multimedia.rtspserver_init(port)初始化服务器最关键的是指定它在哪个“网络端口”上监听客户端的连接请求。参数port: RTSP服务器的监听端口号。常用的是554RTSP标准端口或8554很多开源软件用的替代端口。如果端口被占用服务器会启动失败。返回值无。示例# 在端口8554上启动RTSP服务 self.rtspserver.rtspserver_init(8554)multimedia.rtspserver_deinit()与init对应反初始化关闭监听端口清理网络资源。参数无。返回值无。2.3 第三阶段管理“电视频道”会话一个电视台可以有多个频道RTSP服务器也可以管理多个会话Session每个会话对应一个独立的音视频流。multimedia.rtspserver_createsession(session_name, video_type, enable_audio)创建一个流媒体会话也就是开设一个“频道”。参数session_name: 会话名称字符串类型。比如main_camera。客户端连接时需要指定这个名称。video_type: 视频编码类型字符串。目前支持h264或h265。enable_audio: 布尔值True表示这个会话同时包含音频流False表示只有视频。返回值无。示例# 创建一个名为“livingroom”的H.264视频流不带音频 self.rtspserver.rtspserver_createsession(livingroom, h264, False)multimedia.rtspserver_destroysession(session_name)关闭指定的会话频道。参数session_name: 要销毁的会话名称。返回值无。multimedia.rtspserver_getrtspurl(session_name)获取指定会话的RTSP播放地址。有了这个地址播放器才能找到你的流。参数session_name: 会话名称。返回值返回一个字符串即完整的RTSP URL。示例url self.rtspserver.rtspserver_getrtspurl(livingroom) print(url) # 输出类似rtsp://192.168.1.100:8554/livingroom2.4 第四阶段控制播出与推送内容一切准备就绪可以开始“播出”了。multimedia.rtspserver_start()启动RTSP服务器。调用后服务器开始监听网络端口等待客户端连接。参数无。返回值无。multimedia.rtspserver_stop()停止RTSP服务器。所有连接将被断开。参数无。返回值无。multimedia.rtspserver_sendvideodata(session_name, data, size, timestamp)这是核心推送函数把一帧编码后的视频数据如H.264 NALU单元发送到指定的会话。参数session_name: 目标会话名称。data: 视频数据bytes类型。size: 视频数据的大小字节数。timestamp: 时间戳单位通常是毫秒用于音视频同步和播放器缓冲。需要你根据采集帧率递增。返回值无。示例# 假设从编码器获取了一帧数据 frame_data get_encoded_video_frame() frame_size len(frame_data) current_timestamp int(time.time() * 1000) # 获取当前毫秒时间戳 self.rtspserver.rtspserver_sendvideodata(livingroom, frame_data, frame_size, current_timestamp)multimedia.rtspserver_sendaudiodata(session_name, data, size, timestamp)向指定会话发送一帧音频数据如AAC帧。用法和视频发送类似。参数与sendvideodata类似只是数据是音频的。返回值无。3. 手把手实战构建一个完整的RTSP推流程序看完了所有API咱们把它们串起来写一个真正能跑的程序。下面的代码基于官方示例我加了更详细的注释并解释几个关键点。from media.vencoder import * from media.sensor import * from media.media import * import time, os import _thread import multimedia as mm from time import * class RtspServer: def __init__(self, session_nametest, port8554, video_typemm.multi_media_type.media_h264, enable_audioFalse): # 初始化参数 self.session_name session_name # 会话名称客户端通过它连接 self.video_type video_type # 视频编码类型H.264 self.enable_audio enable_audio # 本例暂不启用音频 self.port port # RTSP服务器端口 self.rtspserver mm.rtsp_server() # 创建RTSP服务器对象 self.venc_chn VENC_CHN_ID_0 # 使用0号视频编码通道 self.start_stream False # 推流线程控制标志 self.runthread_over False # 线程结束标志 def start(self): # 1. 初始化媒体流摄像头、编码器 self._init_stream() # 2. 初始化RTSP服务器绑定端口 self.rtspserver.rtspserver_init(self.port) # 3. 创建RTSP会话我们的“频道” self.rtspserver.rtspserver_createsession(self.session_name, self.video_type, self.enable_audio) # 4. 启动RTSP服务器开始监听网络 self.rtspserver.rtspserver_start() # 5. 启动摄像头和编码器开始产生数据 self._start_stream() # 6. 启动一个后台线程专门负责循环获取数据并推流 self.start_stream True _thread.start_new_thread(self._do_rtsp_stream, ()) def stop(self): if not self.start_stream: return # 1. 通知推流线程退出 self.start_stream False # 2. 等待推流线程安全结束 while not self.runthread_over: sleep(0.1) self.runthread_over False # 3. 停止摄像头和编码器 self._stop_stream() # 4. 停止并反初始化RTSP服务器 self.rtspserver.rtspserver_stop() self.rtspserver.rtspserver_deinit() def get_rtsp_url(self): # 获取当前会话的播放地址 return self.rtspserver.rtspserver_getrtspurl(self.session_name) def _init_stream(self): 初始化摄像头传感器和视频编码器 width 1280 height 720 width ALIGN_UP(width, 16) # 宽度需要16字节对齐硬件要求 # 初始化摄像头传感器 self.sensor Sensor() self.sensor.reset() self.sensor.set_framesize(widthwidth, heightheight, alignment12) self.sensor.set_pixformat(Sensor.YUV420SP) # 设置采集格式为YUV420SP # 创建视频编码器实例 self.encoder Encoder() # 为编码通道设置输出缓冲区 self.encoder.SetOutBufs(self.venc_chn, 8, width, height) # 关键步骤将摄像头数据源与编码器通道绑定 # 这建立了“摄像头-编码器”的数据通路 self.link MediaManager.link(self.sensor.bind_info()[src], (VIDEO_ENCODE_MOD_ID, VENC_DEV_ID, self.venc_chn)) # 初始化媒体管理模块 MediaManager.init() # 配置并创建H.264编码器 chnAttr ChnAttrStr(self.encoder.PAYLOAD_TYPE_H264, self.encoder.H264_PROFILE_MAIN, width, height) self.encoder.Create(self.venc_chn, chnAttr) def _start_stream(self): 启动编码器和摄像头 self.encoder.Start(self.venc_chn) # 启动编码器 self.sensor.run() # 启动摄像头采集 def _stop_stream(self): 停止媒体流释放资源 self.sensor.stop() # 停止摄像头 del self.link # 解除摄像头与编码器的绑定 self.encoder.Stop(self.venc_chn) # 停止编码器 self.encoder.Destroy(self.venc_chn) # 销毁编码器 MediaManager.deinit() # 反初始化媒体管理模块 def _do_rtsp_stream(self): 核心推流线程循环获取编码数据并发送给RTSP服务器 try: streamData StreamData() # 用于存放获取的码流数据 while self.start_stream: # 主循环受start_stream标志控制 os.exitpoint() # 检查退出点用于线程安全退出 # 从编码器获取一帧压缩后的视频数据H.264码流 self.encoder.GetStream(self.venc_chn, streamData) # 一帧数据可能包含多个包NALU需要逐个发送 for pack_idx in range(0, streamData.pack_cnt): # 将数据转换为bytes类型 stream_data bytes(uctypes.bytearray_at(streamData.data[pack_idx], streamData.data_size[pack_idx])) # 关键调用将视频包发送到RTSP服务器 # 时间戳这里简单用了1000实际项目应根据帧率计算递增的时间戳 self.rtspserver.rtspserver_sendvideodata(self.session_name, stream_data, streamData.data_size[pack_idx], 1000) # 释放当前帧数据准备获取下一帧 self.encoder.ReleaseStream(self.venc_chn, streamData) except BaseException as e: print(f推流线程异常: {e}) finally: # 线程结束时设置标志并停止服务器 self.runthread_over True self.stop() self.runthread_over True if __name__ __main__: os.exitpoint(os.EXITPOINT_ENABLE) # 启用线程退出点检查 # 1. 创建RTSP服务器对象使用默认参数会话名test, 端口8554, H.264编码 rtspserver RtspServer() # 2. 启动服务器会初始化硬件、创建会话、启动推流线程 rtspserver.start() # 3. 打印出RTSP播放地址用这个地址在VLC等播放器中打开 print(RTSP服务器已启动URL为:, rtspserver.get_rtsp_url()) # 4. 让服务器运行60秒 sleep(60) # 5. 停止服务器释放所有资源 rtspserver.stop() print(推流结束)4. 关键点解析与避坑指南结合上面的代码我总结几个新手容易迷糊和出错的地方1. 数据流管道是关键整个程序的核心是建立摄像头Sensor - 编码器Encoder - RTSP服务器这条数据流。MediaManager.link()这一步就是在硬件层面把前两者连接起来让摄像头采集的原始YUV数据能自动喂给编码器。如果这一步失败后面GetStream就拿不到数据。2. 推流要在独立线程中进行注意看_do_rtsp_stream函数是在一个由_thread.start_new_thread创建的新线程里运行的。这是因为GetStream函数通常是阻塞的等待一帧编码完成如果放在主线程整个程序就卡住不能做别的事了。用后台线程专门负责循环获取和发送数据是标准的做法。3. 时间戳的处理示例代码里发送数据时时间戳固定用了1000。这在实际播放中可能导致问题比如播放速度不对或音画不同步。一个简单的改进方法是start_time time.time() frame_count 0 fps 30 # 假设帧率是30帧 while self.start_stream: # ... 获取stream_data ... timestamp int((frame_count / fps) * 1000) # 计算基于帧序的毫秒时间戳 # 或者使用相对时间 # timestamp int((time.time() - start_time) * 1000) self.rtspserver.rtspserver_sendvideodata(..., timestamp) frame_count 14. 资源的顺序先创建后销毁初始化顺序必须是传感器/编码器 - RTSP服务器初始化 - 创建会话 - 启动服务器。 销毁顺序则要严格相反停止推流线程 - 停止服务器 - 销毁会话 - 反初始化服务器 - 停止编码器和传感器。顺序错了可能导致资源泄露或程序崩溃。5. 如何测试你的RTSP流程序运行并打印出URL如rtsp://192.168.1.100:8554/test后你可以在同一局域网的电脑或手机上测试电脑VLC打开VLC播放器点击“媒体” - “打开网络串流”粘贴上面的URL。手机如VLC for Mobile在App的网络流地址栏输入相同URL。 如果网络通畅且程序正确就能看到实时的摄像头画面了。把这个流程跑通你就掌握了在庐山派K230上进行网络流媒体开发的核心技能。基于这个框架你可以增加音频采集、动态调整分辨率、甚至同时推多个流做出更复杂的应用。