'How to combine multiple mp4 videos into one video using jcodec in Java?
I have multiple mp4 files which are parts of a whole mp4 file. They have been just split up to smaller files.
I want to combine those files programmatically into one mp4 file using jcodec in Java. Currently, I'm using the following code to do this:
import org.jcodec.common.DemuxerTrack;
import org.jcodec.common.MuxerTrack;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.common.model.Packet;
import org.jcodec.containers.mp4.Brand;
import org.jcodec.containers.mp4.demuxer.MP4Demuxer;
import org.jcodec.containers.mp4.muxer.MP4Muxer;
import java.io.File;
import java.util.List;
import static org.jcodec.common.io.NIOUtils.readableChannel;
import static org.jcodec.common.io.NIOUtils.writableChannel;
public class Main {
    public static void main(String[] args) throws Exception {
        File outputFile = new File("file_path_output.mp4");
        outputFile.mkdirs();
        outputFile.delete();
        File[] inputFiles = new File[]{
                new File("file_path_1.mp4"),
                new File("file_path_2.mp4"),
                new File("file_path_3.mp4"),
        };
        SeekableByteChannel output = writableChannel(outputFile);
        MP4Muxer mp4Muxer = MP4Muxer.createMP4Muxer(output, Brand.MP4);
        MuxerTrack mixedVideoTrack = null;
        MuxerTrack mixedAudioTrack = null;
        for (File input : inputFiles) {
            SeekableByteChannel byteChannel = readableChannel(input);
            MP4Demuxer demuxer = MP4Demuxer.createMP4Demuxer(byteChannel);
            List<DemuxerTrack> videoTracks = demuxer.getVideoTracks();
            List<DemuxerTrack> audioTracks = demuxer.getAudioTracks();
            if (mixedVideoTrack == null) {
                mixedVideoTrack = mp4Muxer.addVideoTrack(videoTracks.get(0).getMeta().getCodec(), videoTracks.get(0).getMeta().getVideoCodecMeta());
            }
            if (mixedAudioTrack == null) {
                mixedAudioTrack = mp4Muxer.addAudioTrack(audioTracks.get(0).getMeta().getCodec(), audioTracks.get(0).getMeta().getAudioCodecMeta());
            }
            for (DemuxerTrack videoTrack : videoTracks) {
                Packet packet;
                while ((packet = videoTrack.nextFrame()) != null) {
                    mixedVideoTrack.addFrame(packet);
                }
            }
            for (DemuxerTrack audioTrack : audioTracks) {
                Packet packet;
                while ((packet = audioTrack.nextFrame()) != null) {
                    mixedAudioTrack.addFrame(packet);
                }
            }
            demuxer.close();
        }
        mp4Muxer.finish();
        output.close();
    }
}
Unfortunately, it does not work as the video generated does not contain audio files nor correct frames. For example, all visual frames I get are like one below:
What is the problem and how can I fix it? Thank you very much.
Solution 1:[1]
You can do this with ffmpeg.
- First you will need to write the file paths to a txt file
txt file with :
- file '/sdcard/video/video1.mp4'
- file '/sdcard/video/video2.mp4'
- file '/sdcard/video/video3.mp4'
- file '/sdcard/video/video4.mp4'
You can use following command.
ffmpeg -f concat -i mp4list.txt -c:v copy -c:a copy merging.mp4
- You can write a wrapper over the Java code. Additionally, you can use the code below.
Resource to help : link
String[] cmd = new String[]{"-f", "concat", "-safe", "0", "-i", "mp4list.txt", "-c", "copy", "-preset", "ultrafast", outFile};
ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler(){
    
        @Override
        public void onFailure(String message){
        }
        @Override
        public void onSuccess(String message){
        }
        @Override
        public void onProgress(String message){
        }
    
        @Override
        public void onStart(){
        }
    
        @Override
        public void onFinish(){
        }
    }
Solution 2:[2]
I don't really know jcodec, but I've used MP4parser in the past. If you need to merge mp4 files, regardless of the library, then I suggest you this one. I'm just pitching it to you because I don't know if you're having problems in merging the files due to the complexity of the library. Might be worth to give it a shot. MP4Parser is quite easy and straightforward. I'll also leave you the link to the maven repository.
https://search.maven.org/artifact/com.googlecode.mp4parser/isoparser/1.1.22/jar
Here there's an implementation I've done to show you how to merge 2 files from the same original video (to replicate your exact case). Basically, you have a Movie class, which represents your mp4 file, containing a  List of Track (only 2); one representing the video while the other the audio.
- First, I've collected from the movies all the video and audio tracks in two separate arrays. 
- Then, I've created a - Listwith the merged audio- Trackand the merged video- Trackin order to set it to the output file.
- Finally, I've built the - Movieinside a- Containerand saved it with a- FileOutputStream.
public class Main {
    public static void main(String[] args) throws IOException {
        MovieCreator mc = new MovieCreator();
        Movie movie1 = mc.build("./test1.mp4");
        Movie movie2 = mc.build("./test2.mp4");
        //Fetching the video tracks from the movies and storing them into an array
        Track[] vetTrackVideo = new Track[0];
        vetTrackVideo = Stream.of(movie1, movie2)
                .flatMap(movie -> movie.getTracks().stream())
                .filter(movie -> movie.getHandler().equals("vide"))
                .collect(Collectors.toList())
                .toArray(vetTrackVideo);
        //Fetching the audio tracks from the movies and storing them into an array
        Track[] vetTrackAudio = new Track[0];
        vetTrackAudio = Stream.of(movie1, movie2)
                .flatMap(movie -> movie.getTracks().stream())
                .filter(movie -> movie.getHandler().equals("soun"))
                .collect(Collectors.toList())
                .toArray(vetTrackAudio);
        //Creating the output movie by setting a list with both video and audio tracks
        Movie movieOutput = new Movie();
        List<Track> listTracks = new ArrayList<>(List.of(new AppendTrack(vetTrackVideo), new AppendTrack(vetTrackAudio)));
        movieOutput.setTracks(listTracks);
        //Building the output movie and storing it into a Container
        DefaultMp4Builder mp4Builder = new DefaultMp4Builder();
        Container c = mp4Builder.build(movieOutput);
        //Writing the output file
        FileOutputStream fos = new FileOutputStream("output.mp4");
        c.writeContainer(fos.getChannel());
        fos.close();
    }
}
Here, I'll leave you also a link to my github repository with the test mp4 files so that you can test the merging sample.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | Arda Kazancı | 
| Solution 2 | Dan | 

