Java / JAudiotagger:Mp3错误的ID3标签大小

时间:2012-10-11 14:06:01

标签: java mp3 id3 id3-tag id3v2

我正在使用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()之后),然后将艺术作品添加到新标记,但新标记与旧标记的大小相同。

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

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

之前的mp3文件:

before http://imageshack.us/a/img694/3766/mp3filebefore.jpg

删除一件艺术品后的mp3文件。请注意,虽然标记较少,但标记仍然保留了以前的大小:

after wrong http://imageshack.us/a/img513/2476/mp3fileafterwrong.jpg

该文件应该如何:

after correct http://imageshack.us/a/img818/1506/mp3fileaftercorrect.jpg

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

3 个答案:

答案 0 :(得分:2)

此问题从今天开始已得到解决。

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

TagOptionSingleton.getInstance().setId3v2PaddingWillShorten(true);

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

答案 1 :(得分:1)

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

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

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

编辑:看看Javadoc,我相信在使用你的文件之前你需要设置这个选项:

TagOptionSingleton.getInstance().setId3v2PaddingWillShorten(true);

答案 2 :(得分:0)

方法

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封面图片。