|
1 | 1 | using NAudio.Lame; |
2 | | -using NAudio.Wave; |
3 | | -using NAudio.Wave.SampleProviders; |
4 | 2 | using Standart.Hash.xxHash; |
| 3 | +using Xabe.FFmpeg; |
5 | 4 |
|
6 | 5 | namespace MaiChartManager.Utils; |
7 | 6 |
|
@@ -76,8 +75,55 @@ public static async Task<string> GetCachedWavPath(string acbPath, string awbPath |
76 | 75 |
|
77 | 76 | public static void ConvertWavPathToMp3Stream(string wavPath, Stream mp3Stream, ID3TagData? tagData = null) |
78 | 77 | { |
79 | | - using var reader = new WaveFileReader(wavPath); |
80 | | - using var writer = new LameMP3FileWriter(mp3Stream, reader.WaveFormat, 256, tagData); |
81 | | - reader.CopyTo(writer); |
| 78 | + var outputPath = Path.Combine(StaticSettings.tempPath, $"ConvertToMp3_{Guid.NewGuid():N}.mp3"); |
| 79 | + string? albumArtPath = null; |
| 80 | + try |
| 81 | + { |
| 82 | + Directory.CreateDirectory(StaticSettings.tempPath); |
| 83 | + |
| 84 | + var conversion = FFmpeg.Conversions.New() |
| 85 | + .AddParameter($"-i " + wavPath.Escape()); |
| 86 | + |
| 87 | + if (tagData != null) |
| 88 | + { |
| 89 | + if (tagData.AlbumArt != null && tagData.AlbumArt.Length > 0) |
| 90 | + { |
| 91 | + // 把专辑封面写到临时文件,然后让ffmpeg把它嵌入mp3 |
| 92 | + albumArtPath = Path.Combine(StaticSettings.tempPath, $"ConvertToMp3_{Guid.NewGuid():N}.png"); |
| 93 | + File.WriteAllBytes(albumArtPath, tagData.AlbumArt); |
| 94 | + conversion.AddParameter($"-i {albumArtPath.Escape()}"); |
| 95 | + } // 顺序不能换!这个必须在第一个,因为-i必须在任何其他参数之前。 |
| 96 | + if (!string.IsNullOrEmpty(tagData.Title)) conversion.AddParameter($"-metadata title=" + tagData.Title.Escape()); |
| 97 | + if (!string.IsNullOrEmpty(tagData.Artist)) conversion.AddParameter($"-metadata artist=" + tagData.Artist.Escape()); |
| 98 | + if (!string.IsNullOrEmpty(tagData.Album)) conversion.AddParameter($"-metadata album=" + tagData.Album.Escape()); |
| 99 | + if (!string.IsNullOrEmpty(tagData.Year)) conversion.AddParameter($"-metadata date=" + tagData.Year.Escape()); |
| 100 | + if (!string.IsNullOrEmpty(tagData.Comment)) conversion.AddParameter($"-metadata comment=" + tagData.Comment.Escape()); |
| 101 | + if (!string.IsNullOrEmpty(tagData.Genre)) conversion.AddParameter($"-metadata genre=" + tagData.Genre.Escape()); |
| 102 | + if (!string.IsNullOrEmpty(tagData.Track)) conversion.AddParameter($"-metadata track=" + tagData.Track.Escape()); |
| 103 | + } |
| 104 | + |
| 105 | + conversion.AddParameter("-c:a libmp3lame -b:a 256k"); // 把wav编码为256kbps的LAME mp3 |
| 106 | + |
| 107 | + if (albumArtPath != null) |
| 108 | + { // 如果有专辑封面,还需要加一堆参数以写入专辑封面 |
| 109 | + conversion.AddParameter("-map 0:a -map 1:v -c:v copy -disposition:v attached_pic"); |
| 110 | + } |
| 111 | + |
| 112 | + conversion.SetOutput(outputPath).SetOverwriteOutput(true); |
| 113 | + conversion.Start().GetAwaiter().GetResult(); |
| 114 | + |
| 115 | + if (!File.Exists(outputPath) || new FileInfo(outputPath).Length == 0) |
| 116 | + { |
| 117 | + throw new InvalidOperationException("ffmpeg produced empty mp3 file from wav input."); |
| 118 | + } |
| 119 | + |
| 120 | + using var outputFile = new FileStream(outputPath, FileMode.Open, FileAccess.Read); |
| 121 | + outputFile.CopyTo(mp3Stream); |
| 122 | + } |
| 123 | + finally |
| 124 | + { |
| 125 | + File.Delete(outputPath); |
| 126 | + if (albumArtPath != null) File.Delete(albumArtPath); |
| 127 | + } |
82 | 128 | } |
83 | 129 | } |
0 commit comments