从缺省堆中分配内存单元实现日程表监测
概述:
当日程表被其他程序添加、删除或修改后,某第三方程序可能需要知道这些变化。他们可能也想知道具体哪项日程当前被执行了。
下面的解决方案描述了如何通过在S60第二版中写下一个日程表监测DLL来完成上述需求,具体可查看关于Calendar Interim API的文档。
解决方案:
1)首先生成一个独立的日程表监测DLL,如通过CAgendaObs::NewL()方法从CAgnObserver派生的一个CAgendaObs对象。
下面的小实例演示了这样的情况:
CAgnObserver* CAgendaObs::CloneL() { if(!iClone) // initial value (TBool) EFalse { // Log: Creating clone CAgendaObs* result = NewL(); result->iClone = ETrue; return result; } } void CAgendaObs::StartObserving() { if(iClone) { //Log: Start observing } } void CAgendaObs::StopObserving() { if(iClone) { // Log: Stop observing } } void CAgendaObs::Send(TInt aFunction, CAgnEntry *aEntry) { if(iClone) { switch(aFunction) { case ENotifyAddEntry: // Entry added break; case ENotifyDeleteEntry: // Entry deleted break; case ENotifyUpdateEntry: // Entry updated break; case ENotifyAddTodoList: // ToDo entry added break; case ENotifyDeleteTodoList: // ToDo entry deleted break; case ENotifyUpdateTodoList: // ToDo entry updated break; default: // Unexpected command break; } } } void CAgendaObs::Send(TInt aFunction, CAgnTodoList *aTodoList) { if(iClone) { switch(aFunction) { case ENotifyAddEntry: // Entry added break; case ENotifyDeleteEntry: // Entry deleted break; case ENotifyUpdateEntry: // Entry updated break; case ENotifyAddTodoList: // ToDo entry added break; case ENotifyDeleteTodoList: // ToDo entry deleted break; case ENotifyUpdateTodoList: // ToDo entry updated break; default: // Unexpected command break; } } } void CAgendaObs::ExternalizeL(RWriteStream &aStream) const { //write your code here if(iClone) { // Log: ExternalizeL called } //closing CAgnObserver::WriteEndMarkerL(aStream); } void CAgendaObs::InternalizeL(RReadStream &aStream) { //write your code here if(iClone) { // Log: InternalizeL called } //closing CAgnObserver::ReadEndMarkerL(aStream); } // The NewL of the DLL, to be exported EXPORT_C CAgendaObs* CAgendaObs::NewL() { CAgendaObs* self = new (ELeave) CAgendaObs(); CleanupStack::PushL(self); self->ConstructL(); CleanupStack::Pop(self); return self; }
2) In another application register the observer using the following code:
#ifdef __WINS__ _LIT(KObserverFile,"agendaobs.dll"); #else _LIT(KObserverFile,"c:\\system\\libs\\agendaobs.dll"); #endif _LIT(KAgendaFile,"c:\\system\\data\\calendar"); // In ConstructL: RAgendaServ *iServer = RAgendaServ::NewL(); iServer->Connect(); CAgendaObs* iObserver = CAgendaObs::NewL(); CAgnEntryModel *iModel = CAgnEntryModel::NewL(this); iModel->SetServer(iServer); iModel->OpenL(KAgendaFile); // Call this method to register the observer DLL void CSomeAppUi::Register() { if(iModel) { iModel->RegisterObserverL(TFileName(KObserverFile), iObserver); } } // Before exiting, unregister the DLL void CAgendaAppAppUi::Unregister() { if(iModel) { iModel->UnregisterObserverL(TFileName(KObserverFile)); } }
注意,在MMP文件中,监测DLL要使用0x10000135作为UID2才行。
使用CHWRMVibra类来启动/停止/查询设备震动的状态
详细描述:
CHWRMVibra类是在S60第三版才开始发布的,它提供了控制设备震动模块的能力。
我们需要的链接库为:WRMVibraClient.lib
链接头文件为:hwrmvibra.h
下列代码演示了如何获得震动状态:
iVibrate = CHWRMVibra::NewL(); CHWRMVibra::TVibraStatus iStatus = iVibrate->VibraStatus();
返回的值有:
EVibraStatusUnknown EVibraStatusNotAllowed EVibraStatusStopped EVibraStatusOn
下列代码演示了如何获取情景模式下的震动部分设置“
CHWRMVibra::TVibraModeState iState = iVibrate->VibraSettings();
返回值为:
EVibraModeUnknown EVibraModeON EVibraModeOFF
下列代码演示了如何启动震动,这时震动的设置必须是EVibraModeON。
iVibrate->StartVibraL(0,50);
第一个参数表示是持续的时间(微秒),如果是0值表明震动将持续到StopVibraL()被调用为止。
第二个参数表明强度值,它的范围是-100至100之间。
下面的代码演示了如何停止震动
iVibrate->StopVibraL();
如何获取设备当前情景模式
详细描述:
我们可以通过使用Profiles Engine Wrapper API来获取当前情景模式。
首先需要包含这两个头文件:
mproengengine.h proengfactory.h
然后是链接库:
ProfileEngine.lib
再看下列演示代码:
MProEngEngine* engine = ProEngFactory::NewEngineLC(); TInt activeId( engine->ActiveProfileId() );
通过调用ActiveProfileId()我们可以获取如下返回值:
0 - General 1 - Silent 2 - Meeting 3 - Outdoor 4 - Pager 5 – Offline
如何在Avkon tabs中使用SVG图标
概述:
我们可以在Avkon tab group的每个tab中显示我们自己的SVG图标。这一情况下对SVG文件有一些限制,现在描述如下。
解决方案:
CAknTabGroup::AddTabL()可用来生成一个带自定义SVG图标的tab,只有图标的mask层(如alpha或transparency)呗使用来生成该图表,其他数据被忽略了。
举例来说,现在有一个白色SVG带有如下图案:白色背景上一个黑色椭圆。
<ellipse fill="#FFFFFF" stroke="#000000" stroke-width="5" cx="25" cy="25" rx="20" ry="20"/>
为了让椭圆显示在tab上,填充参数必须修改如下:
<ellipse fill="none" stroke="#000000" stroke-width="5" cx="25" cy="25" rx="20" ry="20"/>.
只有这样修改后,图片的mask才会出现黑色背景和白色椭圆,当该SVG被使用在tab icon上时,就会现实出黑色的椭圆,而其他图片的其他地方都是做透明处理了。
注意,当mask被用来生成icon时,无法在TAB上绘制有色的SVG。
如何同时建立GMS和GPRS连接
概述:
S60第三方程序可能需要在保持GSM通话时提供访问GPRS的能力。
解决方案:
S60设备按基于GSM通话时保持GPRS的能力,分为三个类型。
Class A
可以同时建立GPRS服务和GSM服务(语音,SMS),并同时使用这两者。
这样的设备现在包括S60第三版机型(Nokia N73/N80/N91/N93, Nokia E60/E61/E70等)
Class B
可以同时建立GPRS服务和GSM服务(语音,SMS),但只能一次使用一种服务。当进行GSM服务时(通话,短信),则GPRS服务将被暂停,直到GSM服务结束才自动继续下去。
大部分S60第二版机型都在此类中(Nokia N70, Nokia N90, Nokia 6680等)
Class C
只能建立GPRS服务或GMS服务(通话,短信)其中一种,如果要切换服务必须手动控制。
注意:
目前没有一个直接可操控的API来询问当前设置支持GPRS类的能力,大部分S60第三版机器3G(WCDMA)电话都归属于A类,有一个API可用来检查当前电话是否支持WCDMA,代码为:
TBool isSupported = CFeatureDiscovery::IsFeatureSupportedL(KFeatureIdProtocolWcdma); if (isSupported) { // activate the service }
绘制动画图片
概述:
应用程序可以通过ICL(Image Converter Library)使用CImageDecoder类在自定义的UI控件中绘制动画图片,比如GIF动画图片。
解决方案:
ICL允许使用CImageDecoder::Convert()将动画图片(多帧)转换为CFbsBitmap位图机型显示,我们可以通过使用CImageDecoder::FrameCount()获得图片文件的帧数,通过CImageDecoder::FrameInfo(TInt aFrameNumber = 0)返回每帧的信息、
对每帧来说都要调用CImageDecoder::Convert(),这个转换是异步的。每次完成后,完成后将返回一个CFbsBitmap实例。
帧之间的时间间隔可以通过TFrameInfo类获得,通过这些信息,我们可以依次播放CFbsBitmap以产生动画效果。
注意:在S60 2nd中可以使用CPAlbImageViewerBasic来播放动画,但在第三版中已经去除了。
当程序通过HTTP进行下载时无法接通来电
详细描述:
当我们使用HTTP Client API通过GPRS下载内容时会造成来电无法接通。当我们在下载一个大文件室需要考虑到这样的问题,如果有可能的话应该将大文件分割为许多小模块进行下载,因为HTTP的
传输能力很低(HTTP头很大),这时开发者需要平衡传输效率和来电接通的问题。
打开WAP Push信息
创建日期:
在访问Smart Message(BIO)数据时有几种不同的方式,大多数信息类型中,信息内容是存放在附件中,我们可以通过新的附件管理示例(CMsvStore)来访问。
某些情况下,内容是存放在CMsvStore流中的,可以通过public stream UID来读取
(定义在pushentry.h)
/** UID for the WAP Push MTM. */ const TUid KUidMtmWapPush = {0x10009158}; /** UID for WAP Push SI messages. */ const TUid KUidWapPushMsgSI = {0x10009159}; /** UID for WAP Push SL messages. */ const TUid KUidWapPushMsgSL = {0x1000915A}; /** UID for WAP Push multipart messages. */ const TUid KUidWapPushMsgMultiPart = {0x1000915B}; /** UID for WAP Push unknown-type messages. */ const TUid KUidWapPushMsgUnknown = {0x1000915C};
从缺省堆中分配内存单元
描述:
一般来说内存单元是从当前线程堆中分配的,但有时无法这样做,特别当要分配的内存单元很大时。
我们可以生成一个新的堆,从它那里获取我们需要的内存单元,示例如下:
//Try to create a heap in a local chunk. //The minimum length of the heap is 10M and the maximum length is 20M RHeap *pChunkHeap = UserHeap::ChunkHeap(NULL, 10000*1024, 20000*1024); if (RHeap) { void *mallocBuffer = NULL; TInt size = 8000*1024; //Try to allocate a 8M memory cell mallocBuffer = pChunkHeap->Alloc(size); if (mallocBuffer ) { //... Use this memory cell ... } }
当N93翻转屏幕时动态更新的CBA在多视图程序中无法显示的问题
描述:
如何产生:
肖像模式->View1->风景模式(设备翻转)->切换到View->肖像模式(设备翻转)->View2中的CBA动态更新
但无法显示
TKeyResponse Ctest1Container2::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) { if(aKeyEvent.iCode == EKeyOK) { if(iCba == R_AVKON_SOFTKEYS_OPTIONS_BACK) { CEikButtonGroupContainer* cba = CEikButtonGroupContainer::Current(); cba->SetCommandSetL(R_AVKON_SOFTKEYS_CANCEL); cba->MakeVisible(EFalse); //Add this line to the source code cba->DrawNow(); cba->MakeVisible(ETrue); //Add this line to the source code //CEikonEnv::Static()->InfoWinL(_L("info"), _L("hi")); iCba = R_AVKON_SOFTKEYS_CANCEL; } else { CEikButtonGroupContainer* cba = CEikButtonGroupContainer::Current(); cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_BACK); cba->MakeVisible(EFalse); //Add this line to the source code cba->DrawNow(); cba->MakeVisible(ETrue); //Add this line to the source code //CEikonEnv::Static()->InfoWinL(_L("info"), _L("hi")); iCba = R_AVKON_SOFTKEYS_OPTIONS_BACK; } return EKeyWasConsumed; } return EKeyWasNotConsumed; }
描述:
一般来说如果将N93的摄像头进行翻转操作,则当前程序会切换到后台,而摄像机程序会出现在前台。
但有时为了防止这样的情况发生,我们可以通过如下方式来操作:
MCoeForegroundObserver::HandleLosingForeground() { const TUid KNativeCameraAppUID = { 0x101ffa86}; //The UID of the native camera application TUid id( KNativeCameraAppUID); TApaTaskList taskList( CEikonEnv::Static()->WsSession() ); TApaTask task = taskList.FindApp( id ); if ( task.Exists() ) //If the native camera application is running { RWsSession WsSession = CCoeEnv::Static()->WsSession(); TWsEvent event; TInt ForegroundWinGroup = WsSession.GetFocusWindowGroup(); if (task.WgId()==ForegroundWinGroup) //If the native camera application is on the foreground { const TUid KCurrentAppUID = { 0x20004A79 }; //The UID of current runing application TUid thisid( KCurrentAppUID ); TApaTaskList taskList1( CEikonEnv::Static()->WsSession() ); TApaTask task1 = taskList1.FindApp( thisid ); if ( task1.Exists() ) { task1.BringToForeground(); } } } }
浏览器控件API无法显示Flash内容
描述:
第三方程序使用Browder Control API,可以显示HTML内容,但如果页面包含有Flash动画,则无法被正确显示,如何配置才能显示出Flash内容呢?
解答:
当前Adobe的Flash播放插件只为Nokia应用程序设计(通过VendorID检测),对其他程序来说,调用插件将返回NULL。无论你使用Netscapge Plug-in API或Browser Control API时,都会出现这样的情况。
使用document handler拷贝或移动未被识别文件时发生的问题
创建日期:
当你使用CDocumentHandler::CopyL()或MoveL()或SilentMoveL()时,被操作文件MIME类型不在下表中的话,那目标文件夹将会是一个临时目录
• image/vnd.nokia.ota-bitmap • image/x-ota-bitmap • application/vnd.nokia.ringing-tone • audio/* • image/* • video/* • application/vnd.rn-realmedia • application/sdp
当CDocumentHandler实例被删除后,那拷贝或移动的文件也将在临时目录中被删除,这可能会导致无意删除行为,特别是在移动文件时。
解决方案:
当使用CDocumentHandler进行拷贝或移动文件操作时,非上述列表类型文件是不推荐使用该方法的。
PathInfo类有个方法叫OthersPath()可用来返回一般内容的路径。
S60 3rd Edition和S60 3rd Edition, FP1中不同的浏览器UID
在启动S60第三版中启动web浏览器打开特定URL的方法无法在S60第三版, FP1设备上完成(如Nokia N95)
这是因为S60第三版设备(如N73)有两个浏览器:“服务”和“网络”
“服务”的UID为0x10008D39而“网络”的UID为 0x1020724D
在第三版FP1设备(如N95)上,只有一个浏览器,UID为0x10008D39
为了能在FP1设备上工作,你必须将0x1020724D转换为0x10008D39
const TUid KOSSBrowserUidValue = {0x10008D39};
详细描述:
==概述==
当你绘制一个控件(如list box, grid, editor等)时会需要使用scroll bar,但这时其背景可能会保持白色。这种情况一般发生在Container没有传递一个正确的对象(context-specific skin parameters)到它的子控件中造成的。完成container类的CCoeControl::MopSupplyObject()方法会帮助子控件拥有正确的皮肤绘制,并且保证控件和他们父类之间的对象链表设置正确。
更多信息可以参考SDK文档中的MObjectProvider和CCoeControl::SetMopParent()部分
==解决方案==
要正确绘制scroll bar的背景,需要如下:
'''首先'''在从CCoeControl派生的view class的构造函数中加入如下代码:
CAknsBasicBackgroundControlContext* iSkinContext = CAknsBasicBackgroundControlContext::NewL( KAknsIIDQsnBgAreaMainAppsGrid, iAvkonAppUi->ApplicationRect(), EFalse );
'''然后'''实现MopSupplyObject()如下:
TTypeUid::Ptr CMyCustomGridAppView::MopSupplyObject( TTypeUid aId ) { if( aId.iUid == MAknsControlContext::ETypeId && iSkinContext != NULL ) { return MAknsControlContext::SupplyMopObject( aId, iSkinContext ); } return CCoeControl::MopSupplyObject( aId ); }
如何定制一个list box
详细描述:
==概述==
开发者可能需要根据自己的需求定制一个list box,这个提供一个示例,从一个double style list box中去除dotted column line.
==解决方案==
我们需要重载list box的item drawer方法,下面这个示例定义了一个double number style list box.
class CDSListItemDrawer : public CFormattedCellListBoxItemDrawer { public: CDSListItemDrawer( MTextListBoxModel* aTextListBoxModel, const CFont* aFont, CFormattedCellListBoxData* aFormattedCellData ); void DrawItemText( TInt aItemIndex, const TRect &aActualItemRect, TBool aItemIsCurrent, TBool aViewIsEmphasized, TBool aItemIsSelected) const; void SetColour( const TRgb& aTextForeground, const TRgb& aTextBackground, const TRgb& aHighlightForeground, const TRgb& aHighlightBackground ); private: // data TRgb iTextForegroundColour; TRgb iTextBackgroundColour; TRgb iHighlightForegroundColour; TRgb iHighlightBackgroundColour; const CFont* iPersistentFont; CFormattedCellListBoxData* iCellData; TInt iScrollOffset; }; /*******************************************************************/ // A list box class whose only responsibility is to look after a CDSListItemDrawer. class CDSListBox : public CAknDoubleNumberStyleListBox { public: CDSListBox( const CFont* aFont, CFormattedCellListBoxData* aFormattedCellListBoxData ); void SetScrollFrame(); void FindCellSize(); protected: virtual void CreateItemDrawerL(); virtual CListBoxView* MakeViewClassInstanceL(); private: const CFont* iFont; CFormattedCellListBoxData* iFormattedCellListBoxData; }; /****************************************************************/ The .cpp source file should have the following implementation. CDSListItemDrawer::CDSListItemDrawer( MTextListBoxModel* aTextListBoxModel, const CFont* aFont, CFormattedCellListBoxData* aFormatedCellData ) : CFormattedCellListBoxItemDrawer( aTextListBoxModel, aFont, aFormatedCellData ), iPersistentFont( aFont ) { } void CDSListItemDrawer::DrawItemText( TInt aItemIndex, const TRect &aItemTextRect, TBool aItemIsCurrent, TBool aViewIsEmphasized, TBool aItemIsSelected) const { Gc()->SetBrushStyle( CGraphicsContext::ESolidBrush ); Gc()->SetBrushColor( KRgbWhite ); Gc()->Clear( aItemTextRect ); TPtrC itemText = iModel->ItemText( aItemIndex ); TInt textLength = itemText.Length(); TInt tabPosition1 = itemText.Locate( '\t' ); TInt tabPosition2 = itemText.Mid(tabPosition1+1).Locate( '\t' ); const CFont* font = Font( aItemIndex ); Gc()->SetPenStyle( CGraphicsContext::ESolidPen ); Gc()->SetBrushStyle( CGraphicsContext::ESolidBrush ); TRgb textColour; TRgb bgColour; if ( aItemIsCurrent ) { textColour = iHighlightForegroundColour; bgColour = iHighlightBackgroundColour; } else { textColour = iTextForegroundColour; bgColour = iTextBackgroundColour; } Gc()->UseFont( iPersistentFont ); // Set the item's background. Gc()->SetBrushStyle( CGraphicsContext::ESolidBrush ); Gc()->SetBrushColor( bgColour ); Gc()->SetPenColor( textColour ); TRect textRect( TPoint( aItemTextRect.iTl.iX, (aItemTextRect.iTl.iY-10) ), aItemTextRect.iBr ); textRect.iBr.iY -= aItemTextRect.Height() / 2; if ( !font ) { font = CEikonEnv::Static()->LegendFont(); } Gc()->UseFont(font); TInt baseline = ( textRect.iBr.iY - textRect.iTl.iY - font->HeightInPixels() ) / 2 + font->AscentInPixels(); Gc()->DrawText( itemText.Mid( 0,tabPosition1 ), textRect, baseline-20, CGraphicsContext::ELeft); Gc()->DrawText( itemText.Mid( tabPosition1+1, tabPosition2 - tabPosition1 ), textRect, baseline, CGraphicsContext::ELeft, 0); font = CCoeEnv::Static()->NormalFont(); Gc()->UseFont(font); textRect.Move( 0, aItemTextRect.Height() / 2 ); baseline = ( textRect.iBr.iY - textRect.iTl.iY - font->HeightInPixels() ) / 2 + font->AscentInPixels(); Gc()->DrawText( itemText.Mid( tabPosition2,textLength-tabPosition2 ), textRect, baseline, CGraphicsContext::ELeft, 1); } void CDSListItemDrawer::SetColour( const TRgb& aTextForeground, const TRgb& aTextBackground, const TRgb& aHighlightForeground, const TRgb& aHighlightBackground) { iTextForegroundColour = aTextForeground; iTextBackgroundColour = aTextBackground; iHighlightForegroundColour = aHighlightForeground; iHighlightBackgroundColour = aHighlightBackground; iBackColor = iTextBackgroundColour; } CDSListBox::CDSListBox( const CFont* aFont, CFormattedCellListBoxData* aFormattedCellListBoxData ) { iFont = aFont; iFormattedCellListBoxData=aFormattedCellListBoxData; } void CDSListBox::CreateItemDrawerL() { iItemDrawer = new (ELeave) CDSListItemDrawer( Model(), iFont, iFormattedCellListBoxData ); } CListBoxView* CDSListBox::MakeViewClassInstanceL() { return new (ELeave) CListBoxView(); } void CDSListBox::SetScrollFrame() { } void CDSListBox::FindCellSize() { } /******************************************************************/ The calling function from a CCoeControl should contain: SetExtentToWholeScreen(); // Drawing it to the whole screen iTextForegroundColour = KRgbGreen; iTextBackgroundColour = KRgbRed; iHighlightForegroundColour = KRgbWhite; iHighlightBackgroundColour = KRgbBlue; iListItems = new (ELeave) CDesC16ArrayFlat( 2 ); const CFont *font; _LIT( KTextFont, "LatinBold13" ); CFont* myFont; CFormattedCellListBoxData* myFormattedCellListBoxData; CGraphicsDevice* screenDevice = CEikonEnv::Static()->ScreenDevice(); TFontSpec textFontSpec( KTextFont, 200 ); screenDevice->GetNearestFontInTwips( myFont,textFontSpec ); myFormattedCellListBoxData = CFormattedCellListBoxData::NewL(); iListBox1 = new (ELeave) CDSListBox( myFont, myFormattedCellListBoxData ); iListBox1->ConstructL( this, 0 ); iListBox1->SetRect( TRect( 0, 0, 3000, 3000 ) ); CDSListItemDrawer* drawer = (CDSListItemDrawer*) iListBox1->View()->ItemDrawer(); drawer->SetColour( iTextForegroundColour, iTextBackgroundColour, iHighlightForegroundColour, iHighlightBackgroundColour ); CColumnListBoxData* columnData=CColumnListBoxData::NewL(); columnData->SetControl( iListBox1 ); TInt columnSize; columnData->ColumnWidthPixel( columnSize ); _LIT( KListItemFormat, "%d\t%S\t%S" ); _LIT( KName1, "Name11" ); _LIT( KContactNo,"123" ); _LIT( KName2,"Name22" ); _LIT( KContactNo2,"789" ); TBuf<40> item; MDesCArray* itemList = iListBox1->Model()->ItemTextArray(); CDesCArray* itemArray = (CDesCArray*) itemList; TBuf<30> NameBuf; TBuf<30> ConBuf; // add first item in the array NameBuf.Copy( KName1 ); ConBuf.Copy( KContactNo ); TInt id = 1; item.Format( KListItemFormat, id, &NameBuf, &ConBuf ); itemArray->AppendL( item ); // add second item in the array NameBuf.Zero(); ConBuf.Zero(); NameBuf.Copy( KName2 ); ConBuf.Copy( KContactNo2 ); item.Format( KListItemFormat, id, &NameBuf, &ConBuf ); itemArray->AppendL( item ); NameBuf.Zero(); ConBuf.Zero(); iListBox1->SetRect( TRect( TPoint( 0,0 ), TPoint( 20000, 20000 )) ); iListBox1->ActivateL(); iListBox1->HandleItemAdditionL(); DrawNow();
注意:这里仅仅是示例,没有包括完整代码。为了正确绘制,相应元素如text, icons, highlight等都需要计算正确,这些需要花一番工夫。
通过CVideoRecorderUtility录制更大尺寸视频
详细描述:
如果想要录制尺寸超过QCIF(176x144)的视频,那就要使用MPEG-4格式("video/mp4v-es")。
_LIT8(KMimeTypeMPEG4VSPL3, "video/mp4v-es; profile-level-id=3"); // MPEG-4 Visual Simple Profile Level 3 _LIT8(KMimeTypeMPEG4VSPL4, "video/mp4v-es; profile-level-id=4"); // MPEG-4 Visual Simple Profile Level 4
我们可以在支持MPEG-4 VSP Level4(Visual Simple Profile Level 4)的设备上捕捉到30fps的VGA(640x480)视频,大部分S60第三版手机至少都支持VSP Level 3,即CIF(352x288)30fps的视频。
如:
iRecorder->OpenFileL( iFilename, iCameraHandle, iControllerUid, iFormatUid, KMimeTypeMPEG4VSPL4, KMMFFourCCCodeAAC );
在MvruoOpenComplete回调函数中,capture size, frame rate以及bit rate应该在CVideoRecorderUtility::Prepare()前设置好,如下示例:
void CMyVideoRecorder::MvruoOpenComplete( TInt aError ) { if( aError == KErrNone ) { // instead of using TRAP_IGNORE, proper error checking should be done TRAP_IGNORE( iRecorder->SetVideoFrameSizeL( iResolution )); TRAP_IGNORE( iRecorder->SetVideoFrameRateL( iFps )); TRAP_IGNORE( iRecorder->SetVideoBitRateL( KMMFVariableVideoBitRate )); ... iRecorder->Prepare();
我们可以通过CCamera获得当前设备所支持最大的视频capture size和frame rate
TInt sizeIndex = 0, rateIndex = 0; iCamera->EnumerateVideoFrameSizes( iResolution, sizeIndex, CCamera::EFormatYUV420Planar ); iCamera->EnumerateVideoFrameRates( iFps, rateIndex, CCamera::EFormatYUV420Planar, sizeIndex );
详细描述:
下列代码演示了如何使用一个可以显示多行信息的询问对话框:
_LIT(KTxtApplicationName, "Application Title"); HBufC* sMessage = StringLoader::LoadLC( R_MESSAGE ); HBufC* sTitle = HBufC::NewLC( KTxtApplicationName().Length() ); sTitle->Des().Append( KTxtApplicationName ); CAknMessageQueryDialog* dialog = new ( ELeave ) CAknMessageQueryDialog(); CleanupStack::PushL( dialog ); dialog->PrepareLC( R_AVKON_MESSAGE_QUERY_DIALOG ); dialog->QueryHeading()->SetTextL( *sTitle ); dialog->SetMessageTextL( *sMessage ); dialog->RunLD(); CleanupStack::Pop(); // dialog CleanupStack::PopAndDestroy(2); // sTitle, sMessage
要显示在对话框中的信息是从资源文件加载的,我们在.rss文件中需要有如下定义:
#define qtn_message “First Line \nSecond Line” RESOURCE TBUF r_message { buf = qtn_message; }
如何获取当前函数的名称
详细描述:
有时候debug时为了记录相关信息,我们需要知道当前函数的名称,这时可以通过__func__来获取。
void LogFunctionName(const char* name) { RDebug::Printf("current function: %s\n", name); }
现在,我们可以通过如下语句打印出函数名:
LogFunctionName(__func__);