容器格式之MKV介绍 MKV 全称 Matroska Multimedia Container马楚卡多媒体容器后缀.mkv是开源免费、无专利收费的多媒体封装格式不是视频压缩编码。 简单理解它是一个万能视频文件收纳箱本身不改变画质音质只负责把视频、多音轨、多字幕、章节、封面打包进单个文件对比 MP4、AVI它兼容性更广、轨道功能更强。 衍生后缀.mkv标准视频视频 音频 字幕.mka纯音频封装.mk3d3D 立体视频专用一、MKV结构所有 MKV 文件 EBML 文件遵循两级规范底层EBML 二进制语法通用上层Matroska 语义规范定义视频 / 音频 / 字幕轨道、时间戳、章节等业务标签MKV 文件 ├── EBML Header - EBML 规范信息 │ ├── EBMLVersion │ ├── DocType (matroska/webm) │ └── DocTypeVersion │ └── Segment - 主要数据段 ├── SeekHead - 索引信息可选 ├── SegmentInfo - 段元数据 │ ├── TimecodeScale │ ├── Duration │ └── MuxingApp │ ├── Tracks - 轨道信息 │ └── TrackEntry × N │ ├── TrackNumber │ ├── TrackType (video/audio/subtitle) │ ├── CodecID │ ├── CodecPrivate (编解码器初始化数据) │ └── Video/Audio/Subtitle 特定信息 │ ├── Chapters - 章节信息可选 ├── Tags - 元数据标签可选 ├── Cues - 时间戳索引可选 └── Clusters - 媒体数据 └── Cluster × N ├── Timecode - 集群时间戳 └── BlockGroup - 数据块 ├── Block - 压缩数据 └── BlockDuration二、EBML介绍2.1 通用EBML结构每个 EBML Element 的二进制布局 ┌─────────────────┬─────────────────────────────┬────────────┐ │ Element ID │ Element Data Size │ Data │ │ (VINT, 1-4字节) │ (VINT, 1-8字节) │ (变长) │ └─────────────────┴─────────────────────────────┴────────────┘ VINT (Variable-Length Integer) 编码示例 值: 0 → 二进制: 10000000 → 0x80 值: 1 → 二进制: 01000001 → 0x41 值: 127 → 二进制: 01111111 → 0x7F 值: 128 → 二进制: 01000000 10000000 → 0x40 0x80 解析规则 • 第一个字节的最高位表示这是几字节的整数 • 第一个字节剩余位为最高位 • 后续字节贡献低位每个字节贡献7位2.2 EBML HeaderEBML Header (Element ID: 0x1A45DFA3) ┌─────────────────────────────────────────────────────────────────┐ │ Element ID: 0x1A45DFA3 (4 bytes, 固定值) │ │ Element Size: VINT (1-8 bytes, 可变长度) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Element Data │ │ │ │ (变长包含以下元素) │ │ │ │ │ │ │ │ EBMLVersion (0x4286) UINT EBML 版本号(必填) │ │ │ │ EBMLReadVersion (0x42F7) UINT 读取器版本(必填) │ │ │ │ EBMLMaxIDLength (0x42F2) UINT 最大 ID 字节数 │ │ │ │ EBMLMaxSizeLength (0x42F3) UINT 最大 Size 字节数 │ │ │ │ DocType (0x4282) STRING 文档类型(必填) │ │ │ │ DocTypeVersion (0x4287) UINT DocType 版本号 │ │ │ │ DocTypeReadVersion (0x4285) UINT DocType 读取版本 │ │ │ │ (其他可选元素...) │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘2.2.1 字段详细说明Element NameElement IDType必须说明EBMLVersion0x4286UINT✔️EBML 规范版本通常为 1EBMLReadVersion0x42F7UINT✔️读取该文件所需的最低 EBML 版本EBMLMaxIDLength0x42F2UINT✔️Element ID 的最大字节数默认 4EBMLMaxSizeLength0x42F3UINT✔️Element Size 的最大字节数默认 8DocType0x4282STRING✔️文档类型matroska / webmDocTypeVersion0x4287UINT✔️DocType 版本DocTypeReadVersion0x4285UINT✔️读取该文件所需的最低 DocType 版本EBMLProfile0x4284UINT❌EBML 配置文件CRC-320xBFBINARY❌校验和很少使用2.2.2 VINT可变长度整数编码编码规则VINT { 标记位 数据位 } 第一个字节的最高位表示这是几字节的整数 • 0b10xxxxxx → 1字节整数 • 0b01xxxxxx → 2字节整数 • 0b001xxxxx → 3字节整数 • 0b0001xxxx → 4字节整数 • ... 以此类推最多 8 字节 剩余位最高位被标记位占用其余字节全部贡献7位为数据位VINT 编码示例十进制值二进制十六进制字节数0100000000x8011010000010x411127011111110x7F112801000000 100000000x40 0x8021638301111111 111111110x7F 0xFF21638400100000 01000000 000000000x20 0x40 0x0032.3 segment介绍Top-Level Elements顶级元素Segment 内部包含以下一级元素顺序可变但通常按以下顺序排列Segment (0x18538067) ┌──────────────────────────────────────────────────────────────────────┐ │ │ │ 1. SeekHead (0x114D9B74) [可选] │ │ └─ 存储其他顶级元素的偏移位置加速随机访问 │ │ │ │ 2. Info (0x1549A966) │ │ ├─ TimecodeScale (0x2AD7B1) - 时间刻度默认 1000000 ns │ │ ├─ Duration (0x4489) - 文件总时长 │ │ ├─ DateUTC (0x4461) - 创建日期UTC │ │ ├─ Title (0x7BA9) - 文件标题 │ │ ├─ MuxingApp (0x4D80) - 封装工具名称 │ │ ├─ WritingApp (0x5741) - 创作工具名称 │ │ ├─ SegmentUID (0x73A4) - Segment 唯一标识 │ │ └─ SegmentFilename (0x7384) - Segment 文件名 │ │ │ │ 3. Tracks (0x1654AE6B) [必须至少一个] │ │ └─ TrackEntry (0xAE) × N │ │ ├─ TrackNumber (0xD7) - 轨道编号 (1-based) │ │ ├─ TrackUID (0x73C5) - 轨道唯一 ID │ │ ├─ TrackType (0x83) - 类型(0x1视频, 0x2音频, 0x11字幕)│ │ ├─ FlagEnabled (0xB9) - 是否启用 │ │ ├─ FlagDefault (0x88) - 是否为默认轨道 │ │ ├─ FlagLacing (0x9C) - 是否使用拼接 │ │ ├─ Language (0x22B59C37) - 语言代码 (eng, zh 等) │ │ ├─ Name (0x536E) - 轨道名称 │ │ ├─ CodecID (0x86) - 编解码器ID (如 V_MPEG4/ISO/AVC) │ │ ├─ CodecPrivate (0x63A2) - 编解码器私有数据 │ │ ├─ CodecName (0x258688) - 编解码器名称 │ │ ├─ DefaultDuration (0x23E383) - 默认帧时长 │ │ ├─ TrackTimecodeScale (0x23314F) - 轨道时间刻度(默认 1.0) │ │ ├─ Video (0xE0) - 视频轨道特有信息 │ │ │ ├─ Interlaced (0x9A) - 是否隔行 │ │ │ ├─ Width (0xB0) - 视频宽度 │ │ │ ├─ Height (0xBA) - 视频高度 │ │ │ ├─ DisplayWidth (0x54B2) - 显示宽度 │ │ │ ├─ DisplayHeight (0x54BA) - 显示高度 │ │ │ ├─ PixelWidth (0x54B0) - 像素宽度 │ │ │ ├─ PixelHeight (0x54BA) - 像素高度 │ │ │ ├─ FrameRate (0x2383E3) - 帧率 │ │ │ └─ Colour (0x55B0) - 颜色元数据HDR 等 │ │ ├─ Audio (0xE1) - 音频轨道特有信息 │ │ │ ├─ SamplingFrequency (0xB5) - 采样率 │ │ │ ├─ OutputSamplingFrequency - 输出采样率 │ │ │ ├─ Channels (0x9F) - 声道数 │ │ │ ├─ ChannelPositions - 声道布局 │ │ │ └─ BitDepth (0x6264) - 位深 │ │ └─ ContentEncodings (0x6D80) - 编码信息压缩/加密 │ │ └─ ContentEncoding (0x6240) │ │ ├─ ContentCompression (0x5034) - 压缩信息 │ │ └─ ContentEncryption (0x5035) - 加密信息 │ │ │ │ 4. Cues (0x1C53BB6B) [可选推荐] │ │ └─ CuePoint (0xBB) × N │ │ ├─ CueTime (0xB3) - 时间戳 │ │ └─ CueTrackPositions (0xB7) - 轨道位置信息 │ │ ├─ CueTrack (0xF7) - 轨道编号 │ │ ├─ CueClusterPosition(0xF1) - Cluster 位置 │ │ ├─ CueClusterRelative(0xF0) - 相对位置 │ │ └─ CueBlockNumber (0x5378) - Block 编号 │ │ │ │ 5. Chapters (0x1043A770) [可选] │ │ └─ EditionEntry (0x45B9) × N │ │ └─ ChapterAtom (0xB6) × N │ │ ├─ ChapterUID (0x73C4) - 章节唯一 ID │ │ ├─ ChapterTimeStart (0x91) - 开始时间 │ │ ├─ ChapterTimeEnd (0x92) - 结束时间 │ │ └─ ChapterDisplay (0x80) - 章节显示信息 │ │ │ │ 6. Tags (0x1254C367) [可选] │ │ └─ Tag (0x7373) × N │ │ ├─ Targets (0x63C0) - 标签目标整文件/轨道/章节等 │ │ └─ SimpleTag (0x67C8) × N │ │ ├─ TagName (0x45A3) - 标签名TITLE, ARTIST 等 │ │ ├─ TagLanguage (0x447A) - 语言 │ │ └─ TagString (0x4487) - 标签值 │ │ │ │ 7. Attachments (0x1941A469) [可选] │ │ └─ AttachedFile (0x61A7) × N │ │ ├─ FileName (0x466E) - 文件名 │ │ ├─ FileMimeType (0x4660) - MIME 类型 │ │ └─ FileData (0x465C) - 文件数据 │ │ │ │ 8. Cluster (0x1F43B675) × N [必须至少一个] │ │ └─ (详见下方 Cluster 详细结构) │ │ │ └──────────────────────────────────────────────────────────────────────┘2.3.1 SeekHead快速索引作用存储其他顶级元素在文件中的偏移位置加速 seeking 操作。SeekHead (0x114D9B74) └─ Seek (0x4DBB) × N ├─ SeekID (0x53AB) - 目标元素的 ID ├─ SeekPosition (0x53AC) - 目标元素在 Segment 内的偏移 └─ (可选) SeekSize / SeekClusterPosition 等示例Seek 条目: SeekID 0x1549A966 (Info) SeekPosition 0x100 Seek 条目: SeekID 0x1654AE6B (Tracks) SeekPosition 0x200 Seek 条目: SeekID 0x1C53BB6B (Cues) SeekPosition 0x10002.3.2 Info段信息作用存储 Segment 级别的元数据。Info (0x1549A966) ├─ SegmentUID (0x73A4) - 128位唯一标识符 ├─ SegmentFilename (0x7384) - 文件名用于分块 ├─ PrevUID (0x3CB923) - 前一 Segment UID ├─ NextUID (0x3EB923) - 后一 Segment UID ├─ TimecodeScale (0x2AD7B1) - 时间刻度默认 1,000,000 ns ├─ Duration (0x4489) - 总时长单位: TimecodeScale ├─ DateUTC (0x4461) - 创建日期2001-01-01 以来的纳秒数 ├─ Title (0x7BA9) - 文件标题 ├─ MuxingApp (0x4D80) - 封装工具如 libmatroska 1.6.3 └─ WritingApp (0x5741) - 创作工具如 FFmpeg 5.12.3.3. Tracks轨道信息作用定义所有音视频字幕轨道。Tracks (0x1654AE6B) └─ TrackEntry (0xAE) × N ├─ TrackNumber (0xD7) - 轨道编号从 1 开始 ├─ TrackUID (0x73C5) - 轨道唯一 ID ├─ TrackType (0x83) - 轨道类型 │ • 0x01 视频 │ • 0x02 音频 │ • 0x03 复杂复合轨道 │ • 0x10 字幕 │ • 0x11 字幕 │ • 0x12 按钮 │ • 0x20 控制 │ • 0x21 元数据 ├─ FlagEnabled (0xB9) - 是否启用 ├─ FlagDefault (0x88) - 是否为默认轨道 ├─ FlagForced (0x55AA) - 是否强制轨道 ├─ FlagLacing (0x9C) - 是否支持 lacing ├─ MinCache (0x6DE7) - 最小缓存帧数 ├─ MaxCache (0x6DF8) - 最大缓存帧数 ├─ DefaultDuration (0x23E383) - 默认帧时长纳秒 ├─ TrackTimecodeScale (0x23314F) - 轨道时间刻度默认 1.0 ├─ Duration (0x4489) - 轨道总时长 ├─ Language (0x22B59C37) - 语言代码如 eng, zh, ja ├─ Name (0x536E) - 轨道名称如 Main Audio ├─ CodecID (0x86) - 编解码器ID如 V_MPEG4/ISO/AVC, A_AAC ├─ CodecPrivate (0x63A2) - 编解码器私有数据 ├─ CodecName (0x258688) - 编解码器名称 ├─ CodecSettings (0x3A9697) - 编解码器设置字符串 ├─ CodecInfoURL (0x3B4040) - 编解码器信息URL ├─ CodecDownloadURL (0x26B240) - 编解码器下载URL ├─ CodecDecodeAll (0xAA) - 是否可解所有帧 ├─ TrackOverlay (0x6FAB) - 轨道叠加用于多视角 ├─ Video (0xE0) - 视频特有字段如果是视频轨道 ├─ Audio (0xE1) - 音频特有字段如果是音频轨道 └─ ContentEncodings (0x6D80) - 内容编码压缩/加密2.3.4. Cues时间索引作用存储关键帧索引实现快速随机访问类似 MP4 的 stss stco。Cues (0x1C53BB6B) └─ CuePoint (0xBB) × N ├─ CueTime (0xB3) - 时间戳 └─ CueTrackPositions (0xB7) × N ├─ CueTrack (0xF7) - 轨道编号 ├─ CueClusterPosition (0xF1) - 在 Segment 内的偏移 ├─ CueClusterRelativePosition (0xF0) - 在 Cluster 内的偏移 ├─ CueBlockNumber (0x5378) - 在 Cluster 内的 Block 编号 └─ CueCodecState (0xEA) - 编解码器状态可选2.3.5 ChapterChapters是 MKV 文件中用于标记内容分段的元数据结构类似于 DVD/Blu-ray 的章节功能。它允许播放器显示章节列表支持一键跳转到特定章节。Chapters (0x1043A770) └─ EditionEntry (0x45B9) × N ← 章节集通常只有 1 个 ├─ EditionUID (0x45BC) - 版本唯一 ID ├─ EditionFlagHidden (0x504898) - 是否隐藏 ├─ EditionFlagDefault (0x504892) - 是否为默认版本 ├─ EditionFlagOrdered (0x504891) - 是否有序 ├─ EditionDisplay (0x4520) × N - 显示信息可选 │ ├─ ChapString (0x4586) - 版本名称 │ ├─ ChapLanguage (0x457C) - 语言 │ └─ ChapCountry (0x457D) - 国家 └─ ChapterAtom (0xB6) × N ← 具体章节 ├─ ChapterUID (0x73C4) - 章节唯一 ID ├─ ChapterStringUID (0x73C4) - 字符串唯一 ID可选 ├─ ChapterTimeStart (0x91) - 开始时间必填 ├─ ChapterTimeEnd (0x92) - 结束时间可选 ├─ ChapterFlagHidden (0x98) - 是否隐藏 ├─ ChapterFlagEnabled (0x4598) - 是否启用 ├─ ChapterDisplay (0x80) × N - 显示信息 │ ├─ ChapString (0x85) - 章节标题多语言 │ ├─ ChapLanguage (0x437C) - 语言代码如 eng, zh │ └─ ChapCountry (0x437D) - 国家代码可选 └─ ChapterProcess (0x6944) × N - 章节处理命令可选很少用 ├─ ChapProcessCodecID (0x6955) - 处理命令类型 ├─ ChapProcessData (0x6933) - 处理数据 └─ ChapProcessPrivate (0x450D) - 私有数据2.3.6 TagsTags是 MKV 文件中用于存储元数据的核心元素类似于 MP4 的 iTunes metadata、ID3v2 tags。它支持为整个文件、单个轨道或章节设置元数据信息。Tags (0x1254C367) └─ Tag (0x7373) × N ← 一个标签集 ├─ Targets (0x63C0) - 目标信息 │ ├─ TargetTypeValue (0x68CA) - 目标类型值 (10/20/30/40/50/60/70) │ ├─ TargetType (0x63CA) - 目标类型字符串 (MOVIE, CHAPTER 等) │ ├─ TargetTrackUID (0x63C5) × N - 目标轨道 UID 列表 │ ├─ TargetChapterUID (0x63C4) × N - 目标章节 UID 列表 │ ├─ TargetAttachmentUID (0x63C6) × N - 目标附件 UID 列表 │ └─ TargetEditionUID (0x63C9) × N - 目标版本 UID 列表 │ └─ SimpleTag (0x67C8) × N - 具体标签 ├─ TagName (0x45A3) - 标签名称 (如 TITLE, ARTIST) ├─ TagLanguage (0x447A) - 语言代码 (如 eng, zh) ├─ TagDefault (0x4484) - 是否为默认语言 (0/1) ├─ TagString (0x4487) - 标签值字符串 ├─ TagBinary (0x4485) - 标签值二进制如图片 └─ SimpleTag (嵌套) × N - 子标签可选用于复杂结构2.3.7 AttachmentsAttachments是 MKV 文件中用于存储附加文件的容器元素。它可以将任意文件嵌入到 MKV 中最常见的用途是存储封面图片、字幕文件、字体文件等。Attachments (0x1941A469) └─ AttachedFile (0x61A7) × N ← 单个附加文件 ├─ FileDescription (0x467E) - 文件描述可选 ├─ FileName (0x466E) - 文件名必需 ├─ FileMimeType (0x4660) - MIME 类型必需 ├─ FileData (0x465C) - 文件数据必需二进制 └─ FileUID (0x46AE) - 文件唯一 ID可选2.3.8. Cluster媒体数据作用存储实际的音视频数据块是文件体积的主要组成部分。Cluster (0x1F43B675) × N ├─ Timecode (0xE7) - Cluster 的基准时间戳 ├─ Position (0xA7) - Cluster 在 Segment 内的位置 ├─ PrevSize (0xAB) - 前一 Cluster 的大小 ├─ SimpleBlock (0xA3) × N - 简单数据块可选 └─ BlockGroup (0xA0) × N ├─ Block (0xA1) - 数据块 ├─ BlockVirtual (0xA2) - 虚拟数据块 ├─ BlockAdditions (0x75A1) - 附加数据 ├─ BlockDuration (0x9B) - 块持续时间 ├─ ReferencePriority (0xFA) - 参考优先级 ├─ ReferenceBlock (0xFB) - 参考块 ├─ ReferenceVirtual (0xFD) - 虚拟参考 ├─ CodecState (0xA4) - 编解码器状态 └─ DiscardPadding (0x75A2) - 丢弃填充