C++开发WebVTT字幕编辑器的时间存储方案选型咨询
字幕编辑器时间存储方案实现
成员类型选型说明
你场景中的begin和end本质是相对于视频起始位置的时长偏移值,不需要关联系统时钟、日历时间,因此不需要使用std::chrono::time_point类型,直接选择std::chrono::milliseconds作为成员类型是最优解,理由如下:
- 精度和WebVTT字幕的毫秒级时间格式完全匹配,没有精度损失
- 底层采用
long long存储,最大可支持约2.9亿年的时长表示,完全覆盖120小时甚至更长视频的需求 - 原生支持加减、比较等运算,不需要额外实现算术逻辑
完整实现代码
#include <chrono> #include <string> #include <vector> #include <stdexcept> #include <string_view> #include <charconv> using namespace std::chrono_literals; // 字幕片段结构体 struct SubtitleElement { std::chrono::milliseconds begin; std::chrono::milliseconds end; std::string text; }; // 转换hh:mm:ss.ZZZ格式字符串为毫秒时长,支持小时超过24 std::chrono::milliseconds parseTimeStr(std::string_view timeStr) { const size_t colon1 = timeStr.find(':'); const size_t colon2 = timeStr.find(':', colon1 + 1); const size_t dot = timeStr.find('.', colon2 + 1); if (colon1 == std::string_view::npos || colon2 == std::string_view::npos || dot == std::string_view::npos) { throw std::invalid_argument("时间格式错误,预期格式为 hh:mm:ss.ZZZ"); } long long hh = 0, mm = 0, ss = 0, zzz = 0; std::from_chars_result res; res = std::from_chars(timeStr.data(), timeStr.data() + colon1, hh); if (res.ec != std::errc()) throw std::invalid_argument("小时数值非法"); res = std::from_chars(timeStr.data() + colon1 + 1, timeStr.data() + colon2, mm); if (res.ec != std::errc() || mm >= 60) throw std::invalid_argument("分钟数值非法,需小于60"); res = std::from_chars(timeStr.data() + colon2 + 1, timeStr.data() + dot, ss); if (res.ec != std::errc() || ss >= 60) throw std::invalid_argument("秒数值非法,需小于60"); res = std::from_chars(timeStr.data() + dot + 1, timeStr.data() + timeStr.size(), zzz); if (res.ec != std::errc() || zzz >= 1000) throw std::invalid_argument("毫秒数值非法,需小于1000"); return std::chrono::hours(hh) + std::chrono::minutes(mm) + std::chrono::seconds(ss) + std::chrono::milliseconds(zzz); } // 字幕时间偏移:offset为正向后偏移,为负向前偏移 // 原示例值传递无法修改原对象,改为引用传递 void shiftTime(SubtitleElement& element, std::chrono::milliseconds offset) { element.begin += offset; element.end += offset; // 可选边界校验:时间不能小于视频起始点 if (element.begin < 0ms) element.begin = 0ms; if (element.end < 0ms) element.end = 0ms; } // 获取单个字幕片段显示时长 std::chrono::milliseconds getDuration(const SubtitleElement& element) { return element.end - element.begin; } // 计算所有字幕片段总显示时长 std::chrono::milliseconds totalDuration(const std::vector<SubtitleElement>& elements) { std::chrono::milliseconds total = 0ms; for (const auto& elem : elements) { total += getDuration(elem); } return total; }
方案优势
- 完全符合现代C++规范,时间运算类型安全,不会出现隐式精度丢失问题
- 零成本抽象,运行性能和手动用
long long存储毫秒值完全一致 - 如需转换回
hh:mm:ss.ZZZ格式,直接用std::chrono::duration_cast拆分时长即可,天然支持小时大于24的场景
内容的提问来源于stack exchange,提问作者DEKKER
相关产品推荐
相关产品推荐

