由于硬件限制,我们制作的软件试图确保它导入到其库中的任何音频文件(准备复制到硬件上)都是可接受的比特率。
最近,我们开始使用 FFmpeg 将许多不同的音频类型转换为 mp3,以便将它们导入并在我们的硬件上使用。虽然转换工作正常并且之后 mp3 文件在我们的硬件上工作,但我们在将专辑封面添加到 mp3 的 ID3 标签时遇到了问题。该曲目不会在我们的软件中播放音频。Windows 似乎也无法在资源管理器中获取 ID3 标签的值,但 Windows Media Player 仍会播放该曲目。
此问题似乎仅在使用 FFmpeg 后更改新转换的 mp3 的 ID3 标签时出现。从其他来源或已经获得 ID3 标签专辑封面的 mp3 上更改标签是可以的。
从我们的软件中使用FFmpeg的代码如下:
private const string SAMPLE_RATE = "44100";
...
//create temp file for output
outFile = Path.GetTempFileName();
outFile = Path.ChangeExtension(outFile, "mp3");
if (!File.Exists(inFile))
return false;
string metadata = (inFile.EndsWith("mp3")) ? " " : " -map_meta_data 0:0 ";
//build process
string workingDirectory = Environment.CurrentDirectory;
ProcessStartInfo FFmpegProcessInfo = new ProcessStartInfo();
FFmpegProcessInfo.WorkingDirectory = workingDirectory;
FFmpegProcessInfo.FileName = "ffmpeg.exe";
FFmpegProcessInfo.Arguments = "-i \"" + inFile + "\"" + " -ar "+SAMPLE_RATE + metadata + "\"" + outFile + "\""; //default conversion to SAMPLE_RATE
FFmpegProcessInfo.CreateNoWindow = true; //hide from user
//let us grab the output
FFmpegProcessInfo.RedirectStandardError = true;
FFmpegProcessInfo.RedirectStandardOutput = true;
FFmpegProcessInfo.UseShellExecute = false;
Process p = Process.Start(FFmpegProcessInfo);
要更改 ID3 标签,我们已经开始使用 TagLib-Sharp,更改 ID3 标签的代码是:
public void SetId3Tags(string path, Bitmap image, IDictionary<string, string> values)
{
FileInfo fileInfo = new FileInfo(path);
fileInfo.Attributes = FileAttributes.Normal;
try
{
TagLib.File tagFile = TagLib.File.Create(path);
if (values.ContainsKey("Title"))
tagFile.Tag.Title = values["Title"];
if (values.ContainsKey("Artist"))
tagFile.Tag.Performers = new string[1] { values["Artist"] };
if (values.ContainsKey("Comments"))
tagFile.Tag.Comment = values["Comments"];
if (image != null) {
string tmpImg = Path.GetTempFileName();
image.Save(tmpImg);
IPicture newArt = new Picture(tmpImg);
tagFile.Tag.Pictures = new IPicture[1] {newArt};
}
tagFile.Save();
}
catch (Exception e)
{
_logger.Log(e);
}
}
以及软件中用来播放曲目的代码(QuartzTypeLib中的FilgraphManager):
public void Play()
{
if (!_isPaused)
{
_graphManager = new FilgraphManager();
_mp3control = (IMediaControl)_graphManager;
_mp3position = (IMediaPosition)_graphManager;
_tempFile = Path.GetTempFileName();
File.Copy(_fullPath, _tempFile, true);
_mp3control.RenderFile(_tempFile);
}
else
{
_isPaused = false;
}
_mp3control.Run();
}
以及执行时的错误_mp3control.RenderFile(_tempFile)
:
{System.Runtime.InteropServices.ExternalException} = {"Exception from HRESULT: 0x80040266"}
at QuartzTypeLib.FilgraphManagerClass.RenderFile(String strFilename)
我最大的问题是我不知道问题是否在于(我们的实现)FFmpeg(在许多其他地方都很好使用的大型库)、TagLib-Sharp 或音频播放。
编辑 1:按照 J. Andrew Laughlin 的建议,我一直在查看每个文件的十六进制中 ID3 标签的差异。这是我发现的:
初始输入是 ID3v2.3。用FFmpeg重新编码后,ID3数据为v2.4。这个初始重新编码的文件在媒体播放器和我们的软件中播放良好。在我们的软件中使用 TagLib# 添加专辑封面会保留 ID3v2.4,但标签只能使用 TagLib# 读取它们,并且只能在 Windows Media Player 等媒体播放器中播放。使用另一个工具更改 ID3 标签(在本例中为 AudioShell 标签编辑器)并添加相同的专辑封面将 ID3 版本更改为 2.3,这意味着 mp3 在我们的软件音频播放器以及其他媒体播放器上播放 - 但是更改标签之后在保存图像时产生异常。
我尝试的另一件事是在重新编码后完全撕掉 ID3v2.4 块,这会在所有媒体播放器中播放(如您所料)。在此未标记文件上使用 TagLib# 时,标记已正确应用 (v2.3),并且它继续在我们的软件和其他软件中正常播放。
除非有人可以提出一个优雅的解决方案(强制 TagLib# 编写一个新的 ID3v2.3 块或完全停止 FFmpeg 编写一个),否则我想我可能只是在编码后以编程方式从文件中删除 ID3v2.4 块,然后编写一个新的一个。