功能介绍

https://github.com/sannies/mp4parser

Java MP4 Parser是一个读取和写入MP4容器的java api。直接操作容器而不是对音视频进行编解码。

功能:

  • MP4parser的典型功能如下:
  • 混合音频视频到MP4文件中
  • 合并同样编码设置的MP4文件
  • 增加或者改变MP4文件的metadata
  • 通过省略帧的方式分割MP4文件

例子采用的音频编码格式是H264和AAC,这两种格式对于MP4文件来说非常常见。当然也有AC-3格式的,以及并不常用的H263/MPEG-2视频轨道。

不能把两个编码格式不同的MP4文件进行合并。

项目使用

项目集成

在gradle中添加依赖

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

视频合并

File sdDir;if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {sdDir = Environment.getExternalStorageDirectory();}else{sdDir = Environment.getDataDirectory().getParentFile();}String sdpath = sdDir.getAbsolutePath();//获取指定图片路径String v0 = sdpath + File.separator + "1.mp4";String v1 = sdpath + File.separator + "2.mp4";final ArrayList<String> strings = new ArrayList<>();strings.add(v0);strings.add(v1);final File mergeVideoFile = new File(sdpath + File.separator + "merge.mp4");findViewById(R.id.tv_1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String s = Mp4ParserUtils.mergeVideo(strings, mergeVideoFile);Toast.makeText(Mp4PaserActivity.this, "合并成功" + s, Toast.LENGTH_LONG).show();}});

视频分割

        final double [] times = {0,3};  //剪切1~3秒final String srcVideoPath = sdpath + File.separator + "merge.mp4";final String resVideoPath = sdpath + File.separator;findViewById(R.id.tv_2).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {try {Mp4ParserUtils.cutVideo(srcVideoPath, resVideoPath, times);Toast.makeText(Mp4PaserActivity.this, "剪切成功", Toast.LENGTH_LONG).show();} catch (IOException e) {}}});

工具类

