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

news2025/6/25 14:36:31

 调试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)
------------------------------------------------------------------------------------------------
do
    local version_str = string.match(_VERSION, "%d+[.]%d*")
    local version_num = version_str and tonumber(version_str) or 5.1
    local bit = (version_num >= 5.2) and require("bit32") or require("bit")
 
    function string.starts(String,Start)
        return string.sub(String,1,string.len(Start))==Start
     end
     
     function string.ends(String,End)
        return End=='' or string.sub(String,-string.len(End))==End
     end
    function get_temp_path()
        local tmp = nil
        if tmp == nil or tmp == '' then
            tmp = os.getenv('HOME')
            if tmp == nil or tmp == '' then
                tmp = os.getenv('USERPROFILE')
                if tmp == nil or tmp == '' then
                    tmp = persconffile_path('temp')
                else
                    tmp = tmp .. "/wireshark_temp"
                end
            else
                tmp = tmp .. "/wireshark_temp"
            end
        end
        return tmp
    end
    function get_ffmpeg_path()
        local tmp = nil
        if tmp == nil or tmp == '' then
            tmp = os.getenv('FFMPEG')
            if tmp == nil or tmp == '' then
                tmp = ""
            else
                if not string.ends(tmp, "/bin/") then
                    tmp = tmp .. "/bin/"
                end
            end
        end
        return tmp
    end
    -- 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 function
    local function export_h265_to_file()
        -- window for showing information
        local tw = TextWindow.new("Export H265 to File Info Win")
        local pgtw;
        
        -- add message to information window
        function twappend(str)
            tw:append(str)
            tw:append("\n")
        end
        
        local ffmpeg_path = get_ffmpeg_path()
        -- temp path
        local temp_path = get_temp_path()
        
        -- running first time for counting and finding sps+pps, second time for real saving
        local first_run = true 
        local writed_nalu_begin = false
        -- variable for storing rtp stream and dumping parameters
        local stream_infos = nil
 
        -- trigered by all h265 packats
        local list_filter = ''
        if filter_string == nil or filter_string == '' then
            list_filter = "h265"
        elseif string.find(filter_string,"h265")~=nil then
            list_filter = filter_string
        else
            list_filter = "h265 && "..filter_string
        end
        twappend("Listener filter: " .. list_filter .. "\n")
        local my_h265_tap = Listener.new("frame", list_filter)
        
        -- get rtp stream info by src and dst address
        function 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 one
                stream_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) then
                    Dir.make(temp_path)
                end
                stream_info.filepath = temp_path.."/"..stream_info.filename
                stream_info.file,msg = io.open(temp_path.."/"..stream_info.filename, "wb")
                if msg then
                    twappend("io.open "..stream_info.filepath..", error "..msg)
                end
                -- twappend("Output file path:" .. stream_info.filepath)
                stream_info.counter = 0 -- counting h265 total NALUs
                stream_info.counter2 = 0 -- for second time running
                stream_infos[key] = stream_info
                twappend("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 .. "] ...")
            end
            return stream_info
        end
        
        -- 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 then
                stream_info.counter = stream_info.counter + 1
                
                if begin_with_nalu_hdr then
                    -- save VPS SPS PPS
                    local nalu_type = bit.rshift(bit.band(str_bytes:byte(0,1), 0x7e),1)
                    if not stream_info.vps and nalu_type == 32 then
                        stream_info.vps = str_bytes
                    elseif not stream_info.sps and nalu_type == 33 then
                        stream_info.sps = str_bytes
                    elseif not stream_info.pps and nalu_type == 34 then
                        stream_info.pps = str_bytes
                    end
                end
                
            else -- second time running
                if not writed_nalu_begin then
                    if begin_with_nalu_hdr then
                        writed_nalu_begin = true
                    else
                        return
                    end
                end
                
                if stream_info.counter2 == 0 then
                    local 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 first
                        if stream_info.vps then
                            stream_info.file:write("\x00\x00\x00\x01")
                            stream_info.file:write(stream_info.vps)
                        else
                            twappend("Not found VPS for [" .. stream_info.filename .. "], it might not be played!")
                        end
                        if stream_info.sps then
                            stream_info.file:write("\x00\x00\x00\x01")
                            stream_info.file:write(stream_info.sps)
                        else
                            twappend("Not found SPS for [" .. stream_info.filename .. "], it might not be played!")
                        end
                        if stream_info.pps then
                            stream_info.file:write("\x00\x00\x00\x01")
                            stream_info.file:write(stream_info.pps)
                        else
                            twappend("Not found PPS for [" .. stream_info.filename .. "], it might not be played!")
                        end
                    end
                end
            
                if begin_with_nalu_hdr then
                    -- *.265 raw file format seams that every nalu start with 0x00000001
                    stream_info.file:write("\x00\x00\x00\x01")
                end
                stream_info.file:write(str_bytes)
                stream_info.counter2 = stream_info.counter2 + 1
                -- update progress window's progress bar
                if stream_info.counter > 0 and stream_info.counter2 < stream_info.counter then
                    pgtw:update(stream_info.counter2 / stream_info.counter)
                end
            end
        end
        
        -- read RFC3984 about single nalu/ap/fu H265 payload format of rtp
        -- single NALU: one rtp payload contains only NALU
        local 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 NALUs
        local function process_ap(stream_info, h265)
            local h265tvb = h265:tvb()
            local offset = 2
            repeat
                local size = h265tvb(offset,2):uint()
                write_to_file(stream_info, h265tvb:raw(offset+2, size), true, true)
                offset = offset + 2 + size
            until 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 body
                local 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 body
                write_to_file(stream_info, h265tvb:raw(3), start_of_nalu, end_of_nalu)
            end
        end
        
        -- call this function if a packet contains h265 payload
        function my_h265_tap.packet(pinfo,tvb)
            if stream_infos == nil then
                -- not triggered by button event, so do nothing.
                return
            end
            local h265s = { f_h265() } -- using table because one packet may contains more than one RTP
            
            for i,h265_f in ipairs(h265s) do
                if h265_f.len < 5 then
                    return
                end
                local 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 NALU
                    process_single_nalu(stream_info, h265)
                elseif hdr_type == 48 then
                    -- APs
                    process_ap(stream_info, h265)
                elseif hdr_type == 49 then
                    -- FUs
                    process_fu(stream_info, h265)
                else
                    twappend("Error: No.=" .. tostring(pinfo.number) .. " unknown type=" .. hdr_type .. " ; we only know 1-47(Single NALU),48(APs),49(FUs)!")
                end
            end
        end
        
        -- close all open files
        local function close_all_files()
            twappend("")
            local index = 0;
            if stream_infos then
                local no_streams = true
                for id,stream in pairs(stream_infos) do
                    if stream and stream.file then
                        stream.file:flush()
                        stream.file:close()
                        stream.file = nil
                        index = index + 1
                        twappend(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)
                        end
                        tw:add_button("Play "..index, anony_fuc)
                        no_streams = false
                    end
                end
                
                if no_streams then
                    twappend("Not found any H.265 over RTP streams!")
                else
                    tw:add_button("Browser", function () browser_open_data_file(temp_path) end)
                end
            end
        end
        
        function my_h265_tap.reset()
            -- do nothing now
        end
        
        tw:set_atclose(function ()
            my_h265_tap:remove()
            if Dir.exists(temp_path) then
                Dir.remove_all(temp_path)
            end
        end)
        
        local function export_h265()
            pgtw = ProgDlg.new("Export H265 to File Process", "Dumping H265 data to file...")
            first_run = true
            stream_infos = {}
            -- first time it runs for counting h.265 packets and finding SPS and PPS
            retap_packets()
            first_run = false
            -- second time it runs for saving h265 data to target file.
            retap_packets()
            close_all_files()
            -- close progress window
            pgtw:close()
            stream_infos = nil
        end
        
        tw:add_button("Export All", function ()
            export_h265()
        end)
 
        tw:add_button("Set Filter", function ()
            tw:close()
            dialog_menu()
        end)
    end
 
    local function dialog_func(str)
        filter_string = str
        export_h265_to_file()
    end
 
    function dialog_menu()
        new_dialog("Filter Dialog",dialog_func,"Filter")
    end
 
    local 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.coloradmin.cn/o/1085963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

