首页 > 其他分享 >基于FFmpeg的音频编码(PCM数据编码成AAC android)

基于FFmpeg的音频编码(PCM数据编码成AAC android)

时间:2023-06-01 10:03:04浏览次数:51  
标签:数据编码 FFmpeg AAC void PCM System private loadLibrary pcm


概述


在Android上实现录音,并利用 FFmpeg将PCM数据编码成AAC。


详细




之前做的一个demo,Android录音获取pcm数据(音频原始数据),然后利用 FFmpeg将PCM数据编码成AAC。

一、准备工作

开发环境

jdk1.8 

Eclipse Luna Service Release 1 (4.4.1)

运行环境:

华为荣耀6(Android4.4)、华为p9(Android7.0)

二、程序实现

代码截图如下:

基于FFmpeg的音频编码(PCM数据编码成AAC android)_FFmpeg

该demo依赖v7包。

FFAacEncoderDemo工程src目录

  • MainActivity.java是主界面,用来控制录音开始和结束。
  • FFAacEncoder.java时native方法,用来和jni通信。

jni目录:

  • include目录下是FFmpeg的一些.h文件
  • libs目录下是FFmpeg编译的so
  • AacCoderc 音频编码
  • cn_vn_aacEncoder_jni_FFAacEncoderJni jni代码与java通信。

1 录音(获取pcm数据)

开始录音

private void startRecord(){  
  
    Log.i(TAG, "startRecord mIsRecording="+mIsRecording);  
    if(!mIsRecording){  
        mIsRecording = true;  
        synchronized (mLock) {  
            mAudioRecordGetExit = false;  
        }  
        //初始化ffmpeg 编码器  
        mFFAacEncoderJni.start();  
        //创建录音线程、开始录音  
        mAudioRecordGetThread = new Thread(new AudioRecordGet());  
        mAudioRecordGetThread.start();  
    }  
}

关闭录音

private void stoptRecord(){  
    if(mIsRecording){  
        synchronized (mLock) {  
            mAudioRecordGetExit = true;  
        }  
        mIsRecording = false;  
    }  
}

具体录音通过使用AudioRecord。

