wireshark抓rtp包,提取出H265裸流数

news/2024/12/13 0:33:37/

 调试rtsp收发流时,经常会需要抓包以确认是网络问题还是程序问题还是其它问题。通过tcpdump或者wireshark抓到的包通常是rtp流,保存为.pcap格式文件后中,可通过wireshark进行解析,得出h264裸流,并保存为文件。

1.wireshark配置

从gitee上可以直接下载的 

WiresharkPlugin: The H265 H264 PS PCM AMR SILK plugin for Wireshark Lua (gitee.com)

1.1 下载rtp_h365_extractor.lua 

-- Dump RTP h.265 payload to raw h.265 file (*.265)
-- According to RFC7798 to dissector H265 payload of RTP to NALU, and write it
-- to from<sourceIp_sourcePort>to<dstIp_dstPort>.265 file. 
-- By now, we support Single NAL Unit Packets, Aggregation Packets (APs)
-- and Fragmentation Units (FUs) format RTP payload for H.265.
-- You can access this feature by menu "Tools"
-- Reference from Huang Qiangxiong (qiangxiong.huang@gmail.com)
-- Author: Yang Xing (hongch_911@126.com)
------------------------------------------------------------------------------------------------
dolocal version_str = string.match(_VERSION, "%d+[.]%d*")local version_num = version_str and tonumber(version_str) or 5.1local bit = (version_num >= 5.2) and require("bit32") or require("bit")function string.starts(String,Start)return string.sub(String,1,string.len(Start))==Startendfunction string.ends(String,End)return End=='' or string.sub(String,-string.len(End))==Endendfunction get_temp_path()local tmp = nilif tmp == nil or tmp == '' thentmp = os.getenv('HOME')if tmp == nil or tmp == '' thentmp = os.getenv('USERPROFILE')if tmp == nil or tmp == '' thentmp = persconffile_path('temp')elsetmp = tmp .. "/wireshark_temp"endelsetmp = tmp .. "/wireshark_temp"endendreturn tmpendfunction get_ffmpeg_path()local tmp = nilif tmp == nil or tmp == '' thentmp = os.getenv('FFMPEG')if tmp == nil or tmp == '' thentmp = ""elseif not string.ends(tmp, "/bin/") thentmp = tmp .. "/bin/"endendendreturn tmpend-- for geting h265 data (the field's value is type of ByteArray)local f_h265 = Field.new("h265") local f_rtp = Field.new("rtp") local f_rtp_seq = Field.new("rtp.seq")local f_rtp_timestamp = Field.new("rtp.timestamp")local filter_string = nil-- menu action. When you click "Tools->Export H265 to file" will run this functionlocal function export_h265_to_file()-- window for showing informationlocal tw = TextWindow.new("Export H265 to File Info Win")local pgtw;-- add message to information windowfunction twappend(str)tw:append(str)tw:append("\n")endlocal ffmpeg_path = get_ffmpeg_path()-- temp pathlocal temp_path = get_temp_path()-- running first time for counting and finding sps+pps, second time for real savinglocal first_run = true local writed_nalu_begin = false-- variable for storing rtp stream and dumping parameterslocal stream_infos = nil-- trigered by all h265 packatslocal list_filter = ''if filter_string == nil or filter_string == '' thenlist_filter = "h265"elseif string.find(filter_string,"h265")~=nil thenlist_filter = filter_stringelselist_filter = "h265 && "..filter_stringendtwappend("Listener filter: " .. list_filter .. "\n")local my_h265_tap = Listener.new("frame", list_filter)-- get rtp stream info by src and dst addressfunction get_stream_info(pinfo)local key = "from_" .. tostring(pinfo.src) .. "_" .. tostring(pinfo.src_port) .. "_to_" .. tostring(pinfo.dst) .. "_" .. tostring(pinfo.dst_port)key = key:gsub(":", ".")local stream_info = stream_infos[key]if not stream_info then -- if not exists, create onestream_info = { }stream_info.filename = key.. ".265"-- stream_info.filepath = stream_info.filename-- stream_info.file,msg = io.open(stream_info.filename, "wb")if not Dir.exists(temp_path) thenDir.make(temp_path)endstream_info.filepath = temp_path.."/"..stream_info.filenamestream_info.file,msg = io.open(temp_path.."/"..stream_info.filename, "wb")if msg thentwappend("io.open "..stream_info.filepath..", error "..msg)end-- twappend("Output file path:" .. stream_info.filepath)stream_info.counter = 0 -- counting h265 total NALUsstream_info.counter2 = 0 -- for second time runningstream_infos[key] = stream_infotwappend("Ready to export H.265 data (RTP from " .. tostring(pinfo.src) .. ":" .. tostring(pinfo.src_port) .. " to " .. tostring(pinfo.dst) .. ":" .. tostring(pinfo.dst_port) .. " write to file:[" .. stream_info.filename .. "] ...")endreturn stream_infoend-- write a NALU or part of NALU to file.local function write_to_file(stream_info, str_bytes, begin_with_nalu_hdr, end_of_nalu)if first_run thenstream_info.counter = stream_info.counter + 1if begin_with_nalu_hdr then-- save VPS SPS PPSlocal nalu_type = bit.rshift(bit.band(str_bytes:byte(0,1), 0x7e),1)if not stream_info.vps and nalu_type == 32 thenstream_info.vps = str_byteselseif not stream_info.sps and nalu_type == 33 thenstream_info.sps = str_byteselseif not stream_info.pps and nalu_type == 34 thenstream_info.pps = str_bytesendendelse -- second time runningif not writed_nalu_begin thenif begin_with_nalu_hdr thenwrited_nalu_begin = trueelsereturnendendif stream_info.counter2 == 0 thenlocal nalu_type = bit.rshift(bit.band(str_bytes:byte(0,1), 0x7e),1)if nalu_type ~= 32 then-- write VPS SPS and PPS to file header firstif stream_info.vps thenstream_info.file:write("\x00\x00\x00\x01")stream_info.file:write(stream_info.vps)elsetwappend("Not found VPS for [" .. stream_info.filename .. "], it might not be played!")endif stream_info.sps thenstream_info.file:write("\x00\x00\x00\x01")stream_info.file:write(stream_info.sps)elsetwappend("Not found SPS for [" .. stream_info.filename .. "], it might not be played!")endif stream_info.pps thenstream_info.file:write("\x00\x00\x00\x01")stream_info.file:write(stream_info.pps)elsetwappend("Not found PPS for [" .. stream_info.filename .. "], it might not be played!")endendendif begin_with_nalu_hdr then-- *.265 raw file format seams that every nalu start with 0x00000001stream_info.file:write("\x00\x00\x00\x01")endstream_info.file:write(str_bytes)stream_info.counter2 = stream_info.counter2 + 1-- update progress window's progress barif stream_info.counter > 0 and stream_info.counter2 < stream_info.counter thenpgtw:update(stream_info.counter2 / stream_info.counter)endendend-- read RFC3984 about single nalu/ap/fu H265 payload format of rtp-- single NALU: one rtp payload contains only NALUlocal function process_single_nalu(stream_info, h265)write_to_file(stream_info, h265:tvb():raw(), true, true)end-- APs: one rtp payload contains more than one NALUslocal function process_ap(stream_info, h265)local h265tvb = h265:tvb()local offset = 2repeatlocal size = h265tvb(offset,2):uint()write_to_file(stream_info, h265tvb:raw(offset+2, size), true, true)offset = offset + 2 + sizeuntil offset >= h265tvb:len()end-- FUs: one rtp payload contains only one part of a NALU (might be begin, middle and end part of a NALU)local function process_fu(stream_info, h265)local h265tvb = h265:tvb()local start_of_nalu = (h265tvb:range(2, 1):bitfield(0,1) ~= 0)local end_of_nalu =  (h265tvb:range(2, 1):bitfield(1,1) ~= 0)if start_of_nalu then-- start bit is set then save nalu header and bodylocal nalu_hdr_0 = bit.bor(bit.band(h265:get_index(0), 0x81), bit.lshift(bit.band(h265:get_index(2),0x3F), 1))local nalu_hdr_1 = h265:get_index(1)write_to_file(stream_info, string.char(nalu_hdr_0, nalu_hdr_1) .. h265tvb:raw(3), start_of_nalu, end_of_nalu)else-- start bit not set, just write part of nalu bodywrite_to_file(stream_info, h265tvb:raw(3), start_of_nalu, end_of_nalu)endend-- call this function if a packet contains h265 payloadfunction my_h265_tap.packet(pinfo,tvb)if stream_infos == nil then-- not triggered by button event, so do nothing.returnendlocal h265s = { f_h265() } -- using table because one packet may contains more than one RTPfor i,h265_f in ipairs(h265s) doif h265_f.len < 5 thenreturnendlocal h265 = h265_f.range:bytes() local hdr_type = h265_f.range(0,1):bitfield(1,6)local stream_info = get_stream_info(pinfo)if hdr_type > 0 and hdr_type < 48 then-- Single NALUprocess_single_nalu(stream_info, h265)elseif hdr_type == 48 then-- APsprocess_ap(stream_info, h265)elseif hdr_type == 49 then-- FUsprocess_fu(stream_info, h265)elsetwappend("Error: No.=" .. tostring(pinfo.number) .. " unknown type=" .. hdr_type .. " ; we only know 1-47(Single NALU),48(APs),49(FUs)!")endendend-- close all open fileslocal function close_all_files()twappend("")local index = 0;if stream_infos thenlocal no_streams = truefor id,stream in pairs(stream_infos) doif stream and stream.file thenstream.file:flush()stream.file:close()stream.file = nilindex = index + 1twappend(index .. ": [" .. stream.filename .. "] generated OK!")local anony_fuc = function ()twappend("ffplay -x 640 -y 640 -autoexit "..stream.filename)--copy_to_clipboard("ffplay -x 640 -y 640 -autoexit "..stream.filepath)os.execute(ffmpeg_path.."ffplay -x 640 -y 640 -autoexit "..stream.filepath)endtw:add_button("Play "..index, anony_fuc)no_streams = falseendendif no_streams thentwappend("Not found any H.265 over RTP streams!")elsetw:add_button("Browser", function () browser_open_data_file(temp_path) end)endendendfunction my_h265_tap.reset()-- do nothing nowendtw:set_atclose(function ()my_h265_tap:remove()if Dir.exists(temp_path) thenDir.remove_all(temp_path)endend)local function export_h265()pgtw = ProgDlg.new("Export H265 to File Process", "Dumping H265 data to file...")first_run = truestream_infos = {}-- first time it runs for counting h.265 packets and finding SPS and PPSretap_packets()first_run = false-- second time it runs for saving h265 data to target file.retap_packets()close_all_files()-- close progress windowpgtw:close()stream_infos = nilendtw:add_button("Export All", function ()export_h265()end)tw:add_button("Set Filter", function ()tw:close()dialog_menu()end)endlocal function dialog_func(str)filter_string = strexport_h265_to_file()endfunction dialog_menu()new_dialog("Filter Dialog",dialog_func,"Filter")endlocal function dialog_default()filter_string = get_filter()export_h265_to_file()end-- Find this feature in menu "Tools"register_menu("Video/Export H265", dialog_default, MENU_TOOLS_UNSORTED)
end

1.2 rtp_h365_extractor.lua放在 Wireshark 安装目录中

1.3 修改init.lua配置文件

2. 流分析

2.1.  解码为RTP数据包

使用wireshark抓包工具抓取码流包(如下图),基于UDP传输。
在这里插入图片描述
选中其中一个数据包(包要选择正确,可根据protocol的类型选择),右键选择解码为(如下图)。
在这里插入图片描述
新增解码规则,选择解码为RTP流(如下图)。
在这里插入图片描述
解码后,可看到数据包解码成了RTP包(如下图)。
在这里插入图片描述

导出h265视频流

2.2. vlc播放视频流 


http://www.ppmy.cn/news/1152429.html

相关文章

【算法分析与设计】分支限界法(下)

目录 一、最大团问题1.1 问题描述1.2 上界函数1.3 算法思想 二、旅行售货员问题2.1 问题描述2.2 算法描述 三、电路板排列问题3.1 算法描述 四、批处理作业调度问题4.1 问题的描述4.2 限界函数4.3 算法描述 五、小结六、随机化算法 一、最大团问题 1.1 问题描述 给定无向图G(V…

考研:数学二例题--∞−∞和0⋅∞型极限

前言 本文只是例题&#xff0c;建议先参考具体如何做这类型例题。请到主文章中参考&#xff1a;https://blog.csdn.net/grd_java/article/details/132246630 ∞ − ∞ 和 0 ⋅ ∞ \infin - \infin 和 0\infin ∞−∞和0⋅∞ 例题 例1&#xff1a; lim ⁡ x → ∞ x 2 x 2 −…

uniapp 一次性上传多条视频 u-upload accept=“video“ uni.chooseMedia uni.uploadFile

方式 一 部分安卓机 只能一条一条传视频 文档地址 uview 2.0 Upload 上传组件 html <view class"formupload"><u-upload accept"video":fileList"fileList3" afterRead"afterRead" delete"deletePic" name"…

2023年中国智能矿山发展历程及趋势分析:智能矿山健康有序发展[图]

智能矿山系统对矿山生产提质增效的效果已经开始显现&#xff1a;对不合规、有风险的行动进行及时预警&#xff0c;减少安全事故发生概率&#xff0c;避免因停产整顿产生的巨额亏损&#xff1b;精细化管理整个生产流程&#xff0c;避免过往传统粗放的流程导致的浪费&#xff0c;…

【IDE插件教学】华为云应用中间件系列—Redis实现(电商游戏应用)排行榜示例

云服务、API、SDK&#xff0c;调试&#xff0c;查看&#xff0c;我都行 阅读短文您可以学习到&#xff1a;应用中间件系列之Redis实现&#xff08;电商游戏应用&#xff09;排行榜示例 1 什么是DEVKIT 华为云开发者插件&#xff08;Huawei Cloud Toolkit&#xff09;&a…

2023年中国玉米深加工产能、市场规模、消费量及产品需求结构[图]

玉米深加工顾名思义就是将产业链延长,进而提升产品附加值,利用玉米提炼出酒精、玉米胚芽油、淀粉和饲料等大概两百余种玉米深加工产品。我国是玉米种植大国&#xff0c;也是玉米深加工大国&#xff0c;但是玉米加工行业却长时间处于产能过剩、开工率不足、利润率低下的境况&…

LCR 026. 重排链表

LCR 026. 重排链表 题目链接&#xff1a;LCR 026. 重排链表 注&#xff1a;该题与 143. 重排链表完全一样 代码如下&#xff1a; class Solution { public:void reorderList(ListNode* head){if(headnullptr||head->nextnullptr||head->next->nextnullptr)return;L…

微服务 BFF 架构设计

在现代软件开发中&#xff0c;由于程序、团队、数据规模太大&#xff0c;需要把企业的业务能力进行复用&#xff0c;将领域服务剥离&#xff0c;提供通用能力&#xff0c;避免重复建设和代码&#xff1b;另外服务功能的弹性能力不一样&#xff0c;比如定时任务、数据同步明确的…