package lzf.video.edit.decoder; import android.util.Log; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; /** * 目前只能对相同采样率,通道和采样精度的音频进行混音 * @author Darcy */ public abstract class MultiAudioMixer { private OnAudioMixListener mOnAudioMixListener; public static MultiAudioMixer createAudioMixer(){ return new AverageAudioMixer(); } public void setOnAudioMixListener(OnAudioMixListener l){ this.mOnAudioMixListener = l; } /** * <p>start to mix , you can call {@link #setOnAudioMixListener(OnAudioMixListener)} before this method to get mixed data. */ public void mixAudios(File[] rawAudioFiles){ final int fileSize = rawAudioFiles.length; FileInputStream[] audioFileStreams = new FileInputStream[fileSize]; File audioFile = null; FileInputStream inputStream; byte[][] allAudioBytes = new byte[fileSize][]; boolean[] streamDoneArray = new boolean[fileSize]; byte[] buffer = new byte[512]; int offset; try { for (int fileIndex = 0; fileIndex < fileSize; ++fileIndex) { audioFile = rawAudioFiles[fileIndex]; audioFileStreams[fileIndex] = new FileInputStream(audioFile); } while(true){ for(int streamIndex = 0 ; streamIndex < fileSize ; ++streamIndex){ inputStream = audioFileStreams[streamIndex]; if(!streamDoneArray[streamIndex] && (offset = inputStream.read(buffer)) != -1){ allAudioBytes[streamIndex] = Arrays.copyOf(buffer,buffer.length); }else{ streamDoneArray[streamIndex] = true; allAudioBytes[streamIndex] = new byte[512]; } } byte[] mixBytes = mixRawAudioBytes(allAudioBytes); if(mixBytes != null && mOnAudioMixListener != null){ mOnAudioMixListener.onMixing(mixBytes); } boolean done = true; for(boolean streamEnd : streamDoneArray){ if(!streamEnd){ done = false; } } if(done){ if(mOnAudioMixListener != null) mOnAudioMixListener.onMixComplete(); break; } } } catch (IOException e) { e.printStackTrace(); if(mOnAudioMixListener != null) mOnAudioMixListener.onMixError(1); }finally{ try { for(FileInputStream in : audioFileStreams){ if(in != null) in.close(); } } catch (IOException e) { e.printStackTrace(); } } } abstract byte[] mixRawAudioBytes(byte[][] data); public interface OnAudioMixListener{ /** * invoke when mixing, if you want to stop the mixing process, you can throw an AudioMixException * @param mixBytes * @throws AudioMixException */ void onMixing(byte[] mixBytes) throws IOException; void onMixError(int errorCode); /** * invoke when mix success */ void onMixComplete(); } public static class AudioMixException extends IOException{ private static final long serialVersionUID = -1344782236320621800L; public AudioMixException(String msg){ super(msg); } } /** * 平均值算法 * @author Darcy */ private static class AverageAudioMixer extends MultiAudioMixer{ @Override byte[] mixRawAudioBytes(byte[][] bMulRoadAudioes) { if (bMulRoadAudioes == null || bMulRoadAudioes.length == 0) return null; byte[] realMixAudio = bMulRoadAudioes[0]; if(bMulRoadAudioes.length == 1) return realMixAudio; for(int rw = 0 ; rw < bMulRoadAudioes.length ; ++rw){ if(bMulRoadAudioes[rw].length != realMixAudio.length){ Log.e("app", "column of the road of audio + " + rw +" is diffrent."); return null; } } int row = bMulRoadAudioes.length; int coloum = realMixAudio.length / 2; short[][] sMulRoadAudioes = new short[row][coloum]; for (int r = 0; r < row; ++r) { for (int c = 0; c < coloum; ++c) { sMulRoadAudioes[r][c] = (short) ((bMulRoadAudioes[r][c * 2] & 0xff) | (bMulRoadAudioes[r][c * 2 + 1] & 0xff) << 8); } } short[] sMixAudio = new short[coloum]; int mixVal; int sr = 0; for (int sc = 0; sc < coloum; ++sc) { mixVal = 0; sr = 0; for (; sr < row; ++sr) { mixVal += sMulRoadAudioes[sr][sc]; } sMixAudio[sc] = (short) (mixVal / row); } for (sr = 0; sr < coloum; ++sr) { realMixAudio[sr * 2] = (byte) (sMixAudio[sr] & 0x00FF); realMixAudio[sr * 2 + 1] = (byte) ((sMixAudio[sr] & 0xFF00) >> 8); } return realMixAudio; } } }