一个简单、朴实、平凡的程序员的编程世界

前话

怎样播放amr音频?这个问题让我好烦恼,在网上找了一些资料,quicktime插件虽然可以播放amr格式的音频,但是不满足项目的要求,html5也不能播放amr格式的音频。后来想到将amr音频转成其他HTML5支持的格式不久行了,后来在网上找到JAVE能转换音频和视频,但是我在转换的过程中老是报如下的异常:

it.sauronsoftware.jave.EncoderException.EncoderException:Duration: N/A, bitrate: N/A上面报的异常让我摸不着头脑,不知道是什么意思,后来经过研究JAVE的源代码发现JAVAE内部其实是使用FFMPEG来进行转换,其实就是用java来调用ffmpeg.exe来进行转换(windows下是ffmpeg.exe文件,linux下是ffmpeg文件),然后通过解析转换过程中的输出语句来获取一些信息。后来我自己在window8下通过命令行来进行转换,能转换成功,而且支持的格式也很多。通过仔细的研究转换过程中输出的语句,我终于找到了产生上面异常的原因:在音频或视频的转换过程中,JAVAE有一段通过正则表达式来获取时长,开始时间和比特率的代码,而该正则表达式不能匹配到。Duration: N/A, bitrate: N/A,而JAVE的这段代码(在it.sauronsoftware.jave.Encoder#public void encode(File source, File target, EncodingAttributes attributes, EncoderProgressListener listener) 中):if (step == 0) {    if (line.startsWith("WARNING: ")) {        if (listener != null) {            listener.message(line);        }    } else if (!line.startsWith("Output #0")) {        throw new EncoderException(line);    } else {        step++;    }}从上面的代码可以看出如果是第0步解析到的某行输出不是以Output #0开头,那么就抛出异常,实际上此时这行的值为Duration: N/A, bitrate: N/A,所以就抛出了如上的异常,从这里也可以看出JAVE是有BUG的:如果通过FFMPEG获取不到时长、开始时间和比特率,那么就会抛出异常,修改上面的配置正则表达式就能修复上面的BUG。实际上JAVE已经很久没维护了,下面进行amr音频格式转换就不使用JAVE,我自己简单的封装一下,可以根据实际的需求进行处理。实现过程

本文是将amr文件转成mp3文件,然后输出到浏览器,思路:通过过滤器拦截以amr结尾的请求,对请求的路径进行处理,获取到文件所在的真实位置,如果文件不存在则让请求通过,如果存在则找同名的mp3文件,如果同名的mp3文件不存在则将amr转成mp3文件,并以相同的名字以mp3为后缀存储。设置相应的类型为MP3的MIME类型,读取mp3文件并输出。

package cn.zq.amrplay.web.filter;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import cn.zq.amrplay.util.AudioUtils;/** * <p>此过滤器用来拦截所有以amr后缀结尾的请求,并转换成mp3流输出,输出<strong>MIME</strong>类型为audio/mpeg。</p> * @author Riccio Zhang * */public class Amr2Mp3Filter implements Filter{/** * mp3扩展名对应的MIME类型,值为"audio/mpeg" */public final static String MP3_MIME_TYPE = "audio/mpeg";public void init(FilterConfig filterConfig) throws ServletException {}public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain)throws IOException, ServletException {HttpServletRequest request;HttpServletResponse response;try {request = (HttpServletRequest) req;response = (HttpServletResponse) resp;} catch (ClassCastException e) {throw new ServletException("non-HTTP request or response");}String requstURI = request.getRequestURI();String contextPath = request.getContextPath();String resPath = requstURI;//去掉requstURI中contextPath部分和参数部分if(contextPath.length() > 0) {resPath = resPath.substring(contextPath.length());}int index = 0;if((index = resPath.lastIndexOf("?")) != -1) {resPath = resPath.substring(0, index);}String resRealPath = req.getServletContext().getRealPath(resPath);String mp3ResRealPath = resRealPath.replaceFirst(".amr$", ".mp3");File mp3File = new File(mp3ResRealPath);if(!mp3File.exists()) {File amrFile = new File(resRealPath);if(!amrFile.exists()) {filterChain.doFilter(request, response);return;}AudioUtils.amr2mp3(amrFile.getAbsolutePath(), mp3File.getAbsolutePath());}response.setContentLength((int)mp3File.length());response.setContentType(MP3_MIME_TYPE);InputStream in = new FileInputStream(mp3File);OutputStream out = response.getOutputStream();try {byte[] buf = new byte[1024];int len = -1;while((len = in.read(buf)) != -1) {out.write(buf, 0, len);}} finally {try {in.close();} catch (Exception e) {e.printStackTrace();}out.flush();}}}上面过滤器的实现与上面的思路是吻合的。谁的指间滑过了千年时光;谁在反反复复中追问可曾遗忘;

一个简单、朴实、平凡的程序员的编程世界

相关文章:

你感兴趣的文章:

标签云: