【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视频码流解析示例源码

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

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

相关文章

【Python机器学习】朴素贝叶斯——条件概率

条件概率 假设现在有一个装了7块石头的罐子&#xff08;3块灰色&#xff0c;4块黑色&#xff09;&#xff0c;如果从中随机取出一块&#xff0c;灰色的可能性就是3/7&#xff0c;黑色的可能性是4/7。我们使用p(gray)来表示取到灰色石头的概率&#xff0c;其概率值可以通过灰色…

cocos creator 3学习记录01——如何替换图片

一、动态加载本地图片 1、通过将图片关联到CCClass属性上来进行代码切换。 1、这种方法&#xff0c;需要提前在脚本文件中声明好代表图片的CCClass属性。 2、然后拖动图片资源&#xff0c;到脚本内声明好的属性上以进行关联。 3、然后通过程序&#xff0c;来进行切换展示。…

unity2D游戏开发01项目搭建

1新建项目 选择2d模板,设置项目名称和存储位置 在Hierarchy面板右击&#xff0c;create Empty 添加组件 在Project视图中右键新建文件夹 将图片资源拖进来&#xff08;图片资源在我的下载里面&#xff09; 点击Player 修改属性&#xff0c;修好如下 点击Sprite Editor 选择第二…

Hadoop3:HDFS的客户端工具Big Data Tools(IDEA版本)

1、安装插件 在Plugins里搜索Big Data Tools 安装完成后&#xff0c;重启IDEA 2、配置Windows环境 主要是配置Hadoop环境&#xff0c;否则无法通过插件远程连接HDFS 1、解压hadoop安装包 2、进入hadoop的bin目录 放入图中标红的两个文件 3、配置hadoop环境变量 新建HAD…

freertos的学习cubemx版

HAL 库的freertos 1 实时 2 任务->线程 3 移植 CMSIS_V2 V1版本 NVIC配置全部是抢占优先级 第四组 抢占级别有 0-15 编码规则&#xff0c; 变量名 &#xff1a;类型前缀&#xff0c; c - char S - int16_t L - int32_t U - unsigned Uc - uint8_t Us - uint…

【游戏制作】使用Python创建一个完整的2048游戏项目

目录 项目运行展示 项目概述 项目目标 项目结构 安装依赖 代码实现 1. 导入库 2. 创建 Game2048 类 3. 设置UI界面 4. 加载二维码图片 5. 创建菜单 6. 游戏逻辑和功能 7. 运行应用 总结 创建一个完整的2048游戏项目 项目运行展示 项目概述 在这个项目中&#xff…

19 Python常用内置函数——range()

range() 是 Python 开发中非常常用的一个内置函数。该函数返回具有惰性求值特点的 range 对象&#xff0c;其中包含左闭右开区间 [start, end) 内以 step 为步长的整数。 参数 start 默认为 0&#xff0c;step 默认为 1。 print(range(5)) print(list(range(5))) print(list(r…

Zenario CMS 9.2 文件上传漏洞(CVE-2022-23043)

前言 CVE-2022-23043 是一个影响 Zenario CMS 9.2 的严重漏洞。该漏洞允许经过身份验证的管理员用户绕过文件上传限制。具体来说&#xff0c;管理员可以通过创建一个新的带有 ".phar" 扩展名的“文件/MIME 类型”&#xff0c;然后上传一个恶意文件。在上传过程中&am…

Java从入门到精通 (十一) ~ 操作系统、进程和线程

无论做什么&#xff0c;请记住都是为你自己而做&#xff0c;这样就毫无怨言&#xff01;今天&#xff0c;我为自己而活&#xff01;今天&#xff0c;又是美丽的一天&#xff01;早安&#xff0c;朋友&#xff01; 目录 前言 一、操作系统 1. 概念 2. 操作系统的基本功能 3…

FPGA开发——LED流水灯实现先从左往右流水,再从右往左流水

