Xamarin.Android wav to m4a。

4

我已经找到了Java的答案:https://dev59.com/lWoy5IYBdhLWcg3wdt8L#36357819并尝试将其移植到Xamarin。

以下是我编写的代码:

    const string COMPRESSED_AUDIO_FILE_MIME_TYPE = "audio/mp4a-latm";
    const int COMPRESSED_AUDIO_FILE_BIT_RATE = 64000; // 64kbps
    const int SAMPLING_RATE = 48000;
    const int BUFFER_SIZE = 48000;
    const int CODEC_TIMEOUT_IN_MS = 5000;

    void Compress()
    {
        var inputFile = new Java.IO.File(tempFileWavPath);
        var fis = new Java.IO.FileInputStream(inputFile);

        var outputFile = new Java.IO.File(fileM4APath);
        if (outputFile.Exists())
            outputFile.Delete();

        var mux = new MediaMuxer(outputFile.AbsolutePath, MuxerOutputType.Mpeg4);

        MediaFormat outputFormat = MediaFormat.CreateAudioFormat(COMPRESSED_AUDIO_FILE_MIME_TYPE, SAMPLING_RATE, 1);
        outputFormat.SetInteger(MediaFormat.KeyAacProfile, (int)MediaCodecProfileType.Aacobjectlc);
        outputFormat.SetInteger(MediaFormat.KeyBitRate, COMPRESSED_AUDIO_FILE_BIT_RATE);
        outputFormat.SetInteger(MediaFormat.KeyMaxInputSize, 16384);

        MediaCodec codec = MediaCodec.CreateEncoderByType(COMPRESSED_AUDIO_FILE_MIME_TYPE);
        codec.Configure(outputFormat, null, null, MediaCodecConfigFlags.Encode);
        codec.Start();

        MediaCodec.BufferInfo outBuffInfo = new MediaCodec.BufferInfo();
        byte[] tempBuffer = new byte[BUFFER_SIZE];
        var hasMoreData = true;
        double presentationTimeUs = 0;
        int audioTrackIdx = 0;
        int totalBytesRead = 0;
        int percentComplete = 0;
        do
        {
            int inputBufIndex = 0;
            while (inputBufIndex != -1 && hasMoreData)
            {
                inputBufIndex = codec.DequeueInputBuffer(CODEC_TIMEOUT_IN_MS);

                if (inputBufIndex >= 0)
                {
                    var dstBuf = codec.GetInputBuffer(inputBufIndex);
                    dstBuf.Clear();

                    int bytesRead = fis.Read(tempBuffer, 0, dstBuf.Limit());
                    if (bytesRead == -1)
                    { // -1 implies EOS
                        hasMoreData = false;
                        codec.QueueInputBuffer(inputBufIndex, 0, 0, (long)presentationTimeUs, MediaCodecBufferFlags.EndOfStream);
                    }
                    else
                    {
                        totalBytesRead += bytesRead;
                        dstBuf.Put(tempBuffer, 0, bytesRead);
                        codec.QueueInputBuffer(inputBufIndex, 0, bytesRead, (long)presentationTimeUs, 0);
                        presentationTimeUs = 1000000l * (totalBytesRead / 2) / SAMPLING_RATE;
                    }
                }
            }
            // Drain audio
            int outputBufIndex = 0;
            while (outputBufIndex != (int)MediaCodecInfoState.TryAgainLater)
            {
                outputBufIndex = codec.DequeueOutputBuffer(outBuffInfo, CODEC_TIMEOUT_IN_MS);
                if (outputBufIndex >= 0)
                {
                    var encodedData = codec.GetOutputBuffer(outputBufIndex);
                    encodedData.Position(outBuffInfo.Offset);
                    encodedData.Limit(outBuffInfo.Offset + outBuffInfo.Size);
                    if ((outBuffInfo.Flags & MediaCodecBufferFlags.CodecConfig) != 0 && outBuffInfo.Size != 0)
                    {
                        codec.ReleaseOutputBuffer(outputBufIndex, false);
                    }
                    else
                    {
                        mux.WriteSampleData(audioTrackIdx, encodedData, outBuffInfo);
                        codec.ReleaseOutputBuffer(outputBufIndex, false);
                    }
                }
                else if (outputBufIndex == (int)MediaCodecInfoState.OutputFormatChanged)
                {
                    outputFormat = codec.OutputFormat;
                    audioTrackIdx = mux.AddTrack(outputFormat);
                    mux.Start();
                }
            }
            percentComplete = (int)Math.Round(((float)totalBytesRead / (float)inputFile.Length()) * 100.0);
        } while (outBuffInfo.Flags != MediaCodecBufferFlags.EndOfStream);
        fis.Close();
        mux.Stop();
        mux.Release();
    }

这几乎起到了转换文件的作用,但生成的文件似乎编码过快 - 音调和速度都太高,重现的时间比预期的短。

很可能只需要做一些轻微的更改,但我不确定需要什么。有人可以建议吗?


你的意思是想要延长时间吗? - Wendy Zang - MSFT
@WendyZang-MSFT 我只想压缩 WAV 文件而不产生任何伪像。对我来说,这种方法并没有奏效,但问题可能出在 WAV 文件上,我会检查一下,不过在播放器中它的表现很好。 - Ivan Ičin
你有没有试过其他的wav文件? - Wendy Zang - MSFT
@WendyZang-MSFT,我刚刚完成了,看起来一样。上面的代码有问题,会在转换时加速声音。 - Ivan Ičin
1个回答

2
我可以翻译这段英文:

当我使用不同的SAMPLING_RATE大小时,我可以复制出结果文件似乎编码得太快。

例如,我在线下载了一个wav文件。采样率为11025。如果我在代码中使用原始速率48000,它会播放得太快。当我使用11025时,它可以正常工作。

enter image description here

所以我们需要知道wav文件的采样率,然后在代码中设置它。
const int SAMPLING_RATE = 11025;//44100, 48000

可能这可以以某种方式使用,但我的文件确实有48000: 比特率:768 kb/s 通道数:1个通道 采样率:48.0 kHz - Ivan Ičin
它是否仍然使用正确的参数进行编码得太快了?您尝试过其他WAV文件吗?是否有相同的问题? - Wendy Zang - MSFT
我的文件总是由应用程序编码,因此它们具有相同的参数。我已在电脑上检查过它们的采样率为48KHz。我可能会尝试这个诀窍,以查看某些数字是否产生合理的结果,但那有点猜测,并且我永远不会知道它是否实际上是1:1的编码... - Ivan Ičin
也许是编码引起的问题。如果您有新想法,请告知我。 - Wendy Zang - MSFT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接