Java转成m3u8,hls格式

news/2024/10/23 7:21:58/

Java转成m3u8,hls格式

需求分析

大致思路

  1. 循环文件夹下面所有文件
  2. 判断当前文件是否是视频文件,如果是视频文件先转为ts文件
    • 因为听别人说先转成ts之后再切片会快很多
  3. 转成ts文件,并为这些文件单独生成一个目录,如果目录不存在则新建一个目录
    • 执行转换命令—转成ts文件
  4. 执行完成后,再将ts文件转成m3u8文件

详细流程

  1. 判断当前文件夹是否是一个目录
  2. 如果是目录就遍历下面的文件包括所以的文件。
  3. 循环这些子文件,如果当前的文件是文件并且是视频文件(写一个判断函数,因为格式不同)
  4. 循环完成后将这些视频转成ts,并为这些文件生成单独目录,转成ts文件命名为output.ts
    • 需要为这些文件单独写一个执行命令函数(封装)
  5. 转成ts后再将这些视频转成m3u8

方法实现

判断是否为文件函数

在类中定义正则表达式,以方便修改。

函数中使用文件名后缀方式判断当前文件是否是符合要求的视频文件。

// 判断是否是视频文件正则
private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";/*** 判断是否符合想要的格式* mp4|avi|mkv* 通过文件后缀名哦安短** @param fileName 文件名称* @return 布尔值*/
private static boolean isVideoFile(String fileName) {return fileName.matches(isVideoFileRegex);
}

执行命令函数

因为在使用过程中需要使用两次命令行的操作,使用Java调起命令行,这是可以封装成单独的函数,使用时只需要将命令行传入即可。

命令行解释

创建了一个 ProcessBuilder 对象,并使用给定的命令字符串初始化它。ProcessBuilder 类用于创建操作系统进程,并提供一种从 Java 程序中启动外部命令的方式。

command.split(" ") 将输入的命令字符串分割成一个字符串数组,每个数组元素都是一个命令或参数。然后,这个数组被用来初始化 ProcessBuilder 对象,以便在后续步骤中启动一个新的进程来执行这些命令。

processBuilder.redirectErrorStream(true) 设置了当启动的进程产生错误流时,将错误流合并到标准输出流中。这意味着在执行命令时,任何由该命令生成的错误输出将会与标准输出一起被捕获,并可以通过 Java 程序进行处理。

ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
processBuilder.redirectErrorStream(true);
  1. processBuilder.start() 启动了之前创建的 ProcessBuilder 对象,执行之前设置的命令。
  2. BufferedReader 对象将其连接到外部进程的标准输出流,程序可以读取外部进程的输出。这里使用了 InputStreamReader 将字节流转换为字符流,然后通过 BufferedReader 逐行读取外部进程的输出。
  3. 在一个 while 循环中,程序持续读取外部进程的输出,直到输出结束。每读取一行输出,该行内容被打印到控制台上。
  4. 之后,通过调用 process.waitFor(),程序会等待外部进程执行完毕。这会导致当前的线程暂停,直到外部进程执行完成。
try {Process process = processBuilder.start();// 将ffmpeg执行内容输出在控制台中BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 等待转换完成process.waitFor();
} catch (IOException | InterruptedException e) {throw new RuntimeException(e);
}
完整代码
// 输入文件夹
private static String inputDirectory = "C:\\Users\\13199\\Downloads";
// 输出m3u8文件
private static String outputM3u8FileName = "index.m3u8";
// 判断是否是视频文件正则
private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";
// 选择切片时间
private static Integer HlsTime = 1;/*** 执行将文件转成m3u8 hls格式** @param command Ffmpeg 命令*/
private static void executeFfmpegCommand(String command) {ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));processBuilder.redirectErrorStream(true);try {Process process = processBuilder.start();// 将ffmpeg执行内容输出在控制台中BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 等待转换完成process.waitFor();} catch (IOException | InterruptedException e) {throw new RuntimeException(e);}
}

