使用 C# 的 MediaTranscoder 将 PCM 音频转码为 MP3
Transcode PCM Audio to MP3 using MediaTranscoder with C#
我正在尝试对从 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;
}
}
所以我必须做的是在开始将数据写入流之前将 header 写入我的 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);
}
我正在尝试对从 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;
}
}
所以我必须做的是在开始将数据写入流之前将 header 写入我的 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);
}