4、提取H264码流中nalu
H264的NALU提取
1、nalu单元
定义nalu的存储单元,ebsp用来存储原始的包含起始码(annexb格式)的原始码流,sodb存储去除防竞争字节后的码流,prefix是3或4字节
nalu_def.h
// nalu_def.h
#pragma once#include <cstdint>class Nalu
{
public:uint8_t* ebsp;uint32_t ebsp_len;uint8_t* sodb;uint32_t sodb_len;uint8_t prefix;uint8_t forbidden_zero_bit; // 1 bituint8_t nal_ref_idc; // 2 bitsuint8_t nal_unit_type; // 5 bitsNalu();Nalu(uint8_t* stream, uint32_t len);~Nalu();void Init(uint8_t* stream, uint32_t len);int ParsePrefix();int ParseRBSP();int ParseHead();uint8_t GetNalUnitType();uint8_t* GetEBSP();uint8_t* GetRBSP();uint8_t* GetSODB();uint32_t GetLenthEBSP();uint32_t GetLenthRBSP();uint32_t GetLenthSODB();};
nalu_def.c
#include <string.h>
#include "nalu_def.h"Nalu::Nalu():ebsp(NULL),ebsp_len(0),sodb(NULL),sodb_len(0),prefix(0),forbidden_zero_bit(0),nal_ref_idc(0),nal_unit_type(0)
{
}Nalu::Nalu(uint8_t* stream, uint32_t len):Nalu()
{Init(stream, len);
}Nalu::~Nalu()
{if (ebsp){delete[] ebsp;}if (sodb){delete[] sodb;}
}void Nalu::Init(uint8_t* stream, uint32_t len)
{if (ebsp){delete[] ebsp;}ebsp = new uint8_t[len];ebsp_len = len;memcpy(ebsp, stream, len);
}int Nalu::ParsePrefix()
{prefix = 0;if (ebsp_len <= 3){if (ebsp[0] == 0 && ebsp[1] == 0 && ebsp[2] == 1)prefix = 3;}else{if (ebsp[0] == 0 && ebsp[1] == 0 && ebsp[2] == 1)prefix = 3;else if (ebsp[0] == 0 && ebsp[1] == 0 && ebsp[2] == 0 && ebsp[3] == 1)prefix = 4;}return prefix == 0 ? -1 : 0;
}int Nalu::ParseRBSP()
{if (ebsp_len < prefix)return -1;if(sodb){delete[] ebsp;}sodb = new uint8_t[ebsp_len];sodb_len = ebsp_len;uint8_t* src = ebsp + prefix;uint8_t* end = ebsp + ebsp_len;uint8_t* dest_temp = sodb;while (src < end){if (src < end - 3 &&(0x00 == src[0] && 0x00 == src[1] && 0x03 == src[2])){*dest_temp++ = 0x00;*dest_temp++ = 0x00;src += 3;continue;}*dest_temp++ = *src++;}sodb_len = dest_temp - sodb;return 0;
}int Nalu::ParseHead()
{if (ebsp_len < prefix + 1)return -1;uint8_t* head = ebsp + prefix;forbidden_zero_bit = (head[0] >> 7) & 0x1;nal_ref_idc = (head[0] >> 5) & 0x3;nal_unit_type = head[0] & 0x1f;return 0;
}uint8_t Nalu::GetNalUnitType()
{return nal_unit_type;
}uint8_t* Nalu::GetEBSP()
{return ebsp;
}uint8_t* Nalu::GetRBSP()
{return ebsp + prefix;
}uint8_t* Nalu::GetSODB()
{return sodb;
}uint32_t Nalu::GetLenthEBSP()
{return ebsp_len;
}uint32_t Nalu::GetLenthRBSP()
{return ebsp_len - prefix;
}uint32_t Nalu::GetLenthSODB()
{return sodb_len;
}
2、nalu文件读取器
每次读取BUFF_SIZE个字节数据到缓冲区中,分割成nalu单元后存入队列,队列为空时加载数据再次存入缓冲区中进行分割
nalu_file_reader.h
#pragma once#include <cstdio>
#include <queue>
#include "nalu_def.h"class NaluFileReader
{
public:NaluFileReader();~NaluFileReader();bool OpenFile(const char* path);Nalu* GetNalu();void CloseFile();private:uint8_t _status;FILE* _file;uint8_t* _buffer;uint32_t _size;std::queue<Nalu*> _nalus;const int32_t BUFF_SIZE = 128 * 1024;void ReadFromFile();int32_t FindStartCode(const uint8_t* buf, uint32_t size, uint8_t* prefix);int Splite();
};
nalu_file_reader.c
#include "nalu_file_reader.h"#pragma warning(disable:4996)NaluFileReader::NaluFileReader() :_status(0),_file(NULL),_buffer(NULL),_size(0)
{_buffer = new uint8_t[BUFF_SIZE];
}NaluFileReader::~NaluFileReader()
{delete[] _buffer;while (!_nalus.empty()){auto nal = _nalus.front();_nalus.pop();delete nal;}
}bool NaluFileReader::OpenFile(const char* path)
{fopen_s(&_file, path, "rb");_status = 0;return _file ? true : false;
}Nalu* NaluFileReader::GetNalu()
{if (!_nalus.empty()){Nalu* nal = _nalus.front();_nalus.pop();return nal;}else if (_status){return NULL;}else{ReadFromFile();Splite();if (!_nalus.empty()){Nalu* nal = _nalus.front();_nalus.pop();return nal;}}return NULL;
}void NaluFileReader::CloseFile()
{fclose(_file);_status = 0;
}void NaluFileReader::ReadFromFile()
{if (_status)return;if (_size != 0){// need seeklong offset = _size;fseek(_file, -offset, SEEK_CUR);_size = 0;}size_t size = fread(_buffer, 1, BUFF_SIZE, _file);if (size != BUFF_SIZE){_status = 1;}_size += size;
}int32_t NaluFileReader::FindStartCode(const uint8_t* buf, uint32_t size, uint8_t* prefix)
{uint32_t pos = 0;*prefix = 0;while (1){if (pos + 4 > size) return -1;if (buf[pos++] != 0x0) continue;if (buf[pos++] != 0x0) continue;if (buf[pos] == 0x01){*prefix = 3;break;}if (buf[pos++] != 0x0) continue;if (buf[pos] == 0x01){*prefix = 4;break;}}return pos + 1;
}int NaluFileReader::Splite()
{uint32_t end_index = 0;uint8_t prefix = 0;uint8_t* buf_stream = _buffer;end_index = FindStartCode(buf_stream, _size, &prefix);if (prefix == 0){return -1;}while (1){uint8_t prefix_pre = prefix;end_index = FindStartCode(buf_stream + prefix, _size - prefix, &prefix);if (prefix == 0){if (_status == 1){Nalu* nalu = new Nalu(buf_stream, _size);_nalus.push(nalu);_size = 0;}break;}else{Nalu* nalu = new Nalu;nalu->Init(buf_stream, end_index - prefix + prefix_pre);_nalus.push(nalu);buf_stream += nalu->GetLenthEBSP();_size -= nalu->GetLenthEBSP();}}return 0;
}
3、使用读取器打印nalu信息
简单示例打印一下所有的nalu单元长度信息
#include <iostream>
#include "nalu_file_reader.h"
using namespace std;int main()
{NaluFileReader nal_reader;nal_reader.OpenFile("F:\\test\\source.h264");while (1){auto nal = nal_reader.GetNalu();if (!nal)break;nal->ParsePrefix(); // 解析前缀0x00000001nal->ParseRBSP(); // 去除防竞争字节nal->ParseHead(); // 解析nal头字段cout << "nal type:" << (int)nal->GetNalUnitType() << ",len:" << nal->GetLenthEBSP() << endl;delete nal;}
}
相关文章:
4、提取H264码流中nalu
H264的NALU提取 1、nalu单元 定义nalu的存储单元,ebsp用来存储原始的包含起始码(annexb格式)的原始码流,sodb存储去除防竞争字节后的码流,prefix是3或4字节 nalu_def.h // nalu_def.h #pragma once#include <cs…...

哈佛大学单细胞课程|笔记汇总 (二)
哈佛大学单细胞课程|笔记汇总 (一) (二)Single-cell RNA-seq data - raw data to count matrix 根据所用文库制备方法的不同,RNA序列(也被称为reads或tag)将从转录本((10X Genomic…...
java中抽象类和接口的区别
文章目录 接口和抽象类的区别一、定义的区别1、抽象类2、接口 二、使用场景的区别1、抽象类2、接口 三、使用案例1、抽象类2、接口 接口和抽象类的区别 一、定义的区别 1、抽象类 关键字: abstract 是模棱两可的,似是而非的,无法给出具体明…...

Spring Boot - 在Spring Boot中实现灵活的API版本控制(下)_ 封装场景启动器Starter
文章目录 Pre设计思路ApiVersion 功能特性使用示例配置示例 ProjectStarter Code自定义注解 ApiVersion配置属性类用于管理API版本自动配置基于Spring MVC的API版本控制实现WebMvcRegistrations接口,用于自定义WebMvc的注册逻辑扩展RequestMappingHandlerMapping的类…...

EasyCVR视频转码:T3视频平台不支持GB28181协议,应该如何实现与视频联网平台的对接与视频共享呢?
EasyCVR视频管理系统以其强大的拓展性、灵活的部署方式、高性能的视频能力和智能化的分析能力,为各行各业的视频监控需求提供了优秀的解决方案。 T3视频为公网HTTP-FLV或HLS格式的视频流,目前T3平台暂不支持国标GB28181协议,因此也无法直接接…...
Spring统一处理请求响应与异常
在web开发中,规范所有请求响应类型,不管是对前端数据处理,还是后端统一数据解析都是非常重要的。今天我们简单的方式实现如何实现这一效果 实现方式 定义响应类型 public class ResponseResult<T> {private static final String SUC…...
SqlServer公用表表达式 (CTE) WITH common_table_expression
SQL Server 中的公用表表达式(Common Table Expressions,简称 CTE)是一种临时命名的结果集,它在执行查询时存在,并且只在该查询执行期间有效。CTE 类似于一个临时的视图或者一个内嵌的查询,但它提供了更好的…...

常见中间件漏洞
Tomcat CVE-2017-12615 1.打开环境,抓包 2.切换请求头为 PUT,请求体添加木马,并在请求头添加木马文件名 1.jsp,后方需要以 / 分隔 3.连接 后台弱口令部署war包 1.打开环境,进入指点位置,账户密码均为 tomcat 2.在此处上传一句话…...

elasticsearch的学习(二):Java api操作elasticsearch
简介 使用Java api操作elasticsearch 创建maven项目 pom.xml文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi…...

docker 部署 ElasticSearch;Kibana
ELasticSearch 创建网络 docker network create es-netES配合Kibana使用时需要组网,使两者运行在同一个网络下 命令 docker run -d \ --name es \ -e "discovery.typesingle-node" \ -v /usr/local/es/data:/usr/share/elasticsearch/data \ -v /usr/…...

k8s使用kustomize来部署应用
k8s使用kustomize来部署应用 本文主要是讲述kustomzie的基本用法。首先,我们说一下部署文件的目录结构。 ./ ├── base │ ├── deployment.yaml │ ├── kustomization.yaml │ └── service.yaml └── overlays└── dev├── kustomization.…...

基于开源FFmpeg和SDL2.0的音视频解码播放和存储系统的实现
目录 1、FFMPEG简介 2、SDL简介 3、视频播放器原理 4、FFMPEG多媒体编解码库 4.1、FFMPEG库 4.2、数据类型 4.3、解码 4.3.1、接口函数 4.3.2、解码流程 4.4、存储(推送) 4.4.1、接口函数 4.4.2、存储流程 5、SDL库介绍 5.1、数据结构 5.…...

保姆级教程,一文了解LVS
目录 一.什么是LVS tips: 二.优点(为什么要用LVS?) 三.作用 四.程序组成 五.LVS 负载均衡集群的类型 六.分布式内容 六.一.分布式存储 六.二.分布式计算 六.三.分布式常见应用 tips: 七.LVS 涉及相关的术语 八.LVS 负…...

【STM32】DMA数据转运(存储器到存储器)
本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发 目录 DMA简介 DMA时钟使能 DMA初始化 转运起始和终止的地址 转运方向 数据宽度 传输次数 转运触发方式 转运模式 通道优先级 开启DMA通道 DMA初始化框架 更改转运次数 DMA应用实例-…...
【Android】通过代码打开输入法
获取焦点 binding.editText.requestFocus()打开键盘 val imm getSystemService(InputMethodManager::class.java) imm.showSoftInput(binding.editText, InputMethodManager.SHOW_IMPLICIT)...
爬虫集群部署:Scrapyd 框架深度解析
🕵️♂️ 爬虫集群部署:Scrapyd 框架深度解析 🛠️ Scrapyd 环境部署 Scrapyd 是一个开源的 Python 爬虫框架,专为分布式爬虫设计。它允许用户在集群中调度和管理爬虫任务,并提供了简洁的 API 进行控制。以下是 Scr…...
pytorch GPU操作事例
>>> import torch >>> if_cuda torch.cuda.is_available() >>> print("if_cuda",if_cuda) if_cuda True >>> gpu_count torch.cuda.device_count() >>> print("gpu_count",gpu_count) gpu_count 8...

linux常见性能监控工具
常用命令top、free 、vmsata、iostat 、sar命令 具体更详细命令可以查看手册,这里只是简述方便找工具 整体性能top,内存看free,磁盘cpu内存历史数据可以vmsata、iostat 、sar、iotop top命令 交互:按P按照CPU排序,按M按照内存…...

C++ | Leetcode C++题解之第331题验证二叉树的前序序列化
题目: 题解: class Solution { public:bool isValidSerialization(string preorder) {int n preorder.length();int i 0;int slots 1;while (i < n) {if (slots 0) {return false;}if (preorder[i] ,) {i;} else if (preorder[i] #){slots--;i…...
【多模态处理】利用GPT逐一读取本地图片并生成描述并保存,支持崩溃后从最新进度恢复
【多模态处理】利用GPT逐一读取本地图片并生成描述,支持崩溃后从最新进度恢复题 代码功能:核心功能最后碎碎念 代码(使用中转平台url):代码(直接使用openai的key) 注意 代码功能: 读…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...