笔记: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;

参考文章

posted on   ahfuzhang  阅读(14)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示