Android 关于使用videocompressor库压缩没有声音和异常的问题
原库地址
https://gitcode.com/gh_mirrors/vi/VideoCompressor/overview
这个库用起来比较方便,使用Android原生的MediaCodec
+mp4parser
的方式进行压缩,不用接入so库也不用适配cpu
问题
接口库后你会发现过时了,所以你一阵捣鼓后你发现压缩正常但是输出文件没有声音,问题是什么?经过我一天的修改,问题是因为你升级了mp4parser
库他接入的是com.googlecode.mp4parser:isoparser:1.0.6
不论你升级到什么版本都会出现没有声音的问题,那是因为谷歌的问题,在1.0.6后在编码的时候更加严格,所以你不升级就ok了!
真的不升级?
随着时间的发展旧版本库无法满足需求,性能各方面都是差异,而且这是7年前的库了,所以你必须升级,那么怎么解决问题呢?
分析问题
问题代码
在1.0.6库之前和之后主要的出现问题代码就在createMovie
中的创建FileChannel
的问题,1.0.6支持你FileOutputStream.getChannel()
这样创建但是1.0.6之后不可以这样,这样就会导致音视频无法同步,所以你需要更换创建方法:new RandomAccessFile(destinationPath, "rw").getChannel()
其中destinationPath
输出文件地址修改了这一行你会发现好了
其他解决思路
这个库的压缩思路:
-
获取视频的
track
,然后利用MediaCodec
对原视频进行解码 -
获取原视频的宽高、帧率等,进行一定的比例缩放
-
在利用
MediaCodec
进行视频编码,输出一个只有视频没有声音的文件 -
在利用相同的方式获取音频的
track
,然后读取音频读写 -
最后对音视频进行合并,他是再同一个输出文件上读写的
-
完结
所以根据上面思路你完全可以分开 -
先利用
MediaCodec
对视频进行压缩,输出到缓存目标文件A -
在读取原文件的音频
-
合并两个文件,输出到真正的目录B,这里不可以和缓存目标文件A相同,必须不同的文件
把思路简化下代码大概是这样,是不是很简单,其实思路就这么点代码
public static void appendMp4List(Context context, Uri sourcePath, String outPutPath) throws Exception {
VideoInfo videoInfo = VideoUtils.getVideoInfo(context, sourcePath);
if (videoInfo == null || videoInfo.width() == 0 || videoInfo.height() == 0) {
return;
}
File tempFile = VideoUtils.copyFileToCacheDir(context, sourcePath);
List<Track> audioTracks = new LinkedList<>();// 音频通道集合
List<Track> videoTracks = new LinkedList<>();// 视频通道集合
for (Track inMovieTrack : MovieCreator.build(tempFile.getAbsolutePath()).getTracks()) {
if ("soun".equals(inMovieTrack.getHandler())) {// 从Movie对象中取出音频通道
audioTracks.add(inMovieTrack);
}
if ("vide".equals(inMovieTrack.getHandler())) {// 从Movie对象中取出视频通道
videoTracks.add(inMovieTrack);
}
}
Movie resultMovie = new Movie();// 结果Movie对象[输出]
if (!videoTracks.isEmpty()) {// 将所有视频通道追加合并
writerVideo(tempFile,videoInfo,outPutPath);//压缩视频,但这样输出的只有视频没有音频
List<Track> resultVideoTrack = MovieCreator.build(outPutPath).getTracks();
for(Track videoTrack:resultVideoTrack){
resultMovie.addTrack(videoTrack);
}
}
if (!audioTracks.isEmpty()) {// 将所有音频通道追加合并
resultMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
Container outContainer = new DefaultMp4Builder().build(resultMovie);// 将结果Movie对象封装进容器
FileChannel fileChannel = new RandomAccessFile(outPutPath, "rw").getChannel();
outContainer.writeContainer(fileChannel);// 将容器内容写入磁盘
fileChannel.close();
}
最终的优化有的代码查看github
https://github.com/fzkf9225/mvvm-componnent-master/tree/master/commonmedia/src/main/java/pers/fz/media/videocompressor