用 Wireshark 解码 H.264

H264,你不知道的小技巧-腾讯云开发者社区-腾讯云

这篇文章写的非常好

这里仅做几点补充

init.lua内容:

-- Set enable_lua to false to disable Lua support.
enable_lua = trueif not enable_lua thenreturn
end-- If false and Wireshark was started as (setuid) root, then the user
-- will not be able to execute custom Lua scripts from the personal
-- configuration directory, the -Xlua_script command line option or
-- the Lua Evaluate menu option in the GUI.
-- Note: Not checked on Windows. running_superuser is always false.
--run_user_scripts_when_superuser = truedofile(DATA_DIR.."rtp_h264_extractor.lua")

init.lua 放到了这个目录:

C:\Program Files\Wireshark\plugins

rtp_h264_extractor.lua 内容为:


--[[* rtp_h264_extractor.lua* wireshark plugin to extract h264 stream from RTP packets** Copyright (C) 2015 Volvet Zhang <volvet2002@gmail.com>** rtp_h264_extractor is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* License as published by the Free Software Foundation; either* version 2.1 of the License, or (at your option) any later version.** rtp_h264_extractor is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU* Lesser General Public License for more details.** You should have received a copy of the GNU Lesser General Public* License along with FFmpeg; if not, write to the Free Software* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*]]dolocal MAX_JITTER_SIZE = 50local h264_data = Field.new("h264")local rtp_seq = Field.new("rtp.seq")local function extract_h264_from_rtp()local function dump_filter(fd)local fh = "h264";if fd ~= nil and fd ~= "" thenreturn string.format("%s and (%s)", fh, fd)elsereturn fhendendlocal h264_tap = Listener.new("ip", dump_filter(get_filter()))local text_window = TextWindow.new("h264 extractor")local filename = ""local seq_payload_table = { }local pass = 0local packet_count = 0local max_packet_count = 0local fu_info = nillocal pre_seq = 0;local function log(info)text_window:append(info)text_window:append("\n")end-- get_preference is only available since 3.5.0if get_preference thenfilename = get_preference("gui.fileopen.dir") .. "/" .. os.date("video_%Y%m%d-%H%M%S.264")elsefilename = "dump.264"endlog("Dumping H264 stream to " .. filename)local fp = io.open(filename, "wb")if fp == nil thenlog("open dump file fail")endlocal function seq_compare(left, right)if math.abs(right.key - left.key) < 1000 thenreturn left.key < right.keyelsereturn left.key > right.keyendendlocal function dump_single_nal(h264_payload)fp:write("\00\00\00\01")fp:write(h264_payload:tvb()():raw())fp:flush()endlocal function dump_fu_a(fu_info)if  fu_info.complete ==  true thenlog("dump_fu_a")fp:write("\00\00\00\01")fp:write(string.char(fu_info.nal_header))for i, obj in ipairs(fu_info.payloads) dofp:write(obj:tvb()():raw(2))endfp:flush()elselog("Incomplete NAL from FUs, dropped")endendlocal function handle_fu_a(seq, h264_data)fu_indicator = h264_data:get_index(0)fu_header = h264_data:get_index(1)nal_header = bit.bor(bit.band(fu_indicator, 0xe0), bit.band(fu_header, 0x1f))if bit.band(fu_header, 0x80) ~= 0 then-- fu start flag foundfu_info = { }fu_info.payloads = { }fu_info.seq = seqfu_info.complete = truefu_info.nal_header = nal_headertable.insert(fu_info.payloads, h264_data)log("Fu start: seq = "..tostring(seq))returnendif fu_info == nil thenlog("Incomplete FU found: No start flag, dropped")returnendif seq ~= (fu_info.seq + 1)% 65536 thenlog("Incomplete FU found:  fu_info.seq = "..tostring(fu_info.seq)..", input seq = "..tostring(seq))fu_info.complete = false;returnendfu_info.seq = seqtable.insert(fu_info.payloads, h264_data)if bit.band(fu_header, 0x40) ~= 0 then-- fu end flag foundlog("Fu stop: seq = "..tostring(seq))dump_fu_a(fu_info)fu_info = nilendendlocal function handle_stap_a(h264_data)log("start dump stap nals")offset = 1		-- skip nal header of STAP-Arepeatsize = h264_data:tvb()(offset, 2):uint()offset = offset + 2local next_nal_type = bit.band(h264_data:get_index(offset), 0x1f)log("STAP-A has naltype = "..next_nal_type..", size = "..size)fp:write("\00\00\00\01")fp:write(h264_data:tvb()():raw(offset, size))offset = offset + sizeuntil offset >= h264_data:tvb():len()fp:flush()log("finish dump stap nals")endlocal function on_ordered_h264_payload(seq, h264_data)local naltype = bit.band(h264_data:get_index(0), 0x1f)if naltype > 0 and naltype < 24 then-- Single NAL unit packetif fu_info ~= nil thenlog("Incomplete FU found: No start flag, dropped")fu_info = nilenddump_single_nal(h264_data)--log("tap.packet: "..", single nal packet dumpped, naltype = "..tostring(naltype)..", len = "..tostring(packet.len))elseif naltype == 28 then-- FU-Ahandle_fu_a(seq, h264_data)elseif naltype == 24 then-- STAP-Aif fu_info ~= nil thenlog("Incomplete FU found: No start flag, dropped")fu_info = nilendhandle_stap_a(h264_data)elselog("tap.packet: "..", Unsupported nal, naltype = "..tostring(naltype))endendlocal function on_jitter_buffer_output()table.sort(seq_payload_table, seq_compare)if #seq_payload_table > 0 thenlog("on_jitter_buffer_output:  seq = "..tostring(seq_payload_table[1].key)..", payload len = "..tostring(seq_payload_table[1].value:len()))on_ordered_h264_payload(seq_payload_table[1].key, seq_payload_table[1].value)table.remove(seq_payload_table, 1)endendlocal function jitter_buffer_finilize()for i, obj in ipairs(seq_payload_table) dolog("jitter_buffer_finilize:  seq = "..tostring(obj.key)..", payload len = "..tostring(obj.value:len()))on_ordered_h264_payload(obj.key, obj.value)endendlocal function on_h264_rtp_payload(seq, payload)local cur_seq = seq.value--log("on_h264_rtp_payload:  seq = "..tostring(seq.value)..", payload len = "..tostring(payload.len)..",pre_seq = "..pre_seq..",cur_seq = "..cur_seq..",packet_count = "..packet_count)if packet_count == 0 thenpre_seq = cur_seqelseif cur_seq == pre_seq thenpacket_count = packet_count + 1--log("on_h264_rtp_payload, duplicate seq = "..tostring(seq.value)..",packet_count = "..packet_count)returnelsepre_seq = cur_seqendendpacket_count = packet_count + 1table.insert(seq_payload_table, { key = tonumber(seq.value), value = payload.value })--log("on_h264_rtp_payload: table size is "..tostring(#seq_payload_table))if #seq_payload_table > MAX_JITTER_SIZE thenon_jitter_buffer_output()endendfunction h264_tap.packet(pinfo, tvb)local payloadTable = { h264_data() }local seqTable = { rtp_seq() }if (#payloadTable) < (#seqTable) thenlog("ERROR: payloadTable size is "..tostring(#payloadTable)..", seqTable size is "..tostring(#seqTable))returnendif pass == 0 thenfor i, payload in ipairs(payloadTable) domax_packet_count = max_packet_count + 1endelsefor i, payload in ipairs(payloadTable) doon_h264_rtp_payload(seqTable[1], payload)endif packet_count == max_packet_count thenjitter_buffer_finilize()endendendfunction h264_tap.reset()endfunction h264_tap.draw()endlocal function remove()if fp thenfp:close()fp = nilendh264_tap:remove()endlog("Start")text_window:set_atclose(remove)log("phase 1")pass = 0retap_packets()log("phase 2:  max_packet_count = "..tostring(max_packet_count))pass = 1retap_packets()if fp ~= nil thenfp:close()fp = nillog("Video stream written to " .. filename)endlog("End")endregister_menu("Extract h264 stream from RTP", extract_h264_from_rtp, MENU_TOOLS_UNSORTED)
end