private class AudioRecordGet implements Runnable{  
    private AudioRecord mAudioRecord;  
    private static final boolean PCM_DUMP_DEBUG = true;  
    private static final boolean AAC_DUMP_DEBUG = false;  
    private int mAudioSource = MediaRecorder.AudioSource.MIC;  
    //采样频率,采样频率越高,音质越好。44100 、22050、 8000、4000等  
    private int mSampleRateHz = 8000;  
    //MONO为单声道 ,STEREO为双声道  
    private int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;  
    //编码格式和采样大小,pcm编码;支持的采样大小16bit和8bit,采样大小越大,信息越多,音质越好。  
    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;  
    //该size设置为AudioRecord.getMinBufferSize(mSampleRateHz, mChannelConfig, mAudioFormat); 编码aac时会失败。  
    private int mBufferSizeInBytes = 2048;//AudioRecord.getMinBufferSize(mSampleRateHz, mChannelConfig, mAudioFormat);  
    private AudioPCMData mAudioPCMData;  
    public AudioRecordGet() {  
        Log.i(TAG, "AudioRecordGet ");  
        mAudioPCMData = new AudioPCMData(mBufferSizeInBytes);  
        mAudioRecord = new AudioRecord(mAudioSource,  
                mSampleRateHz, mChannelConfig, mAudioFormat, mBufferSizeInBytes);  
        Log.i(TAG,"mBufferSizeInBytes="+mBufferSizeInBytes);  
    }  
    @Override  
    public void run() {  
        mAudioRecord.startRecording();  
        FileOutputStream outPCM = null;  
        try {  
            if (PCM_DUMP_DEBUG) {  
                String File = "/sdcard/test.pcm";  
                outPCM = new FileOutputStream(File);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        for(;;){  
            synchronized (mLock) {  
                if(mAudioRecordGetExit){  
                    break;  
                }  
            }  
            //读取录音数据  
            int readSize = mAudioRecord.read(mAudioPCMData.mData, 0, mBufferSizeInBytes);  
            if (AudioRecord.ERROR_INVALID_OPERATION != readSize) {  
                if (PCM_DUMP_DEBUG && null != outPCM) {  
                    try {  
                        outPCM.write(mAudioPCMData.mData, 0, readSize);  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
                mAudioPCMData.mFrameSize = readSize;  
                Log.i(TAG, "audio pcm size="+readSize);  
                //设置pcm数据,进行aac编码  
                mFFAacEncoderJni.setPcmData(mAudioPCMData.mData, readSize);  
            }  
        }  
        if(PCM_DUMP_DEBUG && null != outPCM){  
            try {  
                outPCM.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        //停止录音、释放  
        mAudioRecord.stop();  
        mAudioRecord.release();  
        //停止音频编码  
        mFFAacEncoderJni.stop();  
        Log.i(TAG,"AudioRecordGet thread exit success");  
    }         
}


2 PCM编码成AAC

1 初始化编码器

public class FFAacEncoder {  
    private String TAG = "FFAacEncoder java";  
    //load .so  
    static{  
        System.loadLibrary("avcodec-57");  
        System.loadLibrary("avdevice-57");  
        System.loadLibrary("avfilter-6");  
        System.loadLibrary("avformat-57");  
        System.loadLibrary("avutil-55");  
        System.loadLibrary("postproc-54");  
        System.loadLibrary("swresample-2");  
        System.loadLibrary("swscale-4");  
        System.loadLibrary("aacEncoder");  
    }  
      
    private int mNativeContext = 0;  
    //初始化编码器  
    private native final void nativeStart();  
    //对pcm数据进行编码  
    private native final void nativeSetPcmData(byte[] pcm, int len);  
    //必要的清理  
    private native final void nativeStop();  
      
    public void start(){  
        nativeStart();  
    }  
      
    public void setPcmData(byte[] pcm, int len){  
        nativeSetPcmData(pcm, len);  
    }  
      
    public void stop(){  
        nativeStop();  
    }  
}

调用nativeStart方法。

2 音频编码

//设置pcm数据,进行aac编码  
mFFAacEncoderJni.setPcmData(mAudioPCMData.mData, readSize);

调用nativeSetPcmData

C++层代码,通过编码获取的AAC原始数据不同播放(存储在/sdcard/test.aac文件中,不能播放),

需要添加adts header(不懂的可以了解一下AAC格式),这样才可以正常播放。/sdcard/adts.aac该文件添加了header,可以正常播放。

三、运行效果

运行效果:

基于FFmpeg的音频编码(PCM数据编码成AAC android)_数据_02

运行结果将生成文件 /sdcard/test.aac

基于FFmpeg的音频编码(PCM数据编码成AAC android)_音频编码_03

四、其他补充




注:本文著作权归作者,由demo大师宣传,拒绝转载,转载需要作者授权




标签:数据编码,FFmpeg,AAC,void,PCM,System,private,loadLibrary,pcm
From: https://blog.51cto.com/u_7583030/6392472

相关文章

  • ffmpeg 视频截取-合并
    ffmpeg截取视频ffmpeg-ss00:00:00-i~/1.mp4-ccopy-t00:21:00out.mp4截取从00:00:00开始持续时间21分钟的视频时间被指定为HH:MM:SS.MILLISECONDS。例如,您可以告诉FFmpeg寻找01:02:03——即电影1小时的第2分钟的第3秒!-t范围您可以使用参数指定所需剪辑的持续......
  • [音视频处理] FFmpeg使用指北1-视频解码
    本文将详细介绍如何使用ffmpeg4.4在C++中解码多种格式的媒体文件,这些媒体文件可以是视频、视频流、图片,或是桌面截屏或USB摄像头的实时图片。解码文件后,还将每帧图片转换为OpenCV的Mat格式以供后续使用。目录1基于ffmpeg的媒体文件解码1.1简介1.2详细代码2ffmpeg函数解释2.1......
  • cmd合并多个ts文件,ffmpeg快速转ts为mp4文件,通过m3u8合并文件
    摘自:https://blog.csdn.net/qq_33957603/article/details/1227638891、如何合并多个ts文件进入目录执行如下cmd命令即可copy/b*.tsnew.ts  2、如何将ts转为mp4ffmpeg下载官网:https://ffmpeg.org/github下载稳定版:https://github.com/BtbN/FFmpeg-Builds/releases下......
  • Python 标准类库-因特网数据处理之Base64数据编码
    该模块提供将二进制数据编码为可打印ASCII字符并将这种编码解码回二进制数据的功能。它为RFC3548中指定的编码提供编码和解码功能。定义了Base16、Base32和Base64算法,以及事实上的标准Ascii85和Base85编码。RFC3548编码适用于对二进制数据进行编码,以便可以安全地通过电子邮件......
  • FFMpeg笔记(十二)MP4 box解析
      MP4包含3大box。一、ftypfiletypebox,包含视频文件使用的mp4标准,也作为probemp4的标志;二、moov包含媒体的元数据信息,包含一个mvhd(也就是headerbox)和若干个trak(track)。trak包含一条音/视频轨道信息和音视频数据的编码格式、音视频数据样本、chunks的大小,存储位置,PTS等......
  • 转换视频格式|压缩视频|使用ffmpeg
    代码如下importos.pathimportsubprocessdefcompress_video(origin_file=None,target_file=None,quality=10):#压缩质量(值越小,视频越小)#如果文件存在就删除ifos.path.exists(target_file):os.remove(target_file)ifnotos.path.ex......
  • 使用ffmpeg将内存中的裸流打包成可播放的MP4文件,并输出到内存中
     前两天项目上有个需求,要求大概是这样的,输入端是一帧一帧的h264裸流(本示例只支持h264裸流,h265可基于本示例自己开发,在此我就不过多阐述了)和一个时间,要求输出根据这个时间来产生一个前后各延伸一段时间的视频(伴随录像),且伴随录像是可直接播放的MP4文件。但是产生的视频文件不是直接......
  • ffmpeg 下载链接(exe,源码,include,lib,dll,a,so)
    Releasen4.2.9·FFmpeg/FFmpeg(github.com) 源码DownloadFFmpeg 官网exeBtbN/FFmpeg-Builds(github.com) build,可以编译的,可以下载动态库,可以生成编译文件......
  • Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现
    开发背景好多开发者可能疑惑,外部数据实时预览播放,到底有什么用?是的,一般场景是用不到的,我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块,不过也遇到这样的场景,部分设备输出编码后(视频:H.264/H.265,音频:AAC/PCMA/PCMU)的数据,比如无人机或部分智能硬件设备,回调出来的H.26......
  • Spring boot 整合 ffmpeg 实现给视频添加文字水印 只有上传minio(理论通用!!)
    只要有ffmpeg命令理论可以实现所有ffmpeg能做的的事儿!!思路:前端上传视频通过commons-io的FileUtils.copyInputStreamToFile()将流复制到文件中java执行ffmpeg命令对这个文件进行转换输出到另外一个临时文件在将添加水印后的文件转成inputStream流上传到minio(本人小白可能有......