gpt4 book ai didi

android - 从 3gpp 生成音频图

转载 作者:搜寻专家 更新时间:2023-11-01 09:35:17 26 4
gpt4 key购买 nike

我正在编写录音机作为应用程序的一部分,它也有音频图。录制和显示实时音频图非常简单,只需每隔 X 毫秒调用 MediaRecorder.GetMaxAmplitude() 并基于代表音频图的更新 Canvas 。

问题 - 我想在打开其中一个录音时拥有相同的音频图,所以现在我不能使用 .GetMaxAmplitude() 方法,因为我需要完全播放录音才能生成图表,这需要太多的时间,而且很愚蠢。

如果录音输出是 .wav,那将非常简单,很多 Material 说明了如何做到这一点,但是 MediaRecorder 不支持 .wav,我真的不想将带有包装器的完整 ffmpeg 嵌入到我的应用程序中只是为了这个将 3gpp 解码为 wav 的小功能。

我有哪些选择?

最佳答案

使用 MediaExtractorMediaCodec 您可以将 3gp(或任何其他支持的 mime 类型)解码为一系列 PCM-16 位(mime audio/raw) 缓冲区,您可以从中进行二次采样,以“可绘制的”采样率获得所需的振幅图。

这是一个在输入/输出缓冲区上使用同步处理的示例,因此在非 UI 线程上运行它。

同步 PCM-16 位 MediaCodec 示例:

var file = new Java.IO.File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads), "someaudiofile.mp3");
if (file.CanRead())
{
var mediaExtractor = new MediaExtractor();
mediaExtractor.SetDataSource(file.ToString());
mediaExtractor.SelectTrack(0); // which track? lets assume single/mono for this example
var mediaFormat = mediaExtractor.GetTrackFormat(0);
var mime = mediaFormat.GetString(MediaFormat.KeyMime);
var mediaCodec = MediaCodec.CreateDecoderByType(mime);
mediaCodec.Configure(mediaFormat, null, null, MediaCodecConfigFlags.None);
mediaCodec.Start();
var bufferInfo = new MediaCodec.BufferInfo();
var inputDone = false;
while (true)
{
if (!inputDone) // process input stream and queue it up for output processing
{
int inputBufferIndex = mediaCodec.DequeueInputBuffer(10000);
if (inputBufferIndex >= 0)
{
var inputBuffer = mediaCodec.GetInputBuffer(inputBufferIndex);
int chunkSize = mediaExtractor.ReadSampleData(inputBuffer, 0);
Log.Debug("SO", $"Input Buffer: {inputBufferIndex}");
if (chunkSize <= 0)
{
mediaCodec.QueueInputBuffer(inputBufferIndex, 0, 0, 0L, MediaCodecBufferFlags.EndOfStream);
inputDone = true;
}
else
{
mediaCodec.QueueInputBuffer(inputBufferIndex, 0, chunkSize, mediaExtractor.SampleTime, MediaCodecBufferFlags.None);
mediaExtractor.Advance();
}
}
}

int outputBufferIndex = mediaCodec.DequeueOutputBuffer(bufferInfo, 1000000);
if (outputBufferIndex >= 0)
{
Log.Debug("SO", $"Output Buffer: {outputBufferIndex}");
if (bufferInfo.Size != 0)
{
var outputBuffer = mediaCodec.GetOutputBuffer(outputBufferIndex); // PCM 16-bit output
var outpuFormat = mediaCodec.GetOutputFormat(outputBufferIndex);
outputBuffer.Position(0);
// !!! Sub-sample the buffer based upon your needed sampling rate for display
var pcm16bitBuffer = outputBuffer.AsShortBuffer();
while (pcm16bitBuffer.HasRemaining)
{
var x = pcm16bitBuffer.Get();
// store the prior values and avg./max/... them for later display based upon some subsampling rate
}
pcm16bitBuffer.Dispose();
mediaCodec.ReleaseOutputBuffer(outputBufferIndex, false);
if (bufferInfo.Flags.HasFlag(MediaCodecBufferFlags.EndOfStream))
break;
}
else
break;
}
else if (outputBufferIndex == -2)
{
Log.Debug("SO", "Output buffer is not available yet, feed more input");
}
}
mediaCodec.Stop();
mediaCodec.Release();
}

注意:也有可用的异步方法,请参阅有关 Android API 级别的 MediaCodec 文档,了解适用于您应用的目标受众的方法。

使用上述方法输出示例:

enter image description here

回复:MediaCodec

关于android - 从 3gpp 生成音频图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43802167/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com