package h264import ("sync"log "github.com/sirupsen/logrus"
)const (DEFAULT_CAP int = 1024 * 1024 * 4// NALU类型NALU_TYPE_SLICE    = 1NALU_TYPE_DPA      = 2NALU_TYPE_DPB      = 3NALU_TYPE_DPC      = 4NALU_TYPE_IDR      = 5NALU_TYPE_SEI      = 6NALU_TYPE_SPS      = 7NALU_TYPE_PPS      = 8NALU_TYPE_AUD      = 9NALU_TYPE_EOSEQ    = 10NALU_TYPE_EOSTREAM = 11NALU_TYPE_FILL     = 12// 优先级NALU_PRIORITY_DISPOSABLE = 0NALU_PRIRITY_LOW         = 1NALU_PRIORITY_HIGH       = 2NALU_PRIORITY_HIGHEST    = 3
)type NaluHead struct {StartCodeLen intForbidden    intReference    intUnitType     int
}type H264Buffer struct {mutex       sync.Mutexdata        []bytedataMaxSize intrPtr        intnaluHeads   []*NaluHead // NALU块信息iFrameIndex []int       // I帧索引列表
}func NewH264Buffer(cap int) *H264Buffer {return &H264Buffer{data:        make([]byte, 0, cap),dataMaxSize: cap,rPtr:        0,naluHeads:   make([]*NaluHead, 0),iFrameIndex: make([]int, 0),}
}func (buf *H264Buffer) Push(d []byte) {buf.mutex.Lock()defer buf.mutex.Unlock()log.Info("H264Buffer push data")if len(d) > buf.dataMaxSize {return}// 计算超出的字节数over := len(buf.data) + len(d) - buf.dataMaxSizeif over > 0 {// 左移超出的字节数buf.data = buf.data[over:]buf.rPtr = buf.rPtr - over}buf.data = append(buf.data, d...)// 更新nalu信息buf.updateNALU()log.Info("I frame indexs: ", buf.iFrameIndex)
}func (buf *H264Buffer) getNALUHead(headIdx int) *NaluHead {return &NaluHead{Forbidden: int(buf.data[headIdx] >> 7),Reference: int((buf.data[headIdx] << 1) >> 6),UnitType:  int((buf.data[headIdx] << 3) >> 3),}
}func (buf *H264Buffer) updateNALU() {buf.naluHeads = make([]*NaluHead, 0)buf.iFrameIndex = make([]int, 0)for i := 0; i < len(buf.data)-5; i++ {if buf.data[i] == 0 && buf.data[i+1] == 0 {if buf.data[i+2] == 1 {head := buf.getNALUHead(i + 3)head.StartCodeLen = 3// 起始码长度为3的情况buf.naluHeads = append(buf.naluHeads, head)if head.UnitType == NALU_TYPE_IDR {buf.iFrameIndex = append(buf.iFrameIndex, i)}}if buf.data[i+2] == 0 && buf.data[i+3] == 1 {head := buf.getNALUHead(i + 4)head.StartCodeLen = 4// 起始码长度为4的情况buf.naluHeads = append(buf.naluHeads, head)if head.UnitType == NALU_TYPE_IDR {buf.iFrameIndex = append(buf.iFrameIndex, i)}}}}
}func (buf *H264Buffer) NaluInfo() {buf.mutex.Lock()defer buf.mutex.Unlock()log.Info("|Index\t|\tForbidden\t|\tReference\t|\tUnitType|")for i, v := range buf.naluHeads {reference := "UNKNOW"switch v.Reference {case NALU_PRIORITY_DISPOSABLE:reference = "DISPOSABLE"case NALU_PRIRITY_LOW:reference = "LOW"case NALU_PRIORITY_HIGH:reference = "HIGH"case NALU_PRIORITY_HIGHEST:reference = "HIGHEST"}naluType := "UNKNOW"switch v.UnitType {case NALU_TYPE_SLICE:naluType = "SLICE"case NALU_TYPE_DPA:naluType = "DPA"case NALU_TYPE_DPB:naluType = "DPB"case NALU_TYPE_DPC:naluType = "DPC"case NALU_TYPE_IDR:naluType = "IDR"case NALU_TYPE_SEI:naluType = "SEI"case NALU_TYPE_SPS:naluType = "SPS"case NALU_TYPE_PPS:naluType = "PPS"case NALU_TYPE_AUD:naluType = "AUD"case NALU_TYPE_EOSEQ:naluType = "EOSEQ"case NALU_TYPE_EOSTREAM:naluType = "EOSTREAM"case NALU_TYPE_FILL:naluType = "FILL"}log.Info("|Index: ", i, "\t\t| StartCodeLen: ", v.StartCodeLen, "\t| Forbidden: ", v.Forbidden,"\t| Reference: ", reference, "\t| UnitType: ", naluType)}
}func (buf *H264Buffer) Pop() []byte {buf.mutex.Lock()defer buf.mutex.Unlock()d := buf.data[buf.rPtr:]buf.rPtr = len(buf.data) - 1return d
}func (buf *H264Buffer) PopLastGOP() []byte {buf.mutex.Lock()defer buf.mutex.Unlock()if len(buf.iFrameIndex) == 0 {log.Info("no I Frame")return make([]byte, 0)}idx := buf.iFrameIndex[len(buf.iFrameIndex)-1]d := buf.data[idx:]log.Info("GOP size: ", len(d))return d
}

测试代码

func main() {d, err := ioutil.ReadFile("sintel.h264")if err != nil {log.Fatal(err)}buffer := h264.NewH264Buffer(h264.DEFAULT_CAP)buffer.Push(d)buffer.NaluInfo()
}

H264码流NALU解析相关推荐

  1. H264码流插入自定义数据(SEI字段)

    文章目录 前言 一.H264码流结构 1. 文字说明 2. 码流格式图解 二.自定义数据封装以及H264码流插入 1.将自定义数据封装成SEI字段通用格式即可插入H264码流中 2.编程逻辑 三.附上 ...

  2. h264码流及h265码流结构分析,NAL头类型分析

    视频编码标准规定了编码后码流的语法语义,也就阐明了从比特流提取语法元素并进行解释的方法,也就是视频的解码过程.   1.h264码流结构解析:     H.264/AVC(Advanced Video ...

  3. RTP协议解析和H264码流提取

    一. h264基础概念 SODB: 数据比特串-->最原始的编码数据 RBSP: 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit&q ...

  4. RTP协议全解析(H264码流和PS流

    写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...

  5. 【H264/AVC 句法和语义详解】(二):h264码流格式与NALU详解一

    上一篇中,我们站在句法元素(或称语法元素)的角度,介绍了H.264的句法和语义,和句法元素的分层结构.在这篇中,我们更进一步,从比特的角度出发,来探索h264码流的组成.通过这篇的学习,我们会初步具备 ...

  6. 音视频压缩:H264码流层次结构和NALU详解

    问题背景: 前面在讲封装格式过程中,都有一个章节讲解如何将H.264的NALU单元如何打包到TS.FLV.RTP中,解装刚好相反,怎么从这些封装格式里面解析出一个个NALU单元.NALU即是编码器的输 ...

  7. RTP协议全解析(H264码流和PS流)(转)

    源: RTP协议全解析(H264码流和PS流) 转载于:https://www.cnblogs.com/LittleTiger/p/10489247.html

  8. RTP协议全解(H264码流和PS流)

    1 视频编码的原理 1.1 一个图像或者一个视频序列进行压缩,产生码流. 对图像的处理即是:帧内预测编码 其预测值P,是由已编码的图像做参考,经运动补偿得到的.预测图像P和当前帧Fn相减,得到两图像的 ...

  9. Android MediaCodec 解码H264码流播放

    视频编解码,编的是什么码?解的又是什么码?有没有想过?现在主流的就是H264码流,Android 采集摄像头原始帧数据 这篇博客讲解的是如何从摄像头从提取YUV画面色值,然后由MediaCodec进行 ...

最新文章

  1. R语言str_extract函数从字符串中抽取匹配模式的字符串
  2. asp.net Web API 身份验证 不记名令牌验证 Bearer Token Authentication 简单实现
  3. python自动化测试框架pytest.pdf_Python 自动化测试框架 unittest 和 pytest 对比
  4. HTTP Header 详解
  5. 你觉得你个性上最大的优点是什么?
  6. Common Used Excel Formulas
  7. 阿诺德图像加密c语言,基于Arnold置乱的数字图像加密算法(二)
  8. qt 下log4cplus的使用
  9. python 之禅 import this
  10. SQL性能第2篇:查询分析和访问路径制定
  11. 记一次悲惨的excel导出事件
  12. 《物联网Android程序开发案例式教程》Demo1:线性布局
  13. Mac中无法运行旧版本印象笔记:版本太旧 你的本地印象笔记数据是由新版印象笔记管理
  14. 国外 计算机专业 网站,国外计算机类核心期刊及其网站
  15. php红包互助源码_完整的微信红包接口API实现(php版)
  16. 如何把照片压缩到20k一下_如何将照片压缩到20k_手机怎么把照片压缩到20k
  17. 装饰器模式:藏在漫威电影里的设计模式
  18. 离散数学 2. 范式、推理
  19. 审稿人意见回复 Response to revierwers (Updating)
  20. IM通讯协议总结之三SIMPLE协议

热门文章

  1. 深度解读数据管理葵花宝典-《DAMA-DMBOK2数据管理知识体系指南(第2版)》
  2. Python模拟手机微博登录
  3. 编译Android 9.0内核源码并刷入手机
  4. 7-15 单继承中的构造函数与析构函数 (10 分)
  5. 7-2 输出学生成绩 C++ 简单做法
  6. 【招聘内推】软告招聘大数据架构师
  7. 陌陌、米聊、微博、微信看IT人士对交际的重视
  8. 西虹市首富:在币圈赔光10亿的一万种办法
  9. 一些在线系统的计时操作的实现(spring-boot计时器使用,时间戳比较先后)
  10. [Java 基础]-- corejava知识汇总