1

I created the setArtwork method to set the artwork of an aac file in an .m4a container and it does exactly what I want it to when I run the main method

public static void setArtwork(File art, File m4a) throws Exception{
    Mp4TagReader reader = new Mp4TagReader();
    Mp4TagWriter writer = new Mp4TagWriter();
    RandomAccessFile song = new RandomAccessFile(m4a.toString(),"rw");
    Mp4Tag mp4tag = reader.read(song);

    Artwork artwork = ArtworkFactory.createArtworkFromFile(art);
    mp4tag.addField(artwork);
    mp4tag.setField(artwork);

    RandomAccessFile temp = new RandomAccessFile(m4a,"rw");
    writer.write(mp4tag,song,temp);
}
public static void main(String[] args) throws Exception{
    File art = new File("C:\\Users\\Zubair\\Documents\\music\\coverArt.jpeg");
    File m4a = new File("C:\\Users\\Zubair\\Documents\\music\\song.m4a");
    setArtwork(art,m4a);
}

BUT, when I try to use the setArtwork method in a different method in a different class it doesn't actually save the mp4 tag to the File. I did some debugging to see if the picture was even being added to the artwork tag and it all looks good, but it seems that the tag doesn't get written to the file.

public static void mp3Tom4a(File mp3File, File m4aFolder, File coverArt) throws Exception {
    String input = mp3File.toString();
    String name = mp3File.getName();

    String output = name.substring(0,name.indexOf(MP3)) + M4A;
    output = m4aFolder.toString() + "\\" + output;

    //cd ffmpeg\bin && ffmpeg -y -i input.mp3 -an -vcodec copy cover.jpg && ffmpeg -y -i input.mp3 -c:a aac -b:a 192k -vn output.m4a
    ProcessBuilder builder = new ProcessBuilder(
            "cmd.exe","/c","cd ffmpeg\\bin && ffmpeg -y -i "
            + input +" -an -vcodec copy "+coverArt+
            " && ffmpeg -y -i " + input + " -c:a aac -b:a 128k -vn " + output);
    builder.redirectErrorStream(true);
    builder.start();
    JAudioData.setArtwork(coverArt,new File(output));
}
public static void main(String[] args) throws Exception {
    mp3Tom4a(new File("C:\\Users\\Zubair\\Documents\\music\\song.mp3"),
            new File("C:\\Users\\Zubair\\Documents\\music"),
            new File("C:\\Users\\Zubair\\Documents\\music\\coverArt.jpeg"));
}

it doesn't make sense that setArtwork only works when it's in the main method of its own class, especially because the objects I am using for the parameters are identical to eachother, so there should be no difference in the result. I think it might have something to do with the RandomAccessFile object being updated but the physical storage not getting updated

Edit- If I comment out builder.start() then it can successfully write the mp4tag to the m4a file. But I don't see why having builder.start() would prevent that from happenning. My best guess is that because builder.start() is what creates song.m4a it is still being "edited" by that and can't be edited by any other processes.

  • I guess you are assuming that the external process has successfully completed by the time you can `setArtwork` ? – Scary Wombat Aug 08 '18 at 02:46
  • @ScaryWombat I already did some debugging to see if the setArtwork method even runs. It does end up running and creating an mp4tag that has the correct artwork added to it, But i don't see the new tag written to the original file. But this error isn't made when I run the main method from the first class – Zubair Ahmed Aug 08 '18 at 02:53
  • Is some exception being thrown? – Scary Wombat Aug 08 '18 at 04:04
  • @ScaryWombat no exceptions are thrown. It performs just as it performs in the main method, but when I check the properties of the song.m4a nothing is changed. – Zubair Ahmed Aug 08 '18 at 04:42
  • Maybe try checking that it works if you omit calling the external process first – Scary Wombat Aug 08 '18 at 05:15
  • Okay so when I comment out all of the code using the ProcessBuilder builder object then I can successfully add the artwork to the file. But I don't see how the ProcessBuilder code can stop the Artwork from being written. – Zubair Ahmed Aug 08 '18 at 05:27
  • Maybe it is not successfully - or properly - closing the file – Scary Wombat Aug 08 '18 at 05:55
  • Don't you need to waitFor() the end of the process before you call the setArtwork method ? – Guillaume Pansier Aug 08 '18 at 06:54
  • if I use waitFor() then it never stops running. What interests me is that if I comment out the builder.startt() then it still creates the song.m4a file. And then if I add that code back in then run main then it adds the artwork onto the file successfully. So that means that the first time it can't add the artwork because the file isn't yet available for editing. Great now I know the problem but have no idea how to fix it – Zubair Ahmed Aug 08 '18 at 07:14
  • Can you have a look at https://stackoverflow.com/a/5483953/4716890 ? Maybe there are some errors you don't see when running the process. – Guillaume Pansier Aug 08 '18 at 09:08

1 Answers1

0

I found the answer from this other thread

https://stackoverflow.com/a/5483976/10194055

Class Process

Because some native platforms only provide limited buffer size for standard input and >output streams, failure to promptly write the input stream or read the output stream of >the subprocess may cause the subprocess to block, and even deadlock.

Fail to clear the buffer of input stream (which pipes to the output stream of >subprocess) from Process may lead to a subprocess blocking.

Here is what my functional code looks like. The other class and methods stay exactly the same

public static void mp3Tom4a(File mp3File, File m4aFolder, File coverArt) throws Exception {

    String input = mp3File.toString();
    String name = mp3File.getName();

    String output = name.substring(0, name.indexOf(MP3)) + M4A;
    output = m4aFolder.toString() + "\\" + output;
    //cd ffmpeg\bin && ffmpeg -y -i input.mp3 -an -vcodec copy cover.jpg && ffmpeg -y -i input.mp3 -c:a aac -b:a 192k -vn output.m4a
    ProcessBuilder builder = new ProcessBuilder(
            "cmd.exe", "/c", "cd ffmpeg\\bin && ffmpeg -y -i "
            + input + " -an -vcodec copy " + coverArt +
            " && ffmpeg -y -i " + input + " -c:a aac -b:a 128k -vn " + output);
    builder.redirectErrorStream(true);
    Process p = builder.start();
    BufferedReader reader =
            new BufferedReader(new InputStreamReader(p.getInputStream()));
    while ((reader.readLine()) != null) {}
    p.waitFor();

    JAudioData.setArtwork(coverArt, new File(output));
}
Community
  • 1
  • 1