id3 图像编辑后播放 mp3 时遇到问题
由于硬件限制,我们生产的软件试图确保导入到其库中的任何音频文件(准备复制到硬件上)都是可接受的比特率。
最近,我们开始使用 FFmpeg 将许多不同的音频类型转换为 mp3,以便在我们的硬件上导入和使用它们。虽然转换工作正常并且 mp3 文件随后可以在我们的硬件上工作,但在将专辑封面添加到 mp3 的 ID3 标签时,我们遇到了问题。该曲目不会在我们的软件中播放音频。 Windows 似乎也无法在资源管理器中获取 ID3 标签的值,但 Windows Media Player 仍会播放该曲目。
此问题似乎仅在使用 FFmpeg 后更改新转换的 mp3 的 ID3 标签时才会出现。更改来自其他来源的 mp3 或已经具有 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 块,然后编写一个新的。
Due to hardware restrictions, the software we produce tries to ensure that any audio file it imports into it's library (ready to be copied onto the hardware) is an acceptable bit rate.
Recently we've started using FFmpeg to convert a number of different audio types to mp3 to allow them to be imported and used on our hardware. Whilst the conversion works fine and the mp3 files work on our hardware afterwards, we're having issues specifically when adding an album art to the ID3 tags of the mp3. The track will not play audio in our software. It also seems that Windows cannot pick up the values of the ID3 tags in explorer, but Windows Media Player will still play the track.
This problem only seems to occur when changing a newly converted mp3s' ID3 tags after using FFmpeg. Changing tags on mp3s from other sources or those that have already got ID3 tag album art is fine.
The code for using FFmpeg from our software is as follows:
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);
To change the ID3 tags we have started using TagLib-Sharp and the code for changing the ID3 tags is:
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);
}
}
And the code used to play the track in the software (FilgraphManager in QuartzTypeLib):
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();
}
And the error when executing _mp3control.RenderFile(_tempFile)
:
{System.Runtime.InteropServices.ExternalException} = {"Exception from HRESULT: 0x80040266"}
at QuartzTypeLib.FilgraphManagerClass.RenderFile(String strFilename)
My largest problem here is that I don't know whether the fault lies with (our implementation of) FFmpeg (large library that's used fine in many other places), TagLib-Sharp or the audio playing.
Edit 1: Following J. Andrew Laughlin's advice I've been looking at the differences of the ID3 tags in the hex of each file. This is what I've found:
The initial input is ID3v2.3. After re-encoding with FFmpeg, the ID3 data is v2.4. This initial re-encoded file plays fine in media players and our software. Using TagLib# in our software to add album art keeps ID3v2.4 but the tags are only available using TagLib# to read them and it only plays in media players such as Windows Media Player. Using another tool to change the ID3 tags (in this case AudioShell Tag Editor) and add the same album art changed the ID3 version to 2.3 and meant that the mp3 played on our softwares audio player as well as other media players - However changing the tags afterwards produces an exception when saving the image.
One other thing I tried was to rip out the ID3v2.4 block completely after the re-encoding, this plays (as you'd expect) in all media players. When using the TagLib# on this untagged file, the tags were correctly applied (v2.3) and it continued to play properly in our software as well as others.
Unless anyone can suggest an elegant solution (either force TagLib# to write a new ID3v2.3 block or stop FFmpeg from writing one at all) I think I may just programmatically remove the ID3v2.4 block from the file after encoding and then write a new one.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
TagLib# 可用于将 ID3 标签从 2.4“降级”到 2.3。我个人更喜欢将 ID3 标签转换为 2.3,因为音乐播放器更一致地采用它。
已经有一段时间了,但我相信您可以在上面的代码中使用以下内容:
或者,您可以在应用程序初始化时使用以下代码强制所有标签在 2.3 中呈现:
TagLib# 还可以完全删除标签并重新添加他们,但事情不应该发展到这个地步。
祝你好运!
TagLib# can be used to "downgrade" an ID3 tag from 2.4 to 2.3. I personally prefer to convert my ID3 tags to 2.3 since it is more consistently adopted across music players.
It's been a while, but I believe you can use the following in your above code:
Alternatively, you can force all tags to render in 2.3 by using the following code when your application initializes:
TagLib# can also remove tags completely and re-add them, but it shouldn't have to come to that.
Good luck!