Linux下搭建基于ffmpeg的jave并且提取视频中的音频

匿名 (未验证) 提交于 2019-12-02 21:59:42


1.安装yasm-1.3.0

cd到解压目录下对进行:

如果提示说缺少"automake-1.15",则在其源码目录执行




2.安装fdk-acc-0.1.6

过程同1.



3.安装配置ffmpeg-4.0(这里一定要使用jave2.0的jar 不然后续使用jave会一直出错)

tar cd之后

执行

make时间较长需要耐心等待

检验是否安装成功:

会出现报错:

/usr/local/ffmpeg/bin/ffmpeg: error while loading shared libraries: libavdevice.so.56: cannot open shared object file: No such file or directory

就是库文件检索不到,因此需要手动修改连接库文件/etc/ld.so.conf

在vim好如上命令之后,接下来使得命令需生效,使用的命令为:

ldconfig

配置环境变量Path,以使得其在所有目录下都可以使用ffmpeg:

检测是否可以再任意目录下进行:



4.使用jave

调用:

    private boolean convertAmr2MP3(File src, File target) {         AudioAttributes audio = new AudioAttributes();         audio.setCodec("libmp3lame");         Encoder encoder = new Encoder();         EncodingAttributes attrs = new EncodingAttributes();         attrs.setFormat("mp3");         attrs.setAudioAttributes(audio);         try {             encoder.encode(src, target, attrs);             return true;         } catch (IllegalArgumentException e) {             e.printStackTrace();         } catch (InputFormatException e) {             e.printStackTrace();         } catch (EncoderException e) {             e.printStackTrace();         }         return false;     }

报错:

it.sauronsoftware.jave.InputFormatException 	at it.sauronsoftware.jave.Encoder.parseMultimediaInfo(Encoder.java:659) 	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:840) 	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:713) 	at com.music.read.MusicFileParser.convertAmr2MP3(MusicFileParser.java:256) 	at com.music.read.MusicFileParser.loadFile(MusicFileParser.java:75) 	at com.music.read.MusicFileParser.access$000(MusicFileParser.java:24) 	at com.music.read.MusicFileParser$1.run(MusicFileParser.java:43) 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 	at java.lang.Thread.run(Thread.java:748)

继续到官网找原因:

Using an alternative ffmpeg executable JAVE is not pure Java: it acts as a wrapper around an ffmpeg (http://ffmpeg.mplayerhq.hu/) executable. ffmpeg is an open source and free software project entirely written in C, so its executables cannot be easily ported from a machine to another. You need a pre-compiled version of ffmpeg in order to run JAVE on your target machine. The JAVE distribution includes two pre-compiled executables of ffmpeg: a Windows one and a Linux one, both compiled for i386/32 bit hardware achitectures. This should be enough in most cases. If it is not enough for your specific situation, you can still run JAVE, but you need to obtain a platform specific ffmpeg executable. Check the Internet for it. You can even build it by yourself getting the code (and the documentation to build it) on the official ffmpeg site. Once you have obtained a ffmpeg executable suitable for your needs, you have to hook it in the JAVE library. That's a plain operation. JAVE gives you an abstract class called it.sauronsoftware.jave.FFMPEGLocator. Extend it. All you have to do is to define the following method:  public java.lang.String getFFMPEGExecutablePath() This method should return a file system based path to your custom ffmpeg executable.  Once your class is ready, suppose you have called it MyFFMPEGExecutableLocator, you have to create an alternate encoder that uses it instead of the default locator:  Encoder encoder = new Encoder(new MyFFMPEGExecutableLocator()) You can use the same procedure also to switch to other versions of ffmpeg, even if you are on a platform covered by the executables bundled in the JAVE distribution.  Anyway be careful and test ever your application: JAVE it's not guaranteed to work properly with custom ffmpeg executables different from the bundled ones.

在官方文档上看了这一段,大意就是说要去ffmpeg的官网下载对应版本的ffmpeg。然后需要自己创建一个类去继承FFMPEGLocator,实现抽象方法,将ffmpeg的路径传JAVE



使用类加载器,获取ffmpeg的真实路经:

public class MyFFMPEGExecute extends FFMPEGLocator {     protected String getFFMPEGExecutablePath() {          String path = MyFFMPEGExecute.class.getResource("/res/ffmpeg").getPath();          return path;     } }

调用方法改为:

    private boolean convertAmr2MP3(File src, File target) {         AudioAttributes audio = new AudioAttributes();         audio.setCodec("libmp3lame");         Encoder encoder = new Encoder(new MyFFMPEGExecute());         EncodingAttributes attrs = new EncodingAttributes();         attrs.setFormat("mp3");         attrs.setAudioAttributes(audio);         try {             encoder.encode(src, target, attrs);             return true;         } catch (IllegalArgumentException e) {             e.printStackTrace();         } catch (InputFormatException e) {             e.printStackTrace();         } catch (EncoderException e) {             e.printStackTrace();         }         return false;     }

运行之后仍然报错:

it.sauronsoftware.jave.EncoderException: Stream mapping: 	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:863) 	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:713) 	at com.music.read.MusicFileParser.convertAmr2MP3(MusicFileParser.java:256) 	at com.music.read.MusicFileParser.loadFile(MusicFileParser.java:75) 	at com.music.read.MusicFileParser.access$000(MusicFileParser.java:24) 	at com.music.read.MusicFileParser$1.run(MusicFileParser.java:43) 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 	at java.lang.Thread.run(Thread.java:748)

这下就尴尬了,都是都是按照要求来实现的啊?怎么就不行呢?


看来还是得翻墙,后来找到一个更新版本的jave的jar包。JAVE官网最新的版本发布日期是2009年!所以可能是这个原因


加入新的jar包后重新编译运行,仍然报错。但这此报的异常又变了,感觉有希望

Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory 	at java.net.URLClassLoader.findClass(URLClassLoader.java:381) 	at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) 	at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 	... 8 more

从异常来看,最新的jave依赖了commons-logging,加上这个:

   <dependency>             <groupId>commons-logging</groupId>             <artifactId>commons-logging</artifactId>             <version>1.2</version>         </dependency>

但是这方案不建议使用,使用maven添加依赖在非maven项目下比较麻烦,因此建议使用commons-logging-1.2.jar

此中间还出现了一个插曲,如果提示ClassDefNotFound,很有可能是你的路径包含有中文名字


最后根据实际项目需求写了一个获取目录下所有的视频文件,在上一层目录建立一个新的文件夹下,把原来要转换的视频转换到这里。

import it.sauronsoftware.jave.AudioAttributes; import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.EncodingAttributes; import it.sauronsoftware.jave.FFMPEGLocator;  import java.io.File; import java.util.ArrayList; import java.util.List;  import banger.video.EncryptUtil; public class Main {  	public static void main(String[] args) { 		// TODO Auto-generated method stub 		String filePath="/Users/hackjeremy/Desktop/env/1/"; 		String videoType=".avi"; 		System.out.println( 				Main.work(Main.getFileList(filePath,videoType), videoType));	 	} 	 	public static String work(List<File>filelist,String fileType){ 		long startTime = System.currentTimeMillis(); // 获取开始时间 		String newFloderPath=""; 		if(filelist.size()>0){ 			String []temp=(filelist.get(0)+"").split("/"); 			for(int i=0;i<temp.length-1;i++){ 				if(temp[i].length()>0){ 					newFloderPath+=("/"+temp[i]); 				} 			} 		}else{ 			return ""; 		} 		newFloderPath+="_finish/"; 		 		List<String>filename=new ArrayList<String>();//目录下所有要处理的文件名字 不含后缀名 		for(int i=0;i<filelist.size();i++){ 			String []t=filelist.get(i).toString().split("/"); 			String []tt=t[t.length-1].split(fileType); 			filename.add(tt[0]); 		} 		 		List<String>filename_cast=new ArrayList<String>(); 		if(createDir(newFloderPath)){ 			for(int i=0;i<filelist.size();i++){ 				try { 					String castFilePath=newFloderPath+filename.get(i).toString()+"_cast"+fileType; 					filename_cast.add(castFilePath); 					EncryptUtil.encryFile(filelist.get(i).toString(),castFilePath); 					File source = new File(filename_cast.get(i)); 					File target = new File(newFloderPath+filename.get(i).toString()+"_finish"+".wav"); 					AudioAttributes audio = new AudioAttributes(); 					audio.setCodec("pcm_s16le"); 					audio.setChannels(new Integer(2)); 					EncodingAttributes attrs = new EncodingAttributes(); 					attrs.setFormat("wav"); 					attrs.setAudioAttributes(audio); 					Encoder encoder = new Encoder(new MyFFMPEGExecute()); 					encoder.encode(source, target, attrs); 				} catch (Exception e) { 					// TODO Auto-generated catch block 					e.printStackTrace(); 					System.out.println("cast error"); 				} 			} 			 			for(int i=0;i<filename_cast.size();i++){//删除转换后的视频 				if(!deleteFile(filename_cast.get(i).toString())){ 					return ""; 				} 			} 		}else{ 			return ""; 		} 		long endTime = System.currentTimeMillis(); // 获取结束时间 		System.out.println("run time:" + (endTime - startTime) + "ms"); 		return newFloderPath; 	} 	 	 	public static boolean deleteFile(String fileName) {         File file = new File(fileName);         // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除         if (file.exists() && file.isFile()) {             if (file.delete()) {                 System.out.println("删除单个文件" + fileName + "成功!");                 return true;             } else {                 System.out.println("删除单个文件" + fileName + "失败!");                 return false;             }         } else {             System.out.println("删除单个文件失败:" + fileName + "不存在!");             return false;         }     }  	 	public static boolean createDir(String destDirName) {           File dir = new File(destDirName);           if (dir.exists()) {               System.out.println("创建目录" + destDirName + "失败,目标目录已经存在");               return false;           }           if (!destDirName.endsWith(File.separator)) {               destDirName = destDirName + File.separator;           }           //创建目录           if (dir.mkdirs()) {               System.out.println("创建目录" + destDirName + "成功!");               return true;           } else {               System.out.println("创建目录" + destDirName + "失败!");               return false;           }       }    	public static List<File> getFileList(String strPath,String fileType) {         File dir = new File(strPath);         List<File>filelist=new ArrayList<File>();         File[] files = dir.listFiles();          if (files != null) {             for (int i = 0; i < files.length; i++) {                 String fileName = files[i].getName();                 if (files[i].isDirectory()) {                      getFileList(files[i].getAbsolutePath(),fileType);                  } else if (fileName.endsWith(fileType)) {                      String strFileName = files[i].getAbsolutePath();                     filelist.add(files[i]);                 } else {                     continue;                 }             }         }         return filelist;     } }
初试文件为:


控制台输出为:


运行之后的视频转换如下:


看某个视频简略图:


完全没有任何问题

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!