kotlin 如何在Java中使用jcodec将多个mp4视频组合成一个视频?

tf7tbtn2  于 2023-01-26  发布在  Kotlin
关注(0)|答案(2)|浏览(239)

我有多个mp4文件,它们是整个mp4文件的一部分。它们只是被分割成更小的文件。
我想用Java中的jcodec将这些文件以编程方式组合成一个mp4文件,目前我使用以下代码来完成此操作:

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();
    }
}

不幸的是,它不工作,因为生成的视频不包含音频文件,也不包含正确的帧。例如,我得到的所有视觉帧都像下面这样:

问题是什么,我该如何解决?非常感谢。

omtl5h9j

omtl5h9j1#

您可以使用ffmpeg来完成此操作。
1.首先,您需要将文件路径写入txt文件
txt文件:

  • 文件“/sdcard/视频/视频1.mp4”
  • 文件“/sdcard/视频/视频2.mp4”
  • 文件“/sdcard/视频/视频3.mp4”
  • 文件“/sdcard/视频/视频4.mp4”

您可以使用以下命令。

ffmpeg -f concat -i mp4list.txt -c:v copy -c:a copy merging.mp4

1.你可以在Java代码上写一个 Package 器,另外,你可以使用下面的代码。
帮助资源: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(){
        }
    }
kmb7vmvb

kmb7vmvb2#

我不是很了解jcodec,但是我以前用过MP4parser,如果你需要合并mp4文件,不管是什么库,那么我向你推荐这个。我只是向你推销它,因为我不知道你在合并文件时是否会因为库的复杂性而遇到问题。也许值得一试。MP4 Parser非常简单明了。我“我还会给您留下到maven存储库的链接。
https://search.maven.org/artifact/com.googlecode.mp4parser/isoparser/1.1.22/jar
这里有一个我已经完成的实现来向你展示如何合并来自同一个原始视频的两个文件(复制你的情况),基本上,你有一个Movie类,它代表你的mp4文件,包含一个ListTrack(只有2个);一个表示视频而另一个表示音频。
1.首先,我从电影中收集了两个独立数组中的所有视频和音频轨道。
1.然后,我用合并的音频Track和合并的视频Track创建了一个List,以便将其设置为输出文件。
1.最后,我在Container中构建了Movie,并将其保存在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();
    }
}

在这里,我也会给你一个链接到我的github存储库,里面有测试mp4文件,这样你就可以测试合并示例了。
https://github.com/daniele-aveta/MP4Merger

相关问题