基于FFmpeg的音频编码(PCM数据编码成AAC android)
概述
详细
之前做的一个demo,Android录音获取pcm数据(音频原始数据),然后利用 FFmpeg将PCM数据编码成AAC。
一、准备工作
开发环境
jdk1.8
Eclipse Luna Service Release 1 (4.4.1)
运行环境:
华为荣耀6(Android4.4)、华为p9(Android7.0)
二、程序实现
代码截图如下:

该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,可以正常播放。
三、运行效果
运行效果:

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

四、其他补充
博客地址:http://blog.csdn.net/vnanyesheshou/article/details/54560684
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
基于FFmpeg的音频编码(PCM数据编码成AAC android)的更多相关文章
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
		
http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...
 - 最简单的基于FFmpeg的移动端样例附件:Android 自带播放器
		
===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...
 - FFmpeg(11)-基于FFmpeg进行音频重采样(swr_init(), swr_convert())
		
一.包含头文件和库文件 修改CMakeLists # swresample add_library(swresample SHARED IMPORTED) set_target_properties( ...
 - 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)
		
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
 - 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)
		
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
 - [总结]FFMPEG视音频编解码零基础学习方法--转
		
ffmpeg编解码学习 目录(?)[-] ffmpeg程序的使用ffmpegexeffplayexeffprobeexe 1 ffmpegexe 2 ffplayexe 3 ffprobeexe ...
 - FFMPEG视音频编解码零基础学习方法
		
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...
 - FFMPEG视音频编解码零基础学习方法-b
		
感谢大神分享,虽然现在还看不懂,留着大家一起看啦 PS:有不少人不清楚“FFmpeg”应该怎么读.它读作“ef ef em peg” 0. 背景知识 本章主要介绍一下FFMPEG都用在了哪里(在这里仅 ...
 - [总结]FFMPEG视音频编解码零基础学习方法
		
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...
 
随机推荐
- Unity3d操作的一些技巧知识点和BUG解决方案
			
自己记录一些东西,转载请良心注明出处. 1.如何同时打开两个UNITY3D项目. 有时候需要对比,或者需要添加另一个项目的某资源到目前项目,同时打开两个项目看起来会比较明了.如果直接打开的话, ...
 - Oracle约束的启用和停用
			
关于Oracle的约束概念和基本操作,我已经在以前的<Constraint基础概念>.<Constraint的简单操作>两篇文章中有过比较详细的介绍了,但是对于如何停用和启 ...
 - JAVA笔记-如何将百万级数据高效的导出到Excel表单
			
今天,一朋友问我使用JAVA有没有什么办法导出百万级的数据到Excel工作表. 当时我的第一个念头就是这真的是一个好疯狂的念头.然后就想假如真的有这样类似的需求,我自己应该怎么做呢? ps: 首先科普 ...
 - JTable常见用法细则
			
JTable是Swing编程中很常用的控件,这里总结了一些常用方法以备查阅.欢迎补充,转载请注明作者与出处. 一.创建表格控件的各种方式:1) 调用无参构造函数. JTable table = ne ...
 - XCL-Charts画曲线图(CurveChart) 例2
			
还有一个横向的曲线图(CurveChart) 效果: 代码: //图基类 chart = new CurveChart(); //图所占范围大小 chart.setChartRange(0, 0, t ...
 - Spring与web MVC的整合——Spring的应用上下文管理
			
问题1 如何让web容器加载你的web MVC框架 对于基于servlet的web容器来说,遵循的是servlet规范,入口配置文件是web.xml.这类web容器会在启动的时候会而且仅会加载如下三种 ...
 - 玩转OpenStack
			
一.OpenStack包含那些内容 1.预备知识 首先会有虚拟化和云计算的“预备知识”,会介绍 KVM,IaaS 等技术. 2.OpenStack核心 包含OpenStack的架构和和各个核心组件. ...
 - 浅析Linux线程调度
			
在Linux中,线程是由进程来实现,线程就是轻量级进程( lightweight process ),因此在Linux中,线程的调度是按照进程的调度方式来进行调度的,也就是说线程是调度单元.Linux ...
 - ASP.NET与ASP.NET  MVC 中Cache的总结
			
Cache有多种翻译,可以是高速缓冲存储器,也可以是法国的服装品牌,本文只是简单的谈谈就是ASP.NET 中Cache,做过Web应用程序的都知道,如果网站访问量比较大,系统应用程序可以将那些频繁访问 ...
 - 巧妙利用函数的惰性载入提高javascript 代码性能
			
在 javascript 代码中,因为各浏览器之间的行为的差异,我们经常会在函数中包含了大量的 if 语句,以检查浏览器特性,解决不同浏览器的兼容问题. 例如,我们最常见的为 dom 节点添加事件的函 ...