sw_scale中实现yuv420转rgb888——neon汇编优化

          在全志a31s上 使用ffmpeg库中sw_scale转换格式yuv4202rgbx888时,1920x1080的转换耗时有50多ms,渲染50多ms,实际效果无法达到声音视频同步。后在网上找到neon汇编优化代码,移植到sw_scale函数中,效果仍未能改善。

发现主要耗时在加载/存储内存指令上。现将移植部分代码贴上,以备后来再做分析。

.text
	.global	ImgYUV2RGB24_neon
        .global	ImgYUV2RGB24_neon1
@void ImgYUV2RGB24_neon(u8 *pu8RgbBuffer, u8 *pu8SrcYUV, l32 l32Width, l32 l32Height)
ImgYUV2RGB24_neon:
    @push            {r4, r5, r6, r7, r8, r9, r10,r11,r12, lr}

    stmfd	    sp!, {r4-r10,lr}

    mov             r6,  r2
    mov             r7,  r3
    ldr             r2, [sp,#32]       
    ldr             r3, [sp,#36] 
           


    add             r4,  r2, r2            
    add             r4,  r4, r2             @r4 : DstStride =4 * Width
    add             r4,  r4, r2
    

    
    @lsr             r8, r2, #3             @r8 记录了col的循环次数, r2记录了YUV图像宽度
    mov		     r8, r2, lsr #3
    @lsr             lr, r3, #1             @lr 记录了Row的循环次数, r3记录了YUV图像高度
    mov		     lr, r3, lsr #1
   

    add             r3, r1, r2             @r1, pu8Src1@  r3 : pu8Src2, r2 : Width
    add             r5, r0, r4             @r5 : pu8Dst2 = pu8Dst - l32DstStride
    
        mov             r9, #16
	vdup.8          d8, r9                          @d8: 16
	 
	mov             r10, #128
	vdup.8          d9, r10                         @d9: 128
	
	mov             r9, #75
	vdup.16         q5, r9 				@q5: 75
	
	mov             r10, #102
	vdup.16         q6, r10				@q6: 102
	
	mov             r9, #25
	vdup.16         q7, r9 				@q7: 25
	
	mov             r10, #52
	vdup.16         q8, r10				@q8: 52
	
	mov             r9, #129
	vdup.16         q9, r9				@q9: 129
        
loop_row:
loop_col:
	subs            r8, r8, #1
	vld1.u8         d0, [r1]!     		@YLine1
	vld1.u8         d2, [r3]!     		@YLine2
	vld1.32         {d4[0]}, [r6]!          @U
	vld1.32         {d4[1]}, [r7]!		@V
	
	vsubl.u8        q0, d0, d8         @YLine2 - 16
	vsubl.u8        q1, d2, d8         @YLine1 - 16	
	
	vsubl.u8        q2, d4, d9
	vmov            q3, q2
	vzip.s16		q2, q3               @q2:U - 128  q3: V-128
	
	@开始计算乘法部分				
	vmul.s16         q10, q3, q8			
	vmla.s16         q10, q2, q7	 @得到计算G分量所需要的后半部分U、V之和
	
	vmul.s16         q11, q2, q9	 @得到计算B分量的后半部分所需要的U
	
	vmul.s16         q2, q3, q6	 @得到计算R分量的后半部分所需要的V	
	
	@计算Y的部分乘积
	vmul.s16       	q0, q0, q5	     @q0、q1得到第一行Y的共8点乘积
	vmul.s16        q1, q1, q5	     @q2、q3得到第二行Y的共8点乘积



	
	@得到两行的G分量
	vqsub.s16        q13, q0, q10
	vqsub.s16        q14, q1, q10
	 
	vqrshrun.s16     d25, q13, #6  		@@@@@@@@@@@@@@@@@@第一行的G   
	vqrshrun.s16     d29, q14, #6		@@@@@@@@@@@@@@@@@@第二行的G	
	
	@得到两行的B分量
	vqadd.s16       q10, q0, q11
	vqadd.s16       q11, q1, q11
	
	vqrshrun.s16    d26, q10, #6			@@@@@@@@@@@@@@@@@@第一行的B
	vqrshrun.s16    d30, q11, #6			@@@@@@@@@@@@@@@@@@第二行的B
	
	@得到两行的R分量	
	vqadd.s16       q11, q0, q2
	vqadd.s16       q2,  q1, q2
	
	vqrshrun.s16    d24, q11, #6			@@@@@@@@@@@@@@@@@@第一行的R
	vqrshrun.s16    d28, q2, #6			@@@@@@@@@@@@@@@@@@第二行的R
	

	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
	@做interleave操作,形成RGBx形式,然后存入目标buffer
	vst4.8          {d24,d25,d26,d27}, [r0]!
	vst4.8          {d28,d29,d30,d31}, [r5]!
 
	bgt             loop_col
	
	subs            lr, lr, #1 
	
	add             r0, r0, r4
	add             r5, r0, r4
	
	add             r1, r1, r2
	add             r3, r3, r2
   @     add             r6, r6, r11
   @     add             r7, r7, r11

	mov				r8, r2, lsr #3
        
    bgt             loop_row

    @pop             {r4, r5, r6, r7, r8, r9, r10, lr}
    ldmfd			sp!, {r4-r10,lr}
    bx              lr

c部分接口

static int yuv420_rgb24_neon(SwsContext *c, const uint8_t *src[], int srcStride[],
                           int sliceY, int sliceH, uint8_t *dst[], int dstStride[])
{

   if(srcStride[0]>c->srcW)
		ImgYUV2RGB24_neon1(dst[0],src[0],src[1],src[2],c->srcW,c->srcH);
   else
    	ImgYUV2RGB24_neon(dst[0],src[0],src[1],src[2],c->srcW,c->srcH);

	return 0;
}


由于有些视频解码后宽度变大,改进后实现切边

 

ImgYUV2RGB24_neon1:

    stmfd	    sp!, {r4-r10,lr}
    mov             r6,  r2
    mov             r7,  r3
    ldr             r2, [sp,#32]       
    ldr             r3, [sp,#36] 
           
    add             r4,  r2, r2            
    add             r4,  r4, r2             @r4 : DstStride = 4 * l32Width
    add             r4,  r4, r2
       
            
    mov		     r8, r2, lsr #3         @r8 记录了col的循环次数, r2记录了YUV图像宽度          
    mov		     lr, r3, lsr #1        @lr 记录了Row的循环次数, r3记录了YUV图像高度
   
    add             r3, r1, r2             @r1, pu8Src1@  r3 : pu8Src2, r2 : l32Width
    add             r3, r3, #16
    add             r5, r0, r4             @r5 : pu8Dst2 = pu8Dst - l32DstStride
    
        mov             r9, #16
	vdup.8          d8, r9                          @d8: 16
	 
	mov             r10, #128
	vdup.8          d9, r10                         @d9: 128
	
	mov             r9, #75
	vdup.16         q5, r9 				@q5: 75
	
	mov             r10, #102
	vdup.16         q6, r10				@q6: 102
	
	mov             r9, #25
	vdup.16         q7, r9 				@q7: 25
	
	mov             r10, #52
	vdup.16         q8, r10				@q8: 52
	
	mov             r9, #129
	vdup.16         q9, r9				@q9: 129
        
loop_row1:
loop_col1:
	subs            r8, r8, #1
	vld1.u8         d0, [r1]!     		@YLine1
	vld1.u8         d2, [r3]!     		@YLine2
	vld1.32         {d4[0]}, [r6]!          @U
	vld1.32         {d4[1]}, [r7]!		@V
	
	vsubl.u8        q0, d0, d8         @YLine2 - 16
	vsubl.u8        q1, d2, d8         @YLine1 - 16	
	
	vsubl.u8        q2, d4, d9
	vmov            q3, q2
	vzip.s16		q2, q3               @q2:U - 128  q3: V-128
	
	@开始计算乘法部分				
	vmul.s16         q10, q3, q8			
	vmla.s16         q10, q2, q7	 @得到计算G分量所需要的后半部分U、V之和
	
	vmul.s16         q11, q2, q9	 @得到计算B分量的后半部分所需要的U
	
	vmul.s16         q2, q3, q6	 @得到计算R分量的后半部分所需要的V	
	
	@计算Y的部分乘积
	vmul.s16       	q0, q0, q5	     @q0、q1得到第一行Y的共8点乘积
	vmul.s16        q1, q1, q5	     @q2、q3得到第二行Y的共8点乘积



	
	@得到两行的G分量
	vqsub.s16        q13, q0, q10
	vqsub.s16        q14, q1, q10
	 
	vqrshrun.s16     d25, q13, #6  		@@@@@@@@@@@@@@@@@@第一行的G   
	vqrshrun.s16     d29, q14, #6		@@@@@@@@@@@@@@@@@@第二行的G	
	
	@得到两行的B分量
	vqadd.s16       q10, q0, q11
	vqadd.s16       q11, q1, q11
	
	vqrshrun.s16    d26, q10, #6			@@@@@@@@@@@@@@@@@@第一行的B
	vqrshrun.s16    d30, q11, #6			@@@@@@@@@@@@@@@@@@第二行的B
	
	@得到两行的R分量	
	vqadd.s16       q11, q0, q2
	vqadd.s16       q2,  q1, q2
	
	vqrshrun.s16    d24, q11, #6			@@@@@@@@@@@@@@@@@@第一行的R
	vqrshrun.s16    d28, q2, #6			@@@@@@@@@@@@@@@@@@第二行的R
	

	@做interleave操作,形成RGBx形式,然后存入目标buffer
	vst4.8          {d24,d25,d26,d27}, [r0]!
	vst4.8          {d28,d29,d30,d31}, [r5]!
 
	bgt             loop_col1
	
	subs            lr, lr, #1 
	
	add             r0, r0, r4
	add             r5, r0, r4
	
        add             r1, r1, #16
        add             r3, r3, #16

	add             r1, r1, r2
	add             r3, r3, r2

        add             r1, r1, #16
        add             r3, r3, #16
        add             r6, r6, #8
        add             r7, r7, #8

	mov				r8, r2, lsr #3
        
    bgt             loop_row1

    @pop             {r4, r5, r6, r7, r8, r9, r10, lr}
    ldmfd			sp!, {r4-r10,lr}
    bx              lr

  后期可能会尝试进步优化,现在暂时没有好的想法...     




你可能感兴趣的:(视频多媒体)