一、概述 我们在设计完一个方向的流水灯的设计时&#xff0c;总是会想实现让流水灯倒着流水回去的设计&#xff0c;这里我也是一样&#xff0c;实现这种设计的方法有很多种&#xff0c;其中就有直接使用case语句将所有可能包含进去编写&#xff0c;这种设计方法是最简单的&…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(四)高斯牛顿法详解

一、高斯牛顿法详解 拓展阅读&#xff1a;高斯牛顿法详解_gauss-newton算法步骤-CSDN博客 1、梯度下降法 ​ ​ ​ 无论一阶泰勒展开&#xff0c;还是二阶泰勒展开都是关于增量​的方程。 2、牛顿法 ​ 这个自变量增量都是可求的。但是二阶求解复杂。因此为了简化有了下…

windows下运行sh文件

1、打开git bash 2、进入sh文件所在文件夹&#xff0c;使用sh xx.sh运行

@RequiredArgsConstructor详解

RequiredArgsConstructor详解 一、什么是RequiredArgsConstructor? RequiredArgsConstructor是Lombok的一个注解&#xff0c;简化了我们对Autowired书写&#xff0c;我们在写Controller层或者Service层的时候&#xff0c;总是需要注入很多mapper接口或者service接口&#xf…

初识Play Framework框架和第一个Java play web项目的创建

文章目录 初识Play Framework框架和第一个Java play web项目的创建一、简介特点架构开发流程示例代码总结 二、创建第一个Java play web项目1、下载play框架&#xff0c;配置系统环境变量(jdk的安装就不再说了) 2、检查play的版本和创建第一个play项目3、将项目通过idea或eclip…

【NoSQL数据库】Redis知识小册

一、缓存穿透 缓存穿透是先查Redis&#xff0c;发现缓存中没有数据&#xff0c;再查数据库。然而&#xff0c;如果查询的数据在数据库中也不存在&#xff0c;那么每次查询都会绕过缓存&#xff0c;直接落到数据库上。 解决方案一、缓存空数据 查询Redis缓存&#xff1a;首先查…

Java泛型的介绍和基本使用

什么是泛型 ​ 泛型就是将类型参数化&#xff0c;比如定义了一个栈&#xff0c;你必须在定义之前声明这个栈中存放的数据的类型&#xff0c;是int也好是double或者其他的引用数据类型也好&#xff0c;定义好了之后这个栈就无法用来存放其他类型的数据。如果这时候我们想要使用这…

Codeforces 903 div3 A-F

A 题目分析 数据范围很小&#xff0c;暴力枚举即可&#xff0c;然后给字符串x的长度设置一个上限&#xff0c;我设了50&#xff0c;因为n*m<25&#xff0c;多一倍够用了 C代码 #include<iostream> using namespace std; void solve(){int n,m;string x,s;cin>>…

基于RS485的Modbus协议

RS485&#xff1a;用来传输数据&#xff0c;RS485是一种差分传输的串行通信标准&#xff0c;以其强大的抗干扰能力、长距离传输和多点通信能力&#xff0c;在工业控制领域得到广泛应用。RS485使用一对差分信号线&#xff08;A和B&#xff09;来传输数据&#xff0c;差分信号能有…

eclipse ui bug

eclipse ui bug界面缺陷&#xff0c;可能项目过多&#xff0c;特别maven项目过多&#xff0c;下载&#xff0c;自动编译&#xff0c;加载更新界面异常 所有窗口死活Restore不回去了 1&#xff09;尝试创建项目&#xff0c;还原界面&#xff0c;失败 2&#xff09;关闭所有窗口&…

Django学习(二)

get请求 练习&#xff1a; views.py def test_method(request):if request.method GET:print(request.GET)# 如果链接中没有参数a会报错print(request.GET[a])# 使用这个方法&#xff0c;当查询不到参数时&#xff0c;不会报错而是返回你设置的值print(request.GET.get(c,n…