前段时间研究了一下用Hi3531做多路图像拼接
主要问题是
1)多路图像拼接(有相互覆盖):HD的PIP各种限制,无法任意多画面拼接
2)视频同步:想让多个3531同步显示
对于问题(1),我找到两个办法
a)用虚拟VO
大概的思路是,使用虚拟VO,虚拟VO跟SD VO类似,多画面叠加没有太多限制,再将虚拟VO绑定到HD VO
这个是我做的实验
http://www.ebaina.com/bbs/forum.php?mod=redirect&goto=findpost&ptid=11048&pid=31257&fromuid=11974
b)用IVE
把要显示的图像通过IVE的DMA操作手动拼接成一幅大图像,再发送给HD VO
对于问题(2),实在是束手无策
用一个UDP server做时间服务器,发送广播包给两个3531,让它们SyncPts
这两个3531播放同一个RTSP live视频源,pts也一级一级保留发送给vdec->vpss->vo
但最终结果只能是大概同步,还是能明显的发现有先后差别(人眼能看到,最起码有2~3帧了吧)
接触Hi3531不久,有错误的地方,还请各位指正。
// virtual_vo_test.c
// {{{ headers
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include “hi_common.h”
include “hi_comm_sys.h”
include “hi_comm_vb.h”
include “hi_comm_vi.h”
include “hi_comm_vo.h”
include “hi_comm_venc.h”
include “hi_comm_vpss.h”
include “hi_comm_vdec.h”
include “hi_comm_vda.h”
include “hi_comm_region.h”
include “hi_comm_adec.h”
include “hi_comm_aenc.h”
include “hi_comm_ai.h”
include “hi_comm_ao.h”
include “hi_comm_aio.h”
include “hi_comm_hdmi.h”
include “hi_defines.h”
include “mpi_sys.h”
include “mpi_vb.h”
include “mpi_vi.h”
include “mpi_vo.h”
include “mpi_venc.h”
include “mpi_vpss.h”
include “mpi_vdec.h”
include “mpi_vda.h”
include “mpi_region.h”
include “mpi_adec.h”
include “mpi_aenc.h”
include “mpi_ai.h”
include “mpi_ao.h”
include “mpi_hdmi.h”
// }}} end of headers
define VO_DHD0 0
define VO_VIRT 10
define WIN_NUM 4
define SAMPLE_SYS_ALIGN_WIDTH 64
define SAMPLE_PIXEL_FORMAT PIXEL_FORMAT_YUV_SEMIPLANAR_420
define SAMPLE_PRT(fmt…) \
do { \
printf("[%s]-%d: ", __FUNCTION__, __LINE__); \
printf(fmt); \
} while(0)
ifdef __cplusplus
if __cplusplus
extern “C” {
endif
endif /* End of #ifdef __cplusplus */
typedef struct {
pthread_t pid;
HI_BOOL bRun;
} ThreadParam;
ThreadParam threadParam;
int sysInit();
int memConfig();
int startVoVirtual();
int startVo();
int bindVo();
int startVdec();
int bindVdec();
void decodeProcess();
void* decodeJpeg(void *pParam);
int stopVdec();
int unbindVdec();
int stopVirtualVo();
int stopVo();
int unbindVo();
void sysExit();
int main(int argc, char* argv[]) {/{{{/
if (HI_SUCCESS != sysInit()) {
return HI_FAILURE;
}
if (HI_SUCCESS != memConfig()) {
return HI_FAILURE;
}
if (HI_SUCCESS != startVoVirtual()) {
return HI_FAILURE;
}
if (HI_SUCCESS != startVo()) {
return HI_FAILURE;
}
if (HI_SUCCESS != bindVo()) {
return HI_FAILURE;
}
if (HI_SUCCESS != startVdec()) {
return HI_FAILURE;
}
if (HI_SUCCESS != bindVdec()) {
return HI_FAILURE;
}
decodeProcess();
if (HI_SUCCESS != stopVdec()) {
return HI_FAILURE;
}
if (HI_SUCCESS != unbindVdec()) {
return HI_FAILURE;
}
if (HI_SUCCESS != stopVirtualVo()) {
return HI_FAILURE;
}
if (HI_SUCCESS != stopVo()) {
return HI_FAILURE;
}
if (HI_SUCCESS != unbindVo()) {
return HI_FAILURE;
}
sysExit();
return HI_SUCCESS;
}/}}}/
int sysInit() {/{{{/
HI_S32 s32Ret;
MPP_SYS_CONF_S stSysConf;
VB_CONF_S stVbConf;
HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
/******************************************
* vb init
*****************************************/
memset(&stVbConf,0,sizeof(VB_CONF_S));
stVbConf.u32MaxPoolCnt = 128;
s32Ret = HI_MPI_VB_SetConf(&stVbConf);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VB_SetConf failed!\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VB_Init();
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VB_Init failed!\n");
return HI_FAILURE;
}
/******************************************
* sys init
*****************************************/
stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;
s32Ret = HI_MPI_SYS_SetConf(&stSysConf);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_SYS_SetConf failed\n");
return HI_FAILURE;
}
s32Ret = HI_MPI_SYS_Init();
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_SYS_Init failed!\n");
return HI_FAILURE;
}
return HI_SUCCESS;
}/}}}/
int memConfig() {/{{{/
HI_S32 s32Ret;
MPP_CHN_S stMppChn;
HI_CHAR* pcMmzName;
int i;
/******************************************
* vdec mem config
*****************************************/
for (i = 0; i < WIN_NUM; i++) {
stMppChn.enModId = HI_ID_VDEC;
stMppChn.s32DevId = 0;
stMppChn.s32ChnId = i;
pcMmzName = (i%2)? "ddr1" : NULL;
s32Ret = HI_MPI_SYS_SetMemConf(&stMppChn, pcMmzName);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_SYS_SetMemConf failed!\n");
return HI_FAILURE;
}
}
/******************************************
* virtual vo mem config
*****************************************/
stMppChn.enModId = HI_ID_VOU;
stMppChn.s32DevId = VO_VIRT;
stMppChn.s32ChnId = 0;
s32Ret = HI_MPI_SYS_SetMemConf(&stMppChn, NULL);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_SYS_SetMemConf failed!\n");
return HI_FAILURE;
}
/******************************************
* vo mem config
*****************************************/
stMppChn.enModId = HI_ID_VOU;
stMppChn.s32DevId = VO_DHD0;
stMppChn.s32ChnId = 0;
s32Ret = HI_MPI_SYS_SetMemConf(&stMppChn, NULL);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_SYS_SetMemConf failed!\n");
return HI_FAILURE;
}
return HI_SUCCESS;
}/}}}/
int startVoVirtual() {/{{{/
HI_S32 s32Ret;
VO_DEV voDev = VO_VIRT;
VO_PUB_ATTR_S stVoPubAttr;
VO_VIDEO_LAYER_ATTR_S stLayerAttr;
VO_CHN_ATTR_S stChnAttr;
HI_U32 u32Width = 1920;
HI_U32 u32Height = 1080;
int i;
VO_CHN chn;
stVoPubAttr.u32BgColor = 0x000000ff;
stVoPubAttr.enIntfType = VO_INTF_BT1120;
stVoPubAttr.enIntfSync = VO_OUTPUT_1080P50;
stVoPubAttr.bDoubleFrame = HI_FALSE;
s32Ret = HI_MPI_VO_SetPubAttr(voDev, &stVoPubAttr);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_SetPubAttr failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_Enable(voDev);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_Enable failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
stLayerAttr.enPixFormat = SAMPLE_PIXEL_FORMAT;
stLayerAttr.u32DispFrmRt = 25;
stLayerAttr.stDispRect.s32X = 0;
stLayerAttr.stDispRect.s32Y = 0;
stLayerAttr.stDispRect.u32Width = u32Width;
stLayerAttr.stDispRect.u32Height = u32Height;
stLayerAttr.stImageSize.u32Width = u32Width;
stLayerAttr.stImageSize.u32Height = u32Height;
s32Ret = HI_MPI_VO_SetVideoLayerAttr(voDev, &stLayerAttr);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_SetVideoLayerAttr failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_EnableVideoLayer(voDev);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_EnableVideoLayer failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
for (i = 0; i < WIN_NUM; i++) {
chn = i;
//stChnAttr.stRect.s32X = (i % 2) * u32Width / 2;
//stChnAttr.stRect.s32Y = (i / 2) * u32Height / 2;
stChnAttr.stRect.s32X = (u32Width / 2 * i / WIN_NUM) / 2 * 2;
stChnAttr.stRect.s32Y = (u32Height / 2 * i / WIN_NUM) / 2 * 2;
stChnAttr.stRect.u32Width = u32Width / 2;
stChnAttr.stRect.u32Height = u32Height / 2;
stChnAttr.u32Priority = i;
stChnAttr.bDeflicker = HI_FALSE;
s32Ret = HI_MPI_VO_SetChnAttr(voDev, chn, &stChnAttr);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VO_SetChnAttr failed with %#x!\n", s32Ret);
}
s32Ret = HI_MPI_VO_EnableChn(voDev, chn);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VO_EnableChn failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
}
return HI_SUCCESS;
}/}}}/
int startVo() {/{{{/
HI_S32 s32Ret;
VO_DEV voDev = VO_DHD0;
VO_PUB_ATTR_S stVoPubAttr;
VO_VIDEO_LAYER_ATTR_S stLayerAttr;
VO_CHN_ATTR_S stChnAttr;
HI_U32 u32Width = 1920;
HI_U32 u32Height = 1080;
stVoPubAttr.u32BgColor = 0x000000ff;
stVoPubAttr.enIntfType = VO_INTF_BT1120;
stVoPubAttr.enIntfSync = VO_OUTPUT_1080P50;
stVoPubAttr.bDoubleFrame = HI_FALSE;
s32Ret = HI_MPI_VO_SetPubAttr(voDev, &stVoPubAttr);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_SetPubAttr failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_Enable(voDev);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_Enable failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
stLayerAttr.enPixFormat = SAMPLE_PIXEL_FORMAT;
stLayerAttr.u32DispFrmRt = 25;
stLayerAttr.stDispRect.s32X = 0;
stLayerAttr.stDispRect.s32Y = 0;
stLayerAttr.stDispRect.u32Width = u32Width;
stLayerAttr.stDispRect.u32Height = u32Height;
stLayerAttr.stImageSize.u32Width = u32Width;
stLayerAttr.stImageSize.u32Height = u32Height;
s32Ret = HI_MPI_VO_SetVideoLayerAttr(voDev, &stLayerAttr);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_SetVideoLayerAttr failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VO_EnableVideoLayer(voDev);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_EnableVideoLayer failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
stChnAttr.stRect.s32X = 0;
stChnAttr.stRect.s32Y = 0;
stChnAttr.stRect.u32Width = u32Width;
stChnAttr.stRect.u32Height = u32Height;
stChnAttr.u32Priority = 0;
stChnAttr.bDeflicker = HI_FALSE;
s32Ret = HI_MPI_VO_SetChnAttr(voDev, 0, &stChnAttr);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VO_SetChnAttr failed with 0x%#x!\n", s32Ret);
}
s32Ret = HI_MPI_VO_EnableChn(voDev, 0);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_VO_EnableChn failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
return HI_SUCCESS;
}/}}}/
int bindVo() {/{{{/
HI_S32 s32Ret;
// virtual vo -> vo
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
stSrcChn.enModId = HI_ID_VOU;
stSrcChn.s32DevId = VO_VIRT;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = HI_ID_VOU;
stDestChn.s32DevId = VO_DHD0;
stDestChn.s32ChnId = 0;
s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_SYS_Bind failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
return HI_SUCCESS;
}/}}}/
int startVdec() {/{{{/
VDEC_CHN_ATTR_S stAttr;
VDEC_PRTCL_PARAM_S stPrtclParam;
HI_S32 s32Ret;
HI_U32 u32Width = 1920;
HI_U32 u32Height = 1080;
HI_S32 s32ChnID = 0;
int i;
memset(&stAttr, 0, sizeof(VDEC_CHN_ATTR_S));
stAttr.enType = PT_JPEG;
stAttr.u32BufSize = u32Width * u32Height;
stAttr.u32Priority = 1;//此处必须大于0
stAttr.u32PicWidth = u32Width;
stAttr.u32PicHeight = u32Height;
stAttr.stVdecJpegAttr.enMode = VIDEO_MODE_FRAME;
for (i = 0; i < WIN_NUM; i++) {
s32ChnID = i;
s32Ret = HI_MPI_VDEC_CreateChn(s32ChnID, &stAttr);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VDEC_CreateChn failed with 0x%#x \n", s32Ret);
return s32Ret;
}
s32Ret = HI_MPI_VDEC_GetPrtclParam(s32ChnID, &stPrtclParam);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VDEC_GetPrtclParam failed errno 0x%#x \n", s32Ret);
return s32Ret;
}
stPrtclParam.s32MaxSpsNum = 21;
stPrtclParam.s32MaxPpsNum = 22;
stPrtclParam.s32MaxSliceNum = 100;
s32Ret = HI_MPI_VDEC_SetPrtclParam(s32ChnID, &stPrtclParam);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VDEC_SetPrtclParam failed errno 0x%#x \n", s32Ret);
return s32Ret;
}
s32Ret = HI_MPI_VDEC_StartRecvStream(s32ChnID);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VDEC_StartRecvStream failed errno 0x%#x \n", s32Ret);
return s32Ret;
}
}
return HI_SUCCESS;
}/}}}/
int bindVdec() {/{{{/
HI_S32 s32Ret;
int i;
// vdec -> virtual vo
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
for (i = 0; i < WIN_NUM; i++) {
stSrcChn.enModId = HI_ID_VDEC;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = i;
stDestChn.enModId = HI_ID_VOU;
stDestChn.s32DevId = VO_VIRT;
stDestChn.s32ChnId = i;
s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_SYS_Bind failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
}
return HI_SUCCESS;
}/}}}/
void decodeProcess() {/{{{/
threadParam.bRun = HI_FALSE;
// create thread
pthread_create(&threadParam.pid, NULL, decodeJpeg, &threadParam);
// join thread
pthread_join(threadParam.pid, NULL);
printf("press two enter to quit!\n");
getchar();
getchar();
}/}}}/
void* decodeJpeg(void pParam) {/{{{*/
//ThreadParam* pThreadParam = (ThreadParam*)pParam;
FILE* fp = NULL;
char szFile[] = “test.jpg”;
VDEC_STREAM_S stStream;
HI_U8 buf[1920*1080*2];
int readLen;
HI_S32 s32Ret;
int i;
fp = fopen(szFile, "rb");
if (NULL == fp) {
SAMPLE_PRT("can't open file %s\n", szFile);
return (void*)(HI_FAILURE);
}
readLen = fread(buf, 1, sizeof(buf), fp);
fclose(fp);
if (readLen <= 0) {
SAMPLE_PRT("can't read file %s\n", szFile);
}
stStream.u64PTS = 0;
stStream.pu8Addr = buf;
stStream.u32Len = readLen;
for (i = 0; i < WIN_NUM; i++) {
s32Ret = HI_MPI_VDEC_SendStream(i, &stStream, HI_IO_BLOCK);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VDEC_SendStream failed with %#x!\n", s32Ret);
return (void*)(HI_FAILURE);
}
}
fflush(stdout);
return (void*)(HI_SUCCESS);
}/}}}/
int stopVdec() {/{{{/
HI_S32 s32Ret;
HI_S32 s32ChnID = 0;
int i;
for (i = 0; i < WIN_NUM; i++) {
s32ChnID = i;
s32Ret = HI_MPI_VDEC_StopRecvStream(s32ChnID);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VDEC_StopRecvStream failed errno 0x%x\n", s32Ret);
return HI_FAILURE;
}
s32Ret = HI_MPI_VDEC_DestroyChn(s32ChnID);
if (HI_SUCCESS != s32Ret) {
SAMPLE_PRT("HI_MPI_VDEC_DestroyChn failed errno 0x%x \n", s32Ret);
return HI_FAILURE;
}
}
return HI_SUCCESS;
}/}}}/
int unbindVdec() {/{{{/
HI_S32 s32Ret;
int i;
// vdec -> virtual vo
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
for (i = 0; i < WIN_NUM; i++) {
stSrcChn.enModId = HI_ID_VDEC;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = i;
stDestChn.enModId = HI_ID_VOU;
stDestChn.s32DevId = VO_VIRT;
stDestChn.s32ChnId = i;
s32Ret = HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_SYS_UnBind failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
}
return HI_SUCCESS;
}/}}}/
int stopVirtualVo() {/{{{/
HI_S32 s32Ret;
int i;
for (i = 0; i < WIN_NUM; i++) {
s32Ret = HI_MPI_VO_DisableChn(VO_VIRT, i);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_DisableChn failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
}
return HI_SUCCESS;
}/}}}/
int stopVo() {/{{{/
HI_S32 s32Ret;
s32Ret = HI_MPI_VO_DisableChn(VO_DHD0, 0);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_VO_DisableChn failed with %#x!\n", s32Ret);
return HI_FAILURE;
}
return HI_SUCCESS;
}/}}}/
int unbindVo() {/{{{/
HI_S32 s32Ret;
VO_DEV voDev = VO_VIRT;
// virtual vo -> vo
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
stSrcChn.enModId = HI_ID_VOU;
stSrcChn.s32DevId = VO_VIRT;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = HI_ID_VOU;
stDestChn.s32DevId = VO_DHD0;
stDestChn.s32ChnId = 0;
s32Ret = HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (s32Ret != HI_SUCCESS) {
SAMPLE_PRT("HI_MPI_SYS_UnBind failed with 0x%#x!\n", s32Ret);
return HI_FAILURE;
}
return HI_SUCCESS;
}/}}}/
void sysExit() {/{{{/
HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
return;
}/}}}/
ifdef __cplusplus
if __cplusplus
}
endif
endif /* End of #ifdef __cplusplus */
// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker: