使用带有 C# 的 MediaTranscoder 将 PCM 音频转码为 MP3

Posted

技术标签:

【中文标题】使用带有 C# 的 MediaTranscoder 将 PCM 音频转码为 MP3【英文标题】:Transcode PCM Audio to MP3 using MediaTranscoder with C# 【发布时间】:2019-11-04 20:32:15 【问题描述】:

我正在尝试对从 WebRTC 调用中保存的 PCM 格式的音频文件进行转码。 WebRTC 报告的音频流格式为 16 位深度、1 通道和 48000 Hz 采样率。我想将音频转换为 MP3,以便之后可以将音频作为背景音轨添加到我的 Unity UWP 应用程序的屏幕录制中(使用 MediaComposition)。我在第一部分遇到问题:尝试将我的 PCM 音频文件转码为 MP3 文件。当我尝试准备转码时,preparedTranscodeResult.CanTranscode 正在返回 false。以下是我的代码。

StorageFile remoteAudioPCMFile = await StorageFile.GetFileFromPathAsync(Path.Combine(Application.temporaryCachePath, "remote.pcm").Replace("/", "\\"));
StorageFolder tempFolder = await StorageFolder.GetFolderFromPathAsync(Application.temporaryCachePath.Replace("/", "\\"));
StorageFile remoteAudioMP3File = await tempFolder.CreateFileAsync("remote.mp3", CreationCollisionOption.ReplaceExisting);

MediaEncodingProfile profile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.Auto);
profile.Audio.BitsPerSample = 16;
profile.Audio.ChannelCount = 1;
profile.Audio.SampleRate = 48000;

MediaTranscoder transcoder = new MediaTranscoder();
var preparedTranscodeResult = await transcoder.PrepareFileTranscodeAsync(remoteAudioPCMFile, remoteAudioMP3File, profile);

if (preparedTranscodeResult.CanTranscode)

    await preparedTranscodeResult.TranscodeAsync();

else

    if (remoteAudioPCMFile != null)
    
        await remoteAudioPCMFile.DeleteAsync();
    

    if (remoteAudioMP3File != null)
    
        await remoteAudioMP3File.DeleteAsync();
    

    switch (preparedTranscodeResult.FailureReason)
    
        case TranscodeFailureReason.CodecNotFound:
            Debug.LogError("Codec not found.");
            break;
        case TranscodeFailureReason.InvalidProfile:
            Debug.LogError("Invalid profile.");
            break;
        default:
            Debug.LogError("Unknown failure.");
            break;
    

【问题讨论】:

您的开关盒中是否有任何日志?您是否尝试过转码? 您好,我测试了一些不同类型的音频文件,只有 pcm 无法正确转码,并且无法提供有效的错误信息。 MediaTranscode现在可能无法直接转码 pcm 音频文件。我正在寻求工程师的帮助,看看是否有其他解决方案。 @LouisGarczynski 是的,它转到默认情况并打印“未知故障”。 @RichardZhang-MSFT 好的,谢谢!对此,我真的非常感激!我希望先使用 ffmpeg,但您无法在 UWP 中启动外部进程。 如果您可以访问该文件,为什么不使用任何类型的在线转换器来获取 mp3? 【参考方案1】:

所以我必须在开始将数据写入流之前将标头写入我的FileStream。我是从this post 那里得到的。

private void WriteWavHeader(FileStream stream, bool isFloatingPoint, ushort channelCount, ushort bitDepth, int sampleRate, int totalSampleCount)

    stream.Position = 0;

    // RIFF header.
    // Chunk ID.
    stream.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4);

    // Chunk size.
    stream.Write(BitConverter.GetBytes((bitDepth / 8 * totalSampleCount) + 36), 0, 4);

    // Format.
    stream.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);



    // Sub-chunk 1.
    // Sub-chunk 1 ID.
    stream.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);

    // Sub-chunk 1 size.
    stream.Write(BitConverter.GetBytes(16), 0, 4);

    // Audio format (floating point (3) or PCM (1)). Any other format indicates compression.
    stream.Write(BitConverter.GetBytes((ushort)(isFloatingPoint ? 3 : 1)), 0, 2);

    // Channels.
    stream.Write(BitConverter.GetBytes(channelCount), 0, 2);

    // Sample rate.
    stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);

    // Bytes rate.
    stream.Write(BitConverter.GetBytes(sampleRate * channelCount * (bitDepth / 8)), 0, 4);

    // Block align.
    stream.Write(BitConverter.GetBytes(channelCount * (bitDepth / 8)), 0, 2);

    // Bits per sample.
    stream.Write(BitConverter.GetBytes(bitDepth), 0, 2);



    // Sub-chunk 2.
    // Sub-chunk 2 ID.
    stream.Write(Encoding.ASCII.GetBytes("data"), 0, 4);

    // Sub-chunk 2 size.
    stream.Write(BitConverter.GetBytes(bitDepth / 8 * totalSampleCount), 0, 4);

【讨论】:

以上是关于使用带有 C# 的 MediaTranscoder 将 PCM 音频转码为 MP3的主要内容,如果未能解决你的问题,请参考以下文章

带有 C# 后端的电子 GUI

如何使用带有 WebImage 类的 C# 裁剪图像?

使用带有 C# 的公钥验证 JWT

在 C# 中使用带有多个 if 语句的 else

使用带有 C# 的 Entity Framework 6 调用现有的存储过程

使用带有 C#、Visual Studio 2010 的 PhoneNumbers.dll 验证电话号码