Qt5.7实战从零开发夸克缓存视频合并工具最近在整理手机上的视频素材时发现夸克浏览器缓存的视频被分割成了大量TS片段手动合并起来非常麻烦。作为一个有经验的C开发者我决定用Qt框架开发一个专门的小工具来解决这个问题。本文将详细介绍整个开发过程包括环境配置、核心功能实现和实际应用中的各种坑点。1. 开发环境准备在开始编码之前我们需要确保开发环境配置正确。我选择的是Qt5.7.0版本这个版本在Windows平台上有很好的兼容性同时也能满足我们项目的需求。首先从Qt官网下载并安装Qt Creator和Qt5.7.0。安装时记得勾选以下组件MSVC 2015 32-bit或与你Visual Studio版本匹配的编译器Qt Charts可选用于未来可能的可视化扩展Qt Multimedia处理视频可能需要安装完成后创建一个新的Qt Widgets Application项目。在.pro文件中添加以下配置确保编码支持QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets # 支持中文路径 QMAKE_CXXFLAGS /source-charset:utf-8 /execution-charset:utf-8提示Windows平台下中文路径处理是个常见问题提前在编译选项中设置字符集可以避免很多麻烦。2. 解析夸克缓存结构夸克浏览器的视频缓存通常由一个m3u8索引文件和同名的文件夹组成文件夹内包含多个TS视频片段。我们的工具需要先解析m3u8文件获取所有TS片段的顺序信息。在MainWindow类中添加以下方法用于递归获取目录下所有文件QStringList MainWindow::getFilesRecursively(const QString dirPath) { QStringList fileList; QDir dir(dirPath); if (!dir.exists()) { qWarning() Directory does not exist: dirPath; return fileList; } QDirIterator it(dirPath, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); QFileInfo fileInfo it.fileInfo(); fileList.append(fileInfo.absoluteFilePath()); } return fileList; }这个方法会递归遍历指定目录下的所有文件返回它们的绝对路径。我们可以在UI中添加一个按钮让用户选择缓存目录然后调用这个方法获取所有m3u8文件void MainWindow::onSelectDirectoryClicked() { QString dir QFileDialog::getExistingDirectory(this, tr(选择夸克缓存目录), QDir::homePath()); if (dir.isEmpty()) return; QStringList m3u8Files getFilesRecursively(dir).filter(.m3u8); ui-fileComboBox-addItems(m3u8Files); }3. 实现视频合并功能核心的合并功能基于Windows的copy命令但直接使用QProcess调用会遇到各种问题。我的解决方案是生成一个临时批处理文件然后执行它。首先我们需要解析m3u8文件提取TS片段信息QStringList MainWindow::parseM3u8File(const QString filePath) { QStringList tsSegments; QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() Failed to open m3u8 file: filePath; return tsSegments; } QTextStream in(file); in.setCodec(UTF-8); while (!in.atEnd()) { QString line in.readLine().trimmed(); if (line.startsWith(#) || line.isEmpty()) continue; // 处理相对路径 if (!line.contains(/)) { QFileInfo info(filePath); line info.absolutePath() / line; } tsSegments line; } file.close(); return tsSegments; }接下来是生成批处理文件的代码bool MainWindow::generateBatchFile(const QStringList tsFiles, const QString outputPath) { QFile batchFile(merge_video.bat); if (batchFile.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream out(batchFile); out.setCodec(GBK); // Windows批处理文件需要GBK编码 // 切换到TS文件所在目录 QFileInfo firstTs(tsFiles.first()); out cd /d \ firstTs.absolutePath() \\n; // 构建copy命令 out copy /b ; foreach (const QString tsFile, tsFiles) { QFileInfo info(tsFile); out \ info.fileName() \ ; } out.seek(out.pos() - 3); // 移除最后的 out \ outputPath \\n; batchFile.close(); return true; } return false; }4. 处理中文路径问题中文路径是Windows平台下常见的问题源。Qt默认使用UTF-8编码而Windows API通常使用本地编码简体中文环境下是GBK。我们需要特别注意以下几点文件读写编码QTextStream in(file); in.setCodec(UTF-8); // 对于文本文件进程输出编码转换QProcess process; process.start(cmd.exe, QStringList() /c merge_video.bat); process.waitForFinished(); QString output QString::fromLocal8Bit(process.readAllStandardOutput()); ui-logTextEdit-append(output);路径拼接安全处理QString safePath QDir::toNativeSeparators(path); if (!safePath.endsWith(QDir::separator())) { safePath QDir::separator(); }5. 完整源码结构工具的主要类结构如下- MainWindow |- onSelectDirectoryClicked() : 选择目录槽函数 |- onMergeClicked() : 执行合并槽函数 |- getFilesRecursively() : 递归获取文件列表 |- parseM3u8File() : 解析m3u8文件 |- generateBatchFile() : 生成批处理文件 |- executeBatchFile() : 执行批处理并捕获输出UI设计只需要两个按钮选择目录和执行合并、一个下拉框选择m3u8文件和一个文本编辑框显示日志。6. 实际应用中的优化在实际使用过程中我发现几个可以优化的地方进度反馈长时间合并操作需要给用户反馈QProgressDialog progress(合并视频中..., 取消, 0, 0, this); progress.setWindowModality(Qt::WindowModal); progress.show(); QEventLoop loop; connect(process, SIGNAL(finished(int)), loop, SLOT(quit())); loop.exec(); progress.close();错误处理增强if (process.exitCode() ! 0) { QString error QString::fromLocal8Bit(process.readAllStandardError()); QMessageBox::critical(this, 错误, 合并失败:\n error); return; }批量处理支持自动处理目录下所有m3u8文件void MainWindow::batchProcessDirectory(const QString dirPath) { QStringList m3u8Files getFilesRecursively(dirPath).filter(.m3u8); foreach (const QString m3u8File, m3u8Files) { ui-fileComboBox-setCurrentText(m3u8File); onMergeClicked(); QCoreApplication::processEvents(); // 保持UI响应 } }7. 跨平台考虑虽然本文以Windows为例但工具可以很容易地扩展到其他平台。主要区别在于Linux/macOS使用cat命令代替copycat segment1.ts segment2.ts output.ts换行符处理QString command; #ifdef Q_OS_WIN command merge_video.bat; #else command sh merge_video.sh; #endif这个工具虽然不大但解决了一个实际痛点。开发过程中最耗时的不是核心功能实现而是各种边界情况的处理特别是Windows平台下的编码和路径问题。完整源码已经放在GitHub上包含了更多细节处理和错误检查代码。
Qt5.7实战:手把手教你用C++写夸克缓存视频合并工具(附完整源码)
Qt5.7实战从零开发夸克缓存视频合并工具最近在整理手机上的视频素材时发现夸克浏览器缓存的视频被分割成了大量TS片段手动合并起来非常麻烦。作为一个有经验的C开发者我决定用Qt框架开发一个专门的小工具来解决这个问题。本文将详细介绍整个开发过程包括环境配置、核心功能实现和实际应用中的各种坑点。1. 开发环境准备在开始编码之前我们需要确保开发环境配置正确。我选择的是Qt5.7.0版本这个版本在Windows平台上有很好的兼容性同时也能满足我们项目的需求。首先从Qt官网下载并安装Qt Creator和Qt5.7.0。安装时记得勾选以下组件MSVC 2015 32-bit或与你Visual Studio版本匹配的编译器Qt Charts可选用于未来可能的可视化扩展Qt Multimedia处理视频可能需要安装完成后创建一个新的Qt Widgets Application项目。在.pro文件中添加以下配置确保编码支持QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets # 支持中文路径 QMAKE_CXXFLAGS /source-charset:utf-8 /execution-charset:utf-8提示Windows平台下中文路径处理是个常见问题提前在编译选项中设置字符集可以避免很多麻烦。2. 解析夸克缓存结构夸克浏览器的视频缓存通常由一个m3u8索引文件和同名的文件夹组成文件夹内包含多个TS视频片段。我们的工具需要先解析m3u8文件获取所有TS片段的顺序信息。在MainWindow类中添加以下方法用于递归获取目录下所有文件QStringList MainWindow::getFilesRecursively(const QString dirPath) { QStringList fileList; QDir dir(dirPath); if (!dir.exists()) { qWarning() Directory does not exist: dirPath; return fileList; } QDirIterator it(dirPath, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); QFileInfo fileInfo it.fileInfo(); fileList.append(fileInfo.absoluteFilePath()); } return fileList; }这个方法会递归遍历指定目录下的所有文件返回它们的绝对路径。我们可以在UI中添加一个按钮让用户选择缓存目录然后调用这个方法获取所有m3u8文件void MainWindow::onSelectDirectoryClicked() { QString dir QFileDialog::getExistingDirectory(this, tr(选择夸克缓存目录), QDir::homePath()); if (dir.isEmpty()) return; QStringList m3u8Files getFilesRecursively(dir).filter(.m3u8); ui-fileComboBox-addItems(m3u8Files); }3. 实现视频合并功能核心的合并功能基于Windows的copy命令但直接使用QProcess调用会遇到各种问题。我的解决方案是生成一个临时批处理文件然后执行它。首先我们需要解析m3u8文件提取TS片段信息QStringList MainWindow::parseM3u8File(const QString filePath) { QStringList tsSegments; QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() Failed to open m3u8 file: filePath; return tsSegments; } QTextStream in(file); in.setCodec(UTF-8); while (!in.atEnd()) { QString line in.readLine().trimmed(); if (line.startsWith(#) || line.isEmpty()) continue; // 处理相对路径 if (!line.contains(/)) { QFileInfo info(filePath); line info.absolutePath() / line; } tsSegments line; } file.close(); return tsSegments; }接下来是生成批处理文件的代码bool MainWindow::generateBatchFile(const QStringList tsFiles, const QString outputPath) { QFile batchFile(merge_video.bat); if (batchFile.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream out(batchFile); out.setCodec(GBK); // Windows批处理文件需要GBK编码 // 切换到TS文件所在目录 QFileInfo firstTs(tsFiles.first()); out cd /d \ firstTs.absolutePath() \\n; // 构建copy命令 out copy /b ; foreach (const QString tsFile, tsFiles) { QFileInfo info(tsFile); out \ info.fileName() \ ; } out.seek(out.pos() - 3); // 移除最后的 out \ outputPath \\n; batchFile.close(); return true; } return false; }4. 处理中文路径问题中文路径是Windows平台下常见的问题源。Qt默认使用UTF-8编码而Windows API通常使用本地编码简体中文环境下是GBK。我们需要特别注意以下几点文件读写编码QTextStream in(file); in.setCodec(UTF-8); // 对于文本文件进程输出编码转换QProcess process; process.start(cmd.exe, QStringList() /c merge_video.bat); process.waitForFinished(); QString output QString::fromLocal8Bit(process.readAllStandardOutput()); ui-logTextEdit-append(output);路径拼接安全处理QString safePath QDir::toNativeSeparators(path); if (!safePath.endsWith(QDir::separator())) { safePath QDir::separator(); }5. 完整源码结构工具的主要类结构如下- MainWindow |- onSelectDirectoryClicked() : 选择目录槽函数 |- onMergeClicked() : 执行合并槽函数 |- getFilesRecursively() : 递归获取文件列表 |- parseM3u8File() : 解析m3u8文件 |- generateBatchFile() : 生成批处理文件 |- executeBatchFile() : 执行批处理并捕获输出UI设计只需要两个按钮选择目录和执行合并、一个下拉框选择m3u8文件和一个文本编辑框显示日志。6. 实际应用中的优化在实际使用过程中我发现几个可以优化的地方进度反馈长时间合并操作需要给用户反馈QProgressDialog progress(合并视频中..., 取消, 0, 0, this); progress.setWindowModality(Qt::WindowModal); progress.show(); QEventLoop loop; connect(process, SIGNAL(finished(int)), loop, SLOT(quit())); loop.exec(); progress.close();错误处理增强if (process.exitCode() ! 0) { QString error QString::fromLocal8Bit(process.readAllStandardError()); QMessageBox::critical(this, 错误, 合并失败:\n error); return; }批量处理支持自动处理目录下所有m3u8文件void MainWindow::batchProcessDirectory(const QString dirPath) { QStringList m3u8Files getFilesRecursively(dirPath).filter(.m3u8); foreach (const QString m3u8File, m3u8Files) { ui-fileComboBox-setCurrentText(m3u8File); onMergeClicked(); QCoreApplication::processEvents(); // 保持UI响应 } }7. 跨平台考虑虽然本文以Windows为例但工具可以很容易地扩展到其他平台。主要区别在于Linux/macOS使用cat命令代替copycat segment1.ts segment2.ts output.ts换行符处理QString command; #ifdef Q_OS_WIN command merge_video.bat; #else command sh merge_video.sh; #endif这个工具虽然不大但解决了一个实际痛点。开发过程中最耗时的不是核心功能实现而是各种边界情况的处理特别是Windows平台下的编码和路径问题。完整源码已经放在GitHub上包含了更多细节处理和错误检查代码。