sw_scale中实现yuv420转rgb888——neon汇编优化
来源:互联网 发布:java long转int 溢出 编辑:程序博客网 时间:2024/06/06 14:09
在全志a31s上 使用ffmpeg库中sw_scale转换格式yuv4202rgbx888时,1920x1080的转换耗时有50多ms,渲染50多ms,实际效果无法达到声音视频同步。后在网上找到neon汇编优化代码,移植到sw_scale函数中,效果仍未能改善。
发现主要耗时在加载/存储内存指令上。现将移植部分代码贴上,以备后来再做分析。
.text.globalImgYUV2RGB24_neon .globalImgYUV2RGB24_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, #16vdup.8 d8, r9 @d8: 16 mov r10, #128vdup.8 d9, r10 @d9: 128mov r9, #75vdup.16 q5, r9 @q5: 75mov r10, #102vdup.16 q6, r10@q6: 102mov r9, #25vdup.16 q7, r9 @q7: 25mov r10, #52vdup.16 q8, r10@q8: 52mov r9, #129vdup.16 q9, r9@q9: 129 loop_row:loop_col:subs r8, r8, #1vld1.u8 d0, [r1]! @YLine1vld1.u8 d2, [r3]! @YLine2vld1.32 {d4[0]}, [r6]! @Uvld1.32 {d4[1]}, [r7]!@Vvsubl.u8 q0, d0, d8 @YLine2 - 16vsubl.u8 q1, d2, d8 @YLine1 - 16vsubl.u8 q2, d4, d9vmov q3, q2vzip.s16q2, q3 @q2:U - 128 q3: V-128@开始计算乘法部分vmul.s16 q10, q3, q8vmla.s16 q10, q2, q7 @得到计算G分量所需要的后半部分U、V之和vmul.s16 q11, q2, q9 @得到计算B分量的后半部分所需要的Uvmul.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, q10vqsub.s16 q14, q1, q10 vqrshrun.s16 d25, q13, #6 @@@@@@@@@@@@@@@@@@第一行的G vqrshrun.s16 d29, q14, #6@@@@@@@@@@@@@@@@@@第二行的G@得到两行的B分量vqadd.s16 q10, q0, q11vqadd.s16 q11, q1, q11vqrshrun.s16 d26, q10, #6@@@@@@@@@@@@@@@@@@第一行的Bvqrshrun.s16 d30, q11, #6@@@@@@@@@@@@@@@@@@第二行的B@得到两行的R分量vqadd.s16 q11, q0, q2vqadd.s16 q2, q1, q2vqrshrun.s16 d24, q11, #6@@@@@@@@@@@@@@@@@@第一行的Rvqrshrun.s16 d28, q2, #6@@@@@@@@@@@@@@@@@@第二行的R@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@做interleave操作,形成RGBx形式,然后存入目标buffervst4.8 {d24,d25,d26,d27}, [r0]!vst4.8 {d28,d29,d30,d31}, [r5]! bgt loop_colsubs lr, lr, #1 add r0, r0, r4add r5, r0, r4add r1, r1, r2add r3, r3, r2 @ add r6, r6, r11 @ add r7, r7, r11movr8, r2, lsr #3 bgt loop_row @pop {r4, r5, r6, r7, r8, r9, r10, lr} ldmfdsp!, {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, #16vdup.8 d8, r9 @d8: 16 mov r10, #128vdup.8 d9, r10 @d9: 128mov r9, #75vdup.16 q5, r9 @q5: 75mov r10, #102vdup.16 q6, r10@q6: 102mov r9, #25vdup.16 q7, r9 @q7: 25mov r10, #52vdup.16 q8, r10@q8: 52mov r9, #129vdup.16 q9, r9@q9: 129 loop_row1:loop_col1:subs r8, r8, #1vld1.u8 d0, [r1]! @YLine1vld1.u8 d2, [r3]! @YLine2vld1.32 {d4[0]}, [r6]! @Uvld1.32 {d4[1]}, [r7]!@Vvsubl.u8 q0, d0, d8 @YLine2 - 16vsubl.u8 q1, d2, d8 @YLine1 - 16vsubl.u8 q2, d4, d9vmov q3, q2vzip.s16q2, q3 @q2:U - 128 q3: V-128@开始计算乘法部分vmul.s16 q10, q3, q8vmla.s16 q10, q2, q7 @得到计算G分量所需要的后半部分U、V之和vmul.s16 q11, q2, q9 @得到计算B分量的后半部分所需要的Uvmul.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, q10vqsub.s16 q14, q1, q10 vqrshrun.s16 d25, q13, #6 @@@@@@@@@@@@@@@@@@第一行的G vqrshrun.s16 d29, q14, #6@@@@@@@@@@@@@@@@@@第二行的G@得到两行的B分量vqadd.s16 q10, q0, q11vqadd.s16 q11, q1, q11vqrshrun.s16 d26, q10, #6@@@@@@@@@@@@@@@@@@第一行的Bvqrshrun.s16 d30, q11, #6@@@@@@@@@@@@@@@@@@第二行的B@得到两行的R分量vqadd.s16 q11, q0, q2vqadd.s16 q2, q1, q2vqrshrun.s16 d24, q11, #6@@@@@@@@@@@@@@@@@@第一行的Rvqrshrun.s16 d28, q2, #6@@@@@@@@@@@@@@@@@@第二行的R@做interleave操作,形成RGBx形式,然后存入目标buffervst4.8 {d24,d25,d26,d27}, [r0]!vst4.8 {d28,d29,d30,d31}, [r5]! bgt loop_col1subs lr, lr, #1 add r0, r0, r4add r5, r0, r4 add r1, r1, #16 add r3, r3, #16add r1, r1, r2add r3, r3, r2 add r1, r1, #16 add r3, r3, #16 add r6, r6, #8 add r7, r7, #8movr8, r2, lsr #3 bgt loop_row1 @pop {r4, r5, r6, r7, r8, r9, r10, lr} ldmfdsp!, {r4-r10,lr} bx lr
后期可能会尝试进步优化,现在暂时没有好的想法...
0 0
- sw_scale中实现yuv420转rgb888——neon汇编优化
- neon优化的yuv420转rgb24汇编代码,iOS/Android可用
- neon汇编优化实例讲解
- ARM NEON 编程系列8——ARM NEON 优化
- -00-neon汇编优化实例讲解【ARM NEON加速】
- neon汇编代码的乱序优化
- ARM NEON 编程系列7——NEON gcc编译器intrinsics函数对应的汇编指令
- 从一个复数点积算法看NEON的汇编优化(NEON优化实例)
- (NEON实例一)ARM处理器NEON编程及优化技巧——数据加载和存储
- (NEON实例一)ARM处理器NEON编程及优化技巧——数据加载和存储
- ARM NEON优化(一)——NEON简介及基本架构
- ARM NEON 编程系列4——如何将neon用来优化我们的程序
- neon内嵌汇编实现一个yuv转rgb的功能stopped原因
- (NEON实例二)ARM处理器NEON编程及优化技巧——处理剩余的元素
- (NEON实例二)ARM处理器NEON编程及优化技巧——处理剩余的元素
- NEON汇编笔记
- arm汇编和neon汇编
- 图像转置的Neon优化代码
- Shiro RememberMe
- 为什么你应该(从现在开始就)写博客
- Dos汇编的简单输入输出.
- 强大的vim配置文件,让编程更随意
- TortoiseSVN—Repo-browser,打开你要比较的两个版本所在的地址,选择一个版本做为比较的基础(单击右键—选择mark for comparison),再选择另外一个版本(单击右键—选
- sw_scale中实现yuv420转rgb888——neon汇编优化
- 解决Ubuntu 12.04安装qtcreator后无法打开时的错误:Could not initialize GLX
- 2015一切都是新的开始
- android中的match_parent, fill_parent和wrap_content
- cocos2dx3.2 xcode代码块啊,气死自己的类名,低级的错误何时了?
- 配置vim开发Android[神器终究是神器]
- 静态链表
- 进程、挂起、线程、死锁、中断、陷入
- [leetcode 4] Median of Two Sorted Arrays