sannies / mp4parser

A Java API to read, write and create MP4 files
Apache License 2.0
2.76k stars 567 forks source link

How can I release the input sources put in `MovieCreator.build()`? #420

Open nICEnnnnnnnLee opened 4 years ago

nICEnnnnnnnLee commented 4 years ago

I'm doing something like that in MuxMp4SourcesExample.java

String audioEnglish = "audio.mp4";
String video = "video.mp4";

Movie countVideo = MovieCreator.build(video);
Movie countAudioEnglish = MovieCreator.build(audioEnglish);
Track audioTrackEnglish = countAudioEnglish.getTracks().get(0);
audioTrackEnglish.getTrackMetaData().setLanguage("eng");
countVideo.addTrack(audioTrackEnglish);

Container out = new DefaultMp4Builder().build(countVideo);
FileOutputStream fos = new FileOutputStream(new File("output.mp4"));
out.writeContainer(fos.getChannel());
fos.close();

After that, I attempt to delete the audio file but failed.

boolean deleted = new File(audioEnglish).delete();
System.out.println("deleted : " + deleted );  // ---> false

Will it auto release the resources, or how could I mannualy free it?

nICEnnnnnnnLee commented 4 years ago

I've noticed that the implementations of Track is instance of Closeable.
for example,

But CencMp4TrackImplImpl, PiffMp4TrackImpl, Mp4TrackImpl in MovieCreator.build() somehow ignores it. Here, in Mp4TrackImpl.java, it does nothing.

It should do sth since a RandomAccessSource is put in the Mp4TrackImpl, am I right?

public Mp4TrackImpl(final long trackId, Container isofile, RandomAccessSource randomAccess, String name)
HadiDortaj commented 2 years ago

I have the same problem. What should I do?

HadiDortaj commented 2 years ago

I created a custom MovieCreator for this bug and it seems to be working(the code is written in Kotlin). Remeber that you should call movie.tracks.forEach { track -> track.close() } when you are done.

import org.mp4parser.Container
import org.mp4parser.IsoFile
import org.mp4parser.boxes.iso14496.part12.SchemeTypeBox
import org.mp4parser.boxes.iso14496.part12.TrackBox
import org.mp4parser.muxer.*
import org.mp4parser.tools.Path
import java.io.File
import java.io.FileInputStream
import java.io.RandomAccessFile
import java.nio.channels.ReadableByteChannel

class CustomMovieCreator {

companion object {

    fun newMovieInstance(filePath: String): Movie {
        val f = File(filePath)
        val fis = FileInputStream(f)
        val m = newMovieInstance(fis.channel, FileRandomAccessSourceImpl(RandomAccessFile(f, "r")), filePath)
        fis.close()
        return m
    }

    private fun newMovieInstance(readableByteChannel: ReadableByteChannel?, randomAccessSource: RandomAccessSource?, name: String?): Movie {
        val isoFile = IsoFile(readableByteChannel)
        val m = Movie()
        val trackBoxes = isoFile.movieBox.getBoxes(TrackBox::class.java)
        for (trackBox in trackBoxes) {
            val schm = Path.getPath<SchemeTypeBox>(trackBox, "mdia[0]/minf[0]/stbl[0]/stsd[0]/enc.[0]/sinf[0]/schm[0]")
            if (schm != null && (schm.schemeType == "cenc" || schm.schemeType == "cbc1")) {
                m.addTrack(
                    CustomCencMp4TrackImplImpl(
                        trackBox.trackHeaderBox.trackId, isoFile,
                        randomAccessSource, name + "[" + trackBox.trackHeaderBox.trackId + "]"
                    )
                )
            } else if (schm != null && schm.schemeType == "piff") {
                m.addTrack(
                    CustomPiffMp4TrackImpl(
                        trackBox.trackHeaderBox.trackId, isoFile,
                        randomAccessSource, name + "[" + trackBox.trackHeaderBox.trackId + "]"
                    )
                )
            } else {
                m.addTrack(
                    CustomMp4TrackImp(
                        trackBox.trackHeaderBox.trackId, isoFile,
                        randomAccessSource, name + "[" + trackBox.trackHeaderBox.trackId + "]"
                    )
                )
            }
        }
        m.matrix = isoFile.movieBox.movieHeaderBox.matrix
        return m
    }

}

private class CustomMp4TrackImp(trackId: Long, isofile: Container?, private val randomAccess: RandomAccessSource?, name: String?) : Mp4TrackImpl(trackId, isofile, randomAccess, name) {

    override fun close() {
        kotlin.runCatching {
            randomAccess?.close()
        }
    }
}

private class CustomPiffMp4TrackImpl(trackId: Long, isofile: Container?, private val randomAccess: RandomAccessSource?, name: String?) : PiffMp4TrackImpl(trackId, isofile, randomAccess, name) {

    override fun close() {
        kotlin.runCatching {
            randomAccess?.close()
        }
    }
}

private class CustomCencMp4TrackImplImpl(trackId: Long, isofile: Container?, private val randomAccess: RandomAccessSource?, name: String?) : CencMp4TrackImplImpl(trackId, isofile, randomAccess, name) {

    override fun close() {
        kotlin.runCatching {
            randomAccess?.close()
        }
    }
}

}