Camera-enable Your Applications with BREW’s ICamera APIs

Camera-enable Your Applications with BREW’s ICamera APIs

eginning in BREW 2.1, QUALCOMM introduced the ICamera API to support still and motion image capture from the image sensor found on many of today’s mid- and high-end BREW-enabled wireless handsets. This interface lets you configure the image sensor, obtain bitmaps suitable for painting on the display to present an image viewfinder, as well as capture and encode still and moving images in formats including JPEG and 3GPP. In this article, you’ll learn how to configure and use QUALCOMM’s BREW ICamera interface in C.

Getting Started
Before you begin, it’s important to look at the business case for your camera-based application. There are many kinds of applications that can be camera-enabled: inventory control, entertainment, and messaging applications, for example, not to mention special applications that require video such as character, bar-code, or facial recognition applications.

In conjunction with the business case, not all handsets have ICamera support, so you should be sure to check the handset data sheets available from QUALCOMM. Moreover, some handsets support different options for ICamera; some handsets offer greater control over image capture options such as exposure settings and the like.

Another business-case concern you must consider is that of the requirements of the operators through which you will launch your application. For example, some carriers dictate that images may only be moved from the handset using the Multimedia Messaging Service (MMS) available as part of their service package, so if you’re considering building an application that relies on sharing images off-handset, you’d be wise to consider this restriction when establishing your business case.

As with BREW’s other multimedia interfaces, the ICamera interface is a highly asynchronous interface, with your interaction being split between setting parameters, issuing requests through method calls, and responding to ICamera requests through the callback you register. The typical flow when using ICamera is this:

  1. You begin by calculating the screen bounds on the display where you will show the camera viewfinder.
  2. Next, create an instance of the ICamera interface using ISHELL_CreateInstance.
  3. With the newly-created ICamera interface in hand, register a callback handler that the ICamera interface invokes when changing state or as new images become available.
  4. After creating the ICamera interface and registering a callback handler, you will set basic options controlling the camera’s behavior including exposure options. Most applications should set the camera to a fully automatic mode; some high-performance applications, or those intended for integration with the handset firmware, might provide a sophisticated user interface controlling all of the ICamera interface’s options for exposure control, white balance, and so forth.
  5. Once the camera is configured, interaction with ICamera consists of interpreting user events (such as a request for image capture) and invoking the appropriate ICamera methods, or responding to ICamera requests through your callback function.

Creating and Configuring the ICamera Interface
Interestingly, creating an instance of ICamera does not require privilege in the application’s MIF file; a simple call to ISHELL_CreateInstance suffices:

