@@ -17,9 +17,49 @@ public class FFmpegService implements AudioProcessor {
1717 @ Value ("${media.ffprobe.path:ffprobe}" )
1818 private String ffprobePath ;
1919
20+ private String resolveExecutable (String configuredPath , String fallback ) {
21+ if (configuredPath == null || configuredPath .isBlank ()) {
22+ return resolveFallbackExecutable (fallback );
23+ }
24+
25+ File candidate = new File (configuredPath );
26+ if (isAbsolutePath (configuredPath ) && !candidate .exists ()) {
27+ log .warn ("[FFmpeg] ์ค์ ๋ ์คํ ํ์ผ์ ์ฐพ์ง ๋ชปํด PATH ๋ช
๋ น์ด๋ก ๋์ฒดํฉ๋๋ค: {}" , configuredPath );
28+ return resolveFallbackExecutable (fallback );
29+ }
30+
31+ return configuredPath ;
32+ }
33+
34+ private boolean isAbsolutePath (String path ) {
35+ return new File (path ).isAbsolute () || path .startsWith ("/" ) || path .startsWith ("\\ " );
36+ }
37+
38+ private String resolveFallbackExecutable (String fallback ) {
39+ if (File .separatorChar != '\\' ) {
40+ return fallback ;
41+ }
42+
43+ try {
44+ Process process = new ProcessBuilder ("where.exe" , fallback ).start ();
45+ try (BufferedReader reader = new BufferedReader (new InputStreamReader (process .getInputStream ()))) {
46+ String resolved = reader .readLine ();
47+ process .waitFor ();
48+ if (resolved != null && !resolved .isBlank ()) {
49+ return resolved .trim ();
50+ }
51+ }
52+ } catch (Exception e ) {
53+ log .debug ("[FFmpeg] ๋์ฒด ์คํ ํ์ผ ํ์ ์คํจ: {}, ์์ธ={}" , fallback , e .getMessage ());
54+ }
55+
56+ return fallback ;
57+ }
58+
2059 public Integer getAudioDurationMs (File audioFile ) throws Exception {
60+ String resolvedFfprobePath = resolveExecutable (ffprobePath , "ffprobe" );
2161 String [] cmd = {
22- ffprobePath , "-v" , "error" , "-show_entries" , "format=duration" ,
62+ resolvedFfprobePath , "-v" , "error" , "-show_entries" , "format=duration" ,
2363 "-of" , "default=noprint_wrappers=1:nokey=1" , audioFile .getAbsolutePath ()
2464 };
2565 Process process = new ProcessBuilder (cmd ).start ();
@@ -31,11 +71,12 @@ public Integer getAudioDurationMs(File audioFile) throws Exception {
3171 }
3272
3373 public File createSilenceFile (int durationMs ) throws Exception {
74+ String resolvedFfmpegPath = resolveExecutable (ffmpegPath , "ffmpeg" );
3475 File output = File .createTempFile ("silence_" , ".mp3" );
3576 double seconds = durationMs / 1000.0 ;
3677
3778 String [] cmd = {
38- ffmpegPath , "-y" , "-f" , "lavfi" , "-i" , "anullsrc=r=44100:cl=mono" ,
79+ resolvedFfmpegPath , "-y" , "-f" , "lavfi" , "-i" , "anullsrc=r=44100:cl=mono" ,
3980 "-t" , String .valueOf (seconds ), "-acodec" , "libmp3lame" , output .getAbsolutePath ()
4081 };
4182
@@ -44,25 +85,22 @@ public File createSilenceFile(int durationMs) throws Exception {
4485 }
4586
4687 public File mergeAudioFiles (List <File > audioFiles ) throws Exception {
47- if (audioFiles == null || audioFiles .isEmpty ()) throw new IllegalArgumentException ("๋ณํฉํ ํ์ผ์ด ์์ต๋๋ค." );
88+ if (audioFiles == null || audioFiles .isEmpty ()) throw new IllegalArgumentException ("merged audio file list is empty." );
89+ String resolvedFfmpegPath = resolveExecutable (ffmpegPath , "ffmpeg" );
4890
49- // FFmpeg์ ์ ๋ฌํ ๋ฆฌ์คํธ ํ์ผ ์์ฑ (UTF-8 ์ธ์ฝ๋ฉ)
5091 File listFile = File .createTempFile ("ffmpeg_list_" , ".txt" );
5192 try (BufferedWriter writer = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (listFile ), "UTF-8" ))) {
5293 for (File file : audioFiles ) {
53- // ์๋์ฐ์ 'C:\temp\file.mp3'๋ฅผ 'C:/temp/file.mp3'๋ก ๋ณํ
5494 String safePath = file .getAbsolutePath ().replace ("\\ " , "/" );
55- // FFmpeg ๋ฌธ๋ฒ์ ๋ง์ถฐ file '๊ฒฝ๋ก' ํํ๋ก ๊ธฐ๋ก
5695 writer .write ("file '" + safePath + "'" );
5796 writer .newLine ();
5897 }
5998 }
6099
61100 File output = File .createTempFile ("merged_full_" , ".mp3" );
62101
63- // ๋ณํฉ ๋ช
๋ น์ด ๊ตฌ์ฑ
64102 String [] cmd = {
65- ffmpegPath , "-y" , "-f" , "concat" , "-safe" , "0" ,
103+ resolvedFfmpegPath , "-y" , "-f" , "concat" , "-safe" , "0" ,
66104 "-i" , listFile .getAbsolutePath (),
67105 "-acodec" , "libmp3lame" , "-q:a" , "2" ,
68106 output .getAbsolutePath ()
@@ -74,24 +112,22 @@ public File mergeAudioFiles(List<File> audioFiles) throws Exception {
74112 }
75113
76114 private void executeCommand (String [] cmd ) throws Exception {
77- log .info ("[FFmpeg] ๋ช
๋ น์ด ์คํ: {}" , String .join (" " , cmd ));
115+ log .info ("[FFmpeg] ๋ช
๋ น ์คํ: {}" , String .join (" " , cmd ));
78116 ProcessBuilder pb = new ProcessBuilder (cmd );
79- pb .redirectErrorStream (true ); // ์๋ฌ์ ์ถ๋ ฅ์ ํฉ์นจ
117+ pb .redirectErrorStream (true );
80118 Process process = pb .start ();
81119
82- // ์ค์๊ฐ ๋ก๊ทธ ์ถ๋ ฅ (์๋ฌ ์์ธ ํ์
์ฉ)
83120 try (BufferedReader reader = new BufferedReader (new InputStreamReader (process .getInputStream (), "UTF-8" ))) {
84121 String line ;
85122 while ((line = reader .readLine ()) != null ) {
86- log .info ("[FFmpeg Output ] {}" , line ); // ๋ฌธ์ ๋ฐ์ ์ ๋ก๊ทธ์์ ๋ฐ๋ก ํ์ธ ๊ฐ๋ฅ
123+ log .info ("[FFmpeg ์ถ๋ ฅ ] {}" , line );
87124 }
88125 }
89126
90127 int exitCode = process .waitFor ();
91-
92128 if (exitCode != 0 ) {
93- log .error ("[FFmpeg] ํ๋ก์ธ์ค ์ค๋ฅ ๋ฐ์! Exit Code: {}" , exitCode );
129+ log .error ("[FFmpeg] ํ๋ก์ธ์ค ์ค๋ฅ ๋ฐ์. Exit Code: {}" , exitCode );
94130 throw new RuntimeException ("FFmpeg ํ๋ก์ธ์ค ์ค๋ฅ ๋ฐ์. Exit Code: " + exitCode );
95131 }
96132 }
97- }
133+ }
0 commit comments