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

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

汇编代码

AREA |.text|, CODE, READONLY; name this block of codeEXPORT ImgYUV2RGB24_neonALIGN;void ImgYUV2RGB24_neon(u8 *pu8RgbBuffer, u8 *pu8SrcYUV, l32 l32Width, l32 l32Height)ImgYUV2RGB24_neon;push{r4, r5, r6, r7, r8, r9, r10, lr}stmfdsp!, {r4-r10,lr}addr4, r2, r2addr4, r4, r2;r4 : DstStride = 3 * l32Widthmulr5, r4, r3subr5, r5, r4addr0, r0, r5;r0: pu8Dst = pu8Dst + l32DstStride * (l32Height – 1)mulr5, r2, r3addr6, r1, r5;r6 : pu8SrcU = pu8SrcYUV + l32Width * l32Heightaddr7, r6, r5, lsr #2;r7 : pu8SrcV = pu8SrcU + ((l32Width * l32Height)>>2);lsrr8, r2, #3;r8 记录了col的循环次数, r2记录了YUV图像宽度movr8, r2, lsr #3;lsrlr, r3, #1;lr 记录了Row的循环次数, r3记录了YUV图像高度movlr, r3, lsr #1addr3, r1, r2;r1, pu8Src1; r3 : pu8Src2, r2 : l32Widthsubr5, r0, r4;r5 : pu8Dst2 = pu8Dst – l32DstStridemovr9, #16vdup.8d8, r9movr10, #128vdup.8d9, r10movr9, #75vdup.16q5, r9;q5: 75movr10, #102vdup.16q6, r10;q6: 102movr9, #25vdup.16q7, r9;q7: 25movr10, #52vdup.16q8, r10;q8: 52movr9, #129vdup.16q9, r9;q9: 129loop_rowloop_colsubsr8, r8, #1vld1.u8d0, [r1]!;YLine1vld1.u8d2, [r3]!;YLine2vld1.32{d4[0]}, [r6]!;Uvld1.32{d4[1]}, [r7]!;Vvsubl.u8q0, d0, d8;YLine2 – 16vsubl.u8q1, d2, d8;YLine1 – 16vsubl.u8q2, d4, d9vmovq3, q2vzip.s16q2, q3;q2:U – 128 q3: V-128;开始计算乘法部分vmul.s16q10, q3, q8vmla.s16q10, q2, q7 ;得到计算G分量所需要的后半部分U、V之和vmul.s16q11, q2, q9 ;得到计算B分量的后半部分所需要的Uvmul.s16q12, q3, q6 ;得到计算R分量的后半部分所需要的V;计算Y的部分乘积vmul.s16q0, q0, q5;q0、q1得到第一行Y的共8点乘积vmul.s16q1, q1, q5;q2、q3得到第二行Y的共8点乘积;得到两行的G分量vqsub.s16q13, q0, q10vqsub.s16q14, q1, q10vqrshrun.s16d27, q13, #6 ;;;;;;;;;;;;;;;;;;第一行的Gvqrshrun.s16d30, q14, #6;;;;;;;;;;;;;;;;;;第二行的G;得到两行的B分量vqadd.s16q10, q0, q11vqadd.s16q11, q1, q11vqrshrun.s16 d26, q10, #6;;;;;;;;;;;;;;;;;;第一行的Bvqrshrun.s16 d29, q11, #6;;;;;;;;;;;;;;;;;;第二行的B;得到两行的R分量vqadd.s16q11, q0, q12vqadd.s16q12, q1, q12vqrshrun.s16 d28, q11, #6;;;;;;;;;;;;;;;;;;第一行的Rvqrshrun.s16 d31, q12, #6;;;;;;;;;;;;;;;;;;第二行的R;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;做interleave操作,形成RGB形式,然后存入目标buffervst3.8{d26, d27, d28}, [r0]!vst3.8{d29, d30, d31}, [r5]!bgtloop_colsubslr, lr, #1subr0, r5, r4, lsl #1subr5, r0, r4addr1, r1, r2addr3, r3, r2;lsrr8, r2, #3movr8, r2, lsr #3bgtloop_row;pop{r4, r5, r6, r7, r8, r9, r10, lr}ldmfdsp!, {r4-r10,lr}bxlrEND

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;}}}

人生就像是一场旅行,遇到的既有感人的,

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

相关文章:

你感兴趣的文章:

标签云: