
【免费下载链接】rocketride-serverHigh-performance AI pipeline engine with a C core and 50 Python-extensible nodes. Build, debug, and scale LLM workflows with 13 model providers, 8 vector databases, and agent orchestration, all from your IDE. Includes VS Code extension, TypeScript/Python SDKs, and Docker deployment.项目地址https://gitcode.com/gh_mirrors/ro/rocketride-server点击查看免费下载media_inspect是 RocketRiderocketride-server 仓库nodes/下的 Python 扩展节点中用于处理流式音频/视频的专业节点它接收以 BEGIN/WRITE/END 三段式到达的媒体流在输入对象关闭时完成处理支持元数据探测probe、静音/RMS 响度测量levels与按时间点抽取 JPEG 静帧stills三种操作模式。读完本文你可以理解该节点的流生命周期与隔离机制、完整配置参数及其在源码中的钳制规则、三种mode的请求结构与返回格式并学会用仓库自带的 example.pipe 把它接入 webhook → parse → 处理 → 响应的真实管道。节点定位只处理流不碰存储根据 README 的定义media_inspect的核心行为边界非常明确接收 BEGIN/WRITE/END 流式媒体输入对象关闭时才真正处理临时文件仅私有于当前对象在“处理完成、失败或取消清理”三种路径之后统一释放节点从不调用账号存储、不抓取 URL、不保留持久源缓存——结果持久化必须由下游节点完成。这个“只过手、不落地”的契约在 IInstance.py 中可以得到印证MediaInstance类注释写明 “Own temporary files until closing; downstream nodes own persistence”其close()方法L218-L228会关闭所有进行中的流文件、释放资源并销毁Workspace且可被重复调用——这正是失败/取消路径下也能干净释放临时盘的实现保障。输入校验的源码细节在 instance.py 的_receive方法中BEGIN 阶段会依次检查同一 lane 上存在未结束的旧流 → 抛Previous media stream did not finish流描述符必须是 JSON 对象name取自描述符的name或resource_name重名拒绝与已接收或进行中的流重名即失败每对象最多 128 个输入流len(self._inputs) len(self._active) 128时拒绝名称以保留目录outputs/开头会被拒绝声明的size若为非负整数且超过剩余字节预算在 BEGIN 即失败。WRITE 阶段则在每次写入前再次检查剩余预算L124-L127单块超出剩余max_input_mb预算、或累计字节超过声明size都会立即报错END 时若收到 0 字节或实际字节数与声明不符则报Empty or truncated media stream。这说明 README 中“输入限制在每块写入前强制执行即使未声明 size”不是纸面约定而是逐块落地的检查。Lane 拓扑两条输入 lane三类输出README 给出的 lane 矩阵如下配置时可原样用于核对管道连线Lane inLane out说明videotextJSON 测量/报告stills 模式下附带图片名标记videoanswers结构化结果 manifestvideoimage命名的 JPEG 流audiotextJSON 测量/报告stills 模式下附带图片名标记audioanswers结构化结果 manifestaudioimage命名的 JPEG 流从源码看输出分发逻辑在 instance.pyclosing()会强制要求至少连接了text或answers消费者否则抛Connect a text or answers consumer而imagelane 仅在 stills 模式使用且需要独立连接图片 sink。answers输出通过Answer(expectJsonTrue)承载完整结果对象text输出则是json.dumps后的同一份 payloadL200-L208。配置参数profile 覆盖 硬钳制README 指出所有覆盖项写在所选 profile 块中chunk_kb控制输出块大小钳制到 64–8192 KB输入字节增量落盘到临时磁盘event_type命名进度事件且进度不写入任何文件。IGlobal.py 定义了默认值并在beginGlobal中做类型转换与钳制DEFAULTS { request: {}, event_type: media_inspect, chunk_kb: 1024, max_input_mb: 16384, silence_db: -40.0, silence_ms: 700, peak_ms: 100, scene_threshold: 0.35, }注意源码中的钳制比 README 正文更精确chunk_bytes max(64, min(8192, chunk_kb)) * 1024max_input_mb钳制到 1–1048576peak_ms最小 10silence_ms最小 1。profile 的读取由 config.py 的load_node_config完成管线 profile 值按默认值的类型int/float/bool/str逐键覆盖非法数值静默回退默认值。完整 Schema 表与 README 生成区 一致FieldTypeDescriptionDefaultmedia_inspect.chunk_kbnumber流式输出块大小KB钳制 64–81921024media_inspect.event_typestring本管道发出的进度事件名media_inspectmedia_inspect.max_input_mbnumber每对象累计输入上限MiB含全部资产钳制 1–1048576未声明 size 也强制16384media_inspect.peak_msnumber单个响度桶长度ms最小 10100media_inspect.profilestring配置 profile 名defaultmedia_inspect.requeststring操作请求JSON 字符串probe、levelsrange、ranges、scan、scan_scenes或 stillsstills 数组{}media_inspect.scene_thresholdnumber镜头切换需跨越的场景分数阈值0.35media_inspect.silence_dbnumber静音阈值dB-40media_inspect.silence_msnumber值得报告的最短静音时长ms700进度事件通过 instance.py 的_status()以 SSE 形式推给引擎监控monitorSSE携带schema_version、node、stage及自由字段如stills、scanning、stills_done等 stage投递失败只记 debug 日志不影响媒体输出。request一个 JSON 字符串决定操作模式request是编码为字符串的 JSON 对象mode选择操作input_name可选地指定接收到的媒体描述符名。默认是probe源必须以媒体流形式到达——单独的存储路径不构成输入。README 特别强调顶层的write_to、probe_to、status_to、report_to会被拒绝。源码中对应 instance.py 的_request()LEGACY_DESTINATIONS {write_to, probe_to, status_to, report_to} # ... if LEGACY_DESTINATIONS.intersection(request): raise ValueError(Storage destinations are unsupported; connect a downstream sink) mode request.get(mode, self.modes[0]) if mode not in self.modes: raise ValueError(mode must be one of: , .join(self.modes))modes (probe, levels, stills)非法 mode 直接报错。源解析规则closingL151-L161为给了input_name就按名取只有一条音视频流则自动使用多条则必须显式指定否则报Multiple media streams require input_name。另外_processL176-L178明确约束本处理器每个对象只接受恰好 1 条媒体流。probe一次拿到全部元数据probe返回时长、显示/编码尺寸、像素宽高比、编解码器、帧率、音频声道与采样率等。返回结构由 media.py 的probe_payload组装{ schema_version: 1, kind: media_probe, mode: probe, duration_ms: 123456, width: 853, height: 480, sar: 1.185185, coded_width: 720, coded_height: 480, fps: 29.97, has_video: true, has_audio: true, size: 12345678, video_codec: h264, audio_codec: aac, audio_channels: 2, audio_sample_rate: 48000, container: mov,mp4,m4a,3gp,3g2,mj2, context: { mode: probe, source: source.media } }值得注意的实现细节width/height是显示方形像素尺寸——各向异性像素源DV、HDV、4:3 广播母带如 720×480 SAR 32:27会先经display_dims换算sar与coded_width/coded_height随行携带调用方无需二次探测即可区分方形与非方形源media.py。探测主路径用 PyAVprobe()L323-L374PyAV 缺失时回退到解析ffmpeg -i输出_probe_ffmpegL258-L320子进程超时 60 秒——这正是 README 所说“元数据子进程最大 60 秒超时”的实现。levels静音、RMS 峰值与镜头切换levels在一次请求中做三类全区间扫描加一类按需测量levels.py 模块 docstring 有完整说明rangestart_ms-end_ms也接受[start, end]形式见 parse_range省略时默认全时长rangesJSON 数组[[a, b], …]ms只对指定窗口测 RMSdBFS每个窗口一次短解码不触碰文件其余部分scan: no跳过全区间扫描此时不产生任何解码scan_scenes: no只跳过镜头切换扫描场景检测是全扫描中最贵的一步silence_db、silence_ms、peak_ms、scene_threshold均可在 request 内覆盖同名 profile 参数IInstance.py。测量管线scan_levelssilences区间先解码成 16 kHz 单声道 PCM WAVANALYSIS_RATE 16000再跑 ffmpegsilencedetectkeep_pause_ms0报告原始静音而非“可安全剪掉的静音”peaks同一 WAV 按peak_ms分桶计算 RMS归一化到最响桶0..1peaks[i]对应start_ms i*peak_ms起的桶——绘图与“候选剪辑点两侧是否有声音”的判断都靠它scenes对缩放到 320 px 宽的降采样解码跑场景分数超过scene_threshold的时间戳即镜头切换点rangesmeasure_ranges逐窗口测 dBFS测不到的窗口返回None而不是编造数字。所有时间都在源时钟上扫描先 seek 到区间起点报告前把区间偏移加回。无画面的区间不报 scenes无声的区间不报 silences/peaks——“这是回答不是失败”。scan: no与scan_scenes: no对长录制的成本差异在源码注释中被量化为“场景检测约每分钟对应 10 分钟画面”的量级差是长文件上“秒级与分钟级”的区别。stills按时间点抽 JPEG 并走 image lanestills模式下stills是[{id, t_ms, crop, width}]数组crop为显示像素下的[x, y, width, height]quality设置 JPEG 量化值钳制 2–31缺省或 0 用默认值 2见 IInstance.py 的max(2, min(31, quality))与media_lib.STILL_QUALITY 2。README 给的示例可直接使用{mode:stills,stills:[{id:poster,t_ms:1000,width:320}]}行为要点IInstance.py 的_stills与 media.py逐条容错无效条目只进failed列表其余条目继续执行——“一条坏 crop 不再拖垮整批静帧”crop 自动钳位crop_windowmedia.py L73-L88把越界框收回画面内部x/y钳到[0, w-cw]/[0, h-ch]宽高至少 1 pxid 必须是不含路径分隔符的普通文件名still_entry校验/、\、.、..与控制字符因为它直接作为输出流名无视频轨的文件该条计入failed输出必须接 image sink_image_listenerL104-L109检测hasListener(image)没有监听者时抛Connect an image sink for extracted stills命名标记机制每张图在 image lane 上以独立流BEGIN/WRITE/END发出而名字先在 text lane 上写一行标记再发图。源码注释解释了原因response 节点会把一次运行写入 image lane 的全部字节聚合进同一个输入对象名下的 text 缓冲image lane 的描述符名到不了读 text 的调用方——所以标记行写在 text 上是“名字能活下来”的唯一途径。这是理解该节点与下游 response 节点配合的关键细节。单帧抽取cut_still的时间精度规则在 picture_pass 中有专门论述媒体元素在时刻 t 显示的是pts t的帧而 ffmpeg-ss t返回pts t的帧——因此 seek 回退一个网格步长、用fps滤镜以start_time锚定并rounddown配合settb1/1000000与 0.1 ms 的FRAME_EPSILON_S使输出帧与“播放到该毫秒时你看到的帧”逐帧一致。多帧 JPEG 流image2pipe/mjpeg按 SOI/EOI 标记精确切分split_jpegsL94-L109因为熵编码数据中 0xFF 后必跟 0x00 或重启标记切分点不会误判。超时与资源边界README 的“Stream lifecycle and limits”一节列出的边界在源码中逐项可查FFmpeg 编码超时环境变量ROCKETRIDE_MEDIA_FFMPEG_TIMEOUT限制每次 FFmpeg 编码默认 3600 秒允许大于 0 到 86400非法值显式失败而非静默回退。实现见 media.py非数值、0、86400或非有限数都抛ValueError。测试 test_review_regressions.py 中test_ffmpeg_timeout_is_bounded_and_reported与test_timeout_configuration_rejects_unbounded_values正是对这条约束的回归验证元数据子进程最大 60 秒超时_probe_ffmpeg的timeout60max_input_mb默认 16384 MiB16 GiB钳制 1–1048576 MiB在 BEGIN声明 size 超出剩余预算与每个 WRITE 块前双重执行。README 特别澄清该入口限制不约束解码/中间输出大小流数量每对象最多 128 条输入流本处理器每对象只接受恰好 1 条媒体流失败面空流、截断流、超声明大小的流、重名流均显式失败异常终止进程被强杀可能留下 scratch 文件由宿主清理浏览器中转节点契约不需要浏览器下载/再上传中继。README 同时说明标准filestore_source目前拒绝保存超过 100 MiB 的文件直接 webhook 上传可绕开该源端限制这些节点不修改标准 source/sink 的实现。持久的进度、恢复与输出命名属于管线/应用编排层的职责不在本节点内。示例管线webhook → parse → media_inspect → response 图片 sinkexample.pipe 给出了完整可运行的拓扑运行前需按部署环境配置各 sink 目标{ id: media, provider: media_inspect, config: { profile: default, default: { request: {\mode\: \probe\} } }, input: [ { from: parse, lane: video }, { from: parse, lane: audio } ] }节点链为webhooksource→parse消费tagslane→media_inspect消费video/audiolane→response_answers消费answerslane另有一条media_inspect的imagelane 接到filestoresinktargetDir: media-results/image、onConflict: unique。默认probe请求返回元数据把request改成stills后image sink 即开始落盘静帧。README 同时说明该节点不加载任何语音模型。测试与依赖验证层位于 nodes/test/media_inspecttest_streams.py流生命周期与对象隔离test_live.py真实 FFmpeg 操作与在线引擎集成test_review_regressions.py非法 ranges 永不退化为全量输入、range 输入形式、FFmpeg 超时钳制、stills 质量钳制test_still_quality_is_bounded等回归项。依赖requirements.txt与 README 生成区一致依赖版本约束avPyAV18,19imageio-ffmpeg0.6,0.7numpy2,3FFmpeg 可执行文件的解析顺序在 media.py环境变量MEDIA_TOOLKIT_FFMPEG优先其次imageio_ffmpeg内置二进制最后退回 PATH 上的ffmpeg。小结media_inspect的设计可以概括为三句话流进流出、对象级隔离临时文件随对象生死持久化交给下游 sink三种模式各司其职probe 拿元数据、levels 做静音/RMS/场景测量、stills 抽帧走 image lane所有边界显式失败超时钳制、字节预算逐块检查、crop 钳位、无效静帧逐条降级。结合 IInstance.py、levels.py 与 example.pipe你可以在 RocketRide 管道中放心地把它作为媒体分析的前置节点并用nodes/test/media_inspect下的测试验证任何定制改动。赞分享【免费下载链接】rocketride-serverHigh-performance AI pipeline engine with a C core and 50 Python-extensible nodes. Build, debug, and scale LLM workflows with 13 model providers, 8 vector databases, and agent orchestration, all from your IDE. Includes VS Code extension, TypeScript/Python SDKs, and Docker deployment.项目地址https://gitcode.com/gh_mirrors/ro/rocketride-server点击查看免费下载相关推荐3步掌握Seraphine智能助手你的英雄联盟排位赛专属数据分析解决方案3步掌握Seraphine智能助手你的英雄联盟排位赛专属数据分析解决方案 你是否曾在英雄联盟排位赛中遇到过这样的困境BP阶段手忙脚乱既要分析对手战绩又要RocketRide Gemini Vision 节点在 LLM 流水线中实现图像分析、OCR 与视频帧理解RocketRide Gemini Vision 节点在 LLM 流水线中实现图像分析、OCR 与视频帧理解 RocketRide 的 llm_vision_librealsense C API 深度测距实战基于 rs-distance 示例解析深度帧流与中心点距离测量librealsense C API 深度测距实战基于 rs distance 示例解析深度帧流与中心点距离测量 导读 本文围绕 librealsenseR智能硬件音视频计算机视觉上一篇【亲测免费】 TextCluster高效文本聚类实战指南下一篇DB-GPT容器化部署实战指南基于Docker的智能数据助手架构解析与性能优化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考