๐Ÿ“Œโ€FFmpeg ๊ธฐ๋ฐ˜ HLS ๋ณ€ํ™˜ ๋ฐ ffprobe ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ์œ ํ‹ธ ๊ฐœ๋ฐœ๊ธฐโ€

๐Ÿ“… 2025๋…„ 4์›” 27์ผ / โœ๏ธ by ๋ฐ•์ฐฌํฌ


๐Ÿ”ง ์™œ ์ด๊ฑธ ๋งŒ๋“ค์—ˆ๋Š”๊ฐ€?

JSP ๊ธฐ๋ฐ˜ ๊ฐ•์˜ ํ”Œ๋žซํผ์—์„œ ๋“œ๋””์–ด โ€˜์ง„์งœ ์˜์ƒโ€™์„ ๋‹ค๋ฃจ๊ฒŒ ๋๋‹ค. ๋‹จ์ˆœ ํŒŒ์ผ ์—…๋กœ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ, ์ŠคํŠธ๋ฆฌ๋ฐ์— ์ ํ•ฉํ•œ ํฌ๋งท์œผ๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•˜๊ณ , ์ธ๋„ค์ผ๊ณผ ์˜์ƒ ๊ธธ์ด๊นŒ์ง€ ์ถ”์ถœํ•˜๋Š” ๋กœ์ง์ด ํ•„์š”ํ–ˆ๋‹ค.

๋ฌผ๋ก  ์ง์ ‘ ํ”Œ๋ ˆ์ด์–ด๋ฅผ ์ปจํŠธ๋กคํ•  ์ˆœ ์—†์œผ๋‹ˆ, .mp4๋ฅผ โ†’ .m3u8 + .ts๋กœ ๋ณ€ํ™˜ํ•ด์„œ HLS(HTTP Live Streaming) ๊ตฌ์กฐ๋กœ ์ „ํ™˜ํ•ด์•ผ ํ–ˆ๋‹ค. ์—ฌ๊ธฐ์— ffmpeg, ffprobe๋ฅผ ์—ฐ๋™ํ•œ ์ˆœ์ˆ˜ Java ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒŒ ์ด๋ฒˆ ๋ชฉํ‘œ์˜€๋‹ค.


๐ŸŽฏ ๊ตฌํ˜„ ๋ชฉํ‘œ

  1. ๊ฐ•์˜ ๋“ฑ๋ก ์‹œ .mp4 ํŒŒ์ผ์„ HLS ์ŠคํŠธ๋ฆฌ๋ฐ์šฉ .m3u8 ํฌ๋งท์œผ๋กœ ์ž๋™ ๋ณ€ํ™˜
  2. DB์— ์ €์žฅํ•  ์˜์ƒ ๊ธธ์ด (์ดˆ ๋‹จ์œ„)๋„ ์ž๋™ ์ถ”์ถœ
  3. ํ–ฅํ›„ AWS S3๋‚˜ CDN ํ™•์žฅ๊นŒ์ง€ ๊ณ ๋ คํ•ด ๊ฒฝ๋กœ ์„ค๊ณ„, ์˜ˆ์™ธ ์ฒ˜๋ฆฌ, ๋กœ๊น… ๊ตฌ์กฐ๋ฅผ ์ž˜ ์ •๋ฆฌํ•ด๋‘˜ ๊ฒƒ

๐Ÿงฉ ํ•ต์‹ฌ ๊ตฌํ˜„ ์š”์•ฝ

1. FFmpeg๋ฅผ ํ™œ์šฉํ•œ mp4 โ†’ HLS ๋ณ€ํ™˜

public static String convertToHLS(File inputFile, String uuid, String outputDir)
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)

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)

๋ฌธ์ œ:

ํ•ด๊ฒฐ:

String safePath = file.getAbsolutePath().replace("\\", "/");

๐ŸŒฑ ํ™•์žฅ ๊ณ ๋ ค์‚ฌํ•ญ

