根據帖子: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
該帖子屬於原創帖子:轉載請貼原帖子的地址,謝謝!