当前位置: 首页 > news >正文

【H.264】H.264详解(二)—— H264视频码流解析示例源码

文章目录

    • 一、前言
    • 二、示例源码
      • 【1】目录结构
      • 【2】Makefile源码
      • 【3】h264parser.c源码
      • 【4】编译运行
      • 【5】源码下载地址

声明:此篇示例源码非原创,原作者雷霄骅。雷霄骅,中国传媒大学通信与信息系统专业博士生,在此向雷霄骅雷神致敬。
代码原文地址:视音频数据处理入门:H.264视频码流解析

一、前言

示例源码是一个H.264码流解析程序。该程序可以从H.264码流中分析得到它的基本单元NALU,分离出NALU,然后再分析NALU的各个字段。

关于NALU的相关内容可参考文章【H.264】H.264详解(一)—— 一文看懂H.264协议

二、示例源码

【1】目录结构

project/
├── Makefile
├── h264parser.c
├── sintel.h264

【2】Makefile源码

app:h264parser.cgcc -o app h264parser.c
clean:rm -f app

【3】h264parser.c源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef enum {NALU_TYPE_SLICE    = 1,NALU_TYPE_DPA      = 2,NALU_TYPE_DPB      = 3,NALU_TYPE_DPC      = 4,NALU_TYPE_IDR      = 5,NALU_TYPE_SEI      = 6,NALU_TYPE_SPS      = 7,NALU_TYPE_PPS      = 8,NALU_TYPE_AUD      = 9,NALU_TYPE_EOSEQ    = 10,NALU_TYPE_EOSTREAM = 11,NALU_TYPE_FILL     = 12,
} NaluType;typedef enum {NALU_PRIORITY_DISPOSABLE = 0,NALU_PRIRITY_LOW         = 1,NALU_PRIORITY_HIGH       = 2,NALU_PRIORITY_HIGHEST    = 3
} NaluPriority;typedef struct{int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)unsigned len;                 //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)unsigned max_size;            //! Nal Unit Buffer sizeint forbidden_bit;            //! should be always FALSEint nal_reference_idc;        //! NALU_PRIORITY_xxxxint nal_unit_type;            //! NALU_TYPE_xxxx    char *buf;                    //! contains the first byte followed by the EBSP
} NALU_t;FILE *h264bitstream = NULL;                //!< the bit stream fileint info2=0, info3=0;static int FindStartCode2 (unsigned char *Buf){if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=1) return 0; //0x000001?else return 1;
}static int FindStartCode3 (unsigned char *Buf){if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=0 || Buf[3] !=1) return 0;//0x00000001?else return 1;
}int GetAnnexbNALU (NALU_t *nalu){int pos = 0;int StartCodeFound, rewind;unsigned char *Buf;if ((Buf = (unsigned char*)calloc (nalu->max_size , sizeof(char))) == NULL) printf ("GetAnnexbNALU: Could not allocate Buf memory\n");nalu->startcodeprefix_len=3;if (3 != fread (Buf, 1, 3, h264bitstream)){free(Buf);return 0;}info2 = FindStartCode2 (Buf);if(info2 != 1) {if(1 != fread(Buf+3, 1, 1, h264bitstream)){free(Buf);return 0;}info3 = FindStartCode3 (Buf);if (info3 != 1){ free(Buf);return -1;}else {pos = 4;nalu->startcodeprefix_len = 4;}}else{nalu->startcodeprefix_len = 3;pos = 3;}StartCodeFound = 0;info2 = 0;info3 = 0;while (!StartCodeFound){if (feof (h264bitstream)){nalu->len = (pos-1)-nalu->startcodeprefix_len;memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);     nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bitnalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bitnalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bitfree(Buf);return pos-1;}Buf[pos++] = fgetc (h264bitstream);info3 = FindStartCode3(&Buf[pos-4]);if(info3 != 1)info2 = FindStartCode2(&Buf[pos-3]);StartCodeFound = (info2 == 1 || info3 == 1);}// Here, we have found another start code (and read length of startcode bytes more than we should// have.  Hence, go back in the filerewind = (info3 == 1)? -4 : -3;if (0 != fseek (h264bitstream, rewind, SEEK_CUR)){free(Buf);printf("GetAnnexbNALU: Cannot fseek in the bit stream file");}// Here the Start code, the complete NALU, and the next start code is in the Buf.  // The size of Buf is pos, pos+rewind are the number of bytes excluding the next// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start codenalu->len = (pos+rewind)-nalu->startcodeprefix_len;memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bitnalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bitnalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bitfree(Buf);return (pos+rewind);
}/*** Analysis H.264 Bitstream* @param url    Location of input H.264 bitstream file.*/
int simplest_h264_parser(char *url){NALU_t *n = NULL;int buffersize=100000;//FILE *myout=fopen("output_log.txt","wb+");FILE *myout=stdout;h264bitstream=fopen(url, "rb+");if (h264bitstream==NULL){printf("Open file error\n");return 0;}n = (NALU_t*)calloc (1, sizeof(NALU_t));if (n == NULL){printf("Alloc NALU Error\n");return 0;}n->max_size=buffersize;n->buf = (char*)calloc (buffersize, sizeof(char));if (n->buf == NULL){free (n);printf ("AllocNALU: n->buf");return 0;}int data_offset=0;int nal_num=0;printf("-----+-------- NALU Table ------+---------+\n");printf(" NUM |   POS   |   IDC  |  TYPE |   LEN   |\n");printf("-----+---------+--------+-------+---------+\n");while(!feof(h264bitstream)){int data_lenth;data_lenth=GetAnnexbNALU(n);char type_str[20]={0};switch(n->nal_unit_type){case NALU_TYPE_SLICE:sprintf(type_str,"SLICE");break;case NALU_TYPE_DPA:sprintf(type_str,"DPA");break;case NALU_TYPE_DPB:sprintf(type_str,"DPB");break;case NALU_TYPE_DPC:sprintf(type_str,"DPC");break;case NALU_TYPE_IDR:sprintf(type_str,"IDR");break;case NALU_TYPE_SEI:sprintf(type_str,"SEI");break;case NALU_TYPE_SPS:sprintf(type_str,"SPS");break;case NALU_TYPE_PPS:sprintf(type_str,"PPS");break;case NALU_TYPE_AUD:sprintf(type_str,"AUD");break;case NALU_TYPE_EOSEQ:sprintf(type_str,"EOSEQ");break;case NALU_TYPE_EOSTREAM:sprintf(type_str,"EOSTREAM");break;case NALU_TYPE_FILL:sprintf(type_str,"FILL");break;}char idc_str[20]={0};switch(n->nal_reference_idc>>5){case NALU_PRIORITY_DISPOSABLE:sprintf(idc_str,"DISPOS");break;case NALU_PRIRITY_LOW:sprintf(idc_str,"LOW");break;case NALU_PRIORITY_HIGH:sprintf(idc_str,"HIGH");break;case NALU_PRIORITY_HIGHEST:sprintf(idc_str,"HIGHEST");break;}fprintf(myout,"%5d| %8d| %7s| %6s| %8d|\n",nal_num,data_offset,idc_str,type_str,n->len);data_offset=data_offset+data_lenth;nal_num++;}//Freeif (n){if (n->buf){free(n->buf);n->buf=NULL;}free (n);}return 0;
}int main(int argc, char* argv[]){simplest_h264_parser("sintel.h264");return 0;
}

【4】编译运行

在这里插入图片描述

【5】源码下载地址

H.264详解(二)- H264视频码流解析示例源码

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 使用协程实现调用接口 验证抽奖概率
  • vue-快速入门
  • 周末两天我搭建了一个智能问答ai工具网站
  • vue3——利用自定义指令实现下拉框分页懒加载
  • 前端模块化CommonJS、AMD、CMD、ES6
  • MYSQL(2) 高级查询
  • sql注入 mysql 执行命令 sql注入以及解决的办法
  • C语言 #具有展开功能的排雷游戏
  • WHAT - 不同 HTTP Methods 使用场景、使用方法和可能遇到的问题
  • 力扣1089复写0
  • JVM 性能分析—— 一文带你读懂 G1 垃圾收集器收集流程
  • 鸿蒙应用框架开发【OpenGL三棱椎】 NDK
  • postgres数据库连接超时问题处理
  • ArcGIS Pro SDK (九)几何 17 几何引擎函数
  • @Builder注释导致@RequestBody的前端json反序列化失败,HTTP400
  • 「面试题」如何实现一个圣杯布局?
  • create-react-app做的留言板
  • GitUp, 你不可错过的秀外慧中的git工具
  • input实现文字超出省略号功能
  • React Transition Group -- Transition 组件
  • Redis 中的布隆过滤器
  • Redis在Web项目中的应用与实践
  • SOFAMosn配置模型
  • SpringCloud集成分布式事务LCN (一)
  • 二维平面内的碰撞检测【一】
  • 技术发展面试
  • 今年的LC3大会没了?
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 如何实现 font-size 的响应式
  • 小而合理的前端理论:rscss和rsjs
  • 责任链模式的两种实现
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • zabbix3.2监控linux磁盘IO
  • 积累各种好的链接
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​学习一下,什么是预包装食品?​
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (二)Linux——Linux常用指令
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (接口封装)
  • (算法二)滑动窗口
  • (五)MySQL的备份及恢复
  • .axf 转化 .bin文件 的方法
  • .NET 直连SAP HANA数据库
  • .net下简单快捷的数值高低位切换
  • ??在JSP中,java和JavaScript如何交互?
  • @Autowired 与@Resource的区别
  • @GlobalLock注解作用与原理解析
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • [AIGC codze] Kafka 的 rebalance 机制