How convert audio raw to flac in Android

2019-06-27 23:08发布

问题:

I recording audio with class audoiRecord. Now I want convert audio raw file to *flac format. I convert *raw file to wav next way:

private void copyWaveFile(String inFilename,String outFilename){
    FileInputStream in = null;
    FileOutputStream out = null;
    long totalAudioLen = 0;
    long totalDataLen = totalAudioLen + 36;
    long longSampleRate = sampleRate;
    int channels = 2;
    long byteRate = RECORDER_BPP * sampleRate * channels/8;
    byte[] data_pcm = new byte[mAudioBufferSize];
    try {
        in = new FileInputStream(inFilename);
        out = new FileOutputStream(outFilename);
        totalAudioLen = in.getChannel().size();
        totalDataLen = totalAudioLen + 36;
        Log.i(TAG,"File size: " + totalDataLen);
        WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
        longSampleRate, channels, byteRate);
        while(in.read(data_pcm) != -1){
            out.write(data_pcm);
        }
        in.close();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

This piece of code is responsible for the file header

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] = RECORDER_BPP;  // 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);
}

I do not understand what should be the parameters of the *flac file

回答1:

You need an encoder to convert pcm data to flac format. You cannot just change the header and expect the content to work as flac.

Android (at least till 4.1) does not include a FLAC encoder, although there is a decoder supported from 3.1 onwards (Source: http://developer.android.com/guide/appendix/media-formats.html).

I do not have direct experience, but have seen people use ffmpeg as a flac encoder. This project audioboo-android, which contains the native libFLAC/libFLAC++ encoder, looks interesting.



回答2:

Here's a pure java FLAC encoder: http://javaflacencoder.sourceforge.net

Some of the classes use the javax apis, but they can be safely deleted without affecting the main encoder classes.

Here's some sample code. The record object is of type AudioRecord

try {
                    // Path to write files to
                    String path = Environment.getExternalStoragePublicDirectory("/test").getAbsolutePath();

                    String fileName = name+".flac";
                    String externalStorage = path;
                    File file = new File(externalStorage + File.separator + fileName);

                    // if file doesnt exists, then create it
                    if (!file.exists()) {
                        file.createNewFile();
                    }
                    short sData[] = new short[BufferElements2Rec];

                    FileOutputStream os = null;
                    try {
                        os = new FileOutputStream(file);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }


                    FLACEncoder flacEncoder = new FLACEncoder();
                    StreamConfiguration streamConfiguration = new StreamConfiguration(1,StreamConfiguration.MIN_BLOCK_SIZE,StreamConfiguration.MAX_BLOCK_SIZE,44100,16);

                    FLACFileOutputStream flacOut = new FLACFileOutputStream(os);
                    flacEncoder.setStreamConfiguration(streamConfiguration);
                    flacEncoder.setOutputStream(flacOut);
                    flacEncoder.openFLACStream();


                    record.startRecording();

                    int totalSamples = 0;

                    while (isRecording) {
                        record.read(sData, 0, BufferElements2Rec);
                        totalSamples+=BufferElements2Rec;

                        flacEncoder.addSamples(short2int(sData),BufferElements2Rec);

                        flacEncoder.encodeSamples(BufferElements2Rec, false);
                    }

                    int available = flacEncoder.samplesAvailableToEncode();
                    while(flacEncoder.encodeSamples(available,true) < available) {
                        available = flacEncoder.samplesAvailableToEncode();
                    }
                    try {
                        flacOut.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    record.stop();
                } catch(IOException ex) {
                    ex.printStackTrace();

                }

                record.release();
                record = null;
}

For converting the short data into int data:

private int[] short2int(short[] sData) {
    int length = sData.length;
    int[] iData = new int[length];
    for(int i=0;i<length;i++) {
        iData[i] = sData[i];
    }
    return iData;
}