android-音视频录制
目录
android 音视频录制
所用到的东西,
FBO:离屏渲染,得到视频数据,这里用FBO是为了以后扩展特效预留;
MediaMuxer:封装音视频输出成MP4
AudioRecord:录制音频;
MediaCode:编解码,把音频编码成AAC ,把视频编码成AVC也就是H264
整个流程图如下:
视频流程:
自定义GLSurfaceView,因为GLSurfaceView继承SurfaceView 把一些GL的东西做了,不用再做,
然后把SurfaceTexture给Camera,
mCamera.setPreviewTexture(surfaceTexture);
这个是离屏渲染,OpenGL 不能直接拿到相机的数据,通过绑定纹理的方式去预览,拿到每帧渲染数据;通过Renderer onDrawFrame接口回调,这个时候就进行预览绘制,和录制的离屏绘制,然后把离屏绘制的纹理id给录制类进行处理;
// 这个是手动刷新毎帧
mSurfaceTexture.updateTexImage();
// 预览相机的处理
mSurfaceTexture.getTransformMatrix(mtx);
mCameraFilter.setMatrix(mtx);
int textureId = mCameraFilter.onDrawFrame(mTextureID[0]);
// 绘制
mScreenFilter.onDrawFrame(textureId);
然后再去单独处理录制的,
录制的我使用Android自带的OpenGL es,所以需要EGL;然后通过MedicCodec 去缓冲区拿数据并编码,这里需要在同一线程,
/**
* 4.配置EGL 环境
*/
HandlerThread handlerThread = new HandlerThread("MyMediaRecorder");
handlerThread.start();
Looper looper = handlerThread.getLooper();
mHandler = new Handler(looper);
mHandler.post(new Runnable() {
@Override
public void run() {
mEGL = new MyEGL(mEGLContext, mInputSurface, mContext, mWidth, mHeight);
mMediaCodec.start();
isStart = true;
}
});
/**
* 录制 真正执行编码的函数
*
* @param textureId
* @param timestamp 时间戳
*/
public void encodeFrame(final int textureId, final long timestamp) {
if (!isStart) {
return;
}
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mEGL != null) {
mEGL.draw(textureId, timestamp);
}
getEncodeedData(false);
}
});
}
}
视频编码后的数据放到Mp4RecorderCalbackRenderer里的队列中,然后让MediaMuxer去封装,为什么要放队列?因为还有音频需要一起处理;
音频处理:
使用AudioRecord 录音然后循环取数据,
while (mIsRecording){
int len = mAudioRecord.read(mBuffer,0,mBuffer.length);
if (len>0){
if (mAacEncoder== null){
return;
}
mAacEncoder.queueData(mBuffer);
}
}
然后编码给Mp4RecorderCalbackRenderer 队列中,然后让MediaMuxer封装;
MediaMuxer是使用时间戳来同步音视频;
详细的代码: