easy网盘补充学习——视频上传(使用ffmpeg)
关于ts文件(了解即可)
TS 文件的全称是 Transport Stream(传输流),它是一种专门为了在不稳定的网络环境或广播信号中传输高质量视频而设计的格式。
简单来说,如果把常见的 MP4 比作一本书(必须从头读,中间缺页就读不懂了),那么 TS 就像是一卷卫生纸(哪怕中间撕掉一段,剩下的每一节依然是独立完整的,照样能用)。
为了让你更直观地理解,我为你整理了 TS 文件的核心特点、应用场景以及它和 MP4 的区别。
1. 核心特点:为什么它叫“传输流”?
TS 格式的设计初衷是为了“抗造”(容错率高)。
- 独立的数据包: TS 文件是由一个个固定大小(通常是 188 字节)的小数据包组成的。每个包都包含视频、音频或控制信息。
- 任意位置可播放: 这是 TS 最大的特点。即使文件损坏、或者你只下载了文件的中间一部分,播放器依然可以从那个位置开始解码播放。相比之下,MP4 如果文件头损坏,整个视频通常就无法播放了。
- 多路复用: 它可以把多套节目(比如 CCTV-1、CCTV-5)的音视频流打包在同一个 TS 流中传输,接收端再通过 PID(包标识符)把它们分离出来。
2. TS 与 MP4 的区别
这是新手最容易混淆的地方,我们可以用一张表来对比:
| 特性 | TS (Transport Stream) | MP4 (MPEG-4 Part 14) |
|---|---|---|
| 主要用途 | 传输 (直播、广播、监控) | 存储 (下载、网盘、手机相册) |
| 容错性 | 极高 (丢包也能播) | 低 (文件头损坏则无法播放) |
| 兼容性 | 较差 (部分播放器需转码) | 极好 (几乎所有设备都能播) |
| 文件结构 | 连续的数据包流 | 复杂的树状索引结构 |
| 典型场景 | 电视直播、HLS 切片、监控录像 | 电影下载、短视频上传 |
3. 常见应用场景
你在日常生活中其实经常接触到 TS 文件,只是可能没注意到后缀名:
- 网络直播 (HLS): 当你在手机上看直播时,视频其实是被切成了无数个几秒钟长的
.ts小文件,通过.m3u8索引文件按顺序播放。 - 数字电视广播: 无论是卫星电视还是地面波数字电视,信号传输的标准格式就是 TS。
- 高清摄像机/监控: 很多家用监控摄像头或高清摄像机录制的原始文件也是 TS 格式,因为它能保证即使写入过程中断电,之前的数据也能被读取。
- 蓝光光盘: 蓝光光盘中的高清视频流通常也是封装在 TS 容器中的(通常称为 M2TS)。
4. 如何播放和转换?
- 播放:
- Windows 自带的播放器可能不支持,建议下载 VLC Media Player 或 PotPlayer,它们内置了强大的解码器,可以直接播放 TS 文件。
- 转换 (TS 转 MP4):
- 如果你下载了一个 TS 文件想在手机上看,或者想剪辑,最好的办法是把它转成 MP4。
- 无损转换技巧: 使用 FFmpeg 转换时,可以使用
-c copy参数。因为 TS 和 MP4 内部的视频编码通常都是 H.264,所以不需要重新编码,只需要“换个马甲”,速度极快且画质无损。 - 命令:
ffmpeg -i input.ts -c copy output.mp4
⚠️ 特别提示:别和 TypeScript 搞混了
作为 Java 新手,你在搜索资料时可能会看到另一种 .ts 文件。
- 视频文件: 后缀
.ts,是 Transport Stream。 - 编程文件: 后缀
.ts,是 TypeScript(一种由微软开发的编程语言,是 JavaScript 的超集)。 - 区分方法: 看文件大小。视频文件通常几百 MB 甚至几个 G;代码文件通常只有几 KB 到几百 KB。
总结来说,TS 就是为了“稳”而生的视频格式,它是直播和广播领域的“老大哥”,虽然兼容性不如 MP4,但在传输稳定性上无可替代。
关于.m3u8
.m3u8 文件本质上不是视频文件,而是一个播放列表或索引文件。你可以把它理解成一份“外卖菜单”,它本身不是食物,但上面列出了所有菜品(视频片段)的地址和顺序。
.m3u8 是苹果公司提出的 HLS (HTTP Live Streaming) 流媒体协议的核心组成部分。它的作用是指导播放器如何播放一个视频流。
- m3u8 文件 (菜单/包工头):一个纯文本文件,里面不包含任何视频数据,只记录了视频片段的网络地址、时长和播放顺序。
- .ts 文件 (食物/砖块):视频内容被服务器预先切割成许多个时长很短(通常是几秒到十几秒)的
.ts格式小文件。
当你播放一个 .m3u8 链接时,播放器会先读取这个“菜单”,然后按照指引,自动、快速地从网络上下载一个个 .ts 视频片段,并无缝拼接起来播放,让你感觉像是在看一个完整的视频。
视频切割
private void cutFile4Video(String fileId, String videoFilePath) {
//创建同名切片目录
File tsFolder = new File(videoFilePath.substring(0, videoFilePath.lastIndexOf(".")));
if (!tsFolder.exists()) {
tsFolder.mkdirs();
}
final String CMD_TRANSFER_2TS = "ffmpeg -y -i %s -vcodec copy -acodec copy -vbsf h264_mp4toannexb %s";
final String CMD_CUT_TS = "ffmpeg -i %s -c copy -map 0 -f segment -segment_list %s -segment_time 30 %s/%s_%4d.ts";
String tsPath = tsFolder + "/" + Constants.TS_NAME;
//生成.ts
String cmd = String.format(CMD_TRANSFER_2TS, videoFilePath, tsPath);
ProcessUtils.executeCommand(cmd, false);
//生成索引文件.m3u8和切片.ts
cmd = String.format(CMD_CUT_TS, tsPath, tsFolder.getPath() + "/" + Constants.M3U8_NAME, tsFolder.getPath(), fileId);
ProcessUtils.executeCommand(cmd, false);
//删除index.tx
new File(tsPath).delete();
}
1.首先为切片文件准备一个专属文件夹,防止文件散乱
// 1. 创建同名切片目录
// 假设视频路径是 D:/videos/test.mp4
// 那么 tsFolder 就是 D:/videos/test (去掉后缀名作为文件夹名)
File tsFolder = new File(videoFilePath.substring(0, videoFilePath.lastIndexOf(".")));
if (!tsFolder.exists()) {
tsFolder.mkdirs();
}
关于substring在easy网盘补充学习——substring、indexof和lastIndexOf-CSDN博客
FIle在File学习-CSDN博客
2.定义ffmpeg指令
指令 A:格式转换 (CMD_TRANSFER_2TS)
// 将 MP4 转为一个巨大的 TS 文件
final String CMD_TRANSFER_2TS = "ffmpeg -y -i %s -vcodec copy -acodec copy -vbsf h264_mp4toannexb %s";
-vcodec copy -acodec copy:不进行重新编码,只是复制流,速度极快(无损)。-vbsf h264_mp4toannexb:这是关键。MP4 和 TS 的存储格式不同,这个参数将 H.264 编码从 MP4 格式转换为 TS 格式(Annex B)。
指令 B:切片与生成索引 (CMD_CUT_TS)
// 将那个巨大的 TS 文件,切成 30秒一段的小文件
final String CMD_CUT_TS = "ffmpeg -i %s -c copy -map 0 -f segment -segment_list %s -segment_time 30 %s/%s_%4d.ts";
-f segment:告诉 FFmpeg 使用“分段”模式。-segment_time 30:每 30 秒切一刀。-segment_list %s:生成一个列表文件(即 .m3u8 的前身,或者就是 m3u8 内容)。%s/%s_%4d.ts:输出文件的命名规则,例如video_0001.ts,video_0002.ts。
3.执行“加工”流程
动作 1:先转成中间格式
String tsPath = tsFolder + "/" + Constants.TS_NAME; // 比如叫 index.ts
// 生成.ts
String cmd = String.format(CMD_TRANSFER_2TS, videoFilePath, tsPath);
ProcessUtils.executeCommand(cmd, false);
这里先利用 ProcessUtils(java执行命令工具类)把 MP4 变成一个巨大的 index.ts 文件。
调用ffmpeg 执行CMD_TRANSFER_2TS命令
动作 2:再切分
// 生成索引文件.m3u8和切片.ts
cmd = String.format(CMD_CUT_TS, tsPath, tsFolder.getPath() + "/" + Constants.M3U8_NAME, tsFolder.getPath(), fileId);
ProcessUtils.executeCommand(cmd, false);
利用刚才生成的 index.ts,快速切割成几十个小文件。
调用ffmpeg 执行CMD_CUT_TS命令
4.打扫战场
// 删除 index.ts (中间临时文件)
new File(tsPath).delete();
因为切片已经完成了,那个巨大的 index.ts 就没用了,删掉它以节省磁盘空间。
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)