4

我正在使用JAudiotagger库构建一个 mp3 标记应用程序。我的应用程序可以很好地读取 mp3 元数据,并且也可以很好地写入元数据,除了艺术品。所以我的问题如下:

当我在 mp3 文件中添加一些艺术作品并保存时,文件变得越来越大,这是有道理的。但是当我删除一件或所有艺术品时,文件大小并没有变小

实际问题在于我的 mp3 文件的 ID3v2 标签。当我移除艺术品时,它实际上已从标签中移除,但标签大小本身并没有缩小。

我在删除艺术品时使用的方法是这样的:

    // Get the artworkList from the parentFrame.
    List<Artwork> list = parentFrame.getArtworkList();

    // Get the tag from the parentFrame's mp3File.
    AbstractID3v2Tag tag = parentFrame.getTag();

   // Get the index of the artwork the user is currently looking at (and
   // wants to delete too).
   int visibleArtworkIndex = parentFrame.getVisibleArtworkIndex();

   // Remove it from the list.
   list.remove(visibleArtworkIndex);

   // Update the parentFrame's copy of the artworkList.
   parentFrame.setArtworkList(list);

   // Update the tag (delete its whole artwork field).
   tag.deleteArtworkField();

   // If the list has more artworks left, add them to the tag.
   if (!list.isEmpty()) {
       Iterator<Artwork> iterator = list.iterator();
       while (iterator.hasNext()) {
           try {
               tag.addField(iterator.next());
           } catch (FieldDataInvalidException e1) {
               e1.printStackTrace();
           }
       }
   }

,它实际上从列表中删除了一件艺术品,然后通过删除其所有艺术品并从更新的列表中重新复制它们来更新标签本身。

我对解决方案的尝试是:

  • 从更新的旧标签创建一个新标签(在调用之后tag.deleteArtworkField()),然后将艺术品添加到新标签,但新标签的大小与旧标签相同。

  • 在保存之前使用 修剪 mp3 文件tag.adjustPadding(File fileToBeTrimmed, int sizeToStoreTagBeforeAudioInBytes, long audioStartByte),这会调整 MP3 文件开头的填充长度。
    这里的问题是我只知道错误的标签大小而不是正确的,所以我无法正确修剪 mp3 并最终丢失音频数据。

为了更好地说明问题,我添加了一些图片:

之前的mp3文件:

前

移除一幅作品后的 mp3 文件。请注意,尽管艺术品较少,但标签仍保持其先前的大小:

错后

以及文件应该如何:

改正后

我希望任何人有任何想法。提前致谢。

4

3 回答 3

2

这实际上是预期的行为,这是一种优化。

当向 ID3v2 标签添加数据且空间不足时,需要重写整个文件以腾出足够的空间。当您删除数据时,ID3v2 只是更新以包含数据,并且未使用的空间只是简单地标记为空闲(当您再次添加更多数据时它将被回收)。

在您的库中查找“释放标签中未使用的空间”调用。您需要明确告诉它应该释放可用空间。

编辑:查看 Javadoc,我相信您需要在处理文件之前设置此选项:

TagOptionSingleton.getInstance().setId3v2PaddingWillShorten(true);
于 2012-10-11T15:26:29.730 回答
2

方法

TagOptionSingleton.getInstance().setId3v2PaddingWillShorten(true);
TagOptionSingleton.getInstance().setOriginalSavedAfterAdjustingID3v2Padding(true);

似乎没有完全实施(截至 2018 年 1 月)。例如,检查http://www.jthink.net/jaudiotagger/maven/apidocs/org/jaudiotagger/tag/mp4/Mp4TagCreator.html 以查看 Mp4TagCreator 类在将元数据转换为原始数据时没有实现填充:

padding - 当前忽略的 TODO 填充参数

对于 mp3 文件,我有一个解决方法,使用库 mp3agic https://github.com/mpatric/mp3agic。与上次更新于 2015 年的 jaudiotagger 不同,它仍在更新。在 android 上,您需要使用 0.9.0 版本,因为 0.9.1 使用 java.nio.file-classes,android 不支持,https://github.com/mpatric/mp3agic/issues/141

解决方法是简单地创建一个新标签并复制标签数据,然后将其写入新文件。如果成功,将旧文件替换为新文件。如果不复制封面图像,新文件将比原始文件小。我相信 jaudiotagger 也应该可以做到这一点,但没能做到。以下是 mp3agic 的用法:

                        try {
                        Mp3File song = new Mp3File(location,false);

                        if (song.hasId3v2Tag()){
                            ID3v2 oritag=song.getId3v2Tag();
                            byte[] image=oritag.getAlbumImage();
                            if(image!=null){
                                if (image.length > 10) {
                                    song = new Mp3File(location, true);
                                    oritag=song.getId3v2Tag();
                                    ID3v24Tag newtag = new ID3v24Tag();

                                    // copy metadata

                                    newtag.setArtist(oritag.getArtist());
                                    newtag.setArtistUrl(oritag.getArtistUrl());
                                    newtag.setOriginalArtist(oritag.getOriginalArtist());
                                    newtag.setArtistUrl(oritag.getArtistUrl());

                                    newtag.setAlbum(oritag.getAlbum());
                                    newtag.setAlbumArtist(oritag.getAlbumArtist());

                                    newtag.setAudiofileUrl(oritag.getAudiofileUrl());
                                    newtag.setAudioSourceUrl(oritag.getAudioSourceUrl());
                                    newtag.setUrl(oritag.getUrl());

                                    newtag.setGenre(oritag.getGenre());
                                    newtag.setGrouping(oritag.getGrouping());

                                    newtag.setTitle(oritag.getTitle());
                                    newtag.setTrack(oritag.getTrack());

                                    newtag.setPublisher(oritag.getPublisher());
                                    newtag.setPublisherUrl(oritag.getPublisherUrl());
                                    newtag.setCopyright(oritag.getCopyright());
                                    newtag.setCopyrightUrl(oritag.getCopyrightUrl());
                                    newtag.setComposer(oritag.getComposer());
                                    newtag.setCommercialUrl(oritag.getCommercialUrl());
                                    newtag.setComment(oritag.getComment());
                                    newtag.setYear(oritag.getYear());
                                    newtag.setKey(oritag.getKey());
                                    newtag.setRadiostationUrl(oritag.getRadiostationUrl());
                                    newtag.setPaymentUrl(oritag.getPaymentUrl());

                                    song.setId3v2Tag(newtag);


                                    try {
                                        song.save(location + "intermed");

                                        File from = new File(location + "intermed");
// if successfull then replace old file with new file
                                        if(from.exists()) {
                                            File file = new File(location);
                                            long sizeold = file.length();
                                            file.delete();
                                            File to = new File(location);
                                            long sizenew = from.length();
                                            from.renameTo(to);
                                            freedspace += sizeold - sizenew;
                                            }

                                    } catch (IOException | NotSupportedException e) {
                                        e.printStackTrace();

                                    }
                                }
                            }
                        }

                    } catch (IOException | UnsupportedTagException | InvalidDataException e) {
                        e.printStackTrace();
                    }

备注:我在我的 AudioCleanup-App,https://play.google.com/store/apps/details? id=com.gluege.audiocleanup&hl=en 中实现了这个,它适用于 mp3 文件。我没有设法删除其他文件类型的专辑封面。如果有人有解决方案,请分享。

我不喜欢 Id3 标准,尤其是填充。这是对智能手机宝贵空间的浪费。我见过每首歌都包含相同的 1MB 封面图片的专辑。

于 2018-02-05T09:59:01.650 回答
2

从今天开始,这是固定的。

默认情况下,当您缩小元数据时,jaudiotagger 不会回收空间,但现在如果您设置

TagOptionSingleton.getInstance().setId3v2PaddingWillShorten(true);

在保存更改之前,它将回收不必要的填充以尽可能减小文件大小。

于 2020-03-26T16:56:57.133 回答