转成ts

  1. 根据输入文件路径 inputFilePath 确定了输出目录 outputDirectory。使用正则表达式 \\.[^.]+$ 来匹配文件路径中的文件扩展名,并将其替换为空字符串,从而得到输出目录的路径。
  2. 创建了一个 File 对象来代表输出目录,并检查该目录是否存在。如果输出目录不存在,用 mkdirs() 方法来创建输出目录。
  3. 构建了一个输出文件的路径 outputFilePath,这里假设输出文件的名称为 “output.ts”,并将其放在之前确定的输出目录中。
  4. FFmpeg 命令字符串 command,该命令使用输入文件路径来进行转换,具体命令包括了输入文件、编解码器选项、关键帧选项等参数。
  5. executeFfmpegCommand 将构建的 FFmpeg 命令字符串作为参数传递给该方法,以执行 FFmpeg 命令。
  6. 最后,代码调用了一个名为 convertToM3U8 的方法,该方法可能用于将生成的视频文件转换为 M3U8 格式
// 输入文件夹
private static String inputDirectory = "C:\\Users\\13199\\Downloads";
// 输出m3u8文件
private static String outputM3u8FileName = "index.m3u8";
// 判断是否是视频文件正则
private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";
// 选择切片时间
private static Integer HlsTime = 1;/*** 如果文件名 后缀符合将文件先转成ts类型文件* 有实验表名,先转成ts会快一点** @param inputFilePath 当前文件的路径*/
private static void convertToTs(String inputFilePath) {String outputDirectory = inputFilePath.replaceFirst("\\.[^.]+$", "");File directory = new File(outputDirectory);if (!directory.exists()) {directory.mkdirs();}String outputFilePath = outputDirectory + File.separator + "output.ts";String command = "ffmpeg -i " + inputFilePath + " -c copy -bsf:v h264_mp4toannexb -force_key_frames expr:gte(t,n_forced*" + HlsTime + ") -f mpegts " + outputFilePath;executeFfmpegCommand(command);convertToM3U8(outputDirectory);
}

转成m3u8

输出文件的路径 outputFilePath,这个路径是由输入目录 inputDirectory 和一个名为 outputM3u8FileName

之后将这段代码放到之前封装好的执行命令函数中executeFfmpegCommand

// 输入文件夹
private static String inputDirectory = "C:\\Users\\13199\\Downloads";
// 输出m3u8文件
private static String outputM3u8FileName = "index.m3u8";
// 判断是否是视频文件正则
private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";
// 选择切片时间
private static Integer HlsTime = 1;/*** 将文件转成hls类型,并且m3u8命名为index* 切片的ts以output.ts转换** @param inputDirectory 输入的文件夹*/
private static void convertToM3U8(String inputDirectory) {// 使用FFmpeg将ts文件转换成m3u8文件String outputFilePath = inputDirectory + File.separator + outputM3u8FileName;String command = "ffmpeg -i " + inputDirectory + File.separator + "output.ts" + " -c:v libx264 -c:a aac -force_key_frames expr:gte(t,n_forced*" + HlsTime + ") -hls_time " + HlsTime + " -hls_list_size 0 -f hls " + outputFilePath;executeFfmpegCommand(command);
}
自定义ts输出名

需要使用-hls_segment_filename参数。这个参数可以帮助你自定义切片文件的命名规则。

如果要将输入的ts文件以1,2,3这种方式命名可以使用这个方法inputDirectory + File.separator + "%d.ts"

String segmentFilename = inputDirectory + File.separator + "%d.ts"; // 定义切片文件名规则
String command = "ffmpeg -i " + inputDirectory + File.separator + "output.ts" + " -c:v libx264 -c:a aac -force_key_frames expr:gte(t,n_forced*1) -hls_time 1 -hls_list_size 0 -f hls -hls_segment_filename " + segmentFilename + " " + outputFilePath; // 定义切片文件名规则
executeFfmpegCommand(command);

主函数

  1. 创建了一个 File 对象来代表输入目录 inputDirectory
  2. 检查输入目录是否存在,并且确保它是一个目录而不是一个文件。
  3. 如果输入目录存在且是一个目录,获取了该目录下的所有文件列表,并遍历这些文件。
  4. 在遍历文件列表时,对每个文件进行检查,确保它是一个文件并且文件扩展名表明它是一个视频文件(使用了 isVideoFile 方法进行检查)。
  5. 对于每个找到的视频文件,代码创建了一个新的线程,并在该线程中调用了 convertToTs 方法,传递视频文件的绝对路径作为参数,以启动视频文件的转换过程。
// 输入文件夹
private static String inputDirectory = "C:\\Users\\13199\\Downloads";
// 输出m3u8文件
private static String outputM3u8FileName = "index.m3u8";
// 判断是否是视频文件正则
private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";
// 选择切片时间
private static Integer HlsTime = 1;/*** 定义目录所在位置* 循环遍历这个目录文件,找到子目录的视频文件* 判断当前的文件是否是视频文件* 如果是文件夹则继续遍历** @param args main program arguments*/
public static void main(String[] args) {File directory = new File(inputDirectory);if (directory.isDirectory()) {File[] files = directory.listFiles();assert files != null;for (File file : files) {if (file.isFile() && isVideoFile(file.getName())) {String inputFilePath = file.getAbsolutePath();new Thread(() -> convertToTs(inputFilePath)).start();}}}
}

常规变量

// 输入文件夹
private static String inputDirectory = "C:\\Users\\13199\\Downloads";
// 输出m3u8文件
private static String outputM3u8FileName = "index.m3u8";
// 判断是否是视频文件正则
private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";
// 选择切片时间
private static Integer HlsTime = 1;

完整代码

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;@Data
public class NewTest {// 输入文件夹private static String inputDirectory = "C:\\Users\\13199\\Downloads";// 输出m3u8文件private static String outputM3u8FileName = "index.m3u8";// 判断是否是视频文件正则private static String isVideoFileRegex = ".*\\.(mp4|avi|mkv)$";// 选择切片时间private static Integer HlsTime = 1;/*** 定义目录所在位置* 循环遍历这个目录文件,找到子目录的视频文件* 判断当前的文件是否是视频文件* 如果是文件夹则继续遍历** @param args main program arguments*/public static void main(String[] args) {File directory = new File(inputDirectory);if (directory.isDirectory()) {File[] files = directory.listFiles();assert files != null;for (File file : files) {if (file.isFile() && isVideoFile(file.getName())) {String inputFilePath = file.getAbsolutePath();new Thread(() -> convertToTs(inputFilePath)).start();}}}}/*** 如果文件名 后缀符合将文件先转成ts类型文件* 有实验表名,先转成ts会快一点** @param inputFilePath 当前文件的路径*/private static void convertToTs(String inputFilePath) {String outputDirectory = inputFilePath.replaceFirst("\\.[^.]+$", "");File directory = new File(outputDirectory);if (!directory.exists()) {directory.mkdirs();}String outputFilePath = outputDirectory + File.separator + "output.ts";String command = "ffmpeg -i " + inputFilePath + " -c copy -bsf:v h264_mp4toannexb -force_key_frames expr:gte(t,n_forced*" + HlsTime + ") -f mpegts " + outputFilePath;executeFfmpegCommand(command);convertToM3U8(outputDirectory);}/*** 将文件转成hls类型,并且m3u8命名为index* 切片的ts以output.ts转换** @param inputDirectory 输入的文件夹*/private static void convertToM3U8(String inputDirectory) {// 使用FFmpeg将ts文件转换成m3u8文件String outputFilePath = inputDirectory + File.separator + outputM3u8FileName;String command = "ffmpeg -i " + inputDirectory + File.separator + "output.ts" + " -c:v libx264 -c:a aac -force_key_frames expr:gte(t,n_forced*" + HlsTime + ") -hls_time " + HlsTime + " -hls_list_size 0 -f hls " + outputFilePath;executeFfmpegCommand(command);}/*** 执行将文件转成m3u8 hls格式** @param command Ffmpeg 命令*/private static void executeFfmpegCommand(String command) {ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));processBuilder.redirectErrorStream(true);try {Process process = processBuilder.start();// 将ffmpeg执行内容输出在控制台中BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 等待转换完成process.waitFor();} catch (IOException | InterruptedException e) {throw new RuntimeException(e);}}/*** 判断是否符合想要的格式* mp4|avi|mkv* 通过文件后缀名哦安短** @param fileName 文件名称* @return 布尔值*/private static boolean isVideoFile(String fileName) {return fileName.matches(isVideoFileRegex);}
}

