说起行车记录仪,大首先想到的就是汽车驾驶途中,被开启用于记录道路情况的拍摄仪器。其实手机上现在也有客户要求做这个功能,我不知道客户是本着大功能小设备的理念还是真的是手机市场真有这种巨大需求,自身就遇到这个特殊的需求。
平台:MT6261
要求:实现行车记录仪功能,并分为可设定的一分钟、五分钟、三十分钟存储一次的菜单选项。
现在跟大家一起分享下一步一步实现这个小东西的方法:
1、宏定义,做任何新的功能,肯定至少都应该有一个相关的宏控制这个功能的开关,便于后期维护。
2、菜单,既然客户需要有菜单可供选择,很明显他本身也应该是一个菜单形式的功能。那么我们就采用MT6261上创建菜单的方式来创建一个菜单:
void EntryCarcorderScreen(void) //行车记录仪上层菜单入口
{
U8 *guiBuffer =NULL; /* Buffer holding history data */
U16 ItemList[MAX_SUB_MENUS];
U16 ItemIcons[MAX_SUB_MENUS];
U16 nItems;
U16 menu_item_id;
U16 menu_text_id;
if(mmi_frm_scrn_enter(g_main_menu_group_id , SCR_CARCORDER_MENUID, NULL, EntryCarcorderScreen, MMI_FRM_FULL_SCRN) == MMI_FALSE)
{
return;
}
menu_item_id = ORGANIZER_CARCORDER_MENU;
menu_text_id =STR_MENU_CARCORDER;
guiBuffer = mmi_frm_scrn_get_active_gui_buf();
nItems =GetNumOfChild_Ext(menu_item_id);
GetSequenceStringIds_Ext(menu_item_id, ItemList);
GetSequenceImageIds_Ext(menu_item_id, ItemIcons);
SetParentHandler(menu_item_id);
RegisterHighlightHandler(ExecuteCurrHiliteHandler);
ShowCategory52Screen(
menu_text_id,
GetRootTitleIcon(menu_item_id),
STR_GLOBAL_OK,
IMG_GLOBAL_OK,
STR_GLOBAL_BACK,
IMG_GLOBAL_BACK,
nItems,
ItemList,
ItemIcons,
0,
0,
0,
guiBuffer);
SetCenterSoftkeyFunction(MmiCarcordercScreen, KEY_EVENT_UP);
SetLeftSoftkeyFunction(MmiCarcordercScreen, KEY_EVENT_UP);
SetRightSoftkeyFunction(mmi_frm_scrn_close_active_id, KEY_EVENT_UP);
}
对应这个菜单的高亮函数:
void HighlightCarcorder(void)
{
ChangeLeftSoftkey(STR_GLOBAL_OK, 0);
ChangeRightSoftkey(STR_GLOBAL_BACK,0);
SetLeftSoftkeyFunction(EntryCarcorderScreen,KEY_EVENT_UP);
SetCenterSoftkeyFunction(EntryCarcorderScreen, KEY_EVENT_UP);
SetRightSoftkeyFunction(mmi_frm_scrn_close_active_id, KEY_EVENT_UP);
}
这样就创建好了一个菜单,知道这个菜单放到那个位置,随客户的意思就行。
SetCenterSoftkeyFunction、SetLeftSoftkeyFunction、SetRightSoftkeyFunction分别代表中间键、左键、右键设定的相应事件。
3、功能,这个功能需要用到的就是照相机功能,所以很多部分都是可以参照照相机里的原理来做,只是需要注意做一些互斥的判断。慵懒的做法就是搞嫁接,就是直接在摄像头代码里面进行嫁接修改。这样的好处就是快,但是后期难以维护。好点的做法就是剥离出来,除非是相同的函数,其他的都单独自己写。这里关于进入的预览界面这些都直接省略,跟摄像头一样一样的。
需要注意的地方:就是预览后手动进入录像模式的时候,在时间到达设定点之前,需直接保存并重新自动开始,这里需要处理好逻辑关系,不然很容易死机,或者根本停止不了。
预览状态下需要清空一切按键上此前的消息信息,所以在 ClearKeyEvents();的同时,需要把自身在这个功能需要的按键均清理。
4、保存录制的视频,需要写入保存的格式以及路径,当然同时还需要有个是否具有存储卡的判定。一般保存的格式会根据当前时间来记录,那么请带上GetDateTime函数,来获取当前的时间,当然还有就是存储的格式。
if(g_vdorec_cntx.setting.video_format == VDOREC_SETTING_VIDEO_FORMAT_MJPEG)
{
kal_wsprintf((WCHAR*)file_buf_p, "%w%04d-%02d-%02d-%04d.avi",
(WCHAR*)g_vdorec_cntx.storage_filepath, year, month,day,g_vdorec_cntx.filename_seq_no);
}
else
{
kal_wsprintf((WCHAR*)file_buf_p, "%w%04d-%02d-%02d-%04d.3gp",
(WCHAR*)g_vdorec_cntx.storage_filepath, year, month,day,g_vdorec_cntx.filename_seq_no);
}
然后就是打开存粗位置的默认的位置,判断是否已经具有文件夹,如果没有就重新创建,如果有则就在该目录下,增加条目,并且写入NV确保不会丢失。
file_handle = FS_Open((WCHAR*) file_buf_p, FS_READ_ONLY);
if (file_handle >= 0)
{
/* file exist */
FS_Close(file_handle);
alpha_index++;
}
else
{
/* file not exit. return */
WriteValueSlim(NVRAM_VDOREC_FILENAME_SEQ_NO, &g_vdorec_cntx.filename_seq_no, DS_SHORT);
mmi_ucs2ncpy(g_vdorec_cntx.setting.save_name, (CHAR *)srv_fmgr_path_get_filename_ptr((WCHAR*)(file_buf_p)), SRV_FMGR_PATH_MAX_FILE_NAME_LEN);
mmi_vdorec_store_setting();
return;
}
基础框架完成后,就需要进一步对时间的控制处理:
static const U16 g_vdorec_il_time_select_str[] =
{
STR_ID_VDOREC_TIME_1MIN,
STR_ID_VDOREC_TIME_3MIN,
STR_ID_VDOREC_TIME_5MIN,
STR_ID_VDOREC_TIME_10MIN,
STR_ID_VDOREC_TIME_CLOSED,
};
static const cui_inline_iteStartTimer_select_struct g_vdorec_il_time_select =
{
sizeof(g_vdorec_il_time_select_str)/sizeof(U16), 0, (U16*)g_vdorec_il_time_select_str
};
static const cui_inline_set_item_struct g_mmi_vdorec_setting_time_inline_item[] =
{
{MMI_VDOREC_SETTING_CAMCORDER_IL_TIME_CAPTION, CUI_INLINE_ITEM_TYPE_CAPTION|CUI_INLINE_ITEM_LEFT_JUSTIFY, 0,(void*)&g_vdorec_il_time_cap},
{MMI_VDOREC_SETTING_CAMCORDER_IL_TIME_SELECT,CUI_INLINE_ITEM_TYPE_SELECT|CUI_INLINE_ITEM_CENTER_JUSTIFY, 0,(void*)&g_vdorec_il_time_select},
};
5、将上述菜单的时间控制添加到执行函数中,采用StartTimer是个很好的办法,时间一到,就做出来相应的处理。当下也有几种情况的判断,既是在预览状态、录制状态、还是暂停状态。
如果是在预览状态,再次触发中间键,应该进入的是录制状态,如果是在录制状态,应该是停止且保存,如果是在暂停状态,则应该是录制状态。
因此:case VDOREC_STATE_PREVIEW: --------------> mmi_carcorder_enter_state(VDOREC_STATE_RECORD);
case VDOREC_STATE_PAUSE:--------------------->mmi_Carcorder_rsk_release_hdlr()
case VDOREC_STATE_RECORD:---------------------->mdi_video_rec_record_stop();
同时兼顾timer的时间节点的控制配合,就基本能完成此种功能。
(写的不好,请勿见外,一方面不太熟悉这个博客的使用方式,另一方面自己也没太多写博客的经验)