diff --git a/mkapp/app/setting.ini b/mkapp/app/setting.ini index 0a6c1157..a1bcb4c4 100644 --- a/mkapp/app/setting.ini +++ b/mkapp/app/setting.ini @@ -31,6 +31,7 @@ format_ts=true osd=true audio=true audio_source=0 +naming=0 [image] oled=8 diff --git a/src/core/dvr.c b/src/core/dvr.c index 2f6fd672..fef9a72f 100644 --- a/src/core/dvr.c +++ b/src/core/dvr.c @@ -134,6 +134,7 @@ static void dvr_update_record_conf() { ini_putl("record", "audio", g_setting.record.audio, REC_CONF); dvr_select_audio_source(g_setting.record.audio_source); + ini_putl("record", "naming", g_setting.record.naming, REC_CONF); } void dvr_cmd(osd_dvr_cmd_t cmd) { diff --git a/src/core/settings.c b/src/core/settings.c index ac21818c..88ea3811 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -47,6 +47,7 @@ const setting_t g_setting_defaults = { .osd = true, .audio = true, .audio_source = SETTING_RECORD_AUDIO_SOURCE_MIC, + .naming = SETTING_NAMING_CONTIGUOUS, }, .image = { .oled = 8, @@ -384,6 +385,7 @@ void settings_load(void) { g_setting.record.osd = settings_get_bool("record", "osd", g_setting_defaults.record.osd); g_setting.record.audio = settings_get_bool("record", "audio", g_setting_defaults.record.audio); g_setting.record.audio_source = ini_getl("record", "audio_source", g_setting_defaults.record.audio_source, SETTING_INI); + g_setting.record.naming = ini_getl("record", "naming", g_setting_defaults.record.naming, SETTING_INI); // image g_setting.image.oled = ini_getl("image", "oled", g_setting_defaults.image.oled, SETTING_INI); diff --git a/src/core/settings.h b/src/core/settings.h index 40cf21a6..388e7951 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -71,12 +71,18 @@ typedef enum { SETTING_RECORD_AUDIO_SOURCE_AV_IN = 2 } setting_record_audio_source_t; +typedef enum { + SETTING_NAMING_CONTIGUOUS, + SETTING_NAMING_DATE +} setting_record_naming_t; + typedef struct { bool mode_manual; bool format_ts; bool osd; bool audio; setting_record_audio_source_t audio_source; + setting_record_naming_t naming; } setting_record_t; typedef struct { diff --git a/src/driver/rtc.c b/src/driver/rtc.c index 7bde5592..6dbc4586 100644 --- a/src/driver/rtc.c +++ b/src/driver/rtc.c @@ -18,8 +18,10 @@ #include #include +#include #include "core/settings.h" +#include "ui/page_common.h" /** * Constants @@ -173,19 +175,24 @@ void rtc_tv2rd(const struct timeval *tv, struct rtc_date *rd) { } /** - * Initialize both the hardware ans system clocks. + * Initialize both the hardware and system clocks. */ void rtc_init() { struct rtc_date rd; rtc_get_clock(&rd); - // Has time has accumulated since the - // the installation of the battery? + // Has time accumulated since the + // installation of the battery? g_rtc_has_battery = rd.year > 1970; LOGI("rtc_init %s detected a battery", (g_rtc_has_battery ? "has" : "has NOT")); + if (!g_rtc_has_battery) { + g_setting.record.naming = SETTING_NAMING_CONTIGUOUS; + ini_putl("record", "naming", g_setting.record.naming, SETTING_INI); + } + if (rd.year == 1970) { LOGI("rtc_init updating both clocks via settings"); rd.year = g_setting.clock.year; diff --git a/src/record/confparser.c b/src/record/confparser.c index 5b6676fb..eddc266f 100755 --- a/src/record/confparser.c +++ b/src/record/confparser.c @@ -27,6 +27,7 @@ #define KEY_SIZE "size" #define KEY_FULL "full" #define KEY_AUDIO "audio" +#define KEY_NAMING "naming" #define KEY_WIDTH "width" #define KEY_HEIGHT "height" @@ -426,6 +427,10 @@ void conf_loadRecordParams(char* confFile, RecordParams_t* para) } } + lValue = ini_getl(SEC_RECORD, KEY_NAMING, NAMING_CONTIGUOUS, confFile); + lValue = check_set(lValue, NAMING_CONTIGUOUS, NAMING_DATE); + para->fileNaming = lValue; + lValue = ini_getl(SEC_RECORD, KEY_DURATION, REC_packDURATION, confFile); lValue = check_set(lValue, REC_minDURATION, REC_maxDURATION); para->packDuration = lValue * 60*1000; //minutes to millseconds diff --git a/src/record/main.c b/src/record/main.c index 29aefed5..50077ad7 100644 --- a/src/record/main.c +++ b/src/record/main.c @@ -136,6 +136,7 @@ void record_dumpParams(RecordParams_t* params) LOGD("full: %d MB", params->minDiskSize); LOGD("duration: %d minutes", params->packDuration/(60*1000)); LOGD("audio : %s", params->enableAudio ? "yes" : "no"); + LOGD("naming : %s", params->fileNaming == NAMING_DATE ? "Date" : "Contiguous"); } void record_dumpVeParams(VencParams_t* params) @@ -348,8 +349,20 @@ int record_start(RecordContext_t* recCtx) LOGE("get sps failed: %x", ret); } + char dateString[16]; char sFile[256]; - REC_filePathGet(sFile, recCtx->params.packPath, REC_packPREFIX, nbFileIndex, recCtx->params.packType); + switch (recCtx->params.fileNaming) { + case NAMING_CONTIGUOUS: + REC_filePathGet(sFile, recCtx->params.packPath, REC_packPREFIX, nbFileIndex, recCtx->params.packType); + break; + case NAMING_DATE: { + const time_t t = time(0); + const struct tm* date = localtime(&t); + sprintf(dateString, "%04d%02d%02d-%02d%02d%02d", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); + sprintf(sFile, "%s%s.%s", recCtx->params.packPath, dateString, recCtx->params.packType); + break; + } + } FFPack_t* ff = ffpack_openFile(sFile, NULL); if( ff == NULL ) { @@ -403,6 +416,22 @@ int record_start(RecordContext_t* recCtx) recCtx->fpsStatus.tickFps = recCtx->tickBegin; recCtx->fpsStatus.nbFrames= 0; + // Add metadata to the program context + // Note: ts container does not support date so this will only be visible when + // recording to mp4 container format + { + const time_t t = time(0); + const struct tm * date = localtime(&t); + char localDateString[20]; + char fileName[64]; + + strcpy(fileName, strrchr(sFile, '/') + 1); + av_dict_set(&ff->ofmtContext->metadata, "title", fileName, 0); + + sprintf(localDateString, "%04d-%02d-%02d %02d:%02d:%02d", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); + av_dict_set(&ff->ofmtContext->metadata, "date", localDateString, 0); + } + ret = ffpack_start(ff); if( ret != SUCCESS ) { goto failed; @@ -424,7 +453,14 @@ int record_start(RecordContext_t* recCtx) record_saveStatus(recCtx, REC_statusRun); recCtx->nbFileIndex++; - REC_filePathGet(sFile, recCtx->params.packPath, REC_packPREFIX, nbFileIndex, REC_packSnapTYPE); + switch (recCtx->params.fileNaming) { + case NAMING_CONTIGUOUS: + REC_filePathGet(sFile, recCtx->params.packPath, REC_packPREFIX, nbFileIndex, REC_packSnapTYPE); + break; + case NAMING_DATE: + sprintf(sFile, "%s%s.%s", recCtx->params.packPath, dateString, REC_packSnapTYPE); + break; + } ret = record_takePicture(recCtx, sFile); record_dumpViParams(&viParams); diff --git a/src/record/record.h b/src/record/record.h index 3baf5b0f..aad06987 100644 --- a/src/record/record.h +++ b/src/record/record.h @@ -41,6 +41,11 @@ typedef enum REC_statusBut, } RecordStatus_e; +typedef enum { + NAMING_CONTIGUOUS, + NAMING_DATE +} FileNaming_t; + typedef struct { char diskPath[MAX_pathLEN/2]; @@ -50,6 +55,7 @@ typedef struct uint32_t minDiskSize; uint64_t packSize; bool enableAudio; + FileNaming_t fileNaming; } RecordParams_t; typedef struct diff --git a/src/ui/page_playback.c b/src/ui/page_playback.c index deae92f7..0d0d6425 100644 --- a/src/ui/page_playback.c +++ b/src/ui/page_playback.c @@ -105,6 +105,11 @@ static void show_pb_item(uint8_t pos, char *label) { lv_label_set_text(pb_ui[pos]._label, label); lv_obj_clear_flag(pb_ui[pos]._label, LV_OBJ_FLAG_HIDDEN); + const lv_coord_t labelPosX = pb_ui[pos].x + (ITEM_PREVIEW_W - lv_txt_get_width(label, strlen(label) - 2, &lv_font_montserrat_26, 0, 0)) / 2; + const lv_coord_t labelPosY = pb_ui[pos].y + ITEM_PREVIEW_H + 10; + lv_obj_set_pos(pb_ui[pos]._label, labelPosX, labelPosY); + lv_obj_set_pos(pb_ui[pos]._arrow, labelPosX - lv_obj_get_width(pb_ui[pos]._arrow) - 5, labelPosY); + sprintf(fname, "%s/%s." REC_packJPG, TMP_DIR, label); if (fs_file_exists(fname)) sprintf(fname, "A:%s/%s." REC_packJPG, TMP_DIR, label); @@ -201,6 +206,9 @@ static int walk_sdcard() { } media_file_node_t *pnode = &media_db.list[media_db.count]; + ZeroMemory(pnode->filename, sizeof(pnode->filename)); + ZeroMemory(pnode->label, sizeof(pnode->label)); + ZeroMemory(pnode->ext, sizeof(pnode->ext)); strcpy(pnode->filename, in_file->d_name); strncpy(pnode->label, in_file->d_name, dot - in_file->d_name); strcpy(pnode->ext, dot + 1); @@ -314,11 +322,12 @@ static void mark_video_file(int const seq) { const int index = find_next_available_hot_index(); char cmd[256]; - int length = sprintf(cmd, "mv %s%s ", MEDIA_FILES_DIR, pnode->filename); - REC_filePathGet(&cmd[length], MEDIA_FILES_DIR, REC_packHotPREFIX, index, pnode->ext); + char newLabel[68]; + sprintf(newLabel, "%s%s", REC_hotPREFIX, pnode->label); + + sprintf(cmd, "mv %s%s %s%s.%s", MEDIA_FILES_DIR, pnode->filename, MEDIA_FILES_DIR, newLabel, pnode->ext); system_exec(cmd); - length = sprintf(cmd, "mv %s%s." REC_packJPG " ", MEDIA_FILES_DIR, pnode->label); - REC_filePathGet(&cmd[length], MEDIA_FILES_DIR, REC_packHotPREFIX, index, REC_packJPG); + sprintf(cmd, "mv %s%s." REC_packJPG " %s%s." REC_packJPG, MEDIA_FILES_DIR, pnode->label, MEDIA_FILES_DIR, newLabel); system_exec(cmd); walk_sdcard(); diff --git a/src/ui/page_record.c b/src/ui/page_record.c index a5ae376f..20f31bb8 100644 --- a/src/ui/page_record.c +++ b/src/ui/page_record.c @@ -6,26 +6,36 @@ #include "../core/common.hh" #include "core/settings.h" +#include "driver/rtc.h" #include "page_common.h" #include "ui/ui_style.h" -static btn_group_t btn_group0; -static btn_group_t btn_group1; -static btn_group_t btn_group2; -static btn_group_t btn_group3; -static btn_group_t btn_group4; +static btn_group_t btn_group_record_mode; +static btn_group_t btn_group_format; +static btn_group_t btn_group_record_osd; +static btn_group_t btn_group_record_audio; +static btn_group_t btn_group_audio_source; +static btn_group_t btn_group_file_naming; static lv_coord_t col_dsc[] = {160, 200, 200, 160, 120, 120, LV_GRID_TEMPLATE_LAST}; static lv_coord_t row_dsc[] = {60, 60, 60, 60, 60, 60, 60, 60, 60, 60, LV_GRID_TEMPLATE_LAST}; static void update_visibility() { - btn_group_enable(&btn_group4, btn_group3.current == 0); + btn_group_enable(&btn_group_audio_source, btn_group_record_audio.current == 0); - if (btn_group3.current == 0) { + if (btn_group_record_audio.current == 0) { lv_obj_add_flag(pp_record.p_arr.panel[4], FLAG_SELECTABLE); } else { lv_obj_clear_flag(pp_record.p_arr.panel[4], FLAG_SELECTABLE); } + + btn_group_enable(&btn_group_file_naming, rtc_has_battery() == 0); + + if (rtc_has_battery() == 0) { + lv_obj_add_flag(pp_record.p_arr.panel[5], FLAG_SELECTABLE); + } else { + lv_obj_clear_flag(pp_record.p_arr.panel[5], FLAG_SELECTABLE); + } } static lv_obj_t *page_record_create(lv_obj_t *parent, panel_arr_t *arr) { @@ -53,18 +63,20 @@ static lv_obj_t *page_record_create(lv_obj_t *parent, panel_arr_t *arr) { create_select_item(arr, cont); - create_btn_group_item(&btn_group0, cont, 2, "Record Mode", "Auto", "Manual", "", "", 0); - create_btn_group_item(&btn_group1, cont, 2, "Record Format", "MP4", "TS", "", "", 1); - create_btn_group_item(&btn_group2, cont, 2, "Record OSD", "Yes", "No", "", "", 2); - create_btn_group_item(&btn_group3, cont, 2, "Record Audio", "Yes", "No", "", "", 3); - create_btn_group_item(&btn_group4, cont, 3, "Audio Source", "Mic", "Line In", "A/V In", "", 4); - create_label_item(cont, "< Back", 1, 5, 1); - - btn_group_set_sel(&btn_group0, g_setting.record.mode_manual ? 1 : 0); - btn_group_set_sel(&btn_group1, g_setting.record.format_ts ? 1 : 0); - btn_group_set_sel(&btn_group2, g_setting.record.osd ? 0 : 1); - btn_group_set_sel(&btn_group3, g_setting.record.audio ? 0 : 1); - btn_group_set_sel(&btn_group4, g_setting.record.audio_source); + create_btn_group_item(&btn_group_record_mode, cont, 2, "Record Mode", "Auto", "Manual", "", "", 0); + create_btn_group_item(&btn_group_format, cont, 2, "Record Format", "MP4", "TS", "", "", 1); + create_btn_group_item(&btn_group_record_osd, cont, 2, "Record OSD", "Yes", "No", "", "", 2); + create_btn_group_item(&btn_group_record_audio, cont, 2, "Record Audio", "Yes", "No", "", "", 3); + create_btn_group_item(&btn_group_audio_source, cont, 3, "Audio Source", "Mic", "Line In", "A/V In", "", 4); + create_btn_group_item(&btn_group_file_naming, cont, 2, "Naming Scheme", "Digits", "Date", "", "", 5); + create_label_item(cont, "< Back", 1, 6, 1); + + btn_group_set_sel(&btn_group_record_mode, g_setting.record.mode_manual ? 1 : 0); + btn_group_set_sel(&btn_group_format, g_setting.record.format_ts ? 1 : 0); + btn_group_set_sel(&btn_group_record_osd, g_setting.record.osd ? 0 : 1); + btn_group_set_sel(&btn_group_record_audio, g_setting.record.audio ? 0 : 1); + btn_group_set_sel(&btn_group_audio_source, g_setting.record.audio_source); + btn_group_set_sel(&btn_group_file_naming, g_setting.record.naming); lv_obj_t *label2 = lv_label_create(cont); lv_label_set_text(label2, "MP4 format requires properly closing files or the files will be corrupt. \nTS format is highly recommended."); @@ -74,7 +86,7 @@ static lv_obj_t *page_record_create(lv_obj_t *parent, panel_arr_t *arr) { lv_obj_set_style_pad_top(label2, 12, 0); lv_label_set_long_mode(label2, LV_LABEL_LONG_WRAP); lv_obj_set_grid_cell(label2, LV_GRID_ALIGN_START, 1, 4, - LV_GRID_ALIGN_START, 6, 3); + LV_GRID_ALIGN_START, 7, 3); update_visibility(); @@ -83,37 +95,43 @@ static lv_obj_t *page_record_create(lv_obj_t *parent, panel_arr_t *arr) { static void page_record_on_click(uint8_t key, int sel) { if (sel == 0) { - btn_group_toggle_sel(&btn_group0); - g_setting.record.mode_manual = btn_group_get_sel(&btn_group0); + btn_group_toggle_sel(&btn_group_record_mode); + g_setting.record.mode_manual = btn_group_get_sel(&btn_group_record_mode); settings_put_bool("record", "mode_manual", g_setting.record.mode_manual); } else if (sel == 1) { - btn_group_toggle_sel(&btn_group1); - g_setting.record.format_ts = btn_group_get_sel(&btn_group1); + btn_group_toggle_sel(&btn_group_format); + g_setting.record.format_ts = btn_group_get_sel(&btn_group_format); settings_put_bool("record", "format_ts", g_setting.record.format_ts); if (g_setting.record.format_ts) ini_puts("record", "type", "ts", REC_CONF); else ini_puts("record", "type", "mp4", REC_CONF); } else if (sel == 2) { - btn_group_toggle_sel(&btn_group2); - g_setting.record.osd = !btn_group_get_sel(&btn_group2); + btn_group_toggle_sel(&btn_group_record_osd); + g_setting.record.osd = !btn_group_get_sel(&btn_group_record_osd); settings_put_bool("record", "osd", g_setting.record.osd); } else if (sel == 3) { - btn_group_toggle_sel(&btn_group3); - g_setting.record.audio = !btn_group_get_sel(&btn_group3); + btn_group_toggle_sel(&btn_group_record_audio); + g_setting.record.audio = !btn_group_get_sel(&btn_group_record_audio); settings_put_bool("record", "audio", g_setting.record.audio); update_visibility(); } else if (sel == 4) { - btn_group_toggle_sel(&btn_group4); - g_setting.record.audio_source = btn_group_get_sel(&btn_group4); + btn_group_toggle_sel(&btn_group_audio_source); + g_setting.record.audio_source = btn_group_get_sel(&btn_group_audio_source); ini_putl("record", "audio_source", g_setting.record.audio_source, SETTING_INI); + } else if (sel == 5) { + if (rtc_has_battery() == 0) { + btn_group_toggle_sel(&btn_group_file_naming); + g_setting.record.naming = btn_group_get_sel(&btn_group_file_naming); + ini_putl("record", "naming", g_setting.record.naming, SETTING_INI); + } } } page_pack_t pp_record = { .p_arr = { .cur = 0, - .max = 6, + .max = 7, }, .name = "Record Option", .create = page_record_create,