笔记:H265文件格式分析
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
H265 文件格式分析
总结
-
每段以 00 00 00 01 来开头
- 为什么不用长度来定位?这一点很奇怪
-
之后是两字节的类型信息:类型是其中 6 个 bit
-
不同的段有不同的格式,猜测可能是对应着某个 struct 的结构
例子文件
先使用 ffmpeg 命令行,对一个 hevc(h265) 编码的视频文件取第一帧,并保存为 h265 的裸格式:
# 提取视频的第一帧为原始 h265 格式 ffmpeg -i input.hevc -c:v copy -frames:v 1 first_frame.h265
下面用十六进制编辑器打开 first_frame.h265 文件,分析文件的内容:
0 00 00 01 4E 01 05 23 47 56 4A DC 5C 4C 43 3F 94 EF C5 11 3C D1 43 A8 00 00 03 00 00 03 00 06 66 34 11 03 EE 11 11 EE 02 01 57 5D 34 80 00 00 00 01 40 01 0C 02 FF FF 01 60 00 00 03 00 B0 00 00 03 00 00 03 00 96 00 00 15 C0 90 00 00 00 01 42 01 02 01 60 00 00 03 00 B0 00 00 03 00 00 03 00 96 00 00 A0 01 E0 20 02 1C 58 81 5E E4 59 54 D4 04 04 04 02 00 00 00 01 44 01 C0 2C BC 14 C9 00 00 00 01 44 01 50 0B 2F 05 3C 21 F3 16 43 0C 1A 0A A0 52 84 3E 62 C8 61 83 41 54 0A 50 87 CC 59 0C 30 68 2A 81 4A 10 F9 38 AC 21 07 50 87 C9 C5 61 08 3A 84 3E 4E 2B 08 41 D4 21 FF 4D 34 9A B4 62 A4 D9 0C 59 25 91 48 63 96 20 82 22 4A 38 70 A1 63 C3 C1 68 5C 18 04 82 60 42 81 4A 10 FF A6 9A 4D 5A 31 52 6C 86 2C 92 C8 A4 31 CB 10 41 11 25 1C 38 50 B1 E1 E0 B4 2E 0C 02 41 30 21 40 A5 08 7F D3 4D 26 AD 18 A9 36 43 16 49 64 52 18 E5 88 20 88 92 8E 1C 28 58 F0 F0 5A 17 06 01 20 98 10 A0 52 84 3F EB D7 C9 F8 8F EB F3 7C 57 84 B8 24 C1 84 1E 42 1F F5 EB E4 FC 47 F5 F9 BE 2B C2 5C 12 60 C2 0F 21 0F FA F5 F2 7E 23 FA FC DF 15 E1 2E 09 30 61 07 90 87 FE 9A 69 35 68 C5 49 B2 18 B2 4B 22 90 C7 2C 41 04 44 94 70 E1 42 C7 87 82 D0 B8 30 09 04 C0 85 02 94 21 FF A6 9A 4D 5A 31 52 6C 86 2C 92 C8 A4 31 CB 10 41 11 25 1C 38 50 B1 E1 E0 B4 2E 0C 02 41 30 21 40 A5 08 7F E9 A6 93 56 8C 54 9B 21 8B 24 B2 29 0C 72 C4 10 44 49 47 0E 14 2C 78 78 2D 0B 83 00 90 4C 08 50 29 42 1F FA F5 F2 7E 23 FA FC DF 15 E1 2E 09 30 61 07 90 87 FE BD 7C 9F 88 FE BF 37 C5 78 4B 82 4C 18 41 E4 21 FF AF 5F 27 E2 3F AF CD F1 5E 12 E0 93 06 10 79 08 7F E9 A6 93 56 8C 54 9B 21 8B 24 B2 29 0C 72 C4 10 44 49 47 0E 14 2C 78 78 2D 0B 83 00 90 4C 08 50 29 42 1F FA F5 F2 7E 23 FA FC DF 15 E1 2E 09 30 61 07 89 00 00 00 01 28 01 93 D0 11 07 3A 72 EA 63 A9 8F 18 BD 96 FE B4 11
H265 文件的格式结构大概如下:
开始 | 结束 | 长度 | 内容(HEX) | 说明 |
---|---|---|---|---|
0 | 3 | 4 | 00 00 00 01 | h265 的nal 的分隔符 |
第一段 | 总长 46 | |||
4 | 5 | 2 | 4E 01 | 0100 1110 0000 0001 * Forbidden Bit (1 bit): 0 * NAL Type (6 bits): 100111(39), SEI 补充增强信息 * Layer ID (6 bits): 0 * Temporal ID (3 bits): 1 |
6 | 6 | 1 | 05 | SEI payloadType: User data unregistered |
7 | 7 | 1 | 23 | payloadSize: 35字节 |
8 | 23 | 16 | UUID | |
24 | 27 | 4 | 00 00 03 00 | RBSP 逃码 |
28 | 44 | 17 | ??? | |
45 | 45 | 1 | 80 | 结束标志 |
第二段 | 总长 30 | |||
46 | 49 | 4 | 00 00 00 01 | |
50 | 51 | 2 | 40 01 | 0100 0000 0000 0001 * Forbidden Bit (1 bit): 0 * NAL Type (6 bits): 100000(32), VPS 视频参数集 * Layer ID (6 bits): 0 * Temporal ID (3 bits): 1 |
0C | 最大层数 (12) | |||
02 | 最大子层数 (2) | |||
FF FF | 配置参数 | |||
01 60 | 解码能力 | |||
90 | 结束标记 | |||
24 | ??? | |||
第三段 | 41字节 | |||
76 | 79 | 4 | 00 00 00 01 | |
80 | 81 | 2 | 42 01 | * NAL Type (6 bits): 33, 序列集参数, SPS |
82 | 116 | |||
??? | ||||
第四段 | 11字节 | |||
117 | 120 | 4 | 00 00 00 01 | |
121 | 122 | 2 | 44 01 | * NAL Type (6 bits): 34, 图像参数, PPS |
123 | 127 | 5 | ||
??? | ||||
第五段 | 462 字节 | |||
128 | 131 | 4 | 00 00 00 01 | |
132 | 133 | 2 | 44 01 | * NAL Type (6 bits): 34, 图像参数, PPS |
第 6 段 | ||||
554 | 557 | 4 | 00 00 00 01 | |
558 | 559 | 2 | 28 01 | * NAL Type (6 bits): 20, HEVC_NAL_IDR_N_LP |
560 | 530564 | 530004 | 到文件结束 |
杂乱的笔记
下载官方文档
hevc 的官方文档的下载链接: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.265-201802-S!!PDF-E&type=items
通过 ffmpeg c 的源码来反推格式
以下是一些杂乱的笔记,对分析 h265 文件的格式有帮助:
- 解析格式的源码
libavcodec/h2645_parse.h
typedef struct H2645NAL { const uint8_t *data; int size; /** * Size, in bits, of just the data, excluding the stop bit and any trailing * padding. I.e. what HEVC calls SODB. */ int size_bits; int raw_size; const uint8_t *raw_data; GetBitContext gb; /** * NAL unit type */ int type; /** * H.264 only, nal_ref_idc */ int ref_idc; /** * HEVC only, nuh_temporal_id_plus_1 - 1 */ int temporal_id; /* * HEVC only, identifier of layer to which nal unit belongs */ int nuh_layer_id; int skipped_bytes; int skipped_bytes_pos_size; int *skipped_bytes_pos; } H2645NAL;
- libavcodec/hevc/hevc.h
NAL每一段的含义:
/** * Table 7-1 – NAL unit type codes and NAL unit type classes in * T-REC-H.265-201802 */ enum HEVCNALUnitType { HEVC_NAL_TRAIL_N = 0, HEVC_NAL_TRAIL_R = 1, HEVC_NAL_TSA_N = 2, HEVC_NAL_TSA_R = 3, HEVC_NAL_STSA_N = 4, HEVC_NAL_STSA_R = 5, HEVC_NAL_RADL_N = 6, HEVC_NAL_RADL_R = 7, HEVC_NAL_RASL_N = 8, HEVC_NAL_RASL_R = 9, HEVC_NAL_VCL_N10 = 10, HEVC_NAL_VCL_R11 = 11, HEVC_NAL_VCL_N12 = 12, HEVC_NAL_VCL_R13 = 13, HEVC_NAL_VCL_N14 = 14, HEVC_NAL_VCL_R15 = 15, HEVC_NAL_BLA_W_LP = 16, HEVC_NAL_BLA_W_RADL = 17, HEVC_NAL_BLA_N_LP = 18, HEVC_NAL_IDR_W_RADL = 19, HEVC_NAL_IDR_N_LP = 20, HEVC_NAL_CRA_NUT = 21, HEVC_NAL_RSV_IRAP_VCL22 = 22, HEVC_NAL_RSV_IRAP_VCL23 = 23, HEVC_NAL_RSV_VCL24 = 24, HEVC_NAL_RSV_VCL25 = 25, HEVC_NAL_RSV_VCL26 = 26, HEVC_NAL_RSV_VCL27 = 27, HEVC_NAL_RSV_VCL28 = 28, HEVC_NAL_RSV_VCL29 = 29, HEVC_NAL_RSV_VCL30 = 30, HEVC_NAL_RSV_VCL31 = 31, HEVC_NAL_VPS = 32, HEVC_NAL_SPS = 33, HEVC_NAL_PPS = 34, HEVC_NAL_AUD = 35, HEVC_NAL_EOS_NUT = 36, HEVC_NAL_EOB_NUT = 37, HEVC_NAL_FD_NUT = 38, HEVC_NAL_SEI_PREFIX = 39, HEVC_NAL_SEI_SUFFIX = 40, HEVC_NAL_RSV_NVCL41 = 41, HEVC_NAL_RSV_NVCL42 = 42, HEVC_NAL_RSV_NVCL43 = 43, HEVC_NAL_RSV_NVCL44 = 44, HEVC_NAL_RSV_NVCL45 = 45, HEVC_NAL_RSV_NVCL46 = 46, HEVC_NAL_RSV_NVCL47 = 47, HEVC_NAL_UNSPEC48 = 48, HEVC_NAL_UNSPEC49 = 49, HEVC_NAL_UNSPEC50 = 50, HEVC_NAL_UNSPEC51 = 51, HEVC_NAL_UNSPEC52 = 52, HEVC_NAL_UNSPEC53 = 53, HEVC_NAL_UNSPEC54 = 54, HEVC_NAL_UNSPEC55 = 55, HEVC_NAL_UNSPEC56 = 56, HEVC_NAL_UNSPEC57 = 57, HEVC_NAL_UNSPEC58 = 58, HEVC_NAL_UNSPEC59 = 59, HEVC_NAL_UNSPEC60 = 60, HEVC_NAL_UNSPEC61 = 61, HEVC_NAL_UNSPEC62 = 62, HEVC_NAL_UNSPEC63 = 63, };
- 解析 NAL 时函数调用链:
int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit); int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, H265RawSEI *current, int prefix); // 解析 type int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, H265RawNALUnitHeader *current, int expected_nal_unit_type); // 解析消息 int FUNC(message_list)(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessageList *current, int prefix); // SEI 的格式 typedef struct SEIRawMessage { uint32_t payload_type; uint32_t payload_size; void *payload; void *payload_ref; ///< RefStruct reference uint8_t *extension_data; ///< RefStruct reference size_t extension_bit_length; } SEIRawMessage;
- 读取 vps 段
int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, H265RawVPS *current); // vps 的结构 typedef struct H265RawVPS { H265RawNALUnitHeader nal_unit_header; uint8_t vps_video_parameter_set_id; uint8_t vps_base_layer_internal_flag; uint8_t vps_base_layer_available_flag; uint8_t vps_max_layers_minus1; uint8_t vps_max_sub_layers_minus1; uint8_t vps_temporal_id_nesting_flag; H265RawProfileTierLevel profile_tier_level; uint8_t vps_sub_layer_ordering_info_present_flag; uint8_t vps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; uint8_t vps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; uint32_t vps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; uint8_t vps_max_layer_id; uint16_t vps_num_layer_sets_minus1; uint8_t layer_id_included_flag[HEVC_MAX_LAYER_SETS][HEVC_MAX_LAYERS]; uint8_t vps_timing_info_present_flag; uint32_t vps_num_units_in_tick; uint32_t vps_time_scale; uint8_t vps_poc_proportional_to_timing_flag; uint32_t vps_num_ticks_poc_diff_one_minus1; uint16_t vps_num_hrd_parameters; uint16_t hrd_layer_set_idx[HEVC_MAX_LAYER_SETS]; uint8_t cprms_present_flag[HEVC_MAX_LAYER_SETS]; H265RawHRDParameters hrd_parameters[HEVC_MAX_LAYER_SETS]; uint8_t vps_extension_flag; H265RawExtensionData extension_data; } H265RawVPS;
参考文章
-
HEVC码流解析: https://blog.csdn.net/CrystalShaw/article/details/80624804
-
H265 之格式解析:H265之格式解析_51CTO博客_h265是什么格式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律