package com.dianping.test;import android.content.Context;import com.coremedia.iso.boxes.Container;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import com.googlecode.mp4parser.authoring.tracks.AppendTrack;
import com.googlecode.mp4parser.authoring.tracks.CroppedTrack;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;public class Mp4ParserUtils {/*** 合并视频** @param videoList* @param mergeVideoFile* @return*/public static String mergeVideo(ArrayList<String> videoList, File mergeVideoFile) {FileOutputStream fos = null;FileChannel fc = null;try {List<Movie> sourceMovies = new ArrayList<>();for (String video : videoList) {sourceMovies.add(MovieCreator.build(video));}List<Track> videoTracks = new LinkedList<>();List<Track> audioTracks = new LinkedList<>();for (Movie movie : sourceMovies) {for (Track track : movie.getTracks()) {if ("soun".equals(track.getHandler())) {audioTracks.add(track);}if ("vide".equals(track.getHandler())) {videoTracks.add(track);}}}Movie mergeMovie = new Movie();if (audioTracks.size() > 0) {mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));}if (videoTracks.size() > 0) {mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));}Container out = new DefaultMp4Builder().build(mergeMovie);fos = new FileOutputStream(mergeVideoFile);fc = fos.getChannel();out.writeContainer(fc);fc.close();fos.close();return mergeVideoFile.getAbsolutePath();} catch (Exception e) {e.printStackTrace();} finally {if (fc != null) {try {fc.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}return null;}/*** 剪切视频* @param srcVideoPath* @param dstVideoPath* @param times* @throws IOException*/public static void cutVideo(String srcVideoPath, String dstVideoPath, double[] times) throws IOException {int dstVideoNumber = times.length / 2;String[] dstVideoPathes = new String[dstVideoNumber];for (int i = 0; i < dstVideoNumber; i++) {dstVideoPathes[i] = dstVideoPath + "cutOutput-" + i + ".mp4";}int timesCount = 0;for (int idst = 0; idst < dstVideoPathes.length; idst++) {//Movie movie = new MovieCreator().build(new RandomAccessFile("/home/sannies/suckerpunch-distantplanet_h1080p/suckerpunch-distantplanet_h1080p.mov", "r").getChannel());Movie movie = MovieCreator.build(srcVideoPath);List<Track> tracks = movie.getTracks();movie.setTracks(new LinkedList<Track>());// remove all tracks we will create new tracks from the olddouble startTime1 = times[timesCount];double endTime1 = times[timesCount + 1];timesCount = timesCount + 2;boolean timeCorrected = false;// Here we try to find a track that has sync samples. Since we can only start decoding// at such a sample we SHOULD make sure that the start of the new fragment is exactly// such a framefor (Track track : tracks) {if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {if (timeCorrected) {// This exception here could be a false positive in case we have multiple tracks// with sync samples at exactly the same positions. E.g. a single movie containing// multiple qualities of the same video (Microsoft Smooth Streaming file)throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");}startTime1 = correctTimeToSyncSample(track, startTime1, false);endTime1 = correctTimeToSyncSample(track, endTime1, true);timeCorrected = true;}}for (Track track : tracks) {long currentSample = 0;double currentTime = 0;double lastTime = -1;long startSample1 = -1;long endSample1 = -1;for (int i = 0; i < track.getSampleDurations().length; i++) {long delta = track.getSampleDurations()[i];if (currentTime > lastTime && currentTime <= startTime1) {// current sample is still before the new starttimestartSample1 = currentSample;}if (currentTime > lastTime && currentTime <= endTime1) {// current sample is after the new start time and still before the new endtimeendSample1 = currentSample;}lastTime = currentTime;currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale();currentSample++;}//movie.addTrack(new AppendTrack(new ClippedTrack(track, startSample1, endSample1), new ClippedTrack(track, startSample2, endSample2)));movie.addTrack(new CroppedTrack(track, startSample1, endSample1));}long start1 = System.currentTimeMillis();Container out = new DefaultMp4Builder().build(movie);long start2 = System.currentTimeMillis();FileOutputStream fos = new FileOutputStream(String.format(dstVideoPathes[idst]));FileChannel fc = fos.getChannel();out.writeContainer(fc);fc.close();fos.close();long start3 = System.currentTimeMillis();}}private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) {double[] timeOfSyncSamples = new double[track.getSyncSamples().length];long currentSample = 0;double currentTime = 0;for (int i = 0; i < track.getSampleDurations().length; i++) {long delta = track.getSampleDurations()[i];if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) {// samples always start with 1 but we start with zero therefore +1timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime;}currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale();currentSample++;}double previous = 0;for (double timeOfSyncSample : timeOfSyncSamples) {if (timeOfSyncSample > cutHere) {if (next) {return timeOfSyncSample;} else {return previous;}}previous = timeOfSyncSample;}return timeOfSyncSamples[timeOfSyncSamples.length - 1];}}

局限性

只支持MP4文件
经过尝试对于一些MP4文件分割不了
功能比较少
目前点评有采用这种方案做视频的合并

mp4parser库相关推荐

  1. java如何将mp4写入光盘_iOS - 读取/写入mp4视频的XMP元数据

    我需要在mp4容器中读取并注入XMP元数据 . 我知道这可以在Android上使用"mp4parser"库,但我找不到iOS的等价物 . 对于读取部分,是否可以从相机胶卷读取每个素 ...

  2. Windows API参考大全

    第一章 Win32 API概论 1.1为什么使用 Wu32 API 在Windows程序设计领域处于发展初期时,Windows程序员可使用的编程工具唯有API 函数.这些函数在程序员手中犹如" ...

  3. Android 3分钟一个库搞定视频替换音频 视频合成 视频裁剪(高仿剪映)

    几种框架的比较: https://www.zhihu.com/question/278431860 方法一(Fail) 利用MediaMux实现音视频的合成. 效果:可以实现音视频的合并,利用Andr ...

  4. github中的常用库

    awesome-android 原文链接:http://snowdream.github.io/awesome-android/#UI android libs from github Downloa ...

  5. Android 使用 mp4parser 做视频拼接合并

    做短视频拍摄时,在分段录制结束需要将多个视频片段拼接成一个视频文件,然后进入预览界面播放. 有两种方案: 方案一:使用 FFMpeg 进行视频拼接,命令如下: // inputListFilePath ...

  6. Android 使用 mp4parser 做视频裁剪

    做音视频时我们很多时候需要做音视频裁剪,本文介绍使用开源库 mp4parser 做裁剪. 视频合并请见我的另外一篇博客<Android 使用 mp4parser 做视频拼接合并> 使用时先 ...

  7. Go 编译的可执行文件是否有动态库链接?

    Go 引用了其他包的话,是将引用的包都编译进去.用 ldd 看几个 Go 编译出来的二进制程序有的没有动态链接库的使用.但是有的又有引用动态链接库,这个是为什么? 回答:Go 默认是开启 CGO_EN ...

  8. Go 学习笔记(78)— Go 标准库 net/http 创建服务端(接收 GET、POST 请求)

    使用 net/http 标准库创建一个 http 的 restful api 的服务端,用来处理 GET.POST 等请求. 源代码如下: package mainimport ("enco ...

  9. Go 知识点(12) — 类型转换以三方库 cast

    类型转换在编程语言中是很常见的操作,在 Go 语言中其类型转换有下面一些注意点. 1. 整数类型之间的转换 对于整数类型转换,原则上目标类型的取值范围要包含被转换值,也就是说要转换类型的值取值范围要小 ...

  10. Go 学习笔记(72)— Go 第三方库之 pkg/errors 带堆栈的错误处理

    包 github.com/pkg/errors 让开发人员很容易在 error 错误信息上带上堆栈信息,可以更快更准确定位错误,例如行号等信息. 如果项目代码比较复杂,且经常需要追踪 Bug,建议使用 ...

最新文章

  1. 深入JDK源码,这里总有你不知道的知识点!
  2. LinkedIn工程经理眼中的数据世界格局
  3. 程序员必备的七大面向对象设计原则(三)
  4. 搭建Keras,TensorFlow运行环境
  5. Spring boot的put请求
  6. VTK:Points之ExtractSurface
  7. C# HttpWebRequest提交数据方式
  8. oracle之三手工不完全恢复
  9. 痴人、信徒、先驱:深度学习三巨头等口述神经网络复兴史
  10. [Angular Tutorial] 3-Components
  11. 简单工厂模式初步尝试
  12. python判断题题库大数据技术_智慧树_大数据分析的python基础_判断题答案
  13. Docker安装加速器
  14. 今日得闲,完善一下之前用python画的滑稽笑脸的代码,附计算过程
  15. 桌面的计算机图标误删了怎么恢复,删除桌面图标-如何恢复桌面图标不小心将某个程序的桌面图标给删了,怎么恢复呢 爱问知识人...
  16. dplayer + m3u8+ p2p加速
  17. 【交换机】交换机简介
  18. 海康威视py和c++调用全(超精髓,亲测)
  19. 【UI学习】Android github开源项目,酷炫自定义控件(View)汇总
  20. 组内相关系数intraclass correlation(ICC)

热门文章

  1. 小米五怎么设置锁屏显示无服务器,小米手机怎么设置锁屏状态下不能关机 - 卡饭网...
  2. SAP FI月结 坏账转移及计提准备 Doubtful Receivables Bad Debts
  3. Android强大的控件——RecyclerView
  4. 主流注意力机制介绍以及如何添加到YOLOV5
  5. Building the main Guest Additions module [failed]
  6. 前端学习笔记之——使用边框和背景
  7. codeforces Dima and Trap Graph
  8. Java项目(前端vue后台java微服务)在线考试系统(java+vue+springboot+mysql+maven)
  9. 防骗指南-QQ微信仿冒诈骗
  10. oracle11g64跟32,plsql32 位连接oracle11g64位方法