int Camera_New( CApp* pThis ){  int nErr = 0;    nErr = ISHELL_CreateInstance( pThis->a.m_pIShell, AEECLSID_CAMERA,                                 (void**)&pThis->pICamera );  if( SUCCESS == nErr )  {    AEESize previewSize = {0};    ICAMERA_RegisterNotify( pThis->pICamera, CameraNotify, pThis );  = pThis->previewRect.dx;  = pThis->previewRect.dy;    ICAMERA_SetDisplaySize( pThis->pICamera, &previewSize );    // Setup extra params    ICAMERA_SetParm( pThis->pICamera,              CAM_PARM_FLASH,              CAM_FLASH_AUTO,              0 );  }  return nErr;}

This code first creates an ICamera interface, and then uses it to register the callback function that ICamera will invoke when the camera changes state with ICAMERA_RegisterNotify. Next, it sets the camera viewfinder size?called the preview?based on a rectangle established in the application using ICAMERA_SetDisplaySize. The ICamera interface will attempt to honor the bounds given when creating bitmaps for the preview display, although if it can’t, it may provide smaller bitmaps instead. Finally, the code puts the camera’s flash in automatic mode.

While a full list of camera parameters is beyond the scope of this article (the AEECamera.h file and BREW documentation both cover the options in exhaustive detail), you can rest assured that most common camera functions are covered, including details such as encoding quality, the number of frames per second to capture for video, sharpness, zoom, rotation, exposure, white balance, and focus for handsets with variable-focus lenses. In addition, many of the parameters also have attribute setters and getters with obvious names, such as ICAMERA_SetBrightness() or ICAMERA_SetZoom(). Of course, which you use is a matter of style.

Once you have created and configured the camera, it operates as a simple state machine, being in exactly one state (or mode, according to the QUALCOMM documentation) at any given instant. Freshly created and configured, it is in Ready mode, meaning that you can either request it to provide preview bitmaps for you to display on-screen, or capture still or video images. You can always return to Ready mode from any other mode by invoking

  ICAMERA_Stop( pThis->pICamera );

As you change modes, ICamera invokes your callback function, indicating the camera’s status and mode.

Presenting Preview Images
Presenting preview images is the responsibility of your callback function. First, you must place the camera in Preview mode by invoking ICAMERA_Preview:

  ICAMERA_Preview( pThis->m_cameraData.pICamera );

Once the camera is in preview mode, ICamera periodically invokes your callback function to let it know that a new bitmap is available to display. A typical callback function might look like this:

static void CameraNotify(void* pUser, AEECameraNotify *pn){  CApp* pThis = (CApp*)pUser;  if( !pThis || !pn ) return;  switch( pn->nStatus )  {    case CAM_STATUS_FRAME:    {      IBitmap *pFrame  = NULL;      AEEBitmapInfo bi= {0};      ICAMERA_GetFrame( pThis->pICamera, &pFrame );      if(!pFrame) return;      IBITMAP_GetInfo( pFrame, &bi, sizeof(bi));      IDISPLAY_BitBlt(RM_GET_IDISPLAY(pThis),              pThis->preview.m_previewRect.x,              pThis->preview.m_previewRect.y,    ,,              pFrame,              0,0,              AEE_RO_COPY);      // Draw anything over the image you like here.      break;    }          case CAM_STATUS_DONE:      …  }}

The case we’re interested in is the CAM_STATUS_FRAME case; it’s the command sent to your callback each time a new frame is available. In turn, your callback must invoke ICAMERA_GetFrame() to obtain an IBitmap containing the captured image from the camera and blit it to the screen using IDISPLAY_BitBlt. While this sounds like a lot of work?and in fact some handsets have an option to do this for you, writing the camera contents directly to the LCD display without your intervention?it offers a lot of flexibility, because you can paint over the preview image, showing camera cross-hairs, UI controls, or the like. You could also come up with some pretty neat effects using the new 3D interfaces, too, with alpha blending and the like.

Capturing Still or Video Images
Capturing still or video images is very similar to preview mode, except that you don’t have to do as much work. What you do have to do, however, is specify the format and maximum size of the resulting file, and place the camera in Record mode. For a snapshot, the code looks like this:

{  // Must be done with a capture command; encode the captured image.  int result = 0;  AEEMediaData md  = {0};  md.clsData = MMD_FILE_NAME;  md.pData = pThis->szFileName;  md.dwSize = 0;  result = ICAMERA_SetMediaData( pThis->pICamera, &md, "image/jpg" );  if( SUCCESS == result )  {    // Set the size of this capture    result = ICAMERA_SetSize( pThis->pICamera, &pThis->dwCaptureSize);    if( SUCCESS == result )    {        // dump to the filesystem.      result = ICAMERA_RecordSnapshot( pThis->pICamera );    }  }}

This is pretty straightforward?the code begins by using the ICAMERA_SetMediaData method to indicate the file name to which the camera should record the image, as well as the desired encoding. Next, it calls ICAMERA_SetSize, which tells the camera the maximum allowable size for the media data in bytes. Once this is done, the code triggers an encoding operation by invoking ICAMERA_RecordSnapshot. If you wanted to make a movie, you could simply call ICAMERA_RecordMovie instead, and call ICAMERA_RecordMovie instead, invoking ICAMERA_Stop when the user wishes to stop recording, or ICAMERA_Pause to pause recording.

Handling Suspend and Resume Events
As you might imagine, the ICamera interface uses a lot of system resources3the image sensor consumes power, and the processor uses power when processing image data and executing the ICamera implementation and your callback. Consequently, your application is best off if it stops the ICamera interface and releases it on a suspend event (EVT_APP_SUSPEND), and re-creates it and resumes its prior state on a resume event. (EVT_APP_RESUME).

The BREW ICamera interface is a simple, asynchronous interface to still and moving image capture on today’s mid-range and high-end handsets that provides a great deal of flexibility. Using the ICamera interface, a wide variety of applications are possible. Ineractive games and messaging, content creation (custom wallpapers or ringer IDs), and countless vertical applications can benefit from camera-enabled software.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist