使用C#中的libFLAC将WAV转换为FLAC

时间:2013-08-12 01:17:07

标签: c# pinvoke flac

我尝试将libFLAC encoding example移植到C#并提出了以下代码:

public class LibFLAC {

    public static void Test() {
        string inputPath = Path.Combine("D:\\", "_", "test.pcm");
        string outputPath = Path.Combine("D:\\", "_", "test.flac");

        uint channels = 2;
        uint bitsPerSample = 16;
        uint sampleRate = 44100;


        IntPtr encoder = FLAC__stream_encoder_new();
        if (encoder == IntPtr.Zero) throw new Exception("Encoder: NEW failed");

        bool ok = true;
        ok &= FLAC__stream_encoder_set_channels(encoder, channels);
        ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bitsPerSample);
        ok &= FLAC__stream_encoder_set_sample_rate(encoder, sampleRate);
        ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
        // ok &= FLAC__stream_encoder_set_verify(encoder, true);
        if (!ok) throw new Exception("Encoder: SET failed");

        int status = FLAC__stream_encoder_init_file(encoder, outputPath, IntPtr.Zero, IntPtr.Zero);
        if (status != 0) throw new Exception("Encoder: INIT FILE failed");


        using (FileStream stream = new FileStream(inputPath, FileMode.Open, FileAccess.Read)) {
            uint bps = bitsPerSample / 8;
            byte[] buffer = new byte[channels * bps * 1024];
            Int32[] pcm = new Int32[channels * 1024];
            int read;

            while ((read = stream.Read(buffer, 0, buffer.Length)) != 0) {
                for (var i = 0; i < read / bps; i++) {
                    pcm[i] = (Int32) (((uint) buffer[i * 2 + 1] << 8) | (uint) buffer[i * 2]);
                }

                ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, (uint) (read / bps / channels));
                if (!ok) throw new Exception("Encoder: PROCESS INTERLEAVED failed ::: " + FLAC__stream_encoder_get_state(encoder) + " ::: " + FLAC__stream_encoder_get_verify_decoder_state(encoder));
            }

            ok = FLAC__stream_encoder_finish(encoder);
            if (!ok) throw new Exception("Encoder: FINISH failed");

            FLAC__stream_encoder_delete(encoder);
            encoder = IntPtr.Zero;
        }



        Console.WriteLine("\n\n\nDone");
        Console.ReadKey();
    }


    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr FLAC__stream_encoder_new();

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern void FLAC__stream_encoder_delete(IntPtr encoder);


    [DllImport("libFLAC", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_set_verify(IntPtr encoder, bool value);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_set_channels(IntPtr encoder, uint value);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_set_bits_per_sample(IntPtr encoder, uint value);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_set_sample_rate(IntPtr encoder, uint value);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_set_compression_level(IntPtr encoder, uint value);


    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern int FLAC__stream_encoder_init_file(IntPtr encoder, string filename, IntPtr progress_callback, IntPtr client_data);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_process_interleaved(IntPtr encoder, Int32[] buffer, uint samples);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool FLAC__stream_encoder_finish(IntPtr encoder);


    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern int FLAC__stream_encoder_get_state(IntPtr encoder);

    [DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
    public static extern int FLAC__stream_encoder_get_verify_decoder_state(IntPtr encoder);

}

test.pcm文件是没有WAV或RIFF标头的原始PCM数据,并且采用给定格式(2个通道,16个bps和44.1 kHz)。

代码有效,FLAC正常播放,但创建的文件几乎与源wav一样大(WAV:47MB - > FLAC:45MB),最后有200ms的噪音。如果我使用相同的设置通过FLAC Frontend GUI发送它,我得到一个35MB的文件,所以WAV应该没问题。

此外,如果我启用FLAC__stream_encoder_set_verify,程序会立即在FLAC__stream_encoder_process_interleaved

时失败
  • FLAC__StreamEncoderState = 4(VERIFY_MISMATCH_IN_AUDIO_DATA - 验证解码器检测到原始音频信号与解码后的音频信号不匹配。)和
  • FLAC__StreamDecoderState = 3(READ_FRAME - 解码器已准备好或正在阅读框架。

哪个没意义?

我在转换过程中遗漏了什么或犯了错误吗?

0 个答案:

没有答案