首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从3 3gpp生成音频图

从3 3gpp生成音频图
EN

Stack Overflow用户
提问于 2017-05-05 10:07:12
回答 1查看 728关注 0票数 2

作为应用程序的一部分,我正在编写音频记录器,它也有音频图形。为了记录和显示实时音频图,非常容易,只需每一个X毫秒调用MediaRecorder.GetMaxAmplitude(),并且基于表示音频图的更新画布。

问题是,当其中一个录音打开时,我想要有相同的音频图,所以现在我不能使用.GetMaxAmplitude()方法,因为我需要充分播放录音才能生成图形,这将花费太多的时间,而且非常愚蠢。

如果录音输出是.wav的话,这将是相当简单的,很多材料都是如何实现的,但是MediaRecorder不支持.wav,我也不想在我的应用程序中嵌入完整的ffmpeg和包装器,只是为了将3 3gpp解码到wav中。

我在这里有什么选择?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-05 20:45:11

使用MediaExtractorMediaCodec,您可以将您的3gp (或任何其他受支持的mime类型)解码为一系列PCM-16位(mime audio/raw)缓冲区,然后从这些缓冲区中以“可抓取”的采样速率获得所需的幅值图。

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

同步PCM-16位MediaCodec示例:

代码语言:javascript
复制
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级别的MediaCodec文档,了解应用程序的目标受众可用的内容。

使用上述方法输出示例:

Re:MediaCodec

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43802167

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档