根据帖子:http://blog.csdn.net/z313731418/article/details/50218341 的提示,在linux安装ffmpeg,确实在linux下使用命令可以将amr转成mp3,并且可以进行播放,不过使用编译的jave-1.0.2.jar进行转化的时候,目录下生成了mp3文件并没有变大反而变小(windows下转码会变大,不过代码会报错,不过转化的mp3是可以播放的),发现mp3不能正常播放。项目代码抛出异常如下:
经过项目组的老大的指引:
使用反编译软件查看了该jar的源代码,查找 “ Stream mapping:(linux下出现的)” 和 “Duration: N/A, bitrate: N/A(windows下出现)”对应的源代码如下:
原因分析:
可以确定的一点最后都是拼接成命令:/tmp/jave-1/ffmpeg -i 源文件路径 -f mp3 -y 输出路径 让amr变成mp3
都抛出异常,不过windows下的文件确实转化成功,并且可以播放。根据转化之后的mp3文件的大小判断,可能是异常处理导致写入文件操作被迫中断了。
综合这些分析之后,决定对源代码的异常处理进行修改,重新修改jar包再进行打包。
解决方案:
将 public void encode(File source, File target, EncodingAttributes attributes, EncoderProgressListener listener){}这个方法里面的try的处理读取的异常处理代码进行重写
public void encode(File source, File target, EncodingAttributes attributes, EncoderProgressListener listener) throws IllegalArgumentException, InputFormatException, EncoderException { String formatAttribute = attributes.getFormat(); Float offsetAttribute = attributes.getOffset(); Float durationAttribute = attributes.getDuration(); AudioAttributes audioAttributes = attributes.getAudioAttributes(); VideoAttributes videoAttributes = attributes.getVideoAttributes(); if ((audioAttributes == null) && (videoAttributes == null)) { throw new IllegalArgumentException( "Both audio and video attributes are null"); } target = target.getAbsoluteFile(); target.getParentFile().mkdirs(); FFMPEGExecutor ffmpeg = this.locator.createExecutor(); if (offsetAttribute != null) { ffmpeg.addArgument("-ss"); ffmpeg.addArgument(String.valueOf(offsetAttribute.floatValue())); } ffmpeg.addArgument("-i"); ffmpeg.addArgument(source.getAbsolutePath()); if (durationAttribute != null) { ffmpeg.addArgument("-t"); ffmpeg.addArgument(String.valueOf(durationAttribute.floatValue())); } if (videoAttributes == null) { ffmpeg.addArgument("-vn"); } else { String codec = videoAttributes.getCodec(); if (codec != null) { ffmpeg.addArgument("-vcodec"); ffmpeg.addArgument(codec); } String tag = videoAttributes.getTag(); if (tag != null) { ffmpeg.addArgument("-vtag"); ffmpeg.addArgument(tag); } Integer bitRate = videoAttributes.getBitRate(); if (bitRate != null) { ffmpeg.addArgument("-b"); ffmpeg.addArgument(String.valueOf(bitRate.intValue())); } Integer frameRate = videoAttributes.getFrameRate(); if (frameRate != null) { ffmpeg.addArgument("-r"); ffmpeg.addArgument(String.valueOf(frameRate.intValue())); } VideoSize size = videoAttributes.getSize(); if (size != null) { ffmpeg.addArgument("-s"); ffmpeg.addArgument(String.valueOf(size.getWidth()) + "x" + String.valueOf(size.getHeight())); } } if (audioAttributes == null) { ffmpeg.addArgument("-an"); } else { String codec = audioAttributes.getCodec(); if (codec != null) { ffmpeg.addArgument("-acodec"); ffmpeg.addArgument(codec); } Integer bitRate = audioAttributes.getBitRate(); if (bitRate != null) { ffmpeg.addArgument("-ab"); ffmpeg.addArgument(String.valueOf(bitRate.intValue())); } Integer channels = audioAttributes.getChannels(); if (channels != null) { ffmpeg.addArgument("-ac"); ffmpeg.addArgument(String.valueOf(channels.intValue())); } Integer samplingRate = audioAttributes.getSamplingRate(); if (samplingRate != null) { ffmpeg.addArgument("-ar"); ffmpeg.addArgument(String.valueOf(samplingRate.intValue())); } Integer volume = audioAttributes.getVolume(); if (volume != null) { ffmpeg.addArgument("-vol"); ffmpeg.addArgument(String.valueOf(volume.intValue())); } } ffmpeg.addArgument("-f"); ffmpeg.addArgument(formatAttribute); ffmpeg.addArgument("-y"); ffmpeg.addArgument(target.getAbsolutePath()); try { ffmpeg.execute(); } catch (IOException e) { throw new EncoderException(e); } try { String lastWarning = null; long progress = 0L; RBufferedReader reader = null; reader = new RBufferedReader(new InputStreamReader( ffmpeg.getErrorStream())); MultimediaInfo info = parseMultimediaInfo(source, reader); long duration; long duration; if (durationAttribute != null) { duration = Math.round(durationAttribute.floatValue() * 1000.0F); } else { duration = info.getDuration(); if (offsetAttribute != null) { duration = duration - Math.round(offsetAttribute.floatValue() * 1000.0F); } } if (listener != null) { listener.sourceInfo(info); } int step = 0; String line; while ((line = reader.readLine()) != null) { String line; if (step == 0) { if (line.startsWith("WARNING: ")) { if (listener != null) listener.message(line); } else { if (!line.startsWith("Output #0")) { throw new EncoderException(line); } step++; } } else if ((step == 1) && (!line.startsWith(" "))) { step++; } if (step == 2) { if (!line.startsWith("Stream mapping:")) { throw new EncoderException(line); } step++; } else if ((step == 3) && (!line.startsWith(" "))) { step++; } if (step == 4) { line = line.trim(); if (line.length() > 0) { Hashtable table = parseProgressInfoLine(line); if (table == null) { if (listener != null) { listener.message(line); } lastWarning = line; } else { if (listener != null) { String time = (String)table.get("time"); if (time != null) { int dot = time.indexOf('.'); if ((dot > 0) && (dot == time.length() - 2) && (duration > 0L)) { String p1 = time.substring(0, dot); String p2 = time.substring(dot + 1); try { long i1 = Long.parseLong(p1); long i2 = Long.parseLong(p2); progress = i1 * 1000L + i2 * 100L; int perm = (int)Math.round(progress * 1000L / duration); if (perm > 1000) { perm = 1000; } listener.progress(perm); } catch (NumberFormatException localNumberFormatException) { } } } } lastWarning = null; } } } } if ((lastWarning == null) || (SUCCESS_PATTERN.matcher(lastWarning).matches())) break label1089; throw new EncoderException(lastWarning); } catch (IOException e) { throw new EncoderException(e); } finally { jsr 6; } localObject1 = returnAddress; ffmpeg.destroy(); ret; label1089: jsr -9; } }
上述中的异常处理部分代码进行封装,保证不修改源代码。增加如下方法:
protected void processErrorOutput(EncodingAttributes attributes, BufferedReader errorReader, File source, EncoderProgressListener listener) throws EncoderException, IOException { String lastWarning = null; long progress = 0L; Float offsetAttribute = attributes.getOffset(); MultimediaInfo info = parseMultimediaInfo(source, (RBufferedReader)errorReader); Float durationAttribute = attributes.getDuration(); long duration; long duration; if (durationAttribute != null) { duration = Math.round(durationAttribute.floatValue() * 1000.0F); } else { duration = info.getDuration(); if (offsetAttribute != null) { duration -= Math.round(offsetAttribute.floatValue() * 1000.0F); } } if (listener != null) { listener.sourceInfo(info); } int step = 0; String line; while ((line = errorReader.readLine()) != null) { if (step == 0) { if (line.startsWith("WARNING: ")) { if (listener != null) listener.message(line); } else { if (!line.startsWith("Output #0")) { throw new EncoderException(line); } step++; } } else if ((step == 1) && (!line.startsWith(" "))) { step++; } if (step == 2) { if (!line.startsWith("Stream mapping:")) { throw new EncoderException(line); } step++; } else if ((step == 3) && (!line.startsWith(" "))) { step++; } if (step == 4) { line = line.trim(); if (line.length() > 0) { Hashtable table = parseProgressInfoLine(line); if (table == null) { if (listener != null) { listener.message(line); } lastWarning = line; } else { if (listener != null) { String time = (String)table.get("time"); if (time != null) { int dot = time.indexOf(46); if ((dot > 0) && (dot == time.length() - 2) && (duration > 0L)) { String p1 = time.substring(0, dot); String p2 = time.substring(dot + 1); try { long i1 = Long.parseLong(p1); long i2 = Long.parseLong(p2); progress = i1 * 1000L + i2 * 100L; int perm = (int)Math.round(progress * 1000L / duration); if (perm > 1000) { perm = 1000; } listener.progress(perm); } catch (NumberFormatException e) { } } } } lastWarning = null; } } } } if ((lastWarning != null) && (!SUCCESS_PATTERN.matcher(lastWarning).matches())) throw new EncoderException(lastWarning); } }
将encode方法的中相同的代码修改成调用processErrorOutput(attributes, reader, source, listener); 修改之后的源代码:
public void encode(File source, File target, EncodingAttributes attributes, EncoderProgressListener listener) throws IllegalArgumentException, InputFormatException, EncoderException { FFMPEGExecutor ffmpeg = this.locator.createExecutor(); setAttributes(attributes, ffmpeg, source, target); try { ffmpeg.execute(); } catch (IOException e) { throw new EncoderException(e); } try { RBufferedReader reader = new RBufferedReader(new InputStreamReader(ffmpeg.getErrorStream())); processErrorOutput(attributes, reader, source, listener); } catch (IOException e) { throw new EncoderException(e); } finally { ffmpeg.destroy(); } }
实际上jar包并没有修改啥,只是把异常处理的代码进行抽离成一个方法processErrorOutput而已。
最终实现代码:
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import it.sauronsoftware.jave.*; /** * 音频工具类 */ public class AudioUtil { private static Logger logger = LoggerFactory.getLogger(AudioUtil.class); /** * Amr格式音频转为Mp3格式 * * @param sourcePath * amr格式源路径 * * @param targetPath * mp3格式输出路径 * * @example getAmrConversionMp3("D:\test\04296548.amr","D:\test\04296548.mp3"); * */ public static void getAmrConversionMp3(String sourcePath, String targetPath) { File source = new File(sourcePath); File target = new File(targetPath); AudioAttributes audio = new AudioAttributes(); AmrToMp3Encoder encoder = new AmrToMp3Encoder(); audio.setCodec("libmp3lame"); EncodingAttributes attrs = new EncodingAttributes(); attrs.setFormat("mp3"); attrs.setAudioAttributes(audio); try { encoder.encode(source, target, attrs); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InputFormatException e) { e.printStackTrace(); } catch (EncoderException e) { e.printStackTrace(); } } /** * 判断文件是不是amr格式 * * @param fileName 文件名 * */ public static boolean isAudioAmr(String fileName) { String tmpName = fileName.toLowerCase(); return tmpName.endsWith(".amr"); } private static class AmrToMp3Encoder extends Encoder { protected void processErrorOutput(EncodingAttributes attributes, BufferedReader errorReader, File source, EncoderProgressListener listener) throws EncoderException, IOException { // 屏蔽默认的错误处理 try { String line; while ((line = errorReader.readLine()) != null) { logger.debug(line); } } catch (Exception exp) { logger.error("file convert error message process failed. ", exp); } } } }
结论:
编写AmrToMp3Encoder类继承Encoder,并重写方法processErrorOutput,将默认的方法里面的异常方法全部屏蔽,通过单元测试发现,在linux下和windows下都不会抛出异常,
而且转化的mp3格式均可以播放。可能真的是这个jar包还存在着bug。该结果是在客观事实中进行求证,如有不对之处,请留下评论,大家一起探讨一下,而且ffmpeg这个文件需要进行替换处理,使用你所在linux环境的ffmpeg。修改jar包的源代码已经贴上了。
不想手动的同学可以直接下载:
链接: https://pan.baidu.com/s/1c2FAp8k 密码: fmx3
该帖子属于原创帖子:转载请贴原帖子的地址,谢谢!