๐โFFmpeg ๊ธฐ๋ฐ HLS ๋ณํ ๋ฐ ffprobe ๋ฉํ๋ฐ์ดํฐ ํ์ฑ ์ ํธ ๊ฐ๋ฐ๊ธฐโ
๐ 2025๋ 4์ 27์ผ / โ๏ธ by ๋ฐ์ฐฌํฌ
๐ง ์ ์ด๊ฑธ ๋ง๋ค์๋๊ฐ?
JSP ๊ธฐ๋ฐ ๊ฐ์ ํ๋ซํผ์์ ๋๋์ด โ์ง์ง ์์โ์ ๋ค๋ฃจ๊ฒ ๋๋ค. ๋จ์ ํ์ผ ์ ๋ก๋๊ฐ ์๋๋ผ, ์คํธ๋ฆฌ๋ฐ์ ์ ํฉํ ํฌ๋งท์ผ๋ก ์๋ ๋ณํํ๊ณ , ์ธ๋ค์ผ๊ณผ ์์ ๊ธธ์ด๊น์ง ์ถ์ถํ๋ ๋ก์ง์ด ํ์ํ๋ค.
๋ฌผ๋ก ์ง์ ํ๋ ์ด์ด๋ฅผ ์ปจํธ๋กคํ ์ ์์ผ๋, .mp4
๋ฅผ โ .m3u8 + .ts
๋ก ๋ณํํด์ HLS(HTTP Live Streaming) ๊ตฌ์กฐ๋ก ์ ํํด์ผ ํ๋ค. ์ฌ๊ธฐ์ ffmpeg
, ffprobe
๋ฅผ ์ฐ๋ํ ์์ Java ์ ํธ๋ฆฌํฐ๋ฅผ ๋ง๋๋ ๊ฒ ์ด๋ฒ ๋ชฉํ์๋ค.
๐ฏ ๊ตฌํ ๋ชฉํ
- ๊ฐ์ ๋ฑ๋ก ์
.mp4
ํ์ผ์ HLS ์คํธ๋ฆฌ๋ฐ์ฉ.m3u8
ํฌ๋งท์ผ๋ก ์๋ ๋ณํ - DB์ ์ ์ฅํ ์์ ๊ธธ์ด (์ด ๋จ์)๋ ์๋ ์ถ์ถ
- ํฅํ AWS S3๋ CDN ํ์ฅ๊น์ง ๊ณ ๋ คํด ๊ฒฝ๋ก ์ค๊ณ, ์์ธ ์ฒ๋ฆฌ, ๋ก๊น ๊ตฌ์กฐ๋ฅผ ์ ์ ๋ฆฌํด๋ ๊ฒ
๐งฉ ํต์ฌ ๊ตฌํ ์์ฝ
1. FFmpeg๋ฅผ ํ์ฉํ mp4 โ HLS ๋ณํ
public static String convertToHLS(File inputFile, String uuid, String outputDir)
ffmpeg.exe
๋ฅผ ProcessBuilder๋ก ์ง์ ์คํhls_time 10
: 10์ด ๋จ์๋ก ts ์ธ๊ทธ๋จผํธ ๋ถํ- ์คํ ํ
/upload/hls/{uuid}.m3u8
๊ฒฝ๋ก ๋ฐํ (JSP์์ ์ ๊ทผ์ฉ)
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -hls_time 10 -f hls output.m3u8
๐ ์ฃผ์: FFmpeg๋ ๊ณต๋ฐฑ ํฌํจ๋ ๊ฒฝ๋ก์ ๋ฏผ๊ฐํ๋ค. โ .replace("\\", "/")
ํ์ ์ ์ฉ
2. ์์ ๊ธธ์ด ์ถ์ถ (ffprobe)
public static int getVideoDurationInSeconds(File videoFile)
ffprobe
๋ฅผ ํตํด ๋ณ๋ ๋์ฝ๋ฉ ์์ด ๋ฉํ๋ฐ์ดํฐ๋ง ๋ถ์- ์ถ๋ ฅ:
"122.45"
โDouble.parseDouble()
โMath.round()
โint
๋ณํ
ffmpeg์ ๋นํด ํจ์ฌ ๋น ๋ฅด๊ณ ๊ฐ๋ณ๋ค. ์ค์๊ฐ ์ฒ๋ฆฌ๋ฅผ ์ผ๋์ ๋๋ฉด ffprobe
๋ ํ์ ํด์ด๋ค.
๐ฆ ๊ตฌ์กฐ ์ค๊ณ ํฌ์ธํธ
ํญ๋ชฉ | ๊ณ ๋ ค ์ฌํญ |
---|---|
๐ฏ ์์ ์ ํธํ | FFmpegUtil ์ JSP/์ปจํธ๋กค๋ฌ์ ์ ํ ์์กดํ์ง ์๋๋ก ์ค๊ณ |
๐งฑ ์์ธ ํ๋ฆ | IOException , InterruptedException , NumberFormatException ๋ชจ๋ ๋ก๊น
์ฒ๋ฆฌ |
๐งฉ ์คํ ๊ฒฝ๋ก ๋ถ๋ฆฌ | ffmpeg.exe , ffprobe.exe ๊ฒฝ๋ก๋ ์์๋ก ๊ด๋ฆฌํด OS ์ด์์ฑ ํ๋ณด |
๐ ๋ก๊น ๊ตฌ์กฐ | java.util.logging.Logger ๊ธฐ๋ฐ stdout/stderr ๋ก๊น
โ ์ถํ log4j, slf4j ๋์ ๊ฐ๋ฅ |
๐ ๊ฒฝ๋ก ์ถ์ํ | ์ค์ ์ ์ฅ๊ฒฝ๋ก(C:/lecture_uploads/hls/... ) โ JSP ์ ๊ทผ๊ฒฝ๋ก(/upload/hls/... ) ๋ถ๋ฆฌ |
๐ง ํ๋ก์ธ์ค ์ ์ด | ProcessBuilder ๋ก ์คํ + exitCode ์ฒดํฌ๋ก ์์ ์ฑ ํ๋ณด |
๐งจ ๋๋ฒ๊น
์ด์: ffmpeg ์คํจ (exitCode=1
)
๋ฌธ์ :
- ๋ณํ์ด ์ ๋๊ณ
exitCode=1
๋ง ๋ฆฌํด๋จ - ๋ก๊ทธ๋ฅผ ๋ณด๋ ๊ฒฝ๋ก ๋ฌธ์ ์์ (๊ณต๋ฐฑ/์ญ์ฌ๋์ ์ด์)
ํด๊ฒฐ:
String safePath = file.getAbsolutePath().replace("\\", "/");
- Windows ๊ฒฝ๋ก ๋ฌธ์ ์ฐํ
ProcessBuilder
์ธ์๋ ๊ณต๋ฐฑ ํฌํจ ๊ฒฝ๋ก์ผ ๊ฒฝ์ฐ ๋ฐ๋์ ๋ถ๋ฆฌํ๊ฑฐ๋ ์ ์ฒด ๋ฌธ์์ด๋ก ์ฒ๋ฆฌํด์ผ ์์
๐ฑ ํ์ฅ ๊ณ ๋ ค์ฌํญ
ํ์ฅ ์์ | ์ค๊ณ ๋ฐฉํฅ |
---|---|
โ๏ธ AWS S3 ์ ๋ก๋ | uploadDir ๋ฅผ S3 ๋ฒํท URL๋ก ๋ณ๊ฒฝํ๋ฉด ๋ฐ๋ก ๋์ ๊ฐ๋ฅ |
๐ ์ธ๋ค์ผ ์๋ํ | extractThumbnail() ํจ์๋ก ํ๋ ์ ์บก์ฒ ํ์ฅ ์์ |
๐ ์คํธ๋ฆฌ๋ฐ ๋ณด์ | .m3u8 , .ts ์์ฒญ์ JWT ๊ธฐ๋ฐ ์ ๊ทผ ์ ํ ๋ก์ง ์ ์ฉ ๊ฐ๋ฅ |
โ๏ธ ๋น๋๊ธฐ ์ฒ๋ฆฌ | ํ์ฌ๋ ๋๊ธฐ ์ฒ๋ฆฌ โ ์ถํ ExecutorService ๋๋ MQ ๊ธฐ๋ฐ ๋น๋๊ธฐ๋ก ์ ํ ๊ฒํ ํ์ |
๐ ์ค์ ํ๋ฆ
LectureUploadController
์์ ์ฌ์ฉ์๊ฐ ์ ๋ก๋ํ ํ์ผ์ ์ ์ฅ- ์ ์ฅ๋
File
์convertToHLS()
๋ก ๋ณํ getVideoDurationInSeconds()
๋ก ๊ธธ์ด ์ถ์ถ- DTO์ ์ ๋ณด ์ธํ :
videoPath = "/upload/hls/{uuid}.m3u8";
duration = 125;
thumbnailPath = "/upload/thumb/{uuid}.jpg";
๐ ์ต์ข ์ฑ๊ณผ
<video src="/upload/hls/xxx.m3u8">
ํํ๋ก ์คํธ๋ฆฌ๋ฐ ์๋ฒฝ ๊ตฌํ- JSP์์๋ ๋จ์ ๊ฒฝ๋ก๋ง ์๋ฉด ๋๊ณ , ์ค์ ํ์ผ ๊ตฌ์กฐ๋ ์ธ๋ถ์ ์จ๊ฒจ์ง
- ์ ์ฒด ๋ก์ง์ ์์ Java ์ ํธ๋ฆฌํฐ๋ก ๊ตฌ์ฑ๋์ด ์ฌ์ฌ์ฉ์ฑ๊ณผ ์ด์์ฑ์ด ๋์
โ๏ธ ํ๊ณ & ๋ฐฐ์ด ์
์ด๋ฒ ์์ ์ ํ๋ฉฐ ํฌ๊ฒ 3๊ฐ์ง๋ฅผ ๋๊ผ๋ค:
- ffmpeg์ ffprobe๋ ๋จ์ํ CLI ํด์ด ์๋๋ค.
- ๋ณต์กํ ๋ฐฑ์๋ ์์คํ ์์ ์ ๋ฐํ๊ฒ ์ ์ด ๊ฐ๋ฅํ ์์ ์ฒ๋ฆฌ ๋๊ตฌ๋ค.
- Java์์ ์ธ๋ถ ํ๋ก์ธ์ค๋ฅผ ์คํํ ๋๋ OS ๊ฒฝ๋ก ํธํ์ฑ์ ๋ฏผ๊ฐํด์ผ ํ๋ค.
- ํนํ Windows์์
\
โ/
๋ณํ๊ณผ ๊ณต๋ฐฑ ์ด์๋ ๋ฐ๋์ ์ ์ฒ๋ฆฌํด์ผ ํจ.
- ํนํ Windows์์
- ์์ ์ ํธ๋ฆฌํฐ๋ ์ค๊ณ์ ๋ฏธ๋์ด๋ค.
- JSP๋ Spring๊ณผ ๊ฒฐํฉ๋์ง ์์ ๋ ๋ฆฝ ์ ํธ๋ก ๊ตฌํํ๋, ํ ์คํธ๋ ํธํ๊ณ ํ์ฅ๋ ์์ ๋กญ๋ค.