【问题标题】:How to capture and encode audio in a video system_Android如何在视频系统中捕获和编码音频_Android
【发布时间】:2014-02-23 15:35:20
【问题描述】:

我正在尝试在 android 中构建一个开源视频系统,因为我们无法访问封闭系统中的数据。在这个系统中,我们可以修改摄像头捕获的原始数据。

我使用 MediaCodec 和 MediaMux 来完成视频数据编码和多路复用工作,这很有效。但我不知道音频部分。我使用 onFramePreview 来获取每一帧并逐帧进行编码/混合工作。但是如何同时进行音频录制(我的意思是逐帧捕获音频,对其进行编码并将数据发送到 MediaMux)。

我做了一些研究。似乎我们使用audiorecorder来获取音频的原始数据。但是audiorecorder 做的是一个持续的录音工作,我不认为它可以工作。

谁能给我一个提示?谢谢!

【问题讨论】:

    标签: android audio video android-mediacodec mediamuxer


    【解决方案1】:

    像这样创建audioRecorder:

    private AudioRecord getRecorderInstance() {
        AudioRecord ar = null;
        try {
            //Get a audiorecord
            int N = AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);            
            ar = new AudioRecord(AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10);
        } 
        catch (Exception e) {
    
        }
        return ar; //Returns null if mic is unavailable
    } 
    

    稍后为编码和复用准备和发送数据,就像这样是单独的线程:

    public class MicrophoneInput implements Runnable {
        @Override
        public void run() {
            // Buffer for 200 milliseconds of data, e.g. 400 samples at 8kHz.
            byte[] buffer200ms = new byte[8000 / 10];
    
            try {
                    while (recording) {
                        audioRecorder.read(buffer200ms, 0, buffer200ms.length);
    
                        //process buffer i.e send to encoder
                        //don't forget to set correct timestamps synchronized with video
                    }
            } 
            catch(Throwable x) {        
                    //  
            }
        }
    }
    

    【讨论】:

    • 谢谢你,@Marlon。我已经尝试过了,但我遇到了一些麻烦。我应该把函数 audioRecord.startRecording 放在哪里?我使用回调函数 onPreviewFrame 来获取每一帧的数据并对这些数据进行编码/复用。我尝试将 startRecording 放在 onPreviewFrame 和 onPreviewFrame 之前,但两者都可以。此外,我使用 AsyncTask 进行编码背景(onPreivewFrame 逐帧调用该任务)。如果我为 audioRecord 打开另一个线程,如何为复用器提供逐帧音频?谢谢!
    • 我在 camera.startPreview() 之后有 audioRecord.startRecording。主要思想是视频被编码并发送到相机线程中的复用器。音频链位于自己的线程\Runnable 中,该线程在 while{} 中循环,并在样本准备好(此处为 200 毫秒)时从 audioRecorder 读取音频样本,然后发送到编码器和复用器。 Runnable 与 audioRecord start 一起创建\启动: MicrophoneInput mi = new MicrophoneInput(); audioThread = new Thread(mi);
    • 还有一个想法:可以在 onPreviewFrame 中添加一个同步对象,以便在每个视频帧进入时推送音频线程。因此每个视频帧都会触发音频缓冲区在单独的线程中发送到编码器。但它需要为 audioRecorder 分配更精确的缓冲区
    • 您需要创建 2 个 mediacodec 实例,一个用于音频,另一个用于视频,正确配置它们。在它将数据从 onPrevieFrame 发送到 videoencoder 之后,从 MicrophoneInput 中的 run() 发送到 audioencoder。只需使用循环从 audioRecorder 获取数据并发送到编码器。性能改进的空间肯定存在。并且始终将正确的时间戳发送到编码器输入 - 多路复用器基于它进行同步
    • 根据我的理解,audioRecorder 的工作方式如下:当您请求 audioRecorder.read(buffer200ms, 0, buffer200ms.length); 时,它会填充内部线程中的内部缓冲区。它只是尝试将 200ms 从内部缓冲区复制到 buffer200ms。如果内部缓冲区中的时间少于 200 毫秒,它将返回实际复制的数据大小。分配 1 秒的缓冲区并以不那么频繁的方式进行读取可能会更好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 2012-07-09
    • 1970-01-01
    相关资源
    最近更新 更多