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

纯C读取文件实现解析H264裸流每一帧数据

        最近研究硬解解码,需要解码H264流文件。

        imx的例程是设置一个大的缓冲区,一次性读入不超过10M字节数据,然后全部送到解码器进行解码,对于小于10M字节的视频数据确实很方便的解码了,但是文件大了这种方式就不行了。

        如果暴力分段送入解码器,因为无法找到H264的起始码,解码器会报错。

        还有一种处理方式是使用FFMpeg来读取每一帧数据,然后送入解码器,是可行的。参考这篇博文。

使用FFmpeg开发2-比特流过滤器-CSDN博客

        但是为了简化方便,不想用FFMpeg来实现。

        这里写个纯C读取文件实现分离H264帧。

        首先分析下H264裸流文件,发现每一帧数据的起始码是00 00 00 01,那么就可以利用这个起始码来拆分每一帧数据。

        代码很简单,就是持续读取文件,碰到00 00 00 01则表示一帧读完,然后把这一帧数据送到解码器处理即可。

        因为每一帧的开头都是这个起始码,所以开始直接读取四字节。

//读取一帧H264数据
int read_one_frame(FILE *fp, unsigned char *ptr){
	int size=0;
	static unsigned char ts[4]={0};
	printf("read one frame\n");
    //防止文件数据错误
	if(fread(ptr,1,4,fp)<4){
        printf("read start error\n");
        return size;
    }

	if((*ptr==0x00) && (*(ptr+1)==0x00) && (*(ptr+2)==0x00) && (*(ptr+3)==0x01)){
		 
		size=4;
		while(1){
			if(fread(ptr+size,1,1,fp)){
			
				ts[0]=ts[1];
				ts[1]=ts[2];
				ts[2]=ts[3];
				ts[3]=*(ptr+size);
				size++;
				if((ts[0]==0x00) && (ts[1]==0x00) && (ts[2]==0x00) && (ts[3]==0x01) ){
					//读取到下一帧的起始码,即表示这帧读完了,后移文件指针
                    size-=4;
					fseek(fp,-4,SEEK_CUR);
					//printf("read one frame end \n");
					break;
				}
			}else
				break;//读完文件退出循环
		}
	}
    //读取到的数据大小
	return size;
}

再写个小小的main来测试下

#include <stdio.h>
#include <stdlib.h>


int main(void){
	int readbytes;
	int totalReadSize=0;
	int length=1024*1024*10;
	unsigned char *ptr;
	ptr=malloc(length);
	FILE *fp=fopen("200frames_count.h264", "rb");
	int fileSize;
	fseek(fp, 0L, SEEK_END);
	fileSize = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	printf("fileSize=0x%x\n", fileSize);
	while(totalReadSize<fileSize){
		readbytes=read_one_frame(fp, ptr);
		if(readbytes==0){
			printf("read end\n");
			break;
		}else{
			for(int i=0;i<readbytes;i++)
				printf("%x ", *(ptr+i));
		}
		totalReadSize+=readbytes;
		printf("readbytes: 0x%X    total read size: 0x%X \r\n",readbytes, totalReadSize);
	}

	return 0;
	
}

从打印数据看,成功实现了每一帧数据的读取,经过测试可用,老铁们可以自己拿去优化使用。

对于H264裸流文件可以这么处理,如果是带格式的,老铁们还是用FFMpeg吧。


http://www.kler.cn/a/156948.html

相关文章:

  • ESLint 使用教程(三):12个ESLint 配置项功能与使用方式详解
  • LabVIEW 实现 find_nearest_neighbors 功能(二维平面上的最近邻查找)
  • 基于MATLAB+opencv人脸疲劳检测
  • xrandr源码分析
  • python数据写入excel文件
  • Qwen2 系列大型语言模型
  • 回归分析:预测和建模
  • Git 简介及异常场景处理
  • 12月4日作业
  • 作业12.4
  • 分享77个菜单导航JS特效,总有一款适合您
  • JDBC常见的几种连接池使用(C3P0、Druid、HikariCP 、DBCP)(附上代码详细讲解)
  • 软件测试【理论基础】
  • 基于AT89C51单片机的秒表设计
  • Python机器学习、深度学习入门丨气象常用科学计算库、气象海洋常用可视化库、爬虫和气象海洋数据、气象海洋常用插值方法、EOF统计分析、WRF模式后处理等
  • Stream 流
  • 【Vue】Linux 运行 npm run serve 报错 vue-cli-service: Permission denied
  • Django总结
  • 【bug排查解决】现象级延迟8-10s
  • 编程语言中常量(Constant)简介
  • Python (十八) 正则表达式
  • 外包干了2个月,技术退步明显。。。。。
  • MySQL Connector/J 数据库连接 URL的语法
  • Metasploit渗透测试的漏洞利用和攻击方法
  • Leetcode—409.最长回文串【简单】
  • 语音合成与配音工具(视频配音、微课配音、有声读物、产品营销)