diff mbox

[FFmpeg-devel,1/6] avcodec/hevcdsp: Add NEON optimization for qpel weighted mode

Message ID 20171122111206.17214-2-shengbinmeng@gmail.com
State Superseded
Headers show

Commit Message

Shengbin Meng Nov. 22, 2017, 11:12 a.m. UTC
From: Meng Wang <wangmeng.kids@bytedance.com>

Signed-off-by: Meng Wang <wangmeng.kids@bytedance.com>
---
 libavcodec/arm/hevcdsp_init_neon.c |  66 +++++
 libavcodec/arm/hevcdsp_qpel_neon.S | 509 +++++++++++++++++++++++++++++++++++++
 2 files changed, 575 insertions(+)

Comments

Michael Niedermayer Nov. 22, 2017, 12:26 p.m. UTC | #1
On Wed, Nov 22, 2017 at 07:12:01PM +0800, Shengbin Meng wrote:
> From: Meng Wang <wangmeng.kids@bytedance.com>
> 
> Signed-off-by: Meng Wang <wangmeng.kids@bytedance.com>
> ---
>  libavcodec/arm/hevcdsp_init_neon.c |  66 +++++
>  libavcodec/arm/hevcdsp_qpel_neon.S | 509 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 575 insertions(+)
> 
> diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c

This seems not to apply to git master


Applying: avcodec/hevcdsp: Add NEON optimization for qpel weighted mode
Using index info to reconstruct a base tree...
M       libavcodec/arm/hevcdsp_init_neon.c
Falling back to patching base and 3-way merge...
Auto-merging libavcodec/arm/hevcdsp_init_neon.c
CONFLICT (content): Merge conflict in libavcodec/arm/hevcdsp_init_neon.c
error: Failed to merge in the changes.
Patch failed at 0001 avcodec/hevcdsp: Add NEON optimization for qpel weighted mode
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".


[...]
Shengbin Meng Nov. 22, 2017, 2:01 p.m. UTC | #2
> On 22 Nov 2017, at 20:26, Michael Niedermayer <michael@niedermayer.cc> wrote:
> 
> On Wed, Nov 22, 2017 at 07:12:01PM +0800, Shengbin Meng wrote:
>> From: Meng Wang <wangmeng.kids@bytedance.com>
>> 
>> Signed-off-by: Meng Wang <wangmeng.kids@bytedance.com>
>> ---
>> libavcodec/arm/hevcdsp_init_neon.c |  66 +++++
>> libavcodec/arm/hevcdsp_qpel_neon.S | 509 +++++++++++++++++++++++++++++++++++++
>> 2 files changed, 575 insertions(+)
>> 
>> diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
> 
> This seems not to apply to git master

I looked into that and it seems someone has added commits about hevc decoding in git master after n3.4.
My patches are based on n3.4 so some conflicts occur. And I checked the conflict is mainly due to the following change in master:

ff_hevcdsp_init_neon => ff_hevc_dsp_init_neon  (in libavcodec/arm/hevcdsp_init_neon.c, a common function name was changed).

It is a small conflict though and should be easily resolved. Anyway, I have updated those patches to v2 which are all based on master, for your convenience. They should merge all right.

And since master already contains optimization code for IDCT (even 32x32 blocks, great plus!), our work about IDCT are removed from v2 patches.

Thank you.

Regards,
Shengbin

> Applying: avcodec/hevcdsp: Add NEON optimization for qpel weighted mode
> Using index info to reconstruct a base tree...
> M       libavcodec/arm/hevcdsp_init_neon.c
> Falling back to patching base and 3-way merge...
> Auto-merging libavcodec/arm/hevcdsp_init_neon.c
> CONFLICT (content): Merge conflict in libavcodec/arm/hevcdsp_init_neon.c
> error: Failed to merge in the changes.
> Patch failed at 0001 avcodec/hevcdsp: Add NEON optimization for qpel weighted mode
> The copy of the patch that failed is found in: .git/rebase-apply/patch
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
> 
> 
> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> 
> I am the wisest man alive, for I know one thing, and that is that I know
> nothing. -- Socrates
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
diff mbox

Patch

diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
index 1a3912c609..2559c92095 100644
--- a/libavcodec/arm/hevcdsp_init_neon.c
+++ b/libavcodec/arm/hevcdsp_init_neon.c
@@ -63,6 +63,8 @@  static void (*put_hevc_qpel_neon[4][4])(int16_t *dst, ptrdiff_t dststride, uint8
                                    int height, int width);
 static void (*put_hevc_qpel_uw_neon[4][4])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
                                    int width, int height, int16_t* src2, ptrdiff_t src2stride);
+static void (*put_hevc_qpel_wt_neon[4][4])(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+                                   int width, int height, int denom, int wx1, int ox1, int wx0, int ox0, int16_t* src2, ptrdiff_t src2stride);
 void ff_hevc_put_qpel_neon_wrapper(int16_t *dst, uint8_t *src, ptrdiff_t srcstride,
                                    int height, intptr_t mx, intptr_t my, int width);
 void ff_hevc_put_qpel_uni_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
@@ -70,6 +72,15 @@  void ff_hevc_put_qpel_uni_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_
 void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
                                        int16_t *src2,
                                        int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_qpel_uni_w_neon_wrapper(uint8_t *dst,  ptrdiff_t dststride,
+                                         uint8_t *src, ptrdiff_t srcstride,
+                                         int height, int denom, int wx, int ox,
+                                         intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_qpel_bi_w_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+                                        int16_t *src2,
+                                        int height, int denom, int wx0, int wx1,
+                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width);
+
 #define QPEL_FUNC(name) \
     void name(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, \
                                    int height, int width)
@@ -124,6 +135,26 @@  QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v2_neon_8);
 QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v3_neon_8);
 #undef QPEL_FUNC_UW
 
+#define QPEL_FUNC_WT(name) \
+void name(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, \
+    int width, int height, int denom, int wx1, int ox1, int wx0, int ox0, int16_t* src2, ptrdiff_t src2stride);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_v1_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_v2_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_v3_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h1_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h2_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h3_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h1v1_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h1v2_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h1v3_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h2v1_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h2v2_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h2v3_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h3v1_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h3v2_neon_8);
+QPEL_FUNC_WT(ff_hevc_put_qpel_wt_h3v3_neon_8);
+#undef QPEL_FUNC_WT
+
 void ff_hevc_put_qpel_neon_wrapper(int16_t *dst, uint8_t *src, ptrdiff_t srcstride,
                                    int height, intptr_t mx, intptr_t my, int width) {
 
@@ -142,6 +173,20 @@  void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t
     put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE);
 }
 
