FFmpeg 开发(11):FFmpeg + Android AudioRecorder 音频录制编码
该文章首发于微信大众号:字节活动
FFmpeg 开发系列连载:
-
FFmpeg 开发(01):FFmpeg 编译和集成
-
FFmpeg 开发(02):FFmpeg + ANativeWindow 结束视ios8备忘录频解码播映
-
FFmpegjava面试题 开发(03):androidstudio装置教程FFmpeg + OpenSLES 结束音频解码播映
-
FFmpeg 开发(04):FFmpeffmpeg.dll是什么g + OpenGLES 结束音频可ios模拟器视化播映
-
FFmpeg 开发(05):FFmpeg + OpenGLES 结束视频解码播java游戏放和视频滤镜
-
FFmpeg 开发(06):FFmpeg 播映器结束音视频同步的三种方法
-
FFmpeg 开发(07):java编译器FFmpeg + OpenGLES 结束 3D 全景播映器
-
FFmpeg 开发(08):FFmpeg 播映器视频FFmpeg烘托优化
-
FFmpeg 开发(09):FFmpeg、x264 以及 fdk-aac 编译整合
-
FFmpeg 开发(10):FFmpeg 视频录制 – 视频添加滤镜和编码
前文运用 FFmpeg 对 Android Camera2 收集的预览帧先进行烘托,然后FFmpeg运用 OpenGL 添加OpenGL滤镜,最终将烘托成果进行编码opengl和directx生成 mp4 文件。java游戏
本文将运用 Android AudioRecorder 收集opengles3.1扩展包 PCM 音频,然后运用 Fjava模拟器Fmpeg 对其opengl形式编码生成 aac 文件。
提早预告下,在该系列的下一篇文章将介绍 FFmpeg 一起对 Android Camera 收集的预览帧和 AudioRecorder 收集的音频数据进行编码,生成一个 mp4 文件。
AudioRecorder 运用
这儿运用 Android AudioRecorder API 收集音opengl版别过低频android下载装置 PCM 裸数据,然后经过 jni 传递到 Native 层供 FFmffmpeg装置peg 编码运用。
下面代码将 AudioRecoder 封装到线程里,经过接口回调的方法将 PCM 数据传出来,默许android平板电脑价格采样率为 44.1kHz,双通道立体声android什么意思,采样格局为 PCM 16 bit 。
public class AudioRecorder extends Thread {
private static final String TAG = "AudioRecorder";
private AudiojavahdxxRecord mAudioRecorffmpeg装置d = null;
private static final int DEFios下载AULT_SAMjavahdxxPLopenglskiaE_RATE = 44100;
private static final int DEFAULT_CHANNEL_LAYOUTios是什么意思 = AudioFormat.CHANNEL_IN_STEREO;
private sopengl是什么意思taios8备忘录tic final int DEFAULT_SAMPLE_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
private final AudioRecorderCallback mRecorderCallback;
popengl和directxublic AudioRecorder(AudioReopengl版别过低corderCallback callback) {
this.mRecorderCallback = callback;
}
@Override
public void run() {
final int mMinBufferSize = AudioRecord.getMinBufferSize(DEFopengl-legacyAULT_SAMPLE_RATE, DEFios14.4.1更新了什么AULT_Cjava名优馆在线六区HANNEL_LAYOUT, DEFAULopengl烘托gpu怎样设置T_SAMPLE_FORMAT);
Log.d(java游戏TAG, "run() called mMinBuffeopengl形式rSize=" + mffmpeg从入门到通晓MinBufffmpeg指令详解ferSize);
mAudioRecord = new AudioRecord(android.media.Mjava名优馆在线六区ediaRecorder.AudioSource.MIC, DEFAULT_SAMPLE_Rjava游戏ATE, DEFAULT_CHOpenGLANNEL_LAYOUT, DEFAULT_SAMPLE_FORMAT, mMinBufferSize);
try {
mAudioRecord.startRecording();
} catch (IllegalStateExceptioandroid下载装置n e) {
mRecorderCallback.onError(e.getMessage() + " [startRecording failed]");
return;
}
byte[android体系] sampleBuffer = new byte[4096];
try {
whiios14.4.1更新了什么le (!Thread.candroid下载装置urrentThread().isInterruptedios14.4值得晋级吗()) {
int rejava面试题sult = mAudioRecord.read(sampleBuffer, 0, 4096);
if (result > 0) {
mRecorderCallback.onAudioopengl是什么意思Data(sampleBuffer, result);
}
}
} catch (Exception e) {
mRecorderCallback.onError(e.getMessage())ffmpeg播映器;
}
mAudijava模拟器oRecord.release();java模拟器
mAudioRecord = null;
}ios14.4怎样样
public interface AudioRecorderCallback {
void onAudioData(byte[] data, inandroid平板电脑价格t datajava编译器Size);
void onError(String msg);
}
}
音频编码流程
音频的编码流程与视频编码流程基本上共同,为了更加清楚地展现流程android什么意思,也画了一opengles3.1扩展包张流程图如下图所示。
AudioRecjava怎样读oder 收集的 PCM 音频放入音频部队中,子线程音频编android手机码循环不断从部队中取数据进行编码,最终将编码数据写入媒体文件。
FFmpeg 两种采样格局
由于新的opengl-legacy FFmpeg 版别不再支撑对 AV_SAMPLE_FMT_S16 采样格局的音频数据进行编码,需java名优馆在线六区要运用 swr_convert 将格局转化为 AV_SAMPLE_FMT_FLTP ,而 AV_SAMPLE_FMT_S16 便是 Audiandroid什么意思oRecorder 的 AudioFormat.ENCODING_PCM_16BIT 。
两种采样格局的特色:
- AV_SAMPLE_FMT_S16 位宽 16 bit , shorffmpeg是什么意思t 型,取值规划 [-32767, 32767];
- AV_SAMPLE_FMT_FLTP 位宽 32 bit , float 型,取值规划 [-1.0, 1.0];
能够看出单声道两者仅仅取值规划上的不ffmpeg装置同,ffmpeg.dll找不到是什么状况双声道的话两者还有存储结构上的差异。
双声道 AV_SAMPLE_FMT_S16 和 AV_SAMPLE_FMT_FLTandroid的drawable类P 格局结构
从图中能够看出,双声道 AV_SAMPLE_FMT_S16 类型左右声道数据交叉存储,而双声道 AV_SAMPLE_FMT_FLTP 类型左右声道各存储在一个 planer ,了解 YUV 格局的同学能够看出这种排布办opengl和directx法有点像 YUV420SP 和 YUV420P 。
swffmpeg合并视频resample 库的 swr_convert 函数,网上看到常常有人用错,这儿简单介绍下:
/** Converandroid体系t audio.
* @param s allocated Swr contexffmpeg播映器t, with parameters set
* @param out output buffers, only the first one need be set in case of packed audio
* @param out_ffmpeg装置count amount of space avJavaailable for output in sampopengl和directxles per channel
* @param in input buffers, only the first one need to be set in case of packed audio
* @param in_count number of input samples availableopengl是什么意思 in one chanJavanel
*
* @retandroid的drawable类urn number of samples output per channel, negative valopengles3.1扩展包ue on error
*/
int swr_convert(struct SwrCojava游戏ntext *s, uint8_t **out, int out_coandroid的drawable类unt,
const uint8_t **in , int in_count);
其间 in_count 和 out_count 标明的是输入和输出每个声道的样本数量,而不是 2 个声道总的样本数,比如收集一坨ffmpeg.dll找不到是什么状况 4096 字节的双声道 AV_SAMPLE_FMT_S16 数据,那么它每个通道的样本数量是 4096 / 2(双声道) / 2(16 bits) = 1024 。
其他 AVFrame 中的 nb_samples 标明的也是每个声道的样本数量。
swr_convert 的运用:
// audioFrame->data 标明双声道 AV_SAMPLE_FMT_S16 数据
int result = swr_convert(recorder->m_swrCtx, pFramjava面试题e->data, pFrame->nb_samples, (const uopengl是什么意思int8_t **) &(audioFrame->data), audioFrame->daios模拟器taSize / 4);ffmpeg是什么意思
// result 数量一般等于 in_count , 小于 0 时标明转化失利。
代码结束
FFmpeg 编码音频数据跟编码视频数据结束相同,Android AudioRecordjavascripter 经过 jni 将 PCM 数据传递到 Native 层部队中,供 FFmpeg 编码运用。
extern "C"
JNIEXPORT void JNICALL
Java_com_byteflow_leffmpeg指令详解arnffmpeg_media_MediaRecorderContext_native_1OnAudioData(JNIEnv *env,
jobject thiz,
jbyteArray data,
jiios14.4.1更新了什么nt size) {
int len = env->GetArrayLenandroid下载装置gth (data);
unsigned char* buf = new unsigned char[lenjava名优馆在线六区];
envopengl版别过低-&android是什么手机牌子gtffmpeg指令详解;GetByteArrayRffmpeg教程egion(data, 0, len, rjavahdxxeinterpret_cast<jbyte*>(buf));
MediaRecorderContext *pContext = MediaRecorderContext::GetContext(env, thiz);
if(pContext) pContext->OnAudioData(buf, len);
delete[] bandroid手机uf;
}
为了便当读者 demo ,现在把 FFmpeg 编码音频的结束也放到一个独自的类中来结束。
class SingleAudioRecorder {
public:
SingleAudioRecorder(const char *outUrl, int sampleRate, int channelLayouOpenGLt, int sampleFormat);
~SingleOpenGLAudioRecorder();
//初步录制
int StartRecord();
//接收音频数据
int OnFrame2Encode(AudioFrame *inpffmpeg从入门到通晓utFrame);
/ffmpeg.dll是什么/连续录制
int StopRecord();
private:
//编码循环
static void StartAACEncoderThread(SingleAudioRecorder *context);
//编码一帧的函数
int EncodeFrame(AVFrame *pFrame);
private:
ThrFFmpegeadSafeQueue<ios是什么意思AudioFrame *android体系> m_frameQueue;
char m_outUrl[1024] = {0};
int m_frameIndex = 0;
int m_sjava游戏ampleRate;
int m_channios模拟器elLayout;
int m_sampleFormat;
AiOSVPacket m_avPacket;
Aopengl怎样晋级VFrame *m_pFrame = nullptr;
uint8_t *m_pFrameBuffer = nullandroid什么意思ptr;
int m_frameBufferSize;
AVCodec *m_pCodec = nulandroid是什么手机牌子lptr;
AVStream *mopengl三重缓冲_pStream = nullptr;
AVCodecCojava环境变量装备ntext *m_opengl怎样晋级pCodecCtx = nullptr;
AVFormatContext *m_pFormatCtx = nullptr;
SwrContext *m_swrCtx = nujavascriptllptr;
thread *m_encodeThreffmpeg.dll是什么ad = nullptr;
volatile int m_exit = 0;
};
SingleAudioRecoropenglskiader 在一android手机个线程里敞开编码循环,不断地从音频部队中取数据进行编码。ffmpeg教程
/android平板电脑价格/编码循环
void SingleAudioRecorder::StartAACjava名优馆在线六区EncoderThread(SingleAudioRecorder *recorder) {
LOGJavaCATE("SingleAudioRecorder::StartAACEncoderThread sjava编译器tart"java游戏);
while (!recorandroid/yunosder->m_exit || !recorder-&gjavascriptt;m_frameQueue.Empty())
{
if(recorder->m_frameQueue.Empty()) {
//部队为空,休眠等候
usleffmpeg指令详解ep(10 * 1000);
continue;
}
AudioFrame *audioffmpeg.dll是什么Frame = recorder->m_frameQueue.Pop();
Aandroid的drawable类VFrame *pFrame = recorder->m_pFrame;
//音频采样格局转化
int result = swr_convert(ffmpeg播映器recorder->m_swrCtx, pFrame->data, pFrame->nb_samples, (const uint8_t **) &(audiAndroidoFrame->Androiddata), audioFraandroid平板电脑价格me->dataSize / 4);
LOGCATE("SingleAudioRecorder::StartAACEncoderThread result=%d", result);
if(result >= 0) {
pFrame->pjava环境变量装备ts = recorder-&ffmpeg从入门到通晓gt;m_frameIndex++;
recorder->ffmpeg安卓版别下载;EncodeFrame(pFrame);ios8备忘录
}
delete audioFrameandroid的drawable类;
}
LOGCJavaATE("SingleAudioRecJavaorder::android什么意思StartAACEncoderThread end"ios8备忘录);
}
//编码一帧的函数
int SingleAudioRecoopengl-legacyrder::EncodeFrame(AVFrame *pFrame) {
LOGCATE("SingleAudioRecorder::EncodeFrame pFrame->nb_samples=%d", pFrame != nullptr ? pFrame->nb_samples : 0);
int result = 0;
rios卖肉直播不收费下载esult = avcodec_send_frame(m_pCodecCtx, pFrffmpeg教程ame);
if(result < 0)
{
LOGCATE("SingleAudioRecorder::EncodeFrame avcodec_send_frame fail. retFFmpeg=%d", resultopengl怎样晋级);
retios14.4.1更新了什么urn resuopengl形式lt;
}
while(!rios14.4.1更新了什么esult) {
result = avcodec_receive_pajava基础知识点cket(m_pCodecCtx, &m_avPacffmpeg合并视频ket);
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
returios卖肉直播不收费下载n 0;
} else if (result < 0) {
LOGCATE(android的drawable类"SingleAudioRecoandroid手机rder::EncodeFrame avcodec_receivandroid什么意思e_packet fail. ret=%d", result);
randroid是什么手机牌子eturn result;
}
LOGCATE("SingleAudioRecorder::EncodeFrame frame pandroid下载ts=ios体系%ld, size=%d", m_avPacket.pts, m_avPacket.size);
m_avPacket.stream_index = m_pStream->index;
av_interleaved_write_frame(m_pFormatCtx, &m_avPacket);
av_packet_unref(&m_avPacket);
}
return 0;
}
无缺的结束代码能够参看项目:
LearnFFmpejava环境变量装备g
技能android是什么手机牌子交流
技能交流/获取视频教FFmpeg程能够添加我的微信:Byte-Flow