Step3:获取JPEG Image,并存储JPEG Image,生成JPEG Image的缩略图显示在Camera窗口的右上角。在GrabRawFrame函数的基础上,我们需要将获取的原始数据转化成JPEG格式的数据,所以我们将之前GrabRawFrame获得的原始数据传给GrabJpegFrame(void * buffer)函数,返回满足要求的JPEG格式的数据。随后通过回调函数,向CameraService发送CAMERA_MSG_COMPRESSED_IMAGE消息,CameraService收到该消息之后调用JPEG Image处理函数handleCompressedPicture。
void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) { sp<ICameraClient> c = mCameraClient; if (c != NULL) { c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem); } mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE); }
handleCompressedPicture和之前的处理函数不同,而是将消息和数据直接(其实是间接,还要通过Camera Client端,Camera JNI, Android.hardware.Camera)交给上层AP来处理。包括JPEG Image Storage和 Create Image Thumbnail。
在定义的延迟时间内,在Preview Layout中显示Capture image,之后通过调用restartPreview,恢复到Preview Mode状态下。
(3)VideoCamera Preview Display
当由Capture Preview状态切换到VideoPreview状态进入VideoCamera模式时,首先VideoCamera模式提供给用户的是Preview Display,这部分同Camera Preview Display。
int CameraHardware::previewThread() { mLock.lock(); int previewFrameRate = mParameters.getPreviewFrameRate(); mLock.unlock(); Mutex::Autolock lock(mPreviewLock); if (!previewStopped && mPreviewBuffer != 0 && mRawBuffer !=0 && mDataFn) { int delay = (int)(1000000.0f / float(previewFrameRate)); ①mCamera.GrabRawFrame(mHeap->getBase()); if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){ ②mCamera.GrabPreviewFrame(mHeap->getBase(), mPreviewHeap->getBase()); ③mDataFn(CAMERA_MSG_PREVIEW_FRAME, mPreviewBuffer, mUser); delay-=100; } ①mRecordingLock.lock(); if ((mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) && mRecordBuffer != 0 && mTimestampFn) { ②mCamera.GrabRecordFrame(mHeap->getBase(), mRecordHeap->getBase()); ③nsecs_t timeStamp = systemTime(SYSTEM_TIME_MONOTONIC); ④mTimestampFn(timeStamp, CAMERA_MSG_VIDEO_FRAME, mRecordBuffer, mUser); delay-=100; } mRecordingLock.unlock(); usleep(delay); } return NO_ERROR; }
在VideoCamera模式下,当用户通过ClickShutterButton进入Camera Recording状态时,用户看到的是Camera Recording Preview Display,从数据的显示过程同Camera Preview Display,但在此状态下,需要考虑到向Opencore框架,也就是CameraInput模块投递由Camera硬件采集的Record数据。CameraHardware不仅需要向Preview缓冲区投递数据,同时还要向CameraInput传送数据。如上图所示。
在Camera Recording状态下,libcamera_client.so端的回调函数(也就是CameraListener类定义的回调函数)不再由JNICameraContext类来实现,而是由AndroidCameraInputListener实现,换句话说,在CameraInput中的mListener成员变量是由AndroidCameraInputListener来初始化的。
Location:frameworks/base/include/camera/Camera.h class CameraListener: virtual public RefBase { public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0; virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0; virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0; };
在整个Androi系统中,总共有三个类来分别实现这个抽象类,他们分别是JNICameraContext、AndroidCameraInputListener、CameraSourceListener类。
①Location:frameworks/base/core/jni/android_hardware_Camera.cpp class JNICameraContext: public CameraListener ②Location:external/opencore/android/author/Android_camera_input.h class AndroidCameraInputListener: public CameraListener ③Location:frameworks/base/core/jni/android_hardware_Camera.cpp class CameraSourceListener: public CameraListener
而具体实现上,由于CameraInput只需要带时间戳的数据,所以AndroidCameraInputListener只实现了postDataTimestamp回调函数。
void AndroidCameraInputListener::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) { if ((mCameraInput != NULL) && (msgType == CAMERA_MSG_VIDEO_FRAME)) { mCameraInput->postWriteAsync(timestamp, dataPtr); } }
根据Opencore框架中CameraInput中的实现,CameraInput可以作为CameraClient端得一个实例,通过Camera和CameraService架构实现包括预览,录像在内的所有功能。
但在目前的Camera子系统中,Camera Recording模式与Camera Capture模式共享同一个CameraDevice实例,Camera Recording的预览是通过使用Camera Capture模式下的Surface实现的,即Camera Recording通过调用Camera Capture中的setPreviewDisplay和底层CameraHardware层的previewThread线程实现Camera Recording预览。