You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 03:36:00