+void ff_hevc_put_qpel_uni_w_neon_wrapper(uint8_t *dst,  ptrdiff_t dststride,
+                                              uint8_t *src, ptrdiff_t srcstride,
+                                              int height, int denom, int wx, int ox,
+                                              intptr_t mx, intptr_t my, int width) {
+    put_hevc_qpel_wt_neon[my][mx](dst, dststride, src, srcstride, width, height, denom, wx, ox, 0, 0, NULL, 0);
+}
+
+void ff_hevc_put_qpel_bi_w_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+                                             int16_t *src2,
+                                             int height, int denom, int wx0, int wx1,
+                                             int ox0, int ox1, intptr_t mx, intptr_t my, int width) {
+    put_hevc_qpel_wt_neon[my][mx](dst, dststride, src, srcstride, width, height, denom, wx1, ox1, wx0, ox0, src2, MAX_PB_SIZE);
+}
+
 av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
 {
     if (bit_depth == 8) {
@@ -191,6 +236,21 @@  av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
         put_hevc_qpel_uw_neon[3][1]      = ff_hevc_put_qpel_uw_h1v3_neon_8;
         put_hevc_qpel_uw_neon[3][2]      = ff_hevc_put_qpel_uw_h2v3_neon_8;
         put_hevc_qpel_uw_neon[3][3]      = ff_hevc_put_qpel_uw_h3v3_neon_8;
+        put_hevc_qpel_wt_neon[1][0]      = ff_hevc_put_qpel_wt_v1_neon_8;
+        put_hevc_qpel_wt_neon[2][0]      = ff_hevc_put_qpel_wt_v2_neon_8;
+        put_hevc_qpel_wt_neon[3][0]      = ff_hevc_put_qpel_wt_v3_neon_8;
+        put_hevc_qpel_wt_neon[0][1]      = ff_hevc_put_qpel_wt_h1_neon_8;
+        put_hevc_qpel_wt_neon[0][2]      = ff_hevc_put_qpel_wt_h2_neon_8;
+        put_hevc_qpel_wt_neon[0][3]      = ff_hevc_put_qpel_wt_h3_neon_8;
+        put_hevc_qpel_wt_neon[1][1]      = ff_hevc_put_qpel_wt_h1v1_neon_8;
+        put_hevc_qpel_wt_neon[1][2]      = ff_hevc_put_qpel_wt_h2v1_neon_8;
+        put_hevc_qpel_wt_neon[1][3]      = ff_hevc_put_qpel_wt_h3v1_neon_8;
+        put_hevc_qpel_wt_neon[2][1]      = ff_hevc_put_qpel_wt_h1v2_neon_8;
+        put_hevc_qpel_wt_neon[2][2]      = ff_hevc_put_qpel_wt_h2v2_neon_8;
+        put_hevc_qpel_wt_neon[2][3]      = ff_hevc_put_qpel_wt_h3v2_neon_8;
+        put_hevc_qpel_wt_neon[3][1]      = ff_hevc_put_qpel_wt_h1v3_neon_8;
+        put_hevc_qpel_wt_neon[3][2]      = ff_hevc_put_qpel_wt_h2v3_neon_8;
+        put_hevc_qpel_wt_neon[3][3]      = ff_hevc_put_qpel_wt_h3v3_neon_8;
         for (x = 0; x < 10; x++) {
             c->put_hevc_qpel[x][1][0]         = ff_hevc_put_qpel_neon_wrapper;
             c->put_hevc_qpel[x][0][1]         = ff_hevc_put_qpel_neon_wrapper;
@@ -201,6 +261,12 @@  av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
             c->put_hevc_qpel_bi[x][1][0]      = ff_hevc_put_qpel_bi_neon_wrapper;
             c->put_hevc_qpel_bi[x][0][1]      = ff_hevc_put_qpel_bi_neon_wrapper;
             c->put_hevc_qpel_bi[x][1][1]      = ff_hevc_put_qpel_bi_neon_wrapper;
+            c->put_hevc_qpel_uni_w[x][1][0]   = ff_hevc_put_qpel_uni_w_neon_wrapper;
+            c->put_hevc_qpel_uni_w[x][0][1]   = ff_hevc_put_qpel_uni_w_neon_wrapper;
+            c->put_hevc_qpel_uni_w[x][1][1]   = ff_hevc_put_qpel_uni_w_neon_wrapper;
+            c->put_hevc_qpel_bi_w[x][1][0]    = ff_hevc_put_qpel_bi_w_neon_wrapper;
+            c->put_hevc_qpel_bi_w[x][0][1]    = ff_hevc_put_qpel_bi_w_neon_wrapper;
+            c->put_hevc_qpel_bi_w[x][1][1]    = ff_hevc_put_qpel_bi_w_neon_wrapper;
         }
         c->put_hevc_qpel[0][0][0]  = ff_hevc_put_pixels_w2_neon_8;
         c->put_hevc_qpel[1][0][0]  = ff_hevc_put_pixels_w4_neon_8;
diff --git a/libavcodec/arm/hevcdsp_qpel_neon.S b/libavcodec/arm/hevcdsp_qpel_neon.S
index 86f92cf75a..e188b215ba 100644
--- a/libavcodec/arm/hevcdsp_qpel_neon.S
+++ b/libavcodec/arm/hevcdsp_qpel_neon.S
@@ -333,6 +333,139 @@ 
         bx lr
 .endm
 
+.macro  hevc_put_qpel_wt_vX_neon_8 filter
+        push   {r4-r12}
+        ldr    r5, [sp, #36] // width
+        ldr    r4, [sp, #40] // height
+        ldr    r8, [sp, #44] // denom
+        ldr    r9, [sp, #48] // wx1
+        ldr    r10,[sp, #52] // ox1
+        ldr    r11,[sp, #64] // src2
+        vpush {d8-d15}
+        sub       r2, r2, r3, lsl #1 // r2 - 3*stride
+        sub       r2, r3
+        mov       r12, r4
+        mov       r6, r0
+        mov       r7, r2
+        add       r8, #6     // weight shift = denom + 6
+        vdup.32   q5, r8     // shift is a 32 bit action
+        vneg.s32  q4, q5     // q4 = -q5
+        vdup.32   q6, r9     // q6 wx
+        vdup.32   q5, r10    // q5 ox
+        cmp       r11, #0    // if src2 != 0 goto bi mode
+        bne       .Lbi\@
+0:      loadin8
+        cmp       r5, #4
+        beq       4f
+8:      subs      r4, #1
+        \filter
+        vmovl.s16     q12, d14     // extending signed 4x16bit data to 4x32 bit
+        vmovl.s16     q13, d15
+        vmul.s32      q14, q12, q6   // src * wx
+        vmul.s32      q15, q13, q6   // src * wx
+        vqrshl.s32    q12, q14, q4   // src * wx >> shift
+        vqrshl.s32    q13, q15, q4   // src * wx >> shift
+        vadd.s32      q14, q12, q5   // src * wx >> shift + ox
+        vadd.s32      q15, q13, q5   // src * wx >> shift + ox
+        vqmovun.s32   d2,  q14       // narrow signed 4x32bit to unsigned 4x16bit
+        vqmovun.s32   d3,  q15       // narrow signed 4x32bit to unsigned 4x16bit
+        vqmovn.u16    d0,  q1        // narrow unsigned 8x16bit to unsigned 8x8bit
+        vst1.8        d0, [r0], r1
+        regshuffle_d8
+        vld1.8    {d23}, [r2], r3
+        bne 8b
+        subs  r5, #8
+        beq       99f
+        mov r4, r12
+        add r6, #8
+        mov r0, r6
+        add r7, #8
+        mov r2, r7
+        b     0b
+4:      subs r4, #1
+        \filter
+        vmovl.s16     q12, d14      // extending signed 4x16bit data to 4x32 bit
+        vmul.s32      q14, q12, q6
+        vqrshl.s32    q12, q14, q4
+        vadd.s32      q14, q12, q5
+        vqmovun.s32     d14, q14
+        vqmovn.u16     d0,  q7
+        vst1.32    d0[0], [r0], r1
+        regshuffle_d8
+        vld1.32    {d23[0]}, [r2], r3
+        bne 4b
+        b   99f
+.Lbi\@: ldr         r8,   [sp, #120]  // w0
+        vdup.32     q1,   r8          // q1 wx0
+        ldr         r8,   [sp, #124]  // ox0
+        vdup.32     q2,   r8          // q2 ox0
+        vadd.s32    q2,   q5          // q2 = ox0 +ox1
+        vmov.s32    q10,  #1
+        vadd.s32    q2,   q10         // q2 = ox0 +ox1 + 1
+        vneg.s32    q15,  q4          // q15 = - q4, preperation for left shift
+        vqrshl.s32  q3,   q2, q15     // q3 = (ox0 + ox1 + 1)<<shift
+        vsub.s32    q4,   q10
+        ldr         r9,   [sp, #132]  // src2stride
+        lsl         r9,   #1
+        mov         r10,  r11         // r10 store startpoint src2
+0:      loadin8
+        cmp         r5,   #4
+        beq         4f
+8:      subs        r4,   #1
+        \filter
+        vmovl.s16     q12, d14          // extending signed 4x16bit data to 4x32 bit
+        vmovl.s16     q13, d15
+        vmul.s32      q14, q12,     q6  // src * w1
+        vmul.s32      q15, q13,     q6  // src * w1
+        vld1.16       {q0}, [r11],  r9  // load 8x16 bit pixels from src2 to q0
+        vmovl.s16     q2,   d0          // extend signed 4x16bit to 4x32 bit
+        vmovl.s16     q5,   d1
+        vmul.s32      q2,   q1          // src2 * w0
+        vmul.s32      q5,   q1          // src2 * w0
+        vadd.s32      q14,  q2          // src * w1 + src2 * w0
+        vadd.s32      q15,  q5          // src * w1 + src2 * w0
+        vadd.s32      q14,  q3          // (src* w1 + src2 * w0 +(ox0 + ox1 + 1))<<shift
+        vadd.s32      q15,  q3
+        vqshl.s32     q12,  q14, q4     // shift
+        vqshl.s32     q13,  q15, q4     // shift
+        vqmovun.s32   d28,   q12        // narrow
+        vqmovun.s32   d29,   q13        // narrow
+        vqmovn.u16    d0,   q14         // narrow
+        vst1.8        d0,   [r0], r1
+        regshuffle_d8
+        vld1.8    {d23}, [r2], r3
+        bne 8b
+        subs  r5, #8
+        beq   99f
+        mov r4, r12
+        add r6, #8
+        mov r0, r6
+        add r10, #16
+        mov r11, r10
+        add r7, #8
+        mov r2, r7
+        b     0b
+4:      subs r4, #1
+        \filter
+        vmovl.s16    q12, d14
+        vmul.s32     q14, q12, q6
+        vld1.16      d0, [r11], r9
+        vmovl.s16    q2,  d0
+        vmul.s32     q2,  q1
+        vadd.s32     q14, q2
+        vadd.s32     q14, q3
+        vqshl.s32    q12, q14, q4      // shift
+        vqmovun.s32  d28, q12          // narrow
+        vqmovn.u16   d0,  q14          // narrow
+        vst1.32      d0[0], [r0], r1
+        regshuffle_d8
+        vld1.32    {d23[0]}, [r2], r3
+        bne 4b
+99:     vpop {d8-d15}
+        pop {r4-r12}
+        bx lr
+.endm
+
 function ff_hevc_put_qpel_v1_neon_8, export=1
         hevc_put_qpel_vX_neon_8 qpel_filter_1
 endfunc
@@ -358,6 +491,19 @@  function ff_hevc_put_qpel_uw_v3_neon_8, export=1
         hevc_put_qpel_uw_vX_neon_8 qpel_filter_3
 endfunc
 
+function ff_hevc_put_qpel_wt_v1_neon_8, export=1
+        hevc_put_qpel_wt_vX_neon_8 qpel_filter_1
+endfunc
+
+function ff_hevc_put_qpel_wt_v2_neon_8, export=1
+        hevc_put_qpel_wt_vX_neon_8 qpel_filter_2
+endfunc
+
+function ff_hevc_put_qpel_wt_v3_neon_8, export=1
+        hevc_put_qpel_wt_vX_neon_8 qpel_filter_3
+endfunc
+
+
 .macro hevc_put_qpel_hX_neon_8 filter
         push     {r4, r5, r6, r7}
         ldr    r4, [sp, #16] // height
@@ -469,6 +615,135 @@  endfunc
         bx lr
 .endm
 
+.macro hevc_put_qpel_wt_hX_neon_8 filter
+        push     {r4-r12}
+        ldr       r5, [sp, #36] // width
+        ldr       r4, [sp, #40] // height
+        ldr       r8, [sp, #44] // denom
+        ldr       r9, [sp, #48] // wx1
+        ldr       r10,[sp, #52] // ox1
+        ldr       r11,[sp, #64] // src2
+        vpush    {d8-d15}
+        sub       r2, #4
+        mov      r12, r4
+        mov       r6, r0
+        mov       r7, r2
+        add       r8, #6       // weight shift = denom + 6
+        vdup.32   q5, r8       // dup shift to 32 bit
+        vneg.s32  q4, q5       // q4 = -q5 shift
+        vdup.32   q6, r9       // q6 wx
+        vdup.32   q5, r10      // q5 ox
+        cmp       r11, #0      // if src2 != 0 goto bi mode
+        bne       .Lbi\@
+        cmp       r5, #4
+        beq       4f
+8:      subs      r4, #1
+        vextin8
+        \filter
+        vmovl.s16  q12, d14    // extending signed 4x16bit data to 4x32 bit
+        vmovl.s16  q13, d15
+        vmul.s32      q14, q12, q6
+        vmul.s32      q15, q13, q6
+        vqrshl.s32    q12, q14, q4
+        vqrshl.s32    q13, q15, q4
+        vadd.s32      q14, q12, q5
+        vadd.s32      q15, q13, q5
+        vqmovun.s32   d2,  q14       // narrow
+        vqmovun.s32   d3,  q15       // narrow
+        vqmovn.u16    d0,  q1
+        vst1.8    d0, [r0], r1
+        bne       8b
+        subs      r5, #8
+        beq      99f
+        mov       r4, r12
+        add       r6, #8
+        mov       r0, r6
+        add       r7, #8
+        mov       r2, r7
+        cmp       r5, #4
+        bne       8b
+4:      subs      r4, #1
+        vextin8
+        \filter
+        vmovl.s16     q12, d14      // extending signed 4x16bit data to 4x32 bit
+        vmul.s32      q14, q12, q6
+        vqrshl.s32    q12, q14, q4
+        vadd.s32      q14, q12, q5
+        vqmovun.s32   d14, q14
+        vqmovn.u16    d0,  q7
+        vst1.32  d0[0], [r0], r1
+        bne       4b
+        b         99f
+.Lbi\@:
+        ldr         r8,   [sp, #120]  // w0
+        vdup.32     q1,   r8          // q1 wx0
+        ldr         r8,   [sp, #124]  // ox0
+        vdup.32     q2,   r8          // q2 ox0
+        vadd.s32    q2,   q5          // q2 = ox0 +ox1
+        vmov.s32    q10,  #1
+        vadd.s32    q2,   q10         // q2 = ox0 +ox1 + 1
+        vneg.s32    q15,  q4          // q15 = - q4, preperation for left shift
+        vqrshl.s32  q3,   q2, q15     // q3 = (ox0 + ox1 + 1)<<shift
+        vsub.s32    q4,   q10
+        ldr         r9,   [sp, #132]  // src2stride
+        lsl         r9,   #1
+        cmp         r5,   #4
+        beq         4f
+        mov         r10,  r11
+8:      subs        r4,   #1
+        vextin8
+        \filter
+        vmovl.s16     q12, d14      // extending signed 4x16bit data to 4x32 bit
+        vmovl.s16     q13, d15
+        vmul.s32      q14, q12,     q6  // src * w1
+        vmul.s32      q15, q13,     q6  // src * w1
+        vld1.16       {q0}, [r11],  r9  // load 8x16 bit pixels from src2 to q0
+        vmovl.s16     q2,   d0          // extend signed 4x16bit to 4x32 bit
+        vmovl.s16     q5,   d1
+        vmul.s32      q2,   q1          // src2 * w0
+        vmul.s32      q5,   q1          // src2 * w0
+        vadd.s32      q14,  q2          // src * w1 + src2 * w0
+        vadd.s32      q15,  q5          // src * w1 + src2 * w0
+        vadd.s32      q14,  q3          // (src* w1 + src2 * w0 +(ox0 + ox1 + 1))<<shift
+        vadd.s32      q15,  q3
+        vqshl.s32     q12,  q14,     q4 // shift
+        vqshl.s32     q13,  q15,     q4 // shift
+        vqmovun.s32   d28,  q12         // narrow
+        vqmovun.s32   d29,  q13         // narrow
+        vqmovn.u16    d0,   q14         // narrow
+        vst1.8        d0,   [r0], r1
+        bne           8b
+        subs          r5,   #8
+        beq           99f
+        mov           r4,   r12
+        add           r6,   #8
+        add           r10,  #16
+        mov           r11,  r10
+        mov           r0,   r6
+        add           r7,   #8
+        mov           r2,   r7
+        cmp           r5,   #4
+        bne           8b
+4:      subs          r4,   #1
+        vextin8
+        \filter
+        vmovl.s16     q12,  d14
+        vmul.s32      q14,  q12,   q6
+        vld1.16       d0,   [r11], r9
+        vmovl.s16     q2,   d0
+        vmul.s32      q2,   q1
+        vadd.s32      q14,  q2
+        vadd.s32      q14,  q3
+        vqshl.s32     q12,  q14,   q4    // shift
+        vqmovun.s32   d28,  q12          // narrow
+        vqmovn.u16    d0,   q14          // narrow
+        vst1.32       d0[0], [r0], r1
+        bne       4b
+99:     vpop     {d8-d15}
+        pop      {r4-r12}
+        bx lr
+.endm
+
 function ff_hevc_put_qpel_h1_neon_8, export=1
         hevc_put_qpel_hX_neon_8 qpel_filter_1
 endfunc
@@ -494,6 +769,18 @@  function ff_hevc_put_qpel_uw_h3_neon_8, export=1
         hevc_put_qpel_uw_hX_neon_8 qpel_filter_3
 endfunc
 
+function ff_hevc_put_qpel_wt_h1_neon_8, export=1
+        hevc_put_qpel_wt_hX_neon_8 qpel_filter_1
+endfunc
+
+function ff_hevc_put_qpel_wt_h2_neon_8, export=1
+        hevc_put_qpel_wt_hX_neon_8 qpel_filter_2
+endfunc
+
+function ff_hevc_put_qpel_wt_h3_neon_8, export=1
+        hevc_put_qpel_wt_hX_neon_8 qpel_filter_3
+endfunc
+
 .macro hevc_put_qpel_hXvY_neon_8 filterh filterv
         push   {r4, r5, r6, r7}
         ldr    r4, [sp, #16] // height
@@ -665,6 +952,192 @@  endfunc
         bx lr
 .endm
 
+.macro hevc_put_qpel_wt_hXvY_neon_8 filterh filterv
+        push     {r4-r12}
+        ldr       r5, [sp, #36] // width
+        ldr       r4, [sp, #40] // height
+        ldr       r8, [sp, #44] // denom
+        ldr       r9, [sp, #48] // wx
+        ldr       r10,[sp, #52] // ox
+        ldr       r11,[sp, #64] //src2
+        vpush {d8-d15}
+        sub       r2, #4
+        sub       r2, r2, r3, lsl #1
+        sub       r2, r3  // extra_before 3
+        mov       r12, r4
+        mov       r6, r0
+        mov       r7, r2
+        add       r8, #6
+        vdup.32   q6, r8
+        vneg.s32  q5, q6      // q5 shift
+        vdup.32   q4, r9      // q4 wx
+        vdup.32   q6, r10     // q6 ox
+        vpush     {q4-q6}
+        cmp       r11, #0
+        bne       .Lbi\@
+0:      vextin8
+        \filterh q0
+        vextin8
+        \filterh q1
+        vextin8
+        \filterh q2
+        vextin8
+        \filterh q3
+        vextin8
+        \filterh q4
+        vextin8
+        \filterh q5
+        vextin8
+        \filterh q6
+        vextin8
+        \filterh q7
+        cmp r5, #4
+        beq 4f
+8:      subs  r4, #1
+        \filterv
+        vpop            {q9-q11}     // q9: wx q10: shift q11: ox
+        vmovl.s16       q12, d16
+        vmovl.s16       q13, d17
+        vmul.s32        q14, q12, q9
+        vmul.s32        q15, q13, q9
+        vqrshl.s32      q12, q14, q10
+        vqrshl.s32      q13, q15, q10
+        vadd.s32        q14, q12, q11
+        vadd.s32        q15, q13, q11
+        vqmovun.s32     d24, q14
+        vqmovun.s32     d25, q15
+        vqmovn.u16      d0,  q12
+        vst1.8          d0, [r0], r1
+        vpush           {q9-q11}
+        regshuffle_q8
+        vextin8
+        \filterh q7
+        bne 8b
+        subs  r5, #8
+        beq 99f
+        mov r4, r12
+        add r6, #8
+        mov r0, r6
+        add r7, #8
+        mov r2, r7
+        b 0b
+4:      subs  r4, #1
+        \filterv
+        vpop            {q9-q11}     // q9: wx q10: shift q11: ox
+        vmovl.s16       q12, d16
+        vmul.s32        q14, q12, q9
+        vqrshl.s32      q12, q14, q10
+        vadd.s32        q14, q12, q11
+        vqmovun.s32     d24, q14
+        vqmovn.u16      d0,  q12
+        vst1.32         d0[0], [r0], r1
+        vpush           {q9-q11}
+        regshuffle_q8
+        vextin8
+        \filterh q7
+        bne 4b
+        b   99f
+.Lbi\@: ldr         r8,     [sp, #168]  // w0
+        vdup.32     q1,     r8          // q1 wx0
+        ldr         r8,     [sp, #172]  // ox0
+        vdup.32     q3,     r8          // dup ox0 to q3
+        ldr         r9,     [sp, #180]  // src2stride
+        lsl         r9,     #1
+        vpop        {q9-q11}            // q9: wx q10: shift q11: ox
+        vadd.s32    q3,     q11         // q3 = ox0 + ox1
+        vmov.s32    q4,     #1
+        vadd.s32    q3,     q4          // q3 = ox0 + ox1 + 1
+        vneg.s32    q15,    q10         // q15 = -shift, prepare for left shift
+        vqrshl.s32  q2,     q3,     q15 // q2 = (ox0 + ox1 + 1)<<shift
+        vsub.s32    q10,    q4          // q10 final shift = demon + #7
+        vmov.s32    q3,     q10
+        vmov.s32    q4,     q9
+        vpush       {q1-q4}             // q1: wx0, q2: final offset, q3: final shift, q4: wx1
+        mov         r10,    r11         // r10 store startpoint src2
+0:      vextin8
+        \filterh q0
+        vextin8
+        \filterh q1
+        vextin8
+        \filterh q2
+        vextin8
+        \filterh q3
+        vextin8
+        \filterh q4
+        vextin8
+        \filterh q5
+        vextin8
+        \filterh q6
+        vextin8
+        \filterh q7
+        cmp         r5,    #4
+        beq         4f
+8:      subs        r4,    #1
+        \filterv
+        vpop        {q9-q12}            // q9: wx0, q10: final offset, q11: final shift, q4: wx1
+        vmovl.s16   q13,    d16         // move long filter result from q8 to q12
+        vmovl.s16   q14,    d17         // move long filter result from q8 to q13
+        vmul.s32    q13,    q12         // src * wx1
+        vmul.s32    q14,    q12         // src * wx1
+        vld1.16     {q0},   [r11],  r9
+        vmovl.s16   q8,     d0
+        vmovl.s16   q15,    d1
+        vmul.s32    q8,     q9          // src2 * wx0
+        vmul.s32    q15,    q9          // src2 * wx0
+        vadd.s32    q13,    q8          // src * wx1 + src2 * wx0
+        vadd.s32    q14,    q15         // src * wx1 + src2 * wx0
+        vadd.s32    q13,    q10         // src * wx1 + src2 * wx0 + offset
+        vadd.s32    q14,    q10         // src * wx1 + src2 * wx0 + offset
+        vqshl.s32   q8,     q13,    q11 // shift
+        vqshl.s32   q15,    q14,    q11 // shift
+        vqmovun.s32 d28,    q8          // narrow
+        vqmovun.s32 d29,    q15         // narrow
+        vqmovn.u16  d0,     q14         // narrow
+        vst1.8      d0,     [r0],   r1  // store
+        vpush       {q9-q12}            // push
+        regshuffle_q8
+        vextin8
+        \filterh    q7
+        bne         8b
+        subs        r5,     #8
+        beq         98f
+        mov         r4,     r12
+        add         r6,     #8
+        mov         r0,     r6
+        add         r10,    #16
+        mov         r11,    r10
+        add         r7,     #8
+        mov         r2,     r7
+        b           0b
+4:      subs        r4,     #1
+        \filterv
+        vpop        {q9-q12}            // q9: wx0, q10: final offset, q11: final shift, q4: wx1
+        vmovl.s16   q13,    d16         // move long filter result from q8 to q12
+        vmul.s32    q13,    q12         // src * wx1
+        vld1.16     d0,     [r11],  r9
+        vmovl.s16   q8,     d0
+        vmul.s32    q8,     q9          // src2 * wx0
+        vadd.s32    q13,    q8          // src * wx1 + src2 * wx0
+        vadd.s32    q13,    q10         // src * wx1 + src2 * wx0 + offset
+        vqshl.s32   q8,     q13,    q11 // shift
+        vqmovun.s32 d28,    q8          // narrow
+        vqmovn.u16  d0,     q14         // narrow
+        vst1.32     d0[0],  [r0],   r1
+        vpush       {q9-q12}            // push
+        regshuffle_q8
+        vextin8
+        \filterh    q7
+        bne         4b
+98:     vpop {q9-q12}
+        vpop {d8-d15}
+        pop  {r4-r12}
+        bx  lr
+99:     vpop {q9-q11}
+        vpop {d8-d15}
+        pop {r4-r12}
+        bx lr
+.endm
+
 
 function ff_hevc_put_qpel_h1v1_neon_8, export=1
         hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b
@@ -739,6 +1212,42 @@  function ff_hevc_put_qpel_uw_h3v3_neon_8, export=1
         hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b
 endfunc
 
+function ff_hevc_put_qpel_wt_h1v1_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h2v1_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h3v1_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h1v2_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h2v2_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h3v2_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h1v3_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h2v3_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b
+endfunc
+
+function ff_hevc_put_qpel_wt_h3v3_neon_8, export=1
+        hevc_put_qpel_wt_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b
+endfunc
+
 .macro init_put_pixels
         pld    [r1]
         pld    [r1, r2]