ํ™•์žฅ ์š”์†Œ ์„ค๊ณ„ ๋ฐฉํ–ฅ
โ˜๏ธ AWS S3 ์—…๋กœ๋“œ uploadDir๋ฅผ S3 ๋ฒ„ํ‚ท URL๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฐ”๋กœ ๋Œ€์‘ ๊ฐ€๋Šฅ
๐ŸŽž ์ธ๋„ค์ผ ์ž๋™ํ™” extractThumbnail() ํ•จ์ˆ˜๋กœ ํ”„๋ ˆ์ž„ ์บก์ฒ˜ ํ™•์žฅ ์˜ˆ์ •
๐Ÿ” ์ŠคํŠธ๋ฆฌ๋ฐ ๋ณด์•ˆ .m3u8, .ts ์š”์ฒญ์— JWT ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œํ•œ ๋กœ์ง ์ ์šฉ ๊ฐ€๋Šฅ
โš™๏ธ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํ˜„์žฌ๋Š” ๋™๊ธฐ ์ฒ˜๋ฆฌ โ†’ ์ถ”ํ›„ ExecutorService ๋˜๋Š” MQ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ๋กœ ์ „ํ™˜ ๊ฒ€ํ†  ํ•„์š”

๐Ÿ” ์‹ค์ œ ํ๋ฆ„

  1. LectureUploadController์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์„ ์ €์žฅ
  2. ์ €์žฅ๋œ File์„ convertToHLS()๋กœ ๋ณ€ํ™˜
  3. getVideoDurationInSeconds()๋กœ ๊ธธ์ด ์ถ”์ถœ
  4. DTO์— ์ •๋ณด ์„ธํŒ…:
videoPath = "/upload/hls/{uuid}.m3u8";
duration = 125;
thumbnailPath = "/upload/thumb/{uuid}.jpg";

๐Ÿš€ ์ตœ์ข… ์„ฑ๊ณผ


โœ๏ธ ํšŒ๊ณ  & ๋ฐฐ์šด ์ 

์ด๋ฒˆ ์ž‘์—…์„ ํ•˜๋ฉฐ ํฌ๊ฒŒ 3๊ฐ€์ง€๋ฅผ ๋А๊ผˆ๋‹ค:

  1. ffmpeg์™€ ffprobe๋Š” ๋‹จ์ˆœํ•œ CLI ํˆด์ด ์•„๋‹ˆ๋‹ค.
    • ๋ณต์žกํ•œ ๋ฐฑ์—”๋“œ ์‹œ์Šคํ…œ์—์„œ ์ •๋ฐ€ํ•˜๊ฒŒ ์ œ์–ด ๊ฐ€๋Šฅํ•œ ์˜์ƒ ์ฒ˜๋ฆฌ ๋„๊ตฌ๋‹ค.
  2. Java์—์„œ ์™ธ๋ถ€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋Š” OS ๊ฒฝ๋กœ ํ˜ธํ™˜์„ฑ์— ๋ฏผ๊ฐํ•ด์•ผ ํ•œ๋‹ค.
    • ํŠนํžˆ Windows์—์„œ \ โ†’ / ๋ณ€ํ™˜๊ณผ ๊ณต๋ฐฑ ์ด์Šˆ๋Š” ๋ฐ˜๋“œ์‹œ ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•จ.
  3. ์ˆœ์ˆ˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” ์„ค๊ณ„์˜ ๋ฏธ๋•์ด๋‹ค.
    • JSP๋‚˜ Spring๊ณผ ๊ฒฐํ•ฉ๋˜์ง€ ์•Š์€ ๋…๋ฆฝ ์œ ํ‹ธ๋กœ ๊ตฌํ˜„ํ•˜๋‹ˆ, ํ…Œ์ŠคํŠธ๋„ ํŽธํ•˜๊ณ  ํ™•์žฅ๋„ ์ž์œ ๋กญ๋‹ค.