【HLS】Java实现统计HLS的m3u8清单中所有ts切片的视频持续时长

本章使用两种简单方式使用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);
    }
}
相关推荐
紧跟先前的步伐2 小时前
Go AI Agent 实战 24|工具系统工程化收尾与阶段验收
人工智能·ai·golang·1024程序员节
学长毕设3 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
voipmaker3 小时前
GB28181 对接踩坑实录:注册不上、目录不全、流卡顿,一次说清(附 2022 版变更清单)
物联网·音视频·实时音视频·信息与通信·iot·gb28181·国标gb28181
吠品3 小时前
智谱开源 ZCode 之后,真正的考试才开始
单片机·嵌入式硬件·1024程序员节
zzu123zsw4 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
日日大王学编程4 小时前
#Feed 流项目复盘:Redis 时间线缓存与 Outbox 消息可靠性设计
golang·1024程序员节
2601_958352904 小时前
23.5×19mm 换掉一整条音频链?|A-68 集成了什么:ADC / DAC / 24.576MHz 时钟 / AEC / 波束降噪,主控仅需 6 根线
前端·音视频·ai降噪·回声消除·语音模块
2601_965448874 小时前
AI视频制作:做系列历史人物视频音色不搭,AI 音色克隆的方法实测
人工智能·音视频
码上观世界4 小时前
多余的一声「嗯」:Fun-CosyVoice3 zero_shot 开头伪影排查实录
音视频
源码集结号5 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统