jacky56 发表于 2026-4-6 02:05:15

关于海南鸡饭字幕时间轴不准的解决方法

发现ai的时间轴的开始阶段都比较准确,不准确主要在于结束阶段,造成很多字幕停留时间过长,或者有些字幕停留时间过短,一闪而过
找deepseek给我编了一段c++代码,这几天没时间,等有空的时候,我编译一个小软件测试一下dp的编程水平
把代码贴出来,给大家参考,会编码的同学可以自己拿过去玩玩




请编写一段c++代码
给定一个电影的字幕文件
1、打开字幕文件
2、编辑字幕文件,将字幕文件的显示时间设为如下要求
如果单条字幕显示时间短于2秒,则将字幕显示时间设定为3秒
如果单条字幕显示时间长于5秒,则将字幕显示时间定为5秒
3、完成后关闭文件

我们需编写C++代码处理字幕文件(.srt格式),要求:对于每条字幕,计算其显示时长(结束时间 - 开始时间)。如果时长 < 2秒,则调整结束时间使得时长为3秒;如果时长 > 5秒,则调整结束时间使得时长为5秒。保持开始时间不变,只修改结束时间。需注意毫秒精度。

实现步骤:

打开字幕文件,逐行读取,识别时间行(格式:HH:MM:SS,mmm --> HH:MM:SS,mmm)。

解析开始时间和结束时间,计算当前时长(毫秒)。

根据规则计算新结束时间:若时长<2000ms,新结束=开始+3000ms;若时长>5000ms,新结束=开始+5000ms;否则不变。

将修改后的时间行写回,其他行(序号、文本、空行)原样保留。

输出到新文件或覆盖原文件(这里可覆盖原文件,但建议备份或写新文件)。本代码将结果写回原文件(先读入内存再写回)。

注意处理边界:字幕时间可能跨小时,但计算方法正确。

代码将包含必要头文件、时间解析/格式化函数、主逻辑。

以下 C++ 代码实现了对 SRT 字幕文件的时间调整功能:若字幕显示时长不足 2 秒,则延长至 3 秒;若超过 5 秒,则缩短至 5 秒;其余情况保持不变。

cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <iomanip>
#include <sstream>

// 时间结构体:时、分、秒、毫秒
struct Time {
    int h, m, s, ms;
};

// 解析 "HH:MM:SS,mmm" 字符串为 Time 结构
Time parseTime(const std::string& timeStr) {
    Time t;
    char comma;
    std::stringstream ss(timeStr);
    ss >> t.h >> comma >> t.m >> comma >> t.s >> comma >> t.ms;
    return t;
}

// 将 Time 结构格式化为 "HH:MM:SS,mmm"
std::string formatTime(const Time& t) {
    std::stringstream ss;
    ss << std::setw(2) << std::setfill('0') << t.h << ":"
       << std::setw(2) << std::setfill('0') << t.m << ":"
       << std::setw(2) << std::setfill('0') << t.s << ","
       << std::setw(3) << std::setfill('0') << t.ms;
    return ss.str();
}

// 将 Time 转换为毫秒数(从 0 开始)
int timeToMillis(const Time& t) {
    return ((t.h * 60 + t.m) * 60 + t.s) * 1000 + t.ms;
}

// 将毫秒数转换为 Time 结构(自动规整小时)
Time millisToTime(int totalMs) {
    Time t;
    t.h = totalMs / 3600000;
    totalMs %= 3600000;
    t.m = totalMs / 60000;
    totalMs %= 60000;
    t.s = totalMs / 1000;
    t.ms = totalMs % 1000;
    return t;
}

// 调整字幕时间行:根据规则修改结束时间
// 参数:原始开始时间、原始结束时间
// 返回:新的时间行字符串
std::string adjustTimeLine(const std::string& startStr, const std::string& endStr) {
    Time start = parseTime(startStr);
    Time end   = parseTime(endStr);
   
    int startMs = timeToMillis(start);
    int endMs   = timeToMillis(end);
    int duration = endMs - startMs;
   
    int newEndMs = endMs;
    if (duration < 2000) {          // 小于2秒 -> 设为3秒
      newEndMs = startMs + 3000;
    } else if (duration > 5000) {   // 大于5秒 -> 设为5秒
      newEndMs = startMs + 5000;
    }
   
    Time newEnd = millisToTime(newEndMs);
    return formatTime(start) + " --> " + formatTime(newEnd);
}