日常学习记录随笔-zabix实战

使用zabix结合 实现一套监控报警装置 不管是web开发还是大数据开发 我们的离线项目还是实时项目也好&#xff0c;都需要把我们的应用提交到我们服务器或者容器中去执行 整个应用过程中怎么保证线上整体环境的稳定运行 监控很重要 现在比较主流的就是 普罗米修斯以及zabix 我要做…

Spring Task 快速入门

哈喽~大家好&#xff0c;这篇来看看Spring Task 快速入门。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【日常学习上的分享】 &#x1f949;与这篇相关的文章&#xff1a; Redis…

TSINGSEE利用视频智能化与可视化技术,构建AI智慧工地综合监管方案

一、行业背景 科技高速发展的今天&#xff0c;工地施工已发生翻天覆地的变化&#xff0c;传统工地管理模式很容易造成工地管理混乱、安全事故、数据延迟等问题&#xff0c;人力资源的不足也进一步加剧了监管不到位的局面&#xff0c;严重影响了施工进度质量和安全。 智慧工地…

持续测试新范式:拨压测一体化

作者&#xff1a;拂衣 近日&#xff0c;在 TiD2023 质量竞争力大会上&#xff0c;来自阿里云云原生可观测团队的吴垚进行了《持续测试新范式&#xff1a;拨压测一体化》主题分享&#xff0c;本次分享包含三部分&#xff1a; 业务连续性对稳定性平台的需求阿里稳定性平台的演进…

