Android视频编码的实现是在Android 1.5中才引入的,其设计主要围绕着Camera子系统进行。在进行Camera录像时,流程与拍照基本相同。需要了解的是,对于应用开发者而言,录像的上层接口为MediaRecorder。下图所示为原生层MediaRecorder的状态迁移过程。Android的视频编码框架代码位于mydroid\frameworks\base\media目录下。

视频编码状态图
下面简要介绍在进行录像时,Java层调用Camera原生服务的过程。下图显示的是基于CameraHardwareStub的Camera录像过程。

Camera录像过程
流程说明:
当用户需要进行录像时,首先要进行Camera设备的连接,然后进行预览,为了进行录像,需要通过扩展的Java JNI调用Camera客户端的Camera::startRecording()方法。客户端会请求Camera服务器端提供录像服务,在这一过程中,Camera服务器端会激活CAMERA_ MSG_VIDEO_FRAME消息类型,并将Camera模式设置为CAMERA_RECORDING_MODE。
为了进行录像,首先预先设置录像回调函数(在mRecordingCallback回调函数中,上层实现将收到传过去的帧),然后启动预览,下面是QualcommCameraHardware::startRecording()方法的实现过程:
代码:QualcommCameraHardware:: startRecording ()方法的实现过程
获取媒体播放服务的实现如下:
代码:MediaPlayer::getMediaPlayerService()的实现
status_t QualcommCameraHardware::startRecording(recording_callback rcb, void *ruser)
{
LOGV("start Recording E");
Mutex::Autolock l(&mLock);
{
Mutex::Autolock cbLock(&mCallbackLock);
if (mPreviewstatus) {
mRecordingCallback=rcb; //设置录像回调
mRecordingCallbackCookie=ruser; //设置录像Cookie回调
return NO_ERROR;
}
}
if (!initPreview()) { //初始化预览
LOGE("startPreview X initPreview failed. Not starting preview.");
return UNKNOWN_ERROR;
}
{
Mutex::Autolock cbLock(&mCallbackLock);
mRecordingCallback=rcb;
mRecordingCallbackCookie=ruser;
mPreviewstatus=TRUE;
mCameraRunning=mParameters.getCameraEnabledVal();
}
//向Camera驱动发送CAMERA_START_PREVIEW,开始预览
if (!native_start_preview(camerafd)) {
LOGE("main: start_preview failed!\n");
return UNKNOWN_ERROR;
}
LOGV("waiting for QCS_PREVIEW_IN_PROGRESS");
LOGV("Start Recording X");
return NO_ERROR;
}
在进行预览或者录像时,需要将图像渲染到屏幕。在这一过程中,首先需要创建PMEM预览缓冲,然后将该缓冲进行注册,接着创建frame_thread线程,下面是Qualcomm CameraHardware::initPreview()方法的实现过程:
代码:QualcommCameraHardware::initPreview()方法的实现过程
bool QualcommCameraHardware::initPreview()
{
LOGV("initPreview: preview size=%dx%d", mPreviewWidth, mPreviewHeight);
int cnt=0;
dimension->picture_width= PICTURE_WIDTH;
dimension->picture_height=PICTURE_HEIGHT;
if((native_set_dimension(camerafd, dimension) ==TRUE)) {
// 初始化SF帧
mPreviewFrameSize=mPreviewWidth * mPreviewHeight * 3/2;
//创建PMEM预览缓冲
mPreviewHeap=
new PreviewPmemPool(kRawFrameHeaderSize +
mPreviewWidth * mPreviewHeight * 3/2,
kPreviewBufferCount,
mPreviewFrameSize,
kRawFrameHeaderSize,
"preview");
if (!mPreviewHeap->initialized()) {
mPreviewHeap=NULL;
return false;
}
LOGI("hal display_width=%d height=%d\n",
(int)dimension->display_width, (int)dimension->display_height);
frame_size=(clp2(dimension->display_width * dimension->display_height *3/2));
unsigned char activeBuffer;
for (cnt=0; cnt < PREVIEW_FRAMES_NUM; cnt++) {
frames[cnt].fd=mPreviewHeap->mHeapnew[cnt]->heapID();
frames[cnt].buffer=(unsigned long)mPreviewHeap->mHeapnew[cnt]->base();
LOGE("hal_mmap #%d start=%x end=%x", (int)cnt, (int)frames[cnt].buffer,
(int)(frames[cnt].buffer+frame_size-1));
frames[cnt].y_off=0;
frames[cnt].cbcr_off=dimension->display_width * dimension->display_height;
if (frames[cnt].buffer==0) {
LOGV("main: malloc failed!\n");
return 0;
}
if (cnt==PREVIEW_FRAMES_NUM-1) {
activeBuffer=FALSE;
} else {
activeBuffer=TRUE;
}
frames[cnt].path=MSM_FRAME_ENC;
LOGV("do_mmap pbuf=0x%x, pmem_fd=%d, active=%d\n",(unsigned int)frames[cnt].buffer, frames[cnt].fd, activeBuffer);
native_register_preview_bufs(camerafd, //注册PMEM缓冲dimension,&frames[cnt],activeBuffer);
}
}
if (frame_count==1) {
frame_count--;
lastframe=frames[PREVIEW_FRAMES_NUM-1];
//创建frame_thread线程
pthread_create(&frame_thread, NULL,LINK_cam_frame,&frames[PREVIEW_FRAMES_NUM-1]);
}
return true;
}
需要说明的是,PreviewPmemPool、RawPmemPool、AshmemPool都是基于MemPool内存池的,MemPool内存池则是基于Android PMEM虚拟设备的,Android PMEM用于向用户空间提供连续的物理内存区域。Android PMEM虚拟设备的作用主要有两个方面,第一,CPU核与GPU(Graphic Processing Unit)或者VPU(Vector Permutate Unit)共享的缓冲;第二,用做Android原生服务的内存堆。
当录像结束时,要调用QualcommCameraHardware::stopRecording()方法停止录像,下面是该方法的实现过程:
代码:QualcommCameraHardware::stopRecording()方法的实现过程
void QualcommCameraHardware::stopRecording()
{
LOGV("stopRecording: E");
Mutex::Autolock l(&mLock);
int cnt=0;
{
Mutex::Autolock cbLock(&mCallbackLock);
mRecordingCallback=NULL; //清空回调
mRecordingCallbackCookie=NULL;
mReleaseRecordingFrame=TRUE;
mRecordWait.signal();
mCameraRunning=0;
if(mPreviewCallback !=NULL)
return;
mPreviewstatus=NULL;
}
native_stop_preview(camerafd); //停止预览
LOGV("stopRecording: Freeing preview heap.");
if (!frame_count) {
LINK_camframe_terminate();
if (pthread_join(frame_thread, NULL) !=0) {//结束frame_thread线程
LOGE("frame_thread exit failure!\n");
} else
LOGE("pthread_cancel succeeded on frame_thread\n");
for (cnt=0; cnt< PREVIEW_FRAMES_NUM-1; ++cnt) {
native_unregister_preview_bufs(camerafd,dimension,frames[cnt].fd,(unsigned char *)frames[cnt].buffer); //注销PMEM缓冲
}
native_unregister_preview_bufs(camerafd, dimension,lastframe.fd,(unsigned char *)lastframe.buffer);
frame_count=1;
}
mPreviewHeap=NULL;
mRecordingCallback=NULL;
LOGV("stopRecording: X");
}
在结束录像过程中,会首先将录像用的回调函数如mRecordingCallback、mRecordingCallbackCookie清空,通过native_stop_preview()向Camera驱动发送CAMERA_STOP_PREVIEW消息结束预览,然后调用pthread_join()结束frame_thread线程,后调用native_unregister_preview_bufs()注销预览用的PMEM缓冲。