Search code examples
javaitunesmp4mp4parser

How to write Apple meta-information to MP4 file with mp4parser


I'm using the mp4parser library to add iTunes compatible meta-information to some MP4 files. This example is simplified, because it does not check if boxes are available, but reproduces the issue.

FileChannel fcr = new RandomAccessFile(srcFile, "r").getChannel();
FileChannel fcw = new RandomAccessFile(dstFile, "rw").getChannel();

IsoFile isoFile = new IsoFile(fcr);

MovieBox moov = isoFile.getBoxes(MovieBox.class).get(0);
UserDataBox udta = moov.getBoxes(UserDataBox.class).get(0);
MetaBox meta = udta.getBoxes(MetaBox.class).get(0);
AppleItemListBox apple = meta.getBoxes(AppleItemListBox.class).get(0);

AppleShowBox box = box = new AppleShowBox();
box.setValue("Series-Name");
apple.addBox(box);

isoFile.getBox(fcw);
fcw.force(true);fcw.close();
fcr.close();

The good news are that the file can be imported to iTunes and the Series-Name is shown at the correct place. But, the MP4 file is broken and it's not possible start the movie. How can I add this kind of meta-information without corrupting the file?


Solution

  • You are most likely changing the offsets of the data in the file by increasing the offset of the mdat box. The entries in the chunk offset box need be increased by exactly the number of bytes you add there. You might use this code snippet here to correct:

    private void correctChunkOffsets(IsoFile tempIsoFile, long correction) {
        List<Box> chunkOffsetBoxes = Path.getPaths(tempIsoFile, "/moov[0]/trak/mdia[0]/minf[0]/stbl[0]/stco[0]");
        for (Box chunkOffsetBox : chunkOffsetBoxes) {
    
            LinkedList<Box> stblChildren = new LinkedList<Box>(chunkOffsetBox.getParent().getBoxes());
            stblChildren.remove(chunkOffsetBox);
    
            long[] cOffsets = ((ChunkOffsetBox) chunkOffsetBox).getChunkOffsets();
            for (int i = 0; i < cOffsets.length; i++) {
                cOffsets[i] += correction;
            }
    
            StaticChunkOffsetBox cob = new StaticChunkOffsetBox();
            cob.setChunkOffsets(cOffsets);
            stblChildren.add(cob);
            chunkOffsetBox.getParent().setBoxes(stblChildren);
        }
    }
    

    in rare cases the mdat box comes first and the metadata last, then you don't need to change it. For a full example have a look here: https://mp4parser.googlecode.com/svn/trunk/examples/src/main/java/com/googlecode/mp4parser/stuff/ChangeMetaData.java

    Be aware:

    In the latest release 1.0-RC-24 I had to remove the Apple related stuff since it needs major work. You are stuck with RC-23 for the moment.