公司动态

C语言实战:从零构建SRT字幕生成工具,掌握文件与字符串处理

📅 2026/8/21 19:50:44
C语言实战:从零构建SRT字幕生成工具,掌握文件与字符串处理
这次我们来看一个用 C 语言从零开始实现“编码猫”字幕生成工具的项目。这个项目的核心不是教你复杂的视频编码理论而是通过一个具体的实战案例让你掌握 C 语言处理文件、字符串、时间戳以及生成标准字幕文件如 SRT的核心技能。对于想深入理解 C 语言在多媒体处理、自动化脚本领域应用或者希望自己动手制作简单字幕工具的学习者和开发者来说这是一个非常直接的练手项目。本文将带你从零开始一步步用 C 语言构建一个能够为视频生成中英双语字幕1080P 规格的命令行工具。整个过程不依赖复杂的第三方库重点在于算法逻辑和文件操作。你会看到如何解析原始文本、计算时间轴、处理编码格式并最终输出符合规范的 SRT 文件。无论你是 C 语言初学者想挑战综合项目还是需要为自制视频快速生成字幕模板这篇文章都能提供清晰的实现路径和可运行的代码。1. 核心能力速览能力项说明项目类型C 语言命令行工具用于生成视频字幕文件。核心功能根据输入的文本和时间信息生成标准的.srt格式字幕文件支持中英双语。输出规格适配 1080P 视频生成时间轴精确到毫秒的标准 SRT 格式。运行环境支持 Linux、macOS、Windows需对应 C 编译器如 GCC、MinGW。硬件门槛无特殊要求普通电脑即可运行不涉及 GPU 加速。依赖库仅使用 C 语言标准库stdio.h, stdlib.h, string.h 等无需额外安装。启动方式编译后通过命令行执行接受文本文件作为输入。是否支持批量是可通过脚本批量处理多个文本文件生成对应字幕。适合场景C 语言学习、课程设计、为自制视频添加基础字幕、理解字幕文件格式。2. 适用场景与使用边界这个工具适合以下几类人群C 语言学习者已经掌握基础语法想通过一个完整的、有实用价值的项目来巩固文件 I/O、内存管理、字符串处理和结构体应用。内容创作者制作技术分享、个人 vlog 等视频需要快速为视频生成基础的字幕文件再进行精细调整。嵌入式或系统开发者需要在资源受限的环境下处理文本或生成简单字幕信息此项目提供了轻量级的实现参考。它能解决什么问题自动化字幕生成将按时间分段好的文本自动转换为视频剪辑软件如 Premiere、剪映、DaVinci Resolve能直接导入的 SRT 字幕文件。格式规范保证确保生成的字幕文件时间轴格式、编码完全符合标准避免因格式错误导致软件无法识别。双语字幕支持可以方便地扩展为同一时间轴生成两种语言的字幕行。它的局限性非语音识别本项目不包含语音识别ASR功能。你需要预先准备好视频对应的台词文本和大致的时间点。非图形界面这是一个命令行工具所有操作通过终端和配置文件完成。时间轴需手动估算或外部提供工具本身不分析视频内容来获取精确时间戳需要你提供或估算出每句字幕的开始和结束时间。合规提醒生成的字幕文件应用于视频时请确保你对字幕文本内容拥有相应版权或合法授权尊重原创。3. 环境准备与前置条件在开始编码前你需要准备好基础的开发环境。操作系统Windows、Linux 或 macOS 均可。本文示例以 Linux/Unix 环境为主Windows 用户可使用 WSL、MinGW 或 Visual Studio 的命令行工具。C 编译器Linux/macOS通常默认安装 GCCGNU Compiler Collection。在终端输入gcc --version检查。若未安装Linux 可使用sudo apt install gcc(Debian/Ubuntu) 或sudo yum install gcc(RHEL/CentOS) 安装macOS 可通过 Xcode Command Line Tools 安装。Windows推荐使用 MinGW-w64 或安装 Visual Studio 并选择“使用 C 的桌面开发”工作负载以获取 MSVC 编译器。文本编辑器或 IDE任何你熟悉的即可如 VS Code、Vim、CLion、或 Windows 的 Notepad。基础命令行操作知识需要会使用cd,ls/dir,gcc编译命令等。4. 项目结构与设计思路在动手写代码前我们先规划一下程序的结构。一个字幕生成工具主要需要处理以下几件事读取输入从一个文本文件中读取预先准备好的字幕内容每行一句和可选的时间信息。管理数据将每一条字幕序号、开始时间、结束时间、文本用一个结构体struct来存储。处理时间轴如果没有提供精确时间需要根据句子长度、阅读速度等规则估算时间点如果提供了则解析时间数据。格式化输出按照 SRT 文件格式将每条字幕数据写入到新的文件中。处理编码确保输入输出文件的文本编码如 UTF-8正确以支持中文等非英文字符。设计核心数据结构// subtitle.h 或直接在 main.c 中定义 typedef struct { int index; // 字幕序号从1开始 char start_time[13]; // 开始时间格式 HH:MM:SS,mmm char end_time[13]; // 结束时间格式 HH:MM:SS,mmm char text_zh[256]; // 中文文本 char text_en[256]; // 英文文本 (可根据需要调整长度) } Subtitle;SRT 文件格式示例1 00:00:01,000 -- 00:00:04,000 欢迎来到编码猫的C语言教程。 Welcome to the Coding Cat‘s C tutorial. 2 00:00:04,500 -- 00:00:07,200 今天我们将学习如何编写一个字幕生成工具。 Today we will learn how to write a subtitle generator.5. 核心功能实现步骤5.1 创建项目文件首先在你的工作目录创建以下文件mkdir encode_cat_subtitle cd encode_cat_subtitle touch main.c subtitle.c subtitle.h input.txt Makefile5.2 编写头文件 (subtitle.h)头文件用于声明结构体和函数原型。// subtitle.h #ifndef SUBTITLE_H #define SUBTITLE_H #define MAX_TEXT_LEN 512 #define MAX_LINE_LEN 1024 #define TIME_STR_LEN 13 // HH:MM:SS,mmm\0 typedef struct { int index; char start_time[TIME_STR_LEN]; char end_time[TIME_STR_LEN]; char text_zh[MAX_TEXT_LEN]; char text_en[MAX_TEXT_LEN]; } Subtitle; // 函数声明 int read_input_file(const char* filename, Subtitle** subtitles, int* count); void calculate_timestamps(Subtitle* subtitles, int count, int start_hour, int start_min, int start_sec); int write_srt_file(const char* filename, Subtitle* subtitles, int count); void format_time(int total_ms, char* buffer); #endif5.3 编写辅助函数 (subtitle.c)这个文件包含具体的函数实现。// subtitle.c #include stdio.h #include stdlib.h #include string.h #include subtitle.h // 将毫秒数格式化为 SRT 时间字符串 (HH:MM:SS,mmm) void format_time(int total_ms, char* buffer) { int hours total_ms / (1000 * 60 * 60); int minutes (total_ms % (1000 * 60 * 60)) / (1000 * 60); int seconds (total_ms % (1000 * 60)) / 1000; int milliseconds total_ms % 1000; sprintf(buffer, %02d:%02d:%02d,%03d, hours, minutes, seconds, milliseconds); } // 从输入文件读取字幕文本 // 假设 input.txt 格式每行是“中文文本|英文文本” int read_input_file(const char* filename, Subtitle** subtitles, int* count) { FILE* file fopen(filename, r); if (!file) { perror(无法打开输入文件); return -1; } char line[MAX_LINE_LEN]; int capacity 10; *subtitles (Subtitle*)malloc(capacity * sizeof(Subtitle)); *count 0; while (fgets(line, sizeof(line), file)) { // 去除行尾换行符 line[strcspn(line, \n)] 0; if (strlen(line) 0) continue; // 跳过空行 // 如果数组满了扩容 if (*count capacity) { capacity * 2; *subtitles (Subtitle*)realloc(*subtitles, capacity * sizeof(Subtitle)); } // 解析中英文文本简单按‘|’分割 Subtitle* sub ((*subtitles)[*count]); sub-index *count 1; char* sep strchr(line, ‘|‘); if (sep) { *sep ‘\0‘; // 分割字符串 strncpy(sub-text_zh, line, MAX_TEXT_LEN - 1); strncpy(sub-text_en, sep 1, MAX_TEXT_LEN - 1); } else { // 如果没有分隔符整行作为中文英文留空 strncpy(sub-text_zh, line, MAX_TEXT_LEN - 1); sub-text_en[0] ‘\0‘; } sub-text_zh[MAX_TEXT_LEN - 1] ‘\0‘; sub-text_en[MAX_TEXT_LEN - 1] ‘\0‘; // 时间戳先置空后续计算 sub-start_time[0] ‘\0‘; sub-end_time[0] ‘\0‘; (*count); } fclose(file); return 0; } // 计算每条字幕的时间戳简易算法每句固定时长 void calculate_timestamps(Subtitle* subtitles, int count, int start_hour, int start_min, int start_sec) { int current_ms start_hour * 3600000 start_min * 60000 start_sec * 1000; const int duration_per_sub 3000; // 假设每句字幕显示3秒 for (int i 0; i count; i) { format_time(current_ms, subtitles[i].start_time); current_ms duration_per_sub; format_time(current_ms, subtitles[i].end_time); current_ms 200; // 句间间隔200毫秒 } } // 将字幕数据写入 SRT 文件 int write_srt_file(const char* filename, Subtitle* subtitles, int count) { FILE* file fopen(filename, w); if (!file) { perror(无法创建输出文件); return -1; } for (int i 0; i count; i) { fprintf(file, %d\n, subtitles[i].index); fprintf(file, %s -- %s\n, subtitles[i].start_time, subtitles[i].end_time); fprintf(file, %s\n, subtitles[i].text_zh); if (strlen(subtitles[i].text_en) 0) { fprintf(file, %s\n, subtitles[i].text_en); } fprintf(file, \n); // 字幕块之间空一行 } fclose(file); printf(字幕文件已生成: %s\n, filename); return 0; }5.4 编写主程序 (main.c)主程序负责协调整个流程。// main.c #include stdio.h #include stdlib.h #include subtitle.h int main(int argc, char* argv[]) { const char* input_filename input.txt; const char* output_filename output.srt; // 1. 读取字幕文本 Subtitle* subtitles NULL; int sub_count 0; if (read_input_file(input_filename, subtitles, sub_count) ! 0) { fprintf(stderr, 读取输入文件失败。\n); return 1; } printf(成功读取 %d 条字幕文本。\n, sub_count); // 2. 计算时间轴从视频第0秒开始 calculate_timestamps(subtitles, sub_count, 0, 0, 0); // 3. 写入SRT文件 if (write_srt_file(output_filename, subtitles, sub_count) ! 0) { fprintf(stderr, 写入SRT文件失败。\n); free(subtitles); return 1; } // 4. 清理内存 free(subtitles); printf(程序执行完毕。\n); return 0; }5.5 准备输入文件 (input.txt)按照“中文|英文”的格式准备你的字幕文本。欢迎来到编码猫的C语言教程。|Welcome to Coding Cat‘s C Language Tutorial. 今天我们将从零开始编写一个字幕生成工具。|Today we will write a subtitle generator from scratch. 这个工具可以将文本转换成SRT格式。|This tool can convert text to SRT format. 让我们开始吧|Let‘s get started!5.6 编译与运行使用gcc进行编译可以编写一个简单的Makefile。# Makefile CC gcc CFLAGS -Wall -stdc11 TARGET encode_cat OBJS main.o subtitle.o all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) main.o: main.c subtitle.h $(CC) $(CFLAGS) -c main.c subtitle.o: subtitle.c subtitle.h $(CC) $(CFLAGS) -c subtitle.c clean: rm -f $(OBJS) $(TARGET) output.srt run: $(TARGET) ./$(TARGET)在终端执行# 编译 make # 运行 make run # 或者直接运行编译好的程序 ./encode_cat运行成功后会在当前目录生成output.srt文件。6. 功能测试与效果验证6.1 基础生成测试测试目的验证程序能否正确读取输入文件并生成基本可用的 SRT 文件。操作按照第 5.5 节创建input.txt并填入 3-5 行测试文本。运行程序执行./encode_cat。预期结果终端打印“成功读取 X 条字幕文本”和“字幕文件已生成: output.srt”。用文本编辑器打开output.srt检查格式是否与第 4 节示例一致时间戳是否连续递增。成功标准生成的 SRT 文件能被主流视频播放器如 VLC、PotPlayer或剪辑软件正确识别和导入。6.2 中英文双语支持测试测试目的验证程序能正确处理双语分隔符‘|’。操作在input.txt中混合写入带‘|’和不带‘|’的行。这是只有中文的行。 这是中文|This is English.运行程序并检查output.srt。预期结果第一行字幕块应只有一行中文文本第二行字幕块应有中文和英文两行文本。常见问题如果英文文本没有显示检查subtitle.c中strchr和字符串分割的逻辑。6.3 长文本与换行测试测试目的验证程序对较长字幕行的处理能力。SRT 字幕单行不宜过长通常需要手动换行。操作在input.txt中输入一句很长的中文和英文。观察生成的 SRT 文件该句字幕是否仍然在一行内。注意本示例程序未实现自动换行长文本可能导致在某些播放器中显示不全。进阶改进你可以在write_srt_file函数中添加逻辑在文本超过一定长度如 50 字符时插入换行符\n。6.4 时间轴算法验证测试目的验证calculate_timestamps函数生成的时间轴是否合理。操作修改subtitle.c中duration_per_sub常量为 40004秒重新编译运行。预期结果output.srt中每条字幕的持续时间应变为 4 秒。更真实的算法当前是固定时长更高级的实现可以根据文本字数如中文每秒3-4字英文每秒4-5词动态计算每条字幕的持续时间并更新calculate_timestamps函数。7. 扩展功能与接口设计基础版本完成后可以考虑以下扩展使其更实用。7.1 支持从外部文件读取时间轴很多时候你可能有粗略的时间点。可以修改输入文件格式支持直接指定时间。新输入格式input_with_time.txt00:00:01,000|00:00:04,000|开场白|Opening 00:00:05,000|00:00:08,500|项目介绍|Project Introduction需要修改read_input_file函数来解析四列数据并跳过时间计算步骤。7.2 实现命令行参数解析让工具更灵活可以通过命令行指定输入输出文件、起始时间等。// 示例用法./encode_cat -i dialog.txt -o episode01.srt -s 00:01:30 int main(int argc, char* argv[]) { char* input_file input.txt; char* output_file output.srt; int start_h0, start_m0, start_s0; // 使用 getopt 解析命令行参数 // ... 解析代码 ... // 然后使用解析后的参数调用函数 }7.3 批量处理支持结合 Shell 脚本或 Python可以轻松实现批量处理。Shell 脚本示例 (batch_process.sh)#!/bin/bash for video in ./videos/*.mp4; do base_name$(basename $video .mp4) # 假设每个视频对应一个同名的文本文件 text_file./texts/${base_name}.txt output_srt./subtitles/${base_name}.srt if [[ -f $text_file ]]; then # 这里需要修改程序支持从参数读取输入输出文件 ./encode_cat -i $text_file -o $output_srt echo 为 $video 生成字幕: $output_srt fi done8. 常见问题与排查方法在开发和使用过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案编译错误undefined reference to ...没有链接所有.c文件检查编译命令是否包含了subtitle.c使用gcc main.c subtitle.c -o encode_cat或使用提供的Makefile运行时报错无法打开输入文件1.input.txt不存在2. 文件路径错误3. 程序没有读取权限1. 使用ls或dir确认文件是否存在2. 检查程序工作目录3. 检查文件权限1. 确保input.txt在程序运行目录2. 使用绝对路径或修改代码3. 修改文件权限 (chmod r input.txt)生成的字幕文件乱码文件编码不匹配如非 UTF-8用文本编辑器如 VS Code, Notepad查看文件编码1. 确保input.txt以 UTF-8 编码保存2. 在代码中明确设置文件读写模式如fopen(filename, “r, ccsUTF-8”)在 Windows MSVC 下视频软件无法导入 SRT 文件1. 时间格式错误2. 字幕块之间空行数量不对3. 使用了不兼容的换行符1. 仔细核对 SRT 格式特别是逗号,和箭头--2. 确保每个字幕块后有一个空行3. 在 Windows 下尝试用“wb“模式写入文件1. 严格按照HH:MM:SS,mmm格式2. 检查write_srt_file函数中fprintf(file, “\n“)的位置和次数3. 跨平台时注意换行符 (\r\nfor Windows,\nfor Unix)程序读取文本后崩溃段错误1. 内存分配失败2. 数组越界3. 字符串未正确终止1. 检查malloc/realloc返回值2. 使用valgrind(Linux) 或调试器检查3. 确保所有字符串操作都预留了空间给\01. 为malloc添加失败判断2. 使用strncpy并手动设置终止符dest[MAX_LEN-1] ‘\0‘3. 仔细检查所有数组索引9. 最佳实践与使用建议版本控制使用 Git 管理你的代码。这是练习 C 语言项目的好习惯。模块化设计将字幕结构、文件读写、时间计算等逻辑分离到不同的.c/.h文件中如本文的subtitle.c/h。这提高了代码的可读性和可维护性。防御性编程在read_input_file和write_srt_file中始终检查文件指针 (FILE*) 是否为NULL。对用户输入或输入文件的长度做边界检查防止缓冲区溢出。输入验证在实际项目中应增加对输入文件格式的验证。例如检查时间字符串是否符合HH:MM:SS,mmm的格式。错误处理函数应返回错误码并在主函数中进行统一处理而不是直接调用exit()。编码一致性明确你的项目使用何种字符编码强烈推荐 UTF-8并在所有文件操作中保持一致。可以在代码注释或文档中说明。测试驱动为关键函数如format_time, 时间计算逻辑编写简单的单元测试确保其正确性。文档化在头文件 (subtitle.h) 中使用注释说明每个函数的作用、参数和返回值。为项目编写一个简单的README.md说明编译和运行方法。10. 总结与下一步通过这个“编码猫”字幕生成器项目我们完成了一个从需求分析、数据结构设计、函数实现到最终测试的完整 C 语言开发流程。这个工具的核心价值在于其轻量、透明和可定制性——你完全清楚每一行代码在做什么并且可以轻松地修改时间轴算法、输入格式或输出样式来适应你的特定需求。最值得尝试的扩展方向集成简单语音识别虽然完整的 ASR 很复杂但可以尝试调用本地的开源语音识别库如 Vosk的 C API实现一个真正的“音视频转字幕”工具。开发图形界面使用 GTK、Qt 或 ncurses 库为工具添加一个简单的图形或终端界面让非程序员也能方便使用。支持更多字幕格式除了 SRT还可以增加对 ASS/SSA高级字幕、VTTWebVTT等格式的支持。时间轴微调工具编写一个辅助程序允许用户通过键盘快捷键如左/右箭头对生成的字幕时间轴进行毫秒级的微调。这个项目就像一把钥匙帮你打开了用 C 语言处理实际文件和数据的大门。建议你首先将基础版本跑通生成一个字幕文件并成功导入到视频剪辑软件中验证。然后选择一个你感兴趣的扩展方向进行尝试在实践中遇到和解决问题这才是提升编程能力最有效的途径。