并发编程的三大特性

重要通知&#xff1a; 本人获得了一个运维的上市公司offer&#xff0c;问了一下就业的老师&#xff0c;都推荐能去就去&#xff0c;因为当下的环境&#xff0c;我这种专业需要985211学历才比较好找&#xff0c;所以我要去实习了&#xff08;今年挺多是实习完才给签三方&#x…

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS进阶(四)完结撒花✿✿ヽ(°▽°)ノ✿

思维导图 高阶技巧 1. 深浅拷贝 1.1 浅拷贝 1.2 深拷贝 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…

【ArcGIS】NDVI估算植被覆盖度FVC

NDVI计算 植被覆盖度计算 Step1&#xff1a;调出栅格计算器工具 1、首先打开软件&#xff0c;然后在操作页面点击&#xff0c;自定义工具栏中——自定义模式。 2、再点击窗口中的命令选项。 3、在窗口右上角处搜索“栅格计算”。 4、然后&#xff0c;直接将栅格计算器直接…

大数据学习(7)-hive文件格式总结

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博>主哦&#x…

黄金票据与白银票据

文章目录 黄金票据与白银票据1. 背景2. 具体实现2.1 Kerberos协议认证流程 3. 黄金票据3.1 条件3.2 适用场景3.3 利用方式 4. 白银票据4.1 条件4.2 适用场景4.3 利用方式 5. 金票和银票的区别5.1 获取的权限不同5.2 认证流程不同5.3 加密方式不同 6. 经典面试题6.1 什么是黄金票…

redis在linux系统的安装与使用

一、单机安装Redis。 1.安装redis依赖 在控制台输入 yum install -y gcc tcl2.上传安装包 下载好的安装包上传到/usr/local/src/ 上传方法&#xff1a; 1.确保你拥有Linux服务器的IP地址、用户名和密码。 2.在Windows上&#xff0c;打开命令提示符&#xff08;Command Promp…

Android组件通信——ActivityGroup(二十五)

