解決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

該帖子屬於原創帖子:轉載請貼原帖子的地址,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM