不可行。libmkv已废弃且不支持字幕解析;推荐用ffmpeg:先用ffprobe确认字幕流,再用libavformat解复用,对srt/webvtt可直接读avpacket数据,ass需libass渲染,图形字幕需ocr或渲染。

用 libmkv 提取 MKV 中的字幕轨道是否可行?
不可行。libmkv 是一个已废弃的旧库(Google Code 时代),不支持字幕解析,也不维护多年。它只负责基础容器结构写入,连轨道类型识别都极简。真正能可靠提取字幕的,是 libmatroska 配合 libebml,但直接用它们要手动遍历 Cluster、Block、TrackEntry,对字幕编码(如 UTF-8 文本、ASS、SRT 封装)和时间戳解包要求很高——实际项目中几乎没人这么干。
推荐方案:用 FFmpeg + libavcodec 解析字幕流
FFmpeg 的 libavformat 能自动识别 MKV 内所有轨道,包括 subtitles 类型的流(如 mov_text、ass、srt、webvtt)。关键不是“提取文件”,而是“解复用出字幕帧并转成可读文本”。
- 先用
avformat_open_input()打开 MKV,调用avformat_find_stream_info() - 遍历
fmt_ctx->streams,检查每个stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE - 对目标字幕流,分配
AVCodecContext*并用avcodec_parameters_to_context()初始化 - 用
avcodec_open2()打开解码器(注意:部分字幕如mov_text是“无损封装”,实际无需解码,直接读AVSubtitle或AVPacket数据即可)
常见坑:AV_CODEC_ID_ASS 流需用 libass 渲染才能得纯文本;而 AV_CODEC_ID_SRT 和 AV_CODEC_ID_WEBVTT 的 AVPacket data 字段通常就是 UTF-8 原始文本,带起止时间戳(需解析 pts/dts 或从 AVPacket 的 side_data 中提取)。
快速验证:用 ffprobe 确认字幕轨道是否存在
别急着写 C++,先确认 MKV 里真有你想提的字幕:
ffprobe -v quiet -show_entries stream=index,codec_type,codec_name,tags=title -select_streams s input.mkv
输出类似:
index=2 codec_type=subtitle codec_name=srt tags=title=English
说明第 2 号流是 SRT 字幕,标题为 English。如果 codec_name 是 ass 或 webvtt,后续处理逻辑要区分;如果是 pgssub 或 dvdsub,那就是图形字幕,不能直接转文本,得走 OCR 或渲染流程。
最简 C++ 实现:只提取 SRT/WEBVTT 文本内容
以下逻辑仅适用于纯文本类字幕(srt、webvtt),跳过解码步骤,直接从 AVPacket 拷贝数据:
- 打开文件后,找到字幕流索引
subtitle_stream_idx -
while (av_read_frame(fmt_ctx, &pkt) >= 0)循环读包 - 若
pkt.stream_index == subtitle_stream_idx,则std::string text((char*)pkt.data, pkt.size) - 注意:
pkt.pts是时间戳(单位是time_base),需转换为秒:double sec = pkt.pts * av_q2d(stream->time_base) - 不要忽略
pkt.convergence_duration和pkt.duration,它们共同决定显示时长
真实 MKV 中常有多个字幕流混存,或同一语言含不同格式(比如硬嵌 ASS + 外挂 SRT),务必按 stream->codecpar->codec_id 分支处理,不能一概而论。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











