前言
上一篇已經將himpp套入qt的基礎上進行開發。那麼qt中拿到frame則是很關鍵的交互,這是qt與海思可能編解碼交叉開發的關鍵步驟。
因爲直接配置sample的vi比較麻煩,確實是困難的,其實就是配置驅動,所以我們只能從開發板的demo入手,去在相等條件下探測可能的留,從vpss中拿取後,進行軟編碼。
當然,如果不用qt還有一種方式,也就是大量開發海思人員使用的方式,是基於sample寫一個編碼程序,然後使用本地socket交互,其實絕大部分海思開發者都是這樣開發的,但是他們不涉及與qt的深入交互。
需要移植ffmpeg到海思平臺,可參考博文《FFmpeg開發筆記(十):ffmpeg在ubuntu上的交叉編譯移植到海思HI35xx平臺》。
從vpss中獲取一幀圖像,如下圖:
(原本整理了一大半自己的習慣格式,後續海思看多了,覺得海思文檔也還行,就是爭對性的開發,無用信息有點多,所以此處還是用海思的文檔,但是隻提取涉及的部分,海思文檔是個龐大的體系,需要動手,光看是很難理解的)。
用戶從通道獲取一幀處理完成的圖像,必須與HI_MPI_VPSS_ReleaseChnFrame()配對使用。
HI_S32 HI_MPI_VPSS_GetChnFrame(VPSS_GRP VpssGrp,
VPSS_CHN VpssChn,
VIDEO_FRAME_INFO_S *pstVideoFrame,
HI_S32 s32MilliSec);
- 參數一:VpssGrou,通道組號,海思芯片通道號,
取值[0, VPSS_MAX_GRP_NUM]; - 參數二:VpssChn,通道號,通道組下的通道號,
取值[0, VPSS_MAX_CHN_NUM]; - 參數三:pstVideoFrame,幀數據的結構體,要取的數據就在這個幀裏面,這
是很關鍵的結構體,稍後是會深入講解的重點; - 參數四:s32MilliSec,阻塞時間,跟其他阻塞有點區別,-1爲阻塞,0爲直
接獲取,其他整數位等待的超時時間。
釋放之前通過HI_MPI_VPSS_GetChnFrame獲取獲取的圖像。
HI_S32 HI_MPI_VPSS_ReleaseChnFrame (VPSS_GRP VpssGrp,
VPSS_CHN VpssChn,
const VIDEO_FRAME_INFO_S *pstVideoFrame);
- 參數一:VpssGrou,通道組號,海思芯片通道號,
取值[0, VPSS_MAX_GRP_NUM],之前獲取使用的是哪個就哪個; - 參數二:VpssChn,通道號,通道組下的通道號,
取值[0, VPSS_MAX_CHN_NUM];之前獲取使用的是哪個就哪個; - 參數三:pstVideoFrame,幀數據的結構體,要取的數據就在這個幀裏面,這
是很關鍵的結構體,稍後是會深入講解的重點;
typedef struct hiVIDEO_FRAME_INFO_S
{
VIDEO_FRAME_S stVFrame; // 視頻圖像幀
HI_U32 u32PoolId; // 視頻緩存池ID
MOD_ID_E enModId; // 當前幀數據是由哪一個硬件邏輯模塊寫出的
} VIDEO_FRAME_INFO_S;
typedef struct hiVIDEO_FRAME_S
{
HI_U32 u32Width; // 圖像寬度
HI_U32 u32Height; // 圖像高度
VIDEO_FIELD_E enField; // 幀場模式
PIXEL_FORMAT_E enPixelFormat; // 視頻圖像像素格式
VIDEO_FORMAT_E enVideoFormat; // 視頻圖像格式
COMPRESS_MODE_E enCompressMode; // 視頻壓縮模式
DYNAMIC_RANGE_E enDynamicRange; // 動態範圍
COLOR_GAMUT_E enColorGamut; // 色域範圍
HI_U32 u32HeaderStride[3]; // 圖像壓縮頭跨距
HI_U32 u32Stride[3]; // 圖像數據跨距
HI_U32 u32ExtStride[3]; // 10bit數據位寬的圖像,部分格式分開存
HI_U64 u64HeaderPhyAddr[3]; // 壓縮頭物理地址
HI_U64 u64HeaderVirAddr[3]; // 壓縮頭虛擬地址,內核態虛擬地址
HI_U64 u64PhyAddr[3]; // 圖像數據物理地址
HI_U64 u64VirAddr[3]; // 圖像數據虛擬地址,內核態虛擬地址
HI_U64 u64ExtPhyAddr[3]; // 10bit數據位寬度的圖像,部分格式分開存
HI_U64 u64ExtVirAddr[3]; // 10bit數據位寬度的圖像,部分格式分開存
HI_S16 s16OffsetTop; // 圖像頂部剪裁寬度
HI_S16 s16OffsetBottom; // 圖像底部剪裁寬度
HI_S16 s16OffsetLeft; // 圖像左側剪裁寬度
HI_S16 s16OffsetRight; // 圖像右側剪裁寬度
HI_U32 u32MaxLuminance; // 顯示圖像的最大亮度
HI_U32 u32MinLuminance; // 顯示圖像的最小亮度
HI_U32 u32TimeRef; // 圖像幀序列號
HI_U64 u64PTS; // 圖像時間戳
HI_U64 u64PrivateData; // 私有數據
HI_U32 u32FrameFlag; // 當前幀的標記,使用FRAME_FLAG_E標記
VIDEO_SUPPLEMENT_S stSupplement; // 圖像的補充信息
} VIDEO_FRAME_S;
void HiMppManager::testGetVPssFrame()
{
VIDEO_FRAME_INFO_S videoFrameInfoS;
#if 0
// 搜索開開發板用了哪個通道(應該只有2個攝像頭,綁定了vpss)
// 結果:探測到開發板在snap抓圖模式下在通道組0通道0下有圖片
for(int groupIndex = 0; groupIndex < VPSS_MAX_GRP_NUM; groupIndex++)
{
for(int channelIndex = 0; channelIndex < VPSS_MAX_CHN_NUM; channelIndex++)
{
HI_S32 s32MilliSec = 100;
HI_S32 ret = HI_MPI_VPSS_GetChnFrame(groupIndex, channelIndex, &videoFrameInfoS, s32MilliSec);
if(ret == 0)
{
LOG << QString("Succeed to get HI_MPI_VPSS_GetChnFrame(%1, %2, &videoFrameInfoS, %3)")
.arg(groupIndex)
.arg(channelIndex)
.arg(s32MilliSec);
break;
#if 0
}else{
LOG << QString("Failed to get HI_MPI_VPSS_GetChnFrame(%1, %2, &videoFrameInfoS, %3): %4")
.arg(groupIndex)
.arg(channelIndex)
.arg(s32MilliSec)
.arg(ret);
#endif
}
}
}
#endif
while(HI_MPI_VPSS_GetChnFrame(0, 0, &videoFrameInfoS, -1) == 0)
{
LOG << "get frame";
LOG << videoFrameInfoS.stVFrame.enPixelFormat
<< "PIXEL_FORMAT_YVU_PLANAR_420:" << (int)PIXEL_FORMAT_YVU_PLANAR_420
<< "PIXEL_FORMAT_YVU_SEMIPLANAR_420:" << (int)PIXEL_FORMAT_YVU_SEMIPLANAR_420;
LOG << videoFrameInfoS.stVFrame.enVideoFormat;
HI_MPI_VPSS_ReleaseChnFrame(0, 0, &videoFrameInfoS);
LOG << "release frame"; }
}
使用海思sdk獲取圖像後,多次獲取後,大概20次左右就獲取失敗了。
海思獲取圖像後,需要釋放,是佔用了緩存區。
海思的HI_MPI_VPSS_GetChanFrame與Hi_MPI_VPSS_ReleaseChnFrame要成對使用。