ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

HEIF/HEIC 文件结构解析:ISO/IEC 23008-12:2017 标准与 box 实战

HEIF/HEIC 文件结构解析:ISO/IEC 23008-12:2017 标准与 box 实战 简介ISO/IEC 23008-12:2017 是国际标准化组织与国际电工委员会联合发布的图像文件格式标准聚焦高效编码与异构环境下的媒体交付是理解 HEIF、HEIC 格式的权威依据。资源面向从事图像编解码、移动端多媒体开发、流媒体与智能终端适配的工程师及研究人员帮助厘清 HEVC 编码下图像容器的结构规范与互操作要求。压缩包内共 1 个 PDF 文件约 906KB即标准正文涵盖范围、规范性引用、术语定义、总体要求等章节并涉及图像序列、元数据存储、兼容性转换与性能测试等核心内容。目前已有 259 人学习浏览。通过该标准可系统掌握 HEIF/HEIC 的文件组织方式、解码器与编码器规范以及与其他图像格式的转换规则为实际开发中的格式解析、兼容性排查与方案设计提供一手参考。1. 从一张 iPhone 照片说起ISO/IEC 23008-12:2017 到底规定了什么你从 iPhone 导出一张.heic照片扔进某些老版本 Windows 或 Android 工具里要么打不开要么只剩一张缩略图要么色彩发灰。问题往往不在“解码器不行”而在于没吃透 ISO/IEC 23008-12:2017 这份标准对 HEIF 文件结构的约束。它是 MPEG 体系下 High Efficiency Coding and Media Delivery 的第 12 部分2017 年 12 月首版专门定义 Image File Format也就是大家口中的 HEIF.heic是它最常见的编码载体。标准从 ISO Base Media File Format 派生规定了 image item、image sequence、derived image、image properties、metadata 等 box 的组织方式。适合做相册、相机管线、跨端图片 SDK、格式转换工具的工程师如果你只是偶尔转个图了解第 2 章就够想做解析器或写入器后面几章的 box 语义必须啃。2. HEIF 的 box 骨架从 ISO BMFF 派生出的图像容器2.1 为什么 HEIF 不是“另一种 JPEG”JPEG 把整张图当成一段连续熵编码数据元数据靠 APPn 段塞进去结构松散。HEIF 走的是 ISO BMFF 路线文件是一棵 box 树图像数据被切成多个 item每个 item 有类型、有属性、有位置。ISO/IEC 23008-12:2017 第 6 章明确单张图像和图像集合都从 ISO base media file format 派生metabox 下挂hdlr、pitm、iloc、iinf、iprp、iref等。这样做的好处是一张 HEIC 里可以同时放主图、缩略图、辅助图、深度图、透明通道还能声明它们之间的引用关系。代价是解析器必须按 box 逐层读不能像 JPEG 那样扫到 SOI 就开干。常见做法是先用ffprobe或MP4Box看 box 结构再决定自己写到哪一层。下面这段命令能快速列出顶层 box# 列出 HEIC 文件顶层 box 类型与大小 xxd -l 256 photo.heic # 或用 MP4Box 查看完整 box 树 MP4Box -info photo.heic 21 | head -60xxd看的是前 256 字节能确认ftyp品牌是不是heic、mif1、msf1。MP4Box -info会打印meta、iprp、iloc等层级。参数上-info只读不写适合排查如果要看某个 item 的偏移得配合-dump-item。2.2 核心 box 的职责划分标准第 9 章对 ISO BMFF 做了扩展重点在ItemInfoEntry和Item Properties Box。iinf描述每个 item 的 ID 和类型iloc给出数据偏移和长度iprp里的ipco是属性容器ipma把属性关联到具体 item。iref负责 item 之间的引用比如缩略图指向主图、辅助图指向主图。pitm指定主 item读图工具通常先找它。box作用常见坑ftyp声明品牌与兼容性品牌写错导致播放器拒识meta图像元数据总容器版本号与 flags 影响子 box 解析iinfitem 信息表item 类型hvc1/grid/iden混用iloc数据位置构造方式 0/1/2 偏移基数不同iprp属性容器ipma关联错位导致色彩异常irefitem 引用缩略图未正确指向主图这张表不是让你背而是排错时按行查。比如色彩发灰先看iprp里有没有colr再看ipma有没有把它关联到主 item。2.3 用 Python 读ftyp和meta的最小实现不依赖第三方库也能起步。下面这段代码只做一件事按 box 长度和类型遍历打印层级。import struct def read_boxes(data, offset0, endNone, depth0): 递归读取 ISO BMFF box打印类型与大小 if end is None: end len(data) while offset end: if offset 8 end: break size, struct.unpack(I, data[offset:offset4]) btype data[offset4:offset8].decode(latin1) header 8 if size 1: # 64 位长度 size, struct.unpack(Q, data[offset8:offset16]) header 16 elif size 0: # 延伸到文件末尾 size end - offset print( * depth f{btype} size{size}) # 只递归容器 box避免把图像数据当 box 读 if btype in (meta, iprp, ipco, iinf, iref): child_start offset header if btype meta: child_start 4 # meta 有 version/flags read_boxes(data, child_start, offset size, depth 1) offset size with open(photo.heic, rb) as f: read_boxes(f.read())逻辑说明struct.unpack(I)读 32 位大端长度size1时读 64 位size0表示到文件尾。metabox 在 ISO BMFF 里是 FullBox前 4 字节是 version 和 flags所以递归子 box 时要跳过。参数上depth只控制缩进不影响解析。这段代码不处理uuidbox 和widebox生产环境要补。提示读iloc时注意 construction method。方法 0 的偏移是相对文件起点方法 1 是相对idatbox方法 2 是相对metabox。搞错基数会读到完全无关的数据。3. 图像属性与派生图像色彩、旋转、缩略图怎么落 box3.1ipco里的属性不是装饰品标准 6.5 节列了一长串 image propertiesdecoder configuration、spatial extents、pixel aspect ratio、colour information、pixel information、relative location、clean aperture、rotation、mirroring、layer selection。它们都放在ipco里由ipma按 item ID 关联。ispe给宽高pixi给通道位深colr给色彩原色和传递特性irot给旋转角度imir给镜像。很多工具读 HEIC 时方向不对就是没处理irot和imir。irot的角度是逆时针 0/90/180/270存在 1 字节里实际值要乘 90。imir的 axis 为 0 表示上下翻转1 表示左右翻转。这两个属性经常和 EXIF Orientation 同时存在谁优先标准里irot/imir是容器级变换EXIF 是元数据级解析器一般先应用容器变换再读 EXIF。如果两处冲突以容器为准更安全。3.2 派生图像grid与iden6.6 节定义了 derived image。最常见的是grid把多张图拼成一张用于 HEVC 的 tile 编码。iden是 identity表示派生图就是原图。griditem 的数据区不是像素而是一段描述行数、列数、每块宽高。解析时要先读grid描述再按dimg引用找到各 tile最后拼合。下面这段代码演示如何从iref里找dimg引用def parse_iref(data, offset, size): 解析 iref box返回 {from_id: [(type, to_id), ...]} refs {} pos offset 8 4 # 跳过 box header 和 FullBox version/flags end offset size while pos end: ref_size, struct.unpack(I, data[pos:pos4]) ref_type data[pos4:pos8].decode(latin1) child pos 8 child_end pos ref_size while child child_end: from_id, struct.unpack(H, data[child:child2]) to_id, struct.unpack(H, data[child2:child4]) refs.setdefault(from_id, []).append((ref_type, to_id)) child 4 pos ref_size return refs逻辑说明iref是 FullBox跳过 4 字节 version/flags 后每个子 box 是SingleItemTypeReferenceBox里面是一组from_item_ID和to_item_ID。ref_type常见有dimg派生来源、thmb缩略图、auxl辅助图。参数上item ID 是 16 位超过 65535 的 item 需要iref的 32 位变体标准里有定义但少见。3.3 缩略图与辅助图的引用关系缩略图用thmb引用主图辅助图用auxl。辅助图类型由auxC属性里的 URN 决定比如深度图、透明通道、alpha。标准 6.4 节还定义了 hidden image、cover image、master image、pre-derived coded image、multi-layer image。hidden image 不在普通浏览中显示但可被引用。cover image 用于相册封面。这些角色不是靠文件名区分而是靠iref和属性组合。实操中如果你要生成 HEIC常见做法是主图一个 item缩略图一个 itemthmb指向主图ispe给缩略图尺寸colr继承主图。辅助图要加auxCURN 写对否则播放器不知道这是深度还是 alpha。注意auxC的 URN 字符串必须符合标准注册值自己编一个会导致兼容性问题。常见值包括urn:mpeg:hevc:2015:auxid:1和urn:mpeg:hevc:2015:auxid:2。4. 图像序列与元数据从单张到轨道4.1 image sequence 不是视频轨的简单复用标准第 7 章讲 image sequences。它从 ISO BMFF 的 track 派生但 handler type 不同hdlr里要写pict。Track Header box 的字段有约束Coding Constraints box 也有专门要求。图像序列可以带缩略图序列轨和辅助图序列轨分别用thmb和auxl引用。和普通视频轨的区别在于图像序列的样本是静态图像编码时间轴用于连拍或动画不是连续运动补偿。如果你用ffmpeg把一组 HEIC 转成序列注意它可能默认按视频处理丢掉picthandler。更稳的做法是用MP4Box的-add配合-new指定序列类型或者直接按标准写 box。4.2 元数据与完整性校验第 8 章规定 metadata support包括 image item 和 image sequence track 的元数据以及 integrity checks。完整性校验的语法和语义在 8.4 节用于验证 item 数据没被篡改。常见实现是存一个哈希或校验和读取时比对。实际产品里用得不多但做归档或版权保护时会用到。元数据可以放在meta下的ilst也可以放在 item 属性里。EXIF 和 XMP 通常作为独立 item用cdsc引用主图。这样设计的好处是元数据可以单独更新不用重写图像数据。4.3 用MP4Box做一次完整拆包# 查看 HEIC 所有 item MP4Box -info photo.heic # 导出主图 item 到 raw 文件 MP4Box -dump-item 1:pathitem1.hevc photo.heic # 导出所有 item MP4Box -dump-item all:pathitems photo.heic-dump-item的1是 item ID来自iinf。导出后得到的是 HEVC 码流不是直接可看的图片还要送解码器。参数path指定输出目录或文件名。如果 item 是grid导出的是描述数据不是像素。提示不同版本的MP4Box对 HEIF 支持程度不同遇到解析失败先升级 GPAC再确认文件ftyp品牌是否在支持列表里。5. 避坑与排查HEIC 解析中最容易翻车的五件事5.1 现象图片能打开但颜色发灰原因colr属性缺失或ipma没关联到主 item解码器按默认 sRGB 处理实际是 Display P3 或 BT.2020。 解决读iprp/ipco找colr确认colour_type是nclx还是prof再查ipma的 association。如果colr存在但没关联手动补关联或换解析库。5.2 现象缩略图显示成主图原因pitm指向了缩略图 item或者thmb引用方向写反。 解决pitm的 item ID 必须是主图。thmb是缩略图指向主图不是主图指向缩略图。用MP4Box -info确认pitm值。5.3 现象iloc读到的数据是乱码原因construction method 搞错或者base_offset没加。 解决先看iloc的 version 和 flags方法 0 用文件绝对偏移方法 1 用idat偏移方法 2 用meta偏移。把base_offset和extent_offset相加再读。5.4 现象多 tile 图拼出来错位原因grid的行列数和 tile 顺序没按标准读或者 tile 尺寸不一致。 解决grid数据区前 4 字节是 version/flags接着 1 字节 rows-1、1 字节 columns-1、4 字节 output width、4 字节 output height。tile 按行优先排列尺寸由各自ispe给出。拼合时按dimg引用顺序放。5.5 现象Windows 资源管理器不显示缩略图原因系统 HEIF 扩展没装或文件ftyp品牌不被识别。 解决确认ftyp包含heic或mif1。Windows 需要 HEIF Image Extensions 和 HEVC Video Extensions。这不是文件问题是环境问题别改文件结构去迁就。6. 进阶自己写一个 HEIC 解析器要盯住的三个参数如果你不满足于调库想自己写解析器有三个参数决定成败。第一是iloc的 construction method它决定偏移基数写错全盘皆输。第二是ipma的 association 数量一个 item 可以关联多个属性顺序不重要但必须全部处理。第三是iref的引用类型dimg、thmb、auxl、cdsc语义不同混用会导致派生图解析失败。验证方法很简单拿一张已知正确的 HEIC用你的解析器读出主图宽高、色彩原色、旋转角度和exiftool或MP4Box的输出比对。三个值全对基本结构就通了。再拿一张带缩略图和深度图的 HEIC检查iref是否完整。最后拿一张grid编码的 HEIC拼合后和原图做像素级比对。我自己的习惯是每次改解析器先跑这三类样本再跑一遍iloc边界测试——偏移为 0、长度为 0、item ID 不连续的情况。血泪经验是很多 bug 不在主流程而在这些边界。从那以后我每次写 box 解析都强制走一遍边界样本希望帮到你。本文还有配套的精品资源点击获取
返回列表