2

我需要在我的 Android 应用程序中将 .pcm 转换为 .wav 文件。PCM 录音是原始数字音频样本。以前,一个 PCM 音频文件是以 16000 的采样频率录制的,在单声道模式下(channelConfigurationRecord = AudioFormat.CHANNEL_IN_MONO),一个样本中的 16 位(audioEncoding = AudioFormat.ENCODING_PCM_16BIT)。要将 PCM 转换为 WAV,我需要先编写一个标题,然后添加我所有的 PCM 数据。我花了很多时间在这上面,我尝试了很多变种,但没有任何效果。我不知道我做错了什么......帮帮我!

public class Convert {
    File filePcm;
    File fileWav;

    char chunkId[]={'R','I','F','F'};
    byte chunkSize[];
    char format[]={'W','A','V','E'};
    char subchunk1Id[]={'f','m','t',' '};
    byte subchunk1Size[]={0b0,0b0,0b0,16};
    byte audioFormat[]={0,1};
    byte numChannels[]={0,1};
    byte sampleRate[]={0b0,0b0,0b111110,(byte)0b10000000};
    byte byteRate[]={0b0,0b0,0b1111101,0b0};
    byte blockAlign[]={0,2};
    byte bitsPerSample[]={0,16};
    char subchunk2Id[]={'d','a','t','a'};
    byte subchunk2Size[];

    public Convert (File filePcm){
        this.filePcm = filePcm;
    }
    public void convertWavFile(){
        try {
            fileWav = new File("");
            fileWav.createNewFile();
            writeHeader();
            writePcmData();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void writeHeader() throws IOException {
        long chunkSiz=36+filePcm.length();
        chunkSize = new byte[]{ (byte) (chunkSiz & 0xff),
                (byte) ((chunkSiz >> 8) & 0xff),
                (byte) ((chunkSiz >> 16) & 0xff),
                (byte) ((chunkSiz >> 24) & 0xff)};
        long subchunk2Siz=filePcm.length();
        subchunk2Size = new byte[]{ (byte) (subchunk2Siz & 0xff),
                (byte) ((subchunk2Siz >> 8) & 0xff),
                (byte) ((subchunk2Siz >> 16) & 0xff),
                (byte) ((subchunk2Siz >> 24) & 0xff)};

        FileOutputStream d = new FileOutputStream(fileWav);
        for (char c:chunkId) d.write(c);
        for (byte c:chunkSize) d.write(c);
        for (char c:format) d.write(c);
        for (char c:subchunk1Id) d.write(c);
        for (byte c:subchunk1Size)d.write (c);
        for (byte c:audioFormat)d.write (c);
        for (byte c:numChannels)d.write (c);
        for (byte c:sampleRate) d.write(c);
        for (byte c:byteRate) d.write(c);
        for (byte c:blockAlign)d.write (c);
        for (byte c:bitsPerSample)d.write (c);
        for (char c:subchunk2Id) d.write(c);
        for (byte c:subchunk2Size) d.write(c);
    }

    private void writePcmData() throws IOException {
        FileInputStream fileInputStream = new FileInputStream(filePcm);
        FileOutputStream fileOutputStream = new FileOutputStream(fileWav);
        int i;
        while((i=fileInputStream.read())!=-1){
            fileOutputStream.write(i);
        }
    }
}

输入数据是未经处理的 pcm 样本,在创建和编写此 shell 后,任何播放器都无法识别该文件

4

2 回答 2

1

首先添加 FFMPEG 库,该库可以轻松转换、合并、混合视频和音频。

构建.gradle(应用程序)

 implementation 'com.writingminds:FFmpegAndroid:0.3.2'

活动

    File yourPcmFile = new File("YOUR_PCM_FILE_ABSOLUTE_PATH");
    File yourWawOutput = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/output.wav");
    String command = "-f s16le -ar 44.1k -ac 2 -i "+yourPcmFile.getAbsolutePath()+ yourWawOutput.getAbsolutePath();
    FFmpeg ffmpeg = FFmpeg.getInstance(context);
    try {
        ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
            @Override
            public void onStart() {
            }

            @Override
            public void onFailure() {
            }

            @Override
            public void onSuccess() {
            }

            @Override
            public void onFinish() {
            }
        });
    } catch (Exception e) {
        Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
    }

    try {
        ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
            @Override
            public void onStart() {
                dialog.show();
            }

            @Override
            public void onProgress(String message) {

            }

            @Override
            public void onFailure(String message) {
                Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }

            @Override
            public void onSuccess(String message) {
                Toast.makeText(context, "Build has been successful", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }

            @Override
            public void onFinish() {

            }
        });
    } catch (Exception e) {
        Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
    } finally {
        if (ffmpeg.isFFmpegCommandRunning()) {
            ffmpeg.killRunningProcesses();

显现

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

更多信息

-f s16le -ar 44.1k -ac 2 -i "+yourPcmFile.getAbsolutePath()+ yourWawOutput.getAbsolutePath()
-f s16le >>> signed 16-bit little endian samples
-ar 44.1k >>> sample rate 44.1kHz
-ac 2 >>> 2 channels (stereo)
-i yourPcmFile.getAbsolutePath() >>> input file
yourWawOutput.getAbsolutePath() >>> output file
于 2020-06-03T15:28:54.603 回答
0

该文件是在 FileOutputStream 对象被实例化时创建的。如果文件已存在,则将其覆盖。

您正在创建文件两次。

一次在 writeHeader() 函数中,一次在 writePCM() 函数中。

当您写入 PCM 数据时,您将覆盖您写入的标头数据,并且您最终会得到另一个 PCM 文件。

于 2020-12-29T23:42:26.237 回答