aboutsummaryrefslogtreecommitdiff
path: root/libavcodec
diff options
context:
space:
mode:
authorMåns Rullgård2007-01-28 21:32:08 +0000
committerMåns Rullgård2007-01-28 21:32:08 +0000
commit7d42886b93189dec009b6124cbd2c4e555ae6df6 (patch)
tree15e2607ffee5a3ae550bc75b632f51f75bd56ce2 /libavcodec
parent94d122e96e352fd91f1c75fc9ed05b76b673624b (diff)
ARMv6 SIMD IDCT
Originally committed as revision 7752 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/armv4l/dsputil_arm.c15
-rw-r--r--libavcodec/armv4l/simple_idct_armv6.S385
-rw-r--r--libavcodec/avcodec.h1
4 files changed, 403 insertions, 0 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index adfc04d459..1bdda6a02c 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -355,6 +355,8 @@ OBJS-$(TARGET_IWMMXT) += armv4l/dsputil_iwmmxt.o \
ASM_OBJS-$(TARGET_ARMV5TE) += armv4l/simple_idct_armv5te.o \
armv4l/mpegvideo_armv5te.o \
+ASM_OBJS-$(HAVE_ARMV6) += armv4l/simple_idct_armv6.o
+
# sun sparc
OBJS-$(TARGET_ARCH_SPARC) += sparc/dsputil_vis.o \
diff --git a/libavcodec/armv4l/dsputil_arm.c b/libavcodec/armv4l/dsputil_arm.c
index 9f0bfa2af6..61b5fdacc4 100644
--- a/libavcodec/armv4l/dsputil_arm.c
+++ b/libavcodec/armv4l/dsputil_arm.c
@@ -35,6 +35,12 @@ extern void simple_idct_put_armv5te(uint8_t *dest, int line_size,
extern void simple_idct_add_armv5te(uint8_t *dest, int line_size,
DCTELEM *data);
+extern void ff_simple_idct_armv6(DCTELEM *data);
+extern void ff_simple_idct_put_armv6(uint8_t *dest, int line_size,
+ DCTELEM *data);
+extern void ff_simple_idct_add_armv6(uint8_t *dest, int line_size,
+ DCTELEM *data);
+
/* XXX: local hack */
static void (*ff_put_pixels_clamped)(const DCTELEM *block, uint8_t *pixels, int line_size);
static void (*ff_add_pixels_clamped)(const DCTELEM *block, uint8_t *pixels, int line_size);
@@ -206,6 +212,8 @@ void dsputil_init_armv4l(DSPContext* c, AVCodecContext *avctx)
if(idct_algo == FF_IDCT_AUTO){
#if defined(HAVE_IPP)
idct_algo = FF_IDCT_IPP;
+#elif defined(HAVE_ARMV6)
+ idct_algo = FF_IDCT_SIMPLEARMV6;
#elif defined(HAVE_ARMV5TE)
idct_algo = FF_IDCT_SIMPLEARMV5TE;
#else
@@ -223,6 +231,13 @@ void dsputil_init_armv4l(DSPContext* c, AVCodecContext *avctx)
c->idct_add= simple_idct_ARM_add;
c->idct = simple_idct_ARM;
c->idct_permutation_type= FF_NO_IDCT_PERM;
+#ifdef HAVE_ARMV6
+ } else if (idct_algo==FF_IDCT_SIMPLEARMV6){
+ c->idct_put= ff_simple_idct_put_armv6;
+ c->idct_add= ff_simple_idct_add_armv6;
+ c->idct = ff_simple_idct_armv6;
+ c->idct_permutation_type= FF_LIBMPEG2_IDCT_PERM;
+#endif
#ifdef HAVE_ARMV5TE
} else if (idct_algo==FF_IDCT_SIMPLEARMV5TE){
c->idct_put= simple_idct_put_armv5te;
diff --git a/libavcodec/armv4l/simple_idct_armv6.S b/libavcodec/armv4l/simple_idct_armv6.S
new file mode 100644
index 0000000000..8856855f4e
--- /dev/null
+++ b/libavcodec/armv4l/simple_idct_armv6.S
@@ -0,0 +1,385 @@
+/*
+ * Simple IDCT
+ *
+ * Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2007 Mans Rullgard <mru@inprovide.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
+ */
+
+#define W1 22725 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define W2 21407 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define W3 19266 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define W4 16383 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define W5 12873 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define W6 8867 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define W7 4520 /* cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 */
+#define ROW_SHIFT 11
+#define COL_SHIFT 20
+
+#define W13 (W1 | (W3 << 16))
+#define W26 (W2 | (W6 << 16))
+#define W42 (W4 | (W2 << 16))
+#define W42n (-W4&0xffff | (-W2 << 16))
+#define W46 (W4 | (W6 << 16))
+#define W57 (W5 | (W7 << 16))
+
+ .text
+ .align
+w13: .long W13
+w26: .long W26
+w42: .long W42
+w42n: .long W42n
+w46: .long W46
+w57: .long W57
+
+/*
+ Compute partial IDCT of single row.
+ shift = left-shift amount
+ a1 = source address
+
+ Output in registers v1--v8
+*/
+ .macro idct_row shift
+ ldr a3, [a1] /* a3 = row[2,0] */
+ ldr ip, [pc, #(w42-.-8)] /* ip = W4 | (W2 << 16) */
+ ldr lr, [pc, #(w46-.-8)] /* lr = W4 | (W6 << 16) */
+ ldr a4, [a1, #8] /* a4 = row[3,1] */
+ mov a2, #(1<<(\shift-1))
+ smlad v1, a3, ip, a2
+ smlsd v4, a3, ip, a2
+ ldr ip, [pc, #(w13-.-8)] /* ip = W1 | (W3 << 16) */
+ ldr v7, [pc, #(w57-.-8)] /* v7 = W5 | (W7 << 16) */
+ smlad v2, a3, lr, a2
+ smlsd v3, a3, lr, a2
+
+ smuad v5, a4, ip /* v5 = B0 = W1*row[1] + W3*row[3] */
+ smusdx fp, a4, v7 /* fp = B3 = W7*row[1] - W5*row[3] */
+ ldr lr, [a1, #12] /* lr = row[7,5] */
+ pkhtb a3, ip, v7, asr #16 /* a4 = W7 | (W3 << 16) */
+ pkhbt a2, ip, v7, lsl #16 /* a2 = W1 | (W5 << 16) */
+ smlad v5, lr, v7, v5 /* B0 += W5*row[5] + W7*row[7] */
+ smusdx v7, a4, a2 /* v7 = B2 = W5*row[1] - W1*row[3] */
+ smusdx v6, a3, a4 /* v6 = -B1 = W7*row[3] - W3*row[1] */
+
+ smlad v7, lr, a3, v7 /* B2 += W7*row[5] + W3*row[7] */
+ ldr a3, [a1, #4] /* a3 = row[6,4] */
+ ldr a4, [pc, #(w42n-.-8)] /* a4 = -W4 | (-W2 << 16) */
+ smlsdx fp, lr, ip, fp /* B3 += W3*row[5] - W1*row[7] */
+ ldr ip, [pc, #(w46-.-8)] /* ip = W4 | (W6 << 16) */
+ smlad v6, lr, a2, v6 /* B1 -= W1*row[5] + W5*row[7] */
+
+ smlad v2, a3, a4, v2 /* A1 += -W4*row[4] - W2*row[6] */
+ smlsd v3, a3, a4, v3 /* A2 += -W4*row[4] + W2*row[6] */
+ smlad v1, a3, ip, v1 /* A0 += W4*row[4] + W6*row[6] */
+ smlsd v4, a3, ip, v4 /* A3 += W4*row[4] - W6*row[6] */
+ .endm
+
+/*
+ Compute final part of IDCT single row without shift.
+ Input in registers v1--v8
+ Output in registers ip, v1--v3, lr, v5--v7
+*/
+ .macro idct_finish
+ add ip, v1, v5 /* a2 = A0 + B0 */
+ sub lr, v1, v5 /* a3 = A0 - B0 */
+ sub v1, v2, v6 /* a3 = A1 + B1 */
+ add v5, v2, v6 /* a3 = A1 - B1 */
+ add v2, v3, v7 /* a2 = A2 + B2 */
+ sub v6, v3, v7 /* a2 = A2 - B2 */
+ add v3, v4, fp /* a3 = A3 + B3 */
+ sub v7, v4, fp /* a3 = A3 - B3 */
+ .endm
+
+/*
+ Compute final part of IDCT single row.
+ shift = right-shift amount
+ Input/output in registers v1--v8
+*/
+ .macro idct_finish_shift shift
+ add a4, v1, v5 /* a4 = A0 + B0 */
+ sub a3, v1, v5 /* a3 = A0 - B0 */
+ mov v1, a4, asr #\shift
+ mov v5, a3, asr #\shift
+
+ sub a4, v2, v6 /* a4 = A1 + B1 */
+ add a3, v2, v6 /* a3 = A1 - B1 */
+ mov v2, a4, asr #\shift
+ mov v6, a3, asr #\shift
+
+ add a4, v3, v7 /* a4 = A2 + B2 */
+ sub a3, v3, v7 /* a3 = A2 - B2 */
+ mov v3, a4, asr #\shift
+ mov v7, a3, asr #\shift
+
+ add a4, v4, fp /* a4 = A3 + B3 */
+ sub a3, v4, fp /* a3 = A3 - B3 */
+ mov v4, a4, asr #\shift
+ mov fp, a3, asr #\shift
+ .endm
+
+/*
+ Compute final part of IDCT single row, saturating results at 8 bits.
+ shift = right-shift amount
+ Input/output in registers v1--v8
+*/
+ .macro idct_finish_shift_sat shift
+ add a4, v1, v5 /* a4 = A0 + B0 */
+ sub ip, v1, v5 /* ip = A0 - B0 */
+ usat v1, #8, a4, asr #\shift
+ usat v5, #8, ip, asr #\shift
+
+ sub a4, v2, v6 /* a4 = A1 + B1 */
+ add ip, v2, v6 /* ip = A1 - B1 */
+ usat v2, #8, a4, asr #\shift
+ usat v6, #8, ip, asr #\shift
+
+ add a4, v3, v7 /* a4 = A2 + B2 */
+ sub ip, v3, v7 /* ip = A2 - B2 */
+ usat v3, #8, a4, asr #\shift
+ usat v7, #8, ip, asr #\shift
+
+ add a4, v4, fp /* a4 = A3 + B3 */
+ sub ip, v4, fp /* ip = A3 - B3 */
+ usat v4, #8, a4, asr #\shift
+ usat fp, #8, ip, asr #\shift
+ .endm
+
+/*
+ Compute IDCT of single row, storing as column.
+ a1 = source
+ a2 = dest
+*/
+ .align
+ .func idct_row_armv6
+idct_row_armv6:
+ stmfd sp!, {a2, lr}
+
+ idct_row ROW_SHIFT
+ ldr a2, [sp], #4
+ idct_finish_shift ROW_SHIFT
+
+ strh v1, [a2]
+ strh v2, [a2, #(16*2)]
+ strh v3, [a2, #(16*4)]
+ strh v4, [a2, #(16*6)]
+ strh fp, [a2, #(16*1)]
+ strh v7, [a2, #(16*3)]
+ strh v6, [a2, #(16*5)]
+ strh v5, [a2, #(16*7)]
+
+ ldr pc, [sp], #4
+ .endfunc
+
+/*
+ Compute IDCT of single column, read as row.
+ a1 = source
+ a2 = dest
+*/
+ .align
+ .func idct_col_armv6
+idct_col_armv6:
+ stmfd sp!, {a2, lr}
+
+ idct_row COL_SHIFT
+ ldr a2, [sp], #4
+ idct_finish_shift COL_SHIFT
+
+ strh v1, [a2]
+ strh v2, [a2, #(16*1)]
+ strh v3, [a2, #(16*2)]
+ strh v4, [a2, #(16*3)]
+ strh fp, [a2, #(16*4)]
+ strh v7, [a2, #(16*5)]
+ strh v6, [a2, #(16*6)]
+ strh v5, [a2, #(16*7)]
+
+ ldr pc, [sp], #4
+ .endfunc
+
+/*
+ Compute IDCT of single column, read as row, store saturated 8-bit.
+ a1 = source
+ a2 = dest
+ a3 = line size
+*/
+ .align
+ .func idct_col_put_armv6
+idct_col_put_armv6:
+ stmfd sp!, {a2, a3, lr}
+
+ idct_row COL_SHIFT
+ ldmfd sp!, {a2, a3}
+ idct_finish_shift_sat COL_SHIFT
+
+ strb v1, [a2], a3
+ strb v2, [a2], a3
+ strb v3, [a2], a3
+ strb v4, [a2], a3
+ strb fp, [a2], a3
+ strb v7, [a2], a3
+ strb v6, [a2], a3
+ strb v5, [a2], a3
+
+ sub a2, a2, a3, lsl #3
+
+ ldr pc, [sp], #4
+ .endfunc
+
+/*
+ Compute IDCT of single column, read as row, add/store saturated 8-bit.
+ a1 = source
+ a2 = dest
+ a3 = line size
+*/
+ .align
+ .func idct_col_add_armv6
+idct_col_add_armv6:
+ stmfd sp!, {a2, a3, lr}
+
+ idct_row COL_SHIFT
+ ldmfd sp!, {a2, a3}
+ idct_finish
+
+ ldrb a4, [a2]
+ ldrb v4, [a2, a3]
+ ldrb fp, [a2, a3, lsl #2]
+ add ip, a4, ip, asr #COL_SHIFT
+ usat ip, #8, ip
+ add v1, v4, v1, asr #COL_SHIFT
+ strb ip, [a2], a3
+ ldrb ip, [a2, a3]
+ usat v1, #8, v1
+ ldrb fp, [a2, a3, lsl #2]
+ add v2, ip, v2, asr #COL_SHIFT
+ usat v2, #8, v2
+ strb v1, [a2], a3
+ ldrb a4, [a2, a3]
+ ldrb ip, [a2, a3, lsl #2]
+ strb v2, [a2], a3
+ ldrb v4, [a2, a3]
+ ldrb v1, [a2, a3, lsl #2]
+ add v3, a4, v3, asr #COL_SHIFT
+ usat v3, #8, v3
+ add v7, v4, v7, asr #COL_SHIFT
+ usat v7, #8, v7
+ add v6, fp, v6, asr #COL_SHIFT
+ usat v6, #8, v6
+ add v5, ip, v5, asr #COL_SHIFT
+ usat v5, #8, v5
+ add lr, v1, lr, asr #COL_SHIFT
+ usat lr, #8, lr
+ strb v3, [a2], a3
+ strb v7, [a2], a3
+ strb v6, [a2], a3
+ strb v5, [a2], a3
+ strb lr, [a2], a3
+
+ sub a2, a2, a3, lsl #3
+
+ ldr pc, [sp], #4
+ .endfunc
+
+/*
+ Compute 8 IDCT row transforms.
+ func = IDCT row->col function
+ width = width of columns in bytes
+*/
+ .macro idct_rows func width
+ bl \func
+ add a1, a1, #(16*2)
+ add a2, a2, #\width
+ bl \func
+ add a1, a1, #(16*2)
+ add a2, a2, #\width
+ bl \func
+ add a1, a1, #(16*2)
+ add a2, a2, #\width
+ bl \func
+ sub a1, a1, #(16*5)
+ add a2, a2, #\width
+ bl \func
+ add a1, a1, #(16*2)
+ add a2, a2, #\width
+ bl \func
+ add a1, a1, #(16*2)
+ add a2, a2, #\width
+ bl \func
+ add a1, a1, #(16*2)
+ add a2, a2, #\width
+ bl \func
+
+ sub a1, a1, #(16*7)
+ .endm
+
+ .align
+ .global ff_simple_idct_armv6
+ .func ff_simple_idct_armv6
+/* void ff_simple_idct_armv6(DCTELEM *data); */
+ff_simple_idct_armv6:
+ stmfd sp!, {v1, v2, v3, v4, v5, v6, v7, fp, lr}
+ sub sp, sp, #128
+
+ mov a2, sp
+ idct_rows idct_row_armv6, 2
+ mov a2, a1
+ mov a1, sp
+ idct_rows idct_col_armv6, 2
+
+ add sp, sp, #128
+ ldmfd sp!, {v1, v2, v3, v4, v5, v6, v7, fp, pc}
+ .endfunc
+
+ .align
+ .global ff_simple_idct_add_armv6
+ .func ff_simple_idct_add_armv6
+/* ff_simple_idct_add_armv6(uint8_t *dest, int line_size, DCTELEM *data); */
+ff_simple_idct_add_armv6:
+ stmfd sp!, {a1, a2, v1, v2, v3, v4, v5, v6, v7, fp, lr}
+ sub sp, sp, #128
+
+ mov a1, a3
+ mov a2, sp
+ idct_rows idct_row_armv6, 2
+ mov a1, sp
+ ldr a2, [sp, #128]
+ ldr a3, [sp, #(128+4)]
+ idct_rows idct_col_add_armv6, 1
+
+ add sp, sp, #(128+8)
+ ldmfd sp!, {v1, v2, v3, v4, v5, v6, v7, fp, pc}
+ .endfunc
+
+ .align
+ .global ff_simple_idct_put_armv6
+ .func ff_simple_idct_put_armv6
+/* ff_simple_idct_put_armv6(uint8_t *dest, int line_size, DCTELEM *data); */
+ff_simple_idct_put_armv6:
+ stmfd sp!, {a1, a2, v1, v2, v3, v4, v5, v6, v7, fp, lr}
+ sub sp, sp, #128
+
+ mov a1, a3
+ mov a2, sp
+ idct_rows idct_row_armv6, 2
+ mov a1, sp
+ ldr a2, [sp, #128]
+ ldr a3, [sp, #(128+4)]
+ idct_rows idct_col_put_armv6, 1
+
+ add sp, sp, #(128+8)
+ ldmfd sp!, {v1, v2, v3, v4, v5, v6, v7, fp, pc}
+ .endfunc
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 07ea47d326..615f6c693b 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1234,6 +1234,7 @@ typedef struct AVCodecContext {
#define FF_IDCT_XVIDMMX 14
#define FF_IDCT_CAVS 15
#define FF_IDCT_SIMPLEARMV5TE 16
+#define FF_IDCT_SIMPLEARMV6 17
/**
* slice count.