Old And New Symbian Camera APIA bit of an introduction first. While developing a simple camera application in my free time, I have at times been quite frustrated about the level of documentation and even secrecy around the Symbian camera API (also known as ECAM) and its implementation on Nokia Series 60 devices. I'm hoping that at least some things that will be written on this blog will make life easier for somebody else.
The CCamera class was originally created during times when phone cameras weren't quite as advanced as they are today, so its API is quite limited and some of the features missing from the API are nowadays considered quite basic. In Series 60 3.1 and earlier, the missing features could only officially be taken into use by 3rd party developers by using extensions provided by the device manufacturer. Autofocus was and is the only extension publicly available for Nokia S60 3.0 and 3.1 devices – for other missing things, trying to reverse engineer the non-public APIs is the only way.
In Series 60 3.2, CCamera's new observer interface MCameraObserver2, CCameraAdvancedSettings and CCameraImageProcessing APIs changed everything. Now all of the settings and most of the functionality used by the phone's camera application were also in reach of a normal 3rd party developer. This comes with a price though, an application using the new features via build time DLL linking will not even start on older devices.
One might think that it would make sense to simply develop using the older functionality supported everywhere to make applications more compatible. However, there are a lot of benefits in using the new APIs where available:
We get additional camera related events, the most notable one being event of another application having taken ownership of the camera hardware. When using the older API there's no way to know this has happened, viewfinder frames simply stop coming.There are more settings available.Settings work in a predictable way. When using advanced settings, every setting has an UID and after requersting a new value for a setting we get a callback with that UID when the new value has been taken into use. Old CCamera::SetXXX functions appear synchronous, but for example changing brightness values at key repeat speed will cause viewfinder to stop updating until the value updates stop (at least on Nokia 6220 Classic).It's also worth mentioning, that the old autofocus extension does not work in newer devices, so making an application that works well everywhere using just either of the API versions is simply not possible. In this blog, we will discuss what is needed to use the new functionality where available, while retaining binary compatibility for the older devices. Three different ways of using new functionality with backwards compatibility are presented below.
Supporting Both API Versions In One Application Binary1. Using CameraWrapperThe official Forum Nokia solution for the camera API binary break is a separate ”CameraWrapper” library, which handles instantiation of CCamera and implements some functionality, including autofocus. CameraWrapper also provides pointers to CCamera and CCameraAdvancedSettings, so it's possible to even use settings not directly supported by the wrapper. Sounds good so far.
However, when using CameraWrapper in your application, you need to embed another SIS file in the installation package. This SIS file installs ecamadvancedsettings.dll to the C drive, in case it doesn't already exist in device ROM. Even though the dll makes it possible running an application linked against advanced settings on older Nokia devices, the embedded SIS causes the application installation fail on some (all?) non-Nokia S60 devices. This means CameraWrapper is not the generic solution for the binary break problem.
2. Moving camera handling to a DLLAnother solution, which has been proposed in Forum Nokia discussion boards, is doing all camera handling in a separate DLL. There would be two different versions of the DLL, one using the old camera API observer, another one using the new observer and advanced settings. Version of the DLL would be decided during installation, based on whether ecamadvancedsettings.dll exists in the ROM or not.
This method may work in most cases on Nokia phones, but does it work always? It's possible that there are devices, which have a stub ecamadvancedsettings.dll in the ROM, even though the ecam.dll of the device does not export the New2L function. In this case, the application would fail to start, due to the DLL linking against unsupported function. I wouldn't take this risk, at least with a commercial application that's supposed to run everywhere.
3. Dynamically loading DLLs runtimeA third solution, which will be discussed in more detail in folloing blog posts, does not require installing additional SIS files, or isolating functionality in a separate DLL. Instead, we will divide classes and functions between base functionality (available on all devices) and additional functionality (not available everywhere). Base functionality we can use normally, linking against .lib file at build time and calling functions directly from the code, but to use the additional functionality, we will load DLLs dynamically and resolve functions by their ordinals.
This means some additional work for library loading, but after loading is done, the only difference is that the functions are called through a function pointer, and this-pointer of the object needs to be implicitly given as the first parameter for non-static functions – and even this difficulty can be taken out of sight by using a ”wrapper class”, which hides DLL loading and has similar API as the original class. A few additional lines of code is not too bad compared to the benefit of app running on all devices, whether or not all of the APIs possibly used exist.
With dynamic loading, it would also be possible to have the camera functionality in two different DLLs, both of which are installed and one of which is dynamically loaded during runtime. This would allow the DLLs to use camera functionality linking normally and without wrapping code, and so reduce need of dynamic loading. However, in this blog we'll look into doing everything in one EXE.