H264分析源码学习之结构体篇——h264_stream_t结构体

最近学习H264的编解码,因此先学习了解H264的结构。我是通过h264分析开源库的源码进行学习的。首先先从数据结构体入手,通过了解重要的数据结构体来认识H264!

首先,我们需要初略的知道,H264数据流就是由一个一个独立的NALU单元构成:

...NALUNALUNALU...

再深入一点,每一个NALU由NALU header 和 NALU payload 两个部分组成(头信息主要说明此单元负载的数据类型,占一个字节)

...NALU headerNALU payloadNALU headerNALU payload...

再深入一点,NALU单元之间需要一个标志来区分开。因此,在一个NALU单元开始前都会有一个开始码(0x00 00 01)

...Start CodeNALU HeaderNALU payloadStart CodeNALU HeaderNALU payload...

其实,H264流就这么简单!


h264_stream_t 结构体包含所有NAL类型的数据结构,我们每当读取一个NAL单元时,就将该NALU的数据写入这个结构体中。


/**
   H264 stream
   Contains data structures for all NAL types that can be handled by this library.  
   When reading, data is read into those, and when writing it is written from those.  
   The reason why they are all contained in one place is that some of them depend on others, we need to 
   have all of them available to read or write correctly.
*/
/*
 h264流的结构体:
 		包含所有NAL类型的数据结构,可以被这个库处理
 		当读取时,将数据读入这些数据结构体中,当写入时,从这数据结构体中写入
 
 这个结构体在h264_new()函数中申请内存空间,在h264_free()函数中释放
*/
typedef struct
{
    nal_t* nal;				//NALU单元数据结构(句法元素包括:NALU header的信息,指向NALU payload的指针)
    sps_t* sps;				//sequence parameter sets序列参数集
    pps_t* pps;				//picture parameter sets图片参数集	
    aud_t* aud;
    sei_t* sei; 			//This is a TEMP pointer at whats in h->seis...    
    int num_seis;
    slice_header_t* sh;		
    slice_data_rbsp_t* slice_data;

    sps_t* sps_table[32];
    pps_t* pps_table[256];
    sei_t** seis;
    videoinfo_t* info;

} h264_stream_t;


/**
 Create a new H264 stream object.  Allocates all structures contained within it.
 @return    the stream object
 */
h264_stream_t* h264_new()
{
    h264_stream_t* h = (h264_stream_t*)calloc(1, sizeof(h264_stream_t));

    h->nal = (nal_t*)calloc(1, sizeof(nal_t));

    // initialize tables
    for ( int i = 0; i < 32; i++ ) { h->sps_table[i] = (sps_t*)calloc(1, sizeof(sps_t)); }
    for ( int i = 0; i < 256; i++ ) { h->pps_table[i] = (pps_t*)calloc(1, sizeof(pps_t)); }

    h->sps = h->sps_table[0];
    h->pps = h->pps_table[0];
    h->aud = (aud_t*)calloc(1, sizeof(aud_t));
    h->num_seis = 0;
    h->seis = NULL;
    h->sei = NULL;  //This is a TEMP pointer at whats in h->seis...
    h->sh = (slice_header_t*)calloc(1, sizeof(slice_header_t));
    h->info = (videoinfo_t*)calloc(1, sizeof(videoinfo_t));
    h->info->type = 0;
    return h;   
}



下一篇将介绍h264_stream_t结构体中nal_t结构体!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C++ 中将 H.264 裸流转换成 DHAV 帧结构体,可以使用以下代码作为参考: ```c++ #include <iostream> #include <fstream> #include <cstring> using namespace std; // DHAV帧头结构体 typedef struct _DHAV_HEADER { unsigned char cTag[4]; // 帧头标签,固定为"DHAV" unsigned int nLength; // 帧长度,包括帧头和数据部分 unsigned char cType; // 帧类型,0表示视频帧,1表示音频帧 unsigned char cReserve1; // 保留字段1 unsigned char cReserve2; // 保留字段2 unsigned char cReserve3; // 保留字段3 unsigned int nFrameNum; // 帧序号 unsigned int nTimeStamp; // 时间戳 unsigned int nFrameRate; // 帧率 unsigned int nWidth; // 视频宽度 unsigned int nHeight; // 视频高度 unsigned char cReserve4[16]; // 保留字段4 } DHAV_HEADER; // 读取H.264裸流文件 int readH264File(const char* filePath, unsigned char* buffer, int bufferSize) { ifstream fileStream(filePath, ios::in | ios::binary); if (!fileStream.is_open()) { cout << "Failed to open file: " << filePath << endl; return -1; } fileStream.read((char*)buffer, bufferSize); int readSize = fileStream.gcount(); fileStream.close(); return readSize; } // 将H.264裸流转换成DHAV帧结构体 int h264ToDHAV(unsigned char* h264Buffer, int h264Size, DHAV_HEADER* dhavHeader, unsigned char* dhavBuffer, int dhavBufferSize) { // 填写DHAV帧头部分 memset(dhavHeader, 0, sizeof(DHAV_HEADER)); memcpy(dhavHeader->cTag, "DHAV", 4); dhavHeader->nLength = sizeof(DHAV_HEADER) + h264Size; dhavHeader->cType = 0; // 视频帧 dhavHeader->nFrameNum = 1; // 帧序号,可以根据需要进行修改 dhavHeader->nTimeStamp = time(NULL); // 时间戳,可以根据需要进行修改 dhavHeader->nFrameRate = 25; // 帧率,可以根据需要进行修改 dhavHeader->nWidth = 1920; // 视频宽度,可以根据需要进行修改 dhavHeader->nHeight = 1080; // 视频高度,可以根据需要进行修改 // 填写DHAV帧数据部分 memcpy(dhavBuffer, dhavHeader, sizeof(DHAV_HEADER)); memcpy(dhavBuffer + sizeof(DHAV_HEADER), h264Buffer, h264Size); return dhavHeader->nLength; } int main(int argc, char* argv[]) { const char* h264FilePath = "test.h264"; const char* dhavFilePath = "test.dhav"; const int h264BufferSize = 1024 * 1024; const int dhavBufferSize = 1024 * 1024; unsigned char h264Buffer[h264BufferSize]; DHAV_HEADER dhavHeader; unsigned char dhavBuffer[dhavBufferSize]; // 读取H.264裸流文件 int h264Size = readH264File(h264FilePath, h264Buffer, h264BufferSize); if (h264Size < 0) { return -1; } // 将H.264裸流转换成DHAV帧结构体 int dhavSize = h264ToDHAV(h264Buffer, h264Size, &dhavHeader, dhavBuffer, dhavBufferSize); if (dhavSize < 0) { return -1; } // 将DHAV帧数据写入文件 ofstream fileStream(dhavFilePath, ios::out | ios::binary); if (!fileStream.is_open()) { cout << "Failed to open file: " << dhavFilePath << endl; return -1; } fileStream.write((char*)dhavBuffer, dhavSize); fileStream.close(); return 0; } ``` 需要注意的是,以上代码仅供参考,实际应用中需要根据协议文档进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值