本章使用两种简单方式使用Java统计HLS的m3u8清单中所有ts切片的视频持续时长。
HLS 协议简单介绍
HLS 的全称是 HTTP Live Streaming,中文常译为"HTTP 实时流媒体协议"。
它是由 苹果公司 提出并主导的基于 HTTP 的流媒体网络传输协议。如今,它已经成为互联网上最主流的流媒体传输协议之一,不仅限于苹果设备,几乎所有平台(包括 Android、智能电视、PC 浏览器等)都支持 HLS。
至于M3U8则是HLS协议的一部分,结构可以参考博主下面引用中的文章,这里不再赘述。
想要了解HLS协议和M3U8清单结构内容可以参考博主另外一篇文章:《【HLS】HLS 协议介绍和
m3u8清单文件结构及TS切片详解》
计算时长
1、正则表达式方式计算时长
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class M3U8DurationCalculator {
public static double calculateTotalDuration(String m3u8FilePath) throws IOException {
double totalDuration = 0.0;
Pattern durationPattern = Pattern.compile("#EXTINF:([\\d\\.]+),");
try (BufferedReader reader = new BufferedReader(new FileReader(m3u8FilePath))) {
String line;
while ((line = reader.readLine()) != null) {
Matcher matcher = durationPattern.matcher(line);
if (matcher.find()) {
totalDuration += Double.parseDouble(matcher.group(1));
}
}
}
return totalDuration;
}
public static void main(String[] args) {
try {
double duration = calculateTotalDuration("playlist.m3u8");
System.out.printf("总时长: %.2f 秒\n", duration);
System.out.printf("总时长: %.2f 分钟\n", duration / 60);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、逐行解析
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class M3U8Parser {
public static class DurationResult {
private double totalDuration;
private int segmentCount;
// 构造函数、getter、setter
public DurationResult(double totalDuration, int segmentCount) {
this.totalDuration = totalDuration;
this.segmentCount = segmentCount;
}
public double getTotalDuration() { return totalDuration; }
public int getSegmentCount() { return segmentCount; }
}
public static DurationResult calculateDuration(String m3u8FilePath) throws IOException {
double totalDuration = 0.0;
int segmentCount = 0;
try (BufferedReader reader = new BufferedReader(new FileReader(m3u8FilePath))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("#EXTINF:")) {
String durationStr = extractDuration(line);
if (durationStr != null) {
try {
double duration = Double.parseDouble(durationStr);
totalDuration += duration;
segmentCount++;
} catch (NumberFormatException e) {
System.err.println("无效的时长格式: " + durationStr);
}
}
}
}
}
return new DurationResult(totalDuration, segmentCount);
}
private static String extractDuration(String extinfLine) {
// 格式: #EXTINF:duration,[title]
String content = extinfLine.substring(8); // 移除 "#EXTINF:"
int commaIndex = content.indexOf(',');
if (commaIndex != -1) {
return content.substring(0, commaIndex);
}
return content;
}
public static void main(String[] args) {
try {
DurationResult result = calculateDuration("playlist.m3u8");
System.out.println("解析结果:");
System.out.println("TS片段数量: " + result.getSegmentCount());
System.out.printf("总时长: %.2f 秒\n", result.getTotalDuration());
System.out.printf("总时长: %.2f 分钟\n", result.getTotalDuration() / 60);
// 格式化输出为 HH:mm:ss
formatTime(result.getTotalDuration());
} catch (IOException e) {
e.printStackTrace();
}
}
private static void formatTime(double totalSeconds) {
int hours = (int) (totalSeconds / 3600);
int minutes = (int) ((totalSeconds % 3600) / 60);
int seconds = (int) (totalSeconds % 60);
System.out.printf("总时长: %02d:%02d:%02d\n", hours, minutes, seconds);
}
}