Android 使用mp4parser进行视频的分割与合并

mp4parser 是一个优秀的视频处理框架,下面就教大家使用mp4parser在android上进行视频的分割与合并。


2017年4月10日更新:

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


FFmpeg框架EpMedia



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等。


猜你喜欢

转载自blog.csdn.net/u012027644/article/details/53885837