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

2023-12-01 09:44

本文主要是介绍纯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;}}elsebreak;//读完文件退出循环}}//读取到的数据大小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吧。

这篇关于纯C读取文件实现解析H264裸流每一帧数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/440661

相关文章

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

全面解析Golang 中的 Gorilla CORS 中间件正确用法

《全面解析Golang中的GorillaCORS中间件正确用法》Golang中使用gorilla/mux路由器配合rs/cors中间件库可以优雅地解决这个问题,然而,很多人刚开始使用时会遇到配... 目录如何让 golang 中的 Gorilla CORS 中间件正确工作一、基础依赖二、错误用法(很多人一开

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Mysql中设计数据表的过程解析

《Mysql中设计数据表的过程解析》数据库约束通过NOTNULL、UNIQUE、DEFAULT、主键和外键等规则保障数据完整性,自动校验数据,减少人工错误,提升数据一致性和业务逻辑严谨性,本文介绍My... 目录1.引言2.NOT NULL——制定某列不可以存储NULL值2.UNIQUE——保证某一列的每一

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499