739 lines
20 KiB
C
739 lines
20 KiB
C
/*
|
|
*******************************************************************************
|
|
* Copyright (c) 2010-2022 VATICS(KNERON) Inc. All rights reserved.
|
|
*
|
|
* +-----------------------------------------------------------------+
|
|
* | THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED |
|
|
* | AND COPIED IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF SUCH |
|
|
* | A LICENSE AND WITH THE INCLUSION OF THE THIS COPY RIGHT NOTICE. |
|
|
* | THIS SOFTWARE OR ANY OTHER COPIES OF THIS SOFTWARE MAY NOT BE |
|
|
* | PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. THE |
|
|
* | OWNERSHIP AND TITLE OF THIS SOFTWARE IS NOT TRANSFERRED. |
|
|
* | |
|
|
* | THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT |
|
|
* | ANY PRIOR NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY |
|
|
* | VATICS(KNERON) INC. |
|
|
* +-----------------------------------------------------------------+
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
#include <pthread.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "fec_api.h"
|
|
#include "lvgl_example.h"
|
|
#include "lvgl_example_msg_sender.h"
|
|
|
|
#include "MemBroker/mem_broker.h"
|
|
#include "MsgBroker/msg_broker.h"
|
|
#include "vmf/video_source.h"
|
|
#include "vmf/video_bind.h"
|
|
#include "vmf/video_encoder.h"
|
|
#include "vmf/video_display_mechanism.h"
|
|
#include "vmf/source_connect.h"
|
|
#include "vmf/sync_shared_memory.h"
|
|
#include "vmf/config_fec.h"
|
|
#include "vmf/vector_dma.h"
|
|
#include "comm/video_buf.h"
|
|
#include "comm/frame_info.h"
|
|
#include "iniparser/iniparser.h"
|
|
|
|
#include "lvgl/lvgl.h"
|
|
#include "lvgl/custom/lv_custom.h"
|
|
#include "lv_drivers/display/v4l2dev.h"
|
|
|
|
#define VENC_VSRC_PIN "vsrc_ssm"
|
|
#define VENC_RESOURCE_DIR "./Resource/"
|
|
|
|
#define release_string(X) do { if (X) free(X); } while (0)
|
|
|
|
typedef enum {
|
|
HIDE = 0,
|
|
SHOW
|
|
} TEXT_MODE;
|
|
|
|
VMF_LAYOUT_T g_tLayout;
|
|
VMF_VSRC_HANDLE_T* g_ptVsrcHandle = NULL;
|
|
|
|
static char *g_szConfig = NULL;
|
|
static char *g_szAutoSceneConfig = NULL;
|
|
static char *g_szSensorConfig = NULL;
|
|
static uint32_t g_dwWidth, g_dwHeight;
|
|
static uint32_t g_dwFontSize, g_dwSubIdx;
|
|
static VMF_VENC_CODEC_TYPE g_eCodecType = VMF_VENC_CODEC_TYPE_H265;
|
|
static int g_bTerminate = 0;
|
|
static char text_string[32];
|
|
|
|
/*gui setting */
|
|
static uint32_t pool_size;
|
|
static uint32_t gui_width;
|
|
static uint32_t gui_height;
|
|
static uint32_t gui_x;
|
|
static uint32_t gui_y;
|
|
static bool yuv_device;
|
|
|
|
/*Indev button data*/
|
|
static const char *btn_txt[2][4] = {
|
|
{ "page1", "show_def", "show_ghi", "show_jkl" },
|
|
{ "show_lmn", "show_opq", "show_rst", "return" }
|
|
};
|
|
static const char *ovl_txt[2][4] = {
|
|
{ "", "def", "ghi", "jkl" },
|
|
{"lmn", "opq", "rst", "" }
|
|
};
|
|
static lv_point_t positons[4];
|
|
static int btn_index = 0;
|
|
static bool btn_status = 0;
|
|
static int page_index = 0;
|
|
|
|
static VMF_BIND_CONTEXT_T* g_ptBind = NULL;
|
|
|
|
extern void dump_yuv(uint8_t *, uint8_t *, uint8_t *, uint32_t, const char *);
|
|
|
|
static void load_config(void);
|
|
static void sig_handler(int);
|
|
static void exit_handler(void);
|
|
static int init_video_source(void);
|
|
static int init_fec_mode(void);
|
|
static int init_dma_handle(VMF_DMA_DESCRIPTOR_T **, VMF_DMA_HANDLE_T **);
|
|
static int dma_upadate_mem(uint8_t *, uint8_t *, uint32_t, VMF_DMA_DESCRIPTOR_T *, VMF_DMA_HANDLE_T *);
|
|
static void vsrc_init_callback(unsigned int, unsigned int);
|
|
static void setup_fec(VMF_FEC_ORIG_CONFIG_T *);
|
|
static void setup_spec(VMF_VSRC_SPEC_CONFIG_T *, VMF_VENC_CODEC_TYPE);
|
|
static void release_video_source(void);
|
|
static int init_bind(void);
|
|
static int init_video_display(VMF_VDISP_HANDLE_T **);
|
|
static void *video_loop(void *);
|
|
static void *gui_loop(void *);
|
|
static void draw_screen(void);
|
|
static bool button_read(lv_indev_drv_t *, lv_indev_data_t *);
|
|
static int get_button_index(void);
|
|
static bool get_button_status(void);
|
|
static void reset_button_status(void);
|
|
static void button_event(lv_obj_t *, lv_event_t);
|
|
static void release_bind(void);
|
|
static void msg_callback(MsgContext *, void *);
|
|
static int init_text_overlay(void);
|
|
static int set_text_overlay(TEXT_MODE);
|
|
|
|
void dump_yuv(uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_size, const char *fmt)
|
|
{
|
|
FILE *out = fopen(fmt, "wb");
|
|
fwrite(y, 1, y_size, out);
|
|
fwrite(u, 1, y_size >> 2, out);
|
|
fwrite(v, 1, y_size >> 2, out);
|
|
fclose(out);
|
|
}
|
|
|
|
void load_config(void)
|
|
{
|
|
const char *tmp;
|
|
dictionary *ini;
|
|
|
|
if((ini = iniparser_load(g_szConfig)) == NULL) {
|
|
print_msg("Unable to parse file: %s\n", g_szConfig);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
tmp = iniparser_getstring(ini, "sensor:sensor_config", NULL);
|
|
g_szSensorConfig = strdup(tmp);
|
|
|
|
tmp = iniparser_getstring(ini, "sensor:autoscene_config", NULL);
|
|
g_szAutoSceneConfig = strdup(tmp);
|
|
|
|
g_dwWidth = iniparser_getint(ini, "stream:width", 1920);
|
|
g_dwHeight = iniparser_getint(ini, "stream:height", 1080);
|
|
|
|
pool_size = iniparser_getint(ini, "gui:pool_size", 0);
|
|
|
|
gui_width = iniparser_getint(ini, "gui:width", 480);
|
|
gui_height = iniparser_getint(ini, "gui:height", 320);
|
|
|
|
gui_x = iniparser_getint(ini, "gui:pos_x", 0);
|
|
gui_y = iniparser_getint(ini, "gui:pos_y", 0);
|
|
|
|
yuv_device = iniparser_getboolean(ini, "gui:yuv_device", 0);
|
|
|
|
g_dwFontSize = iniparser_getint(ini, "text_overlay:font_size", 5);
|
|
|
|
iniparser_freedict(ini);
|
|
}
|
|
|
|
void sig_handler(int sig)
|
|
{
|
|
print_msg("[%s] receive SIGNAL: %d\n",__func__, sig);
|
|
g_bTerminate = 1;
|
|
}
|
|
|
|
void exit_handler(void)
|
|
{
|
|
release_string(g_szConfig);
|
|
release_string(g_szSensorConfig);
|
|
release_string(g_szAutoSceneConfig);
|
|
}
|
|
|
|
int init_video_source(void)
|
|
{
|
|
VMF_VSRC_INITOPT_T tInitOpt;
|
|
VMF_VSRC_FRONTEND_CONFIG_T tFrontCfg;
|
|
VMF_FEC_ORIG_CONFIG_T tFecOrgCfg;
|
|
|
|
memset(&tInitOpt, 0, sizeof tInitOpt);
|
|
memset(&tFrontCfg, 0, sizeof tFrontCfg);
|
|
memset(&tFecOrgCfg, 0, sizeof tFecOrgCfg);
|
|
|
|
setup_fec(&tFecOrgCfg);
|
|
tFrontCfg.tFecInitConfig.ptFecConfig = &tFecOrgCfg;
|
|
tFrontCfg.tFecInitConfig.eCoeffMode = VMF_FEC_COEF_MODE_ORIG;
|
|
tFrontCfg.tFecInitConfig.eFecMethod = VMF_FEC_METHOD_GTR;
|
|
tFrontCfg.tFecInitConfig.eGridSize = VMF_FEC_GRID_8X8;
|
|
tFrontCfg.dwSensorConfigCount = 1;
|
|
tFrontCfg.apszSensorConfig[0] = g_szSensorConfig;
|
|
|
|
tInitOpt.dwFrontConfigCount = 1;
|
|
tInitOpt.ptFrontConfig = &tFrontCfg;
|
|
tInitOpt.pszAutoSceneConfig = g_szAutoSceneConfig;
|
|
tInitOpt.pszOutPinPrefix = VENC_VSRC_PIN;
|
|
tInitOpt.bShared = 1;
|
|
tInitOpt.fnInitCallback = vsrc_init_callback;
|
|
tInitOpt.pszResourceDir = VENC_RESOURCE_DIR;
|
|
setup_spec(&tInitOpt.tSpecConfig, g_eCodecType);
|
|
|
|
g_ptVsrcHandle = VMF_VSRC_Init(&tInitOpt);
|
|
if (!g_ptVsrcHandle) {
|
|
print_msg("[%s] VMF_VSRC_Init failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
if (VMF_VSRC_Start(g_ptVsrcHandle, NULL)) {
|
|
print_msg("[%s] VMF_VSRC_Start failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int init_fec_mode(void)
|
|
{
|
|
if (setup_fec_mode(0, FEC_MODE_1R, false, g_eCodecType)) {
|
|
print_msg("[%s] setup_fec_mode failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int init_dma_handle(VMF_DMA_DESCRIPTOR_T **pptDmaDesc, VMF_DMA_HANDLE_T **pptDmaHandle)
|
|
{
|
|
VMF_DMA_1D_INIT_T tDmaInit;
|
|
memset(&tDmaInit, 0, sizeof tDmaInit);
|
|
tDmaInit.dwFormatFlag = 0;
|
|
*pptDmaDesc = VMF_DMA_Descriptor_Create(DMA_1D, &tDmaInit);
|
|
if (!*pptDmaDesc) {
|
|
print_msg("[%s] VMF_DMA_Descriptor_Create failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
*pptDmaHandle = VMF_DMA_Init(1, 128);
|
|
if (!*pptDmaHandle) {
|
|
print_msg("[%s] VMF_DMA_Init failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int dma_upadate_mem(uint8_t *pbyDst, uint8_t *pbySrc, uint32_t dwSize,
|
|
VMF_DMA_DESCRIPTOR_T *ptDmaDesc, VMF_DMA_HANDLE_T *ptDmaHandle)
|
|
{
|
|
VMF_DMA_ADDR_T tDmaAddr;
|
|
tDmaAddr.pbySrcYPhysAddr = pbySrc;
|
|
tDmaAddr.pbyDstYPhysAddr = pbyDst;
|
|
tDmaAddr.dwTransSize = dwSize;
|
|
if (VMF_DMA_Descriptor_Update_Addr(ptDmaDesc, &tDmaAddr)) {
|
|
print_msg("[%s] VMF_DMA_Descriptor_Update_Addr failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
if (VMF_DMA_Setup(ptDmaHandle, &ptDmaDesc, 1)) {
|
|
print_msg("[%s] VMF_DMA_Setup failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
if (VMF_DMA_Process(ptDmaHandle)) {
|
|
print_msg("[%s] VMF_DMA_Process failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void vsrc_init_callback(unsigned int dwWidth, unsigned int dwHeight)
|
|
{
|
|
memset(&g_tLayout, 0, sizeof g_tLayout);
|
|
g_tLayout.dwCanvasWidth = dwWidth;
|
|
g_tLayout.dwCanvasHeight = dwHeight;
|
|
g_tLayout.dwVideoPosX = 0;
|
|
g_tLayout.dwVideoPosY = 0;
|
|
g_tLayout.dwVideoWidth = dwWidth;
|
|
g_tLayout.dwVideoHeight = dwHeight;
|
|
print_msg("[%s]: width:%u, height:%u\n", __func__, dwHeight, dwHeight);
|
|
}
|
|
|
|
void setup_spec(VMF_VSRC_SPEC_CONFIG_T *ptSpec, VMF_VENC_CODEC_TYPE eCodecType)
|
|
{
|
|
ptSpec->bEnableSpec = 1;
|
|
|
|
ptSpec->dwIspMode = VMF_ISP_MODE_FEC;
|
|
|
|
switch (eCodecType) {
|
|
case VMF_VENC_CODEC_TYPE_H264:
|
|
ptSpec->tIfpEncSpec.bEncH264 = 1;
|
|
ptSpec->tIspEncSpec.bEncH264 = 1;
|
|
break;
|
|
case VMF_VENC_CODEC_TYPE_H265:
|
|
ptSpec->tIfpEncSpec.bEncH265 = 1;
|
|
ptSpec->tIspEncSpec.bEncH265 = 1;
|
|
break;
|
|
case VMF_VENC_CODEC_TYPE_MJPG:
|
|
ptSpec->tIfpEncSpec.bEncJPEG = 1;
|
|
ptSpec->tIspEncSpec.bEncJPEG = 1;
|
|
break;
|
|
default:
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void setup_fec(VMF_FEC_ORIG_CONFIG_T *ptFecOrgCfg)
|
|
{
|
|
ptFecOrgCfg->eAppType = VMF_FEC_APP_TABL;
|
|
ptFecOrgCfg->fZoom = 1.0;
|
|
}
|
|
|
|
void release_video_source(void)
|
|
{
|
|
if (g_ptVsrcHandle) {
|
|
VMF_VSRC_Stop(g_ptVsrcHandle);
|
|
VMF_VSRC_Release(g_ptVsrcHandle);
|
|
}
|
|
}
|
|
|
|
int init_bind(void)
|
|
{
|
|
VMF_BIND_INITOPT_T tInitOpt;
|
|
memset(&tInitOpt, 0, sizeof tInitOpt);
|
|
|
|
tInitOpt.dwSrcOutputIndex = 0;
|
|
tInitOpt.ptSrcHandle = g_ptVsrcHandle;
|
|
tInitOpt.pfnQueryFunc = (VMF_BIND_QUERY_FUNC) VMF_VSRC_GetInfo;
|
|
tInitOpt.pfnIspFunc = (VMF_BIND_CONFIG_ISP_FUNC) VMF_VSRC_ConfigISP;
|
|
|
|
g_ptBind = VMF_BIND_Init(&tInitOpt);
|
|
if (!g_ptBind){
|
|
print_msg("[%s] VMF_BIND_Init failed!!\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void release_bind(void)
|
|
{
|
|
if (g_ptBind)
|
|
VMF_BIND_Release(g_ptBind);
|
|
}
|
|
|
|
int init_video_display(VMF_VDISP_HANDLE_T **pptDispHandle)
|
|
{
|
|
VMF_VDISP_INITOPT_T tDisplayOpt;
|
|
memset(&tDisplayOpt, 0, sizeof tDisplayOpt);
|
|
|
|
tDisplayOpt.dwInPixFormat = VMF_MAKEFOURCC('Y', 'M', '1', '2');;
|
|
tDisplayOpt.dwMaxInWidth = VMF_32_ALIGN(g_dwWidth);
|
|
tDisplayOpt.dwMaxInHeight = VMF_16_ALIGN(g_dwHeight);
|
|
if ((*pptDispHandle = VMF_VDISP_Init(&tDisplayOpt)) == NULL) {
|
|
printf("%s VMF_VDISP_Init failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void *video_loop(void *data __attribute__((unused)))
|
|
{
|
|
VMF_SRC_CONNECT_INFO_T tSrcCntInfo;
|
|
SSM_HANDLE_T *ptSsmHandle = NULL;
|
|
SSM_BUFFER_T tSsmBuf;
|
|
VMF_FRAME_BUF_T atDispBuf[VMF_VIDEO_DISPLAY_MIN_QUEUE_SIZE];
|
|
uint8_t *atPhysAddr[VMF_VIDEO_DISPLAY_MIN_QUEUE_SIZE];
|
|
unsigned int dwDispQIdx = 0;
|
|
pthread_t thrd_g;
|
|
unsigned int dwYSize = VMF_32_ALIGN(g_dwWidth)*VMF_16_ALIGN(g_dwHeight), dwYUVSize = dwYSize * 3 >> 1;
|
|
VMF_DMA_DESCRIPTOR_T *ptDmaDesc = NULL;
|
|
VMF_DMA_HANDLE_T *ptDmaHandle = NULL;
|
|
VMF_VDISP_HANDLE_T *ptDispHandle = NULL;
|
|
|
|
if (init_video_display(&ptDispHandle)) {
|
|
print_msg("[%s] init_video_display failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
if (init_dma_handle(&ptDmaDesc, &ptDmaHandle)) {
|
|
print_msg("[%s] init_dma_handle failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
memset(&tSrcCntInfo, 0, sizeof tSrcCntInfo);
|
|
memset(&tSsmBuf, 0, sizeof tSsmBuf);
|
|
memset(atDispBuf, 0, sizeof atDispBuf);
|
|
|
|
for (int i = 0; i < VMF_VIDEO_DISPLAY_MIN_QUEUE_SIZE; i++) {
|
|
atDispBuf[i].apdwData[0] = MemBroker_GetMemory(dwYUVSize, VMF_ALIGN_TYPE_8_BYTE);
|
|
if (!atDispBuf[i].apdwData[0]) {
|
|
print_msg("[%s] allocate display buffer failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
atDispBuf[i].apdwData[1] = atDispBuf[i].apdwData[0] + dwYSize;
|
|
atDispBuf[i].apdwData[2] = atDispBuf[i].apdwData[1] + (dwYSize >> 2);
|
|
atPhysAddr[i] = MemBroker_GetPhysAddr(atDispBuf[i].apdwData[0]);
|
|
}
|
|
|
|
tSrcCntInfo.dwCodecType = g_eCodecType;
|
|
if (VMF_BIND_Request(g_ptBind, g_dwWidth, g_dwHeight, 0, 0, &tSrcCntInfo)) {
|
|
print_msg("[%s] VMF_BIND_Request failed!\n", __func__);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
g_dwSubIdx = tSrcCntInfo.bUseResizedSrc ? 1 : 0;
|
|
|
|
ptSsmHandle = SSM_Reader_Init(tSrcCntInfo.szSrcPin, tSrcCntInfo.bIsSsmShared);
|
|
if (!ptSsmHandle) {
|
|
print_msg("[%s] SSM_Reader_Init failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
if (init_text_overlay()) {
|
|
print_msg("[%s] init_text_overlay failed\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
pthread_create(&thrd_g, NULL, gui_loop, ptDispHandle);
|
|
pthread_setname_np(thrd_g, "gui_loop");
|
|
|
|
while(!g_bTerminate) {
|
|
uint8_t *pbySrc, *pbyDst;
|
|
SSM_Reader_ReturnReceiveBuff(ptSsmHandle, &tSsmBuf);
|
|
pbySrc = MemBroker_GetPhysAddr(tSsmBuf.buffer + VMF_MAX_SSM_HEADER_SIZE);
|
|
pbyDst = atPhysAddr[dwDispQIdx];
|
|
if (dma_upadate_mem(pbyDst, pbySrc, dwYUVSize, ptDmaDesc, ptDmaHandle)) {
|
|
print_msg("[%s] dma_upadate_mem failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
VMF_VDISP_ProcessOneFrame(ptDispHandle, &atDispBuf[dwDispQIdx], &dwDispQIdx);
|
|
}
|
|
|
|
RELEASE:
|
|
if (thrd_g) {
|
|
VMF_VDISP_PIP_Stop(ptDispHandle);
|
|
pthread_join(thrd_g, NULL);
|
|
}
|
|
|
|
if (ptSsmHandle) {
|
|
SSM_Reader_ReturnBuff(ptSsmHandle, &tSsmBuf);
|
|
SSM_Release(ptSsmHandle);
|
|
}
|
|
|
|
if (ptDispHandle)
|
|
VMF_VDISP_Release(ptDispHandle);
|
|
|
|
for (int i = 0; i < VMF_VIDEO_DISPLAY_MIN_QUEUE_SIZE; i++) {
|
|
if (atDispBuf[i].apdwData[0])
|
|
MemBroker_FreeMemory(atDispBuf[i].apdwData[0]);
|
|
}
|
|
|
|
if (ptDmaDesc)
|
|
VMF_DMA_Descriptor_Destroy(ptDmaDesc);
|
|
|
|
if (ptDmaHandle)
|
|
VMF_DMA_Release(ptDmaHandle);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void *gui_loop(void *data)
|
|
{
|
|
VMF_VDISP_HANDLE_T *disp_handle = data;
|
|
unsigned int disp_buf_size;
|
|
lv_color_t *buf;
|
|
lv_disp_buf_t disp_buf;
|
|
lv_disp_drv_t disp_drv;
|
|
lv_indev_drv_t indev_drv;
|
|
lv_indev_t *my_indev;
|
|
|
|
/*LittlevGL init, allocate memory space as pool*/
|
|
lv_init(pool_size);
|
|
|
|
/*Setup screen parameters*/
|
|
lv_scr_setup(disp_handle, gui_width, gui_height, gui_x, gui_y, yuv_device);
|
|
|
|
/*Linux v4l2 dev init*/
|
|
v4l2dev_init();
|
|
|
|
/*Init display buffer, allocate buffer for screen-flushing*/
|
|
disp_buf_size = 10 * lv_scr_get_hor_res();
|
|
buf = malloc(disp_buf_size * sizeof *buf);
|
|
|
|
/*Initialize a descriptor for the buffer*/
|
|
lv_disp_buf_init(&disp_buf, buf, NULL, disp_buf_size);
|
|
|
|
/*Initialize and register a display driver*/
|
|
lv_disp_drv_init(&disp_drv);
|
|
disp_drv.buffer = &disp_buf;
|
|
disp_drv.flush_cb = v4l2dev_flush;
|
|
lv_disp_drv_register(&disp_drv);
|
|
|
|
/*Draw the menu on screen*/
|
|
draw_screen();
|
|
|
|
/*Initialize and register a input driver*/
|
|
lv_indev_drv_init(&indev_drv);
|
|
indev_drv.type = LV_INDEV_TYPE_BUTTON;
|
|
indev_drv.read_cb = button_read;
|
|
my_indev = lv_indev_drv_register(&indev_drv);
|
|
lv_indev_set_button_points(my_indev, positons);
|
|
|
|
/*Flush screen*/
|
|
while (!g_bTerminate) {
|
|
lv_task_handler();
|
|
usleep(5000);
|
|
}
|
|
|
|
/*Release display buffer*/
|
|
free(buf);
|
|
|
|
/*Linux v4l2 dev release*/
|
|
v4l2dev_release();
|
|
|
|
/*LittlevGL release*/
|
|
lv_release();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void draw_screen(void)
|
|
{
|
|
lv_obj_t *scr = NULL;
|
|
static lv_style_t button_style_rel;
|
|
static lv_style_t button_style_pre;
|
|
uint32_t btn_w = lv_scr_get_hor_res() / 2;
|
|
uint32_t btn_h = lv_scr_get_ver_res() / 8;
|
|
|
|
/*Init screen*/
|
|
scr = lv_disp_get_scr_act(NULL);
|
|
lv_obj_clean(scr);
|
|
lv_obj_set_style(scr, &lv_style_transp);
|
|
|
|
/*Init button styles*/
|
|
lv_style_copy(&button_style_rel, &lv_style_btn_rel);
|
|
lv_style_copy(&button_style_pre, &lv_style_btn_pr);
|
|
button_style_rel.body.opa = LV_OPA_TRANSP;
|
|
button_style_rel.body.border.opa = LV_OPA_TRANSP;
|
|
button_style_rel.text.color = LV_COLOR_WHITE;
|
|
button_style_pre.body.opa = LV_OPA_TRANSP;
|
|
button_style_pre.body.border.opa = LV_OPA_TRANSP;
|
|
button_style_pre.text.color = LV_COLOR_YELLOW;
|
|
// button_style_pre.text.font = &lv_font_roboto_16;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
lv_obj_t *btn;
|
|
char name[32];
|
|
lv_obj_t *label;
|
|
uint32_t offset = btn_h * 2 + i * btn_h;
|
|
lv_area_t coords;
|
|
/*Init buttons*/
|
|
btn = lv_btn_create(scr, NULL);
|
|
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &button_style_rel);
|
|
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &button_style_pre);
|
|
lv_obj_set_size(btn, btn_w, btn_h);
|
|
lv_obj_set_event_cb(btn, button_event);
|
|
lv_obj_align(btn, NULL, LV_ALIGN_IN_TOP_MID, 0, offset);
|
|
lv_obj_get_coords(btn, &coords);
|
|
positons[i].x = (coords.x1 + coords.x2) >> 1;
|
|
positons[i].y = (coords.y1 + coords.y2) >> 1;
|
|
/*Init labels*/
|
|
strncpy(name, btn_txt[page_index][i], 32);
|
|
label = lv_label_create(btn, NULL);
|
|
lv_label_set_text(label, name);
|
|
}
|
|
}
|
|
|
|
|
|
bool button_read(lv_indev_drv_t *drv __attribute__((unused)), lv_indev_data_t *data)
|
|
{
|
|
static uint32_t last_btn = 0; /*Store the last indicated button*/
|
|
int curr_btn = get_button_index();
|
|
if (curr_btn >= 0) { /*Is there a button indicated? (-1 means no button was indicated)*/
|
|
last_btn = curr_btn;
|
|
data->state = LV_INDEV_STATE_PR;
|
|
} else {
|
|
data->state = LV_INDEV_STATE_REL;
|
|
}
|
|
data->btn_id = last_btn;
|
|
return false;
|
|
}
|
|
|
|
|
|
/* * This fuction reads external hardware button ID (0, 1, 2, ...)
|
|
* * msg_callback is used to simulate external buttons*/
|
|
int get_button_index(void)
|
|
{
|
|
return btn_index;
|
|
}
|
|
|
|
/* * This fuction reads external hardware button status (pressed/unpressed).
|
|
* * msg_callback is used to simulate external buttons*/
|
|
bool get_button_status(void)
|
|
{
|
|
return btn_status;
|
|
}
|
|
|
|
|
|
/* * This fuction resets external hardware button to unpressed. */
|
|
void reset_button_status(void)
|
|
{
|
|
btn_status = false;
|
|
}
|
|
|
|
void button_event(lv_obj_t *obj __attribute__((unused)), lv_event_t event)
|
|
{
|
|
if (get_button_status() && event == LV_EVENT_PRESSING){
|
|
int ret = 0;
|
|
int curr_idx = get_button_index();
|
|
int swap_idx = (page_index == 0) ? 0 : 3;
|
|
/*Do something*/
|
|
if (curr_idx == swap_idx) {
|
|
page_index = (page_index == 0) ? 1 : 0;
|
|
draw_screen();
|
|
ret |= set_text_overlay(HIDE);
|
|
// release_text_overlay();
|
|
} else {
|
|
strncpy(text_string, ovl_txt[page_index][curr_idx], 32);
|
|
ret |= set_text_overlay(SHOW);
|
|
}
|
|
print_msg("Button %d is selected and pressed.\n", curr_idx);
|
|
reset_button_status();
|
|
}
|
|
}
|
|
|
|
void msg_callback(MsgContext *msg_context, void *user_data __attribute__((unused)))
|
|
{
|
|
print_msg("msg_context->pszHost=%s, msg_context->pszCmd=%s \n",
|
|
msg_context->pszHost, msg_context->pszCmd);
|
|
|
|
if (!strcasecmp(msg_context->pszHost, MODULE_NAME)) {
|
|
if (!strcasecmp(msg_context->pszCmd, MSG_LVGL_BTN)) {
|
|
btn_index = *(int *) msg_context->pbyData;
|
|
btn_status = false;
|
|
} else if (!strcasecmp(msg_context->pszCmd, MSG_LVGL_ENT)) {
|
|
btn_status = true;
|
|
} else if (!strcasecmp(msg_context->pszCmd, MSG_LVGL_RST)) {
|
|
btn_index = -1;
|
|
}
|
|
}
|
|
|
|
if (msg_context->bHasResponse) {
|
|
msg_context->dwDataSize = 0;
|
|
}
|
|
}
|
|
|
|
int set_text_overlay(TEXT_MODE eMode)
|
|
{
|
|
VMF_OVERLAY_TEXT_CONFIG_T tTxtConfig;
|
|
VMF_OVERLAY_CONFIG_T tOvlConfig;
|
|
|
|
memset(&tTxtConfig, 0, sizeof tTxtConfig);
|
|
memset(&tOvlConfig, 0, sizeof tOvlConfig);
|
|
|
|
tTxtConfig.dwPosX = 0;
|
|
tTxtConfig.dwPosY = 0;
|
|
tTxtConfig.dwAlign = VMF_TEXT_ALIGN_TOP | VMF_TEXT_ALIGN_RIGHT;
|
|
tTxtConfig.pszText = text_string;
|
|
|
|
//tOvlConfig->eMode = VMF_OVERLAY_MONO;
|
|
tOvlConfig.eMode = VMF_OVERLAY_MONO;
|
|
tOvlConfig.pszDatetimeFormat = NULL;
|
|
tOvlConfig.dwDatetimePosX = 0;
|
|
tOvlConfig.dwDatetimePosY = 0;
|
|
tOvlConfig.dwDateTimeAlign = VMF_TEXT_ALIGN_TOP | VMF_TEXT_ALIGN_LEFT;
|
|
tOvlConfig.dwTextCount = eMode;
|
|
tOvlConfig.ptTextArray = &tTxtConfig;
|
|
|
|
return VMF_VSRC_ConfigOverlay(g_ptVsrcHandle, 0, g_dwSubIdx, &tOvlConfig);
|
|
}
|
|
|
|
|
|
int init_text_overlay(void)
|
|
{
|
|
FONT_INFO_T tInfo;
|
|
memset(&tInfo, 0, sizeof tInfo);
|
|
memset(text_string, 0, sizeof text_string);
|
|
tInfo.pszFontPath = "DejaVuSans-Bold.ttf";
|
|
tInfo.nFontSize = g_dwFontSize;
|
|
tInfo.fOutlineWidth = 2; // set 0, if outline is not needed
|
|
tInfo.tColorInfo.dwFontColor = 255 | (128<<8) | (128<<16);// Byte 0:y, 1:u, 2:v
|
|
tInfo.tColorInfo.dwBorderColor = 0 | (128<<8) | (128<<16); // Byte 0:y, 1:u, 2:v
|
|
tInfo.tColorInfo.dwBackColor = 0; // Byte 0:y, 1:u, 2:v, 3:alpha, set 0 as transparent background
|
|
return VMF_VSRC_SetFont(g_ptVsrcHandle, 0, g_dwSubIdx, &tInfo);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int ch;
|
|
pthread_t thrd_v;
|
|
|
|
atexit(exit_handler);
|
|
signal(SIGTERM, sig_handler);
|
|
signal(SIGINT, sig_handler);
|
|
|
|
while ((ch = getopt(argc, argv, "c:h")) != -1) {
|
|
switch(ch) {
|
|
case 'c':
|
|
g_szConfig = strdup(optarg);
|
|
break;
|
|
case 'h':
|
|
default:
|
|
print_msg("Usage:%s [-c<config_file)][-h]\n", argv[0]);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
load_config();
|
|
|
|
if (init_video_source()) {
|
|
print_msg("[%s] init_video_source failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
if (0 && init_fec_mode()) {
|
|
print_msg("[%s] init_fec_mode failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
if (init_bind()) {
|
|
print_msg("[%s] init_bind failed!\n", __func__);
|
|
goto RELEASE;
|
|
}
|
|
|
|
pthread_create(&thrd_v, NULL, video_loop, NULL);
|
|
pthread_setname_np(thrd_v, "video_loop");
|
|
|
|
MsgBroker_RegisterMsg(LVGL_CMD_FIFO);
|
|
MsgBroker_Run(LVGL_CMD_FIFO, msg_callback, NULL, &g_bTerminate);
|
|
MsgBroker_UnRegisterMsg();
|
|
|
|
pthread_join(thrd_v, NULL);
|
|
|
|
RELEASE:
|
|
release_bind();
|
|
|
|
release_video_source();
|
|
|
|
return 0;
|
|
}
|