如何在Android中将WAV / OGG文件转换为FLAC文件?

时间:2012-03-16 06:47:19

标签: android wav ogg flac

编辑:纳入更改后的uv001答案。

我只能发现ICS 4.0支持FLAC解码,但编码。我需要一些编码器将wav转换为flac,但是当前我找不到它。我发现有一个jFlac avaible,但我不知道如何使用这个库,只是简单地转换文件。

有人能帮我一把吗?

今天,我自己也有点想法,使用JavaFlacEncoder。 它适用于WAV的某些比特率。

我将值更改为现在正在运行的硬编码值。

/*
 * Copyright (C) 2010  Preston Lacey http://javaflacencoder.sourceforge.net/
 * All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package javaFlacEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import java.io.IOException;
/**
 * FLAC_FileEncoder is a class to encode an input wav File to an output Flac
 * file. It allows the EncodingConfiguration to be set only once, prior to
 * encoding the entire File.
 * 
 * @author Preston Lacey
 * @author Bo Tan (Temple)
 */
public class FLAC_FileEncoder {
    /** Maximum number of bytes to read from file at once */
    private static final int MAX_READ = 16384;

    /** Status enum for encode result */
    public enum Status {
        /** Unknown State. */
        UNKNOWN,
        /** Everything went well */
        FULL_ENCODE,

        /** Something unspecified went wrong...*/
        GENERAL_ERROR,

        /** internal error is something that went haywire that was discovered
         * due to internal sanity checks. A problem in API. */
        INTERNAL_ERROR,

        /** File given was not able to be read */
        UNSUPPORTED_FILE,

        /** Generic file IO Error */
        FILE_IO_ERROR,

        /** Sample size unsupported */
        UNSUPPORTED_SAMPLE_SIZE,

        /** Error with output file */
        OUTPUT_FILE_ERROR,
        /** No errors found. */
        OK
    }
    FLACEncoder flac = null;
    StreamConfiguration sc = null;
    EncodingConfiguration ec = null;
    File outFile = null;
    int lastTotalSamples = 0;
    boolean useThreads;

    /**
     * Constructor creates a FLAC_FileEncoder object with default
     * StreamConfiguration configuration and default EncodingConfiguration.
     * Thread use defaults to true.
     */
    public FLAC_FileEncoder() {
        flac = new FLACEncoder();
        sc = new StreamConfiguration();
        ec = new EncodingConfiguration();
        useThreads = true;
    }

    /**
     * Specify whether to use multiple threads or not.
     * @param val true to use threads, false otherwise.
     */
    public void useThreads(boolean val) {
        useThreads = val;
    }

    private void adjustConfigurations(){//(AudioFormat format) {
        int sampleRate = 16000;//(int)format.getSampleRate();
        int sampleSize = 16; //(int)format.getSampleSizeInBits();
        int channels =1;// (int)format.getChannels();
        //int blockSize = sc.getMaxBlockSize();
        /*sc = new StreamConfiguration(channels, blockSize, blockSize,
                sampleRate, sampleSize);*/
        sc.setSampleRate(sampleRate);
        sc.setBitsPerSample(sampleSize);
        sc.setChannelCount(channels);
    }

    /**
     * Set the stream configuration for this encoder to use. Note that the audio
     * characteristics(number of channels, sample rate, and sample size), will
     * be set to match the input file at encode time, so needn't be set in the
     * given StreamConfiguration object.
     * 
     * @param config StreamConfiguration to use for encoding.
     */
    public void setStreamConfig(StreamConfiguration config) {sc = config; }

    /**
     * Set the EncodingConfiguration to use for encoding.
     * @param config EncodingConfiguration to use.
     */
    public void setEncodingConfig(EncodingConfiguration config){ec = config;}

    private Status openStream() {
        Status status = Status.OK;
        boolean result = flac.setStreamConfiguration(sc);
        result = result & flac.setEncodingConfiguration(ec);
        if( !result)
            status = Status.INTERNAL_ERROR;
        else {
            FLACFileOutputStream fout = null;
            try {
               fout = new FLACFileOutputStream(outFile.getPath());
            } catch(IOException e) {
               status = Status.OUTPUT_FILE_ERROR;
               e.printStackTrace();
            }
            if( status == Status.OK) {
                flac.setOutputStream(fout);
                try {
                    flac.openFLACStream();
                }catch(IOException e) {
                    status = Status.INTERNAL_ERROR;
                }
            }
            else
                status = Status.OUTPUT_FILE_ERROR;
        }
        return status;
    }

