解决linux AMR转MP3出现转码成功却无法播放的问题

时间:2023-03-09 06:36:38
解决linux AMR转MP3出现转码成功却无法播放的问题

根据帖子:http://blog.****.net/z313731418/article/details/50218341  的提示,在linux安装ffmpeg,确实在linux下使用命令可以将amr转成mp3,并且可以进行播放,不过使用编译的jave-1.0.2.jar进行转化的时候,目录下生成了mp3文件并没有变大反而变小(windows下转码会变大,不过代码会报错,不过转化的mp3是可以播放的),发现mp3不能正常播放。项目代码抛出异常如下:

解决linux AMR转MP3出现转码成功却无法播放的问题

经过项目组的老大的指引:

       使用反编译软件查看了该jar的源代码,查找  “ Stream mapping:(linux下出现的)” 和 “Duration: N/A, bitrate: N/A(windows下出现)”对应的源代码如下:

解决linux AMR转MP3出现转码成功却无法播放的问题

解决linux AMR转MP3出现转码成功却无法播放的问题

原因分析:

可以确定的一点最后都是拼接成命令:/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

该帖子属于原创帖子:转载请贴原帖子的地址,谢谢!