“djh”
3 天以前 d7471cff04678b91271bdc566bcbddf2f4ab04b7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.gkhy.exam.common.utils;
 
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import com.gkhy.exam.common.config.FilePathConfig;
import com.gkhy.exam.common.exception.ApiException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.bramp.ffmpeg.FFmpeg;
import net.bramp.ffmpeg.FFmpegExecutor;
import net.bramp.ffmpeg.FFprobe;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import net.bramp.ffmpeg.probe.FFmpegProbeResult;
import net.bramp.ffmpeg.probe.FFmpegStream;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
 
import javax.annotation.Resource;
import java.io.*;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
 
/**
 * @Author sirwsl
 * @Version 1.0
 */
@Slf4j
@Component
public class M3u8Utils {
 
    @Resource
    private FFmpeg ffmpeg;
 
    @Resource
    private FFprobe ffprobe;
 
    @Resource
    private FilePathConfig filePath;
 
 
    /**
     * 视频文件转 m3u8
     * 支持: .mp4 | .flv | .avi | .mov | .wmv | .wav
     * @param file 视频文件
     * @return 路径
     */
    public String mediaFileToM3u8(MultipartFile file){
        if (file.isEmpty()) {
            throw new RuntimeException("未发现文件");
        }
        log.info("开始解析视频");
        long start = System.currentTimeMillis();
        //临时目录创建
        String path = new File(System.getProperty("user.dir")).getAbsolutePath();
        String tempFilePath = path+ filePath.getTempPath();
        if (!FileUtil.exist(tempFilePath)) {
            FileUtil.mkdir(tempFilePath);
        }
        String originalFilename = file.getOriginalFilename();
        String mainName=UUID.fastUUID().toString().replaceAll("-","");
        String fileName = mainName + originalFilename.substring(originalFilename.lastIndexOf("."));
 
        String filePathName = tempFilePath + fileName;
        File dest = new File(filePathName);
        try {
            file.transferTo(dest);
        }catch (Exception e){
            log.error("视频转m3u8格式存在异常,异常原因e:{}",e.getMessage());
        }
        long end = System.currentTimeMillis();
        log.info("临时文件上传成功......耗时:{} ms", end - start);
        String m3u8FilePath = localFileToM3u8(filePathName,mainName);
        log.info("视频转换已完成 !");
        return m3u8FilePath;
    }
 
    /**
     * 本地媒体资源转换
     * @param filePathName : 文件路径
     * @return :
     */
    @SneakyThrows
    public synchronized String localFileToM3u8(String filePathName,String mainName) {
        long startTime = System.currentTimeMillis();
        final FFmpegProbeResult probe = ffprobe.probe(filePathName);
        final List<FFmpegStream> streams = probe.getStreams().stream().filter(fFmpegStream -> fFmpegStream.codec_type != null).collect(Collectors.toList());
        final Optional<FFmpegStream> audioStream = streams.stream().filter(fFmpegStream -> FFmpegStream.CodecType.AUDIO.equals(fFmpegStream.codec_type)).findFirst();
        final Optional<FFmpegStream> videoStream = streams.stream().filter(fFmpegStream -> FFmpegStream.CodecType.VIDEO.equals(fFmpegStream.codec_type)).findFirst();
 
        if (!audioStream.isPresent()) {
            log.error("未发现音频流");
            throw new ApiException("未发现音频流");
        }
        if (!videoStream.isPresent()) {
            log.error("未发现视频流");
            throw new ApiException("未发现视频流");
        }
        //m3u8文件 存储路径
        String path = new File(System.getProperty("user.dir")).getAbsolutePath();
        path=path+filePath.getBasePath()+mainName;
        if (!FileUtil.exist(path)) {
            FileUtil.del(path);
        }
        FileUtil.mkdir(path);
        String m3u8FileName = path+"/" + mainName + ".m3u8";
 
        //下面这一串参数别乱动,经过调优的,1G视频大概需要10秒左右,如果是大佬随意改
        //"-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_wrap", "0", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12"
        FFmpegBuilder builder = new FFmpegBuilder()
                .setInput(filePathName)
                .overrideOutputFiles(true)
                .addOutput(m3u8FileName)//输出文件
                .setFormat(probe.getFormat().format_name) //"mp4"
                .setAudioBitRate(audioStream.map(fFmpegStream -> fFmpegStream.bit_rate).orElse(0L))
                .setAudioChannels(1)
                .setAudioCodec("aac")        // using the aac codec
                .setAudioSampleRate(audioStream.get().sample_rate)
                .setAudioBitRate(audioStream.get().bit_rate)
                .setStrict(FFmpegBuilder.Strict.STRICT)
                .setFormat("hls")
                .setPreset("ultrafast")
               // .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_wrap", "0", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12")  #新版本hls_wrap参数不支持
               // .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_flags", "delete_segments", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12")
                .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_flags", "delete_segments", "-hls_time", "10", "-hls_list_size", "0", "-threads", "6")
                .done();
 
        FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
        // Run a one-pass encode
        executor.createJob(builder).run();
 
        File dest = new File(filePathName);
        if (dest.isFile() && dest.exists()) {
            dest.delete();
            System.gc();
            log.warn("临时文件 {}已删除", dest.getName());
        }
        long endTime = System.currentTimeMillis();
        log.info("文件:{} 转换完成!共耗时{} ms", dest.getName(), (endTime - startTime));
        return m3u8FileName;
    }
 
 
}