Android多媒体之 wav和amr的互转

1、wav和amr文件都有头文件,AudioRecord录制出来的文件是raw格式的就不能播放,加上wav头文件就变成wav文件就可以播放。

给raw文件添加wav头文件

/** 
	 * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。 
	 * 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav 
	 * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有 
	 * 自己特有的头文件。 
	 */
	private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate, int channels, long byteRate) throws IOException {
		byte[] header = new byte[44];
		header[0] = 'R'; // RIFF/WAVE header  
		header[1] = 'I';
		header[2] = 'F';
		header[3] = 'F';
		header[4] = (byte) (totalDataLen & 0xff);
		header[5] = (byte) ((totalDataLen >> 8) & 0xff);
		header[6] = (byte) ((totalDataLen >> 16) & 0xff);
		header[7] = (byte) ((totalDataLen >> 24) & 0xff);
		header[8] = 'W';
		header[9] = 'A';
		header[10] = 'V';
		header[11] = 'E';
		header[12] = 'f'; // 'fmt ' chunk  
		header[13] = 'm';
		header[14] = 't';
		header[15] = ' ';
		header[16] = 16; // 4 bytes: size of 'fmt ' chunk  
		header[17] = 0;
		header[18] = 0;
		header[19] = 0;
		header[20] = 1; // format = 1  
		header[21] = 0;
		header[22] = (byte) channels;
		header[23] = 0;
		header[24] = (byte) (longSampleRate & 0xff);
		header[25] = (byte) ((longSampleRate >> 8) & 0xff);
		header[26] = (byte) ((longSampleRate >> 16) & 0xff);
		header[27] = (byte) ((longSampleRate >> 24) & 0xff);
		header[28] = (byte) (byteRate & 0xff);
		header[29] = (byte) ((byteRate >> 8) & 0xff);
		header[30] = (byte) ((byteRate >> 16) & 0xff);
		header[31] = (byte) ((byteRate >> 24) & 0xff);
		header[32] = (byte) (2 * 16 / 8); // block align  
		header[33] = 0;
		header[34] = 16; // bits per sample  
		header[35] = 0;
		header[36] = 'd';
		header[37] = 'a';
		header[38] = 't';
		header[39] = 'a';
		header[40] = (byte) (totalAudioLen & 0xff);
		header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
		header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
		header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
		out.write(header, 0, 44);
	}
amr头文件

final private static byte[] header = new byte[]{0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A};

2、wav或raw转amr

     2.1 通过Android系统自带的AmrInputStream类,因为它被隐藏了,只有通过反射来操作。

public class AmrInputStream extends InputStream
{    
    static {
        System.loadLibrary("media");
    }
    
    private final static String TAG = "AmrInputStream";
    
    // frame is 20 msec at 8.000 khz
    private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000;
    
    // pcm input stream
    private InputStream mInputStream;
    
    // native handle
    private int mGae;
    
    // result amr stream
    private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
    private int mBufIn = 0;
    private int mBufOut = 0;
    
    // helper for bytewise read()
    private byte[] mOneByte = new byte[1];
    
    /**
     * Create a new AmrInputStream, which converts 16 bit PCM to AMR
     * @param inputStream InputStream containing 16 bit PCM.
     */
    public AmrInputStream(InputStream inputStream) {
        mInputStream = inputStream;
        mGae = GsmAmrEncoderNew();
        GsmAmrEncoderInitialize(mGae);
    }

    @Override
    public int read() throws IOException {
        int rtn = read(mOneByte, 0, 1);
        return rtn == 1 ? (0xff & mOneByte[0]) : -1;
    }
    
    @Override
    public int read(byte[] b) throws IOException {
        return read(b, 0, b.length);
    }

    @Override
    public int read(byte[] b, int offset, int length) throws IOException {
        if (mGae == 0) throw new IllegalStateException("not open");
        
        // local buffer of amr encoded audio empty
        if (mBufOut >= mBufIn) {
            // reset the buffer
            mBufOut = 0;
            mBufIn = 0;
            
            // fetch a 20 msec frame of pcm
            for (int i = 0; i < SAMPLES_PER_FRAME * 2; ) {
                int n = mInputStream.read(mBuf, i, SAMPLES_PER_FRAME * 2 - i);
                if (n == -1) return -1;
                i += n;
            }
            
            // encode it
            mBufIn = GsmAmrEncoderEncode(mGae, mBuf, 0, mBuf, 0);
        }
        
        // return encoded audio to user
        if (length > mBufIn - mBufOut) length = mBufIn - mBufOut;
        System.arraycopy(mBuf, mBufOut, b, offset, length);
        mBufOut += length;
        
        return length;
    }

    @Override
    public void close() throws IOException {
        try {
            if (mInputStream != null) mInputStream.close();
        } finally {
            mInputStream = null;
            try {
                if (mGae != 0) GsmAmrEncoderCleanup(mGae);
            } finally {
                try {
                    if (mGae != 0) GsmAmrEncoderDelete(mGae);
                } finally {
                    mGae = 0;
                }
            }
        }
    }

    @Override
    protected void finalize() throws Throwable {
        if (mGae != 0) {
            close();
            throw new IllegalStateException("someone forgot to close AmrInputStream");
        }
    }
    
    //
    // AudioRecord JNI interface
    //
    public static native int GsmAmrEncoderNew();
    public static native void GsmAmrEncoderInitialize(int gae);
    public static native int GsmAmrEncoderEncode(int gae,
            byte[] pcm, int pcmOffset, byte[] amr, int amrOffset) throws IOException;
    public static native void GsmAmrEncoderCleanup(int gae);
    public static native void GsmAmrEncoderDelete(int gae);

}

JNI位于源代码下的frameworks\base\media\jni目录,对应的libmedia_jni.so文件文件在system/lib,打开File Exploer就可以看到。

下面是通过反射进行文件转换

 /**
     * 通过反射调用android系统自身AmrInputStream类进行转换
     * @param inPath 源文件
     * @param outPath 目标文件
     */
    public void systemWav2Amr(String inPath,String outPath){
		try {
			FileInputStream fileInputStream = new FileInputStream(inPath);
			FileOutputStream fileoutputStream = new FileOutputStream(outPath);
			// 获得Class
			Class<?> cls = Class.forName("android.media.AmrInputStream");
			// 通过Class获得所对应对象的方法
			Method[] methods = cls.getMethods();
			// 输出每个方法名
			fileoutputStream.write(header);
			Constructor<?> con = cls.getConstructor(InputStream.class);
			Object obj = con.newInstance(fileInputStream);
			for (Method method : methods) {
				Class<?>[] parameterTypes = method.getParameterTypes();
				if ("read".equals(method.getName())
						&& parameterTypes.length == 3) {
					byte[] buf = new byte[1024];
					int len = 0;
					while ((len = (int) method.invoke(obj, buf, 0, 1024)) > 0) {
						fileoutputStream.write(buf, 0, len);
					}
					break;
				}
			}
			for (Method method : methods) {
				if ("close".equals(method.getName())) {
					method.invoke(obj);
					break;
				}
			}
			fileoutputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

2.2 通过开源库opencore进行转换,下面是jni部分

public class AmrEncoder {

    public enum Mode {
        MR475,/* 4.75 kbps */
        MR515,    /* 5.15 kbps */
        MR59,     /* 5.90 kbps */
        MR67,     /* 6.70 kbps */
        MR74,     /* 7.40 kbps */
        MR795,    /* 7.95 kbps */
        MR102,    /* 10.2 kbps */
        MR122,    /* 12.2 kbps */
        MRDTX,    /* DTX       */
        N_MODES   /* Not Used  */
    }

    public static native void init(int dtx);

    public static native int encode(int mode, short[] in, byte[] out);

    public static native void reset();

    public static native void exit();

    static {
        System.loadLibrary("amr-codec");
    }
}

转换操作,里面也有解码的部分

private void wav2amr(final String inpath,final String outpath){
    	//	Random random = new Random();
//		File file = new File(root + "/RawAudio.raw");
//    	file.getAbsolutePath(),root + "/test" + random.nextInt(120) + ".amr"
    	new Thread(new Runnable() {
			@Override
			public void run() {
				convertAMR(inpath,outpath);
			}
		}).start();
    }
    /**
     * 将wav或raw文件转换成amr
     * @param inpath 源文件
     * @param outpath 目标文件
     */
    private void convertAMR(String inpath,String outpath){
    	try {
    		AmrEncoder.init(0);
    		File inFile = new File(inpath);
    		List<short[]> armsList = new ArrayList<short[]>();
			FileInputStream inputStream = new FileInputStream(inFile);
			FileOutputStream outStream = new FileOutputStream(outpath);
			//写入Amr头文件
			outStream.write(header);

			int byteSize = 320;
    		byte[] buff = new byte[byteSize];
			int rc = 0;
			while ((rc = inputStream.read(buff, 0, byteSize)) > 0) {
				short[] shortTemp = new short[160];
				//将byte[]转换成short[]
				ByteBuffer.wrap(buff).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shortTemp);  
				//将short[]转换成byte[] 
//				ByteBuffer.wrap(buff).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(shortTemp);  
				armsList.add(shortTemp);
			}
			 
			for (int i = 0; i < armsList.size(); i++) {
				int size = armsList.get(i).length;
				byte[] encodedData = new byte[size*2];
				int len = AmrEncoder.encode(AmrEncoder.Mode.MR122.ordinal(), armsList.get(i), encodedData);
				if (len>0) {
					byte[] tempBuf = new byte[len];
					System.arraycopy(encodedData, 0, tempBuf, 0, len);
					outStream.write(tempBuf, 0, len);
				}
			}
			AmrEncoder.reset();
			AmrEncoder.exit();
			
			outStream.close();
			inputStream.close();
			System.out.println("convert success ... "+outpath);
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

3、参考资料

Android音频实时传输与播放(三):AMR硬编码与硬解码

https://github.com/kevinho/opencore-amr-android


源码下载


  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: 在Android上将MP3换为WAV格式可以使用以下步骤: 1. 导入所需的库和依赖项。使用Android Studio或其他发环境,在项目的build.gradle文件中添加所需的库和依赖项,例如lame库和ffmpeg库。 2. 创建一个换函数。在Android应用程序的代码中,编写一个函数,该函数接受MP3文件路径作为输入,并将MP3文件换为WAV文件。 3. 解码MP3文件。使用lame库中的函数,将MP3文件解码为原始音频数据。 4. 编码WAV文件。使用ffmpeg库中的函数,将原始音频数据编码为WAV文件。 5. 保存WAV文件。将WAV文件保存到设备的特定位置,例如SD卡或应用程序的私有目录。 以下是一个简单的示例代码,用于将MP3换为WAV格式: ```java import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler; import com.github.hiteshsondhi88.libffmpeg.FFmpeg; import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler; import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException; import com.github.hiteshsondhi88.libffmpeg.exceptions.NoSupportedCodecException; public class MP3toWAVConverter { private FFmpeg ffmpeg; public MP3toWAVConverter() { ffmpeg = FFmpeg.getInstance(context); try { ffmpeg.loadBinary(new LoadBinaryResponseHandler() { @Override public void onStart() {} @Override public void onFailure() { // 处理FFmpeg加载失败的情况 } @Override public void onSuccess() {} @Override public void onFinish() {} }); } catch (FFmpegNotSupportedException e) { // 处理设备不支持FFmpeg的情况 } } public void convertMP3toWAV(String mp3FilePath, String wavFilePath) { String[] command = new String[]{"-i", mp3FilePath, "-acodec", "pcm_s16le", wavFilePath}; try { ffmpeg.execute(command, new ExecuteBinaryResponseHandler() { @Override public void onStart() {} @Override public void onProgress(String message) {} @Override public void onFailure(String message) { // 处理换过程中发生的错误 } @Override public void onSuccess(String message) {} @Override public void onFinish() { // 处理换完成后的操作 } }); } catch (NoSupportedCodecException | FFmpegNotSupportedException e) { // 处理换过程中发生的异常情况 } } } ``` 请注意,上述示例代码中的"com.github.hiteshsondhi88.libffmpeg"是一个第三方库,用于在Android应用程序中使用FFmpeg。确保您在项目的build.gradle文件中包含这个库的依赖项。 这只是一个基本的示例代码,实际的实现可能需要更复杂的处理,例如处理换过程中可能发生的错误和异常。另外,请确保在使用FFmpeg换文件时遵循相关的法律和知识产权规定。 ### 回答2: 要将Android上的MP3文件换为WAV格式,可以通过使用合适的音频换软件来实现。以下是一种简单的方法: 1. 在Android设备上下载并安装一个MP3WAV的应用程序,例如"MP3到WAV换器"。 2. 打应用程序,并选择要换的MP3文件。 3. 进行换设置,例如选择输出文件格式为WAV,选择换的质量和比特率等。 4. 点击"换"按钮换过程。 5. 等待换完成,通常会有一个进度条显示换进度。 6. 换完成后,您可以在指定的输出文件夹中找到换后的WAV文件。 如果您不想使用应用程序,而是希望编程实现MP3到WAV换,您可以使用Android的音频处理API来完成。您可以使用MediaCodec类来解码MP3文件,然后使用AudioTrack类将解码后的音频数据编码为WAV格式,并保存到文件中。 这是一个较为复杂的过程,需要较高的编程技能。您需要研究并了解相关的API和编程技术,以正确实现MP3到WAV换功能。 无论您选择使用应用程序还是编程实现换,都应该牢记换过程可能需要消耗较多的系统资源和时间,特别是对于较大的MP3文件。 ### 回答3: Android上可以使用不同的方法将MP3文件换为WAV文件。以下是一种可行的方法: 首先,你需要在Android设备上安装一个适当的音频换应用程序,比如“MP3WAV换器”或“音频格式换器”。你可以通过在Google Play商店搜索这些应用程序来找到它们,并进行安装。 下载并安装应用程序后,你需要运行它,并选择你想要换的MP3文件。通常,应用程序会提供一个文件浏览器界面,以便你浏览并选择要换的文件。选择你的MP3文件并点击“打”按钮。 接下来,应用程序会问你要换的文件类型。选择“WAV”作为目标文件类型,并点击“换”或“换”按钮。 换过程可能需要一些时间,具体取决于你的MP3文件的大小和你的设备性能。 一旦换完成,你会收到一个确认消息,将包含已成功换为WAV格式的文件的路径。你可以点击“打文件”或类似的按钮来查看换后的WAV文件。 现在,你可以在Android设备上的任何音频播放器中播放WAV文件,以确保换的结果满足你的需求。 请注意,以上只是一种方法,具体可以根据你使用的应用程序而有所不同。还有其他的应用程序和在线工具可以用于将MP3换为WAV,你可以在网络上查找并比较它们的功能和用户评价,选择最适合你的工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值