    /**
     * Encode the given input wav file to an output file.
     *
     * @param inputFile Input wav file to encode.
     * @param outputFile Output file to write FLAC stream to. If file exists, it
     * will be overwritten without prompting.
     *
     * @return Status flag for encode
     */
    public Status encode(File inputFile, File outputFile) {
        Status status = Status.FULL_ENCODE;
        this.outFile = outputFile;
        //take file and initial configuration.
        //open file
//        AudioInputStream sin = null;
//        AudioFormat format = null;
//        //File inputFile = new File("encoderTest.wav");
//        try {
//            sin = AudioSystem.getAudioInputStream(inputFile);
//        }catch(IOException e) {
//            status = Status.FILE_IO_ERROR;
//        }catch (UnsupportedAudioFileException e) {
//            status = Status.UNSUPPORTED_FILE;
//        }finally {
//            if(status != Status.FULL_ENCODE)
//                return status;
//        }


        FileInputStream sin=null;
        try {
            sin = new FileInputStream(inputFile);
        } catch (FileNotFoundException e1) {
            status = Status.FILE_IO_ERROR;
            e1.printStackTrace();
        }finally {
            if (status != Status.FULL_ENCODE)
                return status;
        }



        try {
//            format = sin.getFormat();
            //sanitize and optimize configurations
             adjustConfigurations();  //adjustConfigurations(format);
            //open stream
            openStream();
            int frameSize = 2;//format.getFrameSize();
            int sampleSize = 16;//format.getSampleSizeInBits();
            int bytesPerSample = sampleSize/8;
            if(sampleSize %8 != 0) {
                //end processing now
                Exception newEx = new Exception(Status.UNSUPPORTED_SAMPLE_SIZE.name());
                throw newEx;

            }
            int channels =1;// format.getChannels();
            boolean bigEndian =false;// format.isBigEndian();
            byte[] samplesIn = new byte[(int)MAX_READ];
            int samplesRead;
            int framesRead;
            int[] sampleData = new int[MAX_READ*channels/frameSize];
            int blockSize = sc.getMaxBlockSize();
            int unencodedSamples = 0;
            int totalSamples = 0;
            while((samplesRead = sin.read(samplesIn, 0, MAX_READ)) != -1) {
                //System.err.println("Read: " + read);
                framesRead = samplesRead/(frameSize);
                if(bigEndian) {
                    for(int i = 0; i < framesRead*channels; i++) {
                        int lower8Mask = 255;
                        int temp = 0;
                        int totalTemp = 0;
                        for(int x = bytesPerSample-1; x >= 0; x++) {
                            int upShift = 8*x;
                            if(x == 0)//don't mask...we want sign
                                temp = ((samplesIn[bytesPerSample*i+x]) << upShift);
                            else
                                temp = ((samplesIn[bytesPerSample*i+x] & lower8Mask) << upShift);
                            totalTemp = totalTemp | temp;
                        }
                        sampleData[i] = totalTemp;
                    }
                }
                else {
                    for(int i = 0; i < framesRead*channels; i++) {
                        int lower8Mask = 255;
                        int temp = 0;
                        int totalTemp = 0;
                        for(int x = 0; x < bytesPerSample; x++) {
                            int upShift = 8*x;
                            if(x == bytesPerSample-1)//don't mask...we want sign
                                temp = ((samplesIn[bytesPerSample*i+x]) << upShift);
                            else
                                temp = ((samplesIn[bytesPerSample*i+x] & lower8Mask) << upShift);
                            totalTemp = totalTemp | temp;
                        }
                        sampleData[i] = totalTemp;
                    }
                }
                if(framesRead > 0) {
                   flac.addSamples(sampleData, framesRead);
                   unencodedSamples += framesRead;
                }
                //if(unencodedSamples > blockSize*100) {
                    if(useThreads)//Thread.yield();//
                        unencodedSamples -= flac.t_encodeSamples(unencodedSamples, false, flac.getThreadCount());
                    else
                        unencodedSamples -= flac.encodeSamples(unencodedSamples, false);
                    totalSamples += unencodedSamples;
                    //unencodedSamples = 0;

                //}
                //System.err.println("read : "+ samplesRead);
            }
            totalSamples += unencodedSamples;
            if(useThreads)
                unencodedSamples -= flac.t_encodeSamples(unencodedSamples, true, flac.getThreadCount());
            else
                unencodedSamples -= flac.encodeSamples(unencodedSamples, true);
            //unencodedSamples = 0;
            lastTotalSamples = totalSamples;
        }
        catch(IOException e) {
            status = Status.FILE_IO_ERROR;
        }
        catch(Exception e) {
            status = Status.GENERAL_ERROR;
            String message = e.getMessage();
            if(message == null) {            
                e.printStackTrace();
            }
            else if(message.equals(Status.UNSUPPORTED_SAMPLE_SIZE.name()))
                status = Status.UNSUPPORTED_SAMPLE_SIZE;
        }

        //System.err.print("LastTotalSamples: "+lastTotalSamples);
        return status;
    }

    /**
     * Get the total number of samples encoded in last encode.  This is here
     * primarily for use as a sanity check during debugging.
     *
     * @return Total number of samples encoded in last encode attempt.
     */
    public int getLastTotalSamplesEncoded() {
        return this.lastTotalSamples;
    }
}

2 个答案:

答案 0 :(得分:3)

Temple,感谢您的帖子以及附带的FLAC转换代码的回复。它就像你描述的那样有一个小问题。

FLACFileOutputStream(fout)和FileInputStream(sin)在函数末尾没有关闭。请更新您的帖子/代码,以便其他人也可以受益。

finally {
     try {
          if (sin != null) sin.close();
          if (fout != null) fout.close();
     } catch (IOException e) {}
}

PS:需要将FLACFileOutputStream fout提升为类变量才能使其正常工作。

答案 1 :(得分:0)

更改代码中的以下行

unencodedSamples -= flac.t_encodeSamples(unencodedSamples, true);

unencodedSamples -= flac.t_encodeSamples(unencodedSamples, true,flac.getThreadCount());