原因:有人问过说yuv如何拼接,当时只是说对应内存进行拷贝,没有充分考虑数据的类型,故在此编写测试程序进行验证
概况:不同的数据源,找到对应的yuv数据,然后进行对应拷贝。
测试源数据:
YUV420P(又分为YU12和YV12),plane平面模式,y,u,v分量分别存放不同平面。首先是所有Y值,然后是所有V值,最后是所有U值.
YUV420SP(NV12和NV21),two-plane平面模式,y和uv分别为两个plane,uv交错排布。首先是所有Y值,然后是所有UV值。
以下以YV12为源数据进行测试伪代码如下:
竖型拼接,方法填充顺序为全部的Y0,Y1,V0,V1,U0,U1.
void vertical_splice(FILE *pSrc1, FILE *pSrc2, FILE *pOut, int iLen, int iY, int iU)
{
fread(pY, 1, iY, pSrc1);
fread(pU, 1, iU, pSrc1);
fread(pV, 1, iU, pSrc1);
fread(p2Y, 1, iY, pSrc2);
fread(p2U, 1, iU, pSrc2);
fread(p2V, 1, iU, pSrc2);
while (ire && ire2)
{
memcpy(pBuf, pY, iY);//y
memcpy(pBuf + iY, p2Y, iY);//y
memcpy(pBuf + iY + iY, pU, iU);//u
memcpy(pBuf + iY + iY + iU, p2U, iU);//u
memcpy(pBuf + iY * 2 + iU * 2, pV, iU);//v
memcpy(pBuf + iY * 2 + iU * 2 + iU, p2V, iU);//v
fwrite(pBuf, 1, iLen * 2, pOut);
fread(pY, 1, iY, pSrc1);
fread(pU, 1, iU, pSrc1);
fread(pV, 1, iU, pSrc1);
fread(p2Y, 1, iY, pSrc2);
fread(p2U, 1, iU, pSrc2);
fread(p2V, 1, iU, pSrc2);
}
}
横型拼接伪代码如下:首先进行全部Y分量的交错填充,然后全部U分量交错填充,然后为全部V分量交错填充.此时重点为UV分量的起始地址和填充的数据长度.获取出错的话可以在最终的画面上看到画面内存重复。
void horizontal_splice(FILE *pSrc1,FILE *pSrc2,FILE *pOut,int iLen,int iH,int iW)
{
for (int Index =0;Index <200;Index++)
{
int iDuration = 0;
for (int i = 0; i < iH; i++)
{
fread(pY, 1, iW, pSrc1);//y1
memcpy(pBuf + iDuration, pY, iW);
iDuration += iW;
fread(p2Y, 1, iW, pSrc2);//y2
memcpy(pBuf + iDuration, p2Y, iW);
iDuration += iW;
}
for (int i = 0; i < iH/2; i++)
{
fread(pU, 1, iW /2, pSrc1);//u1
memcpy(pBuf + iDuration, pU, iW/2);
iDuration += (iW / 2);
fread(p2U, 1, iW/2, pSrc2);//u2
memcpy(pBuf +iDuration, p2U, iW/2);
iDuration += (iW / 2);
}
for (int i = 0; i < iH/2; i++)
{
fread(pV, 1, iW /2, pSrc1);//v1
memcpy(pBuf+iDuration, pV, iW /2);
iDuration += (iW / 2);
fread(p2V, 1, iW/2, pSrc2);//v2
memcpy(pBuf+ iDuration, p2V, iW/2);
iDuration += (iW / 2);
}
fwrite(pBuf, 1, iDuration, pOut);
}
}
效果如下:测试代码后续上传。
总结:yuv拼接最主要为对应y,u,v分量的拷贝。