1. 程式人生 > >MAC OS下使用JAVE將amr轉mp3的坑

MAC OS下使用JAVE將amr轉mp3的坑

由於專案需求,需要將android手機上的錄音檔案上傳到後臺,可是在android上的錄音都是amr格式的,在mac上無法播放。直接android上轉碼又不太好實現。於是這個工作交給後端來實現。

JAVE是基於ffmpeg的很強大的轉碼工具。下載地址 http://www.sauronsoftware.it/projects/jave/download.php

下載了最新的1.0.2版本,載入到工程中。呼叫方法:

    private boolean convertAmr2MP3(File src, File target) {
        AudioAttributes audio = new AudioAttributes();
        audio.setCodec("libmp3lame");
        Encoder encoder = new Encoder();
        EncodingAttributes attrs = new EncodingAttributes();
        attrs.setFormat("mp3");
        attrs.setAudioAttributes(audio);
        try {
            encoder.encode(src, target, attrs);
            return true;
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InputFormatException e) {
            e.printStackTrace();
        } catch (EncoderException e) {
            e.printStackTrace();
        }
        return false;
    }

發現報錯:
it.sauronsoftware.jave.InputFormatException
	at it.sauronsoftware.jave.Encoder.parseMultimediaInfo(Encoder.java:659)
	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:840)
	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:713)
	at com.music.read.MusicFileParser.convertAmr2MP3(MusicFileParser.java:256)
	at com.music.read.MusicFileParser.loadFile(MusicFileParser.java:75)
	at com.music.read.MusicFileParser.access$000(MusicFileParser.java:24)
	at com.music.read.MusicFileParser$1.run(MusicFileParser.java:43)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

繼續到官網找原因:
Using an alternative ffmpeg executable
JAVE is not pure Java: it acts as a wrapper around an ffmpeg (http://ffmpeg.mplayerhq.hu/) executable. ffmpeg is an open source and free software project entirely written in C, so its executables cannot be easily ported from a machine to another. You need a pre-compiled version of ffmpeg in order to run JAVE on your target machine. The JAVE distribution includes two pre-compiled executables of ffmpeg: a Windows one and a Linux one, both compiled for i386/32 bit hardware achitectures. This should be enough in most cases. If it is not enough for your specific situation, you can still run JAVE, but you need to obtain a platform specific ffmpeg executable. Check the Internet for it. You can even build it by yourself getting the code (and the documentation to build it) on the official ffmpeg site. Once you have obtained a ffmpeg executable suitable for your needs, you have to hook it in the JAVE library. That's a plain operation. JAVE gives you an abstract class called it.sauronsoftware.jave.FFMPEGLocator. Extend it. All you have to do is to define the following method:

public java.lang.String getFFMPEGExecutablePath()
This method should return a file system based path to your custom ffmpeg executable.

Once your class is ready, suppose you have called it MyFFMPEGExecutableLocator, you have to create an alternate encoder that uses it instead of the default locator:

Encoder encoder = new Encoder(new MyFFMPEGExecutableLocator())
You can use the same procedure also to switch to other versions of ffmpeg, even if you are on a platform covered by the executables bundled in the JAVE distribution.

Anyway be careful and test ever your application: JAVE it's not guaranteed to work properly with custom ffmpeg executables different from the bundled ones.

在官方文件上看了這一段,大意就是說要去ffmpeg的官網下載對應版本的ffmpeg。然後需要自己建立一個類去繼承FFMPEGLocator,實現抽象方法,將ffmpeg的路徑傳JAVE

我下載的是這個MAC版



使用類載入器,獲取ffmpeg的真實路經

public class MyFFMPEGExecute extends FFMPEGLocator {
    protected String getFFMPEGExecutablePath() {

        String path = MyFFMPEGExecute.class.getResource("/res/ffmpeg").getPath();

        return path;
    }
}

呼叫方法改為:
    private boolean convertAmr2MP3(File src, File target) {
        AudioAttributes audio = new AudioAttributes();
        audio.setCodec("libmp3lame");
        Encoder encoder = new Encoder(new MyFFMPEGExecute());
        EncodingAttributes attrs = new EncodingAttributes();
        attrs.setFormat("mp3");
        attrs.setAudioAttributes(audio);
        try {
            encoder.encode(src, target, attrs);
            return true;
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InputFormatException e) {
            e.printStackTrace();
        } catch (EncoderException e) {
            e.printStackTrace();
        }
        return false;
    }

執行之後仍然報錯:
it.sauronsoftware.jave.EncoderException: Stream mapping:
	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:863)
	at it.sauronsoftware.jave.Encoder.encode(Encoder.java:713)
	at com.music.read.MusicFileParser.convertAmr2MP3(MusicFileParser.java:256)
	at com.music.read.MusicFileParser.loadFile(MusicFileParser.java:75)
	at com.music.read.MusicFileParser.access$000(MusicFileParser.java:24)
	at com.music.read.MusicFileParser$1.run(MusicFileParser.java:43)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

這下就尷尬了,都是都是按照要求來實現的啊?怎麼就不行呢?

看來還是得翻牆,後來找到一個更新版本的jave的jar包。JAVE官網最新的版本釋出日期是2009年!所以可能是這個原因

加入新的jar包後重新編譯執行,仍然報錯。但這此報的異常又變了,感覺有希望

Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 8 more
從異常來看,最新的jave依賴了commons-logging,加上這個:
   <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
再次編譯執行,這次就沒有再報錯了:
Dec 29 10:44:57  java[2994] <Error>: CGAffineTransformInvert: singular matrix.
Dec 29, 2017 10:45:13 AM it.sauronsoftware.jave.Encoder parseMultimediaInfo
WARNING: Output line: ffmpeg version 3.4.1-tessus Copyright (c) 2000-2017 the FFmpeg developers
Dec 29, 2017 10:45:13 AM it.sauronsoftware.jave.Encoder parseMultimediaInfo
WARNING: Output line:   built with Apple LLVM version 8.0.0 (clang-800.0.42.1)
Dec 29, 2017 10:45:13 AM it.sauronsoftware.jave.Encoder parseMultimediaInfo
WARNING: Output line:   configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libass --enable-libbluray --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzmq --enable-libzvbi --enable-version3 --pkg-config-flags=--static --disable-ffplay
Dec 29, 2017 10:45:13 AM it.sauronsoftware.jave.Encoder parseMultimediaInfo
WARNING: Output line:   libavutil      55. 78.100 / 55. 78.100
Dec 29, 2017 10:45:13 AM it.sauronsoftware.jave.Encoder parseMultimediaInfo
WARNING: Output line:   libavcodec     57.107.100 / 57.107.100

看,對應的MP3檔案已經生成了。


可以正常播放,音質還不錯。除了能轉amr還可以轉其其它的很多格式。

在網上搜來搜去,都是轉載別人文章,而且就是簡單的幾行呼叫程式碼。很少有人寫相關的總結,所以決定寫個入坑過程,給真正需要的朋友。

最後,附上最新的jave的jar檔案以及MAC版的ffmpeg下載地址:點選開啟連結