hls.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://vjs.zencdn.net/7.11.4/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/7.11.4/video.min.js"></script>
</head>
<body>
<video id="video" class="video-js" controls="controls" width="400" autoplay="autoplay"></video>
<script th:inline="javascript">
/*<![CDATA[*/
var videoUrl = /*[[ ${videoUrl} ]]*/;
/*]]*/
videojs.Vhs.xhr.beforeRequest = function (options) {
options.headers = {
Authorization: 'Bearer ' + "userToken"
};
return options;
};
var $vplay = videojs("video");
$vplay.src({
src : videoUrl,
type: "application/x-mpegurl"
});
</script>
</body>
</html>
java
@GetMapping("/hls-make/{fileName}")
@ResponseBody
public void videoHlsMake(@PathVariable String fileName, Model model) throws IOException {
log.debug("************** class = {}, function = {}", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName());
final String FFMPEG_PATH = ffmpegProperties.getPath();
final String FFMPEG = ffmpegProperties.getFfmpeg();
final String FFPROBE = ffmpegProperties.getFfprobe();
final String FILEPATH = UPLOAD_DIR + "/" + fileName;
final String ONLY_FILENAME = fileName.substring(0, fileName.lastIndexOf("."));
final String TS_PATH = UPLOAD_DIR + "/" + ONLY_FILENAME;
File tsPath = new File(TS_PATH);
if(!tsPath.exists()) {
tsPath.mkdir();
}
FFmpeg ffmpeg = new FFmpeg(FFMPEG_PATH + "/" + FFMPEG);
FFprobe ffprobe = new FFprobe(FFMPEG_PATH + "/" + FFPROBE);
FFmpegProbeResult probeResult = ffprobe.probe(FILEPATH);
log.debug("========== VideoFileUtils.getMediaInfo() ==========");
log.debug("filename : {}", probeResult.getFormat().filename);
log.debug("format_name : {}", probeResult.getFormat().format_name);
log.debug("format_long_name : {}", probeResult.getFormat().format_long_name);
log.debug("tags : {}", probeResult.getFormat().tags.toString());
log.debug("duration : {} second", probeResult.getFormat().duration);
log.debug("size : {} byte", probeResult.getFormat().size);
log.debug("width : {} px", probeResult.getStreams().get(0).width);
log.debug("height : {} px", probeResult.getStreams().get(0).height);
log.debug("===================================================");
// TS 파일 생성
FFmpegBuilder builder = new FFmpegBuilder()
//.overrideOutputFiles(true) // 오버라이드 여부
.setInput(FILEPATH) // 동영상파일
.addOutput(TS_PATH + "/" + ONLY_FILENAME + ".m3u8") // 썸네일 경로
.addExtraArgs("-profile:v", "baseline") //
.addExtraArgs("-level", "3.0") //
.addExtraArgs("-start_number", "0") //
.addExtraArgs("-hls_time", "10") //
.addExtraArgs("-hls_list_size", "0") //
.addExtraArgs("-f", "hls") //
.done();
FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
executor.createJob(builder).run();
// 이미지 파일 생성
FFmpegBuilder builderThumbNail = new FFmpegBuilder()
.overrideOutputFiles(true) // 오버라이드 여부
.setInput(FILEPATH) // 동영상파일
.addExtraArgs("-ss", "00:00:03") // 썸네일 추출 싲가점
.addOutput(UPLOAD_DIR + "/" + ONLY_FILENAME + ".png") // 썸네일 경로
.setFrames(1) // 프레임 수
.done();
FFmpegExecutor executorThumbNail = new FFmpegExecutor(ffmpeg, ffprobe);
executorThumbNail.createJob(builderThumbNail).run();
model.addAttribute("result", "OK");
}
@GetMapping("/hls")
public String videoHls(Model model) {
log.debug("************** class = {}, function = {}", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName());
model.addAttribute("videoUrl", "/video/hls/video/video.m3u8");
return TEMPLATE_DIR + "hls";
}
@GetMapping("/hls/{fileName}/{fileName}.m3u8")
public ResponseEntity<Resource> videoHlsM3U8(@PathVariable String fileName) {
log.debug("************** class = {}, function = {}", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName());
String fileFullPath = UPLOAD_DIR + fileName + "/" + fileName + ".m3u8";
Resource resource = new FileSystemResource(fileFullPath);
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName + ".m3u8");
headers.setContentType(MediaType.parseMediaType("application/vnd.apple.mpegurl"));
return new ResponseEntity<Resource>(resource, headers, HttpStatus.OK);
}
@GetMapping("/hls/{fileName}/{tsName}.ts")
public ResponseEntity<Resource> videoHlsTs(@PathVariable String fileName, @PathVariable String tsName) {
log.debug("************** class = {}, function = {}", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName());
String fileFullPath = UPLOAD_DIR + fileName + "/" + tsName + ".ts";
Resource resource = new FileSystemResource(fileFullPath);
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + tsName + ".ts");
headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_OCTET_STREAM_VALUE));
return new ResponseEntity<Resource>(resource, headers, HttpStatus.OK);
}
pom.xml
<!-- ffmpeg 동영상 인코더 연결 라이브러리 -->
<dependency>
<groupId>net.bramp.ffmpeg</groupId>
<artifactId>ffmpeg</artifactId>
<version>0.6.2</version>
</dependency>
https://www.ffmpeg.org/download.html
'Java' 카테고리의 다른 글
윈도우 포트 사용중인 프로세스 확인 및 프로세스 죽이기 (0) | 2023.04.24 |
---|---|
ByteArrayInputStream 파일로 저장 (0) | 2021.09.23 |
이클립스 encoding UTF-8로 전체 변경하기 (0) | 2021.09.06 |
LocalDateTime format, pattern으로 변환하여 표현하기 (0) | 2021.09.02 |
자바, 스프링, 스프링 부트에서 동영상 스트리밍 서비스 (1) | 2021.06.25 |