java+ffmpeg实现mp4转m3u8切片(ts)
java+ffmpeg实现mp4转m3u8切片
目录
前言
M3U8是一种基于文本的播放列表文件格式,用于指定多个媒体文件(通常是视频或音频)的播放顺序和信息,常用于网络流媒体传输。M3U8文件通常包含一系列URL地址,用于指定媒体文件的片段(segment)或流(stream),以及相关的元数据和参数。
M3U8文件一般通过HTTP协议进行下载和访问,播放器通过解析M3U8文件获取媒体文件的地址和相关信息,并根据需要逐个下载和播放分片媒体文件,从而实现流媒体的播放。由于其开放的文本格式和广泛的支持,M3U8文件在各种流媒体应用中得到了广泛的应用,特别是在移动设备和网络直播领域。
1、前提
首先需要安装ffmpeg,参考《Linux+Windows实现ffmpeg配置安装》
注意:
以下功能的实现是在Windwos平台
2、mp4转m3u8
命令如下:
ffmpeg -i D:/m3u8/demo.mp4 -c:v copy -c:a copy -f ssegment -segment_format mpegts -segment_list D:/m3u8/hls/test.m3u8 -segment_time 10 D:/m3u8/hls/test%05d.ts
D:/m3u8/demo.mp4输入的mp4文件
D:/m3u8/hls/test.m3u8输出的m3u8文件
-segment_time设置每片的长度,单位为秒
-segment_list :段文件的名称,%05d表示5位数字
生成的效果是:将demo.mp4视频文件每10秒生成一个ts文件,最后生成一个m3u8文件,m3u8文件是ts的索引文件。
3、播放测试
3.1、html
为了方便测试,写了一个简单的html,详细代码见《测试html》,html只需要解压后,修改里面的src地址,设置为实际的m3u8播放地址
比如:
3.2、nginx
除此之外需要配置,nginx实现资源播放,配置如下:
location /hls {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias D:/m3u8/hls/; #切片存放地址
expires -1;
add_header Cache-Control no-cache;
}
本地的m3u8播放路径为:
http:127.0.0.1/hls/test.m3u8
4、java实现
在实际开发中,可以通过java
调用cmd
命令,使用ffmpeg进行切片操作,主要代码如下:
4.1、ProcessUtil.java
public class ProcessUtil {
public static String execute(List<String> command) {
StringBuffer inputStringBuffer = new StringBuffer();
StringBuffer errorStringBuffer = new StringBuffer();
try {
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
System.out.println("============inputStream============");
// 处理InputStream
Thread t1 = new Thread(() -> {
InputStream input = null;
InputStreamReader reader = null;
BufferedReader buffer = null;
try {
input = process.getInputStream();
reader = new InputStreamReader(input);
buffer = new BufferedReader(reader);
String inputLine = "";
while ((inputLine = buffer.readLine()) != null) {
System.out.println(inputLine);
inputStringBuffer.append(inputLine);
}
//退出循环后表示结束流
System.out.println("===》》退出循环后表示结束流");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (reader != null) {
reader.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t1.setName("deviceName");
t1.start();
System.out.println("============errorStream============");
// 处理ErrorStream
new Thread(() -> {
InputStream input = null;
InputStreamReader reader = null;
BufferedReader buffer = null;
try {
input = process.getErrorStream();
reader = new InputStreamReader(input);
buffer = new BufferedReader(reader);
String errorLine = "";
while ((errorLine = buffer.readLine()) != null) {
System.out.println(errorLine);
errorStringBuffer.append(errorLine);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (reader != null) {
reader.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
// 这里进程阻塞,将等待外部转换成功后,才往下执行
//process.waitFor();
t1.wait();
/**
* 只会存在一个输入流返回
*/
if (inputStringBuffer != null) {
return inputStringBuffer.toString();
}
if (errorStringBuffer != null) {
return errorStringBuffer.toString();
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
return null;
}
return null;
}
}
4.2、Main.java
public class Main {
public static void main(String[] args) {
String input = "D:/m3u8/demo.mp4";
String output = "D:/m3u8/hls/test.m3u8";
List<String> command = new ArrayList<>();
command.add("ffmpeg");
command.add("-i");
command.add(input);
command.add("-c:v");
command.add("copy");
command.add("-c:a");
command.add("copy");
command.add("-f");
command.add("ssegment");
command.add("-segment_format");
command.add("mpegts");
command.add("-segment_list");
command.add(output);
command.add("-segment_time");
command.add("10");
command.add("D:/m3u8/hls/test%05d.ts");
String result = ProcessUtil.execute(command);
}
}
4.3、验证测试
再执行完java程序以后,如果在D:/m3u8/hls
生成了ts和m3u8文件,则表示成功;
5、TS切片好处
比如:我们上传一个10MB的视频进行播放,如果不进行切片话,前端页面在播放时需要先下载完整的视频,这样会导致视频加载时间过长。如果使用ts切片后使用m3u8进行播放,在前端播放时页面会自动间隔一定时间下载ts文件进行播放。
下面视频展示,动态加载ts的过程:
更多推荐
所有评论(0)