Simple BREW Camera Application - 4 / 6 -
Implement Camera Class
Objectives of Camera Class
To create a general purpose C++ class for Cameras processing with BREW which will be reusable in other applications more sophiaticated than SimpleCamera.
Header File of Camera Class
- Camera.hpp - #ifndef __CAMERA_HPP #define __CAMERA_HPP #include#define PICTURE_WIDTH 240 // Width of image taken with camera #define PICTURE_HEIGHT 320 // Height of image taken with camera SFMTYPEDEFCLASS(Camera) class Camera { SFMSEALCOPY(Camera) public: enum StatusEnum { // Status of camera STATUS_PREVIEW, // Preview mode STATUS_FRAME, // New frame of the preview was drawn STATUS_RECORD, // Start of snapshot mode STATUS_ENCODE // Completion of photography in snapshot mode }; private: typedef Void (*NotifySPP)(StatusEnum status, SFCError error, VoidPtr reference); private: SFBCameraSmp _sfbCamera; // ICamera interface StatusEnum _camStatus; // Camera status SFBBitmapSmp _camBitmap; // Photo image in bitmap SFXRectangle _camRect; // Display area of photo // image on screen AEEMediaData _mediaData; // Media data ACharPtr _mimeType; // MIME TYPE Bool _camPreviewable; // Whether it is a possible // preview now or not? Bool _camRecordable; // Whether photography is // available in snapshot mode or not? NotifySPP _camSPP; // Callback function of camera VoidPtr _camReference; // Reference data for the // above callback function Void AfterSnapshot(Void); // Processing after snapshot // picture is taken public: Camera(Void); // Constructor virtual ~Camera(Void); // Destructor SFCError camInitialize(SFXRectangleConstRef rect, NotifySPP spp, VoidPtr reference); // Initialization of camera SFCError camPreview(Void); // Beginning of Preview mode SFCError camRecord(Void); // Beginning of snapshot mode Void camSuspend(Void); // Suspend camera processing SFCError camResume(Void); // Resume camera processing Void camTerminate(Void); // Release source SFBBitmapSmpRef GetBitmap(Void) { // Get photo image in bitmap return _camBitmap; } // Whether it is possible to preview now Bool IsPreviewable(Void) const { return _camPreviewable; } // Callback handler static Void OnCameraSHP(VoidPtr reference, AEECameraNotify* notify); // Callback handler (Body) Void OnCamera(AEECameraNotify *notify); // Get the current brightness of camera SInt16 GetCamBrightness(Void); // Get the range of brightness available for camera Bool GetCamBrightnessRange(SInt16Ptr minimum, SInt16Ptr maximum); // Set the brightness of camera Void SetCamBrightness(SInt16 value); // Get the current zoom value SInt16 GetCamZoom(Void); // Get the range of zoom values available for camera Bool GetCamZoomRange(SInt16Ptr mininum, SInt16Ptr maximum); // Set the zoom value Void SetCamZoon(SInt16 value); }; #endif
Main functions of Camera class :
- camInitialize() : initialize camera
- camPreview() : start to preview
- camRecord() : take a snapshot
- OnCamera() : handle events
Initialize Camera
Camera::camInitialize()
// Intialize Camera class // rect : display area for preview // spp : pointer to external callback function // reference : pointer to data for external callback function SFCError Camera::Initialize(SFXRectangleConstRef rect, NotifySPP spp, VoidPtr reference) { SFCError error(SFERR_NO_ERROR); // Make bitmap for photo image _camBitmap = SFXGraphics::CreateBitmap(rect.GetSize()); if (_camBitmap != null) { error = camResume(); // Preparations for camera processing if (error == SFERR_NO_ERROR) { _camRect = rect; _camSPP = spp; _camReference = reference; } } else { // Bitmap cannot be made because of insufficient memory error = SFERR_NO_MEMORY; } if (error != SFERR_NO_ERROR) { camTerminate(); } return error; }
1st argument: clipped size of photo image as SFXRectangle type
2nd argument: external callback function after handling events
The signature of this function is as follows.
Void foo(Camera::StatusEnum status, SFCError error, VoidPtr reference); // foo is function name
3rd argument: pointer to the data for the function that is the 2nd argument
Camera::camResume()
// Initialize camera SFCError Camera::camResume(Void) { SFCError error(SFERR_NO_ERROR); // Get instance of camera if ((_sfbCamera = SFBCamera::NewInstance()) != null) { _camPreviewable = true; _camRecordable = false; // Register internal callback error = _sfbCamera->RegisterNotify(OnCameraSHP, this); if (error == SFERR_NO_ERROR) { AEESize size; size.cx = PICTURE_WIDTH; size.cy = PICTURE_HEIGHT; error = _sfbCamera->SetSize(&size); if (error == SFERR_NO_ERROR) { // Set the size of photo image error = _sfbCamera->SetDisplaySize(&size); } } } else { // instance of camera cannot be gotten // because of insufficient memory error = SFERR_NO_MEMORY; } if (error != SFERR_NO_ERROR) { camSuspend(); } return error; }
When the Camera needs to suspend its usage, all phone resources (memory) that were being used should be released. And when it resumes, it should be instantiated and initialized again.
The camResume() function is for getting an instance of camera by using SFBCamera::NewInstance() and registering the internal callback functions for camera events by using SFBCamera::RegisterNotify().
The signature of RegisterNotify() is as follows.
SFCError RegisterNotify(PFNCAMERANOTIFY notify, VoidPtr data);
The variable notify is a pointer to the callback function and data is a pointer to the data of the callback function.
In the above example, OnCameraSHP() of Camera is registered.
The callback function is the static function with the following signature.
Void foo(VoidPtr reference, AEECameraNotify *notify);
* The status of camera is saved in nStatus of AEECameraNotify structure.
The size of the photo image AEESize, must be always set by calling SFBCamera::SetDisplaySize() before moving into Preview Mode.
In the example of the Camera class, the size of photo image for both Preview and Snapshot is fixed.
* By using SFBCamera::GetDisplaySizeList() or SFBCamera::GetSizeList(), the size of the photo image can modified to fit a mobile handset.
Start the Preview Mode
Camera::camPreview()
// Start to preview SFCError Camera::camPreview(Void) { SFCError error(SFERR_NO_ERROR); if (_sfbCamera != null) { _camStatus = STATUS_PREVIEW; _camPreviewable = false; _camRecordable = false; error = _sfbCamera->Preview(); // Boot up the camera for previewing } else { error = SFERR_FAILED; } return error; }
The status of camera is saved in nCmd or nSubCmd included in the 2nd argument AEECameraNotify of the callback function foo.
The status of camera may be known by the value of 3 member variable: nStatus, nCmd and nSubCmd, but here it is found only by the value of the _camStatus member variable of the Camera class.
Take Photo in Snapshot Mode
Camera::camRecord()
// take photo in snapshot mode SFCError Camera::camRecord(Void) { SFCError error(SFERR_NO_ERROR); if (_sfbCamera != null) { _camPreviewable = false; _camRecordable = false; _camStatus = STATUS_RECORD; error = _sfbCamera->Stop(); // end of preview // event handler is called at the end of preview // photo in snapshot mode is taken in this handler } else { error = SFERR_FAILED; } return error; }
Preview Mode cannot directly change into Snapshot Mode, and it is necessary to stop the Preview mode by calling SFBCamera::Stop().
At this point, the event CAM_STATUS_DONE will occur.
And STATUS_RECORD should be set on the _camStatus member variable just before the Preview Mode ends.
When the internal callback function recognizes that the value of _camStatus is STATUS_RECORD, the mode will be changed to Snapshot Mode.
Internal Callback Function
Camera::OnCameraSHP() registered by using SFBCamera::RegisterNotify() is a internal callback function. This is because callback functions must be static functions.
OnCamera() is called from OnCameraSHP(). This means that the real body of the internal callback function is OnCamera().
// Internal Callback Handler Void OnCameraSHP(VoidPtr reference, AEECameraNotify *notify) { // call the body of Internal Callback Handler static_cast<CameraPtr>(reference)->OnCamera(notify); return; }
// Internal Callback Handler ( body ) Void Camera::OnCamera(AEECameraNotify* notify) { switch (notify->nStatus) { case CAM_STATUS_START: // completion of camera bootup if (_camStatus == STATUS_PREVIEW) { _camRecordable = true; // call external callback function _camSPP(_camStatus, SFERR_NO_ERROR, _camReference); } break; case CAM_STATUS_FRAME: // new frame has been gotten if (_camStatus == STATUS_PREVIEW) { SFBBitmapSmp bitmap; // The photo image of the camera is obtained as a bitmap. if (_sfbCamera->GetFrame(&bitmap) == SFERR_NO_ERROR) { // Clip displayed area from photo image _camBitmap->BltIn(SFXRectangle(0, 0, _camRect.GetSize()), bitmap, _camRect.GetOrigin()); } // Call external callback function _camSPP(STATUS_FRAME, SFERR_NO_ERROR, _camReference); SFXGraphicsPtr pg = SFXGraphics::GetInstance(); // The obtained image is displayed on the screen. pg->BitBlt(_camRect, _camBitmap, SFXGrid(0, 0)); pg->Update(); // update screen } break; case CAM_STATUS_DONE: // Completion of processing if (_camStatus == STATUS_RECORD) { _camStatus = STATUS_ENCODE; _sfbCamera->DeferEncode(true); // Set delay encode mode _sfbCamera->SetMediaData(&_mediaData, _mimeType); // Take a picture in the snapshot mode. _sfbCamera->RecordSnapshot(); } else if (_camStatus == STATUS_ENCODE) { AfterSnapshot(); } break; case CAM_STATUS_FAIL: case CAM_STATUS_ABORT: // call external callback function _camSPP(_camStatus, EFAILED, _camReference); break; } return; }
The external callback function registered by using Camera::camInitialize() is called with camera status and error code as argument.
The first case statement is for handling the CAM_STATUS_START event that will occur when the camera is booted up.
The second case statement is for handling the CAM_STATUS_FRAME event that will occur when a new image is taken every fixed period in Preview Mode ( this period can be changed by using SFBCamera::SetFramesPerSecond() ).
The code for displaying the photo image only is as follows.
// _sfbCamera is the instance of camera. SFBBitmapSmp bitmap; // The photo image of the camera is obtained as a bitmap. if (_sfbCamera->GetFrame(&bitmap) == SFERR_NO_ERROR) { // Clip displayed area from photo image _camBitmap->BltIn(SFXRectangle(0, 0, _camRect.GetSize()), bitmap, _camRect.GetOrigin()); } // call external callback function _camSPP(STATUS_FRAME, SFERR_NO_ERROR, _camReference); // get instance of screen SFXGraphicsPtr pg = SFXGraphics::GetInstance(); // transfer image to screen pg->BitBlt(_camRect, _camBitmap, SFXGrid(0, 0)); // update screen pg->Update();
*1. When using BREW API, it is necessary to explicitly release the bitmap gotten by using ICAMERA_GetFrame(). But SophiaFramework UNIVERSE automatically releases an image when the control is out of its scope.
*2. As noise canceling functions will not work in Preview Mode, images taken in this mode should not be used for processing.
The 3rd case statement is for handling the CAM_STATUS_DONE event. The CAM_STATUS_DONE event will occur when calling SFBCamera::Stop() which ends the Preview Mode or SFBCamera::RecordSnapshot() which is for taking a picture in the Snapshot Mode
By utilizing this feature, changing into the Snapshot Mode is implemented in the callback function; not by calling SFBCamera::Stop() found in camRecord() of the Camera class.
As Delay Encode is being used, SFBCamera::DeferEncode() is called with an initial value of true. Then SFBCamera::SetMediaData(), SetMediaData(), SFBCamera::RecordSnapshot() are all respectively called sequentially.
* With Regard to calling SetMediaData(), arbitrary values can be set because the photo image is not saved as file.
After SFBCamera::RecordSnapshot() is called, a CAM_STATUS_DONE event will occur when a photo is taken. The photo image can be retrieved by using SFBCamera::GetFrame() function.
At this time, the mode of camera is changed into a waiting staus that is neither Preview Mode nor the Snapshot Mode. To change into Preview Mode, SFBCamera::Preview() needs to be called ( In the Camera class, camPreview() needs to be called ).
In Camera class, the photo image is clipped with the appropriate size in AfterSnapshot(), saved in the _camBitmap member variable and retrieved by using Camera::GetBitmap().
The other case statements are for handling errors.
Contol the Brightness and Zoom
// Get current brightness SInt16 Camera::GetCamBrightness(Void) { SInt16 result(0); if (_sfbCamera != null) { SInt32 value; AEEParmInfo info; // Get brightness if (_sfbCamera->GetParm(CAM_PARM_BRIGHTNESS, &value, (SInt32Ptr)&info) == SFERR_NO_ERROR) { result = (SInt16)value; } } return result; } // Get range of brightness Bool Camera::GetCamBrightnessRange(SInt16Ptr minimum, SInt16Ptr maximum) { Bool result(false); *minimum = *maximum = 0; if (_sfbCamera != null) { Bool support; if (_sfbCamera->IsBrightness(&support) == SFERR_NO_ERROR) { if (support) { SInt32 value; AEEParmInfo info; // Get range if (_sfbCamera->GetParm(CAM_PARM_BRIGHTNESS, &value, (SInt32Ptr)&info) == SFERR_NO_ERROR) { *minimum = (SInt16)info.nMin; *maximum = (SInt16)info.nMax; result = true; } } } } return result; } // Set brightness Void Camera::SetCamBrightness(SInt16 value) { if (_sfbCamera != null) { if (_camRecordable) { // Set brightness _sfbCamera->SetBrightness(value); } } } // Get current zoom value SInt16 Camera::GetCamZoom(Void) { SInt16 result(0); if (_sfbCamera != null) { SInt32 value; AEEParmInfo info; // Get zoom value if (_sfbCamera->GetParm(CAM_PARM_ZOOM, &value, (SInt32Ptr)&info) == SFERR_NO_ERROR) { result = (SInt16)value; } } return result; } // Get range of zoom value Bool Camera::GetCamZoomRange(SInt16Ptr minimum, SInt16Ptr maximum) { Bool result(false); *minimum = *maximum = 0; if (_sfbCamera != null) { Bool support; if (_sfbCamera->IsZoom(&support) == SFERR_NO_ERROR) { if (support) { SInt32 value; AEEParmInfo info; // Get range if (_sfbCamera->GetParm(CAM_PARM_ZOOM, &value, (SInt32Ptr)&info) == SFERR_NO_ERROR) { *minimum = (SInt16)info.nMin; *maximum = (SInt16)info.nMax; result = true; } } } } return result; } // Set zoom value Void Camera::SetCamZoom(SInt16 value) { if (_sfbCamera != null) { if (_camRecordable) { // Setting zoom value _sfbCamera->SetZoom(value); } } }