neon指令进行yuv420到rgb24转换效率

原创 2012年03月21日 11:21:19

从网上找到了一个用neon指令优化yuv420转换成rgb24的代码, 在cortex-A8架构、主频1G的cpu下进行对一帧qcif(176x144)数据测试,另外用网上很流行的用C写的算法做比较,发现前者的速度是后者的700多倍:前者循环1000次用时112ms,后者88645ms。相关代码如下:

汇编代码

        AREA |.text|, CODE, READONLY      ; name this block of code
        EXPORT ImgYUV2RGB24_neon
		
		ALIGN
;void ImgYUV2RGB24_neon(u8 *pu8RgbBuffer, u8 *pu8SrcYUV, l32 l32Width, l32 l32Height)
ImgYUV2RGB24_neon
    ;push            {r4, r5, r6, r7, r8, r9, r10, lr}
    stmfd			sp!, {r4-r10,lr}
    
    add             r4,  r2, r2            
    add             r4,  r4, r2             ;r4 : DstStride = 3 * l32Width
    
    mul             r5, r4, r3
    sub             r5, r5, r4
    add             r0, r0, r5             ;r0: pu8Dst = pu8Dst + l32DstStride * (l32Height - 1)
    
    mul             r5, r2, r3             
    add             r6, r1, r5             ;r6 : pu8SrcU = pu8SrcYUV + l32Width * l32Height
    add             r7, r6, r5, lsr #2     ;r7 : pu8SrcV = pu8SrcU + ((l32Width * l32Height)>>2)
    
    ;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 : l32Width
    sub             r5, r0, r4             ;r5 : pu8Dst2 = pu8Dst - l32DstStride
    
    mov             r9, #16
	vdup.8          d8, r9
	
	mov             r10, #128
	vdup.8          d9, r10
	
	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         q12, 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     d27, q13, #6  		;;;;;;;;;;;;;;;;;;第一行的G   
	vqrshrun.s16     d30, q14, #6		;;;;;;;;;;;;;;;;;;第二行的G	
	
	;得到两行的B分量
	vqadd.s16       q10, q0, q11
	vqadd.s16       q11, q1, q11
	
	vqrshrun.s16    d26, q10, #6			;;;;;;;;;;;;;;;;;;第一行的B
	vqrshrun.s16    d29, q11, #6			;;;;;;;;;;;;;;;;;;第二行的B
	
	;得到两行的R分量	
	vqadd.s16       q11, q0, q12
	vqadd.s16       q12, q1, q12
	
	vqrshrun.s16    d28, q11, #6			;;;;;;;;;;;;;;;;;;第一行的R
	vqrshrun.s16    d31, q12, #6			;;;;;;;;;;;;;;;;;;第二行的R
	
	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;做interleave操作,形成RGB形式,然后存入目标buffer
	vst3.8          {d26, d27, d28}, [r0]!
	
	vst3.8          {d29, d30, d31}, [r5]!
	
	bgt             loop_col
	
	subs            lr, lr, #1 
	
	sub             r0, r5, r4, lsl #1
	sub             r5, r0, r4
	
	add             r1, r1, r2
	add             r3, r3, r2
	;lsr             r8, r2, #3  
	mov				r8, r2, lsr #3
    bgt             loop_row

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

C代码

void YUV420p_to_RGB24(unsigned char *yuv420[3], unsigned char *rgb24, int width, int height) 
{
	//  int begin = GetTickCount();
	int R,G,B,Y,U,V;
	int x,y;
	int nWidth = width>>1; //色度信号宽度
	for (y=0;y<height;y++)
	{
		for (x=0;x<width;x++)
		{
			Y = *(yuv420[0] + y*width + x);
			U = *(yuv420[1] + ((y>>1)*nWidth) + (x>>1));
			V = *(yuv420[2] + ((y>>1)*nWidth) + (x>>1));
			R = Y + 1.402*(V-128);
			G = Y - 0.34414*(U-128) - 0.71414*(V-128);
			B = Y + 1.772*(U-128);

			//防止越界
			if (R>255)R=255;
			if (R<0)R=0;
			if (G>255)G=255;
			if (G<0)G=0;
			if (B>255)B=255;
			if (B<0)B=0;

			*(rgb24 + ((height-y-1)*width + x)*3) = B;
			*(rgb24 + ((height-y-1)*width + x)*3 + 1) = G;
			*(rgb24 + ((height-y-1)*width + x)*3 + 2) = R;
			//    *(rgb24 + (y*width + x)*3) = B;
			//    *(rgb24 + (y*width + x)*3 + 1) = G;
			//    *(rgb24 + (y*width + x)*3 + 2) = R;   
		}
	}
}

如何获取JPEG图片质量和预测压缩图片大小

前言发起这个博客的原因是近期有个需求,当用户在APP中发送图片时,APP要显示将图片压缩到指定尺寸的选项,选项中要显示压缩后图片的大小(占空间),出发点是为了控制上传流量。那转换成技术问题实际上就是计...

uboot——简介和常用命令及环境变量

一、背景   首先我们应该明白计算机系统的三个核心:CPU + 外部储存器(Flash/硬盘) + 内部储存器(DDR/DRAM/SRAM)。   典型的linux嵌入式系统启动过程:嵌入式系统上电后...

RGB24转yuv420 高效率 且颜色没有失真

前面使用dshow获取到的屏幕截图是一段rgb24的数据,需要将其转换成yuv420格式才能进行编码等操作。 网上找了很多资料,发现能用的并不多,这里总结一下。 1.雷大神写的 bmp转yuv: ...

RGB24与YUV420格式相互转换

  • 2016年07月14日 12:35
  • 7KB
  • 下载

yuv420和rgb24互相转换

算法一:  查表法 const int Table_fv1[256]={ -180, -179, -177, -176, -174, -173, -172, -170, -169,...

YUV420转换成RGB24

YUV转换成RGB转换公式:   R = Y + 1.4075 *(V-128)   G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)   B = Y + 1.7...
  • MikeDai
  • MikeDai
  • 2017年03月20日 23:37
  • 363

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

在全志a31s上 使用ffmpeg库中sw_scale转换格式yuv4202rgbx888时,1920x1080的转换耗时有50多ms,渲染50多ms,实际效果无法达到声音视频同步。后在网上找到neo...
  • iisktz
  • iisktz
  • 2015年01月01日 23:39
  • 634

使用ffmpeg进行图像格式转换以及图像缩放/sws_scale/linux/c++/c/rgb-yuv420

转自:http://blog.csdn.net/skys_broyal/article/details/10337147  利用ffmpeg进行图像数据格式的转换以及图片的缩放应用中,主要用到了...

YUV420、YUV422、RGB24转换

//平面YUV422转平面RGB24static void YUV422p_to_RGB24(unsigned char *yuv422[3], unsigned char *rgb24, int w...

使用ffmpeg进行图像格式转换以及图像缩放/sws_scale/linux/c++/c/rgb-yuv420

利用ffmpeg进行图像数据格式的转换以及图片的缩放应用中,主要用到了swscale.h文件中的三个函数,分别是:       struct SwsContext *sws_getContext...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:neon指令进行yuv420到rgb24转换效率
举报原因:
原因补充:

(最多只允许输入30个字)