zoukankan      html  css  js  c++  java
  • 解决linux AMR转MP3出现转码成功却无法播放的问题

    根据帖子: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

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

  • 相关阅读:
    leetcode之String to Integer (atoi)
    初次思考
    leetcode之Reverse Words in a String
    Leetcode之Database篇
    在项目中添加类
    创建项目
    配置Eclipse

    递归
    多态
  • 原文地址:https://www.cnblogs.com/fennudexiaofan/p/7577671.html
Copyright © 2011-2022 走看看