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缓冲。