首页 > 代码库 > YUV420 Planar 转换为 YUV422 Packed

YUV420 Planar 转换为 YUV422 Packed



YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。


Packed 格式将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel),

比如相邻两个像素组成一个宏像素,UYVY


Planar 格式使用三个数组分开存放YUV三个分量。

在使用 FFMPEG avcodec_decode_video() 函数解码H.264码流后,得到 planar 格式存储的YUV分量

data[0], linesize[0], 描述Y分量的地址和跨度(stride)
data[1], data[2], linesize[1], 描述U,V分量的地址和跨度(stride)


在某些场合下,我们需要将YUV420 Planar格式转化成 YUV422 Packed格式,以方便显示或处理。下面这个函数使用MMX指令完成这个任务。


void YUV420toUYVY422(unsigned char *pszSrcY, int iSrcPitchY, unsigned char *pszSrcU,
                     unsigned char *pszSrcV, int iSrcPitchUV, unsigned char *pszDst,
                     int iSrcWidth, int iSrcHeight, int iDstPitch)
{
    int iSrcStride = iSrcPitchY + iSrcPitchY - iSrcWidth;
    int iSrcStrideU = (iSrcPitchY - iSrcWidth) >> 1;
    int iDstStride =(iDstPitch - iSrcWidth) << 1;

    __asm
    {
        push ebx
        mov edi , [pszDst]
        mov esi , [pszSrcY]
        mov eax , [pszSrcU]
        mov ebx , [pszSrcV]
        mov ecx , [iSrcHeight]
        mov edx , [iSrcWidth]
cyc:
        movq mm0, qword ptr[esi] //y1(yyyyyyyy)
        movq mm1, qword ptr[esi + 8] //y2      (yyyyyyyy)
        movq mm2 , qword ptr [eax] //u ( u u u u u u u u)
        movq mm3 , qword ptr [ebx] //v ( v v v v v v v v)
        movq mm4 , mm2

        //push eax
        //xor eax, eax
        //movd mm2, eax //u ( u u u u u u u u)
        //movd mm3, eax //v ( v v v v v v v v)
        //movq mm4, mm2
        //pop eax

        //-----------------------------------------------------
        //punpcklbw mmDST, mmSRC
        //交叉组合 mmDST 与 mmSRC 低位双字(4B)中的字节,
        //结果(8B)放入 mmDST
        //-----------------------------------------------------
        //before:
        //MM0 == 01 02 03 04 _ 05 06 07 08 hex
        //MM1 == 09 0a 0b 0c _ 0d 0e 0f 00 hex
        //punpcklbw MM0, MM1, after:
        //MM0 = 0d 05 0e 06 0f 07 00 08 h  (64bit full)
        //-----------------------------------------------------
        //when write MM0 to memory: 08 00 07 0f 06 0e 05 0d h
        //-----------------------------------------------------
        punpcklbw mm2 , mm3 // uv1 ( LOW 8B         v u v u v u v u)
        punpckhbw mm4 , mm3 // uv2 (v u v u v u v u         HI 8B  )
        movq mm6 , mm2
        movq mm7 , mm4
        movq mm3 , mm2
        movq mm5 , mm4
        punpcklbw mm2 , mm0 // uyvy1 (                y v y u y v y u)
        punpckhbw mm3 , mm0 // uyvy2 (y v y u y v y u                )
        punpcklbw mm4 , mm1 // uyvy3 (                Y v Y u Y v Y u)
        punpckhbw mm5 , mm1 // uyvy4 (Y v Y u Y v Y u                )
        movq qword ptr [edi] , mm2
        movq qword ptr [edi+8] , mm3
        movq qword ptr [edi+16] , mm4
        movq qword ptr [edi+24] , mm5

        add esi , [iSrcPitchY]
        add edi , [iDstPitch]
        
        movq mm0 , qword ptr [esi]   //y1
        movq mm1 , qword ptr [esi+8] //y2
        movq mm2 , mm6
        movq mm4 , mm7
        movq mm3 , mm2
        movq mm5 , mm4
        punpcklbw mm2 , mm0 // uyvy 1  //low byte mix
        punpckhbw mm3 , mm0 // uyvy 2  //high byte mix
        punpcklbw mm4 , mm1 // uyvy 3
        punpckhbw mm5 , mm1 // uyvy 4
        movq qword ptr [edi] , mm2
        movq qword ptr [edi+8] , mm3
        movq qword ptr [edi+16] , mm4
        movq qword ptr [edi+24] , mm5

        sub esi , [iSrcPitchY]
        sub edi , [iDstPitch]
        add eax , 8    //U
        add ebx , 8    //V
        add esi , 16   //Y
        add edi , 32   //DST
        
        sub edx , 16   //WIDTH
        ja cyc         //repeat until current row completes
        
        mov edx,  [iSrcWidth]   //Reload width at new row
        add esi , [iSrcStride]  //Reload stride at new row
        add eax , [iSrcStrideU] //U stride
        add ebx , [iSrcStrideU] //V stride
        add edi , [iDstStride]  //Y stride

        sub ecx,2       //HEIGHT 480
        ja cyc          //repeat until all rows complete
        
        emms
        pop ebx
    }
}


YUV420 Planar 转换为 YUV422 Packed