一.RV1126+OPENCV在視頻中添加LOGO圖像大體流程圖
主要是利用RV1126的視頻流結合OPENCV的API在視頻流里面添加LOGO圖像,換言之就是在RV1126的視頻流里面疊加圖片。大體流程我們來看上圖,要完成這個功能我們需要創建兩個線程(實際上還有初始化過程,這里先忽略了),第一個線程是opencv_vi_logo_handle_thread它主要是獲取VI原始數據并有OPENCV轉換成Mat矩陣然后添加LOGO圖像,并把VI數據發送到VENC編碼器。
第二個線程是get_venc_stream_thread它主要是獲取H264的VENC碼流數據,并且保存到H264文件
二.具體代碼實現
上圖我們已經說了大概的流程圖,這部分我們重點講解代碼的實現
2.1. RV1126模塊初始化并啟動VI工作
2.2VENC模塊初始化
我們之前的很多實戰都沒有使用這個函數開啟視頻流,那是因為很多時候VI模塊我們都與其他模塊綁定了,所以不需要,這里我們并沒有和任何模塊綁定,需要開啟這個
上面代碼是RV1126模塊的初始化,包括VI模塊的初始化(RK_MPI_VI_SetChnAttr)、使能VI模塊(RK_MPI_VI_EnableChn)、VENC模塊的初始化(RK_MPI_VENC_CreateChn)、啟動VI工作(RK_MPI_VI_StartStream)。關于這方面的參數設置,我們就不詳細說了,因為這方面的內容之前的課程已經詳細說過。
2.3創建線程
2.4 創建opencv_vi_logo_handle_thread線程?
上面是opencv_vi_logo_handle_thread的具體實現。
1.我們要通過imread讀取圖片
2.把圖片cvtColor轉換成灰度圖片
(由于VI模塊的圖像格式是NV12,所以我們的圖片必須要以灰度圖的方式進行添加)。
3.調用RK_MPI_SYS_GetMediaBuffer獲取每一幀的VI視頻原始數據
#4.使用OPENCV的API把每一個視頻數據轉換成Mat矩陣
具體的操作是:
Mat rv1126_img_mat = Mat(HEIGHT, WIDTH, CV_8UC1, RK_MPI_MB_GetPtr(mb)),
K_MPI_MB_GetPtr(mb)
?是一個函數調用,返回一個指向內存塊的指針
mb
?是一個媒體緩沖區對象(Media Buffer)
這個構造函數直接使用外部內存,而不是為矩陣分配新內存
函數原型:
Mat(int rows, int cols, int type, void* data, size_t step = AUTO_STEP);
參數含義:
rows:矩陣的行數(HEIGHT)
cols:矩陣的列數(WIDTH)
type:矩陣的數據類型(CV_8UC1)
data:指向數據的指針(RK_MPI_MB_GetPtr (mb))
step:每行數據的字節數(默認為 AUTO_STEP,自動計算)
通過Mat的構造器,就可以把RV1126的VI視頻數據轉換成Mat,轉換成Mat之后,我們就需要對Mat進行圖層疊加操作。
5.Mat疊加操作
需要分兩步
第一步:先創建一個感興趣區域
Mat rv1126_img_mat_roi=rv1126_img_mat(Rect(100,100, logo_img.cols, logo_img.rows)),
這個感性區域的長寬要與logo圖片的一致
第二步:利用copyTo函數把讀取的圖片拷貝到感興趣區域rv1126_img_mat_roi
?具體代碼是logo_img.copyTo(rv1126_img_mat_roi)。
6.要把RV1126疊加過后的視頻VI數據發送到H264的VENC編碼器
調用的API是RK_MPI_SYS_SendMediaBuffer。
2.4?創建get_venc_stream_thread線程?
上面是get_venc_stream_thread的具體實現,在這個線程里面要通過RK_MPI_SYS_GetMediaBuffer獲取每一幀H264的編碼數據,然后用fwrite寫入。
2.5?輸出結果:
經過上面的編碼后,我們來看看輸出的H264文件。可以看到這個H264文件,嵌入了JPG圖片。這個效果就實現了用OPENCV圖片疊加的功能對RV1126的視頻流進行圖片LOGO的添加
?
int ret;VI_CHN_ATTR_S vi_chn_attr;vi_chn_attr.pcVideoNode = CAMERA_PATH; // Pathvi_chn_attr.u32Width = WIDTH; // Widthvi_chn_attr.u32Height = HEIGHT; // Heightvi_chn_attr.enPixFmt = IMAGE_TYPE_NV12; // ImageTypevi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP; // BufTypevi_chn_attr.u32BufCnt = 3; // Cntvi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL; // Moderet = RK_MPI_VI_SetChnAttr(CAMERA_ID, CAMERA_CHN, &vi_chn_attr);if (ret){printf("Vi Set Attr Failed.....\n");return 0;}else{printf("Vi Set Attr Success.....\n");}ret = RK_MPI_VI_EnableChn(CAMERA_ID, CAMERA_CHN);if (ret){printf("Vi Enable Attr Failed.....\n");return 0;}else{printf("Vi Enable Attr Success.....\n");}
VENC_CHN_ATTR_S venc_chn_attr;memset(&venc_chn_attr, 0, sizeof(VENC_CHN_ATTR_S));venc_chn_attr.stVencAttr.u32PicWidth = WIDTH;venc_chn_attr.stVencAttr.u32PicHeight = HEIGHT;venc_chn_attr.stVencAttr.u32VirWidth = WIDTH;venc_chn_attr.stVencAttr.u32VirHeight = HEIGHT;venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;venc_chn_attr.stVencAttr.u32Profile = 66;venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25;venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = WIDTH * HEIGHT * 3;venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;ret = RK_MPI_VENC_CreateChn(VENC_CHN, &venc_chn_attr); if (ret){printf("ERROR: Create venc failed!\n");exit(0);}
三.小結
在做這個功能的時候遇到了挺多問題,比例提示什么gop數據過大啥的,然后一直在重復檢查修改參數,但是還是不行,最后弄了一晚上也找不出哪里有問題。今天早上重新來弄的時候,先用了其他功能的代碼在板子上運行,說vi模塊無法打開,這時候才意識到是板子連接出現了問題,應該是網線接口不緊的問題。
所以遇到問題,首先檢查代碼是沒問題的,如果檢查了代碼,代碼的配置的每一步都與自己所用所學對得上,這時候就不要一股腦的找代碼問題了,雖然報錯是說代碼哪里配置錯誤,但也有可能是硬件設備連接等問題的錯誤導致代碼報錯。