方法一(Fail)

利用MediaMux实现音视频的合成。

效果:可以实现音视频的合并,利用Android原生的VideoView和SurfaceView播放正常,大部分的播放器也播放正常,但是,但是,在上传Youtube就会出现问题:音频不连续,分析主要是上传Youtube时会被再次的压缩,可能在压缩的过程中出现音频的帧率出现问题。


 


方法二

利用mp4parser实现

mp4parser是一个视频处理的开源工具箱,由于mp4parser里的方法都依靠工具箱里的一些内容,所以需要将这些内容打包成jar包,放到自己的工程里,才能对mp4parser的方法进行调用。

 

 

方法三

利用FFmpeg大法

FFmpeg 由于其丰富的 codec 插件,详细的文档说明,并且与其调试复杂量大的编解码代码(是的,用 MediaCodec 实现起来十分啰嗦和繁琐)还是不如调试一行 ffmpeg 命令来的简单。


实现步骤:


1.添加依赖


implementation 'com.googlecode.mp4parser:isoparser:1.1.21'


2.视频裁剪

/**
 * 裁剪视频
 * @param srcPath 需要裁剪的原视频路径
 * @param outPath 裁剪后的视频输出路径
 * @param startTimeMs 裁剪的起始时间
 * @param endTimeMs 裁剪的结束时间
 */
public static void clip(String srcPath, String outPath, double startTimeMs, double endTimeMs) throws IOException, IllegalArgumentException {
    if (TextUtils.isEmpty(srcPath) || TextUtils.isEmpty(outPath)) {
        throw new IllegalArgumentException("file path can't be null!!!!");
    }
    if (!(new File(srcPath).exists())) {
        throw new IllegalArgumentException("the source file is not exist!!!!");
    }
    if (startTimeMs >= endTimeMs) {
        throw new IllegalArgumentException("the startTimeMs is larger than endTimeMs!!!!");
    }
    Movie movie = MovieCreator.build(srcPath);
    List<Track> tracks = movie.getTracks();
    //移除旧的track
    movie.setTracks(new LinkedList<Track>());
    //处理的时间以秒为单位
    double startTime = startTimeMs/1000;
    double endTime = endTimeMs/1000;
    YDLog.logDebeg(TAG, "--->>>>startTimeMs = " + startTimeMs + "\n endTimeMs = " + endTimeMs + "\n tracks.size = " + tracks.size());
    //计算剪切时间,视频的采样间隔大,以视频为准
    for (Track track : tracks) {
        if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
            startTime = correctTimeToSyncSample(track, startTime, false);
            endTime = correctTimeToSyncSample(track, endTime, true);
            if (track.getHandler().equals("vide")) {
                break;
            }
        }
    }
    YDLog.logDebeg(TAG, "--->>>>startTime = " + startTime + "\n endTime = " + endTime);

    long currentSample;
    double currentTime;
    double lastTime;
    long startSample1;
    long endSample1;
    long delta;

    for (Track track : tracks) {
        currentSample = 0;
        currentTime = 0;
        lastTime = -1;
        startSample1 = -1;
        endSample1 = -1;

        //根据起始时间和截止时间获取起始sample和截止sample的位置
        for (int i = 0; i < track.getSampleDurations().length; i++) {
            delta = track.getSampleDurations()[i];
            if (currentTime > lastTime && currentTime <= startTime) {
                startSample1 = currentSample;
            }
            if (currentTime > lastTime && currentTime <= endTime) {
                endSample1 = currentSample;
            }
            lastTime = currentTime;
            currentTime += (double)delta / (double)track.getTrackMetaData().getTimescale();
            currentSample++;
        }
        Log.d(TAG, "track.getHandler() = " + track.getHandler() + "\n startSample1 = " + startSample1 + "\n endSample1 = " + endSample1);
        if (startSample1 <= 0 && endSample1 <= 0) {
            throw new RuntimeException("clip failed !!");
        }
        movie.addTrack(new CroppedTrack(track, startSample1, endSample1));// 添加截取的track
    }

    //合成视频mp4
    Container out = new DefaultMp4Builder().build(movie);
    FileOutputStream fos = new FileOutputStream(outPath);
    FileChannel fco = fos.getChannel();
    out.writeContainer(fco);
    fco.close();
    fos.close();
}


