...
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
OBJS += aarch64/rgb2rgb.o \
|
||||
aarch64/swscale.o \
|
||||
aarch64/swscale_unscaled.o \
|
||||
|
||||
NEON-OBJS += aarch64/hscale.o \
|
||||
aarch64/input.o \
|
||||
aarch64/output.o \
|
||||
aarch64/range_convert_neon.o \
|
||||
aarch64/rgb2rgb_neon.o \
|
||||
aarch64/swscale_unscaled_neon.o \
|
||||
aarch64/yuv2rgb_neon.o \
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Zhao Zhili <quinkblack@foxmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/aarch64/asm.S"
|
||||
|
||||
.macro rgb_to_yuv_load_rgb src, element=3
|
||||
.if \element == 3
|
||||
ld3 { v16.16b, v17.16b, v18.16b }, [\src]
|
||||
.else
|
||||
ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [\src]
|
||||
.endif
|
||||
uxtl v19.8h, v16.8b // v19: r
|
||||
uxtl v20.8h, v17.8b // v20: g
|
||||
uxtl v21.8h, v18.8b // v21: b
|
||||
uxtl2 v22.8h, v16.16b // v22: r
|
||||
uxtl2 v23.8h, v17.16b // v23: g
|
||||
uxtl2 v24.8h, v18.16b // v24: b
|
||||
.endm
|
||||
|
||||
.macro argb_to_yuv_load_rgb src
|
||||
ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [\src]
|
||||
uxtl v21.8h, v19.8b // v21: b
|
||||
uxtl2 v24.8h, v19.16b // v24: b
|
||||
uxtl v19.8h, v17.8b // v19: r
|
||||
uxtl v20.8h, v18.8b // v20: g
|
||||
uxtl2 v22.8h, v17.16b // v22: r
|
||||
uxtl2 v23.8h, v18.16b // v23: g
|
||||
.endm
|
||||
|
||||
.macro rgb_to_yuv_product r, g, b, dst1, dst2, dst, coef0, coef1, coef2, right_shift
|
||||
mov \dst1\().16b, v6.16b // dst1 = const_offset
|
||||
mov \dst2\().16b, v6.16b // dst2 = const_offset
|
||||
smlal \dst1\().4s, \coef0\().4h, \r\().4h // dst1 += rx * r
|
||||
smlal \dst1\().4s, \coef1\().4h, \g\().4h // dst1 += gx * g
|
||||
smlal \dst1\().4s, \coef2\().4h, \b\().4h // dst1 += bx * b
|
||||
smlal2 \dst2\().4s, \coef0\().8h, \r\().8h // dst2 += rx * r
|
||||
smlal2 \dst2\().4s, \coef1\().8h, \g\().8h // dst2 += gx * g
|
||||
smlal2 \dst2\().4s, \coef2\().8h, \b\().8h // dst2 += bx * b
|
||||
sqshrn \dst\().4h, \dst1\().4s, \right_shift // dst_lower_half = dst1 >> right_shift
|
||||
sqshrn2 \dst\().8h, \dst2\().4s, \right_shift // dst_higher_half = dst2 >> right_shift
|
||||
.endm
|
||||
|
||||
.macro rgbToY_neon fmt_bgr, fmt_rgb, element, alpha_first=0
|
||||
function ff_\fmt_bgr\()ToY_neon, export=1
|
||||
cmp w4, #0 // check width > 0
|
||||
ldp w12, w11, [x5] // w12: ry, w11: gy
|
||||
ldr w10, [x5, #8] // w10: by
|
||||
b.gt 4f
|
||||
ret
|
||||
endfunc
|
||||
|
||||
function ff_\fmt_rgb\()ToY_neon, export=1
|
||||
cmp w4, #0 // check width > 0
|
||||
ldp w10, w11, [x5] // w10: ry, w11: gy
|
||||
ldr w12, [x5, #8] // w12: by
|
||||
b.le 3f
|
||||
4:
|
||||
mov w9, #256 // w9 = 1 << (RGB2YUV_SHIFT - 7)
|
||||
movk w9, #8, lsl #16 // w9 += 32 << (RGB2YUV_SHIFT - 1)
|
||||
dup v6.4s, w9 // w9: const_offset
|
||||
|
||||
cmp w4, #16
|
||||
dup v0.8h, w10
|
||||
dup v1.8h, w11
|
||||
dup v2.8h, w12
|
||||
b.lt 2f
|
||||
1:
|
||||
.if \alpha_first
|
||||
argb_to_yuv_load_rgb x1
|
||||
.else
|
||||
rgb_to_yuv_load_rgb x1, \element
|
||||
.endif
|
||||
rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9
|
||||
rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9
|
||||
sub w4, w4, #16 // width -= 16
|
||||
add x1, x1, #(16*\element)
|
||||
cmp w4, #16 // width >= 16 ?
|
||||
stp q16, q17, [x0], #32 // store to dst
|
||||
b.ge 1b
|
||||
cbz x4, 3f
|
||||
2:
|
||||
.if \alpha_first
|
||||
ldrb w13, [x1, #1] // w13: r
|
||||
ldrb w14, [x1, #2] // w14: g
|
||||
ldrb w15, [x1, #3] // w15: b
|
||||
.else
|
||||
ldrb w13, [x1] // w13: r
|
||||
ldrb w14, [x1, #1] // w14: g
|
||||
ldrb w15, [x1, #2] // w15: b
|
||||
.endif
|
||||
|
||||
smaddl x13, w13, w10, x9 // x13 = ry * r + const_offset
|
||||
smaddl x13, w14, w11, x13 // x13 += gy * g
|
||||
smaddl x13, w15, w12, x13 // x13 += by * b
|
||||
asr w13, w13, #9 // x13 >>= 9
|
||||
sub w4, w4, #1 // width--
|
||||
add x1, x1, #\element
|
||||
strh w13, [x0], #2 // store to dst
|
||||
cbnz w4, 2b
|
||||
3:
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
rgbToY_neon bgr24, rgb24, element=3
|
||||
|
||||
rgbToY_neon bgra32, rgba32, element=4
|
||||
|
||||
rgbToY_neon abgr32, argb32, element=4, alpha_first=1
|
||||
|
||||
.macro rgb_set_uv_coeff half
|
||||
.if \half
|
||||
mov w9, #512
|
||||
movk w9, #128, lsl #16 // w9: const_offset
|
||||
.else
|
||||
mov w9, #256
|
||||
movk w9, #64, lsl #16 // w9: const_offset
|
||||
.endif
|
||||
dup v0.8h, w10
|
||||
dup v1.8h, w11
|
||||
dup v2.8h, w12
|
||||
dup v3.8h, w13
|
||||
dup v4.8h, w14
|
||||
dup v5.8h, w15
|
||||
dup v6.4s, w9
|
||||
.endm
|
||||
|
||||
.macro rgb_load_add_half off_r1, off_r2, off_g1, off_g2, off_b1, off_b2
|
||||
ldrb w2, [x3, #\off_r1] // w2: r1
|
||||
ldrb w4, [x3, #\off_r2] // w4: r2
|
||||
add w2, w2, w4 // w2 = r1 + r2
|
||||
|
||||
ldrb w4, [x3, #\off_g1] // w4: g1
|
||||
ldrb w7, [x3, #\off_g2] // w7: g2
|
||||
add w4, w4, w7 // w4 = g1 + g2
|
||||
|
||||
ldrb w7, [x3, #\off_b1] // w7: b1
|
||||
ldrb w8, [x3, #\off_b2] // w8: b2
|
||||
add w7, w7, w8 // w7 = b1 + b2
|
||||
.endm
|
||||
|
||||
.macro rgbToUV_half_neon fmt_bgr, fmt_rgb, element, alpha_first=0
|
||||
function ff_\fmt_bgr\()ToUV_half_neon, export=1
|
||||
cmp w5, #0 // check width > 0
|
||||
b.le 3f
|
||||
|
||||
ldp w12, w11, [x6, #12]
|
||||
ldp w10, w15, [x6, #20]
|
||||
ldp w14, w13, [x6, #28]
|
||||
b 4f
|
||||
endfunc
|
||||
|
||||
function ff_\fmt_rgb\()ToUV_half_neon, export=1
|
||||
cmp w5, #0 // check width > 0
|
||||
b.le 3f
|
||||
|
||||
ldp w10, w11, [x6, #12] // w10: ru, w11: gu
|
||||
ldp w12, w13, [x6, #20] // w12: bu, w13: rv
|
||||
ldp w14, w15, [x6, #28] // w14: gv, w15: bv
|
||||
4:
|
||||
cmp w5, #8
|
||||
rgb_set_uv_coeff half=1
|
||||
b.lt 2f
|
||||
1:
|
||||
.if \element == 3
|
||||
ld3 { v16.16b, v17.16b, v18.16b }, [x3]
|
||||
.else
|
||||
ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [x3]
|
||||
.endif
|
||||
.if \alpha_first
|
||||
uaddlp v21.8h, v19.16b
|
||||
uaddlp v20.8h, v18.16b
|
||||
uaddlp v19.8h, v17.16b
|
||||
.else
|
||||
uaddlp v19.8h, v16.16b // v19: r
|
||||
uaddlp v20.8h, v17.16b // v20: g
|
||||
uaddlp v21.8h, v18.16b // v21: b
|
||||
.endif
|
||||
|
||||
rgb_to_yuv_product v19, v20, v21, v22, v23, v16, v0, v1, v2, #10
|
||||
rgb_to_yuv_product v19, v20, v21, v24, v25, v17, v3, v4, v5, #10
|
||||
sub w5, w5, #8 // width -= 8
|
||||
add x3, x3, #(16*\element)
|
||||
cmp w5, #8 // width >= 8 ?
|
||||
str q16, [x0], #16 // store dst_u
|
||||
str q17, [x1], #16 // store dst_v
|
||||
b.ge 1b
|
||||
cbz w5, 3f
|
||||
2:
|
||||
.if \alpha_first
|
||||
rgb_load_add_half 1, 5, 2, 6, 3, 7
|
||||
.else
|
||||
.if \element == 3
|
||||
rgb_load_add_half 0, 3, 1, 4, 2, 5
|
||||
.else
|
||||
rgb_load_add_half 0, 4, 1, 5, 2, 6
|
||||
.endif
|
||||
.endif
|
||||
|
||||
smaddl x8, w2, w10, x9 // dst_u = ru * r + const_offset
|
||||
smaddl x8, w4, w11, x8 // dst_u += gu * g
|
||||
smaddl x8, w7, w12, x8 // dst_u += bu * b
|
||||
asr x8, x8, #10 // dst_u >>= 10
|
||||
strh w8, [x0], #2 // store dst_u
|
||||
|
||||
smaddl x8, w2, w13, x9 // dst_v = rv * r + const_offset
|
||||
smaddl x8, w4, w14, x8 // dst_v += gv * g
|
||||
smaddl x8, w7, w15, x8 // dst_v += bv * b
|
||||
asr x8, x8, #10 // dst_v >>= 10
|
||||
sub w5, w5, #1
|
||||
add x3, x3, #(2*\element)
|
||||
strh w8, [x1], #2 // store dst_v
|
||||
cbnz w5, 2b
|
||||
3:
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
rgbToUV_half_neon bgr24, rgb24, element=3
|
||||
|
||||
rgbToUV_half_neon bgra32, rgba32, element=4
|
||||
|
||||
rgbToUV_half_neon abgr32, argb32, element=4, alpha_first=1
|
||||
|
||||
.macro rgbToUV_neon fmt_bgr, fmt_rgb, element, alpha_first=0
|
||||
function ff_\fmt_bgr\()ToUV_neon, export=1
|
||||
cmp w5, #0 // check width > 0
|
||||
b.le 3f
|
||||
|
||||
ldp w12, w11, [x6, #12]
|
||||
ldp w10, w15, [x6, #20]
|
||||
ldp w14, w13, [x6, #28]
|
||||
b 4f
|
||||
endfunc
|
||||
|
||||
function ff_\fmt_rgb\()ToUV_neon, export=1
|
||||
cmp w5, #0 // check width > 0
|
||||
b.le 3f
|
||||
|
||||
ldp w10, w11, [x6, #12] // w10: ru, w11: gu
|
||||
ldp w12, w13, [x6, #20] // w12: bu, w13: rv
|
||||
ldp w14, w15, [x6, #28] // w14: gv, w15: bv
|
||||
4:
|
||||
cmp w5, #16
|
||||
rgb_set_uv_coeff half=0
|
||||
b.lt 2f
|
||||
1:
|
||||
.if \alpha_first
|
||||
argb_to_yuv_load_rgb x3
|
||||
.else
|
||||
rgb_to_yuv_load_rgb x3, \element
|
||||
.endif
|
||||
rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9
|
||||
rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9
|
||||
rgb_to_yuv_product v19, v20, v21, v25, v26, v18, v3, v4, v5, #9
|
||||
rgb_to_yuv_product v22, v23, v24, v27, v28, v19, v3, v4, v5, #9
|
||||
sub w5, w5, #16
|
||||
add x3, x3, #(16*\element)
|
||||
cmp w5, #16
|
||||
stp q16, q17, [x0], #32 // store to dst_u
|
||||
stp q18, q19, [x1], #32 // store to dst_v
|
||||
b.ge 1b
|
||||
cbz w5, 3f
|
||||
2:
|
||||
.if \alpha_first
|
||||
ldrb w16, [x3, #1] // w16: r
|
||||
ldrb w17, [x3, #2] // w17: g
|
||||
ldrb w4, [x3, #3] // w4: b
|
||||
.else
|
||||
ldrb w16, [x3] // w16: r
|
||||
ldrb w17, [x3, #1] // w17: g
|
||||
ldrb w4, [x3, #2] // w4: b
|
||||
.endif
|
||||
|
||||
smaddl x8, w16, w10, x9 // x8 = ru * r + const_offset
|
||||
smaddl x8, w17, w11, x8 // x8 += gu * g
|
||||
smaddl x8, w4, w12, x8 // x8 += bu * b
|
||||
asr w8, w8, #9 // x8 >>= 9
|
||||
strh w8, [x0], #2 // store to dst_u
|
||||
|
||||
smaddl x8, w16, w13, x9 // x8 = rv * r + const_offset
|
||||
smaddl x8, w17, w14, x8 // x8 += gv * g
|
||||
smaddl x8, w4, w15, x8 // x8 += bv * b
|
||||
asr w8, w8, #9 // x8 >>= 9
|
||||
sub w5, w5, #1 // width--
|
||||
add x3, x3, #\element
|
||||
strh w8, [x1], #2 // store to dst_v
|
||||
cbnz w5, 2b
|
||||
3:
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
rgbToUV_neon bgr24, rgb24, element=3
|
||||
|
||||
rgbToUV_neon bgra32, rgba32, element=4
|
||||
|
||||
rgbToUV_neon abgr32, argb32, element=4, alpha_first=1
|
||||
|
||||
#if HAVE_DOTPROD
|
||||
ENABLE_DOTPROD
|
||||
|
||||
function ff_bgra32ToY_neon_dotprod, export=1
|
||||
cmp w4, #0 // check width > 0
|
||||
ldp w12, w11, [x5] // w12: ry, w11: gy
|
||||
ldr w10, [x5, #8] // w10: by
|
||||
b.gt 4f
|
||||
ret
|
||||
endfunc
|
||||
|
||||
function ff_rgba32ToY_neon_dotprod, export=1
|
||||
cmp w4, #0 // check width > 0
|
||||
ldp w10, w11, [x5] // w10: ry, w11: gy
|
||||
ldr w12, [x5, #8] // w12: by
|
||||
b.le 3f
|
||||
4:
|
||||
mov w9, #256 // w9 = 1 << (RGB2YUV_SHIFT - 7)
|
||||
movk w9, #8, lsl #16 // w9 += 32 << (RGB2YUV_SHIFT - 1)
|
||||
dup v6.4s, w9 // w9: const_offset
|
||||
|
||||
cmp w4, #16
|
||||
mov w7, w10
|
||||
bfi w7, w11, 8, 8 // the bfi instructions are used to assemble
|
||||
bfi w7, w12, 16, 8 // 4 byte r,g,b,0 mask to be then used by udot.
|
||||
dup v0.4s, w7 // v0 holds the lower byte of each coefficient
|
||||
|
||||
lsr w6, w10, #8
|
||||
lsr w7, w11, #8
|
||||
lsr w8, w12, #8
|
||||
|
||||
bfi w6, w7, 8, 8
|
||||
bfi w6, w8, 16, 8
|
||||
dup v1.4s, w6 // v1 holds the upper byte of each coefficient
|
||||
b.lt 2f
|
||||
1:
|
||||
ld1 { v16.16b, v17.16b, v18.16b, v19.16b }, [x1], #64
|
||||
sub w4, w4, #16 // width -= 16
|
||||
|
||||
mov v2.16b, v6.16b
|
||||
mov v3.16b, v6.16b
|
||||
mov v4.16b, v6.16b
|
||||
mov v5.16b, v6.16b
|
||||
cmp w4, #16 // width >= 16 ?
|
||||
|
||||
udot v2.4s, v16.16b, v0.16b
|
||||
udot v3.4s, v17.16b, v0.16b
|
||||
udot v4.4s, v18.16b, v0.16b
|
||||
udot v5.4s, v19.16b, v0.16b
|
||||
|
||||
ushr v2.4s, v2.4s, #8
|
||||
ushr v3.4s, v3.4s, #8
|
||||
ushr v4.4s, v4.4s, #8
|
||||
ushr v5.4s, v5.4s, #8
|
||||
|
||||
udot v2.4s, v16.16b, v1.16b
|
||||
udot v3.4s, v17.16b, v1.16b
|
||||
udot v4.4s, v18.16b, v1.16b
|
||||
udot v5.4s, v19.16b, v1.16b
|
||||
|
||||
sqshrn v16.4h, v2.4s, #1
|
||||
sqshrn2 v16.8h, v3.4s, #1
|
||||
sqshrn v17.4h, v4.4s, #1
|
||||
sqshrn2 v17.8h, v5.4s, #1
|
||||
|
||||
stp q16, q17, [x0], #32 // store to dst
|
||||
b.ge 1b
|
||||
cbz x4, 3f
|
||||
2:
|
||||
ldrb w13, [x1] // w13: r
|
||||
ldrb w14, [x1, #1] // w14: g
|
||||
ldrb w15, [x1, #2] // w15: b
|
||||
|
||||
smaddl x13, w13, w10, x9 // x13 = ry * r + const_offset
|
||||
smaddl x13, w14, w11, x13 // x13 += gy * g
|
||||
smaddl x13, w15, w12, x13 // x13 += by * b
|
||||
asr w13, w13, #9 // x13 >>= 9
|
||||
sub w4, w4, #1 // width--
|
||||
add x1, x1, #4
|
||||
strh w13, [x0], #2 // store to dst
|
||||
cbnz w4, 2b
|
||||
3:
|
||||
ret
|
||||
endfunc
|
||||
|
||||
DISABLE_DOTPROD
|
||||
#endif
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Clément Bœsch <clement stupeflix.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/aarch64/asm.S"
|
||||
|
||||
function ff_yuv2planeX_8_neon, export=1
|
||||
// x0 - const int16_t *filter,
|
||||
// x1 - int filterSize,
|
||||
// x2 - const int16_t **src,
|
||||
// x3 - uint8_t *dest,
|
||||
// w4 - int dstW,
|
||||
// x5 - const uint8_t *dither,
|
||||
// w6 - int offset
|
||||
|
||||
ld1 {v0.8b}, [x5] // load 8x8-bit dither
|
||||
and w6, w6, #7
|
||||
cbz w6, 1f // check if offsetting present
|
||||
ext v0.8b, v0.8b, v0.8b, #3 // honor offsetting which can be 0 or 3 only
|
||||
1: uxtl v0.8h, v0.8b // extend dither to 16-bit
|
||||
ushll v1.4s, v0.4h, #12 // extend dither to 32-bit with left shift by 12 (part 1)
|
||||
ushll2 v2.4s, v0.8h, #12 // extend dither to 32-bit with left shift by 12 (part 2)
|
||||
cmp w1, #8 // if filterSize == 8, branch to specialized version
|
||||
b.eq 6f
|
||||
cmp w1, #4 // if filterSize == 4, branch to specialized version
|
||||
b.eq 8f
|
||||
cmp w1, #2 // if filterSize == 2, branch to specialized version
|
||||
b.eq 10f
|
||||
|
||||
// The filter size does not match of the of specialized implementations. It is either even or odd. If it is even
|
||||
// then use the first section below.
|
||||
mov x7, #0 // i = 0
|
||||
tbnz w1, #0, 4f // if filterSize % 2 != 0 branch to specialized version
|
||||
// fs % 2 == 0
|
||||
2: mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
|
||||
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
|
||||
mov w8, w1 // tmpfilterSize = filterSize
|
||||
mov x9, x2 // srcp = src
|
||||
mov x10, x0 // filterp = filter
|
||||
3: ldp x11, x12, [x9], #16 // get 2 pointers: src[j] and src[j+1]
|
||||
ldr s7, [x10], #4 // read 2x16-bit coeff X and Y at filter[j] and filter[j+1]
|
||||
add x11, x11, x7, lsl #1 // &src[j ][i]
|
||||
add x12, x12, x7, lsl #1 // &src[j+1][i]
|
||||
ld1 {v5.8h}, [x11] // read 8x16-bit @ src[j ][i + {0..7}]: A,B,C,D,E,F,G,H
|
||||
ld1 {v6.8h}, [x12] // read 8x16-bit @ src[j+1][i + {0..7}]: I,J,K,L,M,N,O,P
|
||||
smlal v3.4s, v5.4h, v7.h[0] // val0 += {A,B,C,D} * X
|
||||
smlal2 v4.4s, v5.8h, v7.h[0] // val1 += {E,F,G,H} * X
|
||||
smlal v3.4s, v6.4h, v7.h[1] // val0 += {I,J,K,L} * Y
|
||||
smlal2 v4.4s, v6.8h, v7.h[1] // val1 += {M,N,O,P} * Y
|
||||
subs w8, w8, #2 // tmpfilterSize -= 2
|
||||
b.gt 3b // loop until filterSize consumed
|
||||
|
||||
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
|
||||
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
|
||||
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
|
||||
st1 {v3.8b}, [x3], #8 // write to destination
|
||||
subs w4, w4, #8 // dstW -= 8
|
||||
add x7, x7, #8 // i += 8
|
||||
b.gt 2b // loop until width consumed
|
||||
ret
|
||||
|
||||
// If filter size is odd (most likely == 1), then use this section.
|
||||
// fs % 2 != 0
|
||||
4: mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
|
||||
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
|
||||
mov w8, w1 // tmpfilterSize = filterSize
|
||||
mov x9, x2 // srcp = src
|
||||
mov x10, x0 // filterp = filter
|
||||
5: ldr x11, [x9], #8 // get 1 pointer: src[j]
|
||||
ldr h6, [x10], #2 // read 1 16 bit coeff X at filter[j]
|
||||
add x11, x11, x7, lsl #1 // &src[j ][i]
|
||||
ld1 {v5.8h}, [x11] // read 8x16-bit @ src[j ][i + {0..7}]: A,B,C,D,E,F,G,H
|
||||
smlal v3.4s, v5.4h, v6.h[0] // val0 += {A,B,C,D} * X
|
||||
smlal2 v4.4s, v5.8h, v6.h[0] // val1 += {E,F,G,H} * X
|
||||
subs w8, w8, #1 // tmpfilterSize -= 2
|
||||
b.gt 5b // loop until filterSize consumed
|
||||
|
||||
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
|
||||
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
|
||||
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
|
||||
st1 {v3.8b}, [x3], #8 // write to destination
|
||||
subs w4, w4, #8 // dstW -= 8
|
||||
add x7, x7, #8 // i += 8
|
||||
b.gt 4b // loop until width consumed
|
||||
ret
|
||||
|
||||
6: // fs=8
|
||||
ldp x5, x6, [x2] // load 2 pointers: src[j ] and src[j+1]
|
||||
ldp x7, x9, [x2, #16] // load 2 pointers: src[j+2] and src[j+3]
|
||||
ldp x10, x11, [x2, #32] // load 2 pointers: src[j+4] and src[j+5]
|
||||
ldp x12, x13, [x2, #48] // load 2 pointers: src[j+6] and src[j+7]
|
||||
|
||||
// load 8x16-bit values for filter[j], where j=0..7
|
||||
ld1 {v6.8h}, [x0]
|
||||
7:
|
||||
mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
|
||||
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
|
||||
|
||||
ld1 {v24.8h}, [x5], #16 // load 8x16-bit values for src[j + 0][i + {0..7}]
|
||||
ld1 {v25.8h}, [x6], #16 // load 8x16-bit values for src[j + 1][i + {0..7}]
|
||||
ld1 {v26.8h}, [x7], #16 // load 8x16-bit values for src[j + 2][i + {0..7}]
|
||||
ld1 {v27.8h}, [x9], #16 // load 8x16-bit values for src[j + 3][i + {0..7}]
|
||||
ld1 {v28.8h}, [x10], #16 // load 8x16-bit values for src[j + 4][i + {0..7}]
|
||||
ld1 {v29.8h}, [x11], #16 // load 8x16-bit values for src[j + 5][i + {0..7}]
|
||||
ld1 {v30.8h}, [x12], #16 // load 8x16-bit values for src[j + 6][i + {0..7}]
|
||||
ld1 {v31.8h}, [x13], #16 // load 8x16-bit values for src[j + 7][i + {0..7}]
|
||||
|
||||
smlal v3.4s, v24.4h, v6.h[0] // val0 += src[0][i + {0..3}] * filter[0]
|
||||
smlal2 v4.4s, v24.8h, v6.h[0] // val1 += src[0][i + {4..7}] * filter[0]
|
||||
smlal v3.4s, v25.4h, v6.h[1] // val0 += src[1][i + {0..3}] * filter[1]
|
||||
smlal2 v4.4s, v25.8h, v6.h[1] // val1 += src[1][i + {4..7}] * filter[1]
|
||||
smlal v3.4s, v26.4h, v6.h[2] // val0 += src[2][i + {0..3}] * filter[2]
|
||||
smlal2 v4.4s, v26.8h, v6.h[2] // val1 += src[2][i + {4..7}] * filter[2]
|
||||
smlal v3.4s, v27.4h, v6.h[3] // val0 += src[3][i + {0..3}] * filter[3]
|
||||
smlal2 v4.4s, v27.8h, v6.h[3] // val1 += src[3][i + {4..7}] * filter[3]
|
||||
smlal v3.4s, v28.4h, v6.h[4] // val0 += src[4][i + {0..3}] * filter[4]
|
||||
smlal2 v4.4s, v28.8h, v6.h[4] // val1 += src[4][i + {4..7}] * filter[4]
|
||||
smlal v3.4s, v29.4h, v6.h[5] // val0 += src[5][i + {0..3}] * filter[5]
|
||||
smlal2 v4.4s, v29.8h, v6.h[5] // val1 += src[5][i + {4..7}] * filter[5]
|
||||
smlal v3.4s, v30.4h, v6.h[6] // val0 += src[6][i + {0..3}] * filter[6]
|
||||
smlal2 v4.4s, v30.8h, v6.h[6] // val1 += src[6][i + {4..7}] * filter[6]
|
||||
smlal v3.4s, v31.4h, v6.h[7] // val0 += src[7][i + {0..3}] * filter[7]
|
||||
smlal2 v4.4s, v31.8h, v6.h[7] // val1 += src[7][i + {4..7}] * filter[7]
|
||||
|
||||
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
|
||||
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
|
||||
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
|
||||
subs w4, w4, #8 // dstW -= 8
|
||||
st1 {v3.8b}, [x3], #8 // write to destination
|
||||
b.gt 7b // loop until width consumed
|
||||
ret
|
||||
|
||||
8: // fs=4
|
||||
ldp x5, x6, [x2] // load 2 pointers: src[j ] and src[j+1]
|
||||
ldp x7, x9, [x2, #16] // load 2 pointers: src[j+2] and src[j+3]
|
||||
|
||||
// load 4x16-bit values for filter[j], where j=0..3 and replicated across lanes
|
||||
ld1 {v6.4h}, [x0]
|
||||
9:
|
||||
mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
|
||||
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
|
||||
|
||||
ld1 {v24.8h}, [x5], #16 // load 8x16-bit values for src[j + 0][i + {0..7}]
|
||||
ld1 {v25.8h}, [x6], #16 // load 8x16-bit values for src[j + 1][i + {0..7}]
|
||||
ld1 {v26.8h}, [x7], #16 // load 8x16-bit values for src[j + 2][i + {0..7}]
|
||||
ld1 {v27.8h}, [x9], #16 // load 8x16-bit values for src[j + 3][i + {0..7}]
|
||||
|
||||
smlal v3.4s, v24.4h, v6.h[0] // val0 += src[0][i + {0..3}] * filter[0]
|
||||
smlal2 v4.4s, v24.8h, v6.h[0] // val1 += src[0][i + {4..7}] * filter[0]
|
||||
smlal v3.4s, v25.4h, v6.h[1] // val0 += src[1][i + {0..3}] * filter[1]
|
||||
smlal2 v4.4s, v25.8h, v6.h[1] // val1 += src[1][i + {4..7}] * filter[1]
|
||||
smlal v3.4s, v26.4h, v6.h[2] // val0 += src[2][i + {0..3}] * filter[2]
|
||||
smlal2 v4.4s, v26.8h, v6.h[2] // val1 += src[2][i + {4..7}] * filter[2]
|
||||
smlal v3.4s, v27.4h, v6.h[3] // val0 += src[3][i + {0..3}] * filter[3]
|
||||
smlal2 v4.4s, v27.8h, v6.h[3] // val1 += src[3][i + {4..7}] * filter[3]
|
||||
|
||||
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
|
||||
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
|
||||
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
|
||||
st1 {v3.8b}, [x3], #8 // write to destination
|
||||
subs w4, w4, #8 // dstW -= 8
|
||||
b.gt 9b // loop until width consumed
|
||||
ret
|
||||
|
||||
10: // fs=2
|
||||
ldp x5, x6, [x2] // load 2 pointers: src[j ] and src[j+1]
|
||||
|
||||
// load 2x16-bit values for filter[j], where j=0..1 and replicated across lanes
|
||||
ldr s6, [x0]
|
||||
11:
|
||||
mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
|
||||
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
|
||||
|
||||
ld1 {v24.8h}, [x5], #16 // load 8x16-bit values for src[j + 0][i + {0..7}]
|
||||
ld1 {v25.8h}, [x6], #16 // load 8x16-bit values for src[j + 1][i + {0..7}]
|
||||
|
||||
smlal v3.4s, v24.4h, v6.h[0] // val0 += src[0][i + {0..3}] * filter[0]
|
||||
smlal2 v4.4s, v24.8h, v6.h[0] // val1 += src[0][i + {4..7}] * filter[0]
|
||||
smlal v3.4s, v25.4h, v6.h[1] // val0 += src[1][i + {0..3}] * filter[1]
|
||||
smlal2 v4.4s, v25.8h, v6.h[1] // val1 += src[1][i + {4..7}] * filter[1]
|
||||
|
||||
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
|
||||
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
|
||||
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
|
||||
st1 {v3.8b}, [x3], #8 // write to destination
|
||||
subs w4, w4, #8 // dstW -= 8
|
||||
b.gt 11b // loop until width consumed
|
||||
ret
|
||||
endfunc
|
||||
|
||||
function ff_yuv2plane1_8_neon, export=1
|
||||
// x0 - const int16_t *src,
|
||||
// x1 - uint8_t *dest,
|
||||
// w2 - int dstW,
|
||||
// x3 - const uint8_t *dither,
|
||||
// w4 - int offset
|
||||
ld1 {v0.8b}, [x3] // load 8x8-bit dither
|
||||
and w4, w4, #7
|
||||
cbz w4, 1f // check if offsetting present
|
||||
ext v0.8b, v0.8b, v0.8b, #3 // honor offsetting which can be 0 or 3 only
|
||||
1:
|
||||
uxtl v0.8h, v0.8b // extend dither to 32-bit
|
||||
2:
|
||||
ld1 {v3.8h}, [x0], #16 // read 8x16-bit @ src[j ][i + {0..7}]: A,B,C,D,E,F,G,H
|
||||
subs w2, w2, #8 // dstW -= 8
|
||||
shadd v1.8h, v0.8h, v3.8h // v1 = (v0 + v3) >> 1
|
||||
sqshrun v2.8b, v1.8h, #6 // clip_uint8(v1 >> 6)
|
||||
|
||||
st1 {v2.8b}, [x1], #8 // write to destination
|
||||
b.gt 2b // loop until width consumed
|
||||
ret
|
||||
endfunc
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Ramiro Polla
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/aarch64/asm.S"
|
||||
|
||||
.macro lumConvertRange fromto, bit_depth
|
||||
function ff_lumRange\fromto\()Jpeg\bit_depth\()_neon, export=1
|
||||
// x0 int16_t *dst
|
||||
// w1 int width
|
||||
// w2 uint32_t coeff
|
||||
// x3 int64_t offset
|
||||
.if \bit_depth == 16
|
||||
.ifc \fromto, To
|
||||
movi v25.4s, #1
|
||||
movi v24.4s, #1<<3, lsl #16
|
||||
sub v24.4s, v24.4s, v25.4s
|
||||
.endif
|
||||
dup v25.4s, w2
|
||||
dup v26.2d, x3
|
||||
1:
|
||||
ld1 {v0.4s, v1.4s}, [x0]
|
||||
mov v16.16b, v26.16b
|
||||
mov v17.16b, v26.16b
|
||||
mov v18.16b, v26.16b
|
||||
mov v19.16b, v26.16b
|
||||
smlal v16.2d, v0.2s, v25.2s
|
||||
smlal2 v17.2d, v0.4s, v25.4s
|
||||
smlal v18.2d, v1.2s, v25.2s
|
||||
smlal2 v19.2d, v1.4s, v25.4s
|
||||
shrn v0.2s, v16.2d, 18
|
||||
shrn2 v0.4s, v17.2d, 18
|
||||
shrn v1.2s, v18.2d, 18
|
||||
shrn2 v1.4s, v19.2d, 18
|
||||
subs w1, w1, #8
|
||||
.ifc \fromto, To
|
||||
smin v0.4s, v0.4s, v24.4s
|
||||
smin v1.4s, v1.4s, v24.4s
|
||||
.endif
|
||||
st1 {v0.4s, v1.4s}, [x0], #32
|
||||
b.gt 1b
|
||||
.else
|
||||
dup v25.4s, w2
|
||||
dup v26.4s, w3
|
||||
1:
|
||||
ld1 {v0.8h}, [x0]
|
||||
mov v16.16b, v26.16b
|
||||
mov v18.16b, v26.16b
|
||||
sxtl v20.4s, v0.4h
|
||||
sxtl2 v22.4s, v0.8h
|
||||
mla v16.4s, v20.4s, v25.4s
|
||||
mla v18.4s, v22.4s, v25.4s
|
||||
.ifc \fromto, To
|
||||
sqshrn v0.4h, v16.4s, 14
|
||||
sqshrn2 v0.8h, v18.4s, 14
|
||||
.else
|
||||
shrn v0.4h, v16.4s, 14
|
||||
shrn2 v0.8h, v18.4s, 14
|
||||
.endif
|
||||
subs w1, w1, #8
|
||||
st1 {v0.8h}, [x0], #16
|
||||
b.gt 1b
|
||||
.endif
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
.macro chrConvertRange fromto, bit_depth
|
||||
function ff_chrRange\fromto\()Jpeg\bit_depth\()_neon, export=1
|
||||
// x0 int16_t *dstU
|
||||
// x1 int16_t *dstV
|
||||
// w2 int width
|
||||
// w3 uint32_t coeff
|
||||
// x4 int64_t offset
|
||||
.if \bit_depth == 16
|
||||
.ifc \fromto, To
|
||||
movi v25.4s, #1
|
||||
movi v24.4s, #1<<3, lsl #16
|
||||
sub v24.4s, v24.4s, v25.4s
|
||||
.endif
|
||||
dup v25.4s, w3
|
||||
dup v26.2d, x4
|
||||
1:
|
||||
ld1 {v0.4s, v1.4s}, [x0]
|
||||
ld1 {v2.4s, v3.4s}, [x1]
|
||||
mov v16.16b, v26.16b
|
||||
mov v17.16b, v26.16b
|
||||
mov v18.16b, v26.16b
|
||||
mov v19.16b, v26.16b
|
||||
mov v20.16b, v26.16b
|
||||
mov v21.16b, v26.16b
|
||||
mov v22.16b, v26.16b
|
||||
mov v23.16b, v26.16b
|
||||
smlal v16.2d, v0.2s, v25.2s
|
||||
smlal2 v17.2d, v0.4s, v25.4s
|
||||
smlal v18.2d, v1.2s, v25.2s
|
||||
smlal2 v19.2d, v1.4s, v25.4s
|
||||
smlal v20.2d, v2.2s, v25.2s
|
||||
smlal2 v21.2d, v2.4s, v25.4s
|
||||
smlal v22.2d, v3.2s, v25.2s
|
||||
smlal2 v23.2d, v3.4s, v25.4s
|
||||
shrn v0.2s, v16.2d, 18
|
||||
shrn2 v0.4s, v17.2d, 18
|
||||
shrn v1.2s, v18.2d, 18
|
||||
shrn2 v1.4s, v19.2d, 18
|
||||
shrn v2.2s, v20.2d, 18
|
||||
shrn2 v2.4s, v21.2d, 18
|
||||
shrn v3.2s, v22.2d, 18
|
||||
shrn2 v3.4s, v23.2d, 18
|
||||
subs w2, w2, #8
|
||||
.ifc \fromto, To
|
||||
smin v0.4s, v0.4s, v24.4s
|
||||
smin v1.4s, v1.4s, v24.4s
|
||||
smin v2.4s, v2.4s, v24.4s
|
||||
smin v3.4s, v3.4s, v24.4s
|
||||
.endif
|
||||
st1 {v0.4s, v1.4s}, [x0], #32
|
||||
st1 {v2.4s, v3.4s}, [x1], #32
|
||||
b.gt 1b
|
||||
.else
|
||||
dup v25.4s, w3
|
||||
dup v26.4s, w4
|
||||
1:
|
||||
ld1 {v0.8h}, [x0]
|
||||
ld1 {v1.8h}, [x1]
|
||||
mov v16.16b, v26.16b
|
||||
mov v17.16b, v26.16b
|
||||
mov v18.16b, v26.16b
|
||||
mov v19.16b, v26.16b
|
||||
sxtl v20.4s, v0.4h
|
||||
sxtl v21.4s, v1.4h
|
||||
sxtl2 v22.4s, v0.8h
|
||||
sxtl2 v23.4s, v1.8h
|
||||
mla v16.4s, v20.4s, v25.4s
|
||||
mla v17.4s, v21.4s, v25.4s
|
||||
mla v18.4s, v22.4s, v25.4s
|
||||
mla v19.4s, v23.4s, v25.4s
|
||||
.ifc \fromto, To
|
||||
sqshrn v0.4h, v16.4s, 14
|
||||
sqshrn v1.4h, v17.4s, 14
|
||||
sqshrn2 v0.8h, v18.4s, 14
|
||||
sqshrn2 v1.8h, v19.4s, 14
|
||||
.else
|
||||
shrn v0.4h, v16.4s, 14
|
||||
shrn v1.4h, v17.4s, 14
|
||||
shrn2 v0.8h, v18.4s, 14
|
||||
shrn2 v1.8h, v19.4s, 14
|
||||
.endif
|
||||
subs w2, w2, #8
|
||||
st1 {v0.8h}, [x0], #16
|
||||
st1 {v1.8h}, [x1], #16
|
||||
b.gt 1b
|
||||
.endif
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
lumConvertRange To, 8
|
||||
lumConvertRange To, 16
|
||||
chrConvertRange To, 8
|
||||
chrConvertRange To, 16
|
||||
lumConvertRange From, 8
|
||||
lumConvertRange From, 16
|
||||
chrConvertRange From, 8
|
||||
chrConvertRange From, 16
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/aarch64/cpu.h"
|
||||
#include "libavutil/cpu.h"
|
||||
#include "libavutil/bswap.h"
|
||||
#include "libswscale/rgb2rgb.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
|
||||
// Only handle width aligned to 16
|
||||
void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
|
||||
uint8_t *vdst, int width, int height, int lumStride,
|
||||
int chromStride, int srcStride, const int32_t *rgb2yuv);
|
||||
|
||||
static void rgb24toyv12(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
|
||||
uint8_t *vdst, int width, int height, int lumStride,
|
||||
int chromStride, int srcStride, const int32_t *rgb2yuv)
|
||||
{
|
||||
int width_align = width & (~15);
|
||||
|
||||
if (width_align > 0)
|
||||
ff_rgb24toyv12_neon(src, ydst, udst, vdst, width_align, height,
|
||||
lumStride, chromStride, srcStride, rgb2yuv);
|
||||
if (width_align < width) {
|
||||
src += width_align * 3;
|
||||
ydst += width_align;
|
||||
udst += width_align / 2;
|
||||
vdst += width_align / 2;
|
||||
ff_rgb24toyv12_c(src, ydst, udst, vdst, width - width_align, height,
|
||||
lumStride, chromStride, srcStride, rgb2yuv);
|
||||
}
|
||||
}
|
||||
|
||||
void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2,
|
||||
uint8_t *dest, int width, int height,
|
||||
int src1Stride, int src2Stride, int dstStride);
|
||||
void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
|
||||
int width, int height, int srcStride,
|
||||
int dst1Stride, int dst2Stride);
|
||||
void ff_shuffle_bytes_0321_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_2103_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_1230_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_3012_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_3210_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_3102_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_2013_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_2130_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
void ff_shuffle_bytes_1203_neon(const uint8_t *src, uint8_t *dst, int src_size);
|
||||
|
||||
void ff_uyvytoyuv422_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
|
||||
const uint8_t *src, int width, int height,
|
||||
int lumStride, int chromStride, int srcStride);
|
||||
void ff_uyvytoyuv420_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
|
||||
const uint8_t *src, int width, int height,
|
||||
int lumStride, int chromStride, int srcStride);
|
||||
void ff_yuyvtoyuv420_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
|
||||
const uint8_t *src, int width, int height,
|
||||
int lumStride, int chromStride, int srcStride);
|
||||
void ff_yuyvtoyuv422_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
|
||||
const uint8_t *src, int width, int height,
|
||||
int lumStride, int chromStride, int srcStride);
|
||||
av_cold void rgb2rgb_init_aarch64(void)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
if (have_neon(cpu_flags)) {
|
||||
ff_rgb24toyv12 = rgb24toyv12;
|
||||
interleaveBytes = ff_interleave_bytes_neon;
|
||||
deinterleaveBytes = ff_deinterleave_bytes_neon;
|
||||
shuffle_bytes_0321 = ff_shuffle_bytes_0321_neon;
|
||||
shuffle_bytes_1230 = ff_shuffle_bytes_1230_neon;
|
||||
shuffle_bytes_2103 = ff_shuffle_bytes_2103_neon;
|
||||
shuffle_bytes_3012 = ff_shuffle_bytes_3012_neon;
|
||||
shuffle_bytes_3210 = ff_shuffle_bytes_3210_neon;
|
||||
shuffle_bytes_3102 = ff_shuffle_bytes_3102_neon;
|
||||
shuffle_bytes_2013 = ff_shuffle_bytes_2013_neon;
|
||||
shuffle_bytes_2130 = ff_shuffle_bytes_2130_neon;
|
||||
shuffle_bytes_1203 = ff_shuffle_bytes_1203_neon;
|
||||
uyvytoyuv422 = ff_uyvytoyuv422_neon;
|
||||
uyvytoyuv420 = ff_uyvytoyuv420_neon;
|
||||
yuyvtoyuv422 = ff_yuyvtoyuv422_neon;
|
||||
yuyvtoyuv420 = ff_yuyvtoyuv420_neon;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,689 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Martin Storsjo
|
||||
* Copyright (c) 2024 Ramiro Polla
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/aarch64/asm.S"
|
||||
|
||||
#define RGB2YUV_COEFFS 16*4+16*32
|
||||
#define BY v0.h[0]
|
||||
#define GY v0.h[1]
|
||||
#define RY v0.h[2]
|
||||
#define BU v1.h[0]
|
||||
#define GU v1.h[1]
|
||||
#define RU v1.h[2]
|
||||
#define BV v2.h[0]
|
||||
#define GV v2.h[1]
|
||||
#define RV v2.h[2]
|
||||
#define Y_OFFSET v22
|
||||
#define UV_OFFSET v23
|
||||
|
||||
const shuf_0321_tbl, align=4
|
||||
.byte 0, 3, 2, 1
|
||||
.byte 4, 7, 6, 5
|
||||
.byte 8, 11, 10, 9
|
||||
.byte 12, 15, 14, 13
|
||||
endconst
|
||||
|
||||
const shuf_1230_tbl, align=4
|
||||
.byte 1, 2, 3, 0
|
||||
.byte 5, 6, 7, 4
|
||||
.byte 9, 10, 11, 8
|
||||
.byte 13, 14, 15, 12
|
||||
endconst
|
||||
|
||||
const shuf_2103_tbl, align=4
|
||||
.byte 2, 1, 0, 3
|
||||
.byte 6, 5, 4, 7
|
||||
.byte 10, 9, 8, 11
|
||||
.byte 14, 13, 12, 15
|
||||
endconst
|
||||
|
||||
const shuf_3012_tbl, align=4
|
||||
.byte 3, 0, 1, 2
|
||||
.byte 7, 4, 5, 6
|
||||
.byte 11, 8, 9, 10
|
||||
.byte 15, 12, 13, 14
|
||||
endconst
|
||||
|
||||
const shuf_3210_tbl, align=4
|
||||
.byte 3, 2, 1, 0
|
||||
.byte 7, 6, 5, 4
|
||||
.byte 11, 10, 9, 8
|
||||
.byte 15, 14, 13, 12
|
||||
endconst
|
||||
|
||||
const shuf_3102_tbl, align=4
|
||||
.byte 3, 1, 0, 2
|
||||
.byte 7, 5, 4, 6
|
||||
.byte 11, 9, 8, 10
|
||||
.byte 15, 13, 12, 14
|
||||
endconst
|
||||
|
||||
const shuf_2013_tbl, align=4
|
||||
.byte 2, 0, 1, 3
|
||||
.byte 6, 4, 5, 7
|
||||
.byte 10, 8, 9, 11
|
||||
.byte 14, 12, 13, 15
|
||||
endconst
|
||||
|
||||
const shuf_1203_tbl, align=4
|
||||
.byte 1, 2, 0, 3
|
||||
.byte 5, 6, 4, 7
|
||||
.byte 9, 10, 8, 11
|
||||
.byte 13, 14, 12, 15
|
||||
endconst
|
||||
|
||||
const shuf_2130_tbl, align=4
|
||||
.byte 2, 1, 3, 0
|
||||
.byte 6, 5, 7, 4
|
||||
.byte 10, 9, 11, 8
|
||||
.byte 14, 13, 15, 12
|
||||
endconst
|
||||
|
||||
// convert rgb to 16-bit y, u, or v
|
||||
// uses v3 and v4
|
||||
|
||||
.macro rgbconv16 dst, b, g, r, bc, gc, rc, shr_bits
|
||||
smull v3.4s, \b\().4h, \bc
|
||||
smlal v3.4s, \g\().4h, \gc
|
||||
smlal v3.4s, \r\().4h, \rc
|
||||
smull2 v4.4s, \b\().8h, \bc
|
||||
smlal2 v4.4s, \g\().8h, \gc
|
||||
smlal2 v4.4s, \r\().8h, \rc // v3:v4 = b * bc + g * gc + r * rc (32-bit)
|
||||
shrn \dst\().4h, v3.4s, \shr_bits
|
||||
shrn2 \dst\().8h, v4.4s, \shr_bits // dst = b * bc + g * gc + r * rc (16-bit)
|
||||
.endm
|
||||
|
||||
// void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
|
||||
// uint8_t *vdst, int width, int height, int lumStride,
|
||||
// int chromStride, int srcStride, int32_t *rgb2yuv);
|
||||
function ff_rgb24toyv12_neon, export=1
|
||||
// x0 const uint8_t *src
|
||||
// x1 uint8_t *ydst
|
||||
// x2 uint8_t *udst
|
||||
// x3 uint8_t *vdst
|
||||
// w4 int width
|
||||
// w5 int height
|
||||
// w6 int lumStride
|
||||
// w7 int chromStride
|
||||
ldrsw x14, [sp]
|
||||
ldr x15, [sp, #8]
|
||||
// x14 int srcStride
|
||||
// x15 int32_t *rgb2yuv
|
||||
|
||||
// extend width and stride parameters
|
||||
uxtw x4, w4
|
||||
sxtw x6, w6
|
||||
sxtw x7, w7
|
||||
|
||||
// src1 = x0
|
||||
// src2 = x10
|
||||
add x10, x0, x14 // x10 = src + srcStride
|
||||
lsl x14, x14, #1 // srcStride *= 2
|
||||
add x11, x4, x4, lsl #1 // x11 = 3 * width
|
||||
sub x14, x14, x11 // srcPadding = (2 * srcStride) - (3 * width)
|
||||
|
||||
// ydst1 = x1
|
||||
// ydst2 = x11
|
||||
add x11, x1, x6 // x11 = ydst + lumStride
|
||||
lsl x6, x6, #1 // lumStride *= 2
|
||||
sub x6, x6, x4 // lumPadding = (2 * lumStride) - width
|
||||
|
||||
sub x7, x7, x4, lsr #1 // chromPadding = chromStride - (width / 2)
|
||||
|
||||
// load rgb2yuv coefficients into v0, v1, and v2
|
||||
add x15, x15, #RGB2YUV_COEFFS
|
||||
ld1 {v0.8h-v2.8h}, [x15] // load 24 values
|
||||
|
||||
// load offset constants
|
||||
movi Y_OFFSET.8h, #0x10, lsl #8
|
||||
movi UV_OFFSET.8h, #0x80, lsl #8
|
||||
|
||||
1:
|
||||
mov w15, w4 // w15 = width
|
||||
|
||||
2:
|
||||
// load first line
|
||||
ld3 {v26.16b, v27.16b, v28.16b}, [x0], #48
|
||||
|
||||
// widen first line to 16-bit
|
||||
uxtl v16.8h, v26.8b // v16 = B11
|
||||
uxtl v17.8h, v27.8b // v17 = G11
|
||||
uxtl v18.8h, v28.8b // v18 = R11
|
||||
uxtl2 v19.8h, v26.16b // v19 = B12
|
||||
uxtl2 v20.8h, v27.16b // v20 = G12
|
||||
uxtl2 v21.8h, v28.16b // v21 = R12
|
||||
|
||||
// calculate Y values for first line
|
||||
rgbconv16 v24, v16, v17, v18, BY, GY, RY, #7 // v24 = Y11
|
||||
rgbconv16 v25, v19, v20, v21, BY, GY, RY, #7 // v25 = Y12
|
||||
|
||||
// load second line
|
||||
ld3 {v26.16b, v27.16b, v28.16b}, [x10], #48
|
||||
|
||||
// pairwise add and save rgb values to calculate average
|
||||
addp v5.8h, v16.8h, v19.8h
|
||||
addp v6.8h, v17.8h, v20.8h
|
||||
addp v7.8h, v18.8h, v21.8h
|
||||
|
||||
// widen second line to 16-bit
|
||||
uxtl v16.8h, v26.8b // v16 = B21
|
||||
uxtl v17.8h, v27.8b // v17 = G21
|
||||
uxtl v18.8h, v28.8b // v18 = R21
|
||||
uxtl2 v19.8h, v26.16b // v19 = B22
|
||||
uxtl2 v20.8h, v27.16b // v20 = G22
|
||||
uxtl2 v21.8h, v28.16b // v21 = R22
|
||||
|
||||
// calculate Y values for second line
|
||||
rgbconv16 v26, v16, v17, v18, BY, GY, RY, #7 // v26 = Y21
|
||||
rgbconv16 v27, v19, v20, v21, BY, GY, RY, #7 // v27 = Y22
|
||||
|
||||
// pairwise add rgb values to calculate average
|
||||
addp v16.8h, v16.8h, v19.8h
|
||||
addp v17.8h, v17.8h, v20.8h
|
||||
addp v18.8h, v18.8h, v21.8h
|
||||
|
||||
// calculate sum of r, g, b components in 2x2 blocks
|
||||
add v16.8h, v16.8h, v5.8h
|
||||
add v17.8h, v17.8h, v6.8h
|
||||
add v18.8h, v18.8h, v7.8h
|
||||
|
||||
// calculate U and V values
|
||||
rgbconv16 v28, v16, v17, v18, BU, GU, RU, #9 // v28 = U
|
||||
rgbconv16 v29, v16, v17, v18, BV, GV, RV, #9 // v29 = V
|
||||
|
||||
// add offsets and narrow all values
|
||||
addhn v24.8b, v24.8h, Y_OFFSET.8h
|
||||
addhn v25.8b, v25.8h, Y_OFFSET.8h
|
||||
addhn v26.8b, v26.8h, Y_OFFSET.8h
|
||||
addhn v27.8b, v27.8h, Y_OFFSET.8h
|
||||
addhn v28.8b, v28.8h, UV_OFFSET.8h
|
||||
addhn v29.8b, v29.8h, UV_OFFSET.8h
|
||||
|
||||
subs w15, w15, #16
|
||||
|
||||
// store output
|
||||
st1 {v24.8b, v25.8b}, [x1], #16 // store ydst1
|
||||
st1 {v26.8b, v27.8b}, [x11], #16 // store ydst2
|
||||
st1 {v28.8b}, [x2], #8 // store udst
|
||||
st1 {v29.8b}, [x3], #8 // store vdst
|
||||
|
||||
b.gt 2b
|
||||
|
||||
subs w5, w5, #2
|
||||
|
||||
// row += 2
|
||||
add x0, x0, x14 // src1 += srcPadding
|
||||
add x10, x10, x14 // src2 += srcPadding
|
||||
add x1, x1, x6 // ydst1 += lumPadding
|
||||
add x11, x11, x6 // ydst2 += lumPadding
|
||||
add x2, x2, x7 // udst += chromPadding
|
||||
add x3, x3, x7 // vdst += chromPadding
|
||||
b.gt 1b
|
||||
|
||||
ret
|
||||
endfunc
|
||||
|
||||
// void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2,
|
||||
// uint8_t *dest, int width, int height,
|
||||
// int src1Stride, int src2Stride, int dstStride);
|
||||
function ff_interleave_bytes_neon, export=1
|
||||
sub w5, w5, w3
|
||||
sub w6, w6, w3
|
||||
sub w7, w7, w3, lsl #1
|
||||
1:
|
||||
ands w8, w3, #0xfffffff0 // & ~15
|
||||
b.eq 3f
|
||||
2:
|
||||
ld1 {v0.16b}, [x0], #16
|
||||
ld1 {v1.16b}, [x1], #16
|
||||
subs w8, w8, #16
|
||||
st2 {v0.16b, v1.16b}, [x2], #32
|
||||
b.gt 2b
|
||||
|
||||
tst w3, #15
|
||||
b.eq 9f
|
||||
|
||||
3:
|
||||
tst w3, #8
|
||||
b.eq 4f
|
||||
ld1 {v0.8b}, [x0], #8
|
||||
ld1 {v1.8b}, [x1], #8
|
||||
st2 {v0.8b, v1.8b}, [x2], #16
|
||||
4:
|
||||
tst w3, #4
|
||||
b.eq 5f
|
||||
|
||||
ld1 {v0.s}[0], [x0], #4
|
||||
ld1 {v1.s}[0], [x1], #4
|
||||
zip1 v0.8b, v0.8b, v1.8b
|
||||
st1 {v0.8b}, [x2], #8
|
||||
|
||||
5:
|
||||
ands w8, w3, #3
|
||||
b.eq 9f
|
||||
6:
|
||||
ldrb w9, [x0], #1
|
||||
ldrb w10, [x1], #1
|
||||
subs w8, w8, #1
|
||||
bfi w9, w10, #8, #8
|
||||
strh w9, [x2], #2
|
||||
b.gt 6b
|
||||
|
||||
9:
|
||||
subs w4, w4, #1
|
||||
b.eq 0f
|
||||
add x0, x0, w5, sxtw
|
||||
add x1, x1, w6, sxtw
|
||||
add x2, x2, w7, sxtw
|
||||
b 1b
|
||||
|
||||
0:
|
||||
ret
|
||||
endfunc
|
||||
|
||||
// void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
|
||||
// int width, int height, int srcStride,
|
||||
// int dst1Stride, int dst2Stride);
|
||||
function ff_deinterleave_bytes_neon, export=1
|
||||
sub w5, w5, w3, lsl #1
|
||||
sub w6, w6, w3
|
||||
sub w7, w7, w3
|
||||
1:
|
||||
ands w8, w3, #0xfffffff0 // & ~15
|
||||
b.eq 3f
|
||||
2:
|
||||
ld2 {v0.16b, v1.16b}, [x0], #32
|
||||
subs w8, w8, #16
|
||||
st1 {v0.16b}, [x1], #16
|
||||
st1 {v1.16b}, [x2], #16
|
||||
b.gt 2b
|
||||
|
||||
tst w3, #15
|
||||
b.eq 9f
|
||||
|
||||
3:
|
||||
tst w3, #8
|
||||
b.eq 4f
|
||||
ld2 {v0.8b, v1.8b}, [x0], #16
|
||||
st1 {v0.8b}, [x1], #8
|
||||
st1 {v1.8b}, [x2], #8
|
||||
4:
|
||||
tst w3, #4
|
||||
b.eq 5f
|
||||
|
||||
ld1 {v0.8b}, [x0], #8
|
||||
shrn v1.8b, v0.8h, #8
|
||||
xtn v0.8b, v0.8h
|
||||
st1 {v0.s}[0], [x1], #4
|
||||
st1 {v1.s}[0], [x2], #4
|
||||
|
||||
5:
|
||||
ands w8, w3, #3
|
||||
b.eq 9f
|
||||
6:
|
||||
ldrh w9, [x0], #2
|
||||
subs w8, w8, #1
|
||||
ubfx w10, w9, #8, #8
|
||||
strb w9, [x1], #1
|
||||
strb w10, [x2], #1
|
||||
b.gt 6b
|
||||
|
||||
9:
|
||||
subs w4, w4, #1
|
||||
b.eq 0f
|
||||
add x0, x0, w5, sxtw
|
||||
add x1, x1, w6, sxtw
|
||||
add x2, x2, w7, sxtw
|
||||
b 1b
|
||||
|
||||
0:
|
||||
ret
|
||||
endfunc
|
||||
|
||||
.macro neon_shuf shuf
|
||||
function ff_shuffle_bytes_\shuf\()_neon, export=1
|
||||
movrel x9, shuf_\shuf\()_tbl
|
||||
ld1 {v1.16b}, [x9]
|
||||
and w5, w2, #~15
|
||||
and w3, w2, #8
|
||||
and w4, w2, #4
|
||||
cbz w5, 2f
|
||||
1:
|
||||
ld1 {v0.16b}, [x0], #16
|
||||
subs w5, w5, #16
|
||||
tbl v0.16b, {v0.16b}, v1.16b
|
||||
st1 {v0.16b}, [x1], #16
|
||||
b.gt 1b
|
||||
2:
|
||||
cbz w3, 3f
|
||||
ld1 {v0.8b}, [x0], #8
|
||||
tbl v0.8b, {v0.16b}, v1.8b
|
||||
st1 {v0.8b}, [x1], #8
|
||||
3:
|
||||
cbz w4, 4f
|
||||
.if \shuf == 0321
|
||||
ldr w5, [x0]
|
||||
rev w5, w5
|
||||
ror w5, w5, #24
|
||||
str w5, [x1]
|
||||
.endif
|
||||
.if \shuf == 1230
|
||||
ldr w5, [x0]
|
||||
ror w5, w5, #8
|
||||
str w5, [x1]
|
||||
.endif
|
||||
.if \shuf == 2103
|
||||
ldr w5, [x0]
|
||||
rev w5, w5
|
||||
ror w5, w5, #8
|
||||
str w5, [x1]
|
||||
.endif
|
||||
.if \shuf == 3012
|
||||
ldr w5, [x0]
|
||||
ror w5, w5, #24
|
||||
str w5, [x1]
|
||||
.endif
|
||||
.if \shuf == 3210
|
||||
ldr w5, [x0]
|
||||
rev w5, w5
|
||||
str w5, [x1]
|
||||
.endif
|
||||
.if \shuf == 3102 || \shuf == 2013 || \shuf == 1203 || \shuf == 2130
|
||||
ld1 {v0.s}[0], [x0]
|
||||
tbl v0.8b, {v0.16b}, v1.8b
|
||||
st1 {v0.s}[0], [x1]
|
||||
.endif
|
||||
4:
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
neon_shuf 0321
|
||||
neon_shuf 1230
|
||||
neon_shuf 2103
|
||||
neon_shuf 3012
|
||||
neon_shuf 3102
|
||||
neon_shuf 2013
|
||||
neon_shuf 1203
|
||||
neon_shuf 2130
|
||||
neon_shuf 3210
|
||||
|
||||
/*
|
||||
v0-v7 - two consecutive lines
|
||||
x0 - upper Y destination
|
||||
x1 - U destination
|
||||
x2 - V destination
|
||||
x3 - upper src line
|
||||
w5 - width/iteration counter - count of line pairs for yuv420, of single lines for 422
|
||||
x6 - lum padding
|
||||
x7 - chrom padding
|
||||
x8 - src padding
|
||||
w9 - number of bytes remaining in the tail
|
||||
x10 - lower Y destination
|
||||
w12 - tmp
|
||||
x13 - lower src line
|
||||
w14 - tmp
|
||||
w17 - set to 1 if last line has to be handled separately (odd height)
|
||||
*/
|
||||
|
||||
// one fast path iteration processes 16 uyvy tuples
|
||||
// is_line_tail is set to 1 when final 16 tuples are being processed
|
||||
// skip_storing_chroma is set to 1 when final line is processed and the height is odd
|
||||
.macro fastpath_iteration src_fmt, dst_fmt, is_line_tail, skip_storing_chroma
|
||||
ld4 {v0.16b - v3.16b}, [x3], #64
|
||||
.if ! \is_line_tail
|
||||
subs w14, w14, #32
|
||||
.endif
|
||||
|
||||
.if ! \skip_storing_chroma
|
||||
.ifc \dst_fmt, yuv420
|
||||
ld4 {v4.16b - v7.16b}, [x13], #64
|
||||
.endif
|
||||
|
||||
.ifc \dst_fmt, yuv420 // store UV
|
||||
.ifc \src_fmt, uyvy
|
||||
uhadd v0.16b, v4.16b, v0.16b // halving sum of U
|
||||
uhadd v2.16b, v6.16b, v2.16b // halving sum of V
|
||||
.else
|
||||
uhadd v1.16b, v5.16b, v1.16b // halving sum of U
|
||||
uhadd v3.16b, v7.16b, v3.16b // halving sum of V
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.ifc \src_fmt, uyvy
|
||||
st1 {v2.16b}, [x2], #16
|
||||
st1 {v0.16b}, [x1], #16
|
||||
.else
|
||||
st1 {v3.16b}, [x2], #16
|
||||
st1 {v1.16b}, [x1], #16
|
||||
.endif
|
||||
|
||||
.ifc \dst_fmt, yuv420 // store_y
|
||||
.ifc \src_fmt, uyvy
|
||||
mov v6.16b, v5.16b
|
||||
st2 {v6.16b,v7.16b}, [x10], #32
|
||||
.else
|
||||
mov v5.16b, v4.16b
|
||||
st2 {v5.16b,v6.16b}, [x10], #32
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.endif // ! \skip_storing_chroma
|
||||
|
||||
.ifc \src_fmt, uyvy
|
||||
mov v2.16b, v1.16b
|
||||
st2 {v2.16b,v3.16b}, [x0], #32
|
||||
.else
|
||||
mov v1.16b, v0.16b
|
||||
st2 {v1.16b,v2.16b}, [x0], #32
|
||||
.endif
|
||||
.endm
|
||||
|
||||
// shift pointers back to width - 32 to process the tail of the line
|
||||
// if the height is odd, processing the final line is simplified
|
||||
.macro fastpath_shift_back_pointers src_fmt, dst_fmt, is_final_odd_line
|
||||
add x3, x3, w9, sxtw #1
|
||||
sub x3, x3, #64
|
||||
.if ! \is_final_odd_line
|
||||
.ifc \dst_fmt, yuv420
|
||||
add x13, x13, w9, sxtw #1
|
||||
sub x13, x13, #64
|
||||
add x10, x10, w9, sxtw
|
||||
sub x10, x10, #32
|
||||
.endif
|
||||
.endif
|
||||
add x0, x0, w9, sxtw
|
||||
sub x0, x0, #32
|
||||
.if ! \is_final_odd_line
|
||||
asr w14, w9, #1
|
||||
add x1, x1, w14, sxtw
|
||||
sub x1, x1, #16
|
||||
add x2, x2, w14, sxtw
|
||||
sub x2, x2, #16
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro slowpath_iteration src_fmt, dst_fmt, skip_storing_chroma
|
||||
.ifc \dst_fmt, yuv422
|
||||
.ifc \src_fmt, uyvy
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x3], #1
|
||||
strb w12, [x1], #1
|
||||
strb w14, [x0], #1
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x3], #1
|
||||
strb w12, [x2], #1
|
||||
strb w14, [x0], #1
|
||||
.else
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x3], #1
|
||||
strb w12, [x0], #1
|
||||
strb w14, [x1], #1
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x3], #1
|
||||
strb w12, [x0], #1
|
||||
strb w14, [x2], #1
|
||||
.endif
|
||||
.endif
|
||||
.ifc \dst_fmt, yuv420
|
||||
.ifc \src_fmt, uyvy
|
||||
.if \skip_storing_chroma
|
||||
ldrb w12, [x3], #2
|
||||
ldrb w14, [x3], #2
|
||||
strb w12, [x0], #1
|
||||
strb w14, [x0], #1
|
||||
.else
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x13], #1
|
||||
add w12, w12, w14
|
||||
lsr w12, w12, #1
|
||||
strb w12, [x1], #1
|
||||
ldrb w14, [x3], #1
|
||||
ldrb w12, [x13], #1
|
||||
strb w14, [x0], #1
|
||||
strb w12, [x10], #1
|
||||
ldrb w14, [x13], #1
|
||||
ldrb w12, [x3], #1
|
||||
add w12, w12, w14
|
||||
lsr w12, w12, #1
|
||||
strb w12, [x2], #1
|
||||
ldrb w14, [x3], #1
|
||||
ldrb w12, [x13], #1
|
||||
strb w14, [x0], #1
|
||||
strb w12, [x10], #1
|
||||
.endif
|
||||
.else
|
||||
.if \skip_storing_chroma
|
||||
ldrb w12, [x3], #2
|
||||
ldrb w14, [x3], #2
|
||||
strb w12, [x0], #1
|
||||
strb w14, [x0], #1
|
||||
.else
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x13], #1
|
||||
strb w12, [x0], #1
|
||||
strb w14, [x10], #1
|
||||
ldrb w12, [x3], #1
|
||||
ldrb w14, [x13], #1
|
||||
add w12, w12, w14
|
||||
lsr w12, w12, #1
|
||||
strb w12, [x1], #1
|
||||
ldrb w14, [x3], #1
|
||||
ldrb w12, [x13], #1
|
||||
strb w14, [x0], #1
|
||||
strb w12, [x10], #1
|
||||
ldrb w14, [x13], #1
|
||||
ldrb w12, [x3], #1
|
||||
add w12, w12, w14
|
||||
lsr w12, w12, #1
|
||||
strb w12, [x2], #1
|
||||
.endif
|
||||
.endif
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro move_pointers_to_next_line src_fmt, dst_fmt, is_final_odd_line
|
||||
add x3, x3, x8
|
||||
add x0, x0, x6
|
||||
.ifc \dst_fmt, yuv420
|
||||
add x13, x13, x8
|
||||
add x10, x10, x6
|
||||
.endif
|
||||
add x1, x1, x7
|
||||
add x2, x2, x7
|
||||
.endm
|
||||
|
||||
.macro interleaved_yuv_to_planar src_fmt, dst_fmt
|
||||
function ff_\src_fmt\()to\dst_fmt\()_neon, export=1
|
||||
sxtw x6, w6
|
||||
sxtw x7, w7
|
||||
ldrsw x8, [sp]
|
||||
ands w11, w4, #~31 // choose between fast and slow path
|
||||
|
||||
.ifc \dst_fmt, yuv420
|
||||
add x10, x0, x6
|
||||
add x13, x3, x8
|
||||
add x8, x8, x8
|
||||
add x6, x6, x6
|
||||
and w17, w5, #1
|
||||
asr w5, w5, #1
|
||||
.endif
|
||||
asr w9, w4, #1
|
||||
sub x8, x8, w4, sxtw #1 // src offset
|
||||
sub x6, x6, w4, sxtw // lum offset
|
||||
sub x7, x7, x9 // chr offset
|
||||
|
||||
b.eq 6f
|
||||
|
||||
1: // fast path - the width is at least 32
|
||||
and w14, w4, #~31 // w14 is the main loop counter
|
||||
and w9, w4, #31 // w9 holds the remaining width, 0 to 31
|
||||
2:
|
||||
fastpath_iteration \src_fmt, \dst_fmt, 0, 0
|
||||
b.ne 2b
|
||||
fastpath_shift_back_pointers \src_fmt, \dst_fmt, 0
|
||||
fastpath_iteration \src_fmt, \dst_fmt, 0, 0
|
||||
subs w5, w5, #1
|
||||
move_pointers_to_next_line \src_fmt, \dst_fmt
|
||||
b.ne 1b
|
||||
|
||||
.ifc \dst_fmt, yuv420 // handle the last line in case the height is odd
|
||||
cbz w17, 3f
|
||||
and w14, w4, #~31
|
||||
4:
|
||||
fastpath_iteration \src_fmt, \dst_fmt, 0, 1
|
||||
b.ne 4b
|
||||
fastpath_shift_back_pointers \src_fmt, \dst_fmt, 1
|
||||
fastpath_iteration \src_fmt, \dst_fmt, 1, 1
|
||||
3:
|
||||
.endif
|
||||
ret
|
||||
|
||||
6: // slow path - width is at most 31
|
||||
and w9, w4, #31
|
||||
7:
|
||||
subs w9, w9, #2
|
||||
slowpath_iteration \src_fmt, \dst_fmt, 0
|
||||
b.ne 7b
|
||||
subs w5, w5, #1
|
||||
move_pointers_to_next_line \src_fmt, \dst_fmt
|
||||
b.ne 6b
|
||||
|
||||
.ifc \dst_fmt, yuv420
|
||||
cbz w17, 8f
|
||||
and w9, w4, #31
|
||||
.ifc \src_fmt, uyvy
|
||||
add x3, x3, #1
|
||||
.endif
|
||||
5:
|
||||
subs w9, w9, #2
|
||||
slowpath_iteration \src_fmt, \dst_fmt, 1
|
||||
b.ne 5b
|
||||
8:
|
||||
.endif
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
interleaved_yuv_to_planar uyvy, yuv422
|
||||
interleaved_yuv_to_planar uyvy, yuv420
|
||||
interleaved_yuv_to_planar yuyv, yuv422
|
||||
interleaved_yuv_to_planar yuyv, yuv420
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/aarch64/cpu.h"
|
||||
|
||||
void ff_hscale16to15_4_neon_asm(int shift, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize);
|
||||
void ff_hscale16to15_X8_neon_asm(int shift, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize);
|
||||
void ff_hscale16to15_X4_neon_asm(int shift, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize);
|
||||
void ff_hscale16to19_4_neon_asm(int shift, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize);
|
||||
void ff_hscale16to19_X8_neon_asm(int shift, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize);
|
||||
void ff_hscale16to19_X4_neon_asm(int shift, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize);
|
||||
|
||||
static void ff_hscale16to15_4_neon(SwsInternal *c, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
|
||||
int sh = desc->comp[0].depth - 1;
|
||||
|
||||
if (sh<15) {
|
||||
sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
|
||||
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
|
||||
sh = 16 - 1;
|
||||
}
|
||||
ff_hscale16to15_4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
|
||||
|
||||
}
|
||||
|
||||
static void ff_hscale16to15_X8_neon(SwsInternal *c, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
|
||||
int sh = desc->comp[0].depth - 1;
|
||||
|
||||
if (sh<15) {
|
||||
sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
|
||||
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
|
||||
sh = 16 - 1;
|
||||
}
|
||||
ff_hscale16to15_X8_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
|
||||
|
||||
}
|
||||
|
||||
static void ff_hscale16to15_X4_neon(SwsInternal *c, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
|
||||
int sh = desc->comp[0].depth - 1;
|
||||
|
||||
if (sh<15) {
|
||||
sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
|
||||
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
|
||||
sh = 16 - 1;
|
||||
}
|
||||
ff_hscale16to15_X4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
|
||||
}
|
||||
|
||||
static void ff_hscale16to19_4_neon(SwsInternal *c, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
|
||||
int bits = desc->comp[0].depth - 1;
|
||||
int sh = bits - 4;
|
||||
|
||||
if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
|
||||
sh = 9;
|
||||
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
|
||||
sh = 16 - 1 - 4;
|
||||
}
|
||||
|
||||
ff_hscale16to19_4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
|
||||
|
||||
}
|
||||
|
||||
static void ff_hscale16to19_X8_neon(SwsInternal *c, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
|
||||
int bits = desc->comp[0].depth - 1;
|
||||
int sh = bits - 4;
|
||||
|
||||
if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
|
||||
sh = 9;
|
||||
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
|
||||
sh = 16 - 1 - 4;
|
||||
}
|
||||
|
||||
ff_hscale16to19_X8_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
|
||||
|
||||
}
|
||||
|
||||
static void ff_hscale16to19_X4_neon(SwsInternal *c, int16_t *_dst, int dstW,
|
||||
const uint8_t *_src, const int16_t *filter,
|
||||
const int32_t *filterPos, int filterSize)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
|
||||
int bits = desc->comp[0].depth - 1;
|
||||
int sh = bits - 4;
|
||||
|
||||
if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
|
||||
sh = 9;
|
||||
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
|
||||
sh = 16 - 1 - 4;
|
||||
}
|
||||
|
||||
ff_hscale16to19_X4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
|
||||
|
||||
}
|
||||
|
||||
#define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
|
||||
void ff_hscale ## from_bpc ## to ## to_bpc ## _ ## filter_n ## _ ## opt( \
|
||||
SwsInternal *c, int16_t *data, \
|
||||
int dstW, const uint8_t *src, \
|
||||
const int16_t *filter, \
|
||||
const int32_t *filterPos, int filterSize)
|
||||
#define SCALE_FUNCS(filter_n, opt) \
|
||||
SCALE_FUNC(filter_n, 8, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 8, 19, opt);
|
||||
#define ALL_SCALE_FUNCS(opt) \
|
||||
SCALE_FUNCS(4, opt); \
|
||||
SCALE_FUNCS(X8, opt); \
|
||||
SCALE_FUNCS(X4, opt)
|
||||
|
||||
ALL_SCALE_FUNCS(neon);
|
||||
|
||||
void ff_yuv2planeX_8_neon(const int16_t *filter, int filterSize,
|
||||
const int16_t **src, uint8_t *dest, int dstW,
|
||||
const uint8_t *dither, int offset);
|
||||
void ff_yuv2plane1_8_neon(
|
||||
const int16_t *src,
|
||||
uint8_t *dest,
|
||||
int dstW,
|
||||
const uint8_t *dither,
|
||||
int offset);
|
||||
|
||||
#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt) do { \
|
||||
if (c->srcBpc == 8) { \
|
||||
if(c->dstBpc <= 14) { \
|
||||
hscalefn = \
|
||||
ff_hscale8to15_ ## filtersize ## _ ## opt; \
|
||||
} else \
|
||||
hscalefn = \
|
||||
ff_hscale8to19_ ## filtersize ## _ ## opt; \
|
||||
} else { \
|
||||
if (c->dstBpc <= 14) \
|
||||
hscalefn = \
|
||||
ff_hscale16to15_ ## filtersize ## _ ## opt; \
|
||||
else \
|
||||
hscalefn = \
|
||||
ff_hscale16to19_ ## filtersize ## _ ## opt; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSIGN_SCALE_FUNC(hscalefn, filtersize, opt) do { \
|
||||
if (filtersize == 4) \
|
||||
ASSIGN_SCALE_FUNC2(hscalefn, 4, opt); \
|
||||
else if (filtersize % 8 == 0) \
|
||||
ASSIGN_SCALE_FUNC2(hscalefn, X8, opt); \
|
||||
else if (filtersize % 4 == 0 && filtersize % 8 != 0) \
|
||||
ASSIGN_SCALE_FUNC2(hscalefn, X4, opt); \
|
||||
} while (0)
|
||||
|
||||
#define ASSIGN_VSCALE_FUNC(vscalefn, opt) \
|
||||
switch (c->dstBpc) { \
|
||||
case 8: vscalefn = ff_yuv2plane1_8_ ## opt; break; \
|
||||
default: break; \
|
||||
}
|
||||
|
||||
#define NEON_INPUT(name) \
|
||||
void ff_##name##ToY_neon(uint8_t *dst, const uint8_t *src, const uint8_t *, \
|
||||
const uint8_t *, int w, uint32_t *coeffs, void *); \
|
||||
void ff_##name##ToUV_neon(uint8_t *, uint8_t *, const uint8_t *, \
|
||||
const uint8_t *, const uint8_t *, int w, \
|
||||
uint32_t *coeffs, void *); \
|
||||
void ff_##name##ToUV_half_neon(uint8_t *, uint8_t *, const uint8_t *, \
|
||||
const uint8_t *, const uint8_t *, int w, \
|
||||
uint32_t *coeffs, void *)
|
||||
#define NEON_INPUT_DOTPROD(name) \
|
||||
void ff_##name##ToY_neon_dotprod(uint8_t *dst, const uint8_t *src, const uint8_t *, \
|
||||
const uint8_t *, int w, uint32_t *coeffs, void *);
|
||||
|
||||
NEON_INPUT(abgr32);
|
||||
NEON_INPUT(argb32);
|
||||
NEON_INPUT(bgr24);
|
||||
NEON_INPUT(bgra32);
|
||||
NEON_INPUT(rgb24);
|
||||
NEON_INPUT(rgba32);
|
||||
NEON_INPUT_DOTPROD(bgra32);
|
||||
NEON_INPUT_DOTPROD(rgba32);
|
||||
|
||||
void ff_lumRangeFromJpeg8_neon(int16_t *dst, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_chrRangeFromJpeg8_neon(int16_t *dstU, int16_t *dstV, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_lumRangeToJpeg8_neon(int16_t *dst, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_chrRangeToJpeg8_neon(int16_t *dstU, int16_t *dstV, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_lumRangeFromJpeg16_neon(int16_t *dst, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_chrRangeFromJpeg16_neon(int16_t *dstU, int16_t *dstV, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_lumRangeToJpeg16_neon(int16_t *dst, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
void ff_chrRangeToJpeg16_neon(int16_t *dstU, int16_t *dstV, int width,
|
||||
uint32_t coeff, int64_t offset);
|
||||
|
||||
av_cold void ff_sws_init_range_convert_aarch64(SwsInternal *c)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
if (have_neon(cpu_flags)) {
|
||||
if (c->dstBpc <= 14) {
|
||||
if (c->opts.src_range) {
|
||||
c->lumConvertRange = ff_lumRangeFromJpeg8_neon;
|
||||
c->chrConvertRange = ff_chrRangeFromJpeg8_neon;
|
||||
} else {
|
||||
c->lumConvertRange = ff_lumRangeToJpeg8_neon;
|
||||
c->chrConvertRange = ff_chrRangeToJpeg8_neon;
|
||||
}
|
||||
} else {
|
||||
if (c->opts.src_range) {
|
||||
c->lumConvertRange = ff_lumRangeFromJpeg16_neon;
|
||||
c->chrConvertRange = ff_chrRangeFromJpeg16_neon;
|
||||
} else {
|
||||
c->lumConvertRange = ff_lumRangeToJpeg16_neon;
|
||||
c->chrConvertRange = ff_chrRangeToJpeg16_neon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
av_cold void ff_sws_init_swscale_aarch64(SwsInternal *c)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
if (have_neon(cpu_flags)) {
|
||||
ASSIGN_SCALE_FUNC(c->hyScale, c->hLumFilterSize, neon);
|
||||
ASSIGN_SCALE_FUNC(c->hcScale, c->hChrFilterSize, neon);
|
||||
ASSIGN_VSCALE_FUNC(c->yuv2plane1, neon);
|
||||
if (c->dstBpc == 8) {
|
||||
c->yuv2planeX = ff_yuv2planeX_8_neon;
|
||||
}
|
||||
switch (c->opts.src_format) {
|
||||
case AV_PIX_FMT_ABGR:
|
||||
c->lumToYV12 = ff_abgr32ToY_neon;
|
||||
if (c->chrSrcHSubSample)
|
||||
c->chrToYV12 = ff_abgr32ToUV_half_neon;
|
||||
else
|
||||
c->chrToYV12 = ff_abgr32ToUV_neon;
|
||||
break;
|
||||
|
||||
case AV_PIX_FMT_ARGB:
|
||||
c->lumToYV12 = ff_argb32ToY_neon;
|
||||
if (c->chrSrcHSubSample)
|
||||
c->chrToYV12 = ff_argb32ToUV_half_neon;
|
||||
else
|
||||
c->chrToYV12 = ff_argb32ToUV_neon;
|
||||
break;
|
||||
case AV_PIX_FMT_BGR24:
|
||||
c->lumToYV12 = ff_bgr24ToY_neon;
|
||||
if (c->chrSrcHSubSample)
|
||||
c->chrToYV12 = ff_bgr24ToUV_half_neon;
|
||||
else
|
||||
c->chrToYV12 = ff_bgr24ToUV_neon;
|
||||
break;
|
||||
case AV_PIX_FMT_BGRA:
|
||||
c->lumToYV12 = ff_bgra32ToY_neon;
|
||||
#if HAVE_DOTPROD
|
||||
if (have_dotprod(cpu_flags)) {
|
||||
c->lumToYV12 = ff_bgra32ToY_neon_dotprod;
|
||||
}
|
||||
#endif
|
||||
if (c->chrSrcHSubSample)
|
||||
c->chrToYV12 = ff_bgra32ToUV_half_neon;
|
||||
else
|
||||
c->chrToYV12 = ff_bgra32ToUV_neon;
|
||||
break;
|
||||
case AV_PIX_FMT_RGB24:
|
||||
c->lumToYV12 = ff_rgb24ToY_neon;
|
||||
if (c->chrSrcHSubSample)
|
||||
c->chrToYV12 = ff_rgb24ToUV_half_neon;
|
||||
else
|
||||
c->chrToYV12 = ff_rgb24ToUV_neon;
|
||||
break;
|
||||
case AV_PIX_FMT_RGBA:
|
||||
c->lumToYV12 = ff_rgba32ToY_neon;
|
||||
#if HAVE_DOTPROD
|
||||
if (have_dotprod(cpu_flags)) {
|
||||
c->lumToYV12 = ff_rgba32ToY_neon_dotprod;
|
||||
}
|
||||
#endif
|
||||
if (c->chrSrcHSubSample)
|
||||
c->chrToYV12 = ff_rgba32ToUV_half_neon;
|
||||
else
|
||||
c->chrToYV12 = ff_rgba32ToUV_neon;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/aarch64/cpu.h"
|
||||
|
||||
#define YUV_TO_RGB_TABLE \
|
||||
c->yuv2rgb_v2r_coeff, \
|
||||
c->yuv2rgb_u2g_coeff, \
|
||||
c->yuv2rgb_v2g_coeff, \
|
||||
c->yuv2rgb_u2b_coeff, \
|
||||
|
||||
#define DECLARE_FF_YUVX_TO_RGBX_FUNCS(ifmt, ofmt) \
|
||||
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
|
||||
uint8_t *dst, int linesize, \
|
||||
const uint8_t *srcY, int linesizeY, \
|
||||
const uint8_t *srcU, int linesizeU, \
|
||||
const uint8_t *srcV, int linesizeV, \
|
||||
const int16_t *table, \
|
||||
int y_offset, \
|
||||
int y_coeff); \
|
||||
\
|
||||
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
|
||||
const int srcStride[], int srcSliceY, \
|
||||
int srcSliceH, uint8_t *const dst[], \
|
||||
const int dstStride[]) { \
|
||||
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
|
||||
\
|
||||
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
|
||||
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
|
||||
src[0], srcStride[0], \
|
||||
src[1], srcStride[1], \
|
||||
src[2], srcStride[2], \
|
||||
yuv2rgb_table, \
|
||||
c->yuv2rgb_y_offset >> 6, \
|
||||
c->yuv2rgb_y_coeff); \
|
||||
} \
|
||||
|
||||
#define DECLARE_FF_YUVX_TO_GBRP_FUNCS(ifmt, ofmt) \
|
||||
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
|
||||
uint8_t *dst, int linesize, \
|
||||
const uint8_t *srcY, int linesizeY, \
|
||||
const uint8_t *srcU, int linesizeU, \
|
||||
const uint8_t *srcV, int linesizeV, \
|
||||
const int16_t *table, \
|
||||
int y_offset, \
|
||||
int y_coeff, \
|
||||
uint8_t *dst1, int linesize1, \
|
||||
uint8_t *dst2, int linesize2); \
|
||||
\
|
||||
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
|
||||
const int srcStride[], int srcSliceY, \
|
||||
int srcSliceH, uint8_t *const dst[], \
|
||||
const int dstStride[]) { \
|
||||
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
|
||||
\
|
||||
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
|
||||
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
|
||||
src[0], srcStride[0], \
|
||||
src[1], srcStride[1], \
|
||||
src[2], srcStride[2], \
|
||||
yuv2rgb_table, \
|
||||
c->yuv2rgb_y_offset >> 6, \
|
||||
c->yuv2rgb_y_coeff, \
|
||||
dst[1] + srcSliceY * dstStride[1], dstStride[1], \
|
||||
dst[2] + srcSliceY * dstStride[2], dstStride[2]); \
|
||||
} \
|
||||
|
||||
#define DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuvx) \
|
||||
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, argb) \
|
||||
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, rgba) \
|
||||
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, abgr) \
|
||||
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, bgra) \
|
||||
DECLARE_FF_YUVX_TO_GBRP_FUNCS(yuvx, gbrp) \
|
||||
|
||||
DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv420p)
|
||||
DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv422p)
|
||||
|
||||
#define DECLARE_FF_NVX_TO_RGBX_FUNCS(ifmt, ofmt) \
|
||||
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
|
||||
uint8_t *dst, int linesize, \
|
||||
const uint8_t *srcY, int linesizeY, \
|
||||
const uint8_t *srcC, int linesizeC, \
|
||||
const int16_t *table, \
|
||||
int y_offset, \
|
||||
int y_coeff); \
|
||||
\
|
||||
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
|
||||
const int srcStride[], int srcSliceY, \
|
||||
int srcSliceH, uint8_t *const dst[], \
|
||||
const int dstStride[]) { \
|
||||
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
|
||||
\
|
||||
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
|
||||
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
|
||||
src[0], srcStride[0], src[1], srcStride[1], \
|
||||
yuv2rgb_table, \
|
||||
c->yuv2rgb_y_offset >> 6, \
|
||||
c->yuv2rgb_y_coeff); \
|
||||
} \
|
||||
|
||||
#define DECLARE_FF_NVX_TO_GBRP_FUNCS(ifmt, ofmt) \
|
||||
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
|
||||
uint8_t *dst, int linesize, \
|
||||
const uint8_t *srcY, int linesizeY, \
|
||||
const uint8_t *srcC, int linesizeC, \
|
||||
const int16_t *table, \
|
||||
int y_offset, \
|
||||
int y_coeff, \
|
||||
uint8_t *dst1, int linesize1, \
|
||||
uint8_t *dst2, int linesize2); \
|
||||
\
|
||||
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
|
||||
const int srcStride[], int srcSliceY, \
|
||||
int srcSliceH, uint8_t *const dst[], \
|
||||
const int dstStride[]) { \
|
||||
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
|
||||
\
|
||||
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
|
||||
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
|
||||
src[0], srcStride[0], src[1], srcStride[1], \
|
||||
yuv2rgb_table, \
|
||||
c->yuv2rgb_y_offset >> 6, \
|
||||
c->yuv2rgb_y_coeff, \
|
||||
dst[1] + srcSliceY * dstStride[1], dstStride[1], \
|
||||
dst[2] + srcSliceY * dstStride[2], dstStride[2]); \
|
||||
} \
|
||||
|
||||
void ff_nv24_to_yuv420p_chroma_neon(uint8_t *dst1, int dstStride1,
|
||||
uint8_t *dst2, int dstStride2,
|
||||
const uint8_t *src, int srcStride,
|
||||
int w, int h);
|
||||
|
||||
static int nv24_to_yuv420p_neon_wrapper(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[], int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
uint8_t *dst1 = dst[1] + dstStride[1] * srcSliceY / 2;
|
||||
uint8_t *dst2 = dst[2] + dstStride[2] * srcSliceY / 2;
|
||||
|
||||
ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w,
|
||||
dst[0], dstStride[0]);
|
||||
|
||||
if (c->opts.src_format == AV_PIX_FMT_NV24)
|
||||
ff_nv24_to_yuv420p_chroma_neon(dst1, dstStride[1], dst2, dstStride[2],
|
||||
src[1], srcStride[1], c->opts.src_w / 2,
|
||||
srcSliceH);
|
||||
else
|
||||
ff_nv24_to_yuv420p_chroma_neon(dst2, dstStride[2], dst1, dstStride[1],
|
||||
src[1], srcStride[1], c->opts.src_w / 2,
|
||||
srcSliceH);
|
||||
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
#define DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nvx) \
|
||||
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, argb) \
|
||||
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, rgba) \
|
||||
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, abgr) \
|
||||
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, bgra) \
|
||||
DECLARE_FF_NVX_TO_GBRP_FUNCS(nvx, gbrp) \
|
||||
|
||||
DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv12)
|
||||
DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv21)
|
||||
|
||||
/* We need a 16 pixel width alignment. This constraint can easily be removed
|
||||
* for input reading but for the output which is 4-bytes per pixel (RGBA) the
|
||||
* assembly might be writing as much as 4*15=60 extra bytes at the end of the
|
||||
* line, which won't fit the 32-bytes buffer alignment. */
|
||||
#define SET_FF_NVX_TO_RGBX_FUNC(ifmt, IFMT, ofmt, OFMT, accurate_rnd) do { \
|
||||
if (c->opts.src_format == AV_PIX_FMT_##IFMT \
|
||||
&& c->opts.dst_format == AV_PIX_FMT_##OFMT \
|
||||
&& !(c->opts.src_h & 1) \
|
||||
&& !(c->opts.src_w & 15) \
|
||||
&& !accurate_rnd) \
|
||||
c->convert_unscaled = ifmt##_to_##ofmt##_neon_wrapper; \
|
||||
} while (0)
|
||||
|
||||
#define SET_FF_NVX_TO_ALL_RGBX_FUNC(nvx, NVX, accurate_rnd) do { \
|
||||
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, argb, ARGB, accurate_rnd); \
|
||||
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, rgba, RGBA, accurate_rnd); \
|
||||
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, abgr, ABGR, accurate_rnd); \
|
||||
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, bgra, BGRA, accurate_rnd); \
|
||||
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, gbrp, GBRP, accurate_rnd); \
|
||||
} while (0)
|
||||
|
||||
static void get_unscaled_swscale_neon(SwsInternal *c) {
|
||||
int accurate_rnd = c->opts.flags & SWS_ACCURATE_RND;
|
||||
|
||||
SET_FF_NVX_TO_ALL_RGBX_FUNC(nv12, NV12, accurate_rnd);
|
||||
SET_FF_NVX_TO_ALL_RGBX_FUNC(nv21, NV21, accurate_rnd);
|
||||
SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv420p, YUV420P, accurate_rnd);
|
||||
SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv422p, YUV422P, accurate_rnd);
|
||||
|
||||
if (c->opts.dst_format == AV_PIX_FMT_YUV420P &&
|
||||
(c->opts.src_format == AV_PIX_FMT_NV24 || c->opts.src_format == AV_PIX_FMT_NV42) &&
|
||||
!(c->opts.src_h & 1) && !(c->opts.src_w & 15) && !accurate_rnd)
|
||||
c->convert_unscaled = nv24_to_yuv420p_neon_wrapper;
|
||||
}
|
||||
|
||||
void ff_get_unscaled_swscale_aarch64(SwsInternal *c)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
if (have_neon(cpu_flags))
|
||||
get_unscaled_swscale_neon(c);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Ramiro Polla
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/aarch64/asm.S"
|
||||
|
||||
function ff_nv24_to_yuv420p_chroma_neon, export=1
|
||||
// x0 uint8_t *dst1
|
||||
// x1 int dstStride1
|
||||
// x2 uint8_t *dst2
|
||||
// x3 int dstStride2
|
||||
// x4 const uint8_t *src
|
||||
// x5 int srcStride
|
||||
// w6 int w
|
||||
// w7 int h
|
||||
|
||||
add x9, x4, w5, sxtw // x9 = src + srcStride
|
||||
lsl w5, w5, #1 // srcStride *= 2
|
||||
sub w5, w5, w6, lsl #2 // srcPadding = (2 * srcStride) - (4 * w)
|
||||
sub w1, w1, w6 // dstPadding1 = dstStride1 - w
|
||||
sub w3, w3, w6 // dstPadding2 = dstStride2 - w
|
||||
|
||||
1:
|
||||
mov w10, w6 // w10 = w
|
||||
|
||||
2:
|
||||
ld2 {v0.16b, v1.16b}, [x4], #32 // v0 = U1, v1 = V1
|
||||
ld2 {v2.16b, v3.16b}, [x9], #32 // v2 = U2, v3 = V2
|
||||
|
||||
uaddlp v0.8h, v0.16b // pairwise add U1 into v0
|
||||
uaddlp v1.8h, v1.16b // pairwise add V1 into v1
|
||||
uadalp v0.8h, v2.16b // pairwise add U2, accumulate into v0
|
||||
uadalp v1.8h, v3.16b // pairwise add V2, accumulate into v1
|
||||
|
||||
shrn v0.8b, v0.8h, #2 // divide by 4
|
||||
shrn v1.8b, v1.8h, #2 // divide by 4
|
||||
|
||||
st1 {v0.8b}, [x0], #8 // store U into dst1
|
||||
st1 {v1.8b}, [x2], #8 // store V into dst2
|
||||
|
||||
subs w10, w10, #8
|
||||
b.gt 2b
|
||||
|
||||
// next row
|
||||
add x4, x4, w5, sxtw // src1 += srcPadding
|
||||
add x9, x9, w5, sxtw // src2 += srcPadding
|
||||
add x0, x0, w1, sxtw // dst1 += dstPadding1
|
||||
add x2, x2, w3, sxtw // dst2 += dstPadding2
|
||||
|
||||
subs w7, w7, #2
|
||||
b.gt 1b
|
||||
|
||||
ret
|
||||
endfunc
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
|
||||
* Copyright (c) 2016 Clément Bœsch <clement stupeflix.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/aarch64/asm.S"
|
||||
|
||||
.macro load_yoff_ycoeff yoff ycoeff
|
||||
#if defined(__APPLE__)
|
||||
ldp w9, w10, [sp, #\yoff]
|
||||
#else
|
||||
ldr w9, [sp, #\yoff]
|
||||
ldr w10, [sp, #\ycoeff]
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro load_dst1_dst2 dst1 linesize1 dst2 linesize2
|
||||
#if defined(__APPLE__)
|
||||
#define DST_OFFSET 8
|
||||
#else
|
||||
#define DST_OFFSET 0
|
||||
#endif
|
||||
ldr x10, [sp, #\dst1 - DST_OFFSET]
|
||||
ldr w12, [sp, #\linesize1 - DST_OFFSET]
|
||||
ldr x15, [sp, #\dst2 - DST_OFFSET]
|
||||
ldr w16, [sp, #\linesize2 - DST_OFFSET]
|
||||
#undef DST_OFFSET
|
||||
sub w12, w12, w0 // w12 = linesize1 - width (padding1)
|
||||
sub w16, w16, w0 // w16 = linesize2 - width (padding2)
|
||||
.endm
|
||||
|
||||
.macro load_args_nv12 ofmt
|
||||
ldr x8, [sp] // table
|
||||
load_yoff_ycoeff 8, 16 // y_offset, y_coeff
|
||||
ld1 {v1.1d}, [x8]
|
||||
dup v0.8h, w10
|
||||
dup v3.8h, w9
|
||||
.ifc \ofmt,gbrp
|
||||
load_dst1_dst2 24, 32, 40, 48
|
||||
sub w3, w3, w0 // w3 = linesize - width (padding)
|
||||
.else
|
||||
sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding)
|
||||
.endif
|
||||
sub w5, w5, w0 // w5 = linesizeY - width (paddingY)
|
||||
sub w7, w7, w0 // w7 = linesizeC - width (paddingC)
|
||||
neg w11, w0
|
||||
.endm
|
||||
|
||||
.macro load_args_nv21 ofmt
|
||||
load_args_nv12 \ofmt
|
||||
.endm
|
||||
|
||||
.macro load_args_yuv420p ofmt
|
||||
ldr x13, [sp] // srcV
|
||||
ldr w14, [sp, #8] // linesizeV
|
||||
ldr x8, [sp, #16] // table
|
||||
load_yoff_ycoeff 24, 32 // y_offset, y_coeff
|
||||
ld1 {v1.1d}, [x8]
|
||||
dup v0.8h, w10
|
||||
dup v3.8h, w9
|
||||
.ifc \ofmt,gbrp
|
||||
load_dst1_dst2 40, 48, 56, 64
|
||||
sub w3, w3, w0 // w3 = linesize - width (padding)
|
||||
.else
|
||||
sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding)
|
||||
.endif
|
||||
sub w5, w5, w0 // w5 = linesizeY - width (paddingY)
|
||||
sub w7, w7, w0, lsr #1 // w7 = linesizeU - width / 2 (paddingU)
|
||||
sub w14, w14, w0, lsr #1 // w14 = linesizeV - width / 2 (paddingV)
|
||||
lsr w11, w0, #1
|
||||
neg w11, w11
|
||||
.endm
|
||||
|
||||
.macro load_args_yuv422p ofmt
|
||||
ldr x13, [sp] // srcV
|
||||
ldr w14, [sp, #8] // linesizeV
|
||||
ldr x8, [sp, #16] // table
|
||||
load_yoff_ycoeff 24, 32 // y_offset, y_coeff
|
||||
ld1 {v1.1d}, [x8]
|
||||
dup v0.8h, w10
|
||||
dup v3.8h, w9
|
||||
.ifc \ofmt,gbrp
|
||||
load_dst1_dst2 40, 48, 56, 64
|
||||
sub w3, w3, w0 // w3 = linesize - width (padding)
|
||||
.else
|
||||
sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding)
|
||||
.endif
|
||||
sub w5, w5, w0 // w5 = linesizeY - width (paddingY)
|
||||
sub w7, w7, w0, lsr #1 // w7 = linesizeU - width / 2 (paddingU)
|
||||
sub w14, w14, w0, lsr #1 // w14 = linesizeV - width / 2 (paddingV)
|
||||
.endm
|
||||
|
||||
.macro load_chroma_nv12
|
||||
ld2 {v16.8b, v17.8b}, [x6], #16
|
||||
ushll v18.8h, v16.8b, #3
|
||||
ushll v19.8h, v17.8b, #3
|
||||
.endm
|
||||
|
||||
.macro load_chroma_nv21
|
||||
ld2 {v16.8b, v17.8b}, [x6], #16
|
||||
ushll v19.8h, v16.8b, #3
|
||||
ushll v18.8h, v17.8b, #3
|
||||
.endm
|
||||
|
||||
.macro load_chroma_yuv420p
|
||||
ld1 {v16.8b}, [ x6], #8
|
||||
ld1 {v17.8b}, [x13], #8
|
||||
ushll v18.8h, v16.8b, #3
|
||||
ushll v19.8h, v17.8b, #3
|
||||
.endm
|
||||
|
||||
.macro load_chroma_yuv422p
|
||||
load_chroma_yuv420p
|
||||
.endm
|
||||
|
||||
.macro increment_nv12
|
||||
ands w17, w1, #1
|
||||
csel w17, w7, w11, ne // incC = (h & 1) ? paddincC : -width
|
||||
add x6, x6, w17, sxtw // srcC += incC
|
||||
.endm
|
||||
|
||||
.macro increment_nv21
|
||||
increment_nv12
|
||||
.endm
|
||||
|
||||
.macro increment_yuv420p
|
||||
ands w17, w1, #1
|
||||
csel w17, w7, w11, ne // incU = (h & 1) ? paddincU : -width/2
|
||||
add x6, x6, w17, sxtw // srcU += incU
|
||||
csel w17, w14, w11, ne // incV = (h & 1) ? paddincV : -width/2
|
||||
add x13, x13, w17, sxtw // srcV += incV
|
||||
.endm
|
||||
|
||||
.macro increment_yuv422p
|
||||
add x6, x6, w7, sxtw // srcU += incU
|
||||
add x13, x13, w14, sxtw // srcV += incV
|
||||
.endm
|
||||
|
||||
.macro compute_rgb r1 g1 b1 r2 g2 b2
|
||||
add v20.8h, v26.8h, v20.8h // Y1 + R1
|
||||
add v21.8h, v27.8h, v21.8h // Y2 + R2
|
||||
add v22.8h, v26.8h, v22.8h // Y1 + G1
|
||||
add v23.8h, v27.8h, v23.8h // Y2 + G2
|
||||
add v24.8h, v26.8h, v24.8h // Y1 + B1
|
||||
add v25.8h, v27.8h, v25.8h // Y2 + B2
|
||||
sqrshrun \r1, v20.8h, #1 // clip_u8((Y1 + R1) >> 1)
|
||||
sqrshrun \r2, v21.8h, #1 // clip_u8((Y2 + R1) >> 1)
|
||||
sqrshrun \g1, v22.8h, #1 // clip_u8((Y1 + G1) >> 1)
|
||||
sqrshrun \g2, v23.8h, #1 // clip_u8((Y2 + G1) >> 1)
|
||||
sqrshrun \b1, v24.8h, #1 // clip_u8((Y1 + B1) >> 1)
|
||||
sqrshrun \b2, v25.8h, #1 // clip_u8((Y2 + B1) >> 1)
|
||||
.endm
|
||||
|
||||
.macro compute_rgba r1 g1 b1 a1 r2 g2 b2 a2
|
||||
compute_rgb \r1, \g1, \b1, \r2, \g2, \b2
|
||||
movi \a1, #255
|
||||
movi \a2, #255
|
||||
.endm
|
||||
|
||||
.macro declare_func ifmt ofmt
|
||||
function ff_\ifmt\()_to_\ofmt\()_neon, export=1
|
||||
load_args_\ifmt \ofmt
|
||||
|
||||
mov w9, w1
|
||||
1:
|
||||
mov w8, w0 // w8 = width
|
||||
2:
|
||||
movi v5.8h, #4, lsl #8 // 128 * (1<<3)
|
||||
load_chroma_\ifmt
|
||||
sub v18.8h, v18.8h, v5.8h // U*(1<<3) - 128*(1<<3)
|
||||
sub v19.8h, v19.8h, v5.8h // V*(1<<3) - 128*(1<<3)
|
||||
sqdmulh v20.8h, v19.8h, v1.h[0] // V * v2r (R)
|
||||
sqdmulh v22.8h, v18.8h, v1.h[1] // U * u2g
|
||||
sqdmulh v19.8h, v19.8h, v1.h[2] // V * v2g
|
||||
add v22.8h, v22.8h, v19.8h // U * u2g + V * v2g (G)
|
||||
sqdmulh v24.8h, v18.8h, v1.h[3] // U * u2b (B)
|
||||
zip2 v21.8h, v20.8h, v20.8h // R2
|
||||
zip1 v20.8h, v20.8h, v20.8h // R1
|
||||
zip2 v23.8h, v22.8h, v22.8h // G2
|
||||
zip1 v22.8h, v22.8h, v22.8h // G1
|
||||
zip2 v25.8h, v24.8h, v24.8h // B2
|
||||
zip1 v24.8h, v24.8h, v24.8h // B1
|
||||
ld1 {v2.16b}, [x4], #16 // load luma
|
||||
ushll v26.8h, v2.8b, #3 // Y1*(1<<3)
|
||||
ushll2 v27.8h, v2.16b, #3 // Y2*(1<<3)
|
||||
sub v26.8h, v26.8h, v3.8h // Y1*(1<<3) - y_offset
|
||||
sub v27.8h, v27.8h, v3.8h // Y2*(1<<3) - y_offset
|
||||
sqdmulh v26.8h, v26.8h, v0.8h // ((Y1*(1<<3) - y_offset) * y_coeff) >> 15
|
||||
sqdmulh v27.8h, v27.8h, v0.8h // ((Y2*(1<<3) - y_offset) * y_coeff) >> 15
|
||||
|
||||
.ifc \ofmt,argb // 1 2 3 0
|
||||
compute_rgba v5.8b,v6.8b,v7.8b,v4.8b, v17.8b,v18.8b,v19.8b,v16.8b
|
||||
.endif
|
||||
|
||||
.ifc \ofmt,rgba // 0 1 2 3
|
||||
compute_rgba v4.8b,v5.8b,v6.8b,v7.8b, v16.8b,v17.8b,v18.8b,v19.8b
|
||||
.endif
|
||||
|
||||
.ifc \ofmt,abgr // 3 2 1 0
|
||||
compute_rgba v7.8b,v6.8b,v5.8b,v4.8b, v19.8b,v18.8b,v17.8b,v16.8b
|
||||
.endif
|
||||
|
||||
.ifc \ofmt,bgra // 2 1 0 3
|
||||
compute_rgba v6.8b,v5.8b,v4.8b,v7.8b, v18.8b,v17.8b,v16.8b,v19.8b
|
||||
.endif
|
||||
|
||||
.ifc \ofmt,gbrp
|
||||
compute_rgb v18.8b,v4.8b,v6.8b, v19.8b,v5.8b,v7.8b
|
||||
st1 { v4.8b, v5.8b }, [x2], #16
|
||||
st1 { v6.8b, v7.8b }, [x10], #16
|
||||
st1 { v18.8b, v19.8b }, [x15], #16
|
||||
.else
|
||||
st4 { v4.8b, v5.8b, v6.8b, v7.8b}, [x2], #32
|
||||
st4 {v16.8b,v17.8b,v18.8b,v19.8b}, [x2], #32
|
||||
.endif
|
||||
subs w8, w8, #16 // width -= 16
|
||||
b.gt 2b
|
||||
add x2, x2, w3, sxtw // dst += padding
|
||||
.ifc \ofmt,gbrp
|
||||
add x10, x10, w12, sxtw // dst1 += padding1
|
||||
add x15, x15, w16, sxtw // dst2 += padding2
|
||||
.endif
|
||||
add x4, x4, w5, sxtw // srcY += paddingY
|
||||
increment_\ifmt
|
||||
subs w1, w1, #1 // height -= 1
|
||||
b.gt 1b
|
||||
mov w0, w9
|
||||
ret
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
.macro declare_rgb_funcs ifmt
|
||||
declare_func \ifmt, argb
|
||||
declare_func \ifmt, rgba
|
||||
declare_func \ifmt, abgr
|
||||
declare_func \ifmt, bgra
|
||||
declare_func \ifmt, gbrp
|
||||
.endm
|
||||
|
||||
declare_rgb_funcs nv12
|
||||
declare_rgb_funcs nv21
|
||||
declare_rgb_funcs yuv420p
|
||||
declare_rgb_funcs yuv422p
|
||||
Reference in New Issue
Block a user