如何找到正确的缓冲区大小以使用 Concentus 解压缩 Opus 文件
How can I find the correct buffer size for decompressing an Opus file with Concentus
我正在尝试编写一个 Android 应用程序(使用 Xamarin),我可以在其中录制然后播放 .opus 文件。我以前从未使用过Opus,所以请多多包涵...
我正在使用 Concentus NuGet 包 compress/decompress 音频。 Concentus 的示例代码建议使用以下内容进行记录:
// Initialize
OpusEncoder encoder = OpusEncoder.Create(48000, 1, OpusApplication.OPUS_APPLICATION_AUDIO);
encoder.Bitrate = 12000;
// Encoding loop
short[] inputAudioSamples
byte[] outputBuffer[1000];
int frameSize = 960;
int thisPacketSize = encoder.Encode(inputAudioSamples, 0, frameSize, outputBuffer, 0, outputBuffer.Length); // this throws OpusException on a failure, rather than returning a negative number
使用这些信息,我创建了以下记录方法:
private void RecordAudio(string filename)
{
_outputStream = File.Open(filename, FileMode.OpenOrCreate);
_binaryWriter = new BinaryWriter(_outputStream);
OpusEncoder encoder = OpusEncoder.Create(AudioFormat.SampleRate, 1, OpusApplication.OPUS_APPLICATION_AUDIO);
encoder.Bitrate = 12000;
int frameSize = AudioFormat.SampleRate * 20 / 1000;
short[] audioBuffer = new short[frameSize];
byte[] outputBuffer = new byte[1000];
_audioRecorder = new AudioRecord(
// Hardware source of recording.
AudioSource.Mic,
// Frequency
AudioFormat.SampleRate,
// Mono or stereo
AudioFormat.ChannelIn,
// Audio encoding
AudioFormat.Encoding,
// Length of the audio clip.
audioBuffer.Length
);
_audioRecorder.StartRecording();
_isRecording = true;
while (_isRecording)
{
try
{
// Keep reading the buffer while there is audio input.
_audioRecorder.Read(audioBuffer, 0, audioBuffer.Length);
int thisPacketSize = encoder.Encode(audioBuffer, 0, frameSize, outputBuffer, 0, outputBuffer.Length); // this throws OpusException on a failure, rather than returning a negative number
Debug.WriteLine("Packet size = " + thisPacketSize);
// Write to the audio file.
_binaryWriter.Write(outputBuffer, 0, thisPacketSize);
}
catch (System.Exception ex)
{
Console.Out.WriteLine(ex.Message);
}
}
}
查看thisPacketSize
,我可以看出它是可变的。
Concentus 建议使用以下解码代码:
OpusDecoder decoder = OpusDecoder.Create(48000, 1);
// Decoding loop
byte[] compressedPacket;
int frameSize = 960; // must be same as framesize used in input, you can use OpusPacketInfo.GetNumSamples() to determine this dynamically
short[] outputBuffer = new short[frameSize];
int thisFrameSize = _decoder.Decode(compressedPacket, 0, compressedPacket.Length, outputBuffer, 0, frameSize, false);
我最初的播放想法如下:
void PlayAudioTrack(string filename)
{
_inputStream = File.OpenRead(filename);
_inputStream.Position = _recording.CurrentPosition - _recording.CurrentPosition % AudioFormat.BytesPerSample;
OpusDecoder decoder = OpusDecoder.Create(AudioFormat.SampleRate, 1);
int frameSize = AudioFormat.SampleRate * 20 / 1000;
_audioTrack = new AudioTrack(
// Stream type
Android.Media.Stream.Music,
// Frequency
AudioFormat.SampleRate,
// Mono or stereo
AudioFormat.ChannelOut,
// Audio encoding
AudioFormat.Encoding,
// Length of the audio clip.
frameSize,
// Mode. Stream or static.
AudioTrackMode.Stream);
_audioTrack.SetPositionNotificationPeriod(AudioFormat.SampleRate / 30);
_audioTrack.PeriodicNotification += _audioTrack_PeriodicNotification;
_audioTrack.Play();
short[] audioBuffer = new short[frameSize];
int bytesRead = 0;
do
{
try
{
byte[] compressedPacket = new byte[???];
bytesRead = _inputStream.Read(compressedPacket, 0, compressedPacket.Length);
int thisFrameSize = decoder.Decode(compressedPacket, 0, compressedPacket.Length, audioBuffer, 0, frameSize, false);
Debug.WriteLine("Frame size = " + thisFrameSize);
_audioTrack.Write(audioBuffer, 0, bytesRead);
}
catch (System.Exception)
{
bytesRead = 0;
}
} while (bytesRead > 0 && _audioTrack.PlayState == PlayState.Playing);
if (!(_audioTrack.PlayState == PlayState.Stopped))
{
RaisePlaybackCompleted(this, new EventArgs());
}
}
我的问题是...如果帧大小必须与在压缩(如果我理解正确的话)?
我认为你要求的是一种打包机制。这里真正的问题是,到目前为止,Concentus 仅在原始 Opus 数据包上运行,但没有代码来实际解析数据包所在的容器(.opus 文件实际上是包含 opus 数据流的 Ogg 媒体容器文件)。所以,如果你真的想要 read/write .opus 格式,你必须为 Ogg 文件实现一个 reader/writer,或者等我在 Concentus 包中实际实现一个(抱歉) .
NVorbis 有一个本机 Ogg 解析器,可以为此目的进行修改。或者,如果您不关心与其他程序的兼容性,您可以通过在每个编码的 Opus 数据块之前编写一个 2 字节的数据包长度字段来实现自己的基本分包器。
编辑:因为无论如何我都需要去做,所以我已经开始研究 Oggfile 解析器包,尽管到目前为止只实现了解码器:https://www.nuget.org/packages/Concentus.Oggfile
edit2:Opusfile 编码器现已实现;-)
我正在尝试编写一个 Android 应用程序(使用 Xamarin),我可以在其中录制然后播放 .opus 文件。我以前从未使用过Opus,所以请多多包涵...
我正在使用 Concentus NuGet 包 compress/decompress 音频。 Concentus 的示例代码建议使用以下内容进行记录:
// Initialize
OpusEncoder encoder = OpusEncoder.Create(48000, 1, OpusApplication.OPUS_APPLICATION_AUDIO);
encoder.Bitrate = 12000;
// Encoding loop
short[] inputAudioSamples
byte[] outputBuffer[1000];
int frameSize = 960;
int thisPacketSize = encoder.Encode(inputAudioSamples, 0, frameSize, outputBuffer, 0, outputBuffer.Length); // this throws OpusException on a failure, rather than returning a negative number
使用这些信息,我创建了以下记录方法:
private void RecordAudio(string filename)
{
_outputStream = File.Open(filename, FileMode.OpenOrCreate);
_binaryWriter = new BinaryWriter(_outputStream);
OpusEncoder encoder = OpusEncoder.Create(AudioFormat.SampleRate, 1, OpusApplication.OPUS_APPLICATION_AUDIO);
encoder.Bitrate = 12000;
int frameSize = AudioFormat.SampleRate * 20 / 1000;
short[] audioBuffer = new short[frameSize];
byte[] outputBuffer = new byte[1000];
_audioRecorder = new AudioRecord(
// Hardware source of recording.
AudioSource.Mic,
// Frequency
AudioFormat.SampleRate,
// Mono or stereo
AudioFormat.ChannelIn,
// Audio encoding
AudioFormat.Encoding,
// Length of the audio clip.
audioBuffer.Length
);
_audioRecorder.StartRecording();
_isRecording = true;
while (_isRecording)
{
try
{
// Keep reading the buffer while there is audio input.
_audioRecorder.Read(audioBuffer, 0, audioBuffer.Length);
int thisPacketSize = encoder.Encode(audioBuffer, 0, frameSize, outputBuffer, 0, outputBuffer.Length); // this throws OpusException on a failure, rather than returning a negative number
Debug.WriteLine("Packet size = " + thisPacketSize);
// Write to the audio file.
_binaryWriter.Write(outputBuffer, 0, thisPacketSize);
}
catch (System.Exception ex)
{
Console.Out.WriteLine(ex.Message);
}
}
}
查看thisPacketSize
,我可以看出它是可变的。
Concentus 建议使用以下解码代码:
OpusDecoder decoder = OpusDecoder.Create(48000, 1);
// Decoding loop
byte[] compressedPacket;
int frameSize = 960; // must be same as framesize used in input, you can use OpusPacketInfo.GetNumSamples() to determine this dynamically
short[] outputBuffer = new short[frameSize];
int thisFrameSize = _decoder.Decode(compressedPacket, 0, compressedPacket.Length, outputBuffer, 0, frameSize, false);
我最初的播放想法如下:
void PlayAudioTrack(string filename)
{
_inputStream = File.OpenRead(filename);
_inputStream.Position = _recording.CurrentPosition - _recording.CurrentPosition % AudioFormat.BytesPerSample;
OpusDecoder decoder = OpusDecoder.Create(AudioFormat.SampleRate, 1);
int frameSize = AudioFormat.SampleRate * 20 / 1000;
_audioTrack = new AudioTrack(
// Stream type
Android.Media.Stream.Music,
// Frequency
AudioFormat.SampleRate,
// Mono or stereo
AudioFormat.ChannelOut,
// Audio encoding
AudioFormat.Encoding,
// Length of the audio clip.
frameSize,
// Mode. Stream or static.
AudioTrackMode.Stream);
_audioTrack.SetPositionNotificationPeriod(AudioFormat.SampleRate / 30);
_audioTrack.PeriodicNotification += _audioTrack_PeriodicNotification;
_audioTrack.Play();
short[] audioBuffer = new short[frameSize];
int bytesRead = 0;
do
{
try
{
byte[] compressedPacket = new byte[???];
bytesRead = _inputStream.Read(compressedPacket, 0, compressedPacket.Length);
int thisFrameSize = decoder.Decode(compressedPacket, 0, compressedPacket.Length, audioBuffer, 0, frameSize, false);
Debug.WriteLine("Frame size = " + thisFrameSize);
_audioTrack.Write(audioBuffer, 0, bytesRead);
}
catch (System.Exception)
{
bytesRead = 0;
}
} while (bytesRead > 0 && _audioTrack.PlayState == PlayState.Playing);
if (!(_audioTrack.PlayState == PlayState.Stopped))
{
RaisePlaybackCompleted(this, new EventArgs());
}
}
我的问题是...如果帧大小必须与在压缩(如果我理解正确的话)?
我认为你要求的是一种打包机制。这里真正的问题是,到目前为止,Concentus 仅在原始 Opus 数据包上运行,但没有代码来实际解析数据包所在的容器(.opus 文件实际上是包含 opus 数据流的 Ogg 媒体容器文件)。所以,如果你真的想要 read/write .opus 格式,你必须为 Ogg 文件实现一个 reader/writer,或者等我在 Concentus 包中实际实现一个(抱歉) .
NVorbis 有一个本机 Ogg 解析器,可以为此目的进行修改。或者,如果您不关心与其他程序的兼容性,您可以通过在每个编码的 Opus 数据块之前编写一个 2 字节的数据包长度字段来实现自己的基本分包器。
编辑:因为无论如何我都需要去做,所以我已经开始研究 Oggfile 解析器包,尽管到目前为止只实现了解码器:https://www.nuget.org/packages/Concentus.Oggfile
edit2:Opusfile 编码器现已实现;-)