前言
最近在项目中遇到了需要上传音视频文件并读取时长、提取视频声音的需求,在经过一番研究后决定使用ffmpeg。
maven引入
我们需要使用jave-all-deps包来引入ffmpeg,因为ffmpeg在各版本是不兼容的,所以此包包括了windows、mac、linux等系统的ffmpeg。
因此我们需要排除我们所需版本外的其他包。
博主是centos x86_64,所以把除此之外的其他包全部排除掉。
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-all-deps</artifactId>
<version>3.3.1</version>
<exclusions>
<!-- 排除windows 32位系统 -->
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-win32</artifactId>
</exclusion>
<!-- 排除windows 64位系统 -->
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-win64</artifactId>
</exclusion>
<!-- 排除linux 32位系统 -->
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-linux32</artifactId>
</exclusion>
<!-- 排除Mac系统-->
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-osx64</artifactId>
</exclusion>
<!-- 排除osxm-->
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-osxm1</artifactId>
</exclusion>
<!-- 排除arm-->
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-linux-arm32</artifactId>
</exclusion>
<exclusion>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-linux-arm64</artifactId>
</exclusion>
</exclusions>
</dependency>
接下来我们使用ffmpeg在java中实现一下提取音视频时长,视频转音频。
提取音视频时长
public static int readDuration(String url){
try {
MultimediaObject media = new MultimediaObject(new URL(url));
MultimediaInfo info = media.getInfo();
// 时长,毫秒级
long duration = info.getDuration();
// 毫秒级时长转化为秒
BigDecimal bigDecimal1 = new BigDecimal(duration);
BigDecimal bigDecimal2 = new BigDecimal(1000);
// 四舍五入,只保留整数
int time = bigDecimal1.divide(bigDecimal2, 0, RoundingMode.HALF_UP).intValue();
return time;
} catch (Exception e) {
log.error("calculate duration exception;{}",e);
throw new MemoException(BaseResultCode.VIDEO_FORMAT_ERR);
}
}
除了直接传url外,MultimediaObject还有重载方法public MultimediaObject(File input)。
视频转音频
private void video2Audio(String mp4path, String mp3path){
try {
File source = new File(mp4path);
File target = new File(mp3path);
//设置音频流的编码属性
AudioAttributes audio = new AudioAttributes();
//libmp3lame表示使用LAME MP3编码器。LAME是一个开源的MP3编码器,FFmpeg中的libmp3lame就是LAME的实现。
audio.setCodec("libmp3lame");
//在MP3编码中,通常的比特率范围是64 kbps到320 kbps。推荐的范围是128 kbps到256 kbps。较低的比特率会导致音频质量下降,但文件大小更小。
audio.setBitRate(128000);
//1单声道,2立体声
audio.setChannels(2);
//设置音频的采样率为44100Hz。这是CD质量的音频的标准采样率。
audio.setSamplingRate(44100);
//转码属性设置
EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("mp3");
attrs.setAudioAttributes(audio);
//转码
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(source), target, attrs);
} catch (Exception ex) {
...
}
}
音频切片
/**
* 音频文件切分
* @param sourceUrl 原文件url
* @param targetDir 存放目录
* @param interval 切割间隔(s)
* @return
*/
public static List<String> audioSplit(String sourceUrl, String targetDir, float interval){
List<String> list = Lists.newArrayList();
long start = System.currentTimeMillis();
try{
//读取音频时长
int duration = readDuration(sourceUrl);
MultimediaObject multimediaObject = new MultimediaObject(new URL(sourceUrl));
AudioAttributes audio = new AudioAttributes();
EncodingAttributes attrs = new EncodingAttributes();
attrs.setAudioAttributes(audio);
Encoder encoder = new Encoder();
int size = (int) Math.ceil(duration / interval);
File target;
for (int i = 0; i < size; i++) {
String path = StrUtil.format("{}{}.mp3", targetDir, i + 1);
target = new File(path);
//偏移量(从offset秒开始)
attrs.setOffset(i * interval);
if(i < size - 1)
attrs.setDuration(interval);
encoder.encode(multimediaObject, target, attrs);
list.add(path);
}
log.info("audio split success! used: {}ms", System.currentTimeMillis() - start);
}catch (Exception e){
log.error("audio split failed! sourceUrl:{}, targetFile:{}, interval:{}, exception:{}", sourceUrl, targetDir, interval, e);
throw new MemoException(BaseResultCode.SYSTEM_ERR);
}
return list;
}
可能遇到的异常
博主的在centos x86_64位服务器上遇到了ws.schild.jave.InputFormatException错误,本地mac系统却没有,后来经过一番查找是需要安装nscd,以下为具体解决方法:
dnf install nscd
systemctl enable nscd
systemctl start nscd
安装完nscd并启动,上述错误成功解决!