mp4parser 是一个优秀的视频处理框架,下面就教大家使用mp4parser在android上进行视频的分割与合并。
2017年4月10日更新:
我发现该框架还有诸多问题和BUG,比如无法合并不同格式(帧率,分辨率)的视频,最近已改用MediaCodec,如果需要做一些比较复杂的处理,还是推荐使用MediaCodec和FFmpeg,后面有时间我会写一写相关的内容。
Github:https://github.com/sannies/mp4parser\
Gradle:
dependencies { compile 'com.googlecode.mp4parser:isoparser:1.1.21' }
视频的分割:
public class VideoClip { private String filePath;//视频路径 private String workingPath;//输出路径 private String outName;//输出文件名 private double startTime;//剪切起始时间 private double endTime;//剪切结束时间 private void clip() { try { Movie movie = MovieCreator.build(filePath); List<Track> tracks = movie.getTracks(); movie.setTracks(new LinkedList<Track>()); //移除旧的通道 boolean timeCorrected = false; //计算剪切时间 for (Track track : tracks) { if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { if (timeCorrected) { throw new RuntimeException( "The startTime has already been corrected by another track with SyncSample. Not Supported."); } startTime = VideoHelper.correctTimeToSyncSample(track, startTime, false); endTime = VideoHelper.correctTimeToSyncSample(track, endTime, true); timeCorrected = true; } } for (Track track : tracks) { long currentSample = 0; double currentTime = 0; double lastTime = 0; long startSample1 = -1; long endSample1 = -1; for (int i = 0; i < track.getSampleDurations().length; i++) { long 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++; } movie.addTrack(new CroppedTrack(track, startSample1, endSample1));// new } //合成视频mp4 Container out = new DefaultMp4Builder().build(movie); File storagePath = new File(workingPath); storagePath.mkdirs(); FileOutputStream fos = new FileOutputStream(new File(storagePath, outName)); FileChannel fco = fos.getChannel(); out.writeContainer(fco); fco.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } }
视频的合并:
public class VideoMerge { private String workingPath;//输出文件目录 private ArrayList<String> videosToMerge;//需要合并的视频的路径集合 private String outName;//输出的视频名称 private void merge(){ int count = videosToMerge.size(); try { Movie[] inMovies = new Movie[count]; for (int i = 0; i < count; i++) { inMovies[i] = MovieCreator.build(videosToMerge.get(i)); } List<Track> videoTracks = new LinkedList<>(); List<Track> audioTracks = new LinkedList<>(); //提取所有视频和音频的通道 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); } if (t.getHandler().equals("")) { } } } //添加通道到新的视频里 Movie result = new Movie(); if (audioTracks.size() > 0) { result.addTrack(new AppendTrack(audioTracks .toArray(new Track[audioTracks.size()]))); } if (videoTracks.size() > 0) { result.addTrack(new AppendTrack(videoTracks .toArray(new Track[videoTracks.size()]))); } Container mp4file = new DefaultMp4Builder() .build(result); //开始生产mp4文件 File storagePath = new File(workingPath); storagePath.mkdirs(); FileOutputStream fos = new FileOutputStream(new File(storagePath,outName)); FileChannel fco = fos.getChannel(); mp4file.writeContainer(fco); fco.close(); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
里面用到的VideoHelper:
public class VideoHelper { //换算剪切时间 public 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) { timeOfSyncSamples[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]; } }
视频的分割与合并也可以用其他方法例如:ffmpeg,MediaCodec等。