Symbian 摄像头编程预研
扫描二维码
随时随地手机看文章
摄像头编程预研
目前使用摄像头编程,网上用的最多的都是直接调用手机自带的照相/摄像程序来完成,不过使用这种方式,可控性就显得弱一些,为此近期对直接使用ECAM API进行了下简单预研。
照相流程
因为本次预研主要还是偏重照相功能。整个照相过程,假设使用文字说明可能会显得相对繁琐,为此结合ECAM API对照相功能进行了顺序流程图描绘,具体如下
该过程主要涉及到的观察器类就是MCameraObserver,该类和CCamera均在ecam.h头文件中被定义,以下是该观察器接口类的声明
class MCameraObserver
{
public:
//CCamera::Reserve异步函数的回调通知
virtual void ReserveComplete(TInt aError)=0;
//CCamera::PowerOn异步函数的回调通知
virtual void PowerOnComplete(TInt aError)=0;
//假如取景器模式为位图模式时预览位图的回调通知
virtual void ViewFinderFrameReady(CFbsBitmap& aFrame)=0;
//CCamera::CaptureImage异步函数的回调通知
virtual void ImageReady(CFbsBitmap* aBitmap,HBufC8* aData,TInt aError)=0;
//CCamera::StartVideoCapture异步函数的回调通知
virtual void FrameBufferReady(MFrameBuffer* aFrameBuffer,TInt aError)=0;
};
在这里需要说明下的,恐怕就是取景器了,因为假设不是数码达人或者第一次接触摄像头类编程,这个概念还是比较新的。其实所谓取景器,可以理解为预览拟拍摄景物的视窗,CCamera支持两种显示取景器的方法:一种是直接屏幕访问模式,即应用程序只要指明在屏幕上的哪个区域显示图像,摄像头对象就会把当前取到的图像直接绘制到这个区域上(可以说过程不用程序干预的);另外一种是位图模式,即摄像头对象提供一系列的位图,由应用程序把位图绘制到窗口上。
一般在设置之前需要先获取一下摄像头参数,看看其是否支持所要设置的模式。EViewFinderDirectSuported就是支持直接屏幕访问模式,EViewFinderBitmapsSupported就是位图模式。通常情况下,假如两种模式都支持的情况下,选用直接屏幕访问模式,因为这种模式比较快而且不用程序代码干预,否则就用位图模式,位图模式时,当捕捉到图像后会调用观察器的ViewFinderFrameReady()函数将图像传给观察器进行绘制。
关于CameraInfo
摄像头本身有属性信息,我们可以通过调用CCamera:: CameraInfo(TCameraInfo& aInfo)函数获取。对N81手机主摄像头进行缺省参数的提取,具体参数如下图所示
对各自参数的分析如下
iHardwareVersion
相机硬件的版本号,该值不用细究,是OEM关心的
iSoftwareVersion
相机软件的版本号(驱动程序版本号),该值也是OEM关心
iOrientation
相机的朝向,该值是OEM出厂时根据相机特性设定的,编程无法修改,不过可以给我们编程提供参考条件,其取值有如下几种类型
/** Possible directions in which the camera may point.
*/
enum TCameraOrientation
{
/** Outward pointing camera for taking pictures.
Camera is directed away from the user. */
EOrientationOutwards,
/** Inward pointing camera for conferencing.
Camera is directed towards the user. */
EOrientationInwards,
/** Mobile camera capable of multiple orientations.
Camera orientation may be changed by the user. */
EOrientationMobile,
/** Camera orientation is not known. */
EOrientationUnknown
};
根据取得的值的情况,N81的主摄像头朝向为EOrientationOutwards,当然通过对N81和E71主次摄像头信息数据的采集,可知类似N81、E71等双摄像头手机的主摄像头属性都是EOrientationOutwards的,而前面次摄像头属性都EOrientationInwards。从而猜测像N93i这样的手机其摄像头朝向属性应该为EOrientationMobile(因为是猜测,所有还期待有人帮忙验证一下)。根据这个属性,对于双摄像头手机,我们可以编程选中需要使用的摄像头。
iOptionsSupported
同样也是一些无法修改的属性,表明了此摄像头支持的功能,因为该值是个位域的值,通常使用过程中要用位与操作来判断其是否支持某一种属性,具体如下罗列的枚举值
enum TOptions
{
/** View finder display direct-to-screen flag */
EViewFinderDirectSupported = 0x0001,
/** View finder bitmap generation flag */
EViewFinderBitmapsSupported = 0x0002,
/** Still image capture flag */
EImageCaptureSupported = 0x0004,
/** Video capture flag */
EVideoCaptureSupported = 0x0008,
/** View finder display mirroring flag */
EViewFinderMirrorSupported = 0x0010,
/** Contrast setting flag */
EContrastSupported = 0x0020,
/** Brightness setting flag */
EBrightnessSupported = 0x0040,
/** View finder clipping flag */
EViewFinderClippingSupported = 0x0080,
/** Still image capture clipping flag */
EImageClippingSupported = 0x0100,
/** Video capture clipping flag */
EVideoClippingSupported = 0x0200
};
我的英文比较差,就不一一翻译了,毕竟有些EviewFinderMirrorSupported、EviewFinderClippingSupported、EimageClippingSupported、EvideoClippingSupported我也不知道是啥具体用的。我们只需要关心这个手机的摄像头支持何种模式的取景器,支不支持拍照(EImageCaptureSupported)、支不支持录像(EVideoCaptureSupported)、支不支持对比度设置(EcontrastSupported)和亮度设置(EBrightnessSupported)就可以了。
因为N81主摄像头的iOptionsSupporte值是14(即1110)所以该主摄像头只支持位图模式的取景器设置,同时支持图像和视频的拍摄,不支持对比度亮度等设置。
iFlashModesSupported
闪光灯支持模式,具体的模式可以参见如下枚举值
enum TFlash
{
/** No flash, always supported. */
EFlashNone = 0x0000,
/** Flash will automatically fire when required. */
EFlashAuto = 0x0001,
/** Flash will always fire. */
EFlashForced = 0x0002,
/** Reduced flash for general lighting */
EFlashFillIn = 0x0004,
/** Red-eye reduction mode. */
EFlashRedEyeReduce = 0x0008,
/** Flash at the moment when shutter opens.快门开时闪 */
EFlashSlowFrontSync = 0x0010,
/** Flash at the moment when shutter closes. 快门关事闪*/
EFlashSlowRearSync = 0x0020,
/** User configurable setting */
EFlashManual = 0x0040
};
这里就不做赘述了,N81的值11(即1011),支持自动、总是打开和红眼消除,当然总是关闭肯定是支持的。
知道了支持何种类型,我们就可以对摄像头的闪光灯类型通过CCamera::Flash和CCamera::SetFlashL两个函数获取和设置。
iExposureModesSupported
曝光支持模式,具体的模式详见如下枚举值
/** Specifies the type of exposure. - EExposureAuto is the default value. */
enum TExposure
{
/** Set exposure automatically. Default, always supported. */
EExposureAuto = 0x0000,
/** Night-time setting for long exposures. */
EExposureNight = 0x0001,
/** Backlight setting for bright backgrounds. */
EExposureBacklight = 0x0002,
/** Centered mode for ignoring surroundings. */
EExposureCenter = 0x0004,
/** Sport setting for very short exposures. */
EExposureSport = 0x0008,
/** Generalised setting for very long exposures. */
EExposureVeryLong = 0x0010,
/** Snow setting for daylight exposure. */
EExposureSnow = 0x0020,
/** Beach setting for daylight exposure with reflective glare. */
EExposureBeach = 0x0040,
/** Programmed exposure setting. */
EExposureProgram = 0x0080,
/** Aperture setting is given priority. */
EExposureAperturePriority = 0x0100,
/** Shutter speed setting is given priority. */
EExposureShutterPriority = 0x0200,
/** User selectable exposure value setting. */
EExposureManual = 0x0400,
/** Exposure night setting with colour removed to get rid of colour noise. */
EExposureSuperNight = 0x0800,
/** Exposure for infra-red sensor on the camera */
EExposureInfra = 0x1000
};
获取N81的相机曝光支持模式为7(即0111),所以只支持自动、夜晚、背光和中间四种模式。
我们可以通过CCamera::Exposure()和CCamera::SetExposureL两个函数对摄像头的曝光模式进行获取和设置。
iWhiteBalanceModesSupported
白平衡支持模式,白平衡具体的模式如下
/** Specifies how the white balance is set. */
enum TWhiteBalance
{
/** Set white balance automatically. Default, always supported. */
EWBAuto = 0x0000,
/** Normal daylight. */
EWBDaylight = 0x0001,
/** Overcast daylight. */
EWBCloudy = 0x0002,
/** Tungsten filament lighting. */
EWBTungsten = 0x0004,
/** Fluorescent tube lighting */
EWBFluorescent = 0x0008,
/** Flash lighting. */
EWBFlash = 0x0010,
/** High contrast daylight primarily snowy */
EWBSnow = 0x0020,
/** High contrast daylight primarily near the sea */
EWBBeach = 0x0040,
/** User configurable mode */
EWBManual = 0x0080
};
具体不做展开,可以通过调用CCamera::WhiteBalance和CCamera::SetWhiteBalanceL两个方法来进行对白平衡参数的获取和设置。
焦距(放大倍数)
在CameraInfo里面涉及焦距的参数真不少,iMinZoom、iMaxZoom、iMaxDigitalZoom、iMinZoomFactor、iMaxZoomFactor、iMaxDigitalZoomFactor
这几个参数值其实很困惑我的,特别是iMaxDigitalZoom,不知道是干嘛用的,这个值只能先不管了。根据CCamer提供了四个关于Zoom的如下四个函数
/**
Sets the digital zoom factor.
This must be in the range of 0 to TCameraInfo::iMaxDigitalZoom inclusive.
May leave with KErrNotSupported if the zoom factor is out of range.
@param aDigitalZoomFactor
The required digital zoom factor.
*/
virtual void SetDigitalZoomFactorL(TInt aDigitalZoomFactor = 0)=0;
/**
Gets the currently set digital zoom factor.
@return The currently set digital zoom factor.
*/
virtual TInt DigitalZoomFactor() const=0;
/**
Sets the zoom factor.
This must be in the range of TCameraInfo::iMinZoom to TCameraInfo::iMaxZoom
inclusive. May leave with KErrNotSupported if the specified zoom factor is
out of range.
@param aZoomFactor
Required zoom factor.
*/
virtual void SetZoomFactorL(TInt aZoomFactor = 0)=0;
/**
Gets the currently set zoom factor.
@return The currently set zoom factor.
*/
virtual TInt ZoomFactor() const=0;
可以猜测分别表示数码变焦和光学变焦。
另外,经过对N81和E71的参数比较,N81的iMaxDigitalZoomFactor是20.0,而E71是4.0,正好对应N81的20倍数码变焦,E71的4倍数码变焦。因为很多手机摄像头镜头都不支持光学变焦,所以在这里对我们有用的也就是只需要通过DigitalZoomFactor和 SetDigitalZoomFactorL两个函数在iMaxDigitalZoomFactor范围内设置数码变焦值就可以了。
图像格式和图像尺寸参数
iImageFormatsSupported和iNumImageSizesSupported两个参数分别用以表明摄像头拍照时所支持的图像格式和图像尺寸数量,具体支持的图像格式如下枚举值定义
enum TFormat
{
/** 8 bit greyscale values, 0=black, 255=white. */
EFormatMonochrome = 0x0001,
/** Packed RGB triplets, 4 bits per pixel with red in the least significant bits
and the 4 most significant bits unused. */
EFormat16bitRGB444 = 0x0002,
/** Packed RGB triplets, 5 bits per pixel for red and blue and 6 bits for green,
with red in the least significant bits. */
EFormat16BitRGB565 = 0x0004,
/** Packed RGB triplets, 8 bits per pixel with red in the least significant bits
and the 8 most significant bits unused. */
EFormat32BitRGB888 = 0x0008,
/** JFIF JPEG. */
EFormatJpeg = 0x0010,
/** EXIF JPEG */
EFormatExif = 0x0020,
/** CFbsBitmap object with display mode EColor4K. */
EFormatFbsBitmapColor4K = 0x0040,
/** CFbsBitmap object with display mode EColor64K. */
EFormatFbsBitmapColor64K = 0x0080,
/** CFbsBitmap object with display mode EColor16M. */
EFormatFbsBitmapColor16M = 0x0100,
/** Implementation dependent. */
EFormatUserDefined = 0x0200,
/** 4:2:0 format, 8 bits per sample, Y00Y01Y10Y11UV. */
EFormatYUV420Interleaved = 0x0400,
/** 4:2:0 format, 8 bits per sample, Y00Y01Y02Y03...U0...V0... */
EFormatYUV420Planar = 0x0800,
/** 4:2:2 format, 8 bits per sample, UY0VY1. */
EFormatYUV422 = 0x1000,
/** 4:2:2 format, 8 bits per sample, Y1VY0U. */
EFormatYUV422Reversed = 0x2000,
/** 4:4:4 format, 8 bits per sample, Y00U00V00 Y01U01V01... */
EFormatYUV444 = 0x4000,
/** 4:2:0 format, 8 bits per sample, Y00Y01Y02Y03...U0V0... */
EFormatYUV420SemiPlanar = 0x8000,
/** CFbsBitmap object with display mode EColor16MU. */
EFormatFbsBitmapColor16MU = 0x00010000
};
因为N81主摄像头的iImageFormatsSupported值为480(也即0x01E0),所以支持的格式为EFormatExif、EFormatFbsBitmapColor4K、 EFormatFbsBitmapColor64K和 EFormatFbsBitmapColor16M四种。
每一种格式又有对应的各种不同的尺寸,而具体支持的尺寸数则有iNumImageSizesSupported来限定,如上N81的iNumImageSizesSupported值为3,对每种格式使用CCamera::EnumerateCaptureSizes获取得尺寸均为320*240,640*480,1152*864,这让我百思不得其解,毕竟N81是200万像素的摄像头,怎么会最大尺寸是菜1152*864呢?系统自带的照相/摄像程序也是支持1600*1200的,而且关键QQ手中邮也是支持1600*1200格式的,后来经过在论坛上搜索,才知道原来CCamera::EnumerateCaptureSizes获取的尺寸跟UI程序时横屏(landscape)还是竖屏(portrait)有关的,像N81在横屏模式下iNumImageSizesSupported的值为4,其尺寸为320*240,640*480,1152*864和1600*1200,而默认竖屏下就是之前的那些数值。
另外用E71手机做过实验,发现对于E71,横屏还是竖屏,其实是一样的,没有任何变化,其iNumImageSizesSupported始终是5,而用CCamera::EnumerateCaptureSizes获取得尺寸也均为320*240,640*480,1152*864,1600*1200和2048*1536,所以我们在获取最大尺寸时可以毫无顾忌的使用横屏模式。
有了这个尺寸,我们就可以根据需要,调用CCamera::PrepareImageCaptureL(TFormat aImageFormat,TInt aSizeIndex)函数来设定我们拍照时需要的具体尺寸了。
在这里画蛇添足下,对于使用横屏和竖屏模式切换,可以在C*AppUi内通过调用CAknAppUiBase::SetOrientationL(TAppUiOrientation aOrientation)来简单实现,具体的参数值横屏时传EappUiOrientationLandscape,竖屏时传EappUiOrientationPortrait。不过类似我们程序的自定义界面,调用完这个函数后,会产生消息到C*AppUi::HandleResourceChangeL,只要我们在这个函数内部处理好界面排版就可以了。关于该项测试,周二已经和大红一起演示过了。
视频格式和视频尺寸参数
手机摄像头自然也提供了视频的录制功能,视频是由一帧一帧的图像构成,在CameraInfo信息里头与视频相关的参数就是iNumVideoFrameSizesSupported(单帧的尺寸)、iNumVideoFrameRatesSupported(帧速)和iVideoFrameFormatsSupported(支持的帧格式)。
因为N81的iVideoFrameFormatsSupported是2048(也即0x800),所以视频格式只支持EFormatYUV420Planar一种格式,而iNumVideoFrameSizesSupported为3,即支持3种模式,通过CCamera::EnumerateVideoFrameSizes(TSize& aSize,TInt aSizeIndex,TFormat aFormat)函数可以得到N81摄像时支持的三种视频尺寸为320*240,176*144,128*96,另外可以通过调用CCamera::EnumerateVideoFrameRates(TReal32& aRate, TInt aRateIndex, TFormat aFormat,TInt aSizeIndex,TExposure aExposure = EExposureAuto)函数得到N81支持的帧速为15帧每秒。
有了这些参数可以方便的通过调用CCamera::PrepareVideoCaptureL函数设置摄像时所要用到的视频尺寸和帧速;调用CCamera::StartVideoCapture函数开启摄像,开启摄像后摄像头会调用MCameraObserver::FrameBufferReady传递回来具体的每一帧数据,供界面显示和编写成视频文件;调用CCamera::StopVideoCapture函数来停止摄像,在任何时候可以通过CCamera::VideoCaptureActive来查询摄像头是否处于摄像过程中。
其它至于目前所使用的帧尺寸和帧速在其它地方是不可设置的,只能通过CCamera::GetFrameSize和CCamera::FrameRate两个函数来进行获取当前的参数值。
帧缓存参数
这个不知道怎么翻译,我就笼统称其为帧缓存参数好了,在摄像过程需要使用到帧缓存有iMaxFramesPerBufferSupported和iMaxBuffersSupported,前者表示每个buffer允许存放的最大帧数,后者为允许使用的buffer最大个数。由于N81的iMaxBuffersSupported为2,所以最多允许使用2个帧缓存区,又iMaxFramesPerBufferSupported是1,也即每个帧缓存最多只能放一帧数据。虽然目前并不完全知道其实际作用如何,但是这两个参数也是只有通过CCamera::PrepareVideoCaptureL这个函数来进行设置,通过函数CCamera::BuffersInUse()和CCamera::FramesPerBuffer()来获取当前的设置值。
由于视频摄像需要涉及到音视频编辑方面的内容,个人在视频录制方面还是空白,为此目前没有真正尝试,也就没有深入进去。
以下在贴几张预研中对E71 320万像素4倍数码变焦的CameraInfo信息截图和N81 200万像素20倍数码变焦横屏时的CameraInfo信息截图,以供大家参阅。
E71 CameraInfo信息截图
N81 横屏CameraInfo信息截图
因为E71不区分横竖屏,所以CameraInfo是一样的,有心的可以对比下之前的竖屏N81截图和横屏的差别。
此次小结先到这里,错误之处还望指正。