// 处理字幕文件
bool processSubtitleFile(const std::string& filename) {
    std::ifstream inFile(filename);
    if (!inFile.is_open()) {
      std::cerr << "错误:无法打开文件 " << filename << std::endl;
      return false;
    }
   
    std::vector<std::string> outputLines;
    std::string line;
    // 匹配时间行的正则表达式:HH:MM:SS,mmm --> HH:MM:SS,mmm
    std::regex timePattern(R"((\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2},\d{3}))");
   
    while (std::getline(inFile, line)) {
      std::smatch match;
      if (std::regex_match(line, match, timePattern)) {
            // 是时间行,进行修改
            std::string start = match;
            std::string end   = match;
            std::string newTimeLine = adjustTimeLine(start, end);
            outputLines.push_back(newTimeLine);
      } else {
            // 其他行(序号、字幕文本、空行)原样保留
            outputLines.push_back(line);
      }
    }
    inFile.close();
   
    // 将修改后的内容写回原文件(覆盖)
    std::ofstream outFile(filename);
    if (!outFile.is_open()) {
      std::cerr << "错误:无法写入文件 " << filename << std::endl;
      return false;
    }
    for (const auto& l : outputLines) {
      outFile << l << '\n';
    }
    outFile.close();
    return true;
}

int main() {
    std::string filename = "subtitle.srt";// 请替换为实际字幕文件路径
   
    if (processSubtitleFile(filename)) {
      std::cout << "字幕文件处理成功!所有显示时间已按要求调整。\n";
    } else {
      std::cerr << "处理失败。\n";
      return 1;
    }
    return 0;
}
代码说明
时间解析与格式化

parseTime:将 HH:MM:SS,mmm 字符串转换为结构体。

formatTime:反向转换,保证两位时、分、秒和三位毫秒。

timeToMillis / millisToTime:用于方便地计算时间差和生成新结束时间。

核心调整函数 adjustTimeLine

计算原始显示时长(毫秒)。

若时长 < 2000ms → 新结束 = 开始 + 3000ms。

若时长 > 5000ms → 新结束 = 开始 + 5000ms。

否则保持原结束时间不变。

返回修改后的时间行字符串。

文件处理流程

使用正则表达式识别时间行(匹配形如 00:01:23,456 --> 00:01:25,789 的行)。

其他行(序号、字幕文本、空行)原样保留。

将所有行存入 vector,处理完成后重新写入原文件(覆盖)。

使用方法
将代码中的 filename 修改为您的字幕文件路径(例如 "movie.srt")。

编译(需支持 C++11 或更高版本):

bash
g++ -std=c++11 adjust_subtitle.cpp -o adjust_subtitle
运行:

bash
./adjust_subtitle

hhhnaruto 发表于 2026-4-6 02:24:34

如果只是根据临界值修改字幕显示时间,其实用py脚本会更简单

daral331 发表于 2026-4-6 07:46:39

本帖最后由 daral331 于 2026-4-6 07:54 编辑

楼主,根据我的观测,应该是:若时长 > 5000ms → 新结束 = 结束 - 5000ms。比较准确

但是我们不会编程的就很难看懂了

jushuwumiao 发表于 2026-4-7 10:18:58

这个功能我也做了个类似的,是根据单条字幕字数判断的,并且把海南鸡饭里面有时候大量出现的重复文字简化了。
缺点也很明显,海南鸡饭有时候断句没做好,一条字幕可能是跨了好几段话,会导致后面说话的时候字幕已经结束了。

jacky56 发表于 2026-4-7 15:40:26

jushuwumiao 发表于 2026-4-7 10:18
这个功能我也做了个类似的,是根据单条字幕字数判断的,并且把海南鸡饭里面有时候大量出现的重复文字简化了 ...

海南鸡饭的配置文件有一个关于重复字幕合并的选项,你把两条字幕之间的间隔时间缩短会好很多,默认间隔是20秒

jushuwumiao 发表于 2026-4-7 17:09:49

jacky56 发表于 2026-4-7 15:40
海南鸡饭的配置文件有一个关于重复字幕合并的选项,你把两条字幕之间的间隔时间缩短会好很多,默认间隔是 ...

感谢,回头试一下
页: [1]
查看完整版本: 关于海南鸡饭字幕时间轴不准的解决方法