mpatric / mp3agic

A java library for reading mp3 files and reading / manipulating the ID3 tags (ID3v1 and ID3v2.2 through ID3v2.4).
MIT License
1.2k stars 309 forks source link

problem about getAlbumImage() #135

Open jerry2714 opened 7 years ago

jerry2714 commented 7 years ago

I got some problem using getAlbumImage(), this is my code:

Mp3File mp3file = new Mp3File(fileName);
if (mp3file.hasId3v2Tag()) {
    ID3v2 id3v2Tag = mp3file.getId3v2Tag();
    byte[] imageData = id3v2Tag.getAlbumImage();
    if (imageData != null) {
        BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageData));
        //myShow();
    }

and I got this: http://imgur.com/38qMbEE The image I've got obviously not the right one, so I use another two music player to check, what I see in Groove(windows 10): http://imgur.com/pGUQJYC what I see in Potplayer: http://imgur.com/h5EIfMw So Groove and my code got the same album cover, which is not the actual cover, and the Potplayer got the real cover image. What should I do to solve this problem? I got the music file form here: https://www.jamendo.com/track/1364268/west-coast-highway

tmzkt commented 7 years ago

Even dumping the raw bytes of the image (not using ImageIO) to a file produces the malformed image as you pointed out. Mp3agic just exposes the raw bytes, but it still makes me curious how some players are able to open the file and others are not. I did a compare between a valid jpeg and a the bytes from the mp3 and the only difference between the files is that the bytes from the mp3 have extra '0' entries scattered throughout the file: JPEG from MP3: [-1, -40, -1, 0, -32, 0, 16, 74, 70, 73, .... valid JPEG: [-1, -40, -1, -32, 0, 16, 74, 70, 73,.... Potplayer must use some library that manages to remove the extra 0's before writing the file. Although this issue doesn't appear to be related to Mp3agic, try investigating this more and see if there is another library to write the image file that "fixes" the data.

jerry2714 commented 7 years ago

I found Mp3agic got right cover image from mp3 files that I scratched from youtube, and got borken image from files that I got from jamendo. So I think maybe jamendo do something on their files that make this happen. Now I use MediaMetadataRetriever in Android api to do this work and it works fine.

tmzkt commented 7 years ago

Good to hear. Can you share the working MediaMetadataRetriever code so we can determine whether or not the bug lies inside or outside of Mp3agic?

jerry2714 commented 7 years ago

MediaMetadataRetriever is a class in Android api Here is my code:

import android.media.MediaMetadataRetriever;

Bitmap getCoverImage(String filePath) {
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    mmr.setDataSource(filePath);
    byte[] imageData = mmr.getEmbeddedPicture();
    if(imageData != null)
    {
        Bitmap img = BitmapFactory.decodeStream(new ByteArrayInputStream(imageData));
        return img;
    }
    return null;
}

The key method of getting cover image is getEmbeddedPicture() These code works well, but I don't know how they done. I've tried to trace the source code, and I found this:

    /**
     * Call this method after setDataSource(). This method finds the optional
     * graphic or album/cover art associated associated with the data source. If
     * there are more than one pictures, (any) one of them is returned.
     * 
     * @return null if no such graphic is found.
     */
    public byte[] getEmbeddedPicture() {
        return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
    }

    private native byte[] getEmbeddedPicture(int pictureType);

So I guess the algorithm is hiding in the native method, maybe in a c++ file that I could not find.

AppWerft commented 5 years ago

Hi, I have the same issue and I switched after reading of this hint to the MediaMetadataRetriever method: still the same issue.

(image in bottom right corner.)

The log: skia: libjpeg error 116 <Corrupt JPEG data: 19 extraneous bytes before marker 0xdb> from output_message And here the code snippet

// Handle creation options
    @Override
    public void handleCreationDict(KrollDict opts) {
        TiBaseFile inputFile = null;
        if (!opts.containsKeyAndNotNull(TiC.PROPERTY_IMAGE))
            throw new IllegalArgumentException("missing property " + TiC.PROPERTY_IMAGE);
        inputFile = Mp3agicModule.getTiBaseFileFromInput(opts.get(TiC.PROPERTY_IMAGE));
        Mp3File mp3file = Mp3agicModule.getID3fromMP3File(inputFile);
        try {
            mp3file = new Mp3File(inputFile.getNativeFile());
            if (mp3file.hasId3v2Tag()) {
                bitmap=getCoverImage(inputFile.nativePath());
            }
        } catch (UnsupportedTagException | InvalidDataException | IOException e) {
            e.printStackTrace();
        }
    }

    // https://github.com/mpatric/mp3agic/issues/135
    private Bitmap getCoverImage(String filePath) {
        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        mmr.setDataSource(filePath);
        byte[] imageData = mmr.getEmbeddedPicture();
        if (imageData != null) {
            return BitmapFactory.decodeStream(new ByteArrayInputStream(imageData));
        }
        return null;
    }