11using Microsoft . WindowsAPICodePack . Dialogs ;
22using OpenCvSharp ;
3+ using Shell32 ;
34using System . Diagnostics ;
45using System . IO ;
6+ using System . Text ;
7+ using System . Text . RegularExpressions ;
58using System . Windows ;
69using Path = System . IO . Path ;
710using Rect = OpenCvSharp . Rect ;
@@ -70,6 +73,10 @@ private void All_do_Click(object sender, RoutedEventArgs e)
7073 // 输出文件夹
7174 if ( ! Directory . Exists ( "./Res" ) )
7275 Directory . CreateDirectory ( "./Res" ) ;
76+ if ( files_dir . Text == null || files_dir . Text == "" )
77+ {
78+ return ;
79+ }
7380 string [ ] filedirs ;
7481 if ( is_all . IsChecked == true )
7582 filedirs = Directory . GetFiles ( files_dir . Text , "*" , SearchOption . AllDirectories ) ;
@@ -84,7 +91,7 @@ private void All_do_Click(object sender, RoutedEventArgs e)
8491 Dispatcher . Invoke ( ( ) => setting . UpdateSetting ( ) ) ;
8592 setting . SaveSetting ( ) ;
8693
87- Task . Run ( ( ) =>
94+ _ = Task . Run ( ( ) =>
8895 {
8996 bool btn_has_start = true , btn_has_end = false ;
9097 Dispatcher . Invoke ( ( ) => btn_has_start = ( bool ) has_start . IsChecked ) ;
@@ -135,27 +142,110 @@ private void All_do_Click(object sender, RoutedEventArgs e)
135142 Dispatcher . Invoke ( ( ) => progressBar . Value = 100 ) ;
136143 }
137144 Dispatcher . Invoke ( ( ) => progressBar . IsIndeterminate = true ) ;
138- string arg = "" ;
139- bool gpu_check = true , cpu_check = false ;
140- string fps_text = "60" , file_dir_text = "" ;
145+ string fps_text = "60" , file_dir_text = "" , bgm_dir_text = "" ;
141146 Dispatcher . Invoke ( ( ) => fps_text = fps . Text ) ;
142147 Dispatcher . Invoke ( ( ) => file_dir_text = files_dir . Text ) ;
148+ Dispatcher . Invoke ( ( ) => bgm_dir_text = bgm_dir . Text ) ;
143149 string ffmpeg_path = System . Environment . CurrentDirectory + @"\ffmpeg\ffmpeg.exe" ;
144- ProcessStartInfo info = new ProcessStartInfo ( ffmpeg_path , $ " -y -r { fps_text } -i { System . Environment . CurrentDirectory } \\ Cache\\ %d.jpg { System . Environment . CurrentDirectory } \\ Cache\\ output.mp4") ;
145- info . UseShellExecute = true ;
146- info . RedirectStandardInput = false ;
147- info . RedirectStandardOutput = false ;
148- info . RedirectStandardError = false ;
149- info . CreateNoWindow = true ;
150+ string cache_dir = "Cache" ;
151+
152+ //合成MP4(无声)
153+ ProcessStartInfo info = new ProcessStartInfo ( ffmpeg_path , $ " -y -r { fps_text } -i { cache_dir } \\ %d.jpg { cache_dir } \\ output.mp4")
154+ {
155+ UseShellExecute = true ,
156+ RedirectStandardInput = false ,
157+ RedirectStandardOutput = false ,
158+ RedirectStandardError = false ,
159+ CreateNoWindow = true
160+ } ;
150161 Process AppProcess = System . Diagnostics . Process . Start ( info ) ;
151162 AppProcess . WaitForExit ( ) ;
152- var files_dir_list = file_dir_text . Split ( "\\ " ) ;
153- if ( File . Exists ( $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") )
163+
164+ // 处理MP3 生成和MP4同样长的MP3文件
165+ if ( bgm_dir_text != "" || bgm_dir_text != null )
154166 {
155- File . Delete ( $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") ;
167+ int mp4sec = ReadMp4During ( System . Environment . CurrentDirectory + "\\ Cache\\ output.mp4" ) ;
168+ int mp3sec = ReadMp3During ( bgm_dir_text ) ;
169+ FileInfo file = new FileInfo ( bgm_dir_text ) ;
170+ if ( file . Exists ) //可以判断源文件是否存在
171+ {
172+ // 这里是true的话覆盖
173+ file . CopyTo ( $ "{ System . Environment . CurrentDirectory } \\ Cache\\ 1.mp3", true ) ;
174+ }
175+ string concat_str = $ "concat:{ cache_dir } \\ 1.mp3";
176+ if ( mp4sec > mp3sec )
177+ {
178+ for ( i = 0 ; i < Math . Ceiling ( ( double ) mp4sec / ( double ) mp3sec ) ; i ++ )
179+ {
180+ concat_str += $ "|{ cache_dir } \\ 1.mp3";
181+ }
182+ ProcessStartInfo info2 = new ProcessStartInfo ( ffmpeg_path , $ " -i \" { concat_str } \" -y -acodec copy { cache_dir } \\ b.mp3")
183+ {
184+ UseShellExecute = true ,
185+ RedirectStandardInput = false ,
186+ RedirectStandardOutput = false ,
187+ RedirectStandardError = false ,
188+ CreateNoWindow = true
189+ } ;
190+ Process AppProcess2 = System . Diagnostics . Process . Start ( info2 ) ;
191+ AppProcess2 . WaitForExit ( ) ;
192+
193+ ProcessStartInfo info3 = new ProcessStartInfo ( ffmpeg_path , $ " -i { cache_dir } \\ b.mp3 -t { mp4sec } -y -acodec copy { cache_dir } \\ c.mp3")
194+ {
195+ UseShellExecute = true ,
196+ RedirectStandardInput = false ,
197+ RedirectStandardOutput = false ,
198+ RedirectStandardError = false ,
199+ CreateNoWindow = true
200+ } ;
201+ Process AppProcess3 = System . Diagnostics . Process . Start ( info3 ) ;
202+ AppProcess3 . WaitForExit ( ) ;
203+ }
204+ else if ( mp4sec < mp3sec )
205+ {
206+ ProcessStartInfo info2 = new ProcessStartInfo ( ffmpeg_path , $ " -i { cache_dir } \\ 1.mp3 -y -t { mp4sec } -acodec copy { cache_dir } \\ c.mp3")
207+ {
208+ UseShellExecute = true ,
209+ RedirectStandardInput = false ,
210+ RedirectStandardOutput = false ,
211+ RedirectStandardError = false ,
212+ CreateNoWindow = true
213+ } ;
214+ Process AppProcess2 = System . Diagnostics . Process . Start ( info2 ) ;
215+ AppProcess2 . WaitForExit ( ) ;
216+ }
217+
218+ ProcessStartInfo info4 = new ProcessStartInfo ( ffmpeg_path , $ " -i { cache_dir } \\ c.mp3 -i { cache_dir } \\ output.mp4 -y { cache_dir } \\ d.mp4")
219+ {
220+ UseShellExecute = true ,
221+ RedirectStandardInput = false ,
222+ RedirectStandardOutput = false ,
223+ RedirectStandardError = false ,
224+ CreateNoWindow = true
225+ } ;
226+ Process AppProcess4 = System . Diagnostics . Process . Start ( info4 ) ;
227+ AppProcess4 . WaitForExit ( ) ;
228+
229+ //导出带BGM的mp4
230+ var files_dir_list = file_dir_text . Split ( "\\ " ) ;
231+ if ( File . Exists ( $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") )
232+ {
233+ File . Delete ( $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") ;
234+ }
235+ File . Move ( "./Cache/d.mp4" , $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") ;
236+ }
237+ else
238+ {
239+ // 导出无声MP4
240+ var files_dir_list = file_dir_text . Split ( "\\ " ) ;
241+ if ( File . Exists ( $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") )
242+ {
243+ File . Delete ( $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") ;
244+ }
245+ File . Move ( "./Cache/output.mp4" , $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") ;
156246 }
157- File . Move ( "./Cache/output.mp4" , $ "Res/{ files_dir_list [ files_dir_list . Length - 1 ] } .mp4") ;
158247 Dispatcher . Invoke ( ( ) => progressBar . IsIndeterminate = false ) ;
248+ //清理缓存
159249 if ( Directory . Exists ( "./Cache" ) )
160250 Directory . Delete ( "./Cache" , true ) ;
161251 } ) ;
@@ -225,7 +315,7 @@ private void LongImg2frame(Mat mat, ref int now_frame)
225315 int sec = ( dst . Height - canvas_height ) / velocity ;
226316 if ( sec <= _sec )
227317 sec = _sec ;
228- else if ( sec > 30 ) sec = 30 ;
318+ else if ( sec > 60 ) sec = 60 ;
229319 int ratio = ( dst . Height - canvas_height ) / ( sec * f ) + 1 ;
230320 int end_frame = 0 ;
231321 //长图头停顿
@@ -278,5 +368,63 @@ private void Img2frame(Mat mat, ref int now_frame)
278368
279369 }
280370
371+ private void open_bgm_Click ( object sender , RoutedEventArgs e )
372+ {
373+ System . Windows . Forms . OpenFileDialog openFileDialog = new System . Windows . Forms . OpenFileDialog ( ) ;
374+ openFileDialog . Filter = "音频文件|*.mp3|所有文件|*.*" ;
375+ openFileDialog . InitialDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . MyDocuments ) ;
376+ openFileDialog . Title = "打开BGM" ;
377+ openFileDialog . Multiselect = false ;
378+ openFileDialog . InitialDirectory = "../" ;
379+ // 显示文件对话框
380+ if ( openFileDialog . ShowDialog ( ) == System . Windows . Forms . DialogResult . OK )
381+ {
382+ // 获取用户选择的文件路径
383+ bgm_dir . Text = openFileDialog . FileName ;
384+ }
385+
386+ }
387+ //获取MP4视频时长
388+ private int ReadMp4During ( string filePath )
389+ {
390+ Debug . WriteLine ( filePath ) ;
391+ ShellClass sc = new ShellClass ( ) ;
392+ Folder dir = sc . NameSpace ( Path . GetDirectoryName ( filePath ) ) ;
393+ FolderItem item = dir . ParseName ( Path . GetFileName ( filePath ) ) ;
394+ StringBuilder sb = new StringBuilder ( ) ;
395+ string pattern = @"\d+" ;
396+ int i = 0 , hour = 0 , min = 0 , sec = 0 ;
397+ foreach ( Match match in Regex . Matches ( dir . GetDetailsOf ( item , 27 ) , pattern ) )
398+ {
399+ if ( i == 0 ) hour = int . Parse ( match . Value ) ;
400+ else if ( i == 1 ) min = int . Parse ( match . Value ) ;
401+ else if ( i == 2 ) sec = int . Parse ( match . Value ) ;
402+ i ++ ;
403+ }
404+ int all_sec = hour * 3600 + min * 60 + sec ;
405+ Debug . WriteLine ( $ "{ filePath } ->{ dir . GetDetailsOf ( item , 27 ) } 合{ all_sec } 秒") ;
406+ return all_sec ;
407+ }
408+
409+ //获取MP3时长
410+ private int ReadMp3During ( string filePath )
411+ {
412+ ShellClass sc = new ShellClass ( ) ;
413+ Folder dir = sc . NameSpace ( Path . GetDirectoryName ( filePath ) ) ;
414+ FolderItem item = dir . ParseName ( Path . GetFileName ( filePath ) ) ;
415+ StringBuilder sb = new StringBuilder ( ) ;
416+ string pattern = @"\d+" ;
417+ int i = 0 , hour = 0 , min = 0 , sec = 0 ;
418+ foreach ( Match match in Regex . Matches ( dir . GetDetailsOf ( item , 27 ) , pattern ) )
419+ {
420+ if ( i == 0 ) hour = int . Parse ( match . Value ) ;
421+ else if ( i == 1 ) min = int . Parse ( match . Value ) ;
422+ else if ( i == 2 ) sec = int . Parse ( match . Value ) ;
423+ i ++ ;
424+ }
425+ int all_sec = hour * 3600 + min * 60 + sec ;
426+ Debug . WriteLine ( $ "{ filePath } ->{ dir . GetDetailsOf ( item , 27 ) } 合{ all_sec } 秒") ;
427+ return all_sec ;
428+ }
281429 }
282430}
0 commit comments