http://www.ppmy.cn/news/1332968.html

相关文章

Linux 挂载读取、卸载 ntfs格式硬盘

windows常用的ntfs硬盘分区格式,在linux通常不能直接读取,不过挂载也是非常容易 一、挂载ntfs分区 1.安装 apt-get install ntfs-3g2.查看现在接上的硬盘 fdisk -l可以找到类似如下的,会显示microsoft basic data 3.创建挂载的目录 创…

Spring5学习笔记

Spring5 框架概述IOC(Inversion Of Control)IOC基本过程:IOC接口(BeanFactory)IOC接口实现类IOC操作Bean管理一、什么是Bean管理?二、什么是DI?三、Bean管理的两种实现方式1.基于XML配置文件方式实现基于XML方式创建对象基于XML方式注入属性常规属性注入特殊属性值的注入…

家用洗地机什么品牌比较好?洗地机口碑榜

近年来,家庭清洁产品备受瞩目,人们寻求省力的清洁解决方案,在清洁产品上面的购买真的是煞费苦心。各大厂商们也不负众望,推出了洗地机,这一产品在市场上受到了广泛欢迎。洗地机作为新时代的产物,集吸尘、拖…

基于OpenLayers实战地理信息系统教程

第1讲-概述.rar 第2讲-庞杂的GIS体系概览 01.rar 第3讲-项目快速实战(-).rar 第4讲-项目快速实战(二) 01.rar 第5讲-项目快速实战(三).rar 第6讲-项目快速实战(四).rar 第7讲-项目快速实战(五).rar 第8讲-项目快速实战(六).rar 第9讲-项目快速实战(七).rar 第10讲-项目…

go-zero 统一返回

1、整体目录结构 1、全局处理主入口 package manageimport ("net/http""github.com/zeromicro/go-zero/rest/httpx" )type Body struct {Code int json:"code"Message string json:"message"Result interface{} jso…

研究性学习:社会关注的热点问题研究

1. 课题名称 社会关注的热点问题研究 2. 起止时间 起始时间:2024年1月25日 结束时间:2024年2月20日 3. 项目组成员 组长:刘明组员:赵丽、陈鑫校内指导教师:王老师校外指导教师:社会工作者李教授4. 组员分工情况 搜集整理资料: 刘明:负责搜集西安市健康上网问题的资…

Git笔记:常用使用Git命令+使用Git关联本地仓库和远程仓库操作步骤

Git 分布式版本控制系统 常用Git命令 创建一个管理代码的文件目录右键Git Bath打开完成配置信息,输入个人用户名、邮件信息 git config --global user.name 用户名 git config --global user.email 邮箱地址初始化仓库 git init: 初始化仓库 文件目录里会出现一个…

2.数据结构 顺序表(自留笔记)

文章目录 一.静态顺序表:长度固定二.动态顺序表1.下面证明原地扩容和异地扩容代码如下:2.下面是写一段Print,打印数字看看:3.头插4.尾删5.头删6.越界一定会报错吗7.下标插入8.下标删除9.查找数字10.应用:利用顺序表写一…