
简介这份资源面向网络运维、安全分析与协议开发人员聚焦从tcpdump或Wireshark生成的pcap抓包文件中筛选并提取符合国家标准的网络数据流这一实际需求。包内共2个文件以1个C语言源码文件和1个Markdown说明文档为主压缩包约5KB体量轻巧便于快速阅读与二次开发。源码承担pcap解析、协议字段识别与国标流提取的核心逻辑说明文档则交代工具用途与使用方式二者配合可帮助读者理解抓包数据的筛选思路与实现路径。目前已有221人学习下载适合需要处理网络流量、做协议解析或格式转换的技术人员参考也可作为网络监控、故障排查与安全事件分析场景下的轻量工具脚本帮助读者掌握从海量数据包中定位目标数据流的关键方法。1. 从 tcpdump 或 Wireshark 抓包文件里把国标流拆出来pcap2ps 到底在解决什么手里拿到一个几百 MB 的 pcap用 Wireshark 打开满屏都是 TCP、UDP、ARP想找一路 GB28181 的视频流却像大海捞针——这是很多做安防接入、流媒体网关、视频平台对接的工程师都遇到过的场景。pcap2ps 这类工具要干的事很具体把抓包文件tcpdump 或 Wireshark 保存的 pcap/pcapng里承载的国标流GB/T 28181 体系下 PS 封装的音视频流识别出来还原成独立的 .ps 文件方便后续用 ffmpeg、VLC 或自研解析器单独分析。它解决的不是抓包问题而是抓完之后怎么把有用的那一路流从混杂报文里剥离出来的问题。适合做视频接入排障、国标信令与媒体流分析、流媒体服务端联调的从业者尤其是那些已经会用 tcpdump 抓包、但面对原始 pcap 无从下手的同学。2. 先搞清楚国标流在 pcap 里长什么样RTP、PS 与端口特征2.1 国标流的三层封装关系要提取先得知道目标长什么样。GB/T 28181 的媒体传输在网络上通常是这样叠起来的最外层是 UDP少数场景用 TCP 被动/主动模式往上是 RTPRTP 载荷里装的是 PS 流Program StreamMPEG-2 系统层封装PS 里面再包着 H.264/H.265 视频和 G.711/AAC 音频。所以你在 Wireshark 里看到的国标流本质是一串 RTP 包每个包的 payload 拼起来才是一段完整的 PS 数据。这里有个容易翻车的点RTP 载荷不等于完整 PS 包。一个 PS 包可能被拆到多个 RTP 包里传输提取时必须按 RTP 序列号重组否则还原出来的 .ps 文件播放器打不开。这也是为什么不能简单地在 Wireshark 里导出分组字节流了事——那样导出的是单个 RTP 包的载荷不是连续的 PS 流。2.2 怎么在 Wireshark 里快速定位国标流先别急着写脚本用 Wireshark 的可视化能力把流找出来能省掉大量试错。常见做法是先用显示过滤器缩小范围# 只看 RTP排除信令和无关流量 rtp # 如果知道大致端口范围国标媒体端口常在 30000 以上 udp.port 30000 rtp # 结合 SIP 信令里协商的 IP锁定某一路流 ip.addr 192.168.1.100 rtp过滤出来后右键任意一个 RTP 包 → 解码为Decode As→ 选 RTPWireshark 会自动把这一串包识别成 RTP 流。再点菜单电话→RTP→流分析能看到这路流的 SSRC、序列号范围、丢包统计。这一步的价值在于确认这确实是一路 RTP 流、拿到它的 SSRC 和端口后面写提取脚本时就有了明确的过滤条件而不是盲猜。提示Wireshark 的导出分组字节流默认导出的是选中包的原始字节包含以太网/IP/UDP/RTP 各层头部。想要纯 PS 载荷要么在导出时选仅显示数据并手动跳过 RTP 头要么干脆用脚本处理别指望 GUI 一步到位。2.3 用 tshark 命令行先做一次流统计如果你更习惯命令行或者 pcap 太大 Wireshark 打开卡顿用 tshark 先摸清底细# 统计 pcap 里所有 RTP 流的 SSRC 和包数量 tshark -r capture.pcap -Y rtp -T fields -e rtp.ssrc -e udp.srcport -e udp.dstport \ | sort | uniq -c | sort -rn | head -20 # 看某一路流假设 SSRC 为 0x12345678的包序列 tshark -r capture.pcap -Y rtp.ssrc 0x12345678 -T fields -e rtp.seq -e frame.number | head第一条命令帮你快速判断这个 pcap 里有几路流、哪路包最多通常就是主码流。第二条确认序列号是否连续——如果序列号有跳变说明抓包期间有丢包还原出来的 PS 会有花屏或断裂这是后面排查问题的关键线索。参数上-Y是显示过滤器-T fields -e指定输出字段rtp.ssrc是 RTP 同步源标识同一路流 SSRC 固定用它做过滤最可靠。3. 写一个 pcap2ps 提取脚本从 RTP 载荷到独立 PS 文件3.1 提取的核心逻辑不管用什么语言提取流程都是固定的四步读 pcap → 过滤出目标 RTP 流 → 按序列号排序并拼接 payload → 写入 .ps 文件。用 Python 的 scapy 或 dpkt 都能做dpkt 更轻量、解析 pcap 更快这里用 dpkt 演示。import dpkt import struct def pcap2ps(pcap_path, out_path, target_ssrcNone, target_portNone): 从 pcap 中提取指定 RTP 流的 PS 载荷写入 .ps 文件 target_ssrc: 目标流的 SSRC十六进制或十进制None 表示不过滤 target_port: 目标 UDP 端口None 表示不过滤 rtp_packets {} # seq - payload with open(pcap_path, rb) as f: pcap dpkt.pcap.Reader(f) for ts, buf in pcap: try: eth dpkt.ethernet.Ethernet(buf) ip eth.data if not isinstance(ip.data, dpkt.udp.UDP): continue udp ip.data # 端口过滤 if target_port and udp.dport ! target_port and udp.sport ! target_port: continue payload udp.data if len(payload) 12: continue # 解析 RTP 头前 12 字节固定 # V2, P, X, CC 在第一个字节 first_byte payload[0] version first_byte 6 if version ! 2: continue cc first_byte 0x0F has_ext (first_byte 4) 0x01 header_len 12 cc * 4 if has_ext: # 扩展头4 字节扩展标识 长度 ext_len struct.unpack(H, payload[header_len2:header_len4])[0] header_len 4 ext_len * 4 seq struct.unpack(H, payload[2:4])[0] ssrc struct.unpack(I, payload[8:12])[0] # SSRC 过滤 if target_ssrc is not None and ssrc ! target_ssrc: continue rtp_payload payload[header_len:] rtp_packets[seq] rtp_payload except Exception: continue # 按序列号排序后拼接 with open(out_path, wb) as out: for seq in sorted(rtp_packets.keys()): out.write(rtp_packets[seq]) print(f提取完成{len(rtp_packets)} 个 RTP 包 - {out_path}) if __name__ __main__: # 用法示例指定 SSRC 和端口 pcap2ps(capture.pcap, output.ps, target_ssrc0x12345678, target_port30000)逻辑说明脚本逐包读取 pcap先判断是不是 UDP再按端口和 SSRC 过滤然后解析 RTP 头拿到序列号和载荷。关键在header_len的计算——RTP 头不是固定 12 字节有 CSRC 列表和扩展头时要动态算算错了载荷就会错位还原的 PS 直接废掉。最后用字典按 seq 存载荷排序后拼接这样即使抓包时包乱序也能还原正确顺序。参数说明target_ssrc和target_port是过滤条件实际用的时候先用第 2 章的 tshark 命令查出真实值再填。如果 pcap 里只有一路流两个都可以传 None。out_path建议用.ps后缀方便 ffmpeg 直接识别。3.2 用 ffmpeg 验证提取结果提取完别急着高兴先验证。最直接的办法是用 ffmpeg 探测# 探测 PS 文件信息 ffprobe -v error -show_format -show_streams output.ps # 如果 PS 能识别直接转封装成 mp4 看画面 ffmpeg -i output.ps -c copy output.mp4如果 ffprobe 报Invalid data found八成是 RTP 头没剥干净或者序列号拼接顺序错了。如果能看到视频流信息但播放花屏多半是抓包丢包导致 PS 不连续这时候要回到 tshark 看序列号有没有跳变。这一步是提取流程的后悔药能帮你快速区分是脚本问题还是原始数据问题。3.3 处理多路流和 TCP 承载的情况实际 pcap 里往往不止一路流甚至国标流可能走 TCPGB28181 的 TCP 被动模式。多路流的情况把脚本里的rtp_packets改成按 SSRC 分组的字典循环处理每一路即可。TCP 承载的国标流稍微麻烦RTP 包前面会加 2 字节的长度字段RFC 4571 帧格式解析时要先读这 2 字节拿到 RTP 包长度再往后取对应字节数。常见做法是判断传输层是 TCP 时按length struct.unpack(H, data[:2])切分然后对每个切片按 UDP 那套逻辑解析 RTP。这块容易踩坑的地方是 TCP 粘包——一个 TCP 段里可能有多个 RTP 包必须循环切分不能假设一段就是一个包。4. 提取国标流最容易翻车的几个地方4.1 现象还原的 PS 文件播放器打不开ffprobe 报错原因RTP 头没剥干净或者把 RTP 头也写进了 PS 文件。很多人图省事直接导出 UDP 载荷忘了 RTP 头占 12 字节以上结果 PS 文件开头就是一堆垃圾数据。解决严格按 RTP 头结构计算header_len确认 CSRC 和扩展头都算进去。验证方法是用十六进制编辑器看输出文件开头PS 流的起始码应该是00 00 01 BAPS 包头或00 00 01 E0视频 PES如果不是说明头部没剥对。4.2 现象PS 能识别但播放花屏、卡顿原因抓包期间丢包RTP 序列号不连续拼接出来的 PS 中间缺数据。解决在脚本里加序列号连续性检查发现跳变时打印警告并记录缺口位置。如果丢包严重这路流基本没法完整还原只能换一次抓包。抓包时尽量在靠近源端的位置抓减少中间网络丢包。4.3 现象提取出来的文件特别大但只有一路流原因过滤条件没生效把多路流的载荷混在一起了。常见于 SSRC 过滤写错或者端口过滤用了or逻辑导致匹配了多个端口。解决先用 tshark 统计确认有几路流、各自 SSRC 是多少脚本里 SSRC 过滤用精确匹配。如果 pcap 里同一端口有多路流少见但存在必须靠 SSRC 区分不能只靠端口。4.4 现象TCP 承载的流提取出来是乱码原因没处理 RFC 4571 的 2 字节长度前缀直接把 TCP 载荷当 RTP 解析了。解决判断传输层协议TCP 时先按 2 字节长度字段切分 RTP 包再解析。注意长度字段是大端序且一个 TCP 段可能包含多个 RTP 包要循环处理。4.5 现象Wireshark 能播放 RTP 流但脚本提取的 PS 不行原因Wireshark 的 RTP 播放功能做了额外的重组和容错而脚本是原样拼接。Wireshark 可能自动处理了乱序、重复包脚本没处理。解决在脚本里加去重逻辑相同 seq 只保留一个和乱序处理按 seq 排序这两步能覆盖大部分差异。如果还有问题对比 Wireshark 导出的流和脚本输出的流用二进制 diff 找差异点。5. 进阶批量提取与自动化验证的一个实用套路单次提取跑通之后真正省时间的是把它做成可复用的批处理流程。我一般的做法是写一个 shell 包装脚本把统计流 → 提取 → 验证串起来输入一个 pcap 目录输出每路流的 PS 文件和验证报告。#!/bin/bash # batch_pcap2ps.sh批量处理目录下所有 pcap PCAP_DIR$1 OUT_DIR$2 mkdir -p $OUT_DIR for pcap in $PCAP_DIR/*.pcap; do name$(basename $pcap .pcap) # 第一步统计所有 SSRC ssrcs$(tshark -r $pcap -Y rtp -T fields -e rtp.ssrc 2/dev/null | sort -u) for ssrc in $ssrcs; do out$OUT_DIR/${name}_${ssrc}.ps # 第二步提取 python3 pcap2ps.py $pcap $out --ssrc $ssrc # 第三步验证 if ffprobe -v error -show_streams $out /dev/null 21; then echo OK: $out else echo FAIL: $out fi done done这个套路的参数说明--ssrc是给 Python 脚本加的命令行参数用 argparse 解析tshark -T fields -e rtp.ssrc | sort -u拿到所有不重复的 SSRC。验证环节用 ffprobe 的退出码判断成败比人工一个个打开靠谱。跑完一遍FAIL 的那些就是需要重点排查的——要么是丢包严重要么是 TCP 承载没处理要么是加密流国标有些场景 RTP 载荷加密这种提取出来也没法直接播。一个我踩过的坑批量处理时如果 pcap 里有加密的 RTP 流ffprobe 必然 FAIL但这不是脚本的问题。判断方法是看 RTP 载荷开头是不是00 00 01 BA不是的话大概率是加密或非 PS 封装这种流直接跳过别浪费时间调脚本。另外SSRC 在 pcap 里可能以十进制或十六进制显示tshark 默认输出十进制脚本里解析时注意进制转换我因为这个问题白排查过半小时。最后说个习惯每次提取完我都会用ffmpeg -i output.ps -f null -跑一遍完整解码看有没有报错。这比只看文件大小靠谱得多——文件大小正常但解码报错的 PS 太多了这一步能帮你确认提取的流是真的能用而不是看起来像那么回事。希望帮到你。本文还有配套的精品资源点击获取