3.视频合成

/**
 * 将 AAC 和 MP4 进行混合[替换了视频的音轨]
 *
 * @param aacPath .aac
 * @param mp4Path .mp4
 * @param outPath .mp4
 */
public static boolean muxAacMp4(String aacPath, String mp4Path, String outPath) {
    try {
        AACTrackImpl aacTrack = new AACTrackImpl(new FileDataSourceImpl(aacPath));
        Movie videoMovie = MovieCreator.build(mp4Path);
        Track videoTracks = null;// 获取视频的单纯视频部分
        for (Track videoMovieTrack : videoMovie.getTracks()) {
            if ("vide".equals(videoMovieTrack.getHandler())) {
                videoTracks = videoMovieTrack;
            }
        }

        Movie resultMovie = new Movie();
        resultMovie.addTrack(videoTracks);// 视频部分
        resultMovie.addTrack(aacTrack);// 音频部分

        Container out = new DefaultMp4Builder().build(resultMovie);
        FileOutputStream fos = new FileOutputStream(new File(outPath));
        out.writeContainer(fos.getChannel());
        fos.close();
    } catch (Exception e) {
        e.printStackTrace();
    }


    return true;
}


4.合成音视频长度不一样的问题

/***
 * 把视频裁剪15s。然后和音频合并。然后再裁剪15s
 * @param sdCardPath
 */
public static void getMergeVideo(String sdCardPath) {
    String srcMergePath = sdCardPath + "/4.mp4";//录屏文件
    String aacPath = sdCardPath + "/5.aac";
    Log.d("peng", "onClick:  aacPath" + aacPath);
    String outMergePath = sdCardPath + "/6.mp4";//得到临时的合成的视频文件
    Log.d("peng", "onClick:  outMergePath" + outMergePath);

    long startTime = 0;
    long endTime = 15 * 1000;

    boolean isMux =  VideoClipUtils.muxAacMp4(aacPath, srcMergePath, outMergePath);

    if (isMux) {
        String outMergeClipPath = sdCardPath + "/7.mp4";
        Log.d("peng", "onClick:  outMergeClipPath" + outMergeClipPath);

        try {
            VideoClipUtils.clip(outMergePath, outMergeClipPath, startTime, endTime);
            Log.d("peng", "OKKKKKKKK");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


 


遇到的问题:


1.音频和视频合成,他们的长度


     要以视频为准的


2.合成音视频的格式,是否支持,2种方案



方案一:


先全部合并,然后再裁剪15s


方案二:(没有声音)


把视频裁剪15s。然后和音频合并。然后再裁剪15s


方案三:(导致有视频不一定有声音,或者有声音不一定有视频)


视频剪切,音频剪切,音频和视频合并


 


 


方法一:

MediaMuxer文件生成:

官方文档:

https://developer.android.google.cn/reference/android/media/MediaMuxer?hl=zh-cn

=========================================================

mp4方案:

 

http://blog.chinaunix.net/uid-20771867-id-4114253.html

 

使用map4parser作为视频处理包,android studio引入 compile 'com.googlecode.mp4parser:isoparser:1.1.21'//视频处理

 

2017年4月10日更新:

我发现该框架还有诸多问题和BUG,比如无法合并不同格式(帧率,分辨率)的视频,最近已改用MediaCodec,如果需要做一些比较复杂的处理,还是推荐使用MediaCodec和FFmpeg,后面有时间我会写一写相关的内容。

 

Android 使用 mp4parser 做视频裁剪

 

 

mp4parser (所有的用法-----可以)

https://www.jianshu.com/p/c87ada9b0f65

 

不错的库:

 

https://github.com/sannies/mp4parser

 

 

Android(java方法)上实现mp4的分割和拼接 (二)