You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android Studio使用mp4parser合并视频出现黑屏有声音问题求助

解决mp4parser拼接不同MP4视频后黑屏有声音的问题

嘿,我之前也碰到过mp4parser拼接视频时黑屏但声音正常的情况,和你说的一模一样——同一段视频拼接完全没问题,换不同视频就翻车。大概率是两个视频的视频轨道参数不匹配导致的,比如分辨率、帧率、编码格式(甚至H.264的profile/level)不一样,播放器没法正确解析拼接后的视频帧,就只能出声音黑屏了。

先给你拆解下问题,再给几个可行的解决方案:

第一步:排查视频轨道参数是否一致

首先得确认两个视频的视频轨道参数是否完全匹配,这是最核心的问题。你可以在代码里加几行打印,快速查看关键参数:

for (Movie m : inMovies) {
    for (Track t : m.getTracks()) {
        if (t.getHandler().equals("soun")) {
            audioTracks.add(t);
        }
        if (t.getHandler().equals("vide")) {
            videoTracks.add(t);
            // 打印关键参数,方便排查
            System.out.println("视频分辨率: " + t.getWidth() + "x" + t.getHeight());
            VisualSampleEntry visualEntry = (VisualSampleEntry) t.getSampleDescriptionBox().getBoxes().get(0);
            System.out.println("编码格式: " + visualEntry.getCodec());
            System.out.println("时间基准(timescale): " + t.getTimescale());
        }
    }
}

如果输出里两个视频的分辨率、编码格式或者timescale不一样,那就是问题根源了。

第二步:针对参数不匹配的解决方案

方案1:统一视频参数后再拼接

mp4parser本身不支持转码,所以你需要先把第二个视频转成和第一个视频参数完全一致的MP4,再用你的原有代码拼接。在Android上可以用MediaCodec实现转码,或者选择避免了text relocations问题的轻量转码库。

方案2:手动统一视频轨道的SampleDescription(仅兼容场景可用)

如果两个视频的编码格式高度兼容(比如都是H.264,只是细微参数不同),可以尝试把第二个视频轨道的SampleDescription替换成第一个的,让播放器用统一的参数解析所有帧。修改你代码里添加视频轨道的部分:

if (videoTracks.size() > 0) {
    // 取第一个视频轨道作为基准,复用它的SampleDescription
    Track baseVideoTrack = videoTracks.get(0);
    List<Track> adjustedVideoTracks = new LinkedList<>();
    adjustedVideoTracks.add(baseVideoTrack);

    for (int i = 1; i < videoTracks.size(); i++) {
        Track currentTrack = videoTracks.get(i);
        // 创建自定义Track,替换SampleDescription为基准轨道的
        Track adjustedTrack = new Track() {
            @Override
            public List<Sample> getSamples() {
                return currentTrack.getSamples();
            }

            @Override
            public SampleDescriptionBox getSampleDescriptionBox() {
                return baseVideoTrack.getSampleDescriptionBox();
            }

            @Override
            public String getHandler() {
                return currentTrack.getHandler();
            }

            @Override
            public List<Edit> getEdits() {
                return currentTrack.getEdits();
            }

            @Override
            public long getDuration() {
                return currentTrack.getDuration();
            }

            @Override
            public long getTimescale() {
                return currentTrack.getTimescale();
            }

            @Override
            public String getName() {
                return currentTrack.getName();
            }

            @Override
            public Type getType() {
                return currentTrack.getType();
            }
        };
        adjustedVideoTracks.add(adjustedTrack);
    }

    // 用调整后的轨道拼接
    result.addTrack(new AppendTrack(adjustedVideoTracks.toArray(new Track[adjustedVideoTracks.size()])));
}

注意:这个方法只适用于编码格式高度兼容的情况,如果分辨率差异大,可能会出现画面拉伸或者依然黑屏的情况。

方案3:处理时间基准(timescale)不匹配的问题

如果两个视频的timescale不一样,拼接后的时间轴会混乱,也可能导致黑屏。你需要把第二个轨道的timescale调整成和第一个一致,同时按比例修改duration:

// 在方案2的基础上,添加timescale调整
long baseTimescale = baseVideoTrack.getTimescale();
long currentTimescale = currentTrack.getTimescale();
if (currentTimescale != baseTimescale) {
    long adjustedDuration = (currentTrack.getDuration() * baseTimescale) / currentTimescale;
    // 修改自定义Track的duration和timescale
    Track adjustedTrack = new Track() {
        // ... 其他方法不变
        @Override
        public long getDuration() {
            return adjustedDuration;
        }

        @Override
        public long getTimescale() {
            return baseTimescale;
        }
    };
    adjustedVideoTracks.add(adjustedTrack);
}

额外检查:轨道的Edit列表

有些视频轨道会包含Edit信息(比如用于裁剪、变速),如果两个视频的Edit列表不一致,也可能导致播放异常。你可以在代码里打印currentTrack.getEdits(),如果不是空的,可能需要统一处理或者清空Edit列表。

先试试第一步的参数排查,大部分情况下都是参数不匹配的问题,解决了这个应该就能正常播放了。

内容的提问来源于stack exchange,提问作者Darkhmar

火山引擎 最新活动