1. ActivityGroup 1.1 知识点 &#xff08;1&#xff09;了解ActivityGroup的作用&#xff1b; &#xff08;2&#xff09;使用ActivityGroup进行复杂标签菜单的实现&#xff1b; &#xff08;3&#xff09;使用PopupWindow组件实现弹出菜单组件开发&#xff1b; 1.2 具体…

17其他内置方法——信息格式化操作

其他内置方法信息格式化操作有两个&#xff0c;一个是__str__,一个是__repr__ 目录 1、__str__ ​编辑 触发方式有两种&#xff0c;一种是通过print&#xff08;p&#xff09;还有一种是打印str&#xff08;p1&#xff09; 2、__repr__:触发方式也有这两种 一种是直接打印…

Mysql高级——事务(1)

事务基础知识 1. 数据库事务概述 1.1 存储引擎支持情况 SHOW ENGINES 命令来查看当前 MySQL 支持的存储引擎都有哪些&#xff0c;以及这些存储引擎是否支持事务。 能看出在 MySQL 中&#xff0c;只有InnoDB 是支持事务的。 1.2 基本概念 **事务&#xff1a;**一组逻辑操作…

iMazing2023免费版苹果iPhone手机备份应用软件

iMazing是一款功能强大的苹果手机备份软件&#xff0c;它可通过备份功能将通讯录备份到电脑上&#xff0c;并在电脑端iMazing“通讯录”功能中随时查看和导出联系人信息。它自带Wi-Fi自动备份功能&#xff0c;能够保证通讯录备份数据是一直在动态更新的&#xff0c;防止手机中新…

去图片里面的水印怎么去?三个小妙招分享给你

当我们在网上搜集图片素材时&#xff0c;经常会遇到图片上有平台水印的情况&#xff0c;这是一个令人头疼的情况。这些水印可能会妨碍我们的创作&#xff0c;限制了素材的使用&#xff0c;那么去图片里面的水印怎么去呢&#xff1f;别担心今天我来分享一些非常实用的技巧&#…

Hydra参数

kali的hyda参数 参数&#xff1a; hydra [[[-l LOGIN|-L FILE] [-p PASS|-P FILE]] | [-C FILE]] [-e ns][-o FILE] [-t TASKS] [-M FILE [-T TASKS]] [-w TIME] [-f] [-s PORT] [-S] [-vV] server service [OPT] -R 继续从上一次进度接着破解。 -S 采用SSL链接。 -s PORT 可通…

windows10系统-15-markdown编辑器和文本复制工具Textify

1 markdown编辑器 Markdown是一种轻量级标记语言&#xff0c;创始人为约翰格鲁伯。 它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成有效的XHTML&#xff08;或者HTML&#xff09;文档。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。 1.1 Typo…

Java每日笔试题错题分析(4)

Java每日笔试题错题分析&#xff08;4&#xff09; 一、错题知识点前瞻第1题第2题第3题第4题第5题 二、错题展示及其解析第1题第2题第3题第4题第5题 一、错题知识点前瞻 第1题 String声明变量在jvm中的存储方法 1&#xff0c;字符串在java中存储在字符串常量区中 2&#xff0c…

Unity编辑器从PC平台切换到Android平台下 Addressable 加载模型出现粉红色,类似于材质丢失的问题

Unity编辑器在PC平台下使用Addressable加载打包好的Cube&#xff0c;运行发现能正常显示。 而在切换到Android平台下&#xff0c;使用Addressable时加载AB包&#xff0c;生成Cube对象时&#xff0c;Cube模型呈现粉红色&#xff0c;出现类似材质丢失的问题。如下图所示。 这是…

Dubbo-SPI机制

1、Java的SPI机制 SPI的全称是Service Provider Interface&#xff0c;是JDK内置的动态加载实现扩展点的机制&#xff0c;通过SPI可以动态获取接口的实现类&#xff0c;属于一种设计理念。 系统设计的各个抽象&#xff0c;往往有很多不同的实现方案&#xff0c;在面向的对象的…