01介紹
Xilinx提供超低延時編解碼方案,并提供了全套軟件。MPSoC Video Codec Unit提供了詳細(xì)說明。其中的底層應(yīng)用軟件是VCU Control-Software(Ctrl-SW)。
本文主要說明為Ctrl-SW增加輸出NV12視頻的功能。
1.1. VCU輸入和輸出格式
Video Codec Unit(VCU) 輸入和輸出都是是NV12/NV16格式的視頻,Y分量存放在一塊連續(xù)內(nèi)存區(qū),UV分量交替存放在Y分量后面的連續(xù)內(nèi)存。具體信息,可以參考VCU Product Guide中的“Source Frame Format”和“Memory Format”。
Ctrl-SW的輸入文件最好是NV12/NV16格式的視頻文件,由于不需要做格式轉(zhuǎn)換,幀率(FPS)最高。但是Ctrl-SW的輸出文件缺省是圖像真實(shí)分辨率的I420/I422的文件,其中的Y、U、V分量,各自存在一塊連續(xù)內(nèi)存,UV分量沒有像NV12/NV16格式的視頻交替在一起。可以使用FFMPeg等工具,將I420的文件,轉(zhuǎn)換成NV12/NV16格式的文件。
1.2. VCU內(nèi)存的高度和寬度要求
對于視頻的輸入內(nèi)存區(qū),VCU要求高和寬都按32向上對齊。對于1920x1080分辨率,輸入的buffer大小至少是1920x1088字節(jié);對于3840x2160分辨率,輸入的buffer大小至少是3840x2176字節(jié)。
對于視頻的輸出內(nèi)存區(qū),VCU要求寬以256地址對齊,高以64地址對齊。對于1920x1080分辨率,輸出的buffer大小是2048x1088字節(jié);對于3840x2160分辨率,輸出的buffer大小是3840x2176字節(jié)。
1.3. VCU內(nèi)存的pitch
視頻數(shù)據(jù)在內(nèi)存區(qū)中存放時,兩行之間的數(shù)據(jù)可以有間隔。對于每個像素的Y分量用8-bit表示的圖像,每個像素的Y分量對應(yīng)內(nèi)存的一個字節(jié),圖像Y分量的每一行對應(yīng)的內(nèi)存大小就是其寬度代表的字節(jié)數(shù)。比如1920x1080,每一行圖像的Y分量需要1920字節(jié)內(nèi)存。如果以2048字節(jié)來存儲一行1920x1080的圖像數(shù)據(jù),則在前面存放圖像數(shù)據(jù),后面的數(shù)據(jù)被VCU忽略。也可以參考PG252的“Figure 7: Frame Buffer Pitch”。
02顯示YUV文件 2.1. 工具RAW yuv player
Github上的RAW yuv player 能顯示YUV文件,它的舊版本Sourceforge RAW yuv player在Sourceforge上。RAW yuv player的菜單“Colour”下,有各種顏色格式,菜單“Size”下有各種分辨率;菜單“Zoom”下可以選擇圖像縮放比例。
RAW yuv player的YUV420(YV12)格式,就是I420格式,可以顯示Ctrl-SW缺省輸出的YUV文件。RAW yuv player的NV12格式,也是Ctrl-SW的NV12格式,可以顯示修改后的Ctrl-SW輸出的YUV NV12文件。
2.1.1. 技巧
各種YUV文件,第一片數(shù)據(jù)一般都是分量Y。如果發(fā)現(xiàn)YUV文件的顯示有問題,可以設(shè)置好分辨率,在菜單“Colour”下選擇“Y”,只看其中的分量Y,當(dāng)成黑白圖片看。如果黑白圖片是正常的,說明分量Y是對的。
2.2. hexdump
如果圖片內(nèi)容不對,可以使用二進(jìn)制比較工具比較錯誤圖片和正確圖片,比如Beyond Compare。比較的時候,注意取消對齊設(shè)置。
如果沒有二進(jìn)制比較工具,可以使用hexdump把YUV文件按HEX格式轉(zhuǎn)換為文本文件,再用文本比較工具,比如kdiff3、meld進(jìn)行比較。hexdump輸出時,會輸出星號“*”代替一樣的行;多個重復(fù)行,也只輸出一個星號。為hexdump加上“-v”選項(xiàng),則會輸出所有數(shù)據(jù)。
xilinx@XSZHANKF$ hexdump -x test_1080p_h264.264.1f.i420.1920x1080.yuv 》 test_1080p_h264.264.1f.i420.1920x1080.yuv.hex
xilinx@XSZHANKF$ hexdump -v -x test_1080p_h264.264.1f.i420.1920x1080.yuv 》 test_1080p_h264.264.1f.i420.1920x1080.yuv.v.hex
03輸出NV12/NV16格式文件
如果Ctrl-SW能輸出NV12/NV16格式的文件,Ctrl-SW就能直接對自己的文件進(jìn)行編碼,測試時更加方便。
經(jīng)過研究,在Ctrl-SW 2020.2里,實(shí)現(xiàn)了輸出NV12/NV16格式文件的功能。
3.1. 選項(xiàng)
Ctrl-SW里有三種分辨率,分別是圖像的真實(shí)分辨率,Meta數(shù)據(jù)分辨率,內(nèi)存塊(buffer)分辨率。
圖像的真實(shí)分辨率,是真實(shí)顯示的分辨率。
在Ctrl-SW里,為YUV數(shù)據(jù)分配內(nèi)存時,根據(jù)圖像分辨率,并按對齊要求像是對齊圖像分辨率后,得到Y(jié)UV數(shù)據(jù)的內(nèi)存塊大小,這就是對應(yīng)的內(nèi)存塊(buffer)分辨率。對于解碼,1920x1080分辨率的內(nèi)存塊是2048x1088字節(jié);3840x2160分辨率的buffer是3840x2176字節(jié)。
另外分配內(nèi)存后,每個內(nèi)存塊有一個對應(yīng)的Meta數(shù)據(jù),保存YUV數(shù)據(jù)的分辨率。Meta數(shù)據(jù)分辨率可能比內(nèi)存塊分辨率低。1920x1080分辨率的Meta數(shù)據(jù)分辨率是2048x1088;而3840x2160分辨率的Meta數(shù)據(jù)分辨率卻是3840x2160,在高度上并沒有像1080p時向上對齊。
所以輸出NV12/NV16的視頻時,也有多種組合。為了測試方便,實(shí)現(xiàn)了輸出各種組合的NV12/NV16的視頻。
如果使用選項(xiàng)“-yuv-nvx”,按得到的Meta數(shù)據(jù)的分辨率信息,從Y和UV分量的地址,逐行寫入到文件。
如果使用選項(xiàng)“-yuv-nvx-1buffer”,行依照pitch長度,高使用分辨率的高度并向上按64字節(jié)對齊,計算出YUV整個的內(nèi)存區(qū)大小,相當(dāng)于內(nèi)存塊(buffer)分辨率,一次性寫入到文件。
如果使用選項(xiàng)“-yuv-nvx-stride”,行依照pitch長度,高使用分辨率的高度,從Y和UV分量的地址,逐行輸出。相當(dāng)于寬按內(nèi)存塊(buffer)分辨率,高按Meta數(shù)據(jù)分辨率輸出。
如果使用選項(xiàng)“-yuv-nvx-dispay”,按得到的顯示分辨率信息,從Y和UV分量的地址,逐行輸出。
另外,還附帶增加了輸出YUV文件時跳幀、抽幀的功能。如果使用選項(xiàng)“--yuv-skip-num”,則前面的指定數(shù)量的幀不會被輸出;比如指定5,前面的5幀不會被寫入到Y(jié)UV文件。如果使用選項(xiàng)“--yuv-skip-interval”,則指定數(shù)字的倍數(shù)序號的幀,才會被輸出;比如指定數(shù)字3,則只有序號是3的倍數(shù)的幀才會被寫入到Y(jié)UV文件。
04代碼
在Ctrl-SW 2020.2里,添加如下代碼后,可以直接輸出NV12/NV16格式的文件。
下面是增加的全局變量定義。
int gi_yuv_output_skip_frame_num=0;
int gi_yuv_output_skip_frame_interval=0;
int gi_yuv_output_nvx_flag=0;
int gi_yuv_output_nvx_1buffer_flag=0;
int gi_yuv_output_nvx_stride_flag=0;
int gi_yuv_output_nvx_dispay_flag=0;
int gi_yuv_output_dispay_width=0;
int gi_yuv_output_dispay_height=0;
下面是增加的ctrlsw_decoder的命令行選項(xiàng)。
opt.addInt(“--yuv-skip-num”, &gi_yuv_output_skip_frame_num, “Skip frame number before writing YUV file.”);
opt.addInt(“--yuv-skip-interval”, &gi_yuv_output_skip_frame_interval, “Interval frame number when writing YUV file.”);
opt.addFlag(“-yuv-nvx”, &gi_yuv_output_nvx_flag, “Output NV12/NV16 YUV file.”, 1);
opt.addFlag(“-yuv-nvx-1buffer”, &gi_yuv_output_nvx_1buffer_flag, “Output one continuous NV12/NV16 buffer to YUV file.”, 1);
opt.addFlag(“-yuv-nvx-stride”, &gi_yuv_output_nvx_stride_flag, “Output NV12/NV16 YUV file with VCU round-up padding/stride.”, 1);
opt.addFlag(“-yuv-nvx-dispay”, &gi_yuv_output_nvx_dispay_flag, “Output NV12/NV16 YUV file with display width.”, 1);
下面是在UncompressedOutputWriter::ProcessFrame()內(nèi)部增加的判斷是否輸出NV12/NV16格式的視頻文件的判斷代碼。
if( gi_yuv_output_skip_frame_num_local 《 gi_yuv_output_skip_frame_num )
{
return;
}
if( 0 == (gi_yuv_output_skip_frame_num_local%gi_yuv_output_skip_frame_interval) )
{
return;
}
if( ( 1 == gi_yuv_output_nvx_flag ) || ( 1 == gi_yuv_output_nvx_1buffer_flag )
|| ( 1 == gi_yuv_output_nvx_stride_flag ) || ( 1 == gi_yuv_output_nvx_dispay_flag ) )
{
ProcessFrameNVx( tRecBuf, info, iBdOut);
return;
}
下面是顯示視頻參數(shù)的代碼,用于調(diào)試,可以被屏蔽掉。
void UncompressedOutputWriter::ShowVideoInfo(AL_TBuffer& tRecBuf, AL_TInfoDecode info, int iBdOut)
{
// only print one time.
static int i_call_time=0;
if( 0 != i_call_time )
{
return;
}
i_call_time++;
iBdOut = convertBitDepthToEven(iBdOut);
auto const iSizePix = (iBdOut + 7) 》》 3;
TFourCC tRecFourCC = AL_PixMapBuffer_GetFourCC(&tRecBuf);
printFourCC( tRecFourCC, “Recorded frame buffer”, __func__, __LINE__ );
int sx = 1, sy = 1;
AL_GetSubsampling(tRecFourCC, &sx, &sy);
int iPitchSrcY = AL_PixMapBuffer_GetPlanePitch(&tRecBuf, AL_PLANE_Y);
int iPitchSrcUV = AL_PixMapBuffer_GetPlanePitch(&tRecBuf, AL_PLANE_UV);
if( iPitchSrcY != iPitchSrcUV )
{
LogInfo(“YUV Y Plane pitch: %d does not equal to UV Plane pitch:%d at %s:%d.
”,
iPitchSrcY, iPitchSrcUV, __func__, __LINE__ );
}
LogVerbose(“YUV Y Plane pitch:%d, UV Plane pitch:%d at %s:%d.
”, iPitchSrcY, iPitchSrcUV, __func__, __LINE__ );
AL_TDimension tYuvDim = AL_PixMapBuffer_GetDimension(&tRecBuf);
int const iRoundUpYWidth = RoundUp(tYuvDim.iWidth, 256);
if( iPitchSrcY != iRoundUpYWidth )
{
LogInfo(“YUV Y Plane pitch %d does not equal to Y Round-up Width:%d at %s:%d.
”,
iPitchSrcY, iRoundUpYWidth, __func__, __LINE__ );
}
// For 1920x1080, YuvDim.iHeight is always rounded up, it is 1920x1088.
// For 3840x2160, YuvDim.iHeight is not rounded up, it is 3840x2160.
int const iRoundUpHeight = RoundUp(tYuvDim.iHeight, 64);
if( tYuvDim.iHeight != iRoundUpHeight )
{
// For 4K video, tYuvDim.iHeight(2160) does not equal to Round-up Height(2176)
LogInfo(“YUV Height: %d does not equal to Round-up Height:%d at %s:%d.
”,
tYuvDim.iHeight, iRoundUpHeight, __func__, __LINE__ );
}
//int const iNumPix = tYuvDim.iHeight * tYuvDim.iWidth; // For I420 without extra padding bytes.
const AL_EChromaMode stRecChromaMode = AL_GetChromaMode(tRecFourCC);
//int const iNumPixC = AL_GetChromaMode(tRecFourCC) == AL_CHROMA_MONO ? 0 : ((tYuvDim.iWidth + sx - 1) / sx) * ((tYuvDim.iHeight + sy - 1) / sy);
int const iLineNumPixC = (stRecChromaMode == AL_CHROMA_MONO) ? 0 : ((tYuvDim.iWidth + sx - 1) / sx) ;
int const iRoundUpLineNumPixC = (stRecChromaMode == AL_CHROMA_MONO) ? 0 : ((iPitchSrcUV + sx - 1) / sx) ;
// Get display in sResolutionFound()
int const iNumPix = tYuvDim.iHeight * tYuvDim.iWidth;
int const iRoundUpNumPix = iRoundUpHeight * iPitchSrcY;
int const iNumPixC = iLineNumPixC * ((tYuvDim.iHeight + sy - 1) / sy);
int const iRoundUpNumPixC = iRoundUpLineNumPixC * ((iRoundUpHeight + sy - 1) / sy);
int i_y_buffer_size = iRoundUpNumPix * iSizePix;
int i_uv_buffer_size = 2 * iRoundUpNumPixC * iSizePix;
int i_yuv_buffer_size = i_y_buffer_size + i_uv_buffer_size;
LogVerbose(“Subsampling sx:%d, sy:%d at %s:%d.
”, sx, sy, __func__, __LINE__ );
LogVerbose(“Height:%d, Width:%d at %s:%d.
”, tYuvDim.iHeight, tYuvDim.iWidth, __func__, __LINE__ );
LogVerbose(“Roundup Height:%d, Width:%d at %s:%d.
”, iRoundUpHeight, iPitchSrcY, __func__, __LINE__ );
LogVerbose(“iNumPix:%d, iLineNumPixC:%d, iNumPixC:%d, iSizePix:%d at %s:%d.
”, iNumPix, iLineNumPixC, iNumPixC, iSizePix, __func__, __LINE__ );
LogVerbose(“iRoundUpNumPix:%d, iRoundUpLineNumPixC:%d, iRoundUpNumPixC:%d at %s:%d.
”, iRoundUpNumPix, iRoundUpLineNumPixC, iRoundUpNumPixC, __func__, __LINE__ );
LogVerbose(“NV12/NV16 YUV Plane Y: %d, UV: %d YUV: %d bytes at %s:%d.
”,
i_y_buffer_size, i_uv_buffer_size, i_yuv_buffer_size, __func__, __LINE__ );
uint8_t* p_buff_y_plane = AL_PixMapBuffer_GetPlaneAddress(&tRecBuf, AL_PLANE_Y);
uint8_t* p_buff_uv_plane = AL_PixMapBuffer_GetPlaneAddress(&tRecBuf, AL_PLANE_UV);
LogVerbose(“NV12/NV16 YUV Y Plane address: %p, UV Plane address: %p at %s:%d.
”,
p_buff_y_plane, p_buff_uv_plane, __func__, __LINE__ );
int const iOffsetY_UV_Plane = ( (unsigned long long)p_buff_uv_plane - (unsigned long long)p_buff_y_plane);
if( i_y_buffer_size != iOffsetY_UV_Plane )
{
LogInfo(“YUV Y Plane sieze: %d does not equal to offset: %d between Y/UV plane at %s:%d.
”,
i_y_buffer_size, iOffsetY_UV_Plane, __func__, __LINE__ );
}
}
下面是增加的輸出NV12/NV16格式的視頻文件的主體代碼。
void UncompressedOutputWriter::ProcessFrameNVx(AL_TBuffer& tRecBuf, AL_TInfoDecode info, int iBdOut)
{
if(?。╕uvFile.is_open() || CertCrcFile.is_open()))
return;
static int i_call_time=0;
i_call_time++;
iBdOut = convertBitDepthToEven(iBdOut);
auto const iSizePix = (iBdOut + 7) 》》 3;
TFourCC tRecFourCC = AL_PixMapBuffer_GetFourCC(&tRecBuf);
#if 1
ShowVideoInfo( tRecBuf, info, iBdOut);
#endif
int sx = 1, sy = 1;
AL_GetSubsampling(tRecFourCC, &sx, &sy);
int iPitchSrcY = AL_PixMapBuffer_GetPlanePitch(&tRecBuf, AL_PLANE_Y);
int iPitchSrcUV = AL_PixMapBuffer_GetPlanePitch(&tRecBuf, AL_PLANE_UV);
AL_TDimension tYuvDim = AL_PixMapBuffer_GetDimension(&tRecBuf);
const AL_EChromaModestRecChromaMode = AL_GetChromaMode(tRecFourCC);
int const iLineNumPixC = (stRecChromaMode == AL_CHROMA_MONO) ? 0 : ((tYuvDim.iWidth + sx - 1) / sx) ;
uint8_t* p_buff_y_plane = AL_PixMapBuffer_GetPlaneAddress(&tRecBuf, AL_PLANE_Y);
LogVerbose(“NV12/NV16 YUV data Y Plane address: %p at %s:%d.
”, p_buff_y_plane, __func__, __LINE__ );
LogVerbose(“YUV data with VCU padding Height:%d, Y Width:%d, UV Width:%d at %s:%d.
”,
tYuvDim.iHeight, iPitchSrcY, iPitchSrcUV, __func__, __LINE__ );
if( 1 == gi_yuv_output_nvx_1buffer_flag )
{
// For 1920x1080, YuvDim.iHeight is always rounded up, it is 1920x1088.
// For 3840x2160, YuvDim.iHeight is not rounded up, it is 3840x2160.
int const iWriteHeight = RoundUp(tYuvDim.iHeight, 64);
//int const iNumPix = tYuvDim.iHeight * tYuvDim.iWidth; // For I420 without extra padding bytes.
int const iRoundUpNumPix = iWriteHeight * iPitchSrcY; // For NV12/NV16 with extra padding bytes.
//int const iNumPixC = AL_GetChromaMode(tRecFourCC) == AL_CHROMA_MONO ? 0 : ((tYuvDim.iWidth + sx - 1) / sx) * ((tYuvDim.iHeight + sy - 1) / sy);
int const iRoundUpLineNumPixC = (stRecChromaMode == AL_CHROMA_MONO) ? 0 : ((iPitchSrcUV + sx - 1) / sx) ;
int const iRoundUpNumPixC = iRoundUpLineNumPixC * ((iWriteHeight + sy - 1) / sy);
int i_y_buffer_size = iRoundUpNumPix * iSizePix;
int i_uv_buffer_size = 2 * iRoundUpNumPixC * iSizePix;
int i_yuv_buffer_size = i_y_buffer_size + i_uv_buffer_size;
// Display YUV file: 1920x1080: 2048x1088; 3840x2160: 3840 x 2176
if( 1 == i_call_time )
{
LogInfo(“Diplay NV12/NV16 YUV file of one continuous buffer with Height:%d, Y Width:%d, UV Width:%d at %s:%d.
”,
iWriteHeight, iPitchSrcY, iPitchSrcUV, __func__, __LINE__ );
}
YuvFile.write((const char*)p_buff_y_plane, i_yuv_buffer_size);
}
else
{
int iWriteHeight;
int iWriteYWidth;
int iWriteUVWidth;
// For 1920x1080, YuvDim.iHeight is always rounded up, it is 1920x1088.
// For 3840x2160, YuvDim.iHeight is not rounded up, it is 3840x2160.
if( 1 == gi_yuv_output_nvx_stride_flag )
{
iWriteHeight = tYuvDim.iHeight;
iWriteYWidth = iPitchSrcY;
iWriteUVWidth = 2 * ((iPitchSrcUV + sx - 1) / sx);
LogVerbose(“Diplay NV12/NV16 YUV file of stride with Height:%d, Y Width:%d, UV Width:%d at %s:%d.
”,
tYuvDim.iHeight, iPitchSrcY, iPitchSrcUV, __func__, __LINE__ );
}
else
{
if( 0 != gi_yuv_output_dispay_height )
{
// Display YUV file: 1920x1080: 1920x1080.
iWriteHeight = gi_yuv_output_dispay_height;
}
else
{
// Display YUV file: 1920x1080: 1920x1088.
iWriteHeight =tYuvDim.iHeight;
}
if( 0 != gi_yuv_output_dispay_width )
{
iWriteYWidth = gi_yuv_output_dispay_width;
iWriteUVWidth = 2 * ((gi_yuv_output_dispay_width + sx - 1) / sx);
}
else
{
iWriteYWidth =tYuvDim.iWidth;
iWriteUVWidth = 2 * iLineNumPixC;
}
}
if( 1 == i_call_time )
{
LogInfo(“Diplay NV12/NV16 YUV file with Height: %d, Y Width: %d, UV Width: %d at %s:%d.
”,
iWriteHeight, iWriteYWidth, iWriteUVWidth, __func__, __LINE__ );
}
// two writes, skipp padding bytes between Y plane and UV plane.
uint8_t* p_buff_y=p_buff_y_plane;
int iYBytes=0;
for( int i=0; i《iWriteHeight; i++ )
{
// Write each line of Y plane, and skipp padding bytes between each line.
YuvFile.write((const char*)p_buff_y, iWriteYWidth);
p_buff_y = p_buff_y + iPitchSrcY;
iYBytes+=iWriteYWidth;
}
uint8_t* p_buff_uv_plane = AL_PixMapBuffer_GetPlaneAddress(&tRecBuf, AL_PLANE_UV);
LogVerbose(“NV12/NV16 YUV data UV Plane address: %p at %s:%d.
”, p_buff_uv_plane, __func__, __LINE__ );
uint8_t* p_buff_uv=p_buff_uv_plane;
int iUVBytes=0;
for( int i=0; i《(iWriteHeight/sy); i++ )
{
// Write each line of UV plane, and skipp padding bytes between each line.
YuvFile.write((const char*)p_buff_uv, iWriteUVWidth);
p_buff_uv = p_buff_uv + iPitchSrcUV;
iUVBytes+=iWriteUVWidth;
}
LogVerbose(“write NV12/NV16 YUV data Y: %d bytes, UV: %d bytes at %s:%d.
”,
iYBytes, iUVBytes, __func__, __LINE__ );
}
}
055. 測試
在開發(fā)過程中,測試了1920x1080、3840x2160分辨率的NV12圖像。
5.1. 1080分辨率
1920x1080分辨率時,以內(nèi)存塊分辨率輸出,分辨率是1920x1088;以pitch長度和分辨率高度向上對齊后輸出,分辨率是2048x1088;以pitch長度和Meta分辨率的高度輸出,分辨率是2048x1088;以顯示分辨率輸出,分辨率是1920x1080。如果沒有特殊說明,圖像都是NV12格式的,也是以NV12格式顯示。
查看YUV文件時,必須設(shè)置正確的分辨率和格式,否則數(shù)據(jù)顯示會混亂。
以分辨率1920x1080顯示選項(xiàng)“-yuv-nvx-dispay”輸出的圖片,結(jié)果正常。
以分辨率2048x1088顯示選項(xiàng)“-yuv-nvx-1buffer”輸出的圖片,結(jié)果正常。右邊有一塊紅色圖像,是因?yàn)閷?yīng)的內(nèi)存區(qū)沒有真實(shí)圖像數(shù)據(jù)。
以分辨率2048x1088顯示選項(xiàng)“-yuv-nvx-stride”輸出的圖片,結(jié)果正常。右邊也有一塊紅色圖像。
5.1.1. 分辨率顯示格式錯誤的現(xiàn)象
以分辨率1920x1080顯示分辨率2048x1088圖片,圖像混亂了。因?yàn)閷?shí)際圖像數(shù)據(jù)每行2048字節(jié),顯示時每行1920字節(jié),所以讀出的數(shù)據(jù)混亂了,上面的連續(xù)紅色塊變成了小塊,分布到了圖像各處。
以分辨率2048x1080顯示分辨率2048x1088圖片,最上面有綠條,因?yàn)榘?行的Y分量數(shù)據(jù)當(dāng)成了UV分量數(shù)據(jù)。這8行的實(shí)際圖像是黑色的。
5.2. 3840x2160分辨率
3840x2160分辨率時,以pitch長度和分辨率高度向上對齊后的分辨率輸出,分辨率是3840x2176;其它模式輸出,分辨率都是3840x2160。
以分辨率3840x2160顯示選項(xiàng)“-yuv-nvx-dispay”輸出的圖片,結(jié)果正常。
以分辨率3840x2176顯示選項(xiàng)“-yuv-nvx-1buffer”輸出的圖片,結(jié)果正常。下面有一條綠色,也是因?yàn)閷?yīng)的內(nèi)存區(qū)沒有有效的圖像數(shù)據(jù)。
5.2.1. x2160分辨率顯示格式錯誤的現(xiàn)象
以分辨率3840x2176格式顯示分辨率3840x2160的圖片,最下面有綠條,是因?yàn)榘巡糠諹V分量數(shù)據(jù)當(dāng)成了Y分量數(shù)據(jù),導(dǎo)致最下面部分圖像缺少UV分量數(shù)據(jù)。
以分辨率3840x2160、I420格式顯示選項(xiàng)“-yuv-nvx-stride”輸出的NV12分辨率3840x2176圖片,輪廓正常,色彩異常。輪廓正常,是因?yàn)閷分量數(shù)據(jù)的解析是對的;色彩異常是因?yàn)閷V分量數(shù)據(jù)的解析是錯的。
06未來工作
未來可以繼續(xù)測試NV16的圖像,也可以測試其它分辨率的圖像。
原文標(biāo)題:【工程師分享】MPSoC VCU Ctrl-SW 2020.2 輸出NV12的YUV文件
文章出處:【微信公眾號:FPGA開發(fā)圈】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
責(zé)任編輯:haq
-
Xilinx
+關(guān)注
關(guān)注
71文章
2155瀏覽量
120850 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
2966瀏覽量
73812 -
VCU
+關(guān)注
關(guān)注
17文章
80瀏覽量
20403
原文標(biāo)題:【工程師分享】MPSoC VCU Ctrl-SW 2020.2 輸出NV12的YUV文件
文章出處:【微信號:FPGA-EETrend,微信公眾號:FPGA開發(fā)圈】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論