该文件放到了这里:

C:\Program Files\Wireshark

此外,Elecard StreamEye Tools 可以到这里下载:

Download video analysis and monitoring applications| Elecard: Video Compression GuruDownload Elecard products for video analysis and monitoring, encoding and decoding video of various formats.icon-default.png?t=N7T8https://www.elecard.com/software

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/794178.shtml

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

相关文章

【蓝桥杯每日一题】4.1 奶酪

我天&#xff01;哥们经过两个周的忙碌又重生了&#xff01; 原题链接&#xff1a;528. 奶酪 - AcWing题库 本题注意点&#xff1a; 注意几个边界值&#xff0c;如果说没有球连接顶部或者底部&#xff0c;老鼠是不可能上来的&#xff0c;直接say no!要利用公式判断两个球是相…

零基础轻松入门Java数据库连接(JDBC)

什么是JDBC&#xff1f; Java数据库连接&#xff08;JDBC&#xff09;就像是Java程序和数据库之间的翻译官。它是一个官方的标准接口集&#xff0c;让Java程序能和不同的数据库“对话”。甭管你是在跟MySQL、Oracle还是SQL Server打交道&#xff0c;只要有了JDBC&#xff0c;J…

OpenCV入门例程:裁剪图片、模糊检测、黑屏检测

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 本例程运行环境为CentOS7&…

AI创业机会的探索

AI创业机会的探索 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已成为当今世界的重要技术之一。AI的广泛应用不仅改变了我们的生活方式&#xff0c;也为创业者带来了前所未有的机会。以下&#xff0c;我们将一起探讨AI领域中的一些创业机会。 一、智能…

JS详解-函数柯里化

简介&#xff1a; 柯里化&#xff08;Currying&#xff09;是一种关于函数的高阶技术。柯里化是一种函数的转换&#xff0c;它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。柯里化不会调用函数。它只是对函数进行转换。 举个例子&#xff1a; 已最简单的…

图像处理入门 3(how to get the pixel pitch / 如何获得单个像素的尺寸)

在这里一节里面&#xff0c;将记录如何获得一个相机传感器中单个像素点的尺寸&#xff0c;为了实现不同相机照片之间的匹配。 如果我们知道了相机传感器的尺寸和分辨率的大小&#xff0c;自然就可以求出单个像素的大小。 在这里插入图片描述&#xff1a; 如何获得相机传感器的…

Redis 怎么发布订阅

在Redis中&#xff0c;发布-订阅模式&#xff08;Pub/Sub&#xff09;允许客户端&#xff08;订阅者&#xff09;订阅频道&#xff0c;并接收其他客户端&#xff08;发布者&#xff09;发送到该频道的消息。下面是如何在Redis中使用发布-订阅模式的简要说明&#xff1a; 订阅频…

C++多线程:async、future、packaged_task、promise、shared_future的学习与使用(九)

1、异步任务线程 异步线程的概念&#xff1a; 异步&#xff1a;就是非同步&#xff0c;同步就是必须一个一个的执行&#xff0c;异步可以两个事情一起干异步线程&#xff1a;异步线程就相当于把非关联的两件事分开找两个线程去执行&#xff0c;而分开的那个就是异步线程举例&am…

06-kafka配置

生产者配置 NAMEDESCRIPTIONTYPEDEFAULTVALID VALUESIMPORTANCEbootstrap.servershost/port列表&#xff0c;用于初始化建立和Kafka集群的连接。列表格式为host1:port1,host2:port2,…&#xff0c;无需添加所有的集群地址&#xff0c;kafka会根据提供的地址发现其他的地址&…

golang设计模式图解——模板方法模式

设计模式 GoF提出的设计模式有23个&#xff0c;包括&#xff1a; &#xff08;1&#xff09;创建型(Creational)模式&#xff1a;如何创建对象&#xff1b; &#xff08;2&#xff09;结构型(Structural )模式&#xff1a;如何实现类或对象的组合&#xff1b; &#xff08;3&a…

FastAPI Web框架教程 第13章 WebSocket

13-1 WebSocket是什么 WebSocket简介&#xff1a; WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。 在WebSocket API中&#xff0c;浏览器和服务器只需要完成一…

【JavaSE】反射

Java代码的生命周期 Java代码在计算机中经历的阶段&#xff1a;Source源代码阶段、Class类对象阶段、RunTime运行时阶段。 Source源代码阶段: 这个阶段是由程序员编写生成源代码,再由Javac编译器生成class文件。 Class类对象阶段&#xff1a;由类加载器将class文件加载到JVM内…

【网站项目】少儿编程管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

备战蓝桥杯---多路归并与归并排序刷题

话不多说&#xff0c;直接看题 1. 我们考虑一行一行合并&#xff0c;一共m次&#xff0c;我们合并两个并取前n小&#xff0c;那么我们怎么取&#xff1f; 我们采用分组的思想&#xff1a; 我们选第一列的min,然后把后面那个再纳入考虑&#xff0c;用优先队列实现即可。 下面…

chatGPT4无法登录

遇到问题&#xff1a;chatgpt网站上点击登录&#xff08;log in),网站就会跳转并显示&#xff1a;unable to connect 解决方法&#xff1a;不要用亚洲节点&#xff0c;亚洲节点被全面封禁&#xff0c;在全局代理中可以换成美国的节点

synchronized到底锁住的是谁?

我们使用synchronized关键字是用来实现线程同步的&#xff0c;当多个线程同时去争抢同一个资源的时候在资源上边加一个synchronized关键字&#xff0c;能够使得线程排队去完成操作。 synchronized到底锁定的是什么资源&#xff1f; 修饰方法非静态方法 &#xff0c;锁定的是方…

《UE5_C++多人TPS完整教程》学习笔记30 ——《P31 摄像机和弹簧臂(Camera And Spring Arm)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P31 摄像机和弹簧臂&#xff08;Camera And Spring Arm&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;…

使用git 和 github协作开发

文章目录 github浏览器汉化插件github新建仓库git安装以及ssh配置团队创建及基本命令的使用创建团队基本命令 分支管理快速切换远程仓库地址 如何使用git && github进行协作开发&#xff0c;包括git常见基础命令 github浏览器汉化插件 在刚开始使用github的时候&#…

ubuntu安装docker,并搭建vulfocus靶场

ubuntu安装docker&#xff0c;并搭建vulfocus靶场 docker是一个容器管理的软件&#xff0c;容器背后其实就是一个进程&#xff1b;类似于一个集装箱。 docker的官方下载地址&#xff1a;Install Docker Engine on Ubuntu | Docker Documentation&#xff08;可以根据自己需要的…

BL200耦合器数据采集模块

BL200耦合器数据采集模块是一个数据采集和控制系统&#xff0c;基于强大的32 位ARM926EJ-S™ 微处理器设计&#xff0c;采用Linux操作系统&#xff0c;支持Modbus TCP协议&#xff0c;可以快速接入现场PLC、MES、Ignition和SCADA以及ERP系统&#xff0c;同时也能快速连接到AWS云…